Ruby методы создания из хеша - PullRequest
2 голосов
/ 11 марта 2011

У меня есть следующий код, который я использую, чтобы превратить коллекцию хешей в методы моих классов (что-то вроде активной записи).У меня проблема в том, что мой сеттер не работает.Я все еще новичок в Ruby и верю, что немного обернулся.

class TheClass
  def initialize
    @properties = {"my hash"}
    self.extend @properties.to_methods
  end
end

class Hash
  def to_methods
    hash = self
    Module.new do
      hash.each_pair do |key, value|
        define_method key do
          value
        end
        define_method("#{key}=") do |val|
          instance_variable_set("@#{key}", val)
        end
      end
    end
  end
end

Методы созданы, и я могу читать их в своем классе, но их установка не работает.

myClass = TheClass.new
item = myClass.property # will work.
myClass.property = item # this is what is currently not working.

Ответы [ 4 ]

6 голосов
/ 11 марта 2011

Если ваша цель - установить динамические свойства, вы можете использовать OpenStruct .

require 'ostruct'

person = OpenStruct.new
person.name = "Jennifer Tilly"
person.age = 52

puts person.name     
# => "Jennifer Tilly"
puts person.phone_number 
# => nil

Он даже имеет встроенную поддержку для создания их из хеша

hash = { :name => "Earth", :population => 6_902_312_042 }
planet = OpenStruct.new(hash)
4 голосов
/ 11 марта 2011

Ваш метод получения всегда возвращает значение в оригинальном хеше. Установка переменной экземпляра не изменит этого; вам нужно заставить getter обращаться к переменной экземпляра. Что-то вроде:

hash.each_pair do |key, value|
  define_method key do
    instance_variable_get("@#{key}")
  end
  # ... define the setter as before
end

И вам также нужно установить переменные экземпляра в начале, скажем, поставив

@properties.each_pair do |key,val|
  instance_variable_set("@#{key}",val)
end

в методе инициализации.

Примечание: я не гарантирую, что это лучший способ сделать это; Я не эксперт по Ruby. Но это работает.

2 голосов
/ 11 марта 2011

Это прекрасно работает для меня (конечно, после исправления очевидных синтаксических ошибок в вашем коде):

myClass.instance_variable_get(:@property) # => nil
myClass.property = 42
myClass.instance_variable_get(:@property) # => 42

Обратите внимание, что в экземпляре Ruby переменные всегда закрыты, и вы никогда не определяете для них метод получениятаким образом, вы не можете смотреть на них со стороны (кроме как через отражение), но это не значит, что ваш код не работает, это означает лишь то, что вы не видите, как он работает.

0 голосов
/ 11 марта 2011

Это по сути то, что я предлагал с method_missing.Я не достаточно знаком с любым из маршрутов, чтобы сказать, почему или почему бы не использовать его, поэтому я спросил выше.По сути, это автоматически сгенерирует свойства для вас:

def method_missing sym, *args
   name = sym.to_s
   aname = name.sub("=","")

   self.class.module_eval do 
      attr_accessor aname
   end
  send name, args.first unless aname == name
end
...