mongo_mapper 0.12.0 → 0.13.0.beta1

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 (154) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +35 -13
  3. data/bin/mmconsole +1 -1
  4. data/lib/mongo_mapper.rb +4 -0
  5. data/lib/mongo_mapper/connection.rb +17 -6
  6. data/lib/mongo_mapper/document.rb +1 -0
  7. data/lib/mongo_mapper/exceptions.rb +4 -1
  8. data/lib/mongo_mapper/extensions/binary.rb +1 -1
  9. data/lib/mongo_mapper/extensions/boolean.rb +20 -23
  10. data/lib/mongo_mapper/extensions/date.rb +3 -3
  11. data/lib/mongo_mapper/extensions/integer.rb +5 -1
  12. data/lib/mongo_mapper/extensions/kernel.rb +2 -0
  13. data/lib/mongo_mapper/extensions/ordered_hash.rb +23 -0
  14. data/lib/mongo_mapper/extensions/string.rb +2 -2
  15. data/lib/mongo_mapper/extensions/time.rb +7 -5
  16. data/lib/mongo_mapper/middleware/identity_map.rb +3 -4
  17. data/lib/mongo_mapper/plugins.rb +1 -1
  18. data/lib/mongo_mapper/plugins/associations.rb +11 -5
  19. data/lib/mongo_mapper/plugins/associations/base.rb +5 -3
  20. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +0 -0
  21. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +8 -8
  22. data/lib/mongo_mapper/plugins/associations/collection.rb +2 -0
  23. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +32 -7
  24. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +2 -2
  25. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +12 -12
  26. data/lib/mongo_mapper/plugins/associations/proxy.rb +5 -1
  27. data/lib/mongo_mapper/plugins/associations/single_association.rb +6 -6
  28. data/lib/mongo_mapper/plugins/clone.rb +4 -2
  29. data/lib/mongo_mapper/plugins/dirty.rb +22 -21
  30. data/lib/mongo_mapper/plugins/document.rb +4 -4
  31. data/lib/mongo_mapper/plugins/dumpable.rb +22 -0
  32. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +58 -9
  33. data/lib/mongo_mapper/plugins/identity_map.rb +42 -32
  34. data/lib/mongo_mapper/plugins/keys.rb +133 -54
  35. data/lib/mongo_mapper/plugins/keys/key.rb +68 -22
  36. data/lib/mongo_mapper/plugins/modifiers.rb +26 -19
  37. data/lib/mongo_mapper/plugins/persistence.rb +15 -5
  38. data/lib/mongo_mapper/plugins/querying.rb +15 -40
  39. data/lib/mongo_mapper/plugins/querying/{decorator.rb → decorated_plucky_query.rb} +24 -4
  40. data/lib/mongo_mapper/plugins/rails.rb +22 -2
  41. data/lib/mongo_mapper/plugins/safe.rb +8 -5
  42. data/lib/mongo_mapper/plugins/sci.rb +26 -4
  43. data/lib/mongo_mapper/plugins/scopes.rb +5 -4
  44. data/lib/mongo_mapper/plugins/timestamps.rb +11 -4
  45. data/lib/mongo_mapper/plugins/validations.rb +1 -1
  46. data/lib/mongo_mapper/utils.rb +12 -0
  47. data/lib/mongo_mapper/version.rb +1 -1
  48. data/lib/rails/generators/mongo_mapper/config/config_generator.rb +20 -7
  49. data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +6 -0
  50. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +18 -1
  51. data/lib/rails/generators/mongo_mapper/model/templates/model.rb +9 -5
  52. data/{test/functional/test_accessible.rb → spec/functional/accessible_spec.rb} +29 -29
  53. data/{test/functional/associations/test_belongs_to_polymorphic_proxy.rb → spec/functional/associations/belongs_to_polymorphic_proxy_spec.rb} +10 -10
  54. data/{test/functional/associations/test_belongs_to_proxy.rb → spec/functional/associations/belongs_to_proxy_spec.rb} +82 -64
  55. data/{test/functional/associations/test_in_array_proxy.rb → spec/functional/associations/in_array_proxy_spec.rb} +68 -68
  56. data/{test/functional/associations/test_many_documents_as_proxy.rb → spec/functional/associations/many_documents_as_proxy_spec.rb} +37 -38
  57. data/{test/functional/associations/test_many_documents_proxy.rb → spec/functional/associations/many_documents_proxy_spec.rb} +233 -146
  58. data/{test/functional/associations/test_many_embedded_polymorphic_proxy.rb → spec/functional/associations/many_embedded_polymorphic_proxy_spec.rb} +19 -20
  59. data/{test/functional/associations/test_many_embedded_proxy.rb → spec/functional/associations/many_embedded_proxy_spec.rb} +23 -24
  60. data/{test/functional/associations/test_many_polymorphic_proxy.rb → spec/functional/associations/many_polymorphic_proxy_spec.rb} +45 -46
  61. data/{test/functional/associations/test_one_as_proxy.rb → spec/functional/associations/one_as_proxy_spec.rb} +75 -77
  62. data/{test/functional/associations/test_one_embedded_polymorphic_proxy.rb → spec/functional/associations/one_embedded_polymorphic_proxy_spec.rb} +31 -32
  63. data/{test/functional/associations/test_one_embedded_proxy.rb → spec/functional/associations/one_embedded_proxy_spec.rb} +10 -10
  64. data/{test/functional/associations/test_one_proxy.rb → spec/functional/associations/one_proxy_spec.rb} +125 -102
  65. data/spec/functional/associations_spec.rb +48 -0
  66. data/{test/functional/test_binary.rb → spec/functional/binary_spec.rb} +6 -6
  67. data/spec/functional/caching_spec.rb +75 -0
  68. data/{test/functional/test_callbacks.rb → spec/functional/callbacks_spec.rb} +84 -26
  69. data/{test/functional/test_dirty.rb → spec/functional/dirty_spec.rb} +57 -42
  70. data/{test/functional/test_document.rb → spec/functional/document_spec.rb} +52 -52
  71. data/spec/functional/dumpable_spec.rb +24 -0
  72. data/{test/functional/test_dynamic_querying.rb → spec/functional/dynamic_querying_spec.rb} +14 -14
  73. data/{test/functional/test_embedded_document.rb → spec/functional/embedded_document_spec.rb} +51 -42
  74. data/{test/functional/test_equality.rb → spec/functional/equality_spec.rb} +4 -4
  75. data/spec/functional/extensions_spec.rb +16 -0
  76. data/{test/functional/test_identity_map.rb → spec/functional/identity_map_spec.rb} +73 -61
  77. data/spec/functional/indexes_spec.rb +48 -0
  78. data/spec/functional/keys_spec.rb +224 -0
  79. data/{test/functional/test_logger.rb → spec/functional/logger_spec.rb} +6 -6
  80. data/spec/functional/modifiers_spec.rb +550 -0
  81. data/spec/functional/pagination_spec.rb +89 -0
  82. data/spec/functional/protected_spec.rb +199 -0
  83. data/spec/functional/querying_spec.rb +1003 -0
  84. data/spec/functional/rails_spec.rb +55 -0
  85. data/spec/functional/safe_spec.rb +163 -0
  86. data/{test/functional/test_sci.rb → spec/functional/sci_spec.rb} +123 -34
  87. data/{test/functional/test_scopes.rb → spec/functional/scopes_spec.rb} +59 -26
  88. data/spec/functional/timestamps_spec.rb +97 -0
  89. data/{test/functional/test_touch.rb → spec/functional/touch_spec.rb} +13 -13
  90. data/spec/functional/userstamps_spec.rb +46 -0
  91. data/{test/functional/test_validations.rb → spec/functional/validations_spec.rb} +64 -64
  92. data/spec/spec_helper.rb +81 -0
  93. data/spec/support/matchers.rb +24 -0
  94. data/{test → spec/support}/models.rb +1 -6
  95. data/spec/unit/associations/base_spec.rb +146 -0
  96. data/spec/unit/associations/belongs_to_association_spec.rb +30 -0
  97. data/spec/unit/associations/many_association_spec.rb +64 -0
  98. data/spec/unit/associations/one_association_spec.rb +48 -0
  99. data/{test/unit/associations/test_proxy.rb → spec/unit/associations/proxy_spec.rb} +21 -21
  100. data/{test/unit/test_clone.rb → spec/unit/clone_spec.rb} +21 -11
  101. data/spec/unit/config_generator_spec.rb +24 -0
  102. data/{test/unit/test_document.rb → spec/unit/document_spec.rb} +42 -42
  103. data/{test/unit/test_dynamic_finder.rb → spec/unit/dynamic_finder_spec.rb} +28 -28
  104. data/{test/unit/test_embedded_document.rb → spec/unit/embedded_document_spec.rb} +102 -108
  105. data/{test/unit/test_equality.rb → spec/unit/equality_spec.rb} +7 -7
  106. data/{test/unit/test_exceptions.rb → spec/unit/exceptions_spec.rb} +3 -3
  107. data/{test/unit/test_extensions.rb → spec/unit/extensions_spec.rb} +85 -71
  108. data/spec/unit/identity_map_middleware_spec.rb +134 -0
  109. data/{test/unit/test_inspect.rb → spec/unit/inspect_spec.rb} +8 -8
  110. data/{test/unit/test_key.rb → spec/unit/key_spec.rb} +82 -52
  111. data/spec/unit/keys_spec.rb +155 -0
  112. data/spec/unit/model_generator_spec.rb +47 -0
  113. data/spec/unit/mongo_mapper_spec.rb +184 -0
  114. data/spec/unit/pagination_spec.rb +11 -0
  115. data/{test/unit/test_plugins.rb → spec/unit/plugins_spec.rb} +14 -14
  116. data/spec/unit/rails_compatibility_spec.rb +40 -0
  117. data/{test/unit/test_rails_reflect_on_association.rb → spec/unit/rails_reflect_on_association_spec.rb} +9 -9
  118. data/{test/unit/test_rails.rb → spec/unit/rails_spec.rb} +31 -31
  119. data/spec/unit/serialization_spec.rb +169 -0
  120. data/spec/unit/serializers/json_serializer_spec.rb +218 -0
  121. data/spec/unit/serializers/xml_serializer_spec.rb +198 -0
  122. data/{test/unit/test_time_zones.rb → spec/unit/time_zones_spec.rb} +8 -8
  123. data/{test/unit/test_translation.rb → spec/unit/translation_spec.rb} +6 -6
  124. data/{test/unit/test_validations.rb → spec/unit/validations_spec.rb} +72 -59
  125. metadata +199 -179
  126. data/test/_NOTE_ON_TESTING +0 -1
  127. data/test/functional/test_associations.rb +0 -46
  128. data/test/functional/test_caching.rb +0 -77
  129. data/test/functional/test_indexes.rb +0 -50
  130. data/test/functional/test_modifiers.rb +0 -537
  131. data/test/functional/test_pagination.rb +0 -91
  132. data/test/functional/test_protected.rb +0 -201
  133. data/test/functional/test_querying.rb +0 -935
  134. data/test/functional/test_safe.rb +0 -76
  135. data/test/functional/test_timestamps.rb +0 -62
  136. data/test/functional/test_userstamps.rb +0 -44
  137. data/test/support/railtie.rb +0 -4
  138. data/test/support/railtie/autoloaded.rb +0 -2
  139. data/test/support/railtie/not_autoloaded.rb +0 -3
  140. data/test/support/railtie/parent.rb +0 -3
  141. data/test/test_active_model_lint.rb +0 -18
  142. data/test/test_helper.rb +0 -93
  143. data/test/unit/associations/test_base.rb +0 -146
  144. data/test/unit/associations/test_belongs_to_association.rb +0 -29
  145. data/test/unit/associations/test_many_association.rb +0 -63
  146. data/test/unit/associations/test_one_association.rb +0 -47
  147. data/test/unit/serializers/test_json_serializer.rb +0 -216
  148. data/test/unit/serializers/test_xml_serializer.rb +0 -196
  149. data/test/unit/test_identity_map_middleware.rb +0 -132
  150. data/test/unit/test_keys.rb +0 -65
  151. data/test/unit/test_mongo_mapper.rb +0 -157
  152. data/test/unit/test_pagination.rb +0 -11
  153. data/test/unit/test_rails_compatibility.rb +0 -38
  154. data/test/unit/test_serialization.rb +0 -166
@@ -59,16 +59,18 @@ module MongoMapper
59
59
  @ivar ||= "@_#{name}"
60
60
  end
61
61
 
62
+ # :nocov:
62
63
  def proxy_class
63
64
  raise NotImplementedError
64
65
  end
65
66
 
66
- def setup(model)
67
- end
68
-
69
67
  def autosave?
70
68
  raise NotImplementedError
71
69
  end
70
+ # :nocov:
71
+
72
+ def setup(model)
73
+ end
72
74
 
73
75
  private
74
76
  def separate_options_and_conditions
@@ -18,16 +18,16 @@ module MongoMapper
18
18
  @target
19
19
  end
20
20
 
21
- def build(attrs={})
22
- instantiate_target(:new, attrs)
21
+ def build(attrs={}, &block)
22
+ instantiate_target(:new, attrs, &block)
23
23
  end
24
24
 
25
- def create(attrs={})
26
- instantiate_target(:create, attrs)
25
+ def create(attrs={}, &block)
26
+ instantiate_target(:create, attrs, &block)
27
27
  end
28
28
 
29
- def create!(attrs={})
30
- instantiate_target(:create!, attrs)
29
+ def create!(attrs={}, &block)
30
+ instantiate_target(:create!, attrs, &block)
31
31
  end
32
32
 
33
33
  def save_to_collection(options={})
@@ -40,8 +40,8 @@ module MongoMapper
40
40
  klass.find_by_id(proxy_owner[association.foreign_key])
41
41
  end
42
42
 
43
- def instantiate_target(instantiator, attrs={})
44
- @target = klass.send(instantiator, attrs)
43
+ def instantiate_target(instantiator, attrs={}, &block)
44
+ @target = klass.send(instantiator, attrs, &block)
45
45
  proxy_owner[association.foreign_key] = @target.id
46
46
  loaded
47
47
  @target
@@ -12,6 +12,8 @@ module MongoMapper
12
12
  end
13
13
  end
14
14
 
15
+ alias_method :to_a, :to_ary
16
+
15
17
  def include?(*args)
16
18
  load_target
17
19
  target.include?(*args)
@@ -5,11 +5,11 @@ module MongoMapper
5
5
  class ManyDocumentsProxy < Collection
6
6
  include DynamicQuerying::ClassMethods
7
7
 
8
- def_delegators :query, *(Querying::Methods - [:to_a, :size, :empty?])
8
+ def_delegators :query, *(Querying::Methods - [:each, :to_a, :size, :empty?])
9
9
 
10
10
  def replace(docs)
11
11
  load_target
12
-
12
+
13
13
  (target - docs).each do |t|
14
14
  case options[:dependent]
15
15
  when :destroy then t.destroy
@@ -17,7 +17,7 @@ module MongoMapper
17
17
  else t.update_attributes(self.foreign_key => nil)
18
18
  end
19
19
  end
20
-
20
+
21
21
  docs.each { |doc| prepare(doc).save }
22
22
  reset
23
23
  end
@@ -33,6 +33,7 @@ module MongoMapper
33
33
  def build(attrs={})
34
34
  doc = klass.new(attrs)
35
35
  apply_scope(doc)
36
+ yield doc if block_given?
36
37
  @target ||= [] unless loaded?
37
38
  @target << doc
38
39
  doc
@@ -40,14 +41,18 @@ module MongoMapper
40
41
 
41
42
  def create(attrs={})
42
43
  doc = klass.new(attrs)
43
- apply_scope(doc).save
44
+ apply_scope(doc)
45
+ yield doc if block_given?
46
+ doc.save
44
47
  reset
45
48
  doc
46
49
  end
47
50
 
48
51
  def create!(attrs={})
49
52
  doc = klass.new(attrs)
50
- apply_scope(doc).save!
53
+ apply_scope(doc)
54
+ yield doc if block_given?
55
+ doc.save!
51
56
  reset
52
57
  doc
53
58
  end
@@ -71,6 +76,10 @@ module MongoMapper
71
76
  @target.each { |doc| doc.save(options) } if @target
72
77
  end
73
78
 
79
+ def each(&block)
80
+ load_target.each(&block)
81
+ end
82
+
74
83
  protected
75
84
  def query(options={})
76
85
  klass.
@@ -81,8 +90,24 @@ module MongoMapper
81
90
  def method_missing(method, *args, &block)
82
91
  if klass.respond_to?(method)
83
92
  result = klass.send(method, *args, &block)
84
- result.is_a?(Plucky::Query) ?
85
- query.merge(result) : super
93
+ case result
94
+ when Plucky::Query
95
+ query.merge result
96
+
97
+ # If we got a single record of this classas a result, return it
98
+ when klass
99
+ result
100
+
101
+ # If we got an array of this class as a result, return it
102
+ when Array
103
+ if result[0].is_a? klass
104
+ result
105
+ else
106
+ super
107
+ end
108
+ else
109
+ super
110
+ end
86
111
  else
87
112
  super
88
113
  end
@@ -4,7 +4,7 @@ module MongoMapper
4
4
  module Associations
5
5
  class ManyEmbeddedProxy < EmbeddedCollection
6
6
  def replace(values)
7
- @_values = (values || []).map do |v|
7
+ @_values = (values || []).compact.map do |v|
8
8
  v.respond_to?(:attributes) ? v.attributes : v
9
9
  end
10
10
  reset
@@ -12,7 +12,7 @@ module MongoMapper
12
12
 
13
13
  private
14
14
  def find_target
15
- (@_values || []).map do |attrs|
15
+ (@_values ||= []).map do |attrs|
16
16
  klass.load(attrs).tap do |child|
17
17
  assign_references(child)
18
18
  end
@@ -3,16 +3,16 @@ module MongoMapper
3
3
  module Plugins
4
4
  module Associations
5
5
  class OneProxy < Proxy
6
- def build(attrs={})
7
- instantiate_target(:new, attrs)
6
+ def build(attrs={}, &block)
7
+ instantiate_target(:new, attrs, &block)
8
8
  end
9
9
 
10
- def create(attrs={})
11
- instantiate_target(:create, attrs)
10
+ def create(attrs={}, &block)
11
+ instantiate_target(:create, attrs, &block)
12
12
  end
13
13
 
14
- def create!(attrs={})
15
- instantiate_target(:create!, attrs)
14
+ def create!(attrs={}, &block)
15
+ instantiate_target(:create!, attrs, &block)
16
16
  end
17
17
 
18
18
  def replace(doc)
@@ -29,7 +29,7 @@ module MongoMapper
29
29
  end
30
30
  end
31
31
  end
32
-
32
+
33
33
  unless doc.nil?
34
34
  proxy_owner.save unless proxy_owner.persisted?
35
35
  doc = klass.new(doc) unless doc.is_a?(klass)
@@ -40,17 +40,17 @@ module MongoMapper
40
40
  loaded
41
41
  @target = doc
42
42
  end
43
-
43
+
44
44
  def destroy
45
45
  target.destroy
46
46
  reset
47
47
  end
48
-
48
+
49
49
  def delete
50
50
  target.delete
51
51
  reset
52
52
  end
53
-
53
+
54
54
  def nullify
55
55
  nullify_scope(target)
56
56
  target.save
@@ -62,8 +62,8 @@ module MongoMapper
62
62
  target_class.first(association.query_options.merge(criteria))
63
63
  end
64
64
 
65
- def instantiate_target(instantiator, attrs={})
66
- @target = target_class.send(instantiator, attrs.update(criteria))
65
+ def instantiate_target(instantiator, attrs={}, &block)
66
+ @target = target_class.send(instantiator, attrs.update(criteria), &block)
67
67
  loaded
68
68
  @target
69
69
  end
@@ -76,9 +76,11 @@ module MongoMapper
76
76
  self unless target.nil?
77
77
  end
78
78
 
79
+ # :nocov:
79
80
  def replace(v)
80
81
  raise NotImplementedError
81
82
  end
83
+ # :nocov:
82
84
 
83
85
  def reset
84
86
  @loaded = false
@@ -90,7 +92,7 @@ module MongoMapper
90
92
  end
91
93
 
92
94
  def send(method, *args)
93
- if proxy_respond_to?(method)
95
+ if proxy_respond_to?(method, true)
94
96
  super
95
97
  else
96
98
  load_target
@@ -119,9 +121,11 @@ module MongoMapper
119
121
  reset
120
122
  end
121
123
 
124
+ # :nocov:
122
125
  def find_target
123
126
  raise NotImplementedError
124
127
  end
128
+ # :nocov:
125
129
 
126
130
  def flatten_deeper(array)
127
131
  array.collect do |element|
@@ -27,16 +27,16 @@ module MongoMapper
27
27
  get_proxy(associations[#{name.inspect}]).present?
28
28
  end
29
29
 
30
- def build_#{name}(attrs={})
31
- get_proxy(associations[#{name.inspect}]).build(attrs)
30
+ def build_#{name}(attrs={}, &block)
31
+ get_proxy(associations[#{name.inspect}]).build(attrs, &block)
32
32
  end
33
33
 
34
- def create_#{name}(attrs={})
35
- get_proxy(associations[#{name.inspect}]).create(attrs)
34
+ def create_#{name}(attrs={}, &block)
35
+ get_proxy(associations[#{name.inspect}]).create(attrs, &block)
36
36
  end
37
37
 
38
- def create_#{name}!(attrs={})
39
- get_proxy(associations[#{name.inspect}]).create!(attrs)
38
+ def create_#{name}!(attrs={}, &block)
39
+ get_proxy(associations[#{name.inspect}]).create!(attrs, &block)
40
40
  end
41
41
  end_eval
42
42
  end
@@ -7,7 +7,9 @@ module MongoMapper
7
7
  def initialize_copy(other)
8
8
  @_new = true
9
9
  @_destroyed = false
10
- @_id = nil
10
+ remove_instance_variable :@_id if instance_variable_defined?(:@_id)
11
+ init_ivars
12
+
11
13
  associations.each do |name, association|
12
14
  instance_variable_set(association.ivar, nil)
13
15
  end
@@ -19,4 +21,4 @@ module MongoMapper
19
21
  end
20
22
  end
21
23
  end
22
- end
24
+ end
@@ -8,11 +8,9 @@ module MongoMapper
8
8
 
9
9
  def initialize(*)
10
10
  # never register initial id assignment as a change
11
- super.tap { changed_attributes.delete('_id') }
12
- end
13
-
14
- def initialize_from_database(*)
15
- super.tap { changed_attributes.clear }
11
+ # Chaining super into tap breaks implicit block passing in Ruby 1.8
12
+ doc = super
13
+ doc.tap { changed_attributes.delete('_id') }
16
14
  end
17
15
 
18
16
  def save(*)
@@ -20,16 +18,8 @@ module MongoMapper
20
18
  end
21
19
 
22
20
  def reload(*)
23
- super.tap { clear_changes }
24
- end
25
-
26
- protected
27
-
28
- def attribute_method?(attr)
29
- # This overrides ::ActiveSupport::Dirty#attribute_method? to allow attributes to be any key
30
- # in the attributes hash ( default ) or any key defined on the model that may not yet have
31
- # had a value stored in the attributes collection.
32
- super || key_names.include?(attr)
21
+ doc = super
22
+ doc.tap { clear_changes }
33
23
  end
34
24
 
35
25
  def clear_changes
@@ -42,19 +32,30 @@ module MongoMapper
42
32
  end
43
33
  end
44
34
 
35
+ protected
36
+
37
+ # We don't call super here to avoid invoking #attributes, which builds a whole new hash per call.
38
+ def attribute_method?(attr_name)
39
+ keys.key?(attr_name) || !embedded_associations.detect {|a| a.name == attr_name }.nil?
40
+ end
41
+
45
42
  private
46
43
 
47
44
  def write_key(key, value)
48
- key = key.to_s
49
- attribute_will_change!(key) unless attribute_changed?(key)
50
- super(key, value).tap do
51
- changed_attributes.delete(key) unless attribute_value_changed?(key)
45
+ key = unalias_key(key)
46
+ if !keys.key?(key)
47
+ super
48
+ else
49
+ attribute_will_change!(key) unless attribute_changed?(key)
50
+ super.tap do
51
+ changed_attributes.delete(key) unless attribute_value_changed?(key)
52
+ end
52
53
  end
53
54
  end
54
55
 
55
56
  def attribute_value_changed?(key_name)
56
- attribute_was(key_name) != read_key(key_name)
57
+ changed_attributes[key_name] != read_key(key_name)
57
58
  end
58
59
  end
59
60
  end
60
- end
61
+ end
@@ -11,11 +11,11 @@ module MongoMapper
11
11
  end
12
12
 
13
13
  def new?
14
- @_new
14
+ !!(@_new ||= false)
15
15
  end
16
16
 
17
17
  def destroyed?
18
- @_destroyed == true
18
+ !!(@_destroyed ||= false)
19
19
  end
20
20
 
21
21
  def reload
@@ -23,8 +23,8 @@ module MongoMapper
23
23
  self.class.associations.each_value do |association|
24
24
  get_proxy(association).reset
25
25
  end
26
- instance_variables.each { |ivar| instance_variable_set(ivar, nil) }
27
- load_from_database(doc)
26
+ instance_variables.each { |ivar| remove_instance_variable(ivar) }
27
+ initialize_from_database(doc)
28
28
  self
29
29
  else
30
30
  raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
@@ -0,0 +1,22 @@
1
+ require 'set'
2
+
3
+ module MongoMapper
4
+ module Plugins
5
+ module Dumpable
6
+ DUMP_BLACKLIST = Set.new([:@errors])
7
+
8
+ def marshal_dump
9
+ instance_variables.map(&:to_sym).inject({}) do |h, var|
10
+ h[var] = instance_variable_get(var) unless DUMP_BLACKLIST.include?(var) or var.to_s.start_with?("@__")
11
+ h
12
+ end
13
+ end
14
+
15
+ def marshal_load(data)
16
+ data.each do |k, v|
17
+ instance_variable_set(k, v)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -9,22 +9,71 @@ module MongoMapper
9
9
 
10
10
  define_model_callbacks :save, :create, :update, :destroy, :only => [:before, :after]
11
11
  define_model_callbacks :touch, :only => [:after]
12
+
13
+ proxy_callbacks(
14
+ :before => [:save, :create, :update, :destroy],
15
+ :after => [:save, :create, :update, :destroy, :touch]
16
+ )
17
+
18
+ @embedded_callbacks_status = nil
12
19
  end
13
20
 
14
- def run_callbacks(callback, *args, &block)
15
- embedded_docs = []
21
+ module ClassMethods
22
+ def define_callbacks(*args)
23
+ embedded_callbacks_on if @embedded_callbacks_status.nil?
24
+ super
25
+ end
26
+
27
+ def embedded_callbacks_on
28
+ @embedded_callbacks_status = true
29
+ end
30
+
31
+ def embedded_callbacks_off
32
+ @embedded_callbacks_status = false
33
+ end
34
+
35
+ def embedded_callbacks_on?
36
+ !!@embedded_callbacks_status
37
+ end
16
38
 
17
- embedded_associations.each do |association|
18
- embedded_docs += Array(get_proxy(association).send(:load_target))
39
+ def embedded_callbacks_off?
40
+ !@embedded_callbacks_status
19
41
  end
20
42
 
21
- block = embedded_docs.inject(block) do |chain, doc|
22
- if doc.class.respond_to?("_#{callback}_callbacks")
23
- lambda { doc.run_callbacks(callback, *args, &chain) }
24
- else
25
- chain
43
+ def proxy_callbacks(definition)
44
+ definition.each do |prefix, suffixes|
45
+ suffixes.each do |suffix|
46
+ callback = "%s_%s" % [prefix, suffix]
47
+ class_eval <<-CALLBACK, __FILE__, __LINE__ + 1
48
+ class << self
49
+ alias_method :__original_#{callback}, :#{callback}
50
+
51
+ def #{callback}(*args, &block)
52
+ embedded_callbacks_on if @embedded_callbacks_status.nil?
53
+ __original_#{callback}(*args, &block)
54
+ end
55
+ end
56
+ CALLBACK
57
+ end
26
58
  end
27
59
  end
60
+ end
61
+
62
+ def run_callbacks(callback, *args, &block)
63
+ if self.class.embedded_callbacks_on? and embedded_associations.length > 0
64
+ embedded_docs = embedded_associations.map do |association|
65
+ Array(get_proxy(association).send(:load_target))
66
+ end.flatten(1)
67
+
68
+ block = embedded_docs.inject(block) do |chain, doc|
69
+ if doc.class.respond_to?("_#{callback}_callbacks")
70
+ lambda { doc.run_callbacks(callback, *args, &chain) }
71
+ else
72
+ chain
73
+ end
74
+ end
75
+ end
76
+
28
77
  super callback, *args, &block
29
78
  end
30
79
  end