mongo_odm 0.1.8

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 (37) hide show
  1. data/Gemfile +11 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +251 -0
  4. data/Rakefile +70 -0
  5. data/lib/mongo_odm.rb +48 -0
  6. data/lib/mongo_odm/collection.rb +42 -0
  7. data/lib/mongo_odm/core_ext/conversions.rb +262 -0
  8. data/lib/mongo_odm/cursor.rb +11 -0
  9. data/lib/mongo_odm/document.rb +34 -0
  10. data/lib/mongo_odm/document/associations.rb +39 -0
  11. data/lib/mongo_odm/document/associations/has_many.rb +19 -0
  12. data/lib/mongo_odm/document/associations/has_one.rb +19 -0
  13. data/lib/mongo_odm/document/attribute_methods.rb +103 -0
  14. data/lib/mongo_odm/document/attribute_methods/dirty.rb +51 -0
  15. data/lib/mongo_odm/document/attribute_methods/localization.rb +67 -0
  16. data/lib/mongo_odm/document/attribute_methods/query.rb +35 -0
  17. data/lib/mongo_odm/document/attribute_methods/read.rb +39 -0
  18. data/lib/mongo_odm/document/attribute_methods/write.rb +37 -0
  19. data/lib/mongo_odm/document/callbacks.rb +29 -0
  20. data/lib/mongo_odm/document/fields.rb +66 -0
  21. data/lib/mongo_odm/document/inspect.rb +28 -0
  22. data/lib/mongo_odm/document/persistence.rb +96 -0
  23. data/lib/mongo_odm/document/validations.rb +46 -0
  24. data/lib/mongo_odm/errors.rb +18 -0
  25. data/lib/mongo_odm/version.rb +7 -0
  26. data/spec/models/00-blank_slate.rb +4 -0
  27. data/spec/models/01-shape.rb +8 -0
  28. data/spec/models/02-circle.rb +7 -0
  29. data/spec/models/03-big_red_circle.rb +8 -0
  30. data/spec/mongo_odm/core_ext/conversions_spec.rb +423 -0
  31. data/spec/mongo_odm/document/fields_spec.rb +187 -0
  32. data/spec/mongo_odm/document/inspect_spec.rb +19 -0
  33. data/spec/mongo_odm/document_spec.rb +12 -0
  34. data/spec/mongo_odm/mongo_odm_spec.rb +84 -0
  35. data/spec/spec.opts +4 -0
  36. data/spec/spec_helper.rb +12 -0
  37. metadata +185 -0
@@ -0,0 +1,262 @@
1
+ # encoding: utf-8
2
+ require 'active_support/core_ext/big_decimal'
3
+ require 'active_support/core_ext/date/conversions'
4
+ require 'active_support/core_ext/date_time/calculations'
5
+ require 'active_support/core_ext/date_time/conversions'
6
+ require 'active_support/core_ext/string/conversions'
7
+ require 'active_support/core_ext/time/conversions'
8
+
9
+ # The type_cast class method is called when:
10
+ # * An attribute of the same class is assigned
11
+ # * An attribute of the same class is readed from the Mongo driver
12
+ #
13
+ # The to_mongo instance method is called when:
14
+ # * An attribute of the same class is sent to the Mongo driver
15
+
16
+ # @private
17
+ class Mongo::ObjectID
18
+ def self.type_cast(value)
19
+ return nil if value.nil?
20
+ return value if value.is_a?(Mongo::ObjectID)
21
+ value.to_s
22
+ end
23
+
24
+ def to_mongo
25
+ self
26
+ end
27
+ end
28
+
29
+ # @private
30
+ class BSON::ObjectID
31
+ def self.type_cast(value)
32
+ return nil if value.nil?
33
+ return value if value.is_a?(BSON::ObjectID)
34
+ value.to_s
35
+ end
36
+
37
+ def to_mongo
38
+ self
39
+ end
40
+ end
41
+
42
+ # @private
43
+ class Array
44
+ def self.type_cast(value)
45
+ return nil if value.nil?
46
+ value.to_a.map {|elem| MongoODM.instanciate(elem)}
47
+ end
48
+
49
+ def to_mongo
50
+ self.map {|elem| elem.to_mongo}
51
+ end
52
+ end
53
+
54
+ # @private
55
+ class Class
56
+ def self.type_cast(value)
57
+ return nil if value.nil?
58
+ value.to_s.constantize
59
+ end
60
+
61
+ def to_mongo
62
+ self.name
63
+ end
64
+ end
65
+
66
+ # @private
67
+ class Symbol
68
+ def self.type_cast(value)
69
+ return nil if value.nil?
70
+ value.to_s.intern
71
+ end
72
+
73
+ def to_mongo
74
+ self
75
+ end
76
+ end
77
+
78
+ # @private
79
+ class Integer
80
+ def self.type_cast(value)
81
+ return nil if value.nil?
82
+ value.to_i
83
+ end
84
+
85
+ def to_mongo
86
+ self
87
+ end
88
+ end
89
+
90
+ # @private
91
+ class Float
92
+ def self.type_cast(value)
93
+ return nil if value.nil?
94
+ value.to_f
95
+ end
96
+
97
+ def to_mongo
98
+ self
99
+ end
100
+ end
101
+
102
+ # @private
103
+ class BigDecimal
104
+ def self.type_cast(value)
105
+ return nil if value.nil?
106
+ value.is_a?(BigDecimal) ? value : new(value.to_s)
107
+ end
108
+
109
+ def to_mongo
110
+ self.to_s
111
+ end
112
+ end
113
+
114
+ # @private
115
+ class String
116
+ def self.type_cast(value)
117
+ return nil if value.nil?
118
+ value.to_s
119
+ end
120
+
121
+ def to_mongo
122
+ self
123
+ end
124
+ end
125
+
126
+ # @private
127
+ class Date
128
+ def self.type_cast(value)
129
+ return nil if value.nil?
130
+ value.to_date
131
+ end
132
+
133
+ def to_mongo
134
+ Time.utc(self.year, self.month, self.day)
135
+ end
136
+ end
137
+
138
+ # @private
139
+ class DateTime
140
+ def self.type_cast(value)
141
+ return nil if value.nil?
142
+ value.to_datetime
143
+ end
144
+
145
+ def to_mongo
146
+ datetime = self.utc
147
+ Time.utc(datetime.year, datetime.month, datetime.day, datetime.hour, datetime.min, datetime.sec)
148
+ end
149
+ end
150
+
151
+ # @private
152
+ class TrueClass
153
+ def self.type_cast(value)
154
+ return nil if value.nil?
155
+ true
156
+ end
157
+
158
+ def to_mongo
159
+ self
160
+ end
161
+ end
162
+
163
+ # @private
164
+ class FalseClass
165
+ def self.type_cast(value)
166
+ return nil if value.nil?
167
+ false
168
+ end
169
+
170
+ def to_mongo
171
+ self
172
+ end
173
+ end
174
+
175
+ # @private
176
+ class Time
177
+ def self.type_cast(value)
178
+ return nil if value.nil?
179
+ value.to_time
180
+ end
181
+
182
+ def to_mongo
183
+ self.utc
184
+ end
185
+ end
186
+
187
+ # Stand-in for true/false property types.
188
+ # @private
189
+ module Boolean
190
+ def self.type_cast(value)
191
+ case value
192
+ when NilClass
193
+ nil
194
+ when Numeric
195
+ !value.zero?
196
+ when TrueClass, FalseClass
197
+ value
198
+ when /^\s*t/i
199
+ true
200
+ when /^\s*f/i
201
+ false
202
+ else
203
+ value.present?
204
+ end
205
+ end
206
+ end
207
+
208
+ # @private
209
+ class Numeric
210
+ def self.type_cast(value)
211
+ return nil if value.nil?
212
+ float_value = value.to_f
213
+ int_value = value.to_i
214
+ float_value == int_value ? int_value : float_value
215
+ end
216
+ end
217
+
218
+ # @private
219
+ class Hash
220
+ def self.type_cast(value)
221
+ return nil if value.nil?
222
+ Hash[value.to_hash.map{|k,v| [MongoODM.instanciate(k), MongoODM.instanciate(v)]}]
223
+ end
224
+
225
+ def to_mongo
226
+ Hash[self.map{|k,v| [k.to_mongo, v.to_mongo]}]
227
+ end
228
+ end
229
+
230
+ # @private
231
+ class HashWithIndifferentAccess
232
+ def self.type_cast(value)
233
+ Hash.type_cast(value).with_indifferent_access
234
+ end
235
+
236
+ def to_mongo
237
+ Hash[self.map{|k,v| [k.to_mongo, v.to_mongo]}]
238
+ end
239
+ end
240
+
241
+ # @private
242
+ class Regexp
243
+ def self.type_cast(value)
244
+ return nil if value.nil?
245
+ new(value)
246
+ end
247
+
248
+ def to_mongo
249
+ self
250
+ end
251
+ end
252
+
253
+ # @private
254
+ class NilClass
255
+ def self.type_cast(value)
256
+ nil
257
+ end
258
+
259
+ def to_mongo
260
+ nil
261
+ end
262
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+ module MongoODM
3
+
4
+ class Cursor < Mongo::Cursor
5
+ def next_document
6
+ doc = super
7
+ MongoODM.instanciate_doc(doc)
8
+ end
9
+ end
10
+
11
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+ require 'mongo_odm'
3
+
4
+ module MongoODM
5
+ module Document
6
+
7
+ extend ActiveSupport::Concern
8
+ extend ActiveSupport::Autoload
9
+
10
+ autoload :Associations
11
+ autoload :AttributeMethods
12
+ autoload :Callbacks
13
+ autoload :Fields
14
+ autoload :Inspect
15
+ autoload :Persistence
16
+ autoload :Validations
17
+
18
+ included do
19
+ include ActiveModel::Conversion
20
+ include ActiveModel::Serializers::JSON
21
+ include ActiveModel::Serializers::Xml
22
+ include ActiveModel::Observing
23
+ include ActiveModel::Translation
24
+ include MongoODM::Document::Persistence
25
+ include MongoODM::Document::AttributeMethods
26
+ include MongoODM::Document::Fields
27
+ include MongoODM::Document::Inspect
28
+ include MongoODM::Document::Associations
29
+ include MongoODM::Document::Callbacks
30
+ include MongoODM::Document::Validations
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ module MongoODM
4
+ module Document
5
+ module Associations
6
+
7
+ extend ActiveSupport::Concern
8
+ extend ActiveSupport::Autoload
9
+
10
+ autoload :HasOne
11
+ autoload :HasMany
12
+
13
+ included do
14
+ class_inheritable_accessor :associations
15
+ self.associations = {}
16
+
17
+ include MongoODM::Document::Associations::HasOne
18
+ include MongoODM::Document::Associations::HasMany
19
+ end
20
+
21
+ module InstanceMethods
22
+ def associations
23
+ self.class.associations
24
+ end
25
+ end
26
+
27
+ module ClassMethods
28
+ def associate(type, options)
29
+ name = options.name.to_s
30
+ associations[name] = MetaData.new(type, options)
31
+ define_method(name) { memoized(name) { type.instantiate(self, options) } }
32
+ define_method("#{name}=") { |object| reset(name) { type.update(object, self, options) } }
33
+ end
34
+ protected :associate
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module MongoODM
4
+ module Document
5
+ module Associations
6
+ module HasMany
7
+
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ def has_many
12
+
13
+ end
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module MongoODM
4
+ module Document
5
+ module Associations
6
+ module HasOne
7
+
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ def has_one
12
+
13
+ end
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,103 @@
1
+ # encoding: utf-8
2
+ require 'active_support/core_ext/hash/indifferent_access'
3
+
4
+ module MongoODM
5
+ module Document
6
+ module AttributeMethods
7
+
8
+ extend ActiveSupport::Concern
9
+ extend ActiveSupport::Autoload
10
+
11
+ autoload :Read
12
+ autoload :Write
13
+ autoload :Query
14
+ autoload :Dirty
15
+ autoload :Localization
16
+
17
+ included do
18
+ include ActiveModel::AttributeMethods
19
+ include MongoODM::Document::AttributeMethods::Read
20
+ include MongoODM::Document::AttributeMethods::Write
21
+ include MongoODM::Document::AttributeMethods::Query
22
+ include MongoODM::Document::AttributeMethods::Dirty
23
+ include MongoODM::Document::AttributeMethods::Localization
24
+ end
25
+
26
+ module InstanceMethods
27
+ attr_reader :attributes
28
+
29
+ def initialize(attrs = {})
30
+ @attributes = {:_class => self.class.name}.with_indifferent_access
31
+ load_attributes_or_defaults(attrs)
32
+ self
33
+ end
34
+
35
+ def force_attributes=(new_attributes)
36
+ send(:attributes=, new_attributes, true)
37
+ end
38
+
39
+ def attributes=(new_attributes, auto_generate_attributes = false)
40
+ return if new_attributes.blank?
41
+ new_attributes.each do |name, value|
42
+ if respond_to?(:"#{name}=")
43
+ send(:"#{name}=", value)
44
+ else
45
+ auto_generate_attributes ? write_attribute(name, value) : raise(MongoODM::Errors::UnknownFieldError, "unknown field: #{name}")
46
+ end
47
+ end
48
+ end
49
+
50
+ def freeze
51
+ @attributes.freeze; super
52
+ end
53
+
54
+ def has_attribute?(name)
55
+ @attributes.has_key?(name)
56
+ end
57
+
58
+ def load_attributes_or_defaults(attrs)
59
+ attrs = self.class.default_attributes.merge(attrs)
60
+ self.force_attributes = attrs
61
+ end
62
+
63
+ def remove_attribute(name)
64
+ @attributes.delete(name)
65
+ end
66
+
67
+ def method_missing(method_id, *args, &block)
68
+ # If we haven't generated any methods yet, generate them, then
69
+ # see if we've created the method we're looking for.
70
+ if !self.class.attribute_methods_generated?
71
+ self.class.define_attribute_methods_for_fields
72
+ method_name = method_id.to_s
73
+ guard_private_attribute_method!(method_name, args)
74
+ send(method_id, *args, &block)
75
+ else
76
+ super
77
+ end
78
+ end
79
+
80
+ def respond_to?(*args)
81
+ self.class.define_attribute_methods_for_fields
82
+ super
83
+ end
84
+
85
+ def attribute_method?(attr_name)
86
+ attr_name == '_id' || attributes.include?(attr_name)
87
+ end
88
+ protected :attribute_method?
89
+ end
90
+
91
+ module ClassMethods
92
+ def default_attributes
93
+ HashWithIndifferentAccess[fields.values.map{|field| [field.name, field.default]}]
94
+ end
95
+
96
+ def define_attribute_methods_for_fields
97
+ define_attribute_methods(fields.keys + [:_id, :_class])
98
+ end
99
+ end
100
+
101
+ end
102
+ end
103
+ end