ruby - Setting method local variables from a proc -


if have class 2 instance variables @x , @y, can change them proc using self.instance_exec:

class location   attr_accessor :x, :y   def initialize     @x = 0     @y = 0   end   def set &block     self.instance_exec(&block)   end end  location = location.new location.set   @x = rand(100)   @y = rand(100) end  puts location.x puts location.y 

if have class method set 2 local variables x , y, can use proc return values set them:

class location   def set &block     x = 0;     y = 0;     x, y = block.call()     # x , y     puts x     puts y   end end  location = location.new location.set   x = rand(100)   y = rand(100)   [x, y] end 

is there way access set method local variables x , y proc without using return values?

you can it, sort of, isn't pretty

there way block set variable in calling method, isn't pretty. can pass in binding, eval code using binding:

def foo(binding)   binding.eval "x = 2" end  x = 1 foo(binding) p x     # => 2 

blocks carry them binding in defined, if block being passed, then:

def foo(&block)   block.binding.eval "x = 2" end  x = 1 foo {} p x     # => 2 

what's in block doesn't matter, in case. it's being used carrier binding.

other ways achieve same goal

yield object

a more pedestrian way block interact it's caller pass object block:

class point   attr_accessor :x   attr_accessor :y end  class location    def set     point = point.new     yield point     p point.x    # => 10     p point.y    # => 20   end  end  location = location.new location.set |point|   point.x = 10   point.y = 20 end 

this preferred fancier techniques: it's easy understand both implementation , use.

instance_eval object

if want (but shouldn't want to), block's caller can use instance_eval/instance_exec call block. sets self object, block.

class location    def set(&block)     point = point.new     point.instance_eval(&block)     p point.x    # => 10     p point.y    # => 20   end  end  location = location.new location.set   self.x = 10   self.y = 20 end 

you see block had use use self. when calling writers, otherwise new, local variables have been declared, not wanted here.

yield or instance_eval object

even though still shouldn't use instance_eval, it's useful. don't know when it's good, though, let's let method's caller decide technique use. method has check block has parameters:

class location    def set(&block)     point = point.new     if block.arity == 1       block.call point     else       point.instance_eval(&block)     end     p point.x     p point.y   end  end 

now user can have block executed in scope of point:

location = location.new location.set   self.x = 10   self.y = 20 end # => 10 # => 20 

or can have point passed it:

location.set |point|   point.x = 30   point.y = 40 end # => 30 # => 40 

Comments

Popular posts from this blog

database - VFP Grid + SQL server 2008 - grid not showing correctly -

jquery - Set jPicker field to empty value -

.htaccess - htaccess convert request to clean url and add slash at the end of the url -