flat_map 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NjNmMzU5MGI0NjIwZGQyZmY4YzBlM2RhYzFmYTMzNGJmM2ZiMzIzMA==
4
+ NmZiN2RlYjcwY2U5YmIzMzAyYWM3ZGE3NzA4NDQyMDI2OGE0MDFhYw==
5
5
  data.tar.gz: !binary |-
6
- NjAxZjRjYThiNWMxN2QwN2NkMWNkODFhZDg0NjEzZDQ0MGE5YWM5ZQ==
7
- SHA512:
6
+ MTYwMjllODAzY2IwNDQ4ZGNiNTJmZDA2NzgxMDU0N2ZkZDEzN2EwMA==
7
+ !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- N2M2NmQzZmFkMjZjMjg3NThmZjhjN2I0YmI2NGMyMWQxZTcyNTYwYTFmNzJj
10
- NmM0Yzc1NDg4YWM1MmM1ZGE3ZTA3MTUzZTNmNjgwZGZkZDYxN2ViMzliNDVl
11
- NWQ4Yjg3ZDI5NTg2MmZiOTQ2ZjQ5ODk1YTUwODQyN2JmNzIxNDQ=
9
+ ZDU4ZDYzYzAzYTBhMDkwZDRlODliODc3ODcyMWM3ODE2YzZkYWVhMmMwN2Nj
10
+ NWJkNDdhOTc1N2RiMTkwZjFlOGYzOGVlZWY4ZjlhZDliZjQ3YmEwYWY2YjU0
11
+ YTJiMDA0ZjdiMWQ4NGQzYjQwZGEyMzIyNzAwNWYzZjBmMWUxNjQ=
12
12
  data.tar.gz: !binary |-
13
- ZTg1ZmI2NzY1NjA3ZGYyYzQ1NTAwYzFlMDUxODY2Y2M5YmNlMWI5YTNkNWYx
14
- MTI5NGQwNDA5YmQwOTNjOTJiYmRhZDdjYWY0YTkwMzU4MzQxM2FlYjU5Nzgy
15
- YzlkYmEzNmNlM2ExNTA5M2E5Y2E1OGFlNDViYmU1MGVmYzg5M2U=
13
+ N2UyMjkzNmRkNjQ0OWI0YmYyOGEwMDE2ZjFjYzc2MWFkN2MxMjZlZTM4MDQ2
14
+ YThhYzUyYzkwZDcxMzFmODI5MzQ0MDQ2M2M5MmQzY2UzMzljODYzMmI2NmUw
15
+ OTQ2MmNkNTljMjgyYmEwN2NhMzJhYTBjZjhlMDgzMDZkOTJmOTA=
@@ -1,9 +1,14 @@
1
+ require 'ostruct'
1
2
  require 'active_support/core_ext'
2
3
  require 'active_record'
3
4
 
4
5
  require "flat_map/version"
5
6
  require 'flat_map/mapping'
6
7
  require 'flat_map/errors'
7
- require 'flat_map/base_mapper'
8
- require 'flat_map/mapper'
9
- require 'flat_map/empty_mapper'
8
+ require 'flat_map/open_mapper'
9
+ require 'flat_map/model_mapper'
10
+
11
+ module FlatMap
12
+ # for backwards compatability
13
+ Mapper = ModelMapper
14
+ end
@@ -180,34 +180,15 @@ module FlatMap
180
180
  # mapper.read[:first_name] # => John
181
181
  # mapper.first_name # => 'John'
182
182
  # mapper.last_name = 'Smith'
183
- class Mapper < BaseMapper
183
+ class ModelMapper < OpenMapper
184
184
  extend ActiveSupport::Autoload
185
185
 
186
- autoload :Targeting
186
+ autoload :Persistence
187
187
  autoload :Skipping
188
188
 
189
- include Targeting
189
+ include Persistence
190
190
  include Skipping
191
191
 
192
- attr_reader :target
193
-
194
192
  delegate :logger, :to => :target
195
-
196
- # Initializes +mapper+ with +target+ and +traits+, which are
197
- # used to fetch proper list of mounted mappers. Raises error
198
- # if target is not specified.
199
- #
200
- # @param [Object] target Target of mapping
201
- # @param [*Symbol] traits List of traits
202
- # @raise [FlatMap::Mapper::NoTargetError]
203
- def initialize(target, *traits)
204
- raise Targeting::NoTargetError.new(self.class) unless target.present?
205
-
206
- @target, @traits = target, traits
207
-
208
- if block_given?
209
- singleton_class.trait :extension, &Proc.new
210
- end
211
- end
212
193
  end
213
194
  end
@@ -1,23 +1,10 @@
1
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
- module Mapper::Targeting
6
- # Raised when mapper is initialized with no target defined
7
- class NoTargetError < ArgumentError
8
- # Initializes exception with a name of mapper class.
9
- #
10
- # @param [Class] mapper_class class of mapper being initialized
11
- def initialize(mapper_class)
12
- super("Target object is required to initialize #{mapper_class.name}")
13
- end
14
- end
15
-
2
+ # This module enhances and modifies original FlatMap::OpenMapper::Persistance
3
+ # functionality for ActiveRecord models as targets.
4
+ module ModelMapper::Persistence
16
5
  extend ActiveSupport::Concern
17
6
 
18
7
  included do
19
- define_callbacks :save
20
-
21
8
  # Writer of the target class name. Allows manual control over target
22
9
  # class of the mapper, for example:
23
10
  #
@@ -29,15 +16,6 @@ module FlatMap
29
16
 
30
17
  # ModelMethods class macros
31
18
  module ClassMethods
32
- # Create a new mapper object wrapped around new instance of its
33
- # +target_class+, with a list of passed +traits+ applied to it.
34
- #
35
- # @param [*Symbol] traits
36
- # @return [FlatMap::Mapper] mapper
37
- def build(*traits, &block)
38
- new(target_class.new, *traits, &block)
39
- end
40
-
41
19
  # Find a record of the +target_class+ by +id+ and use it as a
42
20
  # target for a new mapper, with a list of passed +traits+ applied
43
21
  # to it.
@@ -71,8 +49,8 @@ module FlatMap
71
49
  #
72
50
  # @return [String]
73
51
  def default_target_class_name
74
- ancestor_classes = ancestors.select{ |ancestor| ancestor.is_a? Class }
75
- base_mapper_index = ancestor_classes.index(::FlatMap::Mapper)
52
+ ancestor_classes = ancestors.select{ |ancestor| ancestor.is_a? Class }
53
+ base_mapper_index = ancestor_classes.index(::FlatMap::ModelMapper)
76
54
  ancestor_classes[base_mapper_index - 1].name[/^([\w:]+)Mapper.*$/, 1]
77
55
  end
78
56
  end
@@ -1,8 +1,8 @@
1
1
  module FlatMap
2
- # This helper module slightly enhances functionality of the
3
- # {BaseMapper::Skipping} module for most commonly used +ActiveRecord+ targets.
4
- # This is done to improve modularity of the {FlatMap} mappers.
5
- module Mapper::Skipping
2
+ # This helper module slightly enhances ofunctionality of the
3
+ # {FlatMap::OpenMapper::Skipping} module for most commonly
4
+ # used +ActiveRecord+ targets.
5
+ module ModelMapper::Skipping
6
6
  # Extend original #skip! method for Rails-models-based targets
7
7
  #
8
8
  # Note that this will mark the target record as
@@ -1,9 +1,17 @@
1
1
  module FlatMap
2
- # +BaseMapper+ is an abstract class that hosts overwhelming majority
3
- # of common functionality of {EmptyMapper EmptyMappers} and {Mapper Mappers}.
4
- #
5
- # For more detailed information on what mappers are, refer to {Mapper} documentation.
6
- class BaseMapper
2
+ # Base Mapper that can be used for mounting other mappers, handling business logic,
3
+ # etc. For the intentional usage of mappers, pleas see {ModelMapper}
4
+ class OpenMapper
5
+ # Raised when mapper is initialized with no target defined
6
+ class NoTargetError < ArgumentError
7
+ # Initializes exception with a name of mapper class.
8
+ #
9
+ # @param [Class] mapper_class class of mapper being initialized
10
+ def initialize(mapper_class)
11
+ super("Target object is required to initialize #{mapper_class.name}")
12
+ end
13
+ end
14
+
7
15
  extend ActiveSupport::Autoload
8
16
 
9
17
  autoload :Mapping
@@ -22,8 +30,8 @@ module FlatMap
22
30
  include Persistence
23
31
  include Skipping
24
32
 
25
- attr_reader :traits
26
33
  attr_writer :host, :suffix
34
+ attr_reader :target, :traits
27
35
  attr_accessor :owner, :name
28
36
 
29
37
  # Callback to dup mappings and mountings on inheritance.
@@ -38,11 +46,21 @@ module FlatMap
38
46
  subclass.mountings = mountings.dup
39
47
  end
40
48
 
41
- # Raise exception on trying to initialize an instance.
49
+ # Initializes +mapper+ with +target+ and +traits+, which are
50
+ # used to fetch proper list of mounted mappers. Raises error
51
+ # if target is not specified.
42
52
  #
43
- # @raise [RuntimeError]
44
- def initialize
45
- raise 'BaseMapper is abstract class and cannot be initialized'
53
+ # @param [Object] target Target of mapping
54
+ # @param [*Symbol] traits List of traits
55
+ # @raise [FlatMap::Mapper::NoTargetError]
56
+ def initialize(target, *traits)
57
+ raise NoTargetError.new(self.class) unless target.present?
58
+
59
+ @target, @traits = target, traits
60
+
61
+ if block_given?
62
+ singleton_class.trait :extension, &Proc.new
63
+ end
46
64
  end
47
65
 
48
66
  # Return a simple string representation of +mapper+. Done so to
@@ -8,22 +8,22 @@ module FlatMap
8
8
  # NOTE: :to_ary method is called internally by Ruby 1.9.3 when we call
9
9
  # something like [mapper].flatten. And we DO want default behavior
10
10
  # for handling this missing method.
11
- module BaseMapper::AttributeMethods
11
+ module OpenMapper::AttributeMethods
12
12
  # Lazily define reader and writer methods for all mappings available
13
13
  # to the mapper, and extend +self+ with it.
14
14
  def method_missing(name, *args, &block)
15
15
  if name == :to_ary ||
16
16
  @attribute_methods_defined ||
17
- FlatMap::BaseMapper.protected_instance_methods.include?(name)
17
+ self.class.protected_instance_methods.include?(name)
18
18
  return super
19
19
  end
20
20
 
21
21
  mappings = all_mappings
22
- valid_names = mappings.map{ |_mapping|
23
- mapping_full_name = _mapping.full_name
24
- [ mapping_full_name,
25
- "#{mapping_full_name}=".to_sym ]
26
- }.flatten
22
+ valid_names = mappings.map do |mapping|
23
+ full_name = mapping.full_name
24
+ [full_name, "#{full_name}=".to_sym]
25
+ end
26
+ valid_names.flatten!
27
27
 
28
28
  return super unless valid_names.include?(name)
29
29
 
@@ -39,12 +39,13 @@ module FlatMap
39
39
  # @return [Module] module with method definitions
40
40
  def attribute_methods(mappings)
41
41
  Module.new do
42
- mappings.each do |_mapping|
43
- mapping_full_name = _mapping.full_name
44
- define_method(mapping_full_name){ |*args| _mapping.read(*args) }
42
+ mappings.each do |mapping|
43
+ full_name = mapping.full_name
44
+
45
+ define_method(full_name){ |*args| mapping.read(*args) }
45
46
 
46
- define_method("#{mapping_full_name}=") do |value|
47
- _mapping.write(value)
47
+ define_method("#{full_name}=") do |value|
48
+ mapping.write(value)
48
49
  end
49
50
  end
50
51
  end
@@ -3,7 +3,7 @@ module FlatMap
3
3
  # and to instantiate and setup corresponding mapper objects thereafter.
4
4
  # Factory objects are stored by mapper classes in opposite to actual
5
5
  # mounted mappers that are stored by mapper objects themselves.
6
- class BaseMapper::Factory
6
+ class OpenMapper::Factory
7
7
  # Initializes factory with an identifier (name of a mounted mapper,
8
8
  # or the actual class for a trait) and a set of options. Those args
9
9
  # are used to create actual mapper object for the host mapper.
@@ -46,69 +46,83 @@ module FlatMap
46
46
  # Return the anonymous trait class if the factory defines a trait.
47
47
  # Fetch and return the class of a mapper defined by a symbol.
48
48
  #
49
- # @return [Class] ancestor of {FlatMap::BaseMapper}
49
+ # @return [Class] ancestor of {FlatMap::OpenMapper}
50
50
  def mapper_class
51
- return @identifier if traited?
51
+ @mapper_class ||= begin
52
+ case
53
+ when traited? then @identifier
54
+ when @options[:open] then open_mapper_class
55
+ else
56
+ class_name = @options[:mapper_class_name] || "#{name.to_s.camelize}Mapper"
57
+ class_name.constantize
58
+ end
59
+ end
60
+ end
52
61
 
53
- class_name = @options[:mapper_class_name] || "#{name.to_s.camelize}Mapper"
54
- class_name.constantize
62
+ # Return descendant of +OpenMapper+ class to be used when mounting
63
+ # open mappers.
64
+ #
65
+ # @return [Class]
66
+ def open_mapper_class
67
+ klass = Class.new(OpenMapper)
68
+ klass_name = "#{name.to_s.camelize}Mapper"
69
+ klass.singleton_class.send(:define_method, :name){ klass_name }
70
+ klass
55
71
  end
56
72
 
57
- # Return +true+ if factory should create targeted mapper.
73
+ # Return +true+ if mapper to me mounted is +ModelMapper+
58
74
  #
59
75
  # @return [Boolean]
60
- def targeted_mount?
61
- mapper_class < Mapper
76
+ def model_mount?
77
+ mapper_class < ModelMapper
78
+ end
79
+
80
+ # Return +true+ if mapper to me mounted is not +ModelMapper+, i.e. +OpenMapper+.
81
+ #
82
+ # @return [Boolean]
83
+ def open_mount?
84
+ !model_mount?
62
85
  end
63
86
 
64
87
  # Fetch the target for the mapper being created based on target of a host mapper.
65
88
  #
66
- # @param [FlatMap::BaseMapper] mapper Host mapper
89
+ # @param [FlatMap::OpenMapper] mapper Host mapper
67
90
  # @return [Object] target for new mapper
68
91
  def fetch_target_from(mapper)
69
- return explicit_target!(mapper) if mapper.is_a?(EmptyMapper) && targeted_mount?
70
-
71
92
  owner_target = mapper.target
72
93
 
73
94
  return owner_target if traited?
74
95
 
75
- explicit_target(owner_target) ||
76
- target_from_association(owner_target) ||
77
- target_from_name(owner_target)
96
+ if open_mount?
97
+ explicit_target(mapper) || new_target
98
+ else
99
+ explicit_target(mapper) ||
100
+ target_from_association(owner_target) ||
101
+ target_from_name(owner_target) ||
102
+ new_target
103
+ end
78
104
  end
79
105
 
80
- # When creating mappers mounted on top of EmptyMapper, target cannot be implicitly
81
- # fetched from it and should be specified explicitly.
106
+ # Return new instance of +target_class+ of the mapper.
82
107
  #
83
- # @param [FlatMap::EmptyMapper] mapper Host empty mapper
84
- # @return [Object] target for new mapper
85
- def explicit_target!(mapper)
86
- target = @options[:target]
87
-
88
- if target.present?
89
- case target
90
- when Proc then target.call
91
- when Symbol then mapper.send(target)
92
- else target
93
- end
94
- else
95
- raise Mapper::Targeting::NoTargetError.new(mapper_class)
96
- end
108
+ # @return [Object]
109
+ def new_target
110
+ mapper_class.target_class.new
97
111
  end
98
112
 
99
113
  # Try to use explicit target definition passed in options to fetch a
100
114
  # target. If this value is a +Proc+, will call it with owner target as
101
115
  # argument.
102
116
  #
103
- # @param [Object] owner_target
117
+ # @param [FlatMap::OpenMapper] mapper
104
118
  # @return [Object, nil] target for new mapper.
105
- def explicit_target(owner_target)
119
+ def explicit_target(mapper)
106
120
  if @options.key?(:target)
107
121
  target = @options[:target]
108
- if target.is_a? Proc
109
- target.call(owner_target)
110
- else
111
- target
122
+ case target
123
+ when Proc then target.call(mapper.target)
124
+ when Symbol then mapper.send(target)
125
+ else target
112
126
  end
113
127
  end
114
128
  end
@@ -132,7 +146,7 @@ module FlatMap
132
146
  # # it based on :has_many association, i.e. foo.bars.build
133
147
  # end
134
148
  def target_from_association(owner_target)
135
- return unless owner_target.kind_of?(ActiveRecord::Base)
149
+ return unless owner_target.is_a?(ActiveRecord::Base)
136
150
 
137
151
  reflection = reflection_from_target(owner_target)
138
152
  return unless reflection.present?
@@ -145,7 +159,6 @@ module FlatMap
145
159
  owner_target.send(name) || owner_target.send("build_#{name}")
146
160
  when reflection_macro == :has_many
147
161
  owner_target.association(reflection.name).build
148
- else # nil
149
162
  end
150
163
  end
151
164
 
@@ -157,8 +170,8 @@ module FlatMap
157
170
  def reflection_from_target(target)
158
171
  return unless name.present? && target.is_a?(ActiveRecord::Base)
159
172
  target_class = target.class
160
- reflection = target_class.reflect_on_association(name)
161
- reflection || target_class.reflect_on_association(name.to_s.pluralize.to_sym)
173
+ reflection = target_class.reflect_on_association(name)
174
+ reflection || target_class.reflect_on_association(name.to_s.pluralize.to_sym)
162
175
  end
163
176
 
164
177
  # Send the name of the mounting to the target of the host mapper, and use
@@ -173,10 +186,10 @@ module FlatMap
173
186
  # be created should be saved. In particular, targets of <tt>:belongs_to</tt>
174
187
  # associations should be saved before target of +mapper+ is saved.
175
188
  #
176
- # @param [FlatMap::BaseMapper] mapper
189
+ # @param [FlatMap::OpenMapper] mapper
177
190
  # @return [Symbol]
178
191
  def fetch_save_order(mapper)
179
- return :after if mapper.is_a?(EmptyMapper)
192
+ return :after unless mapper.is_a?(ModelMapper)
180
193
 
181
194
  reflection = reflection_from_target(mapper.target)
182
195
  return unless reflection.present?
@@ -188,24 +201,16 @@ module FlatMap
188
201
  # Otherwise, assign the name of the factory to it to be able to find it
189
202
  # later on.
190
203
  #
191
- # @param [FlatMap::BaseMapper] mapper Host mapper
204
+ # @param [FlatMap::OpenMapper] mapper Host mapper
192
205
  # @param [*Symbol] owner_traits List of traits to be applied to a newly created mapper
193
206
  def create(mapper, *owner_traits)
194
207
  save_order = @options[:save] || fetch_save_order(mapper) || :after
195
- all_traits = (traits + owner_traits).uniq
196
-
197
- new_one =
198
- if targeted_mount? then
199
- mapper_class.new(fetch_target_from(mapper), *all_traits, &@extension)
200
- else
201
- mapper_class.new(*all_traits, &@extension)
202
- end
203
-
208
+ new_one = mapper_class.new(fetch_target_from(mapper), *(traits + owner_traits).uniq, &@extension)
204
209
  if traited?
205
210
  new_one.owner = mapper
206
211
  else
207
- new_one.host = mapper
208
- new_one.name = @identifier
212
+ new_one.host = mapper
213
+ new_one.name = @identifier
209
214
  new_one.save_order = save_order
210
215
 
211
216
  if (suffix = @options[:suffix] || mapper.suffix).present?
@@ -229,10 +234,10 @@ module FlatMap
229
234
  return true unless traited?
230
235
 
231
236
  traits.include?(trait_name) ||
232
- mapper_class.mountings.any?{ |factory|
237
+ mapper_class.mountings.any? do |factory|
233
238
  factory.traited? &&
234
- factory.required_for_any_trait?(traits)
235
- }
239
+ factory.required_for_any_trait?(traits)
240
+ end
236
241
  end
237
242
  end
238
243
  end