May 21 2007

Ruby Struct

A Struct in Ruby is a convenient and elegant way to bundle attributes together without having to write a class with explicit accessor methods.

For example, let's look at a DTO used with a Rails ActionMailer class:

class EmailDto < Struct.new(:full_name, :email, :date); end

So in a Model we can have something along the lines of:

class Account < ActiveRecord::Base
  def activate
    self.active = true; self.save
    dto = EmailDto.new(self.full_name, self.email, Time.now)
    Notifier.deliver_activation_notification(dto)
  end
end

... with a Notifier that looks like:

class Notifier < ActionMailer::Base
  def activation_notification(dto)
    @recipients = dto.email
    @from = "newsletters@example.com"
    @subject = "Your account is now active!"
    @body[:content] = dto
  end
end

An interesting, more flexible/dynamic alternative to Struct is OpenStruct. OpenStruct allows the creation of data objects which accept arbitrary attributes at any time.

require 'ostruct'

flexie = OpenStruct.new(:music => 'rock')
flexie.bands = ['zep', 'sabbath']

flexie.music # => "rock"
flexie.bands.first # => "zep"

Of course, attributes can always be assigned blocks:

flexie.hello = Proc.new { puts 'hello world'}
flexie.hello.call # => hello world

In many cases, Structs can offer a more meaningful, more concrete alternative to aspects of what Hashes are currently popular for in Ruby.