How to use instance variables from lambda / proc defined in class variable?

I wrote the following code:

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 

This works, however, when the @commands hash is a class variable, the code inside the hash does not know the @people array.

How to make the @commands hash of a @commands variable and still have access to specific object instance variables?

+4
source share
2 answers

You can use instance_exec to provide the appropriate context for lambdas, when you call them, look for comments to see the changes:

 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 
+6
source

EDIT Following the recommendations of @VictorMoroz and @mu:

 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 

or

 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 
+1
source

Source: https://habr.com/ru/post/1389151/


All Articles