Class: Krikri::MappingDSL::ChildDeclaration

Inherits:
PropertyDeclaration show all
Defined in:
lib/krikri/mapping_dsl/child_declaration.rb

Overview

Specifies a mapping between a property and one or more child nodes.

The child node is built by processing a sub-mapping, generating an object that can be set to the property.

Multiple sub-mappings can be processed with, the ‘:each` and `:as` options. When given, the sub-mapping is run once for each value given to `:each`, with the variable `:as` passed to.

Examples:

a basic declaration

class Book; attr_accessor :author; end
class Agent; attr_accessor :name, :locale; end

dec = Krikri::MappingDSL::ChildDeclaration.new(:author, Agent) do
  name   'Moomin'
  locale 'Moomin Valley'
end

book = Book.new
dec.to_proc.call(book, nil) # nil stands in for a record.
book.author
# => #<Agent:0x0055654f5d5138 @locale="Moomin Valley", @name="Moomin">

an :each/:as declaration

class Book; attr_accessor :author; end
class Agent; attr_accessor :name, :locale; end

dec = Krikri::MappingDSL::ChildDeclaration.new(:author, Agent,
    each: ['Moomin', 'Snuffkin'], as: :agent_name) do
  name    agent_name
  locale 'Moomin Valley'
end

book = Book.new.tap { |b| b.author = [] }
dec.to_proc.call(book, nil)
book.author
# => [#<Agent:0x0055654f405808
#   @locale="Moomin Valley",
#   @name="Moomin">,
#  #<Agent:0x0055654f4040c0
#   @locale="Moomin Valley",
#   @name="Snuffkin">]

See Also:

Instance Attribute Summary

Attributes inherited from PropertyDeclaration

#name, #value

Instance Method Summary collapse

Constructor Details

#initialize(name, target_class, opts = {}, &block) ⇒ ChildDeclaration

Returns a new instance of ChildDeclaration.

Parameters:

  • name (Symbol)

    a symbol representing the property to set the child node(s) to.

  • target_class (#call, Object)

    the class to use when building child mappings. Values set through a ChildDeclartaion will be instances of this class

  • opts (Hash) (defaults to: {})

Options Hash (opts):

  • :each (#call, Enumerable)

    the values to bind to

  • :as (Symbol)

    the “variable” to bind the values of ‘:each` to within the child Mapping’s scope



60
61
62
63
64
65
66
# File 'lib/krikri/mapping_dsl/child_declaration.rb', line 60

def initialize(name, target_class, opts = {}, &block)
  @name         = name
  @target_class = target_class
  @block        = block
  @each         = opts.delete(:each)
  @as           = opts.delete(:as)
end

Instance Method Details

#to_procProc

Returns a proc that can be run to create one or more child node as instances of the ‘target_class`. Each node is evaluated as a sub-mapping with the block given. The values of `:each` are available within the block’s scope.

Returns:

  • (Proc)

    a callable proc that evaluates the sub-mappings



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/krikri/mapping_dsl/child_declaration.rb', line 75

def to_proc
  block        = @block
  target_class = @target_class
  each_val     = @each
  as_sym       = @as
  
  lambda do |target, record|
    # if `@each` is set, iterate through its values and process the mapping for each.
    # this results in a different child record/node for each value in `@each`.
    if each_val
      iter = each_val.respond_to?(:call) ? each_val.call(record) : each_val
      iter.each do |value|
        map = Krikri::Mapping.new(target_class)

        # define as_sym to return the node (not the value) for this value, 
        # only on this instance
        map.define_singleton_method(as_sym) do
          each_val.dup.select do |v|
            v = v.value if v.respond_to? :value
            v == value
          end
        end

        map.instance_eval(&block)
        target.send(name) << map.process_record(record)
      end
    # else, process a single child mapping over a single instance of 
    # `target_class`
    else
      map = Krikri::Mapping.new(target_class)
      map.instance_eval(&block)
      target.send(setter, map.process_record(record))
    end
  end
end