2011-05-01 63 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