Reputation: 26212
I found this interesting answer :
https://stackoverflow.com/a/2348854/169277
This is ok when you're trying to set instance variables it works really great.
Is there a way to apply the same logic or better one to create generic constructor like :
def initialize(obj)
obj.each do |k,v|
#find the setter for each k and set the value v to and return newly created object
end
end
If I had object TestObject
:
class TestObject
attr_accessor :name, :surname, :sex
end
I was thinking to create it something like this:
TestObject.new({:name => 'Joe', :surname => 'Satriani'})
How would one achieve this?
So doing this would be a shorthand of :
t = TestObject.new
t.name = 'Joe'
t.surname = 'Satriani'
Upvotes: 0
Views: 1738
Reputation: 369458
I think it would be better to use keyword arguments for this. After all, the Hash
keys are guaranteed to be valid Ruby identifier Symbol
s since they need to match up with method names. You don't need the capability to pass in arbitrary Ruby objects as keys of the Hash
.
def initialize(**attrs)
attrs.each do |attr, value| send(:"#{attr}=", value) end
end
TestObject.new(name: 'Joe', surname: 'Satriani')
Upvotes: 0
Reputation: 62648
Sure, you can use send to send arbitrary messages to an object. Since we're operating on self
here, we can just invoke send
directly.
def initialize(obj)
obj.each do |k,v|
send(:"#{k}=", v)
end
end
For example, TestObject.new({:name => 'Joe'})
will call send "name=", "Joe"
.
Upvotes: 1
Reputation: 29880
You can inherit from Struct to make a simple object, and then pass in the attributes to the initializer:
class TestObject < Struct.new(:name, :surname, :sex)
end
TestObject.new('Joe', 'Satriani') #=> sex will be nil
You can use OpenStruct to make quick value objects with arbitrary attributes:
t = OpenStruct(name: 'Joe', surname: 'Satriani')
You can include a module like Virtus: https://github.com/solnic/virtus
Or you can do what Chris Heald said.
Upvotes: 1