A few months ago I created a custom class to enhance the base Ruby Struct
object. What I needed for my Whois
library was the ability to create a new instance from a Hash
.
Loser = Struct.new(:id, :name)
Winner = SuperStruct.new(:id, :name)
# The default Struct accepts up to N arguments
# where N is the total number of elements defined in the Struct.
Loser.new(:id => "1", :name => "John Doe")
# => #<struct Loser id={:name=>"John Doe", :id=>"1"}, name=nil>
Winner.new(:id => "1", :name => "John Doe")
# => #<struct Winner id="1", name="John Doe">
Because the first argument is mapped to the :id
element, the Hash
is stored as value for the id attribute.
In a standard Ruby Struct
I have to map each Hash
value to the specific position in the Struct
, loosing the flexibility of passing a Hash
with optional keys.
hash = { :name => "John Doe" }
Loser.new(hash)
# => #<struct Loser id={:name=>"John Doe"}, name=nil>
Loser.new(nil, hash[:name])
# => #<struct Loser id=nil, name="John Doe">
Winner.new(hash)
# => #<struct Winner id=nil, name="John Doe">
Also, I'd like to be able to pass a block to the initialize
method and yield
on self
.
Loser.new do |c|
c.name = "John Doe"
end
# => #<struct Loser id=nil, name=nil>
# Name is not set
Winner.new do |c|
c.name = "John Doe"
end
# => #<struct Winner id=nil, name="John Doe">
# Hurra! Name is set!
I called it RubyStruct
. It was created for the Ruby Whois, but ultimately I found myself using it quite often in my projects and I decided to package it in a single file along with a basic test suite.
Here's the library.