在运行时获取/设置Ruby方法元数据的最佳策略是什么?

时间:2009-01-14 14:33:21

标签: ruby extension-methods metaprogramming metadata

我有一个有一些方法的课。这是超级巨星,但我已经复制了我能在这里发现的东西。

Class RayGun
  # flashes red light
  # requires confirmation
  # makes "zowowowowowow" sound
  def stun!
    # ...
  end

  # flashes blue light
  # does not require confirmation
  # makes "trrrtrtrtrrtrtrtrtrtrtr" sound
  def freeze!
    # ...
  end

  # doesn't flash any lights
  # does not require confirmation
  # makes Windows startup sound
  def killoblast!
    # ...
  end
end

我希望能够在运行时查询有关其中一个方法的类,并接收类似的哈希或结构:

  {:lights => 'red', :confirmation => false, :sound => 'windows'}

这样做的最佳方法是什么?显然你可以同时拥有单独的YAML文件,并设置一个约定两者的约定,但理想情况下我想在一个地方使用代码和元数据。

我能提出的最有希望的想法是这样的:

class RayGun
  cattr_accessor :metadata
  def self.register_method(hsh)
    define_method(hsh.name, hsh.block)
    metadata[hsh[:name]] = hsh
  end

  register_method({
    :name => 'stun!', 
    :lights => 'red', 
    :confirmation => 'true', 
    :sound => 'zowowo',
    :block => Proc.new do
      # code goes here
   })

   # etc.
end

有人有更好的想法吗?我咆哮着一棵非常错的树吗?

3 个答案:

答案 0 :(得分:2)

只是一点点美化:

class RayGun
  cattr_accessor :metadata
  def self.register_method(name, hsh, &block)
    define_method(name, block)
    metadata[name] = hsh
  end

  register_method( 'stun!',
    :lights => 'red', 
    :confirmation => 'true', 
    :sound => 'zowowo',
    ) do
      # code goes here
  end

   # etc.
end

您确实无法轻松访问原始闭包,但可能不需要它。

要回答这个问题,它看起来并不坏,你可以做一些更多的会议,但可能已经足够好了:

class RayGun
  cattr_accessor :metadata

  @metadata[:stun!] = {:lights => 'red', 
                        :confirmation => 'true', 
                        :sound => 'zowowo'}
  def stun!
    # ...
  end

   # etc.
end

在原始示例中,register_method是公共的,如果您计划以这种方式使用它,则第二个选项变得不那么有用,因为它不能确保一致性。

答案 1 :(得分:2)

我找到了围绕http://github.com/wycats/thor/tree的另一个策略。 Thor让你写这样的东西:

Class RayGun < Thor
  desc "Flashes red light and makes zowowowowow sound"
  method_options :confirmation => :required
  def stun!
    # ...
  end
end

它通过使用(未记录的)钩子Module#method_added来管理它。它的工作原理如下:

  1. 致电Thor#descThor#method_options设置实例 变量@desc@method_options

  2. 定义方法stun!调用 Thor#method_added(meth)

  3. Thor#method_added个寄存器 Task.new(meth.to_s, @desc, @method_options)(粗略地说) 并取消@desc@method_options

  4. 现在已经为下一个方法做好了准备

  5. 纯!如此整洁,我将接受我自己的答案:)

答案 2 :(得分:1)

YARD工具可让您向方法添加元数据。我很确定它只是将元数据粘贴到您生成的rdoc文件中,但您可以轻松地构建它以获取运行时信息。