2012-01-03 143 views
4

我写了下面的代码:如何使用类变量中定义的lambda/Proc中的实例变量?

class Actions 
    def initialize 
    @people = [] 
    @commands = { 
     "ADD" => ->(name){@people << name }, 
     "REMOVE" => ->(n=0){ puts "Goodbye" }, 
     "OTHER" => ->(n=0){puts "Do Nothing" } 
    } 
    end 
    def run_command(cmd,*param) 
    @commands[cmd].call param if @commands.key?(cmd) 
    end 
    def people 
    @people 
    end 
end 
act = Actions.new 

act.run_command('ADD','joe') 
act.run_command('ADD','jack') 
puts act.people 

然而这工作,当@commands哈希是一个类变量,哈希里面的代码不知道@people阵列。

如何使@commands散列成为类变量并仍然能够访问特定的对象实例变量?

+1

只是好奇为什么不定义方法'添加',''删除'和'其他'作为实例方法,并使用'respond_to?'和'发送'来调用它们? – 2012-01-03 21:42:55

+0

为什么你要'@ commands'成为一个类变量? – 2012-01-03 22:00:58

+0

@Victor:一个很好的理由是它使得访问控制更容易。如果你使用'send'和方法,你需要一个允许使用'run_command'的方法的单独列表,使用Hash将可用的命令及其实现收集到一个漂亮的包中。 – 2012-01-03 22:09:41

回答

6

你可以使用instance_exec提供相应的上下文,当你给他们打电话的lambda表达式,查找意见以查看更改:

class Actions 
    # Move the lambdas to a class variable, a COMMANDS constant 
    # would work just as well and might be more appropriate. 
    @@commands = { 
    "ADD" => ->(name) { @people << name }, 
    "REMOVE" => ->(n = 0) { puts "Goodbye" }, 
    "OTHER" => ->(n = 0) { puts "Do Nothing" } 
    } 
    def initialize 
    @people = [ ] 
    end 
    def run_command(cmd, *param) 
    # Use instance_exec and blockify the lambdas with '&' 
    # to call them in the context of 'self'. Change the 
    # @@commands to COMMANDS if you prefer to use a constant 
    # for this stuff. 
    instance_exec(param, &@@commands[cmd]) if @@commands.key?(cmd) 
    end 
    def people 
    @people 
    end 
end 
+0

啊! '参数作为块参数传递给instance_exec – maprihoda 2012-01-03 22:22:18

1

编辑继@ VictorMoroz的和@亩的建议:

class Actions 
    def initialize 
    @people = [] 
    end 

    def cmd_add(name) 
    @people << name 
    end 

    def cmd_remove 
    puts "Goodbye" 
    end 

    def cmd_other 
    puts "Do Nothing" 
    end 

    def people 
    p @people 
    end 

    def run_command(cmd, *param) 
    cmd = 'cmd_' + cmd.to_s.downcase 
    send(cmd, *param) if respond_to?(cmd) 
    end 
end 

act = Actions.new 

act.run_command('add', 'joe') 
act.run_command(:ADD, 'jill') 
act.run_command('ADD', 'jack') 

act.run_command('people') # does nothing 

act.people 

或者

class Actions 
    ALLOWED_METHODS = %w(add remove other) 

    def initialize 
    @people = [] 
    end 

    def add(name) 
    @people << name 
    end 

    def remove 
    puts "Goodbye" 
    end 

    def other 
    puts "Do Nothing" 
    end 

    def people 
    p @people 
    end 

    def run_command(cmd, *param) 
    cmd = cmd.to_s.downcase 
    send(cmd, *param) if ALLOWED_METHODS.include?(cmd) 
    end 
end 

act = Actions.new 

act.run_command('add', 'joe') 
act.run_command(:add, 'jill') 
act.run_command('add', 'jack') 

act.run_command('people') # does nothing 

act.people