numon 0.0.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 (99) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +31 -0
  4. data/Rakefile +52 -0
  5. data/bin/mmconsole +60 -0
  6. data/lib/mongo_mapper.rb +138 -0
  7. data/lib/mongo_mapper/document.rb +359 -0
  8. data/lib/mongo_mapper/embedded_document.rb +61 -0
  9. data/lib/mongo_mapper/plugins.rb +34 -0
  10. data/lib/mongo_mapper/plugins/associations.rb +105 -0
  11. data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
  12. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  13. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  14. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  15. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +39 -0
  16. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +144 -0
  17. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  18. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +120 -0
  19. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  20. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  21. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  22. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  23. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  24. data/lib/mongo_mapper/plugins/callbacks.rb +234 -0
  25. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  26. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  27. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  28. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  29. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  30. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  31. data/lib/mongo_mapper/plugins/keys.rb +336 -0
  32. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  33. data/lib/mongo_mapper/plugins/modifiers.rb +87 -0
  34. data/lib/mongo_mapper/plugins/pagination.rb +24 -0
  35. data/lib/mongo_mapper/plugins/pagination/proxy.rb +72 -0
  36. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  37. data/lib/mongo_mapper/plugins/rails.rb +53 -0
  38. data/lib/mongo_mapper/plugins/serialization.rb +75 -0
  39. data/lib/mongo_mapper/plugins/timestamps.rb +21 -0
  40. data/lib/mongo_mapper/plugins/userstamps.rb +14 -0
  41. data/lib/mongo_mapper/plugins/validations.rb +46 -0
  42. data/lib/mongo_mapper/query.rb +130 -0
  43. data/lib/mongo_mapper/support.rb +216 -0
  44. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  45. data/lib/mongo_mapper/support/find.rb +77 -0
  46. data/lib/mongo_mapper/version.rb +3 -0
  47. data/numon.gemspec +207 -0
  48. data/performance/read_write.rb +52 -0
  49. data/specs.watchr +51 -0
  50. data/test/NOTE_ON_TESTING +1 -0
  51. data/test/active_model_lint_test.rb +11 -0
  52. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  53. data/test/functional/associations/test_belongs_to_proxy.rb +101 -0
  54. data/test/functional/associations/test_in_array_proxy.rb +325 -0
  55. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  56. data/test/functional/associations/test_many_documents_proxy.rb +453 -0
  57. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  58. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  59. data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
  60. data/test/functional/associations/test_one_proxy.rb +161 -0
  61. data/test/functional/test_associations.rb +44 -0
  62. data/test/functional/test_binary.rb +27 -0
  63. data/test/functional/test_callbacks.rb +151 -0
  64. data/test/functional/test_dirty.rb +163 -0
  65. data/test/functional/test_document.rb +1165 -0
  66. data/test/functional/test_embedded_document.rb +130 -0
  67. data/test/functional/test_identity_map.rb +508 -0
  68. data/test/functional/test_indexing.rb +44 -0
  69. data/test/functional/test_logger.rb +20 -0
  70. data/test/functional/test_modifiers.rb +322 -0
  71. data/test/functional/test_pagination.rb +93 -0
  72. data/test/functional/test_protected.rb +161 -0
  73. data/test/functional/test_string_id_compatibility.rb +67 -0
  74. data/test/functional/test_timestamps.rb +64 -0
  75. data/test/functional/test_userstamps.rb +28 -0
  76. data/test/functional/test_validations.rb +329 -0
  77. data/test/models.rb +232 -0
  78. data/test/support/custom_matchers.rb +55 -0
  79. data/test/support/timing.rb +16 -0
  80. data/test/test_helper.rb +61 -0
  81. data/test/unit/associations/test_base.rb +207 -0
  82. data/test/unit/associations/test_proxy.rb +105 -0
  83. data/test/unit/serializers/test_json_serializer.rb +202 -0
  84. data/test/unit/test_descendant_appends.rb +71 -0
  85. data/test/unit/test_document.rb +231 -0
  86. data/test/unit/test_dynamic_finder.rb +123 -0
  87. data/test/unit/test_embedded_document.rb +663 -0
  88. data/test/unit/test_keys.rb +173 -0
  89. data/test/unit/test_mongo_mapper.rb +155 -0
  90. data/test/unit/test_pagination.rb +160 -0
  91. data/test/unit/test_plugins.rb +50 -0
  92. data/test/unit/test_query.rb +340 -0
  93. data/test/unit/test_rails.rb +123 -0
  94. data/test/unit/test_rails_compatibility.rb +52 -0
  95. data/test/unit/test_serialization.rb +51 -0
  96. data/test/unit/test_support.rb +366 -0
  97. data/test/unit/test_time_zones.rb +39 -0
  98. data/test/unit/test_validations.rb +544 -0
  99. metadata +305 -0
@@ -0,0 +1,14 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Inspect
4
+ module InstanceMethods
5
+ def inspect
6
+ attributes_as_nice_string = key_names.collect do |name|
7
+ "#{name}: #{self[name].inspect}"
8
+ end.join(", ")
9
+ "#<#{self.class} #{attributes_as_nice_string}>"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,336 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Keys
4
+ def self.configure(model)
5
+ model.key :_id, ObjectId
6
+ end
7
+
8
+ module ClassMethods
9
+ def inherited(descendant)
10
+ descendant.instance_variable_set(:@keys, keys.dup)
11
+ super
12
+ end
13
+
14
+ def keys
15
+ @keys ||= HashWithIndifferentAccess.new
16
+ end
17
+
18
+ def key(*args)
19
+ key = Key.new(*args)
20
+ keys[key.name] = key
21
+
22
+ create_accessors_for(key)
23
+ create_key_in_descendants(*args)
24
+ create_indexes_for(key)
25
+ create_validations_for(key)
26
+
27
+ key
28
+ end
29
+
30
+ def using_object_id?
31
+ object_id_key?(:_id)
32
+ end
33
+
34
+ def object_id_key?(name)
35
+ key = keys[name.to_s]
36
+ key && key.type == ObjectId
37
+ end
38
+
39
+ def to_mongo(instance)
40
+ return nil if instance.nil?
41
+ instance.to_mongo
42
+ end
43
+
44
+ def from_mongo(value)
45
+ return nil if value.nil?
46
+ value.is_a?(self) ? value : load(value)
47
+ end
48
+
49
+ # load is overridden in identity map to ensure same objects are loaded
50
+ def load(attrs)
51
+ begin
52
+ klass = attrs['_type'].present? ? attrs['_type'].constantize : self
53
+ klass.new(attrs, true)
54
+ rescue NameError
55
+ new(attrs, true)
56
+ end
57
+ end
58
+
59
+ private
60
+ def accessors_module
61
+ module_defined = if method(:const_defined?).arity == 1 # Ruby 1.9 compat check
62
+ const_defined?('MongoMapperKeys')
63
+ else
64
+ const_defined?('MongoMapperKeys', false)
65
+ end
66
+
67
+ if module_defined
68
+ const_get 'MongoMapperKeys'
69
+ else
70
+ const_set 'MongoMapperKeys', Module.new
71
+ end
72
+ end
73
+
74
+ def create_accessors_for(key)
75
+ accessors_module.module_eval <<-end_eval
76
+ def #{key.name}
77
+ read_key(:#{key.name})
78
+ end
79
+
80
+ def #{key.name}_before_typecast
81
+ read_key_before_typecast(:#{key.name})
82
+ end
83
+
84
+ def #{key.name}=(value)
85
+ write_key(:#{key.name}, value)
86
+ end
87
+
88
+ def #{key.name}?
89
+ read_key(:#{key.name}).present?
90
+ end
91
+ end_eval
92
+
93
+ include accessors_module
94
+ end
95
+
96
+ def create_key_in_descendants(*args)
97
+ return if descendants.blank?
98
+ descendants.each { |descendant| descendant.key(*args) }
99
+ end
100
+
101
+ def create_indexes_for(key)
102
+ ensure_index key.name if key.options[:index] && !key.embeddable?
103
+ end
104
+
105
+ def create_validations_for(key)
106
+ attribute = key.name.to_sym
107
+
108
+ if key.options[:required]
109
+ validates_presence_of(attribute)
110
+ end
111
+
112
+ if key.options[:unique]
113
+ validates_uniqueness_of(attribute)
114
+ end
115
+
116
+ if key.options[:numeric]
117
+ number_options = key.type == Integer ? {:only_integer => true} : {}
118
+ validates_numericality_of(attribute, number_options)
119
+ end
120
+
121
+ if key.options[:format]
122
+ validates_format_of(attribute, :with => key.options[:format])
123
+ end
124
+
125
+ if key.options[:in]
126
+ validates_inclusion_of(attribute, :within => key.options[:in])
127
+ end
128
+
129
+ if key.options[:not_in]
130
+ validates_exclusion_of(attribute, :within => key.options[:not_in])
131
+ end
132
+
133
+ if key.options[:length]
134
+ length_options = case key.options[:length]
135
+ when Integer
136
+ {:minimum => 0, :maximum => key.options[:length]}
137
+ when Range
138
+ {:within => key.options[:length]}
139
+ when Hash
140
+ key.options[:length]
141
+ end
142
+ validates_length_of(attribute, length_options)
143
+ end
144
+ end
145
+ end
146
+
147
+ module InstanceMethods
148
+ def initialize(attrs={}, from_database=false)
149
+ unless attrs.nil?
150
+ provided_keys = attrs.keys.map { |k| k.to_s }
151
+ unless provided_keys.include?('_id') || provided_keys.include?('id')
152
+ write_key :_id, Mongo::ObjectID.new
153
+ end
154
+ end
155
+
156
+ assign_type_if_present
157
+
158
+ if from_database
159
+ @new = false
160
+ self.attributes = attrs
161
+ else
162
+ @new = true
163
+ assign(attrs)
164
+ end
165
+ end
166
+
167
+ def new?
168
+ @new
169
+ end
170
+
171
+ def attributes=(attrs)
172
+ return if attrs.blank?
173
+
174
+ attrs.each_pair do |name, value|
175
+ writer_method = "#{name}="
176
+
177
+ if respond_to?(writer_method)
178
+ if writer_method == '_root_document='
179
+ puts "_root_document= #{value.inspect}"
180
+ end
181
+ self.send(writer_method, value)
182
+ else
183
+ self[name.to_s] = value
184
+ end
185
+ end
186
+ end
187
+
188
+ def attributes
189
+ attrs = HashWithIndifferentAccess.new
190
+
191
+ keys.each_pair do |name, key|
192
+ value = key.set(self[key.name])
193
+ attrs[name] = value
194
+ end
195
+
196
+ embedded_associations.each do |association|
197
+ if documents = instance_variable_get(association.ivar)
198
+ attrs[association.name] = documents.map { |document| document.to_mongo }
199
+ end
200
+ end
201
+
202
+ attrs
203
+ end
204
+ alias :to_mongo :attributes
205
+
206
+ def assign(attrs={})
207
+ self.attributes = attrs
208
+ end
209
+
210
+ def update_attributes(attrs={})
211
+ assign(attrs)
212
+ save
213
+ end
214
+
215
+ def update_attributes!(attrs={})
216
+ assign(attrs)
217
+ save!
218
+ end
219
+
220
+ def id
221
+ _id
222
+ end
223
+
224
+ def id=(value)
225
+ if self.class.using_object_id?
226
+ value = MongoMapper.normalize_object_id(value)
227
+ end
228
+
229
+ self[:_id] = value
230
+ end
231
+
232
+ def [](name)
233
+ read_key(name)
234
+ end
235
+
236
+ def []=(name, value)
237
+ ensure_key_exists(name)
238
+ write_key(name, value)
239
+ end
240
+
241
+ # @api public
242
+ def keys
243
+ self.class.keys
244
+ end
245
+
246
+ # @api private?
247
+ def key_names
248
+ keys.keys
249
+ end
250
+
251
+ # @api private?
252
+ def non_embedded_keys
253
+ keys.values.select { |key| !key.embeddable? }
254
+ end
255
+
256
+ # @api private?
257
+ def embedded_keys
258
+ keys.values.select { |key| key.embeddable? }
259
+ end
260
+
261
+ private
262
+ def assign_type_if_present
263
+ self._type = self.class.name if respond_to?(:_type=)
264
+ end
265
+
266
+ def ensure_key_exists(name)
267
+ self.class.key(name) unless respond_to?("#{name}=")
268
+ end
269
+
270
+ def read_key(name)
271
+ if key = keys[name]
272
+ var_name = "@#{name}"
273
+ value = key.get(instance_variable_get(var_name))
274
+ instance_variable_set(var_name, value)
275
+ else
276
+ raise KeyNotFound, "Could not find key: #{name.inspect}"
277
+ end
278
+ end
279
+
280
+ def read_key_before_typecast(name)
281
+ instance_variable_get("@#{name}_before_typecast")
282
+ end
283
+
284
+ def write_key(name, value)
285
+ key = keys[name]
286
+
287
+ if key.embeddable? && value.is_a?(key.type)
288
+ value._parent_document = self
289
+ end
290
+
291
+ instance_variable_set "@#{name}_before_typecast", value
292
+ instance_variable_set "@#{name}", key.set(value)
293
+ end
294
+ end
295
+
296
+ class Key
297
+ attr_accessor :name, :type, :options, :default_value
298
+
299
+ def initialize(*args)
300
+ options = args.extract_options!
301
+ @name, @type = args.shift.to_s, args.shift
302
+ self.options = (options || {}).symbolize_keys
303
+ self.default_value = self.options.delete(:default)
304
+ end
305
+
306
+ def ==(other)
307
+ @name == other.name && @type == other.type
308
+ end
309
+
310
+ def embeddable?
311
+ type.respond_to?(:embeddable?) && type.embeddable? ? true : false
312
+ end
313
+
314
+ def number?
315
+ [Integer, Float].include?(type)
316
+ end
317
+
318
+ def get(value)
319
+ if value.nil? && !default_value.nil?
320
+ if default_value.respond_to?(:call)
321
+ return default_value.call
322
+ else
323
+ return default_value
324
+ end
325
+ end
326
+
327
+ type.from_mongo(value)
328
+ end
329
+
330
+ def set(value)
331
+ type.to_mongo(value)
332
+ end
333
+ end
334
+ end
335
+ end
336
+ end
@@ -0,0 +1,17 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Logger
4
+ module ClassMethods
5
+ def logger
6
+ MongoMapper.logger
7
+ end
8
+ end
9
+
10
+ module InstanceMethods
11
+ def logger
12
+ self.class.logger
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,87 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Modifiers
4
+ module ClassMethods
5
+ def increment(*args)
6
+ modifier_update('$inc', args)
7
+ end
8
+
9
+ def decrement(*args)
10
+ criteria, keys = criteria_and_keys_from_args(args)
11
+ values, to_decrement = keys.values, {}
12
+ keys.keys.each_with_index { |k, i| to_decrement[k] = -values[i].abs }
13
+ collection.update(criteria, {'$inc' => to_decrement}, :multi => true)
14
+ end
15
+
16
+ def set(*args)
17
+ modifier_update('$set', args)
18
+ end
19
+
20
+ def push(*args)
21
+ modifier_update('$push', args)
22
+ end
23
+
24
+ def push_all(*args)
25
+ modifier_update('$pushAll', args)
26
+ end
27
+
28
+ def push_uniq(*args)
29
+ criteria, keys = criteria_and_keys_from_args(args)
30
+ keys.each { |key, value | criteria[key] = {'$ne' => value} }
31
+ collection.update(criteria, {'$push' => keys}, :multi => true)
32
+ end
33
+
34
+ def pull(*args)
35
+ modifier_update('$pull', args)
36
+ end
37
+
38
+ def pull_all(*args)
39
+ modifier_update('$pullAll', args)
40
+ end
41
+
42
+ def pop(*args)
43
+ modifier_update('$pop', args)
44
+ end
45
+
46
+ private
47
+ def modifier_update(modifier, args)
48
+ criteria, keys = criteria_and_keys_from_args(args)
49
+ modifiers = {modifier => keys}
50
+ collection.update(criteria, modifiers, :multi => true)
51
+ end
52
+
53
+ def criteria_and_keys_from_args(args)
54
+ keys = args.pop
55
+ criteria = args[0].is_a?(Hash) ? args[0] : {:id => args}
56
+ [to_criteria(criteria), keys]
57
+ end
58
+ end
59
+
60
+ module InstanceMethods
61
+ def increment(hash)
62
+ self.class.increment({:_id => id}, hash)
63
+ end
64
+
65
+ def decrement(hash)
66
+ self.class.decrement({:_id => id}, hash)
67
+ end
68
+
69
+ def set(hash)
70
+ self.class.set({:_id => id}, hash)
71
+ end
72
+
73
+ def push(hash)
74
+ self.class.push({:_id => id}, hash)
75
+ end
76
+
77
+ def pull(hash)
78
+ self.class.pull({:_id => id}, hash)
79
+ end
80
+
81
+ def push_uniq(hash)
82
+ self.class.push_uniq({:_id => id}, hash)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end