Какова лучшая стратегия получения / установки метаданных для методов Ruby во время выполнения? - PullRequest
2 голосов
/ 14 января 2009

У меня есть класс с некоторыми методами. Это суперсекрет, но я воспроизвел то, что я могу здесь.

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 ]

2 голосов
/ 26 марта 2009

Я обнаружил, что еще одна стратегия - http://github.com/wycats/thor/tree. Тор позволяет вам писать такие вещи:

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

Управляет этим с помощью (недокументированного) хука Module#method_added. Это работает так:

  1. Позвоните на Thor#desc и Thor#method_options установить экземпляр переменные @desc, @method_options.

  2. Определение метода stun! вызовы Thor#method_added(meth)

  3. Thor#method_added регистров Task.new(meth.to_s, @desc, @method_options) (грубо говоря) и unsets @desc, @method_options.

  4. Теперь все готово к следующему методу

Ухоженная! Настолько аккуратно, что я приму свой ответ :) 1037 *

2 голосов
/ 14 января 2009

Просто немного красоты:

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 голос
/ 14 января 2009

Существует инструмент YARD , который позволяет добавлять метаданные к методам. Я почти уверен, что метаданные просто вставляются в генерируемые вами файлы rdoc, но вы легко можете использовать их для получения информации времени выполнения.

...