Module: Gorillib::Resolution

Extended by:
Concern
Includes:
FancyBuilder
Included in:
Ironfan::Dsl
Defined in:
lib/gorillib/resolution.rb

Overview

The attribute :underlay provides an object (preferably another

Gorillib::Model or the like) that will resolve stacked
defaults. If fields are declared with a :resolver, it will
apply that call in preference the default rules (self.field
-> underlay.field -> self.field.default )

To provide resolve cleanly without read-write loops destroying

the separation of concerns, the resolve mechanism has been
broken from the regular read-write accessors.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#underlayObject

Returns the value of attribute underlay.



59
60
61
# File 'lib/gorillib/resolution.rb', line 59

def underlay
  @underlay
end

Instance Method Details

#deep_resolve(field_name) ⇒ Object

This is one of two methods used to resolve Gorillib collections. (The other is merge_resolve.) It simply resolves the field and returns the result. In case the field is a gorillib collection, it resolves each item in the collection.

Parameters:

  • field_name (String or Symbol)


89
90
91
92
93
94
95
96
97
98
99
# File 'lib/gorillib/resolution.rb', line 89

def deep_resolve(field_name)
  temp = read_set_or_underlay_attribute(field_name)
  return if temp.nil?
  if temp.is_a? Gorillib::Collection
    result = temp.class.new
    temp.each_pair {|k,v| result[k] = resolve_value(v) }
  else
    result = resolve_value(result)
  end
  result
end

#merge_resolve(field_name) ⇒ Object

This is one of two methods used to resolve Gorillib collections. (The other is deep_resolve.) It returns the result of merging the value of a field with the value of that field on the parent (underlay) of this object.

Parameters:

  • field_name (String or Symbol)


113
114
115
116
117
118
119
# File 'lib/gorillib/resolution.rb', line 113

def merge_resolve(field_name)
  field = self.class.fields[field_name] or return
  result = field.type.new
  merge_values(result,read_underlay_attribute(field_name))
  merge_values(result,read_set_attribute(field_name))
  result
end

#merge_values(target, value = nil) ⇒ Object

This method makes the assumption that target and value are both instances of either Gorillib::Model or Gorillib::Collection. They should be the same type.

This method is called for its side-effects on the ‘target’ parameter.

In case they are both models, target.receive!(value) is called.

In case they are both collections, target.receive!(v) is called, for each k,v in value.

Parameters:



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/gorillib/resolution.rb', line 135

def merge_values(target, value=nil)
  value ||= {}
  if target.is_a? Gorillib::Collection
    value.each_pair do |k,v|
      existing = target[k]
      if existing && existing.respond_to?(:receive!)
        target[k].receive! v
      elsif existing && existing.respond_to?(:merge!)
        target[k].merge! v
      else
        target[k] = v
      end
    end
  else
    target.receive! value
  end
end

#read_resolved_attribute(field_name) ⇒ Object



153
154
155
156
# File 'lib/gorillib/resolution.rb', line 153

def read_resolved_attribute(field_name)
  field = self.class.fields[field_name] or return
  self.send(field.resolver, field_name)
end

#read_set_attribute(field_name) ⇒ Object



158
159
160
161
# File 'lib/gorillib/resolution.rb', line 158

def read_set_attribute(field_name)
  attr_name = "@#{field_name}"
  instance_variable_get(attr_name) if instance_variable_defined?(attr_name)
end

#read_set_or_underlay_attribute(field_name) ⇒ Object



168
169
170
171
172
# File 'lib/gorillib/resolution.rb', line 168

def read_set_or_underlay_attribute(field_name)
  result = read_set_attribute(field_name)
  return result unless result.nil?
  read_underlay_attribute(field_name)
end

#read_underlay_attribute(field_name) ⇒ Object



163
164
165
166
# File 'lib/gorillib/resolution.rb', line 163

def read_underlay_attribute(field_name)
  return if underlay.nil?
  Gorillib.deep_copy(underlay.read_resolved_attribute(field_name))
end

#resolveObject

Return a fully-resolved copy of this object. All objects

referenced will be clean deep_copies, and will lack the
:underlay accessor. This is by design, to prevent self-
referential loops (parent->collection->child->owner)
when deep_coping.


66
67
68
69
70
71
72
73
# File 'lib/gorillib/resolution.rb', line 66

def resolve
  result = self.class.new
  self.class.fields.each do |field_name, field|
    value = read_resolved_attribute(field_name)
    result.write_attribute(field_name, value) unless value.nil?
  end
  result
end

#resolve!Object



75
76
77
78
79
80
81
# File 'lib/gorillib/resolution.rb', line 75

def resolve!
  resolved = resolve
  self.class.fields.each do |field_name, field|
    write_attribute(field_name, resolved.send(field_name.to_sym))
  end
  self
end

#resolve_value(value) ⇒ Object



101
102
103
104
105
# File 'lib/gorillib/resolution.rb', line 101

def resolve_value(value)
  return if value.nil?
  return value.resolve if value.respond_to? :resolve
  deep_copy(value)
end