2

我知道 Ruby 提供了几个有用的钩子方法。但是,我似乎找不到像“ constant_added”钩子这样的东西。我想要一个的原因是因为我希望覆盖它,这样每当添加一个常量时,就可以执行某些其他操作来更新某些变量,而不必自己调用某种更新方法。

更具体地说,我试图保留与特定正则表达式匹配的所有现有常量的列表,但不循环遍历所有现有常量,以特定间隔搜索匹配项,或者在添加的最后一个常量与正则表达式匹配时更新列表;我相信这需要一个显式的方法调用。

如果钩子尚不存在,是否可以创建一个,如果没有,我该如何获得这种行为?

4

2 回答 2

1

我曾经在 Ruby 1.9 中使用Kernel.set_trace_func. 您可以继续检查"line"事件。每当发生此类事件时,使用该constants方法获取与前一次常量的差值。如果您检测到差异,那么这就是添加/删除常量的时刻。

Kernel.set_trace_func ->event, _, _, _, _, _{
  case event
  when "line"
    some_routine
  end
}

Ruby 2.0 可能有更强大的 API,它允许更直接的方式来做这件事,但我不确定。

于 2013-07-01T15:25:14.703 回答
0

所以我想我想出了一个替代方案:

class Object
  def typedef &block
    Module.new &block
  end
end

module Type
  @@types = []
  @@prev = Module.constants

  def self.existing_types
    diff = Module.constants - @@prev
    @@prev = Module.constants

    new_types = diff.select { |const| const.to_s.start_with? 'TYPE_' }

    @@types |= new_types
  end
end

我没有监控何时创建常量,而是在访问常量列表时对其进行处理。所以现在我可以做这样的事情:

irb(main):002:0> Type.existing_types
=> []
irb(main):003:0> TYPE_rock = typedef do
irb(main):004:1*   def self.crumble
irb(main):005:2>     puts "I'm crumbling! D:"
irb(main):006:2>   end
irb(main):007:1> end
=> TYPE_rock
irb(main):008:0> Type.existing_types
=> [:TYPE_rock]
irb(main):009:0> FOO_CONST = 54
=> 54
irb(main):011:0> TYPE_water = typedef do
irb(main):012:1*   def self.splash
irb(main):013:2>     puts "Water! :3"
irb(main):014:2>   end
irb(main):015:1> end
=> TYPE_water
irb(main):016:0> Type.existing_types
=> [:TYPE_rock, :TYPE_water]
irb(main):017:0> TYPE_rock.crumble
I'm crumbling! D:
=> nil
irb(main):018:0> TYPE_water.splash
Water! :3
=> nil

你怎么看?这完成了我想要的,而且相当简单,但我对 Ruby 还是很陌生,我不确定 Ruby 是否已经提供了一些不错的 API 来执行此操作。

于 2013-07-01T17:48:32.277 回答