分享 Understanding instance exec in ruby

rubyu2 · 2015年04月10日 · 2090 次阅读

Understanding instance exec in ruby

  • 在 procs 中有上下文

    square = lambda { x * x }
    x = 20
    puts square.call()
    # => undefined local variable or method `x' for main:Object (NameError)
    
    • 定义 proc 时,需要保证里面的变量已经定义 ruby x = 2 square = lambda { x * x } x = 20 puts square.call() # => 400 上面得出结果是 400,而不是 4,是因为 proc 定义时只是 binding 了上下文的变量 x,并不是 x 的值。
    • 可以是方法 ruby square = lambda { x * x } def x 20 end puts square.call() # => 400 binding is smart enough to figure out that since no x variable is present,这里方法可以后定义。
    • lexical binding in procs ruby def square(p) x = 2 puts p.call end x = 20 square(lambda { x * x }) #=> 400 > In the above case the value of x is set as 20 at the code compile time. Don’t get fooled by x being 2 inside the method call. Inside the method call a new scope starts and the x inside the method is not the same x as outside .

proc 只跟当前上下文的变量绑定

  • Issues because of lexical scoping ```ruby class Person code = proc { puts self }

define_method :name do code.call() end end

class Developer < Person end

Person.new.name # => Person Developer.new.name # => Person

> In the above case when Developer.new.name is executed then output is Person. And that can cause problem. For example in Ruby on Rails at a number of places self is used to determine if the model that is being acted upon is STI or not. If the model is STI then for Developer the query will have an extra where clause like AND "people"."type" IN ('Developer') . So we need to find a solution so that self reports correctly for both Person and ‘Developer` .

- instance_eval can change self
```ruby
class Person
  code = proc { puts self }

  define_method :name do
    self.class.instance_eval &code
  end
end

class Developer < Person
end

Person.new.name #=> Person
Developer.new.name #=> Developer

但是 instance_eval 不能接受参数

class Person
  code = proc { |greetings| puts greetings; puts self }

  define_method :name do
    self.class.instance_eval 'Good morning', &code
  end
end

class Developer < Person
end

Person.new.name
Developer.new.name

#=> wrong number of arguments (1 for 0) (ArgumentError)
  • instance_exec to rescue ```ruby class Person code = proc { |greetings| puts greetings; puts self }

define_method :name do self.class.instance_exec 'Good morning', &code end end

class Developer < Person end

Person.new.name #=> Good morning Person Developer.new.name #=> Good morning Developer

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册