monkey patching vs class_eval?

可紊 提交于 2019-11-30 11:35:17

With class_eval you can do more dynamic things:

>> met = "hello" #=> "hello"
>> String.class_eval "def #{met} ; 'hello' ; end" #=> nil
>> "foo".hello #=> "hello"

class_eval do conceptually class reopening (or monkey patching). There are mostly syntactic differences. If you pass string to class_eval (as in Michael's example) you have mostly the same syntax inside the string as in class String; ... end. If you pass block: String.class_eval { ... } it compares as follows:

  • inside class_eval block outer local variables are visible
  • inside reopened class outer local variables are NOT visible
  • inside class_eval you CANNOT assign constants and class variables scoped to the class
  • inside reopened class you CAN

It would be interesting to know the other differences

akostadinov

Other answers are good. Want to add that class_eval can be used when you want reference class not by its constant or to patch particular object.

e.g.

huh = String
class huh
end
SyntaxError: (eval):2: class/module name must be CONSTANT

huh.class_eval <<-eof
def mamma
puts :papa
end
eof

"asdff".mamma
=> papa

You can use class_eval to patch particular object without affectin whole root class.

obj = "asd"
obj.singleton_class.class_eval <<-eof
def asd
puts "gah"
end
undef_method :some_method

The above is same as:

class << obj
  ...
end

instance_eval will have slightly different behavior by some usage.

I find this question and answers interesting: How to monkey patch a ruby class inside a method

Also there were questions about instance_eval vs class_eval but I don't have a link handy.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!