Я новичок в 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, которые я пробовал.