Module: SimpleMapper::Attribute::Collection

Included in:
Pattern
Defined in:
lib/simple_mapper/attribute/collection.rb

Overview

Include in a SimpleMapper::Attribute to give it collection behaviors:

* have an attribute be a collection (i.e. a hash or array) of values
  rather than a single value
* map N keys from a source value to the attribute, based on the +:member_key?+ test
* map keys/values from the collection object back to a "source" structure

Instance Method Summary collapse

Instance Method Details

#apply_type(value) ⇒ Object

If the receiver has a valid type specified, returns a new collection based on value, with the key/value pairs from value but each value encoded by the type converter.



37
38
39
40
41
42
43
# File 'lib/simple_mapper/attribute/collection.rb', line 37

def apply_type(value)
  converter = self.converter
  value.inject(new_collection) do |hash, keyval|
    hash[keyval[0]] = converter.decode(keyval[1])
    hash
  end
end

#changed?(object) ⇒ Boolean

Returns:

  • (Boolean)


83
84
85
86
87
88
# File 'lib/simple_mapper/attribute/collection.rb', line 83

def changed?(object)
  val = value(object)
  return true if val.changed_members.size > 0
  return true if mapper and val.find {|keyval| keyval[1].changed?}
  false
end

#freeze_for(object) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/simple_mapper/attribute/collection.rb', line 69

def freeze_for(object)
  val = value(object)
  if val
    if mapper
      if val.respond_to?(:values)
        val.values.each {|member| member.freeze}
      else
        val.each {|member| member.freeze}
      end
    end
    val.freeze
  end
end

#from_simple_key(key) ⇒ Object

Given a key from the source structure (the “simple structure”), returns a transformed key as it will be entered in the attribute’s collection value. By default, this simply passes through key, but it can be overridden to allow for more sophisticated source/object mappings.



58
59
60
# File 'lib/simple_mapper/attribute/collection.rb', line 58

def from_simple_key(key)
  key
end

#member_key?(key) ⇒ Boolean

Returns:

  • (Boolean)


23
24
25
# File 'lib/simple_mapper/attribute/collection.rb', line 23

def member_key?(key)
  false
end

#new_collectionObject

Returns a new collection object to be used as the basis for building the attribute’s value collection; by default, returns instances of SimpleMapper::Collection::Hash. Override this to alter the kinds of collections your attributes work with.



48
49
50
51
52
# File 'lib/simple_mapper/attribute/collection.rb', line 48

def new_collection
  h = SimpleMapper::Collection::Hash.new
  h.attribute = self
  h
end

#source_value(object) ⇒ Object



27
28
29
30
31
32
# File 'lib/simple_mapper/attribute/collection.rb', line 27

def source_value(object)
  object.simple_mapper_source.inject(new_collection) do |hash, keyval|
    hash[from_simple_key(keyval[0])] = keyval[1] if member_key?(keyval[0])
    hash
  end
end

#to_simple(object, container, options = {}) ⇒ Object

Converts the object’s attribute value into its simple representation, putting the keys/values into container. This is conceptually consistent with SimpleMapper::Attributes#to_simple, but adds a few collection-oriented concerns:

* the attribute's value is assumed to be a collection with N key/value pairs
  to be mapped into _container_
* the keys are transformed via +:to_simple_key+ on their way into _container_.

This will work with any kind of container that can be assigned to via []=, and any value for the attribute that supports :inject in the same manner as a Hash (yields the accumulated value and a key/value pair to the block).



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/simple_mapper/attribute/collection.rb', line 101

def to_simple(object, container, options = {})
  val = value(object)
  mapper = self.mapper
  strings = options[:string_keys] || false
  changed_members = change_tracking_for(val)
  if options[:changed]
    if mapper
      change_proc = Proc.new do |key, val|
        changed_members[key] or (! val.nil? and val.changed?)
      end
    else
      change_proc = Proc.new {|k, v| changed_members[k]}
    end
  else
    change_proc = nil
  end
  changes = options[:changed] || false
  container = val.inject(container) do |hash, keyvalue|
    key = to_simple_key(keyvalue[0])
    hash[strings ? key.to_s : key] = mapper ? keyvalue[1].to_simple(options) : encode(keyvalue[1]) if ! change_proc or change_proc.call(*keyvalue)
    hash
  end
  if (change_proc or options[:all]) and ! options[:defined]
    changed_members.keys.find_all {|x| ! val.is_member?(x)}.each do |key|
      container[to_simple_key(key)] = nil
    end
  end
  container
end

#to_simple_key(key) ⇒ Object

The reverse of :to_simple_key, given a key from the attribute collection, returns the transformed version of that key as it should appear in the “simple” representation of the object.



65
66
67
# File 'lib/simple_mapper/attribute/collection.rb', line 65

def to_simple_key(key)
  key
end

#transformed_source_value(object) ⇒ Object

Given an object that has the attribute represented by the receiver, returns the source value for the attribute after applying defaults and types. The type check is applied to either the raw source value (if one exists) or the default value (if no source exists and a default was specified for the attribute).

Type checking is not enforced here; it is expected that :source_value, :default_value, and :apply_type will all return objects of the expected collection type (or consistent interface).



15
16
17
18
19
20
21
# File 'lib/simple_mapper/attribute/collection.rb', line 15

def transformed_source_value(object)
  val = source_value(object)
  val = default_value(object) if val.nil?
  val = apply_type(val) if type
  val.change_tracking = true if val.respond_to?(:change_tracking)
  val
end