Module: Functional::Union

Extended by:
Union
Included in:
Union
Defined in:
lib/functional/union.rb

Overview

Note:

This is a write-once, read-many, thread safe object that can be used in concurrent systems. Thread safety guarantees cannot be made about objects contained within this object, however. Ruby variables are mutable references to mutable objects. This cannot be changed. The best practice it to only encapsulate immutable, frozen, or thread safe objects. Ultimately, thread safety is the responsibility of the programmer.

An immutable data structure with multiple fields, only one of which can be set at any given time. A ‘Union` is a convenient way to bundle a number of field attributes together, using accessor methods, without having to write an explicit class.

The ‘Union` module generates new `AbstractStruct` subclasses that hold a set of fields with one and only one value associated with a single field. For each field a reader method is created along with a predicate and a factory. The predicate method indicates whether or not the give field is set. The reader method returns the value of that field or `nil` when not set. The factory creates a new union with the appropriate field set with the given value.

A ‘Union` is very similar to a Ruby `Struct` and shares many of its behaviors and attributes. Where a `Struct` can have zero or more values, each of which is assiciated with a field, a `Union` can have one and only one value. Unlike a Ruby `Struct`, a `Union` is immutable: its value is set at construction and it can never be changed. Divergence between the two classes derive from these two core differences.

Examples:

Creating a New Class


LeftRightCenter = Functional::Union.new(:left, :right, :center) #=> LeftRightCenter
LeftRightCenter.ancestors #=> [LeftRightCenter, Functional::AbstractStruct... ]
LeftRightCenter.fields   #=> [:left, :right, :center]

prize = LeftRightCenter.right('One million dollars!') #=> #<union LeftRightCenter... >
prize.fields #=> [:left, :right, :center]
prize.values  #=> [nil, "One million dollars!", nil]

prize.left?   #=> false
prize.right?  #=> true
prize.center? #=> false

prize.left    #=> nil
prize.right   #=> "One million dollars!"
prize.center  #=> nil

Registering a New Class with Union


Functional::Union.new('Suit', :clubs, :diamonds, :hearts, :spades)
 #=> Functional::Union::Suit

Functional::Union::Suit.hearts('Queen')
 #=> #<union Functional::Union::Suit :clubs=>nil, :diamonds=>nil, :hearts=>"Queen", :spades=>nil>

See Also:

Instance Method Summary collapse

Instance Method Details

#new(*fields) ⇒ Functional::AbstractStruct

Create a new union class with the given fields.

Returns:

  • (Functional::AbstractStruct)

    the new union subclass

Raises:

  • (ArgumentError)

    no fields specified



63
64
65
66
# File 'lib/functional/union.rb', line 63

def new(*fields)
  raise ArgumentError.new('no fields provided') if fields.empty?
  build(fields)
end