HornsAndHooves-flat_map 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +34 -0
- data/.metrics +17 -0
- data/.rspec +4 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +20 -0
- data/HornsAndHooves-flat_map.gemspec +29 -0
- data/LICENSE +21 -0
- data/README.markdown +214 -0
- data/Rakefile +15 -0
- data/lib/flat_map.rb +14 -0
- data/lib/flat_map/errors.rb +57 -0
- data/lib/flat_map/mapping.rb +124 -0
- data/lib/flat_map/mapping/factory.rb +21 -0
- data/lib/flat_map/mapping/reader.rb +12 -0
- data/lib/flat_map/mapping/reader/basic.rb +28 -0
- data/lib/flat_map/mapping/reader/formatted.rb +45 -0
- data/lib/flat_map/mapping/reader/formatted/formats.rb +28 -0
- data/lib/flat_map/mapping/reader/method.rb +25 -0
- data/lib/flat_map/mapping/reader/proc.rb +15 -0
- data/lib/flat_map/mapping/writer.rb +11 -0
- data/lib/flat_map/mapping/writer/basic.rb +25 -0
- data/lib/flat_map/mapping/writer/method.rb +28 -0
- data/lib/flat_map/mapping/writer/proc.rb +18 -0
- data/lib/flat_map/model_mapper.rb +195 -0
- data/lib/flat_map/model_mapper/persistence.rb +108 -0
- data/lib/flat_map/model_mapper/skipping.rb +45 -0
- data/lib/flat_map/open_mapper.rb +113 -0
- data/lib/flat_map/open_mapper/attribute_methods.rb +55 -0
- data/lib/flat_map/open_mapper/factory.rb +244 -0
- data/lib/flat_map/open_mapper/mapping.rb +123 -0
- data/lib/flat_map/open_mapper/mounting.rb +168 -0
- data/lib/flat_map/open_mapper/persistence.rb +178 -0
- data/lib/flat_map/open_mapper/skipping.rb +66 -0
- data/lib/flat_map/open_mapper/traits.rb +95 -0
- data/lib/flat_map/version.rb +3 -0
- data/spec/flat_map/errors_spec.rb +23 -0
- data/spec/flat_map/mapper/attribute_methods_spec.rb +36 -0
- data/spec/flat_map/mapper/callbacks_spec.rb +76 -0
- data/spec/flat_map/mapper/factory_spec.rb +285 -0
- data/spec/flat_map/mapper/mapping_spec.rb +98 -0
- data/spec/flat_map/mapper/mounting_spec.rb +142 -0
- data/spec/flat_map/mapper/persistence_spec.rb +152 -0
- data/spec/flat_map/mapper/skipping_spec.rb +91 -0
- data/spec/flat_map/mapper/targeting_spec.rb +156 -0
- data/spec/flat_map/mapper/traits_spec.rb +172 -0
- data/spec/flat_map/mapper/validations_spec.rb +72 -0
- data/spec/flat_map/mapper_spec.rb +9 -0
- data/spec/flat_map/mapping/factory_spec.rb +12 -0
- data/spec/flat_map/mapping/reader/basic_spec.rb +15 -0
- data/spec/flat_map/mapping/reader/formatted_spec.rb +62 -0
- data/spec/flat_map/mapping/reader/method_spec.rb +13 -0
- data/spec/flat_map/mapping/reader/proc_spec.rb +13 -0
- data/spec/flat_map/mapping/writer/basic_spec.rb +15 -0
- data/spec/flat_map/mapping/writer/method_spec.rb +13 -0
- data/spec/flat_map/mapping/writer/proc_spec.rb +13 -0
- data/spec/flat_map/mapping_spec.rb +123 -0
- data/spec/flat_map/open_mapper_spec.rb +19 -0
- data/spec/spec_helper.rb +7 -0
- data/tmp/metric_fu/_data/20131218.yml +6902 -0
- data/tmp/metric_fu/_data/20131219.yml +6726 -0
- metadata +220 -0
@@ -0,0 +1,123 @@
|
|
1
|
+
module FlatMap
|
2
|
+
# This module hosts all definitions required to define and use mapping
|
3
|
+
# functionality within mapper classes. This includes mapping definition
|
4
|
+
# methods and basic reading and writing methods.
|
5
|
+
module OpenMapper::Mapping
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
# Mapping class macros
|
9
|
+
module ClassMethods
|
10
|
+
# Mapping-modifier options to distinguish options from mappings
|
11
|
+
# themselves:
|
12
|
+
MAPPING_OPTIONS = [:reader, :writer, :format, :multiparam].freeze
|
13
|
+
|
14
|
+
# Define single or multiple mappings at a time. Usually, a Hash
|
15
|
+
# is passed in a form !{mapping_name => target_attribute}. All keys
|
16
|
+
# that are listed under {MAPPING_OPTIONS} will be extracted and used
|
17
|
+
# as modifiers for new mappings.
|
18
|
+
#
|
19
|
+
# Also, mapping names may be listed as an array preceding the hash.
|
20
|
+
# In that case, its elements are treated as !{mapping_name => mapping_name}
|
21
|
+
# mapping elements.
|
22
|
+
#
|
23
|
+
# Example:
|
24
|
+
# map :brand, :account_source => :source, :format => :enum
|
25
|
+
# # is equivalent to:
|
26
|
+
# map :brand => :brand, :format => :enum
|
27
|
+
# map :account_source => :source, :format => :enum
|
28
|
+
def map(*args)
|
29
|
+
mapping_options = args.extract_options!
|
30
|
+
mappings = mapping_options.slice!(*MAPPING_OPTIONS)
|
31
|
+
mappings_from_array = args.zip(args).flatten
|
32
|
+
mappings.merge!(Hash[*mappings_from_array]) unless mappings_from_array.empty?
|
33
|
+
|
34
|
+
define_mappings(mappings, mapping_options)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Define a set of +mappings+, passed as a {Hash} with +options+ as modifiers.
|
38
|
+
# Eventually, adds a mapping factories to list of class mappings. Those
|
39
|
+
# factory objects are used to create actual mappings for specific mapper
|
40
|
+
# object.
|
41
|
+
#
|
42
|
+
# @param [Hash] mappings
|
43
|
+
# @param [Hash] options
|
44
|
+
# @return [Array<FlatMap::Mapping::Factory>] list of mappings
|
45
|
+
def define_mappings(mappings, options)
|
46
|
+
mappings.each do |name, target_attribute|
|
47
|
+
self.mappings << FlatMap::Mapping::Factory.new(name, target_attribute, options)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
private :define_mappings
|
51
|
+
|
52
|
+
# List of class mappings (mapping factories).
|
53
|
+
#
|
54
|
+
# @return [Array<FlatMap::Mapping::Factory>]
|
55
|
+
def mappings
|
56
|
+
@mappings ||= []
|
57
|
+
end
|
58
|
+
|
59
|
+
# Writer for mappings.
|
60
|
+
def mappings=(val)
|
61
|
+
@mappings = val
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Send passed +params+ +write_from_params+ method of each
|
66
|
+
# of the mappings of +self+.
|
67
|
+
#
|
68
|
+
# Overloaded in {OpenMapper::Mounting}.
|
69
|
+
#
|
70
|
+
# @param [Hash] params
|
71
|
+
# @return [Hash] params
|
72
|
+
def write(params)
|
73
|
+
mappings.each do |mapping|
|
74
|
+
mapping.write_from_params(params)
|
75
|
+
end
|
76
|
+
params
|
77
|
+
end
|
78
|
+
|
79
|
+
# Send +read_as_params+ method to all mappings associated with
|
80
|
+
# self. And consolidate results in a single hash.
|
81
|
+
#
|
82
|
+
# @return [Hash] set of read values
|
83
|
+
def read
|
84
|
+
mappings.inject({}) do |params, mapping|
|
85
|
+
params.merge(mapping.read_as_params)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Retrieve mapping value via its name, which might differ from its
|
90
|
+
# full_name, if suffix was used.
|
91
|
+
#
|
92
|
+
# @param [Symbol] name
|
93
|
+
def [](name)
|
94
|
+
mapping(name).try(:read)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Write value to mapping specified by name, which might differ from its
|
98
|
+
# full_name, if suffix was used.
|
99
|
+
#
|
100
|
+
# @param [Symbol] name
|
101
|
+
# @param [Object] value
|
102
|
+
def []=(name, value)
|
103
|
+
mapping(name).try(:write, value)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Lookup mapping by its name, which might differ from its
|
107
|
+
# full_name, if suffix was used.
|
108
|
+
#
|
109
|
+
# @param [Symbol] name
|
110
|
+
# @return [FlatMap::Mapping]
|
111
|
+
def mapping(name)
|
112
|
+
mappings.find{ |mapping| mapping.name == name }
|
113
|
+
end
|
114
|
+
|
115
|
+
# Return a list of mappings associated to +self+.
|
116
|
+
#
|
117
|
+
# @return [FlatMap::Mapping]
|
118
|
+
def mappings
|
119
|
+
@mappings ||= self.class.mappings.map{ |factory| factory.create(self) }
|
120
|
+
end
|
121
|
+
private :mappings
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
module FlatMap
|
2
|
+
# This module hosts definitions required for mounting functionality
|
3
|
+
# of the mappers. This includes mounting definition methods, overloaded
|
4
|
+
# +read+ and +write+ methods to make them aware of mounted mappers and
|
5
|
+
# other methods.
|
6
|
+
#
|
7
|
+
# Also, the +method_missing+ method is defined here to delegate the missing
|
8
|
+
# method to the very first mounted mapper that responds to it.
|
9
|
+
module OpenMapper::Mounting
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
included do
|
13
|
+
attr_accessor :save_order
|
14
|
+
end
|
15
|
+
|
16
|
+
# Mounting class macros.
|
17
|
+
module ClassMethods
|
18
|
+
# Add a mounting factory to a list of factories of a class
|
19
|
+
# These factories are used to create actual mounted objects,
|
20
|
+
# which are mappers themselves, associated to a particular
|
21
|
+
# mapper.
|
22
|
+
#
|
23
|
+
# @param [*Object] args
|
24
|
+
# @return [Array<FlatMap::OpenMapper::Factory>]
|
25
|
+
def mount(*args, &block)
|
26
|
+
mountings << FlatMap::OpenMapper::Factory.new(*args, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
# List of mountings (factories) of a class.
|
30
|
+
#
|
31
|
+
# @return [Array<FlatMap::OpenMapper>]
|
32
|
+
def mountings
|
33
|
+
@mountings ||= []
|
34
|
+
end
|
35
|
+
|
36
|
+
# Writer for @mountings.
|
37
|
+
def mountings=(val)
|
38
|
+
@mountings = val
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Extend original {Mapping#read} method to take
|
43
|
+
# into account mountings of mounted mappers.
|
44
|
+
#
|
45
|
+
# @return [Hash] read values
|
46
|
+
def read
|
47
|
+
mountings.inject(super) do |result, mapper|
|
48
|
+
result.merge(mapper.read)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Extend original {Mapping#write} method to pass
|
53
|
+
# +params+ to mounted mappers.
|
54
|
+
#
|
55
|
+
# Overridden in {Persistence}. Left here for consistency.
|
56
|
+
#
|
57
|
+
# @param [Hash] params
|
58
|
+
# @return [Hash] params
|
59
|
+
def write(params)
|
60
|
+
super
|
61
|
+
|
62
|
+
mountings.each do |mapper|
|
63
|
+
mapper.write(params)
|
64
|
+
end
|
65
|
+
|
66
|
+
params
|
67
|
+
end
|
68
|
+
|
69
|
+
# Return list of mappings to be saved before saving target of +self+
|
70
|
+
#
|
71
|
+
# @return [Array<FlatMap::OpenMapper>]
|
72
|
+
def before_save_mountings
|
73
|
+
nearest_mountings.select{ |mount| mount.save_order == :before }
|
74
|
+
end
|
75
|
+
|
76
|
+
# Return list of mappings to be saved after target of +self+ was saved
|
77
|
+
#
|
78
|
+
# @return [Array<FlatMap::OpenMapper>]
|
79
|
+
def after_save_mountings
|
80
|
+
nearest_mountings.reject{ |mount| mount.save_order == :before }
|
81
|
+
end
|
82
|
+
|
83
|
+
# Return all mountings that are mouted on +self+ directly or through
|
84
|
+
# traits.
|
85
|
+
#
|
86
|
+
# @return [Array<FlatMap::OpenMapper>]
|
87
|
+
def nearest_mountings
|
88
|
+
mountings.map{ |mount| mount.owned? ? mount.nearest_mountings : mount }.flatten
|
89
|
+
end
|
90
|
+
|
91
|
+
# Return a list of all mountings (mapper objects) associated with +self+.
|
92
|
+
#
|
93
|
+
# Overridden in {Traits}. Left here for consistency.
|
94
|
+
#
|
95
|
+
# @return [Array<FlatMap::OpenMapper>]
|
96
|
+
def mountings
|
97
|
+
@mountings ||= self.class.mountings.map{ |factory| factory.create(self) }
|
98
|
+
end
|
99
|
+
|
100
|
+
# Return a mapping with the name that corresponds to passed +mounting_name+,
|
101
|
+
# if it exists.
|
102
|
+
#
|
103
|
+
# @return [FlatMap::Mapping, nil]
|
104
|
+
def mounting(mounting_name, is_deep = true)
|
105
|
+
list = is_deep ? all_mountings : mountings
|
106
|
+
list.find{ |mount| mount.name == mounting_name }
|
107
|
+
end
|
108
|
+
|
109
|
+
# Return a list of all mounted mappers. If +self+ is a trait, return a
|
110
|
+
# list of all mountings of the owner. This will allow separate traits
|
111
|
+
# to share methods via method_missing pattern.
|
112
|
+
#
|
113
|
+
# @return [Array<FlatMap::OpenMapper>] mounted mappers (including traits)
|
114
|
+
def all_mountings
|
115
|
+
return all_nested_mountings.unshift(self) unless owned?
|
116
|
+
owner.all_mountings
|
117
|
+
end
|
118
|
+
protected :all_mountings
|
119
|
+
|
120
|
+
# Return a list of mountings that are accessible by a named mapper.
|
121
|
+
#
|
122
|
+
# @return [Array<FlatMap::OpenMapper>]
|
123
|
+
def all_nested_mountings
|
124
|
+
mountings.dup.concat(mountings.map{ |mount| mount.send(:all_nested_mountings) }).flatten
|
125
|
+
end
|
126
|
+
protected :all_nested_mountings
|
127
|
+
|
128
|
+
# Return a list of all mappings, i.e. mappings associated to +self+,
|
129
|
+
# plus mappings of all deeply mounted mappers. If +self+ is the owner,
|
130
|
+
# that means it is a part (a trait) of a host mapper. That means that all
|
131
|
+
# mappings of it actually correspond to all mappings of a host mapper.
|
132
|
+
# This allows to define things like validation in a trait where access
|
133
|
+
# to top-level mappings is required.
|
134
|
+
#
|
135
|
+
# @return [Array<FlatMap::Mapping>]
|
136
|
+
def all_mappings
|
137
|
+
return all_nested_mappings unless owned?
|
138
|
+
owner.all_mappings
|
139
|
+
end
|
140
|
+
protected :all_mappings
|
141
|
+
|
142
|
+
# Return a list of all mappings, i.e. mappings that associated to +self+
|
143
|
+
# plus mappings of all deeply mounted mappers.
|
144
|
+
#
|
145
|
+
# @return [Array<FlatMap::Mapping>]
|
146
|
+
def all_nested_mappings
|
147
|
+
(mappings + mountings.map{ |mount| mount.send(:all_nested_mappings) }).flatten
|
148
|
+
end
|
149
|
+
protected :all_nested_mappings
|
150
|
+
|
151
|
+
# Delegate missing method to any mounted mapping that respond to it,
|
152
|
+
# unless those methods are protected methods of FlatMap::OpenMapper.
|
153
|
+
#
|
154
|
+
# NOTE: :to_ary method is called internally by Ruby 1.9.3 when we call
|
155
|
+
# something like [mapper].flatten. And we DO want default behavior
|
156
|
+
# for handling this missing method.
|
157
|
+
def method_missing(name, *args, &block)
|
158
|
+
return super if name == :to_ary ||
|
159
|
+
self.class.protected_instance_methods.include?(name)
|
160
|
+
|
161
|
+
return self[name] if mapping(name).present?
|
162
|
+
|
163
|
+
mounting = all_mountings.find{ |mount| mount.respond_to?(name) }
|
164
|
+
return super if mounting.nil?
|
165
|
+
mounting.send(name, *args, &block)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
module FlatMap
|
2
|
+
# This module provides some integration between mapper and its target,
|
3
|
+
# which is usually an ActiveRecord model, as well as some integration
|
4
|
+
# between mapper and Rails forms.
|
5
|
+
#
|
6
|
+
# In particular, validation and save methods are defined here. And
|
7
|
+
# the <tt>save</tt> method itself is defined as a callback. Also, Rails
|
8
|
+
# multiparam attributes extraction is defined within this module.
|
9
|
+
module OpenMapper::Persistence
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
included do
|
13
|
+
define_callbacks :save
|
14
|
+
end
|
15
|
+
|
16
|
+
# ModelMethods class macros
|
17
|
+
module ClassMethods
|
18
|
+
# Create a new mapper object wrapped around new instance of its
|
19
|
+
# +target_class+, with a list of passed +traits+ applied to it.
|
20
|
+
#
|
21
|
+
# @param [*Symbol] traits
|
22
|
+
# @return [FlatMap::OpenMapper] mapper
|
23
|
+
def build(*traits, &block)
|
24
|
+
new(target_class.new, *traits, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Default target class for OpenMapper is OpenStruct.
|
28
|
+
#
|
29
|
+
# @return [Class] class
|
30
|
+
def target_class
|
31
|
+
OpenStruct
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Write a passed set of +params+. Then try to save the model if +self+
|
36
|
+
# passes validation. Saving is performed in a transaction.
|
37
|
+
#
|
38
|
+
# @param [Hash] params
|
39
|
+
# @return [Boolean]
|
40
|
+
def apply(params)
|
41
|
+
write(params)
|
42
|
+
valid? && save
|
43
|
+
end
|
44
|
+
|
45
|
+
# Extract the multiparam values from the passed +params+. Then use the
|
46
|
+
# resulting hash to assign values to the target. Assignment is performed
|
47
|
+
# by sending writer methods to +self+ that correspond to keys in the
|
48
|
+
# resulting +params+ hash.
|
49
|
+
#
|
50
|
+
# @param [Hash] params
|
51
|
+
# @return [Hash] params
|
52
|
+
def write(params)
|
53
|
+
extract_multiparams!(params)
|
54
|
+
|
55
|
+
params.each do |name, value|
|
56
|
+
self.send("#{name}=", value)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Try to save the target and send a +save+ method to all mounted mappers.
|
61
|
+
#
|
62
|
+
# The order in which mappings are saved is important, since we save
|
63
|
+
# records with :validate => false option. Since Rails will perform
|
64
|
+
# auto-saving on associations (and it in its turn will try to save associated
|
65
|
+
# record with :validate => true option. To be more precise, with
|
66
|
+
# :validate => !autosave option, where autosave corresponds to that option
|
67
|
+
# of reflection, which is usually not specified, i.e. nil), we might come to
|
68
|
+
# a situation of saving a record with nil foreign key for belongs_to association,
|
69
|
+
# which will raise exception. Thus, we want to explicitly save records in
|
70
|
+
# order which will allow them to be saved.
|
71
|
+
# Return +false+ if that chain of +save+ calls returns +true+ on any of
|
72
|
+
# its elements. Return +true+ otherwise.
|
73
|
+
#
|
74
|
+
# Saving is performed as a callback.
|
75
|
+
#
|
76
|
+
# @return [Boolean]
|
77
|
+
def save
|
78
|
+
before_res = save_mountings(before_save_mountings)
|
79
|
+
target_res = self_mountings.map{ |mount| mount.shallow_save }.all?
|
80
|
+
after_res = save_mountings(after_save_mountings)
|
81
|
+
|
82
|
+
before_res && target_res && after_res
|
83
|
+
end
|
84
|
+
|
85
|
+
# Return +true+ since OpenStruct is always 'saved'.
|
86
|
+
#
|
87
|
+
# @return [true]
|
88
|
+
def save_target
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
# Perform target save with callbacks call
|
93
|
+
#
|
94
|
+
# @return [Boolean]
|
95
|
+
def shallow_save
|
96
|
+
run_callbacks(:save){ save_target }
|
97
|
+
end
|
98
|
+
|
99
|
+
# Return +true+ if target was updated.
|
100
|
+
#
|
101
|
+
# @return [Boolean]
|
102
|
+
def persisted?
|
103
|
+
target != OpenStruct.new
|
104
|
+
end
|
105
|
+
|
106
|
+
# Send <tt>:save</tt> method to all mountings in list. Will return +true+
|
107
|
+
# only if all savings are positive.
|
108
|
+
#
|
109
|
+
# @param [Array<FlatMap::OpenMapper>] mountings
|
110
|
+
# @return [Boolean]
|
111
|
+
def save_mountings(mountings)
|
112
|
+
mountings.map{ |mount| mount.save }.all?
|
113
|
+
end
|
114
|
+
private :save_mountings
|
115
|
+
|
116
|
+
# Return +true+ if the mapper is valid, i.e. if it is valid itself, and if
|
117
|
+
# all mounted mappers (traits and other mappers) are also valid.
|
118
|
+
#
|
119
|
+
# Accepts any parameters, but doesn't use them to be compatible with
|
120
|
+
# ActiveRecord calls.
|
121
|
+
#
|
122
|
+
# @return [Boolean]
|
123
|
+
def valid?(*)
|
124
|
+
res = trait_mountings.map(&:valid?).all?
|
125
|
+
res = super && res # we do want to call super
|
126
|
+
mounting_res = mapper_mountings.map(&:valid?).all?
|
127
|
+
consolidate_errors!
|
128
|
+
res && mounting_res
|
129
|
+
end
|
130
|
+
|
131
|
+
# Consolidate the errors of all mounted mappers to a set of errors of +self+.
|
132
|
+
#
|
133
|
+
# @return [Array<ActiveModel::Errors>]
|
134
|
+
def consolidate_errors!
|
135
|
+
mountings.map(&:errors).each do |errs|
|
136
|
+
errors.messages.merge!(errs.to_hash){ |key, old, new| old.concat(new) }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
private :consolidate_errors!
|
140
|
+
|
141
|
+
# Overridden to use {FlatMap::Errors} instead of ActiveModel ones.
|
142
|
+
#
|
143
|
+
# @return [FlatMap::Errors]
|
144
|
+
def errors
|
145
|
+
@errors ||= FlatMap::Errors.new(self)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Extract Rails multiparam parameters from the +params+, modifying
|
149
|
+
# original hash. Behaves somewhat like
|
150
|
+
# {ActiveRecord::AttributeAssignment#extract_callstack_for_multiparameter_attributes}
|
151
|
+
# See this method for more details.
|
152
|
+
#
|
153
|
+
# @param [Hash] params
|
154
|
+
# @return [Array<FlatMap::Mapping>] return value is not used, original
|
155
|
+
# +params+ hash is modified instead and used later on.
|
156
|
+
def extract_multiparams!(params)
|
157
|
+
all_mappings.select(&:multiparam?).each do |mapping|
|
158
|
+
param_keys = params.keys.
|
159
|
+
select { |key| key.to_s =~ /#{mapping.full_name}\(\d+[isf]\)/ }.
|
160
|
+
sort_by{ |key| key.to_s[/\((\d+)\w*\)/, 1].to_i }
|
161
|
+
|
162
|
+
next if param_keys.empty?
|
163
|
+
|
164
|
+
args = param_keys.inject([]) do |values, key|
|
165
|
+
value = params.delete key
|
166
|
+
type = key[/\(\d+(\w*)\)/, 1]
|
167
|
+
value = value.send("to_#{type}") unless type.blank?
|
168
|
+
|
169
|
+
values.push value
|
170
|
+
values
|
171
|
+
end
|
172
|
+
|
173
|
+
params[mapping.name] = mapping.multiparam.new(*args) rescue nil
|
174
|
+
end
|
175
|
+
end
|
176
|
+
private :extract_multiparams!
|
177
|
+
end
|
178
|
+
end
|