mongo_odm 0.1.8

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