mongo_mapper 0.12.0 → 0.13.0.beta1

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