Value Struct
¶ ↑
A value struct is a subclass of the normal Ruby struct that behaves almost the same. However, it has a major difference:
Value structs are immutable, i.e. they don't have setters (although, not recursively*)
Additionally, this gem provides the following optional mixins to make life easier when using immutable structs:
-
:dup_with_changes Extends
#dup
to take a optional hash for setting new values in the duplicate -
:strict_arguments Value structs need to be initialized with the exact amount of arguments
-
:freeze Automatically freezes new instances
-
:no_clone Alters
#clone
to return the same object
By default, only :dup_with_changes will be included.
Without mixins, ValueStructs are almost as fast as normal structs. Some mixins add noticable overhead, e.g. strict_arguments
Why?¶ ↑
See this blog article for more information.
Example 1¶ ↑
require 'value_struct' SimplePoint = ValueStruct.new(:x, :y)
Please refer to the documentation of Ruby’s struct for more details on general struct usage.
How to use structs with mixins¶ ↑
Point = ValueStruct.new_with_mixins :x, :y, [ :freeze, :dup_with_changes, :strict_arguments, ] p = Point.new(1,2) p.frozen? #=> true p.dup(x: 0) #=> #<ValueStruct Point x=0, y=2> Point.new(1) # ArgumentError
Alternatively, you can put custom modules in the mixin array.
Example 2¶ ↑
require 'value_struct' Point = ValueStruct.new_with_mixins( :x, :y, [:dup_with_changes, :freeze, :no_clone], ) do def initialize(x,y) raise ArgumentError, 'points must be initialized with two numerics' unless x.is_a?(Numeric) && y.is_a?(Numeric) super(x,y) end def abs ( x**2 + y**2 ) ** 0.5 end def +(o) dup(x: x + o.x, y: y + o.y) end def -(o) dup(x: x - o.x, y: y - o.y) end def +@ self end def -@ dup(x: -x, y: -o.y) end def to_c Complex(x,y) end def to_s "(#{x},#{y})" end alias inspect to_s end
*¶ ↑
Because of the nature of Ruby, most things are not really immutable. So if you have an attribute :by
and initialize it with an array, you cannot change the value struct anymore, but still the array:
Ru = ValueStruct.new(:by) ruby = Ru.by([1,2,3]) ruby.by # => [1,2,3] ruby.by = [1,2,3,4] # not possible ruby.by << 4 # possible
Install¶ ↑
$ gem install value_struct
Influenced by / Thanks to¶ ↑
-
Tom Crayford: Values
-
Theo Hultberg: ImmutableStruct
-
Ruby Rogues
J-_-L¶ ↑
Copyright © 2012-2015 Jan Lelis, janlelis.com, released under the MIT license.