2012-01-03 136 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