美文网首页
Understanding instance exec in r

Understanding instance exec in r

作者: orcl_zhang | 来源:发表于2015-07-18 11:33 被阅读79次

    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时,需要保证里面的变量已经定义
    x = 2
    square = lambda { x * x }
    x = 20
    puts square.call()
    # => 400
    

    上面得出结果是400,而不是4,是因为proc定义时只是binding了上下文的变量x,并不是x的值。

    • 可以是方法
    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
    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
    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
    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
    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
    

    相关文章

      网友评论

          本文标题:Understanding instance exec in r

          本文链接:https://www.haomeiwen.com/subject/vlrpqttx.html