Метод создания методов: простое метапрограммирование на Ruby - PullRequest
4 голосов
/ 18 мая 2010

У меня есть несколько методов, подобных этому, в помощнике по представлению

  def background
    "#e9eaec"
  end
  def footer_link_color
    "#836448"
  end

Мне бы хотелось, чтобы эти методы были доступны для представления, но я бы предпочел, чтобы помощник был немного более кратким. Какой лучший способ превратить хеш, скажем, в методы (или что-то еще)?

Ответы [ 4 ]

3 голосов
/ 18 мая 2010

Если вы создаете константы в пространстве имен, то вы можете легко получить доступ к таким константам:

class Foo

  module Values
    FOO = 1
    BAR = 'bar'
    BAZ = :baz
  end
  include Values

  Values.constants.each do |name|
    define_method(name.downcase) do
      Values.const_get(name)
    end
  end

end

foo = Foo.new
p foo.foo    # => 1
p foo.bar    # => "bar"
p foo.baz    # => :baz

include Values смешивает константы в Foo для удобства собственных методов Foo. Этот шаблон не нужен для работы.

3 голосов
/ 18 мая 2010
module MyHelper
  {:background => "#e9eaec", :footer_link_color => "#836448"}.each do |k,v|
    define_method(k) {v}
  end
end

Хотя я не думаю, что обмен этой краткости на удобочитаемость вашего первого подхода - это, безусловно, хорошая идея.

Если вы хотите обобщить это, вы можете добавить следующий метод в класс Module:

class Module
  def methods_from_hash(hash)
    hash.each do |k,v|
      define_method(k) {v}
    end
  end
end

А потом в вашем помощнике позвоните methods_from_hash(:background => ...).

2 голосов
/ 23 мая 2010

На самом деле, в ruby ​​есть что-то под названием OpenStruct , что довольно здорово и действительно полезно, когда вы хотите использовать хеш, но не хотите использовать его как единое целое.

require 'ostruct'

colors = OpenStruct.new({:background => "0x00FF00", :color => "0xFF00FF"})

p colors.background #=> "0x00FF00"
0 голосов
/ 21 мая 2010

Вот мой ремикс на ответ sepp2k. Это немного больше ОО и работает даже в irb. Не уверен, стоит ли исправлять Object или Hash.

class Hash
  def keys_to_methods()
    each do |k,v|
      self.class.send(:define_method, k,  Proc.new {v});
    end
    length
  end
end

Тестовый код

hash = {:color_one=>"black", :color_two=>"green"}
hash.keys_to_methods
has.color_one # returns black

OpenStruct : еще раз спасибо sepp2k! Я не знал это существовало.

Вот еще одна версия, использующая method_missing

class Hash
  def method_missing(method_id)
    key = method_id.id2name
    if has_key?(key)
      return self[key]
    elsif has_key?(key.to_sym)
      return self[key.to_sym]
    else
      super.method_missing(method_id)
    end
  end
end

hash = {:color_one=>"black", :color_two=>"green"}
hash.color_one

Я уверен, что смог бы сделать код более плотным (если бы я знал, как).

...