HornsAndHooves-flat_map 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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