将使用 open class 的实例方法添加到 ruby 中的对象 class?

add instance method using open class to Object class in ruby?

我有一个 class Operator 执行其他对象的某些实例的代码块:

class Operator

    def operation(&block)
        #execution of a block in some object
    end
end

另一方面,我有 class 签名

class Criature

    operational

    def level_up
        @level+=1
    end

end

我需要用 open class.

对 class Object 进行 monkeypatch

所以,我需要在 Object 中定义方法 operational ,因为每次 Operator 的实例执行 operation 时,(例如)块:{ c.level_up() } 将在其 class 主体中为每个带有 operational 的实例执行。

我该怎么做才能做到这一点?

executes a block of code of some instances of some objects:

如果我很好理解,用方法

    operational

你想在一些 class 的主体中执行,比如 Criature,你想标记他们的实例,说“嘿,当 operation 是时给我打电话执行。"

来自 The Pickaxe :

ObjectSpace.each_object( ‹ class_or_mod› )

Calls the block once for each living, nonimmediate object in this Ruby process. If class_or_mod is specified, calls the block for only those classes or modules that match (or are a subclass of) class_or_mod.

使用 ObjectSpace 可以迭代某个 class 的对象。这让我想到可以使用 superclass.

来完成签名,即您想给某些实例的标志。
ObjectSpace.each_object(Operational)

将收集具有此“签名”的 classes 的所有实例。

文件tc.rb:

class Operational
    
end

class Criature < Operational
    def initialize(p_name)
        @name  = p_name
        @level = 0
    end
        
    def level_up
        @level+=1
        puts "level is now #{@level}"
    end
end

class XYZ < Operational
    def initialize(p_name)
        @name = p_name
    end
    
end

文件to.rb:

require_relative 'tc'

class Operator

    def operation(&block)
        #execution of a block in some object
        Special.currently_operational.each do | obj |
            puts "operation on #{obj.inspect}"
            block.call(obj) if obj.respond_to? 'level_up'
        end
    end
end

class Special
    def self.currently_operational
        operationals = []

        ObjectSpace.each_object(Operational) do | object |
            operationals << object
        end

        puts "#{operationals.size} objects are flagged as operational"
        operationals
    end
end

Criature.new('c1')
Criature.new('c2')
Criature.new('c3')

block = Proc.new{ | x | x.level_up }
puts 'first round'
Operator.new.operation(&block)

# later ...
XYZ.new('x1')
XYZ.new('x2')

puts 'second round'
Operator.new.operation(&block)

执行:

$ ruby -w to.rb 
first round
3 objects are flagged as operational
operation on #<Criature:0x007fc45683d2f0 @name="c3", @level=0>
level is now 1
operation on #<Criature:0x007fc45683d368 @name="c2", @level=0>
level is now 1
operation on #<Criature:0x007fc45683d3b8 @name="c1", @level=0>
level is now 1
second round
5 objects are flagged as operational
operation on #<XYZ:0x007fc45683cad0 @name="x2">
operation on #<XYZ:0x007fc45683cb48 @name="x1">
operation on #<Criature:0x007fc45683d2f0 @name="c3", @level=1>
level is now 2
operation on #<Criature:0x007fc45683d368 @name="c2", @level=1>
level is now 2
operation on #<Criature:0x007fc45683d3b8 @name="c1", @level=1>
level is now 2