ign-mongo_mapper 0.8.6.1

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 (147) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +33 -0
  3. data/UPGRADES +7 -0
  4. data/bin/mmconsole +60 -0
  5. data/examples/attr_accessible.rb +22 -0
  6. data/examples/attr_protected.rb +22 -0
  7. data/examples/cache_key.rb +24 -0
  8. data/examples/custom_types.rb +24 -0
  9. data/examples/identity_map.rb +33 -0
  10. data/examples/identity_map/automatic.rb +8 -0
  11. data/examples/keys.rb +40 -0
  12. data/examples/modifiers/set.rb +25 -0
  13. data/examples/plugins.rb +41 -0
  14. data/examples/querying.rb +35 -0
  15. data/examples/safe.rb +43 -0
  16. data/examples/scopes.rb +52 -0
  17. data/examples/validating/embedded_docs.rb +29 -0
  18. data/lib/mongo_mapper.rb +83 -0
  19. data/lib/mongo_mapper/connection.rb +83 -0
  20. data/lib/mongo_mapper/document.rb +41 -0
  21. data/lib/mongo_mapper/embedded_document.rb +31 -0
  22. data/lib/mongo_mapper/exceptions.rb +27 -0
  23. data/lib/mongo_mapper/extensions/array.rb +19 -0
  24. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  25. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  26. data/lib/mongo_mapper/extensions/date.rb +25 -0
  27. data/lib/mongo_mapper/extensions/float.rb +14 -0
  28. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  29. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  30. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  31. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  32. data/lib/mongo_mapper/extensions/object.rb +27 -0
  33. data/lib/mongo_mapper/extensions/object_id.rb +30 -0
  34. data/lib/mongo_mapper/extensions/set.rb +20 -0
  35. data/lib/mongo_mapper/extensions/string.rb +18 -0
  36. data/lib/mongo_mapper/extensions/time.rb +29 -0
  37. data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
  38. data/lib/mongo_mapper/plugins.rb +15 -0
  39. data/lib/mongo_mapper/plugins/accessible.rb +44 -0
  40. data/lib/mongo_mapper/plugins/associations.rb +134 -0
  41. data/lib/mongo_mapper/plugins/associations/base.rb +124 -0
  42. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +29 -0
  43. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +24 -0
  44. data/lib/mongo_mapper/plugins/associations/collection.rb +27 -0
  45. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +40 -0
  46. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +151 -0
  47. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  48. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +109 -0
  49. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  50. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  51. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  52. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +41 -0
  53. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  54. data/lib/mongo_mapper/plugins/associations/proxy.rb +139 -0
  55. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  56. data/lib/mongo_mapper/plugins/callbacks.rb +243 -0
  57. data/lib/mongo_mapper/plugins/clone.rb +22 -0
  58. data/lib/mongo_mapper/plugins/descendants.rb +17 -0
  59. data/lib/mongo_mapper/plugins/dirty.rb +124 -0
  60. data/lib/mongo_mapper/plugins/document.rb +41 -0
  61. data/lib/mongo_mapper/plugins/dynamic_querying.rb +43 -0
  62. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  63. data/lib/mongo_mapper/plugins/embedded_document.rb +48 -0
  64. data/lib/mongo_mapper/plugins/equality.rb +17 -0
  65. data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
  66. data/lib/mongo_mapper/plugins/indexes.rb +12 -0
  67. data/lib/mongo_mapper/plugins/inspect.rb +15 -0
  68. data/lib/mongo_mapper/plugins/keys.rb +311 -0
  69. data/lib/mongo_mapper/plugins/keys/key.rb +65 -0
  70. data/lib/mongo_mapper/plugins/logger.rb +18 -0
  71. data/lib/mongo_mapper/plugins/modifiers.rb +112 -0
  72. data/lib/mongo_mapper/plugins/pagination.rb +14 -0
  73. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  74. data/lib/mongo_mapper/plugins/protected.rb +53 -0
  75. data/lib/mongo_mapper/plugins/querying.rb +176 -0
  76. data/lib/mongo_mapper/plugins/querying/decorator.rb +46 -0
  77. data/lib/mongo_mapper/plugins/querying/plucky_methods.rb +15 -0
  78. data/lib/mongo_mapper/plugins/rails.rb +58 -0
  79. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  80. data/lib/mongo_mapper/plugins/sci.rb +32 -0
  81. data/lib/mongo_mapper/plugins/scopes.rb +21 -0
  82. data/lib/mongo_mapper/plugins/serialization.rb +76 -0
  83. data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
  84. data/lib/mongo_mapper/plugins/userstamps.rb +15 -0
  85. data/lib/mongo_mapper/plugins/validations.rb +50 -0
  86. data/lib/mongo_mapper/support/descendant_appends.rb +45 -0
  87. data/lib/mongo_mapper/version.rb +4 -0
  88. data/rails/init.rb +15 -0
  89. data/test/_NOTE_ON_TESTING +1 -0
  90. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +64 -0
  91. data/test/functional/associations/test_belongs_to_proxy.rb +117 -0
  92. data/test/functional/associations/test_in_array_proxy.rb +349 -0
  93. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  94. data/test/functional/associations/test_many_documents_proxy.rb +615 -0
  95. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  96. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  97. data/test/functional/associations/test_many_polymorphic_proxy.rb +303 -0
  98. data/test/functional/associations/test_one_embedded_proxy.rb +100 -0
  99. data/test/functional/associations/test_one_proxy.rb +206 -0
  100. data/test/functional/test_accessible.rb +168 -0
  101. data/test/functional/test_associations.rb +46 -0
  102. data/test/functional/test_binary.rb +27 -0
  103. data/test/functional/test_caching.rb +76 -0
  104. data/test/functional/test_callbacks.rb +151 -0
  105. data/test/functional/test_dirty.rb +163 -0
  106. data/test/functional/test_document.rb +272 -0
  107. data/test/functional/test_dynamic_querying.rb +75 -0
  108. data/test/functional/test_embedded_document.rb +210 -0
  109. data/test/functional/test_identity_map.rb +513 -0
  110. data/test/functional/test_indexes.rb +42 -0
  111. data/test/functional/test_logger.rb +20 -0
  112. data/test/functional/test_modifiers.rb +416 -0
  113. data/test/functional/test_pagination.rb +91 -0
  114. data/test/functional/test_protected.rb +175 -0
  115. data/test/functional/test_querying.rb +873 -0
  116. data/test/functional/test_safe.rb +76 -0
  117. data/test/functional/test_sci.rb +230 -0
  118. data/test/functional/test_scopes.rb +171 -0
  119. data/test/functional/test_string_id_compatibility.rb +67 -0
  120. data/test/functional/test_timestamps.rb +62 -0
  121. data/test/functional/test_userstamps.rb +27 -0
  122. data/test/functional/test_validations.rb +342 -0
  123. data/test/models.rb +233 -0
  124. data/test/test_active_model_lint.rb +13 -0
  125. data/test/test_helper.rb +102 -0
  126. data/test/unit/associations/test_base.rb +212 -0
  127. data/test/unit/associations/test_proxy.rb +105 -0
  128. data/test/unit/serializers/test_json_serializer.rb +217 -0
  129. data/test/unit/test_clone.rb +69 -0
  130. data/test/unit/test_descendant_appends.rb +71 -0
  131. data/test/unit/test_document.rb +208 -0
  132. data/test/unit/test_dynamic_finder.rb +125 -0
  133. data/test/unit/test_embedded_document.rb +639 -0
  134. data/test/unit/test_extensions.rb +376 -0
  135. data/test/unit/test_identity_map_middleware.rb +34 -0
  136. data/test/unit/test_inspect.rb +22 -0
  137. data/test/unit/test_key.rb +205 -0
  138. data/test/unit/test_keys.rb +89 -0
  139. data/test/unit/test_mongo_mapper.rb +110 -0
  140. data/test/unit/test_pagination.rb +11 -0
  141. data/test/unit/test_plugins.rb +50 -0
  142. data/test/unit/test_rails.rb +181 -0
  143. data/test/unit/test_rails_compatibility.rb +52 -0
  144. data/test/unit/test_serialization.rb +51 -0
  145. data/test/unit/test_time_zones.rb +39 -0
  146. data/test/unit/test_validations.rb +564 -0
  147. metadata +385 -0
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Clone
5
+ module InstanceMethods
6
+ def initialize_copy(other)
7
+ @_new = true
8
+ @_destroyed = false
9
+ default_id_value
10
+ associations.each do |name, association|
11
+ instance_variable_set(association.ivar, nil)
12
+ end
13
+ self.attributes = other.attributes.clone.except(:_id).inject({}) do |hash, entry|
14
+ key, value = entry
15
+ hash[key] = value.duplicable? ? value.clone : value
16
+ hash
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Descendants
5
+ module ClassMethods
6
+ def inherited(descendant)
7
+ descendants << descendant
8
+ super
9
+ end
10
+
11
+ def descendants
12
+ @descendants ||= []
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,124 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Dirty
5
+ module InstanceMethods
6
+ def method_missing(method, *args, &block)
7
+ if method.to_s =~ /(_changed\?|_change|_will_change!|_was)$/
8
+ method_suffix = $1
9
+ key = method.to_s.gsub(method_suffix, '')
10
+
11
+ if key_names.include?(key)
12
+ case method_suffix
13
+ when '_changed?'
14
+ key_changed?(key)
15
+ when '_change'
16
+ key_change(key)
17
+ when '_will_change!'
18
+ key_will_change!(key)
19
+ when '_was'
20
+ key_was(key)
21
+ end
22
+ else
23
+ super
24
+ end
25
+ else
26
+ super
27
+ end
28
+ end
29
+
30
+ def changed?
31
+ !changed_keys.empty?
32
+ end
33
+
34
+ def changed
35
+ changed_keys.keys
36
+ end
37
+
38
+ def changes
39
+ changed.inject({}) { |h, key| h[key] = key_change(key); h }
40
+ end
41
+
42
+ def initialize(*)
43
+ # never register initial id assignment as a change
44
+ super.tap { changed_keys.delete('_id') }
45
+ end
46
+
47
+ def initialize_from_database(*)
48
+ super.tap { changed_keys.clear }
49
+ end
50
+
51
+ def save(*)
52
+ if status = super
53
+ changed_keys.clear
54
+ end
55
+ status
56
+ end
57
+
58
+ def save!(*)
59
+ status = super
60
+ changed_keys.clear
61
+ status
62
+ end
63
+
64
+ def reload(*)
65
+ document = super
66
+ changed_keys.clear
67
+ document
68
+ end
69
+
70
+ private
71
+ def clone_key_value(key)
72
+ value = read_key(key)
73
+ value.duplicable? ? value.clone : value
74
+ rescue TypeError, NoMethodError
75
+ value
76
+ end
77
+
78
+ def changed_keys
79
+ @changed_keys ||= {}
80
+ end
81
+
82
+ def key_changed?(key)
83
+ changed_keys.include?(key)
84
+ end
85
+
86
+ def key_change(key)
87
+ [changed_keys[key], __send__(key)] if key_changed?(key)
88
+ end
89
+
90
+ def key_was(key)
91
+ key_changed?(key) ? changed_keys[key] : __send__(key)
92
+ end
93
+
94
+ def key_will_change!(key)
95
+ changed_keys[key] = clone_key_value(key)
96
+ end
97
+
98
+ def write_key(key, value)
99
+ key = key.to_s
100
+
101
+ if changed_keys.include?(key)
102
+ old = changed_keys[key]
103
+ changed_keys.delete(key) unless value_changed?(key, old, value)
104
+ else
105
+ old = clone_key_value(key)
106
+ changed_keys[key] = old if value_changed?(key, old, value)
107
+ end
108
+
109
+ super(key, value)
110
+ end
111
+
112
+ def value_changed?(key_name, old, value)
113
+ key = keys[key_name]
114
+
115
+ if key.number? && value.blank?
116
+ value = nil
117
+ end
118
+
119
+ old != value
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Document
5
+ module ClassMethods
6
+ def embeddable?
7
+ false
8
+ end
9
+ end
10
+
11
+ module InstanceMethods
12
+ def new?
13
+ @_new
14
+ end
15
+
16
+ def destroyed?
17
+ @_destroyed == true
18
+ end
19
+
20
+ def reload
21
+ if doc = collection.find_one(:_id => id)
22
+ tap do |instance|
23
+ instance.class.associations.each_value do |association|
24
+ get_proxy(association).reset
25
+ end
26
+ instance.attributes = doc
27
+ end
28
+ else
29
+ raise DocumentNotFound, "Document match #{_id.inspect} does not exist in #{collection.name} collection"
30
+ end
31
+ end
32
+
33
+ # Used by embedded docs to find root easily without if/respond_to? stuff.
34
+ # Documents are always root documents.
35
+ def _root_document
36
+ self
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: UTF-8
2
+ require 'mongo_mapper/plugins/dynamic_querying/dynamic_finder'
3
+
4
+ module MongoMapper
5
+ module Plugins
6
+ module DynamicQuerying
7
+ module ClassMethods
8
+ def dynamic_find(finder, args)
9
+ attributes = {}
10
+
11
+ finder.attributes.each_with_index do |attr, index|
12
+ attributes[attr] = args[index]
13
+ end
14
+
15
+ options = args.extract_options!.merge(attributes)
16
+
17
+ if result = send(finder.finder, options)
18
+ result
19
+ else
20
+ if finder.raise?
21
+ raise DocumentNotFound, "Couldn't find Document with #{attributes.inspect} in collection named #{collection.name}"
22
+ end
23
+
24
+ if finder.instantiator
25
+ self.send(finder.instantiator, attributes)
26
+ end
27
+ end
28
+ end
29
+
30
+ protected
31
+ def method_missing(method, *args, &block)
32
+ finder = DynamicFinder.new(method)
33
+
34
+ if finder.found?
35
+ dynamic_find(finder, args)
36
+ else
37
+ super
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module DynamicQuerying
5
+ class DynamicFinder
6
+ attr_reader :method, :attributes, :finder, :bang, :instantiator
7
+
8
+ def initialize(method)
9
+ @method = method
10
+ @finder = :first
11
+ @bang = false
12
+ match
13
+ end
14
+
15
+ def found?
16
+ @finder.present?
17
+ end
18
+
19
+ def raise?
20
+ bang == true
21
+ end
22
+
23
+ protected
24
+ def match
25
+ case method.to_s
26
+ when /^find_(all_by|by)_([_a-zA-Z]\w*)$/
27
+ @finder = :all if $1 == 'all_by'
28
+ names = $2
29
+ when /^find_by_([_a-zA-Z]\w*)\!$/
30
+ @bang = true
31
+ names = $1
32
+ when /^find_or_(initialize|create)_by_([_a-zA-Z]\w*)$/
33
+ @instantiator = $1 == 'initialize' ? :new : :create
34
+ names = $2
35
+ else
36
+ @finder = nil
37
+ end
38
+
39
+ @attributes = names && names.split('_and_')
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,48 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module EmbeddedDocument
5
+ def self.configure(model)
6
+ model.class_eval do
7
+ attr_accessor :_parent_document
8
+ end
9
+ end
10
+
11
+ module ClassMethods
12
+ def embeddable?
13
+ true
14
+ end
15
+
16
+ def embedded_in(owner_name)
17
+ define_method(owner_name) { _parent_document }
18
+ end
19
+ end
20
+
21
+ module InstanceMethods
22
+ def new?
23
+ _root_document.try(:new?) || @_new
24
+ end
25
+
26
+ def destroyed?
27
+ !!_root_document.try(:destroyed?)
28
+ end
29
+
30
+ def save(options={})
31
+ _root_document.try(:save, options).tap do |result|
32
+ @_new = false if result
33
+ end
34
+ end
35
+
36
+ def save!(options={})
37
+ _root_document.try(:save, options).tap do |result|
38
+ @_new = false if result
39
+ end
40
+ end
41
+
42
+ def _root_document
43
+ @_root_document ||= _parent_document.try(:_root_document)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,17 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Equality
5
+ module InstanceMethods
6
+ def eql?(other)
7
+ other.is_a?(self.class) && _id == other._id
8
+ end
9
+ alias :== :eql?
10
+
11
+ def hash
12
+ _id.hash
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,128 @@
1
+ # encoding: UTF-8
2
+ require 'set'
3
+
4
+ module MongoMapper
5
+ module Plugins
6
+ module IdentityMap
7
+ def self.models
8
+ @models ||= Set.new
9
+ end
10
+
11
+ def self.clear
12
+ models.each { |m| m.identity_map.clear }
13
+ end
14
+
15
+ def self.configure(model)
16
+ IdentityMap.models << model
17
+ end
18
+
19
+ module ClassMethods
20
+ def inherited(descendant)
21
+ descendant.identity_map = identity_map
22
+ super
23
+ end
24
+
25
+ def identity_map
26
+ @identity_map ||= {}
27
+ end
28
+
29
+ def identity_map=(v)
30
+ @identity_map = v
31
+ end
32
+
33
+ module IdentityMapQueryMethods
34
+ def all(opts={})
35
+ query = clone.update(opts)
36
+ super.tap do |docs|
37
+ model.remove_documents_from_map(docs) if query.fields?
38
+ end
39
+ end
40
+
41
+ def find_one(opts={})
42
+ query = clone.update(opts)
43
+
44
+ if model.identity_map_on? && query.simple? && model.identity_map[query[:_id]]
45
+ model.identity_map[query[:_id]]
46
+ else
47
+ super.tap do |doc|
48
+ model.remove_documents_from_map(doc) if query.fields?
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def query(opts={})
55
+ super.extend(IdentityMapQueryMethods)
56
+ end
57
+
58
+ def remove_documents_from_map(*documents)
59
+ documents.flatten.compact.each do |document|
60
+ identity_map.delete(document['_id'])
61
+ end
62
+ end
63
+
64
+ def load(attrs)
65
+ return nil if attrs.nil?
66
+ document = identity_map[attrs['_id']]
67
+
68
+ if document.nil? || identity_map_off?
69
+ document = super
70
+ identity_map[document._id] = document if identity_map_on?
71
+ end
72
+
73
+ document
74
+ end
75
+
76
+ def identity_map_status
77
+ defined?(@identity_map_status) ? @identity_map_status : true
78
+ end
79
+
80
+ def identity_map_on
81
+ @identity_map_status = true
82
+ end
83
+
84
+ def identity_map_off
85
+ @identity_map_status = false
86
+ end
87
+
88
+ def identity_map_on?
89
+ identity_map_status
90
+ end
91
+
92
+ def identity_map_off?
93
+ !identity_map_on?
94
+ end
95
+
96
+ def without_identity_map(&block)
97
+ identity_map_off
98
+ yield
99
+ ensure
100
+ identity_map_on
101
+ end
102
+
103
+ private
104
+ def selecting_fields?(options)
105
+ !options[:fields].nil?
106
+ end
107
+ end
108
+
109
+ module InstanceMethods
110
+ def identity_map
111
+ self.class.identity_map
112
+ end
113
+
114
+ def save(*args)
115
+ if result = super
116
+ identity_map[_id] = self if self.class.identity_map_on?
117
+ end
118
+ result
119
+ end
120
+
121
+ def delete
122
+ identity_map.delete(_id) if self.class.identity_map_on?
123
+ super
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end