Ruby Struct and OpenStruct classes
Vinicius Negrisolo Ruby >
Ruby Struct
and OpenStruct
are two different classes that handle to keep some data into a class instance. Although they have similar name and features they are actually very different in usage. Let’s highlight the differences between these two classes and find out the best scenarios for using each one.
First the Similarities
Both Struct and OpenStruct classes were made to handle some data into a instance of a class. In both instance created from Struct
or instance of OpenStruct
it is possible to:
- call its attributes using getter methods
- change attribute values using setter methods
- get attributes in hash style through a key that could be
String
orSymbol
- compare all keys and values using
==
method
Check this out:
PersonStruct = Struct.new(:name)
joe = PersonStruct.new('Joe')
joe.name
#=> Joe
joe[:name]
#=> Joe
joe['name']
#=> Joe
joe.name = 'Not Joe anymore'
joe.name
#=> Not Joe anymore
joe_one = PersonStruct.new('Joe')
joe_two = PersonStruct.new('Joe')
joe_one == joe_two
#=> true
require 'ostruct'
mary = OpenStruct.new(name: 'Mary')
mary.name
#=> Mary
mary[:name]
#=> Mary
mary['name']
#=> Mary
mary.name = 'Not Mary anymore'
mary.name
#=> Not Mary anymore
mary_one = OpenStruct.new(name: 'Mary')
mary_two = OpenStruct.new(name: 'Mary')
mary_one == mary_two
#=> true
Now let’s check the differences.
Struct
The Struct is a Ruby core class, so you don’t need to require it before usage.
First you define/initialize a Struct
passing to the new
method all acceptable attributes. At this point it’s also possible to define custom implementations, such as methods.
After that you can create instances passing to them the values in the same order as it was defined earlier on. Omitted values will be set as nil
.
You can use the methods members
and each_pair
to get all keys and values.
PersonStruct = Struct.new(:name, :age) do
def hi
"Hello #{name}!"
end
end
joe = PersonStruct.new('Joe', 29)
joe.age
#=> 29
joe.hi
#=> Hello Joe!
PersonStruct.new('Joe', 29).to_h
#=> {name: 'Joe', age: 29}
PersonStruct.new('Joe').to_h
#=> {name: 'Joe', age: nil}
joe.members
#=> [:name, :age]
joe.each_pair {|k, v| puts "key=#{k}, value=#{v}" }
#=> key=name, value=Joe
#=> key=age, value=29
OpenStruct
The OpenStruct is a Ruby stdlib class, so you need to require ostruct
before usage.
OpenStruct
is a simpler implementation than Struct
and in fact it looks like a wrapper for Hash
class. You initialize a OpenStruct
with a hash and that’s it, nothing more required.
It’s not possible to customize this object.
You can use the methods to_h
and each_pair
to get all keys and values, almost the same way as Struct
.
Finally it’s possible to remove an attribute from a OpenStruct
instance using delete_field
.
require 'ostruct'
mary = OpenStruct.new(name: 'Mary', age: 30)
mary.age
#=> 30
mary.to_h.keys
#=> [:name, :age]
mary.each_pair {|k, v| puts "key=#{k}, value=#{v}" }
#=> key=name, value=Mary
#=> key=age, value=30
mary.age = nil
mary.to_h
#=> {name: 'Mary', age: nil}
mary.delete_field(:age)
mary.to_h
#=> {name: 'Mary'}
Conclusion
Both classes Struct
and OpenStruct
seems to solve the same problem, but it’s important to know their differences very well for making wise choices:
- if you have unknown attribute keys then you’ll need the flexible that comes with
OpenStruct
- if you need some custom implementation, such as additional methods, you have to use
Struct
- otherwise you can basically choose any of these that you’ll be fine, so it’s just chose the preferred flavor