【问题标题】:add instance method using open class to Object class in ruby?将使用开放类的实例方法添加到 ruby​​ 中的 Object 类?
【发布时间】:2017-10-22 19:43:57
【问题描述】:

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

class Operator

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

另一方面,我有 Criature 类

class Criature

    operational

    def level_up
        @level+=1
    end

end

我需要用公开课对Object 进行monkeypatch。

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

我该怎么做?

【问题讨论】:

  • 有一个module 然后include Operator 有什么问题?
  • 执行必须在 Operator 中,criatures 不是触发执行的,所以我也不能将实例作为参数传递。
  • 我说的是传统的Ruby mixin策略。当您include 一些代码时,执行上下文是它包含的实例。它成为该类的一部分,成为与其他任何实例方法一样的实例方法。
  • 是的,我知道,但是,通过这种方式,每次我执行“操作”方法(只有一个块作为参数,没有实例的副本)时,我该怎么做才能执行包含 mixin 的每个实例上的块?
  • 我不确定operation 方法的目的是什么。根据您的描述,听起来您想在代码中包含某种存根,您将在其中迭代给定类的所有实例并执行某种块?这是一种非常不寻常的实现方式,它肯定会出现问题。最好将实例聚合到集合、数组或某种容器中,这样迭代就明确而清晰,而不是神奇和神秘。

标签: ruby metaprogramming block


【解决方案1】:

执行一些对象的一些实例的代码块:

如果我很好理解,用方法

    operational

如果您想在 Criature 等某些类的主体中执行,您想标记它们的实例,并说“嘿,在执行 operation 时给我一个电话。”

来自The Pickaxe

ObjectSpace.each_object(‹ class_or_mod›)

为这个 Ruby 进程中的每个活的、非立即的对象调用一次块。如果指定了 class_or_mod,则只为与 class_or_mod 匹配(或者是其子类)的类或模块调用块。

使用ObjectSpace 可以迭代某个类的对象。这给了我一个想法,签名,你想给某些实例的这个标志,可以用一个超类来完成。

ObjectSpace.each_object(Operational)

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

文件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

【讨论】:

  • 用你的块调用编辑。
猜你喜欢
  • 2011-11-15
  • 2016-04-04
  • 1970-01-01
  • 2014-12-03
  • 1970-01-01
  • 2014-06-14
  • 2010-09-13
  • 1970-01-01
  • 2013-11-12
相关资源
最近更新 更多