Я довольно новичок в Ruby, поэтому извиняюсь, если это очевидный вопрос.
Я хотел бы использовать именованные параметры при создании экземпляра Struct, т.е. иметь возможность указать, какие элементы в Struct получают то, чтозначения и по умолчанию остальные равны nil.
Например, я хочу сделать:
Movie = Struct.new :title, :length, :rating
m = Movie.new :title => 'Some Movie', :rating => 'R'
Это не работает.
Поэтому я придумал следующее:
class MyStruct < Struct
# Override the initialize to handle hashes of named parameters
def initialize *args
if (args.length == 1 and args.first.instance_of? Hash) then
args.first.each_pair do |k, v|
if members.include? k then
self[k] = v
end
end
else
super *args
end
end
end
Movie = MyStruct.new :title, :length, :rating
m = Movie.new :title => 'Some Movie', :rating => 'R'
Кажется, это работает просто отлично, но я не уверен, есть ли лучший способ сделать это, или я делаю что-то довольно безумное.Если кто-то может проверить / разорвать этот подход, я был бы очень признателен.
ОБНОВЛЕНИЕ
Я запустил это изначально в 1.9.2, и он отлично работает;однако, попробовав его в других версиях Ruby (спасибо rvm), он работает / не работает следующим образом:
- 1.8.7: не работает
- 1.9.1:Работает
- 1.9.2: Работает
- JRuby (установлен для запуска как 1.9.2): не работает
JRuby - проблема для меня, так как яхотелось бы, чтобы он был совместим с этим для целей развертывания.
ДАЛЕЕ ДРУГОЕ ОБНОВЛЕНИЕ
В этом постоянно растущем вопросе я экспериментировал с различными версиями Ruby иобнаружил, что Structs в 1.9.x хранит своих членов в виде символов, но в 1.8.7 и JRuby они хранятся в виде строк, поэтому я обновил код так, чтобы он был следующим (учитывая предложения, которые были любезно предоставлены):
class MyStruct < Struct
# Override the initialize to handle hashes of named parameters
def initialize *args
return super unless (args.length == 1 and args.first.instance_of? Hash)
args.first.each_pair do |k, v|
self[k] = v if members.map {|x| x.intern}.include? k
end
end
end
Movie = MyStruct.new :title, :length, :rating
m = Movie.new :title => 'Some Movie', :rating => 'R'
Теперь это работает для всех разновидностей Ruby, которые я пробовал.