Class: ObjectForge::Crucible

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

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

Since:

  • 0.1.0

{}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from UnBasicObject

#class, #eql?, #freeze, #frozen?, #hash, #inspect, #is_a?, #pretty_print, #pretty_print_cycle, #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 Procs, 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 Procs, using self as the evaluation context.

Attributes can freely refer to each other inside Procs 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