【发布时间】:2012-01-03 01:33:02
【问题描述】:
我试图弄清楚如何为我的 Ruby 项目创建一种“无类 DSL”,类似于如何在 Cucumber 步骤定义文件中定义步骤定义或在 Sinatra 应用程序中定义路由。
例如,我想要一个文件,其中我的所有 DSL 函数都被调用:
#sample.rb
when_string_matches /hello (.+)/ do |name|
call_another_method(name)
end
我认为使用一组特定于我的项目的方法来污染全局 (Kernel) 命名空间是一种不好的做法。因此,when_string_matches 和 call_another_method 方法将在我的库中定义,sample.rb 文件将以某种方式在我的 DSL 方法的上下文中进行评估。
更新:以下是当前如何定义这些 DSL 方法的示例:
DSL 方法是在一个被子类化的类中定义的(我想找到一种在简单 DSL 和类实例之间重用这些方法的方法):
module MyMod
class Action
def call_another_method(value)
puts value
end
def handle(text)
# a subclass would be expected to define
# this method (as an alternative to the
# simple DSL approach)
end
end
end
然后在某个时刻,在我的程序初始化期间,我想解析sample.rb 文件并存储这些操作以供以后执行:
module MyMod
class Parser
# parse the file, saving the blocks and regular expressions to call later
def parse_it
file_contents = File.read('sample.rb')
instance_eval file_contents
end
# doesnt seem like this belongs here, but it won't work if it's not
def self.when_string_matches(regex, &block)
MyMod.blocks_for_executing_later << { regex: regex, block: block }
end
end
end
# Later...
module MyMod
class Runner
def run
string = 'hello Andrew'
MyMod.blocks_for_executing_later.each do |action|
if string =~ action[:regex]
args = action[:regex].match(string).captures
action[:block].call(args)
end
end
end
end
end
到目前为止我所遇到的问题(以及我尝试过的各种我上面没有提到的事情)是当文件中定义一个块时,实例方法不可用(我知道它是现在在不同的班级)。但我想做的更像是创建一个实例并在该上下文中进行评估,而不是在Parser 类中进行评估。但我不知道该怎么做。
我希望这是有道理的。任何帮助、经验或建议都将不胜感激。
【问题讨论】:
标签: ruby