Class: ObjectForge::Crucible

Inherits:
UnBasicObject show all
Defined in:
lib/object_forge/crucible.rb,
sig/object_forge.rbs

Overview

Note:

This class is not intended to be used directly, but it's not a private API.

Melting pot for the forged object's attributes.

Since:

  • 0.1.0

Constant Summary collapse

EMPTY_YARD =

steep:ignore UnannotatedEmptyCollection

Returns:

  • (Hash[Symbol, untyped])

Since:

  • 0.1.0

{}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from UnBasicObject

#block_given?, #class, #eql?, #freeze, #frozen?, #hash, #inspect, #is_a?, #kind_of?, #pretty_print, #pretty_print_cycle, #raise, #respond_to?, #to_s

Constructor Details

#initialize(attributes, yard: EMPTY_YARD) ⇒ Crucible

Returns a new instance of Crucible.

Parameters:

  • attributes (Hash{Symbol => Proc, Any})

    initial attributes

  • yard (Hash{Symbol => Any}, nil) (defaults to: EMPTY_YARD)

    additional context for the crucible

Since:

  • 0.1.0



44
45
46
47
48
49
50
# File 'lib/object_forge/crucible.rb', line 44

def initialize(attributes, yard: EMPTY_YARD)
  super()
  @attributes = attributes
  @yard = yard || EMPTY_YARD
  @resolved_attributes = ::Set.new
  @resolving_attributes = []
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name) ⇒ Any (private) Also known as: []

Get the value of the attribute name.

To prevent problems with calling methods which may be defined, #[] can be used instead.

Examples:

attrs = {
  name: -> { "Name" },
  description: -> { name.downcase },
  duration: -> { rand(1000) }
}
Crucible.call(attrs)
  # => { name: "Name", description: "name", duration: 123 }

using conflicting and reserved names

attrs = {
  "[]": -> { "Brackets" },
  "[]=": -> { "#{self[:[]]} are brackets" },
  "!": -> { "#{self[:[]=]}!" }
}
Crucible.resolve(attrs)
  # => { "[]": "Brackets", "[]=": "Brackets are brackets", "!": "Brackets are brackets!" }

Parameters:

  • name (Symbol)

Returns:

  • (Any)

Raises:

Since:

  • 0.1.0



99
100
101
102
103
104
105
106
107
108
109
# File 'lib/object_forge/crucible.rb', line 99

def method_missing(name)
  if @attributes.key?(name)
    raise_circular_dependency_error!(name) if @resolving_attributes.include?(name)
    resolve_attribute!(name) unless @resolved_attributes.include?(name)
    @attributes[name]
  elsif @yard.key?(name)
    @yard[name]
  else
    super
  end
end

Instance Attribute Details

#yardHash{Symbol => Any}, Forgeyard (readonly)

Returns additional context for the crucible.

Returns:

  • (Hash{Symbol => Any}, Forgeyard)

    additional context for the crucible

Since:

  • 0.1.0



40
41
42
# File 'lib/object_forge/crucible.rb', line 40

def yard
  @yard
end

Class Method Details

.call(attributes, yard: EMPTY_YARD) ⇒ Hash{Symbol => Any} Also known as: resolve

Note:

This method destructively modifies initial attributes.

Resolve all attributes by calling their +Proc+s, using a new instance as evaluation context.

Parameters:

  • attributes (Hash{Symbol => Proc, Any})

    initial attributes

  • yard (Hash{Symbol => Any}, nil) (defaults to: EMPTY_YARD)

    additional context for the crucible

Returns:

  • (Hash{Symbol => Any})

    resolved attributes

See Also:

Since:

  • 0.1.0



30
31
32
# File 'lib/object_forge/crucible.rb', line 30

def call(attributes, yard: EMPTY_YARD)
  new(attributes, yard:).resolve!
end

Instance Method Details

#resolve!Hash{Symbol => Any}

Note:

This method destructively modifies initial attributes.

Resolve all attributes by calling their +Proc+s, using self as the evaluation context.

Attributes can freely refer to each other inside +Proc+s through bareword names or #[]. However, make sure to avoid cyclic dependencies: they can't be resolved and will raise ObjectForge::CircularAttributeDependencyError.

Returns:

  • (Hash{Symbol => Any})

    resolved attributes

Raises:

Since:

  • 0.1.0



65
66
67
68
# File 'lib/object_forge/crucible.rb', line 65

def resolve!
  @attributes.each_key { |name| method_missing(name) }
  @attributes
end