Class: Functional::ValueStruct

Inherits:
Synchronization::Object
  • Object
show all
Defined in:
lib/functional/value_struct.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.

A variation on Ruby's OpenStruct in which all fields are immutable and set at instantiation. For compatibility with FinalStruct, predicate methods exist for all potential fields and these predicates indicate if the field has been set. Calling a predicate method for a field that does not exist on the struct will return false.

Unlike Record, which returns a new class which can be used to create immutable objects, ValueStruct creates simple immutable objects.

Examples:

Instanciation

name = Functional::ValueStruct.new(first: 'Douglas', last: 'Adams')

name.first   #=> 'Douglas'
name.last    #=> 'Adams'
name.first?  #=> true
name.last?   #=> true
name.middle? #=> false

See Also:

Instance Method Summary collapse

Constructor Details

#initialize(attributes) ⇒ ValueStruct

Returns a new instance of ValueStruct.

Raises:

  • (ArgumentError)


30
31
32
33
34
35
36
37
38
39
40
# File 'lib/functional/value_struct.rb', line 30

def initialize(attributes)
  raise ArgumentError.new('attributes must be given as a hash') unless attributes.respond_to?(:each_pair)
  super
  @attribute_hash = {}
  attributes.each_pair do |field, value|
    set_attribute(field, value)
  end
  @attribute_hash.freeze
  ensure_ivar_visibility!
  self.freeze
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(symbol, *args) ⇒ Object (private)

Check the method name and args for signatures matching potential final predicate methods. If the signature matches call the appropriate method

Parameters:

  • symbol (Symbol)

    the name of the called function

  • args (Array)

    zero or more arguments

Returns:

  • (Object)

    the result of the proxied method or the super call



136
137
138
139
140
141
142
143
144
# File 'lib/functional/value_struct.rb', line 136

def method_missing(symbol, *args)
  if args.length == 0 && (match = /([^\?]+)\?$/.match(symbol))
    set?(match[1])
  elsif args.length == 0 && set?(symbol)
    get(symbol)
  else
    super
  end
end

Instance Method Details

#each_pair {|field, value| ... } ⇒ Enumerable

Calls the block once for each attribute, passing the key/value pair as parameters. If no block is given, an enumerator is returned instead.

Yield Parameters:

  • field (Symbol)

    the struct field for the current iteration

  • value (Object)

    the value of the current field

Returns:

  • (Enumerable)

    when no block is given



77
78
79
80
81
82
# File 'lib/functional/value_struct.rb', line 77

def each_pair
  return enum_for(:each_pair) unless block_given?
  @attribute_hash.each do |field, value|
    yield(field, value)
  end
end

#eql?(other) ⇒ Boolean Also known as: ==

Compares this object and other for equality. A ValueStruct is eql? to other when other is a ValueStruct and the two objects have identical fields and values.

Parameters:

  • other (Object)

    the other record to compare for equality

Returns:

  • (Boolean)

    true when equal else false



98
99
100
# File 'lib/functional/value_struct.rb', line 98

def eql?(other)
  other.is_a?(self.class) && @attribute_hash == other.to_h
end

#fetch(field, default) ⇒ Object

Get the current value of the given field if already set else return the given default value.

Parameters:

  • field (Symbol)

    the field to get the value for

  • default (Object)

    the value to return if the field has not been set

Returns:

  • (Object)

    the value of the given field else the given default value



66
67
68
# File 'lib/functional/value_struct.rb', line 66

def fetch(field, default)
  @attribute_hash.fetch(field.to_sym, default)
end

#get(field) ⇒ Object Also known as: []

Get the value of the given field.

Parameters:

  • field (Symbol)

    the field to retrieve the value for

Returns:

  • (Object)

    the value of the field is set else nil



46
47
48
# File 'lib/functional/value_struct.rb', line 46

def get(field)
  @attribute_hash[field.to_sym]
end

#set?(field) ⇒ Boolean

Check the internal hash to unambiguously verify that the given attribute has been set.

Parameters:

  • field (Symbol)

    the field to get the value for

Returns:

  • (Boolean)

    true if the field has been set else false



56
57
58
# File 'lib/functional/value_struct.rb', line 56

def set?(field)
  @attribute_hash.has_key?(field.to_sym)
end

#to_hHash

Converts the ValueStruct to a Hash with keys representing each attribute (as symbols) and their corresponding values.

Returns:

  • (Hash)

    a Hash representing this struct



88
89
90
# File 'lib/functional/value_struct.rb', line 88

def to_h
  @attribute_hash.dup # dup removes the frozen flag
end