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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.metrics +17 -0
  4. data/.rspec +4 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +9 -0
  8. data/Gemfile +20 -0
  9. data/HornsAndHooves-flat_map.gemspec +29 -0
  10. data/LICENSE +21 -0
  11. data/README.markdown +214 -0
  12. data/Rakefile +15 -0
  13. data/lib/flat_map.rb +14 -0
  14. data/lib/flat_map/errors.rb +57 -0
  15. data/lib/flat_map/mapping.rb +124 -0
  16. data/lib/flat_map/mapping/factory.rb +21 -0
  17. data/lib/flat_map/mapping/reader.rb +12 -0
  18. data/lib/flat_map/mapping/reader/basic.rb +28 -0
  19. data/lib/flat_map/mapping/reader/formatted.rb +45 -0
  20. data/lib/flat_map/mapping/reader/formatted/formats.rb +28 -0
  21. data/lib/flat_map/mapping/reader/method.rb +25 -0
  22. data/lib/flat_map/mapping/reader/proc.rb +15 -0
  23. data/lib/flat_map/mapping/writer.rb +11 -0
  24. data/lib/flat_map/mapping/writer/basic.rb +25 -0
  25. data/lib/flat_map/mapping/writer/method.rb +28 -0
  26. data/lib/flat_map/mapping/writer/proc.rb +18 -0
  27. data/lib/flat_map/model_mapper.rb +195 -0
  28. data/lib/flat_map/model_mapper/persistence.rb +108 -0
  29. data/lib/flat_map/model_mapper/skipping.rb +45 -0
  30. data/lib/flat_map/open_mapper.rb +113 -0
  31. data/lib/flat_map/open_mapper/attribute_methods.rb +55 -0
  32. data/lib/flat_map/open_mapper/factory.rb +244 -0
  33. data/lib/flat_map/open_mapper/mapping.rb +123 -0
  34. data/lib/flat_map/open_mapper/mounting.rb +168 -0
  35. data/lib/flat_map/open_mapper/persistence.rb +178 -0
  36. data/lib/flat_map/open_mapper/skipping.rb +66 -0
  37. data/lib/flat_map/open_mapper/traits.rb +95 -0
  38. data/lib/flat_map/version.rb +3 -0
  39. data/spec/flat_map/errors_spec.rb +23 -0
  40. data/spec/flat_map/mapper/attribute_methods_spec.rb +36 -0
  41. data/spec/flat_map/mapper/callbacks_spec.rb +76 -0
  42. data/spec/flat_map/mapper/factory_spec.rb +285 -0
  43. data/spec/flat_map/mapper/mapping_spec.rb +98 -0
  44. data/spec/flat_map/mapper/mounting_spec.rb +142 -0
  45. data/spec/flat_map/mapper/persistence_spec.rb +152 -0
  46. data/spec/flat_map/mapper/skipping_spec.rb +91 -0
  47. data/spec/flat_map/mapper/targeting_spec.rb +156 -0
  48. data/spec/flat_map/mapper/traits_spec.rb +172 -0
  49. data/spec/flat_map/mapper/validations_spec.rb +72 -0
  50. data/spec/flat_map/mapper_spec.rb +9 -0
  51. data/spec/flat_map/mapping/factory_spec.rb +12 -0
  52. data/spec/flat_map/mapping/reader/basic_spec.rb +15 -0
  53. data/spec/flat_map/mapping/reader/formatted_spec.rb +62 -0
  54. data/spec/flat_map/mapping/reader/method_spec.rb +13 -0
  55. data/spec/flat_map/mapping/reader/proc_spec.rb +13 -0
  56. data/spec/flat_map/mapping/writer/basic_spec.rb +15 -0
  57. data/spec/flat_map/mapping/writer/method_spec.rb +13 -0
  58. data/spec/flat_map/mapping/writer/proc_spec.rb +13 -0
  59. data/spec/flat_map/mapping_spec.rb +123 -0
  60. data/spec/flat_map/open_mapper_spec.rb +19 -0
  61. data/spec/spec_helper.rb +7 -0
  62. data/tmp/metric_fu/_data/20131218.yml +6902 -0
  63. data/tmp/metric_fu/_data/20131219.yml +6726 -0
  64. metadata +220 -0
@@ -0,0 +1,124 @@
1
+ module FlatMap
2
+ # Encapsulates mapping concept used by mappers. Each mapping belongs to
3
+ # a particular mapper and has its own reader and writer objects.
4
+ class Mapping
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :Reader
8
+ autoload :Writer
9
+ autoload :Factory
10
+
11
+ attr_reader :mapper, :name, :full_name, :target_attribute
12
+ attr_reader :reader, :writer
13
+ attr_reader :multiparam
14
+
15
+ delegate :target, :to => :mapper
16
+ delegate :write, :to => :writer, :allow_nil => true
17
+ delegate :read, :to => :reader, :allow_nil => true
18
+
19
+ # Initialize a mapping, passing to it a +mapper+, which is
20
+ # a gateway to actual +target+, +name+, which is an external
21
+ # identifier, +target_attribute+, which is used to access
22
+ # actual information of the +target+, and +options+.
23
+ #
24
+ # @param [FlatMap::Mapper] mapper
25
+ # @param [Symbol] name
26
+ # @param [Symbol] target_attribute
27
+ # @param [Hash] options
28
+ # @option [Symbol, Proc] :reader specifies how value will
29
+ # be read from the +target+
30
+ # @option [Symbol] :format specifies additional processing
31
+ # of the value on reading
32
+ # @option [Symbol, Proc] :writer specifies how value will
33
+ # be written to the +target+
34
+ # @option [Class] :multiparam specifies multiparam Class,
35
+ # object of which will be instantiated on writing
36
+ # multiparam attribute passed from the Rails form
37
+ def initialize(mapper, name, target_attribute, options = {})
38
+ @mapper = mapper
39
+ @name = name
40
+ @target_attribute = target_attribute
41
+
42
+ @full_name = mapper.suffixed? ? :"#{@name}_#{mapper.suffix}" : name
43
+
44
+ @multiparam = options[:multiparam]
45
+
46
+ fetch_reader(options)
47
+ fetch_writer(options)
48
+ end
49
+
50
+ # Return +true+ if the mapping was created with the <tt>:multiparam</tt>
51
+ # option set.
52
+ #
53
+ # @return [Boolean]
54
+ def multiparam?
55
+ !!@multiparam
56
+ end
57
+
58
+ # Lookup the passed hash of params for the key that corresponds
59
+ # to the +full_name+ of +self+, and write it if it is present.
60
+ #
61
+ # @param [Hash] params
62
+ # @return [Object] value assigned
63
+ def write_from_params(params)
64
+ write(params[full_name]) if params.key?(full_name) && writer.present?
65
+ end
66
+
67
+ # Return a hash of a single key => value pair, where key
68
+ # corresponds to +full_name+ and +value+ to value read from
69
+ # +target+. If +reader+ is not set, return an empty hash.
70
+ #
71
+ # @return [Hash]
72
+ def read_as_params
73
+ reader ? {full_name => read} : {}
74
+ end
75
+
76
+ # Instantiate a +reader+ object based on the <tt>:reader</tt>
77
+ # and <tt>:format</tt> values of +options+.
78
+ #
79
+ # @param [Hash] options
80
+ # @return [FlatMap::Mapping::Reader::Basic]
81
+ def fetch_reader(options)
82
+ options_reader = options[:reader]
83
+
84
+ @reader =
85
+ case options_reader
86
+ when Symbol, String
87
+ Reader::Method.new(self, options_reader)
88
+ when Proc
89
+ Reader::Proc.new(self, options_reader)
90
+ when false
91
+ nil
92
+ else
93
+ if options.key?(:format) then
94
+ Reader::Formatted.new(self, options[:format])
95
+ else
96
+ Reader::Basic.new(self)
97
+ end
98
+ end
99
+ end
100
+ private :fetch_reader
101
+
102
+ # Instantiate a +writer+ object based on the <tt>:writer</tt>
103
+ # value of +options+.
104
+ #
105
+ # @param [Hash] options
106
+ # @return [FlatMap::Mapping::Writer::Basic]
107
+ def fetch_writer(options)
108
+ options_writer = options[:writer]
109
+
110
+ @writer =
111
+ case options_writer
112
+ when Symbol, String
113
+ Writer::Method.new(self, options_writer)
114
+ when Proc
115
+ Writer::Proc.new(self, options_writer)
116
+ when false
117
+ nil
118
+ else
119
+ Writer::Basic.new(self)
120
+ end
121
+ end
122
+ private :fetch_writer
123
+ end
124
+ end
@@ -0,0 +1,21 @@
1
+ module FlatMap
2
+ # Factory objects store mapping definitions within mapper class and are
3
+ # used eventually to generate mapping objects for a particular mapper.
4
+ class Mapping::Factory
5
+ # Simply store all arguments necessary to create a new mapping for
6
+ # a specific mapper.
7
+ #
8
+ # @param [*Object] args
9
+ def initialize(*args)
10
+ @args = args
11
+ end
12
+
13
+ # Return a new mapping, initialized by +mapper+ and <tt>@args</tt>.
14
+ #
15
+ # @param [FlatMap::Mapper] mapper
16
+ # @return [FlatMap::Mapping]
17
+ def create(mapper)
18
+ Mapping.new(mapper, *@args)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ module FlatMap
2
+ # Reader module hosts various readers that are used by
3
+ # mappings for reading and returning values.
4
+ module Mapping::Reader
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :Basic
8
+ autoload :Method
9
+ autoload :Proc
10
+ autoload :Formatted
11
+ end
12
+ end
@@ -0,0 +1,28 @@
1
+ module FlatMap
2
+ module Mapping::Reader
3
+ # Basic reader simply sends a mapped attribute to the target
4
+ # and returns the result value.
5
+ class Basic
6
+ attr_reader :mapping
7
+
8
+ delegate :target, :target_attribute, :to => :mapping
9
+
10
+ # Initialize the reader with a mapping.
11
+ #
12
+ # @param [FlatMap::Mapping] mapping
13
+ def initialize(mapping)
14
+ @mapping = mapping
15
+ end
16
+
17
+ # Send the attribute method to the target and return its value.
18
+ # As a base class for readers, it allows to pass additional
19
+ # arguments when reading value (for example, used by :enum
20
+ # format of {Formatted} reader)
21
+ #
22
+ # @return [Object] value returned by reading
23
+ def read(*)
24
+ target.send(target_attribute)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,45 @@
1
+ module FlatMap
2
+ module Mapping::Reader
3
+ # Formatted reader reads the value the same as Basic reader does, but
4
+ # additionally performs value postprocessing. All processing methods
5
+ # are defined within {Formatted::Formats} module. The method is chosen
6
+ # based on the :format option when the mapping is defined.
7
+ class Formatted < Basic
8
+ extend ActiveSupport::Autoload
9
+ autoload :Formats
10
+
11
+ include Formats
12
+
13
+ # Initialize the reader with a +mapping+ and a +format+.
14
+ #
15
+ # @param [FlatMap::Mapping] mapping
16
+ # @param [Symbol] format
17
+ def initialize(mapping, format)
18
+ @mapping, @format = mapping, format
19
+ end
20
+
21
+ # Read the value just like the {Basic} reader does, but
22
+ # additionally send the returned value to its format method.
23
+ #
24
+ # Additional arguments will be passed to formatting function
25
+ # of the mapping's format.
26
+ #
27
+ # @return [Object] formatted value
28
+ def read(*args)
29
+ format_value(super, *args)
30
+ end
31
+
32
+ # Send the +value+ to the format method, defined in the {Format}
33
+ # module and specified upon reader initialization.
34
+ #
35
+ # Additional optional arguments are passed as well.
36
+ #
37
+ # @param [Object] value
38
+ # @return [Object] formatted value
39
+ def format_value(value, *args)
40
+ send(@format, value, *args)
41
+ end
42
+ private :format_value
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ module FlatMap
2
+ module Mapping::Reader
3
+ # Hosts various formats that can be applied to values read by mappings
4
+ # for post-processing.
5
+ module Formatted::Formats
6
+ if defined? I18n
7
+ # Pass +value+ to <tt>I18n::l</tt> method.
8
+ def i18n_l(value)
9
+ I18n::l(value) if value
10
+ end
11
+ end
12
+
13
+ if defined? PowerEnum
14
+ # Return the specified +property+ of a +value+ which
15
+ # is supposed to be an +enum+ record. By default,
16
+ # uses <tt>:name</tt>. However, <tt>:description</tt>
17
+ # might be also useful for UI purposes.
18
+ #
19
+ # @param [Object] value
20
+ # @param [Symbol] property
21
+ # @return [Object]
22
+ def enum(value, property = :name)
23
+ value.send(property) if value
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ module FlatMap
2
+ module Mapping::Reader
3
+ # Method mapper calls a method, defined by the mapper, sending
4
+ # the mapping object to it as an argument.
5
+ class Method < Basic
6
+ delegate :mapper, :to => :mapping
7
+
8
+ # Initialize the reader with a +mapping+ and a +method+.
9
+ #
10
+ # @param [FlatMap::Mapping] mapping
11
+ # @param [Symbol] method name
12
+ def initialize(mapping, method)
13
+ @mapping, @method = mapping, method
14
+ end
15
+
16
+ # Send the <tt>@method</tt> to the mapping's mapper, passing
17
+ # the mapping itself to it.
18
+ #
19
+ # @return [Object] value returned by reader
20
+ def read
21
+ mapper.send(@method, mapping)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ module FlatMap
2
+ module Mapping::Reader
3
+ # Proc reader accepts a lambda and calls it with the target
4
+ # as an argument for reading.
5
+ class Proc < Method
6
+ # Call a <tt>@method</tt>, which is a {Proc} object,
7
+ # passing the +target+ object to it.
8
+ #
9
+ # @return [Object] value returned by reader's lambda
10
+ def read
11
+ @method.call(target)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module FlatMap
2
+ # Writer module hosts various writer classes that are used
3
+ # by mappings to assign values to the target of an associated mapper.
4
+ module Mapping::Writer
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :Basic
8
+ autoload :Method
9
+ autoload :Proc
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ module FlatMap
2
+ module Mapping::Writer
3
+ # Basic writer simply calls the target's attribute assignment method
4
+ # passing to it the value being written.
5
+ class Basic
6
+ attr_reader :mapping
7
+
8
+ delegate :target, :target_attribute, :to => :mapping
9
+
10
+ # Initialize writer by passing +mapping+ to it.
11
+ def initialize(mapping)
12
+ @mapping = mapping
13
+ end
14
+
15
+ # Call the assignment method of the target, passing
16
+ # the +value+ to it.
17
+ #
18
+ # @param [Object] value
19
+ # @return [Object] result of assignment
20
+ def write(value)
21
+ target.send("#{target_attribute}=", value)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,28 @@
1
+ module FlatMap
2
+ module Mapping::Writer
3
+ # Method writer calls a method defined by mapper and sends mapping
4
+ # and value to it as arguments.
5
+ #
6
+ # Note that this doesn't set anything on the target itself.
7
+ class Method < Basic
8
+ delegate :mapper, :to => :mapping
9
+
10
+ # Initialize the writer with a +mapping+ and +method+ name
11
+ # that should be called on the mapping's mapper.
12
+ #
13
+ # @param [FlatMap::Mapping] mapping
14
+ # @param [Symbol] method
15
+ def initialize(mapping, method)
16
+ @mapping, @method = mapping, method
17
+ end
18
+
19
+ # Write a +value+ by sending it, along with the mapping itself.
20
+ #
21
+ # @param [Object] value
22
+ # @return [Object] result of writing
23
+ def write(value)
24
+ mapper.send(@method, mapping, value)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,18 @@
1
+ module FlatMap
2
+ module Mapping::Writer
3
+ # Proc writer calls a lambda passed on the mapping definition and
4
+ # sends the mapper's target and value to it.
5
+ #
6
+ # Note that this doesn't set anything on the target itself.
7
+ class Proc < Method
8
+ # Call a <tt>@method</tt>, which is a +Proc+ object,
9
+ # passing it the mapping's +target+ and +value+.
10
+ #
11
+ # @param [Object] value
12
+ # @return [Object] result of writing
13
+ def write(value)
14
+ @method.call(target, value)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,195 @@
1
+ module FlatMap
2
+ # == Mapper
3
+ #
4
+ # FlatMap mappers are designed to provide complex set of data, distributed over
5
+ # associated AR models, in the simple form of a plain hash. They accept a plain
6
+ # hash of the same format and distribute its values over deeply nested AR models.
7
+ #
8
+ # To achieve this goal, Mapper uses three major concepts: Mappings, Mountings and
9
+ # Traits.
10
+ #
11
+ # === Mappings
12
+ #
13
+ # Mappings are defined view Mapper.map method. They represent a simple one-to-one
14
+ # relation between target attribute and a mapper, extended by additional features
15
+ # for convenience. The best way to show how they work is by example:
16
+ #
17
+ # class CustomerMapper < FlatMap::Mapper
18
+ # # When there is no need to rename attributes, they can be passed as array:
19
+ # map :first_name, :last_name
20
+ #
21
+ # # When hash is used, it will map field name to attribute name:
22
+ # map :dob => :date_of_birth
23
+ #
24
+ # # Also, additional options can be used:
25
+ # map :name_suffix, :format => :enum
26
+ # map :password, :reader => false, :writer => :assign_password
27
+ #
28
+ # # Or you can combine all definitions together if they all are common:
29
+ # map :first_name, :last_name,
30
+ # :dob => :date_of_birth,
31
+ # :suffix => :name_suffix,
32
+ # :reader => :my_custom_reader
33
+ # end
34
+ #
35
+ # When mappings are defined, one can read and write values using them:
36
+ #
37
+ # mapper = CustomerMapper.find(1)
38
+ # mapper.read # => {:first_name => 'John', :last_name => 'Smith', :dob => '02/01/1970'}
39
+ # mapper.write(params) # will assign same-looking hash of arguments
40
+ #
41
+ # Following options may be used when defining mappings:
42
+ # [<tt>:format</tt>] Allows to additionally process output value on reading it. All formats are
43
+ # defined within FlatMap::Mapping::Reader::Formatted::Formats and
44
+ # specify the actual output of the mapping
45
+ # [<tt>:reader</tt>] Allows you to manually control reader value of a mapping, or a group of
46
+ # mappings listed on definition. When String or Symbol is used, will call
47
+ # a method, defined by mapper class, and pass mapping object to it. When
48
+ # lambda is used, mapper's target (the model) will be passed to it.
49
+ # [<tt>:writer</tt>] Just like with the :reader option, allows to control how value is assigned
50
+ # (written). Works the same way as :reader does, but additionally value is
51
+ # sent to both mapper method and lambda.
52
+ # [<tt>:multiparam</tt>] If used, multiparam attributes will be extracted from params, when
53
+ # those are passed for writing. Class should be passed as a value for
54
+ # this option. Object of this class will be initialized with the arguments
55
+ # extracted from params hash.
56
+ #
57
+ # === Mountings
58
+ #
59
+ # Mappers may be mounted on top of each other. This ability allows host mapper to gain all the
60
+ # mappings of the mounted mapper, thus providing more information for external usage (both reading
61
+ # and writing). Usually, target for mounted mapper may be obtained from association of target of
62
+ # the host mapper itself, but may be defined manually.
63
+ #
64
+ # class CustomerMapper < FlatMap::Mapper
65
+ # map :first_name, :last_name
66
+ # end
67
+ #
68
+ # class CustomerAccountMapper < FlatMap::Mapper
69
+ # map :source, :brand, :format => :enum
70
+ #
71
+ # mount :customer
72
+ # end
73
+ #
74
+ # mapper = CustomerAccountMapper.find(1)
75
+ # mapper.read # => {:first_name => 'John', :last_name => 'Smith', :source => nil, :brand => 'FTW'}
76
+ # mapper.write(params) # Will assign params for both CustomerAccount and Customer records
77
+ #
78
+ # The following options may be used when mounting a mapper:
79
+ # [<tt>:mapper_class</tt>] Specifies mapper class if it cannot be determined from mounting itself
80
+ # [<tt>:mapper_class_name</tt>] Alternate string form of class name instead of mapper_class.
81
+ # [<tt>:target</tt>] Allows to manually specify target for the new mapper. May be an object or lambda
82
+ # with arity of one that accepts host mapper target as argument. Comes in handy
83
+ # when target cannot be obviously detected or requires additional setup:
84
+ # <tt>mount :title, :target => lambda{ |customer| customer.title_customers.build.build_title }</tt>
85
+ # [<tt>:traits</tt>] Specifies list of traits to be used by mounted mapper
86
+ # [<tt>:suffix</tt>] Specifies the suffix that will be appended to all mappings and mountings of mapper,
87
+ # as well as mapper name itself.
88
+ #
89
+ # === Traits
90
+ #
91
+ # Traits allow mappers to encapsulate named sets of additional definitions, and use them optionally
92
+ # on mapper initialization. Everything that can be defined within the mapper may be defined within
93
+ # the trait. In fact, from the implementation perspective traits are mappers themselves that are
94
+ # mounted on the host mapper.
95
+ #
96
+ # class CustomerAccountMapper < FlatMap::Mapper
97
+ # map :brand, :format => :enum
98
+ #
99
+ # trait :with_email do
100
+ # map :source, :format => :enum
101
+ #
102
+ # mount :email_address
103
+ #
104
+ # trait :with_email_phones_residence do
105
+ # mount :customer, :traits => [:with_phone_numbers, :with_residence]
106
+ # end
107
+ # end
108
+ # end
109
+ #
110
+ # CustomerAccountMapper.find(1).read # => {:brand => 'TLP'}
111
+ # CustomerAccountMapper.find(1, :with_email).read # => {:brand => 'TLP', :source => nil, :email_address => 'j.smith@gmail.com'}
112
+ # CustomerAccountMapper.find(1, :with_email_phone_residence).read # => :brand, :source, :email_address, phone numbers,
113
+ # #:residence attributes - all will be available for reading and writing in plain hash
114
+ #
115
+ # === Extensions
116
+ #
117
+ # When mounting a mapper, one can pass an optional block. This block is used as an extension for a mounted
118
+ # mapper and acts as an anonymous trait. For example:
119
+ #
120
+ # class CustomerAccountMapper < FlatMap::Mapper
121
+ # mount :customer do
122
+ # map :dob => :date_of_birth, :format => :i18n_l
123
+ # validates_presence_of :dob
124
+ #
125
+ # mount :unique_identifier
126
+ #
127
+ # validates_acceptance_of :mandatory_agreement, :message => "You must check this box to continue"
128
+ # end
129
+ # end
130
+ #
131
+ # === Validation
132
+ #
133
+ # <tt>FlatMap::Mapper</tt> includes <tt>ActiveModel::Validations</tt> module, allowing each model to
134
+ # perform its own validation routines before trying to save its target (which is usually AR model). Mapper
135
+ # validation is very handy when mappers are used with Rails forms, since there no need to lookup for a
136
+ # deeply nested errors hash of the AR models to extract error messages. Mapper validations will attach
137
+ # messages to mapping names.
138
+ #
139
+ # Mapper validations become even more useful when used within traits, providing way of very flexible validation sets.
140
+ #
141
+ # === Callbacks
142
+ #
143
+ # Since mappers include <tt>ActiveModel::Validation</tt>, they already support ActiveSupport's callbacks.
144
+ # Additionally, <tt>:save</tt> callbacks have been defined (i.e. there have been define_callbacks <tt>:save</tt>
145
+ # call for <tt>FlatMap::Mapper</tt>). This allows you to control flow of mapper saving:
146
+ #
147
+ # set_callback :save, :before, :set_model_validation
148
+ #
149
+ # def set_model_validation
150
+ # target.use_validation :some_themis_validation
151
+ # end
152
+ #
153
+ # === Skipping
154
+ #
155
+ # In some cases, it is required to omit mapper processing after it has been created within mounting chain. If
156
+ # <tt>skip!</tt> method is called on mapper, it will return <tt>true</tt> for <tt>valid?</tt> and <tt>save</tt>
157
+ # method calls without performing any other operations. For example:
158
+ #
159
+ # class CustomerMapper < FlatMap::Mapper
160
+ # # some definitions
161
+ #
162
+ # trait :product_selection do
163
+ # attr_reader :selected_product_id
164
+ #
165
+ # mount :product
166
+ #
167
+ # set_callback :validate, :before, :ignore_new_product
168
+ #
169
+ # def ignore_new_bank_account
170
+ # mounting(:product).skip! if product_selected?
171
+ # end
172
+ #
173
+ # # some more definitions
174
+ # end
175
+ # end
176
+ #
177
+ # === Attribute Methods
178
+ #
179
+ # All mappers have the ability to read and write values via method calls:
180
+ #
181
+ # mapper.read[:first_name] # => John
182
+ # mapper.first_name # => 'John'
183
+ # mapper.last_name = 'Smith'
184
+ class ModelMapper < OpenMapper
185
+ extend ActiveSupport::Autoload
186
+
187
+ autoload :Persistence
188
+ autoload :Skipping
189
+
190
+ include Persistence
191
+ include Skipping
192
+
193
+ delegate :logger, :to => :target
194
+ end
195
+ end