2011-05-01 60 views
28

块内部结合我在Ruby DSL的作品,像这样:更改上下文/红宝石

desc 'list all todos' 
command :list do |c| 
    c.desc 'show todos in long form' 
    c.switch :l 
    c.action do |global,option,args| 
    # some code that's not relevant to this question 
    end 
end 

desc 'make a new todo' 
command :new do |c| 
    # etc. 
end 

一位同行开发商建议我提高我的DSL不要求通过ccommand块,和因此不需要所有 里面的方法c.;据推测,他暗示我可以做下面的代码工作是相同的:

desc 'list all todos' 
command :list do 
    desc 'show todos in long form' 
    switch :l 
    action do |global,option,args| 
    # some code that's not relevant to this question 
    end 
end 

desc 'make a new todo' 
command :new do 
    # etc. 
end 

command的代码看起来像

def command(*names) 
    command = make_command_object(..) 
    yield command                              
end 

我试过几件事情,是无法得到它的工作;我无法弄清楚如何改变command块内代码的上下文/绑定,使其与默认值不同。

任何想法,如果这是可能的,我怎么可能做到这一点?

回答

27

粘贴此代码:

def evaluate(&block) 
    @self_before_instance_eval = eval "self", block.binding 
    instance_eval &block 
    end 

    def method_missing(method, *args, &block) 
    @self_before_instance_eval.send method, *args, &block 
    end 

欲了解更多信息,请参阅本真正的好文章here

+0

是评价特殊?链接的文章并未如此表示。我的代码在'command'的定义中做了一个yield。你是说我应该在我的方法sig中放入&block,然后是block而不是yield的instance_eval? (用这个信息更新问题) – davetron5000 2011-05-02 00:39:22

4
class CommandDSL 
    def self.call(&blk) 
    # Create a new CommandDSL instance, and instance_eval the block to it 
    instance = new 
    instance.instance_eval(&blk) 
    # Now return all of the set instance variables as a Hash 
    instance.instance_variables.inject({}) { |result_hash, instance_variable| 
     result_hash[instance_variable] = instance.instance_variable_get(instance_variable) 
     result_hash # Gotta have the block return the result_hash 
    } 
    end 

    def desc(str); @desc = str; end 
    def switch(sym); @switch = sym; end 
    def action(&blk); @action = blk; end 
end 

def command(name, &blk) 
    values_set_within_dsl = CommandDSL.call(&blk) 

    # INSERT CODE HERE 
    p name 
    p values_set_within_dsl 
end 

command :list do 
    desc 'show todos in long form' 
    switch :l 
    action do |global,option,args| 
    # some code that's not relevant to this question 
    end 
end 

会打印:

:list 
{:@desc=>"show todos in long form", :@switch=>:l, :@action=>#<Proc:[email protected]:/Users/Ryguy/Desktop/tesdt.rb:38>} 
9

也许

def command(*names, &blk) 
    command = make_command_object(..) 
    command.instance_eval(&blk) 
end 

可以评估命令对象上下文中的块。

2

我写了一个类来处理这个确切的问题,并处理诸如@instance_variable访问,嵌套等等。这是从另一个问题的写作:

Block call in Ruby on Rails