Vous n'avez pas besoin de la constante, mais je ne pense pas que vous puissiez éliminer le passage d'un symbole à une chaîne :
class Example
attr_reader :name, :age
def initialize args
args.each do |k,v|
instance_variable_set("@#{k}", v) unless v.nil?
end
end
end
#=> nil
e1 = Example.new :name => 'foo', :age => 33
#=> #<Example:0x3f9a1c @name="foo", @age=33>
e2 = Example.new :name => 'bar'
#=> #<Example:0x3eb15c @name="bar">
e1.name
#=> "foo"
e1.age
#=> 33
e2.name
#=> "bar"
e2.age
#=> nil
BTW, vous pourriez jeter un coup d'œil (si vous ne l'avez pas déjà fait) à la rubrique Struct
classe générateur, c'est un peu similaire à ce que vous faites, mais pas d'initialisation de type hash (mais je suppose qu'il ne serait pas difficile de faire une classe générateur adéquate).
HasProperties
En essayant de mettre en œuvre l'idée de hurikhan, voici ce à quoi je suis arrivé :
module HasProperties
attr_accessor :props
def has_properties *args
@props = args
instance_eval { attr_reader *args }
end
def self.included base
base.extend self
end
def initialize(args)
args.each {|k,v|
instance_variable_set "@#{k}", v if self.class.props.member?(k)
} if args.is_a? Hash
end
end
class Example
include HasProperties
has_properties :foo, :bar
# you'll have to call super if you want custom constructor
def initialize args
super
puts 'init example'
end
end
e = Example.new :foo => 'asd', :bar => 23
p e.foo
#=> "asd"
p e.bar
#=> 23
Comme je ne suis pas très compétent en matière de métaprogrammation, j'ai fait de la réponse un wiki communautaire, de sorte que tout le monde est libre de modifier l'implémentation.
Struct.hash_initialized
En complément de la réponse de Marc-André, voici un générique, Struct
pour créer des classes initialisées par le hash :
class Struct
def self.hash_initialized *params
klass = Class.new(self.new(*params))
klass.class_eval do
define_method(:initialize) do |h|
super(*h.values_at(*params))
end
end
klass
end
end
# create class and give it a list of properties
MyClass = Struct.hash_initialized :name, :age
# initialize an instance with a hash
m = MyClass.new :name => 'asd', :age => 32
p m
#=>#<struct MyClass name="asd", age=32>