Sonntag, 21. Dezember 2014

Structure Ruby objects with Structs!

Decomposing fatty degenerated classes into several concerning classes makes sense in any case. Breaking them apart following the single responsibility pattern leads to new classes, each one easy to read, maintain and a pleasure to deal with others.
Sometimes it is very convenient to define one dynamically or it just should be a structure able to receive a few messages. Then the Ruby Struct comes into play.
Creating a Struct object is as easy as:
Struct.new 'Food', :name, :kcal
food = Struct::Food.new 'Apple', 52
=> #<struct Struct::Food name="Apple", kcal=52>
and it has the 2 defined accessors name and kcal:
food.name
=> "Apple"
food.name = 'Pea'
=> "Pea"
food[:kcal] = 57
=> 57
Adding a receiver message goes like:
Struct.new 'Food', :name, :kcal do
  def to_s
    "#{name} (#{kcal})"
  end
end
food = Struct::Food.new 'Apple', 52
food.to_s
=> "Apple (52)"
More practice-focused is inheriting from Struct:
class Food < Struct.new(:name, kcal)
  def to_s
    "#{name} (#{kcal})"
  end
end
and:
food = Food.new 'Apple', 52
food.to_s
=> "Apple (52)"
Whoever argues inheriting from an instance can not be possible: Struct#new returns a class. That is why this also works nice:
Food = Struct.new :name, :kcal
food = Food.new 'Apple'
=> #<struct Food name="Foo", kcal=nil>
food.kcal = 52
A Struct class was assigned to the constant Food. It is possible because classes are just constants.
Please note the difference between the namespaced Struct::Food class in the first example and this Food class.
Structs can be incredible convenient.

Supported by Ruby 2.1.1