Skip to main content

class_eval and instance_eval in Ruby

Created: August 29, 2017 2 min read

ClassName.instance_eval 添加类方法

def add_method_to1(klass)
  klass.instance_eval do
    def hello
      "hello!"
    end
  end
end

ClassName.class_eval 添加实例方法

def add_method_to2(klass)
  klass.class_eval  do
    def hello
      "hello!"
    end
  end
end

测试

class A

end

class B

end

add_method_to1(A)
A.hello # => "hello"
A.new.hello # => NoMethodError

add_method_to2(B)
B.hello # => NoMethodError
B.new.hello # =>  "hello"
  • ClassName.class_eval # 打开当前类,定义实例方法

  • ClassName.instance_eval # 打开当前类对象,定义类方法,类的单件方法

  • object.class_eval # NoMethodError

  • object.instance_eval # 在实例变量作用域中执行,在对象的上下文中执行一个块

The module_eval method is just an alias to class_eval so you can use them both for classes and modules. The instance_eval method works just like class_eval but it will add the behavior you’re trying to define to the object instance where it was called.

No, it isn’t. With class_eval we opened up a class definition and added code to it’s body. Any kind of code valid inside a class definition was also valid in there. When we’re using instance_eval the rules change a bit ‘cos we’re not opening up a class, but a single object instance.

class Dog
  attribute_accessor :name
end

dog = Dog.new
dog.name = 'Fido'

dog.instance_eval do
    #here I am defining a bark method only for this “dog” instance and not for the Dog class
  def bark
   puts 'Huf! Huf! Huf!'
  end

end

other_dog = Dog.new
other_dog.name = 'Dido'

puts dog.name
puts other_dog.name

dog.bark
other_dog.bark #this line will raise a NoMethodError as there’s no “bark” method
                      #at this other_dog object

用法总结

instance_eval

  • instance_eval 能访问对象内的实例变量和私有方法
  • instance_eval 在对象的上下文中执行代码块
  • 在类上调用instance_eval,创建类方法(类的单件方法, singleton_method)
  • 在对象上调用instance_eval,创建对象的单件方法,singleton_method

class_eval

  • class_eval 在一个类的上下文执行字符串或代码块,功能上好像重新打开类,然后插入了一些新的代码,在类的定义中,class和end关键字之间的所有代码都可以使用class_eval完成。

  • class_eval 作为单例方法被定义在模块类中,所以它只可以被模块或者类使用。

  • 当在执行class_evalinstance_eval方法时,变量self会被设置为接收者。

eval都用注入风险,可以使用exec替代

Resources

https://mauricio.github.io/2009/06/04/understanding-class_eval-module_eval-and-instance_eval.html

📢 In-Article Ad (Development Mode)

Comments

Share this article

Scan to read on mobile