Reputation: 5233
Is it possible to create attribute dynamicaly in the Struct
instance?
class Person < Struct.new(:name)
end
p = Person.new("Bilbo")
p[:surname] = "Jenkins" # does not work
Upvotes: 7
Views: 1788
Reputation: 110755
You can subclass Struct
, in which case you will be creating two classes, but it is more common to just create one:
Person = Struct.new(:name)
Person.instance_methods(false)
#=> [:name, :name=]
p = Person.new("Bilbo")
#=> #<struct Person name="Bilbo">
Does `p` have an instance variable `@name` whose value is `"Bilbo"`?
p.instance_variables
#=> []
No, it does not. Rather, it has "members":
p.members
#=> [:name]
Can name
be treated as an instance variable with the accessors provided by Struct
?
p.name
#=> "Bilbo"
p.name = "cat"
p.name
#=> "cat"
Yes! That's because the members of a Struct
instance are stored in array that you are not intended to access directly, only through the accessors.
Can we add Struct
members dynamically? I don't know the answer to that, but methods are not provide to do that easily. Instead, just add instance variables and, optionally, accessors.
We can add an instance variable and set its value with:
p.instance_variable_set('@surname', 'Jenkins')
#=> "Jenkins"
p.instance_variables
#=> [:@surname]
and retrieve its value with:
p.instance_variable_get('@surname')
#=> "Jenkins"
If you wish to create accessors for that variable, this is one way:
p.class.instance_eval do
attr_accessor :surname
end
p.surname
#=> "Jenkins"
p.surname = 'cat'
#=> "cat"
p.surname
#=> "cat"
p.class.instance_methods(false)
#=> [:name, :name=, :surname, :surname=]
Upvotes: 1
Reputation: 35493
You can define new methods on your Person
class by doing this:
Person.send(:define_method, :surname){@surname}
Person.send(:define_method, :surname=){|x|@surname=x}
I prefer define_method
instead of instance_eval
because I try to omit eval
when possible.
Upvotes: 1
Reputation: 12568
You could use an OpenStruct
:
require 'ostruct'
p = OpenStruct.new(name: "Bilbo")
p[:surname] = "Jenkins"
p.surname # => "Jenkins"
Upvotes: 3