Module: Farce::Abstract::Value Abstract

Included in:
Atom, Counter, Flag, Lazy, Envelope, WeakValue
Defined in:
lib/farce/abstract/value.rb,
lib/farce/integrations/active_support/blank.rb

Overview

This module is abstract.

Mixin to indicate #value can safely be called on an object.

ActiveSupport Integration collapse

Instance Method Summary collapse

Instance Method Details

#blank? ⇒ Boolean

Note:

This methods is only available if ActiveSupport has been loaded.

Returns true if the value is blank, false otherwise.

Returns:

  • (Boolean) —

    true if the value is blank, false otherwise.



40
# File 'lib/farce/integrations/active_support/blank.rb', line 40

def blank? = value.blank?

#unwrap(default = nil) ⇒ BasicObject #unwrap {|value| ... } ⇒ BasicObject

Unwraps nested Farce::Abstract::Value objects to get the underlying value.

Examples:

Nested unwrapping

MyValue = Data.define(:value) { include Farce::Abstract::Value }
inner   = MyValue.new(42)
outer   = MyValue.new(inner)
outer.unwrap # => 42

Cycle detection

MyValue = Struct.new(:name, :value) { include Farce::Abstract::Value }

a = MyValue.new("A")
b = MyValue.new("B", a)
c = MyValue.new("C", a)
a.value = b

c.unwrap # => nil
c.unwrap("default") # => "default"

# RuntimeError: cycle detected starting at A
c.unwrap { raise "cycle detected starting at #{value.name}" }

Overloads:

  • #unwrap(default = nil) ⇒ BasicObject

    Parameters:

    • default (BasicObject) (defaults to: nil) —

      The value to return if a cycle is detected.

  • #unwrap {|value| ... } ⇒ BasicObject

    Yields:

    • (value) —

      Block to call if a cycle is detected.

    Yield Parameters:

    • value (Value) —

      The value that has been determined to be the start of the cycle.

    Yield Returns:

    • (BasicObject) —

      The value to return if a cycle is detected

Returns:

  • (BasicObject) —

    The underlying value of the object, or a default value based on the argument or block.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/farce/abstract/value.rb', line 51

def unwrap(default = nil)
  value = value()
  return value unless value.is_a?(Value)

  seen = ::Set.new.compare_by_identity
  seen << self

  while value.is_a?(Value)
    return block_given? ? yield(value) : default if seen.include?(value)
    seen << value
    value = value.value
  end

  value
end

#value ⇒ BasicObject

This method is abstract.

Can be called multiple times without argument. Some subclasses may allow optional arguments, especially a timeout keyword argument. This method may block.

Returns:

  • (BasicObject) —

    The underlying value of the object.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/farce/abstract/value.rb', line 17

module Value
  Internal::Atom.include(self)

  # Unwraps nested {Value} objects to get the underlying value.
  #
  # @example Nested unwrapping
  #   MyValue = Data.define(:value) { include Farce::Abstract::Value }
  #   inner   = MyValue.new(42)
  #   outer   = MyValue.new(inner)
  #   outer.unwrap # => 42
  #
  # @example Cycle detection
  #   MyValue = Struct.new(:name, :value) { include Farce::Abstract::Value }
  #
  #   a = MyValue.new("A")
  #   b = MyValue.new("B", a)
  #   c = MyValue.new("C", a)
  #   a.value = b
  #
  #   c.unwrap # => nil
  #   c.unwrap("default") # => "default"
  #
  #   # RuntimeError: cycle detected starting at A
  #   c.unwrap { raise "cycle detected starting at #{value.name}" }
  #
  # @overload unwrap(default = nil)
  #   @param [BasicObject] default The value to return if a cycle is detected.
  #
  # @overload unwrap
  #   @yield [value] Block to call if a cycle is detected.
  #   @yieldparam [Value] value The value that has been determined to be the start of the cycle.
  #   @yieldreturn [BasicObject] The value to return if a cycle is detected
  #
  # @return [BasicObject] The underlying value of the object, or a default value based on the argument or block.
  def unwrap(default = nil)
    value = value()
    return value unless value.is_a?(Value)

    seen = ::Set.new.compare_by_identity
    seen << self

    while value.is_a?(Value)
      return block_given? ? yield(value) : default if seen.include?(value)
      seen << value
      value = value.value
    end

    value
  end
end