No commit activity in last 3 years
No release in over 3 years
Immutable value objects using Ruby Structs
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 0
>= 0
 Project Readme

ValueObjectStruct¶ ↑

The ValueObjectStruct module uses Ruby’s native Struct class to facilitate the declaration of immutable value object classes.

ValueObjectStruct classes are defined with ValueObjectStruct.class_with_attributes and a list of member attributes specified by Symbol. Like Struct classes, they may be assigned to a constant or variable, or used in a superclass declaration.

ValueObjectStruct instances are Struct instances with private attribute write access, including both named attribute writers and Hash or Array style bracketed subscript assignment. ValueObjectStruct instances created with ::value (as opposed to ::new or ::for_values) are frozen, so that attribute values may not be reassigned after initialization, even by private methods.

ValueObjectStruct instances do not enforce immutability of attribute values themselves, so it may be desirable to freeze mutable value types such as String, Array and Hash before using them to initialize an instance.

As Struct instances, ValueObjectStruct instances provide equality and hash semantics via #== and #hash. #empty? returns true for value object instances with no non-nil attribute values.

ValueObjectStruct instances provide an #attributes and #attribute method for compatibility with ActiveModel. #attributes returns a hash representation of attribute values. #attribute is an alias for #[].

Example¶ ↑

class Address < ValueObjectStruct.class_with_attributes(:street,:zip); end
address = Address.new(street: "123 Main", zip: 11211)

address.street   = "123 Maple" # raises NoMethodError
address[:street] = "456 Elm"   # raises NoMethodError
address[1]       = "789 Pine"  # raises NoMethodError

address == Address.new(street: "123 Main", zip: 11211)  # => true
address == Address.new(street: "123 Maple", zip: 11211) # => false

set = Set[address]
set.include? Address.new(street: "123 Main", zip: 11211) # => true
set.include? Address.new(street: "123 Main", zip: 11212) # => false

Copyright © 2012 Riley Lynch, Teleological Software, LLC. See LICENSE.txt for further details.