[英]ruby monkey patching on the fly
Is there a way to implement monkey patching while an object is being instantiated?有没有办法在实例化对象时实现猴子补丁?
When I call:当我打电话时:
a = Foo.new
Prior to the instance being instantiated, I would like to extend the Foo class based on information which I will read from a data store.在实例化实例之前,我想根据我将从数据存储中读取的信息扩展 Foo 类。 As such, each time I call Foo.new
, the extension(s) that will be added to that instance of the class would change dynamically.因此,每次我调用Foo.new
,将添加到该类实例的扩展Foo.new
动态更改。
tl;dr: Adding methods to an instance is possible. tl;dr:可以向实例添加方法。
Answer: Adding methods to an instance is not possible.答:无法向实例添加方法。 Instances in Ruby don't have methods. Ruby 中的实例没有方法。 But each instance can have a singleton class, where one can add methods, which will then be only available on the single instance that this singleton class is made for.但是每个实例都可以有一个单例类,可以在其中添加方法,然后这些方法只能在为该单例类创建的单个实例上可用。
class Foo
end
foo = Foo.new
def foo.bark
puts "Woof"
end
foo.bark
class << foo
def chew
puts "Crunch"
end
end
foo.chew
foo.define_singleton_method(:mark) do
puts "Widdle"
end
foo.mark
are just some of the ways to define a singleton method for an object.只是为对象定义单例方法的一些方法。
module Happy
def cheer
puts "Wag"
end
end
foo.extend(Happy)
foo.cheer
This takes another approach, it will insert the module between the singleton class and the real class in the inheritance chain.这采用了另一种方法,它将在继承链中的单例类和真实类之间插入模块。 This way, too, the module is available to the instance, but not on the whole class.这样,模块也可用于实例,但不能用于整个类。
Sure you can!你当然可以!
method_name_only_known_at_runtime = 'hello'
string_only_known_at_runtime = 'Hello World!'
test = Object.new
test.define_singleton_method(method_name_only_known_at_runtime) do
puts(string_only_known_at_runtime)
end
test.hello
#> Hello World!
Prior to the instance being instantiated, I would like to extend在实例化实例之前,我想扩展
Given a class Foo
which does something within its initialize
method:给定一个类Foo
,它在其initialize
方法中执行某些操作:
class Foo
attr_accessor :name
def initialize(name)
self.name = name
end
end
And a module FooExtension
which wants to alter that behavior:还有一个模块FooExtension
想要改变这种行为:
module FooExtension
def name=(value)
@name = value.reverse.upcase
end
end
You could patch it via prepend
:您可以通过prepend
修补它:
module FooPatcher
def initialize(*)
extend(FooExtension) if $do_extend # replace with actual logic
super
end
end
Foo.prepend(FooPatcher)
Or you could extend
even before calling initialize
by providing your own new
class method:或者您甚至可以在调用initialize
之前通过提供您自己的new
类方法进行extend
:
class Foo
def self.new(*args)
obj = allocate
obj.extend(FooExtension) if $do_extend # replace with actual logic
obj.send(:initialize, *args)
obj
end
end
Both variants produce the same result:两种变体产生相同的结果:
$do_extend = false
Foo.new('hello')
#=> #<Foo:0x00007ff66582b640 @name="hello">
$do_extend = true
Foo.new('hello')
#=> #<Foo:0x00007ff66582b280 @name="OLLEH">
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.