Create struct-like classes that don't have setters, but have an awesome constructor.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
.circleci
lib
spec
.gitignore
.ruby-gemset
.ruby-version
.travis.yml
CODE_OF_CONDUCT.md
CONTRIBUTING.md
Gemfile
LICENSE.txt
README.rdoc
Rakefile
build-matrix.json
immutable-struct.gemspec
owners.json

README.rdoc

ImmutableStruct

Build Status

Creates struct-like classes (that can build value objects) that do not have setters and also have better constructors than Ruby's built-in Struct.

This is highly useful for creating presenters, non-database-related models, or other quick and dirty classes in your application. Instead of using a Hash or OpenStruct, you can create a bit more clarity around your types by using ImmutableStruct, which is almost as convienient.

Install

Add to your Gemfile:

gem 'immutable-struct'

Then install:

bundle install

If not using bundler, just use RubyGems:

gem install immutable-struct

To use

Person = ImmutableStruct.new(:name, :age, :job, :active?, [:addresses]) do
  def minor?
    age < 18
  end
end

p = Person.new(name: "Dave",   # name will be 'Dave'
               age: 40,        # age will be 40
                               # job is omitted, so will be nil
               active: true)   # active and active? will be true
                               # addresses is omitted, but since we've selected
                               # Array coercion, it'll be []
p.name      # => "Dave"
p.age       # => 40
p.active?   # => true
p.minor?    # => false
p.addresses # => []

p2 = Person.new(name: "Dave", age: 40, active: true)

p == p2     # => true
p.eql?(p2)  # => true

SimilarPerson = ImmutableStruct.new(:name, :age, :job, :active?, [:addresses])

sp = SimilarPerson.new(name: "Dave", age: 40, active: true)

p == sp     # => false         # Different class leads to inequality

new_person = p.merge(name: "Other Dave", age: 41) # returns a new object with merged attributes
new_person.name    # => "Other Dave"
new_person.age     # => 41
new_person.active? # => true

You can treat the interior of the block as a normal class definition with the exception of setting constants. Use const_set to scope constants as-expected.

Point = ImmutableStruct.new(:x, :y) do
  const_set(:ZERO, 0)
  ONE_HUNDRED = 100
end
Point::ZERO # => 0
::ONE_HUNDRED # => 100
::ZERO # => NameError: uninitialized constant ZERO

Links