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:

Class Method Summary (collapse)

Instance Method Summary (collapse)

Class Method Details

+ (Functional::AbstractStruct) new(*fields)

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

Instance Method Details

- (Functional::AbstractStruct) new(*fields)

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