Class: Functional::Option

Inherits:
Synchronization::Object
  • Object
show all
Defined in:
lib/functional/option.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 optional value that may be none (no value) or some (a value). This type is a replacement for the use of nil with better type checks. It is an immutable data structure that extends AbstractStruct.

See Also:

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#reasonObject (readonly)

The reason for the absence of a value when none, defaults to nil



34
35
36
# File 'lib/functional/option.rb', line 34

def reason
  @reason
end

Class Method Details

.iff(value, condition = NO_OPTION) { ... } ⇒ Option

If the condition satisfies, return the given A in some, otherwise, none.

Parameters:

  • value (Object)

    The some value to use if the condition satisfies.

  • condition (Boolean) (defaults to: NO_OPTION)

    The condition to test (when no block given).

Yields:

  • The condition to test (when no condition given).

Returns:

  • (Option)

    A constructed option based on the given condition.

Raises:

  • (ArgumentError)

    When both a condition and a block are given.



180
181
182
183
184
# File 'lib/functional/option.rb', line 180

def self.iff(value, condition = NO_OPTION)
  raise ArgumentError.new('requires either a condition or a block, not both') if condition != NO_OPTION && block_given?
  condition = block_given? ? yield : !! condition
  condition ? some(value) : none
end

.none(reason = nil) ⇒ Option

Construct an Option with no value.

Returns:



41
42
43
# File 'lib/functional/option.rb', line 41

def none(reason = nil)
  new(nil, true, reason).freeze
end

.some(value) ⇒ Option

Construct an Option with the given value.

Parameters:

  • value (Object)

    the value of the option

Returns:



49
50
51
# File 'lib/functional/option.rb', line 49

def some(value)
  new(value, false).freeze
end

Instance Method Details

#and(other = NO_OPTION) {|value| ... } ⇒ Boolean

Perform a logical and operation against this option and the provided option or block. Returns true if this option is some and:

  • other is an Option with some value
  • other is a truthy value (not nil or false)
  • the result of the block is a truthy value

If a block is given the value of the current option is passed to the block and the result of block processing will be evaluated for its truthiness. An exception will be raised if an other value and a block are both provided.

Parameters:

  • other (Object) (defaults to: NO_OPTION)

    the value to be evaluated against this option

Yield Parameters:

  • value (Object)

    the value of this option when some

Returns:

  • (Boolean)

    true when the union succeeds else false

Raises:

  • (ArgumentError)

    when given both other and a block



106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/functional/option.rb', line 106

def and(other = NO_OPTION)
  raise ArgumentError.new('cannot give both an option and a block') if other != NO_OPTION && block_given?
  return false if none?

  if block_given?
    !! yield(some)
  elsif Protocol::Satisfy? other, :Option
    other.some?
  else
    !! other
  end
end

#else(other = NO_OPTION) ⇒ Object

Returns the value of this option when some else returns the value of the other option or block. When the other is also an option its some value is returned. When the other is any other value it is simply passed through. When a block is provided the block is processed and the return value of the block is returned. An exception will be raised if an other value and a block are both provided.

Parameters:

  • other (Object) (defaults to: NO_OPTION)

    the value to be evaluated when this is none

Returns:

  • (Object)

    this value when some else the value of other

Raises:

  • (ArgumentError)

    when given both other and a block



158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/functional/option.rb', line 158

def else(other = NO_OPTION)
  raise ArgumentError.new('cannot give both an option and a block') if other != NO_OPTION && block_given?
  return some if some?

  if block_given?
    yield
  elsif Protocol::Satisfy? other, :Option
    other.some
  else
    other
  end
end

#inspectObject Also known as: to_s



187
188
189
# File 'lib/functional/option.rb', line 187

def inspect
  super.gsub(/ :some/, " (#{some? ? 'some' : 'none'}) :some")
end

#lengthFixnum Also known as: size

Returns the length of this optional value; 1 if there is a value, 0 otherwise.

Returns:

  • (Fixnum)

    The length of this optional value; 1 if there is a value, 0 otherwise.



85
86
87
# File 'lib/functional/option.rb', line 85

def length
  none? ? 0 : 1
end

#none?Boolean Also known as: reason?, rejected?

Is the option absent a value?

Returns:

  • (Boolean)

    true if none else false



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

def none?
  @none
end

#or(other = NO_OPTION) ⇒ Boolean

Perform a logical or operation against this option and the provided option or block. Returns true if this option is some. If this option is none it returns true if:

  • other is an Option with some value
  • other is a truthy value (not nil or false)
  • the result of the block is a truthy value

If a block is given the value of the result of block processing will be evaluated for its truthiness. An exception will be raised if an other value and a block are both provided.

Parameters:

  • other (Object) (defaults to: NO_OPTION)

    the value to be evaluated against this option

Returns:

  • (Boolean)

    true when the intersection succeeds else false

Raises:

  • (ArgumentError)

    when given both other and a block



134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/functional/option.rb', line 134

def or(other = NO_OPTION)
  raise ArgumentError.new('cannot give both an option and a block') if other != NO_OPTION && block_given?
  return true if some?

  if block_given?
    !! yield
  elsif Protocol::Satisfy? other, :Option
    other.some?
  else
    !! other
  end
end

#someObject Also known as: value

The value of this option.

Returns:

  • (Object)

    the value when some else nil



75
76
77
# File 'lib/functional/option.rb', line 75

def some
  to_h[:some]
end

#some?Boolean Also known as: value?, fulfilled?

Does the option have a value?

Returns:

  • (Boolean)

    true if some else false



57
58
59
# File 'lib/functional/option.rb', line 57

def some?
  ! none?
end