mongodb 0.0.4 → 0.0.5
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.
- data/lib/{mongodb → mongo}/driver.rb +2 -2
- data/lib/{mongodb → mongo}/driver/collection.rb +0 -0
- data/lib/{mongodb → mongo}/driver/database.rb +0 -0
- data/lib/{mongodb → mongo}/driver/dynamic_finders.rb +0 -0
- data/lib/{mongodb → mongo}/driver/spec.rb +0 -0
- data/lib/{mongodb → mongo}/gems.rb +0 -0
- data/lib/mongo/migration.rb +8 -0
- data/lib/{mongodb → mongo}/migration/definition.rb +0 -0
- data/lib/{mongodb → mongo}/migration/migration.rb +0 -0
- data/lib/{mongodb → mongo}/migration/tasks.rb +0 -0
- data/lib/{mongodb → mongo}/object.rb +4 -4
- data/lib/mongo/object/object.rb +284 -0
- data/lib/mongo/object/object_helper.rb +80 -0
- data/lib/mongo/object/spec.rb +4 -0
- data/{spec/object → lib/mongo/object/spec}/crud_shared.rb +2 -2
- data/readme.md +11 -9
- data/spec/driver/spec_helper.rb +2 -2
- data/spec/migration/migration_spec.rb +1 -1
- data/spec/object/callbacks_spec.rb +32 -32
- data/spec/object/crud_spec.rb +7 -1
- data/spec/object/spec_helper.rb +7 -7
- data/spec/object/validation_spec.rb +18 -15
- metadata +18 -28
- data/lib/mongodb/migration.rb +0 -8
- data/lib/mongodb/object/object_helper.rb +0 -62
- data/lib/mongodb/object/object_serializer.rb +0 -273
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'mongo/gems'
|
2
2
|
|
3
3
|
require 'mongo'
|
4
4
|
|
@@ -9,7 +9,7 @@ class Mongo::NotFound < Mongo::Error; end
|
|
9
9
|
database
|
10
10
|
collection
|
11
11
|
dynamic_finders
|
12
|
-
).each{|f| require "
|
12
|
+
).each{|f| require "mongo/driver/#{f}"}
|
13
13
|
|
14
14
|
# defaults
|
15
15
|
Mongo.class_eval do
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require '
|
1
|
+
require 'mongo/driver'
|
2
2
|
|
3
3
|
%w(
|
4
|
-
|
4
|
+
object
|
5
5
|
object_helper
|
6
|
-
).each{|f| require "
|
6
|
+
).each{|f| require "mongo/object/#{f}"}
|
7
7
|
|
8
8
|
Mongo.defaults[:callbacks] = true
|
9
9
|
|
@@ -11,7 +11,7 @@ Mongo.defaults[:callbacks] = true
|
|
11
11
|
Mongo::Collection.class_eval do
|
12
12
|
include Mongo::ObjectHelper
|
13
13
|
|
14
|
-
%w(
|
14
|
+
%w(create update save destroy).each do |method|
|
15
15
|
alias_method "#{method}_without_object", method
|
16
16
|
alias_method method, "#{method}_with_object"
|
17
17
|
end
|
@@ -0,0 +1,284 @@
|
|
1
|
+
module Mongo::Object
|
2
|
+
attr_accessor :_id
|
3
|
+
|
4
|
+
def valid? opts = {}
|
5
|
+
opts = ::Mongo::Object.parse_options opts
|
6
|
+
begin
|
7
|
+
return false unless errors.empty?
|
8
|
+
|
9
|
+
return false if opts[:callbacks] and !::Mongo::Object.run_callbacks(self, :before, :validate)
|
10
|
+
|
11
|
+
child_opts = opts.merge internal: true
|
12
|
+
if child_objects.all?{|group| group.all?{|obj| obj.valid?(child_opts)}} and errors.empty?
|
13
|
+
::Mongo::Object.run_callbacks(self, :after, :validate) if opts[:callbacks]
|
14
|
+
true
|
15
|
+
else
|
16
|
+
false
|
17
|
+
end
|
18
|
+
ensure
|
19
|
+
clear_child_objects unless opts[:internal]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def errors
|
24
|
+
@_errors ||= {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_object collection, opts
|
28
|
+
with_object_callbacks :create, opts do |opts|
|
29
|
+
doc = ::Mongo::Object.to_mongo self
|
30
|
+
collection.create(doc, opts)
|
31
|
+
self._id = doc[:_id] || doc['_id']
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def update_object collection, opts
|
36
|
+
with_object_callbacks :update, opts do |opts|
|
37
|
+
id = _id || "can't update object without _id (#{self})!"
|
38
|
+
doc = ::Mongo::Object.to_mongo self
|
39
|
+
collection.update({_id: id}, doc, opts)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def destroy_object collection, opts
|
44
|
+
with_object_callbacks :destroy, opts do |opts|
|
45
|
+
id = _id || "can't destroy object without _id (#{self})!"
|
46
|
+
collection.destroy({_id: id}, opts)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def save_object collection, opts
|
51
|
+
if _id
|
52
|
+
update_object collection, opts
|
53
|
+
else
|
54
|
+
create_object collection, opts
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# need this to allow change it in specs
|
59
|
+
# RSpec adds @mock_proxy, and we need to skip it
|
60
|
+
SKIP_IV_REGEXP = /^@_/
|
61
|
+
|
62
|
+
class << self
|
63
|
+
def parse_options opts
|
64
|
+
opts = opts.clone
|
65
|
+
opts[:validate] = true unless opts.include?(:validate)
|
66
|
+
opts[:callbacks] = Mongo.defaults[:callbacks] unless opts.include?(:callbacks)
|
67
|
+
return opts
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_mongo_options opts
|
71
|
+
opts = opts.clone
|
72
|
+
opts.delete :validate
|
73
|
+
opts.delete :callbacks
|
74
|
+
opts
|
75
|
+
end
|
76
|
+
|
77
|
+
def each_instance_variable obj, &block
|
78
|
+
obj.instance_variables.each do |iv_name|
|
79
|
+
# skipping variables starting with _xx, usually they
|
80
|
+
# have specific meaning and used for example for cache
|
81
|
+
next if iv_name =~ SKIP_IV_REGEXP
|
82
|
+
|
83
|
+
block.call iv_name, obj.instance_variable_get(iv_name)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# converts object to document (also works with nested & arrays)
|
88
|
+
def to_mongo obj
|
89
|
+
return obj.to_mongo if obj.respond_to? :to_mongo
|
90
|
+
symbolize = ::Mongo.defaults[:symbolize]
|
91
|
+
|
92
|
+
if obj.is_a? Hash
|
93
|
+
doc = {}
|
94
|
+
obj.each do |k, v|
|
95
|
+
doc[k] = to_mongo v
|
96
|
+
end
|
97
|
+
doc
|
98
|
+
elsif obj.is_a? Array
|
99
|
+
obj.collect{|v| to_mongo v}
|
100
|
+
elsif obj.is_a? Mongo::Object
|
101
|
+
doc = {}
|
102
|
+
|
103
|
+
# copying instance variables
|
104
|
+
each_instance_variable obj do |iv_name, v|
|
105
|
+
k = iv_name.to_s[1..-1]
|
106
|
+
k = k.to_sym if symbolize
|
107
|
+
doc[k] = to_mongo v
|
108
|
+
end
|
109
|
+
|
110
|
+
# adding _id & _class
|
111
|
+
id_key, class_key = symbolize ? [:_id, :_class] : ['_id', '_class']
|
112
|
+
id = instance_variable_get('@_id')
|
113
|
+
doc[id_key] = id if id
|
114
|
+
doc[class_key] = obj.class.name
|
115
|
+
|
116
|
+
doc
|
117
|
+
else # simple type
|
118
|
+
obj
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def each_object obj, include_first = true, &block
|
123
|
+
if obj.is_a? Hash
|
124
|
+
obj.each{|k, v| each_object v, &block}
|
125
|
+
elsif obj.is_a? Array
|
126
|
+
obj.each{|v| each_object v, &block}
|
127
|
+
elsif obj.is_a? ::Mongo::Object
|
128
|
+
block.call obj if include_first
|
129
|
+
each_instance_variable obj do |iv_name, v|
|
130
|
+
each_object v, &block
|
131
|
+
end
|
132
|
+
end
|
133
|
+
nil
|
134
|
+
end
|
135
|
+
|
136
|
+
def build doc
|
137
|
+
return unless doc
|
138
|
+
obj = _build doc
|
139
|
+
obj.send :update_internal_state! if obj.is_a? ::Mongo::Object
|
140
|
+
obj
|
141
|
+
end
|
142
|
+
|
143
|
+
def run_callbacks obj, type, method_name
|
144
|
+
obj.respond_to?(:run_callbacks) ? obj.run_callbacks(type, method_name) : true
|
145
|
+
end
|
146
|
+
|
147
|
+
protected
|
148
|
+
def _build doc
|
149
|
+
if doc.is_a? Hash
|
150
|
+
if class_name = doc[:_class] || doc['_class']
|
151
|
+
klass = constantize class_name
|
152
|
+
|
153
|
+
if klass.respond_to? :from_mongo
|
154
|
+
klass.from_mongo doc
|
155
|
+
else
|
156
|
+
obj = klass.new
|
157
|
+
doc.each do |k, v|
|
158
|
+
next if k.to_sym == :_class
|
159
|
+
|
160
|
+
v = _build v
|
161
|
+
obj.instance_variable_set "@#{k}", v
|
162
|
+
end
|
163
|
+
obj
|
164
|
+
end
|
165
|
+
else
|
166
|
+
doc
|
167
|
+
end
|
168
|
+
elsif doc.is_a? Array
|
169
|
+
doc.collect{|v| _build v}
|
170
|
+
else
|
171
|
+
doc
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def constantize class_name
|
176
|
+
@constantize_cache ||= {}
|
177
|
+
unless klass = @constantize_cache[class_name]
|
178
|
+
klass = eval class_name, TOPLEVEL_BINDING, __FILE__, __LINE__
|
179
|
+
@constantize_cache[class_name] = klass
|
180
|
+
end
|
181
|
+
klass
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
protected
|
186
|
+
attr_writer :_original_children
|
187
|
+
def _original_children
|
188
|
+
@_original_children ||= []
|
189
|
+
end
|
190
|
+
|
191
|
+
def update_internal_state!
|
192
|
+
return unless ::Mongo.defaults[:callbacks]
|
193
|
+
|
194
|
+
_original_children.clear
|
195
|
+
::Mongo::Object.each_object self, false do |obj|
|
196
|
+
_original_children << obj
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def clear_child_objects
|
201
|
+
if instance_variable_get(:@_child_objects)
|
202
|
+
child_objects.each do |group|
|
203
|
+
group.each{|obj| obj.clear_child_objects}
|
204
|
+
end
|
205
|
+
remove_instance_variable :@_child_objects
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def child_objects
|
210
|
+
unless @_child_objects
|
211
|
+
created_children, updated_children, destroyed_children = [], [], []
|
212
|
+
|
213
|
+
original_children_ids = Set.new; _original_children.each{|obj| original_children_ids << obj.object_id}
|
214
|
+
::Mongo::Object.each_object self, false do |obj|
|
215
|
+
(original_children_ids.include?(obj.object_id) ? updated_children : created_children) << obj
|
216
|
+
end
|
217
|
+
|
218
|
+
children_ids = Set.new; ::Mongo::Object.each_object(self, false){|obj| children_ids << obj.object_id}
|
219
|
+
destroyed_children = _original_children.select{|obj| !children_ids.include?(obj.object_id)}
|
220
|
+
|
221
|
+
@_child_objects = [created_children, updated_children, destroyed_children]
|
222
|
+
end
|
223
|
+
@_child_objects
|
224
|
+
end
|
225
|
+
|
226
|
+
def with_object_callbacks method_name, opts, &block
|
227
|
+
opts = ::Mongo::Object.parse_options opts
|
228
|
+
|
229
|
+
# validation
|
230
|
+
return false if opts[:validate] and !valid?(opts.merge(internal: true))
|
231
|
+
|
232
|
+
# before callbacks
|
233
|
+
return false if opts[:callbacks] and !run_all_callbacks(:before, method_name)
|
234
|
+
|
235
|
+
# saving
|
236
|
+
block.call ::Mongo::Object.to_mongo_options(opts)
|
237
|
+
update_internal_state!
|
238
|
+
|
239
|
+
# after callbacks
|
240
|
+
run_all_callbacks :after, method_name if opts[:callbacks]
|
241
|
+
|
242
|
+
true
|
243
|
+
ensure
|
244
|
+
clear_child_objects
|
245
|
+
end
|
246
|
+
|
247
|
+
# TODO1 move to static method
|
248
|
+
def run_all_callbacks type, method_name
|
249
|
+
result = if type == :before
|
250
|
+
::Mongo::Object.run_callbacks self, type, method_name
|
251
|
+
else
|
252
|
+
true
|
253
|
+
end
|
254
|
+
|
255
|
+
result &= if method_name == :create
|
256
|
+
child_objects.all? do |group|
|
257
|
+
group.all? do |obj|
|
258
|
+
obj.run_all_callbacks type, method_name
|
259
|
+
end
|
260
|
+
end
|
261
|
+
elsif method_name == :update
|
262
|
+
created_children, updated_children, destroyed_children = child_objects
|
263
|
+
created_children.all?{|obj| obj.run_all_callbacks type, :create} and
|
264
|
+
updated_children.all?{|obj| obj.run_all_callbacks type, :update} and
|
265
|
+
destroyed_children.all?{|obj| obj.run_all_callbacks type, :destroy}
|
266
|
+
elsif method_name == :destroy
|
267
|
+
child_objects.all? do |group|
|
268
|
+
group.all? do |obj|
|
269
|
+
obj.run_all_callbacks type, method_name
|
270
|
+
end
|
271
|
+
end
|
272
|
+
else
|
273
|
+
raise_error "unknown callback method (#{method_name})!"
|
274
|
+
end
|
275
|
+
|
276
|
+
result &= if type == :after
|
277
|
+
::Mongo::Object.run_callbacks self, type, method_name
|
278
|
+
else
|
279
|
+
true
|
280
|
+
end
|
281
|
+
|
282
|
+
result
|
283
|
+
end
|
284
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Mongo::ObjectHelper
|
2
|
+
#
|
3
|
+
# CRUD
|
4
|
+
#
|
5
|
+
def create_with_object doc, opts = {}
|
6
|
+
if doc.is_a? ::Mongo::Object
|
7
|
+
doc.create_object self, opts
|
8
|
+
else
|
9
|
+
create_without_object doc, opts
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def update_with_object *args
|
14
|
+
if args.first.is_a? ::Mongo::Object
|
15
|
+
doc, opts = args
|
16
|
+
opts ||= {}
|
17
|
+
doc.update_object self, opts
|
18
|
+
else
|
19
|
+
update_without_object *args
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def save_with_object doc, opts = {}
|
24
|
+
if doc.is_a? ::Mongo::Object
|
25
|
+
doc.save_object self, opts
|
26
|
+
else
|
27
|
+
save_without_object doc, opts
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def destroy_with_object *args
|
32
|
+
if args.first.is_a? ::Mongo::Object
|
33
|
+
doc, opts = args
|
34
|
+
opts ||= {}
|
35
|
+
doc.destroy_object self, opts
|
36
|
+
else
|
37
|
+
destroy_without_object *args
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def create! *args
|
42
|
+
create(*args) || raise(Mongo::Error, "can't create #{doc.inspect}!")
|
43
|
+
end
|
44
|
+
|
45
|
+
def update! *args
|
46
|
+
update(*args) || raise(Mongo::Error, "can't update #{doc.inspect}!")
|
47
|
+
end
|
48
|
+
|
49
|
+
def save! *args
|
50
|
+
save(*args) || raise(Mongo::Error, "can't save #{doc.inspect}!")
|
51
|
+
end
|
52
|
+
|
53
|
+
def destroy! *args
|
54
|
+
destroy(*args) || raise(Mongo::Error, "can't destroy #{doc.inspect}!")
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
#
|
59
|
+
# Querying
|
60
|
+
#
|
61
|
+
def first selector = {}, opts = {}, &block
|
62
|
+
opts = opts.clone
|
63
|
+
if opts.delete(:object) == false
|
64
|
+
super selector, opts, &block
|
65
|
+
else
|
66
|
+
::Mongo::Object.build super(selector, opts, &block)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def each selector = {}, opts = {}, &block
|
71
|
+
opts = opts.clone
|
72
|
+
if opts.delete(:object) == false
|
73
|
+
super selector, opts, &block
|
74
|
+
else
|
75
|
+
super selector, opts do |doc|
|
76
|
+
block.call ::Mongo::Object.build(doc)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -7,7 +7,7 @@ shared_examples_for 'object CRUD' do
|
|
7
7
|
|
8
8
|
# create
|
9
9
|
db.units.save(@zeratul).should be_true
|
10
|
-
@zeratul.
|
10
|
+
@zeratul._id.should_not be_nil
|
11
11
|
|
12
12
|
# read
|
13
13
|
db.units.count.should == 1
|
@@ -31,7 +31,7 @@ shared_examples_for 'embedded object CRUD' do
|
|
31
31
|
it 'crud' do
|
32
32
|
# create
|
33
33
|
db.players.save(@player)
|
34
|
-
@player.
|
34
|
+
@player._id.should_not be_nil
|
35
35
|
|
36
36
|
# read
|
37
37
|
db.players.count.should == 1
|
data/readme.md
CHANGED
@@ -16,7 +16,7 @@ These enhancements alter the driver's API and made it more simple and intuitive.
|
|
16
16
|
- 100% backward compatibility with original driver API (if not - it's a bug, report it please)
|
17
17
|
|
18
18
|
``` ruby
|
19
|
-
require '
|
19
|
+
require 'mongo/driver'
|
20
20
|
|
21
21
|
# Changing some defaults.
|
22
22
|
Mongo.defaults.merge! symbolize: true, multi: true, safe: true
|
@@ -67,7 +67,7 @@ So, please use standard Ruby driver documentation.
|
|
67
67
|
Define migration steps, specify desired version and apply it (usually all this should be done via Rake task).
|
68
68
|
|
69
69
|
``` ruby
|
70
|
-
require '
|
70
|
+
require 'mongo/migration'
|
71
71
|
|
72
72
|
# Connection & db.
|
73
73
|
connection = Mongo::Connection.new
|
@@ -121,8 +121,16 @@ Save any Ruby object to MongoDB, as if it's a document. Objects can be any type,
|
|
121
121
|
Note: the :initialize method should allow to create object without arguments.
|
122
122
|
|
123
123
|
``` ruby
|
124
|
+
# Connecting to MongoDB.
|
125
|
+
require 'mongo/object'
|
126
|
+
Mongo.defaults.merge! symbolize: true, multi: true, safe: true
|
127
|
+
connection = Mongo::Connection.new
|
128
|
+
db = connection.db 'default_test'
|
129
|
+
db.units.drop
|
130
|
+
|
124
131
|
# Let's define the game unit.
|
125
132
|
class Unit
|
133
|
+
include Mongo::Object
|
126
134
|
attr_reader :name, :stats
|
127
135
|
|
128
136
|
# don't forget to allow creating object with no arguments
|
@@ -131,6 +139,7 @@ class Unit
|
|
131
139
|
end
|
132
140
|
|
133
141
|
class Stats
|
142
|
+
include Mongo::Object
|
134
143
|
attr_accessor :attack, :life, :shield
|
135
144
|
|
136
145
|
def initialize attack = nil, life = nil, shield = nil
|
@@ -139,13 +148,6 @@ class Unit
|
|
139
148
|
end
|
140
149
|
end
|
141
150
|
|
142
|
-
# Connecting to MongoDB.
|
143
|
-
require 'mongodb/object'
|
144
|
-
Mongo.defaults.merge! symbolize: true, multi: true, safe: true
|
145
|
-
connection = Mongo::Connection.new
|
146
|
-
db = connection.db 'default_test'
|
147
|
-
db.units.drop
|
148
|
-
|
149
151
|
# Create.
|
150
152
|
zeratul = Unit.new('Zeratul', Unit::Stats.new(85, 300, 100))
|
151
153
|
tassadar = Unit.new('Tassadar', Unit::Stats.new(0, 80, 300))
|
data/spec/driver/spec_helper.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'mongo/driver'
|
2
2
|
|
3
3
|
Mongo.defaults.merge! \
|
4
4
|
symbolize: true,
|
@@ -9,7 +9,7 @@ Mongo.defaults.merge! \
|
|
9
9
|
|
10
10
|
require 'ruby_ext'
|
11
11
|
require 'rspec_ext'
|
12
|
-
require '
|
12
|
+
require 'mongo/driver/spec'
|
13
13
|
|
14
14
|
#
|
15
15
|
# Handy spec helpers
|
@@ -5,11 +5,11 @@ describe 'Object callbacks' do
|
|
5
5
|
|
6
6
|
before :all do
|
7
7
|
class Player
|
8
|
-
include RSpec::CallbackHelper
|
8
|
+
include Mongo::Object, RSpec::CallbackHelper
|
9
9
|
attr_accessor :missions
|
10
10
|
|
11
11
|
class Mission
|
12
|
-
include RSpec::CallbackHelper
|
12
|
+
include Mongo::Object, RSpec::CallbackHelper
|
13
13
|
end
|
14
14
|
end
|
15
15
|
end
|
@@ -22,49 +22,49 @@ describe 'Object callbacks' do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'create' do
|
25
|
-
%w(before_validate
|
26
|
-
@player.should_receive(name).once.ordered
|
27
|
-
@mission.should_receive(name).once.ordered
|
25
|
+
%w(before_validate after_validate before_create after_create).each do |name|
|
26
|
+
@player.should_receive(name).once.ordered.and_return(true)
|
27
|
+
@mission.should_receive(name).once.ordered.and_return(true)
|
28
28
|
end
|
29
29
|
|
30
|
-
db.players.save
|
30
|
+
db.players.save(@player).should be_true
|
31
31
|
end
|
32
32
|
|
33
33
|
it 'update' do
|
34
|
-
db.players.save(@player)
|
34
|
+
db.players.save(@player).should be_true
|
35
35
|
|
36
|
-
%w(before_validate
|
37
|
-
@player.should_receive(name).once.ordered
|
38
|
-
@mission.should_receive(name).once.ordered
|
36
|
+
%w(before_validate after_validate before_update after_update).each do |name|
|
37
|
+
@player.should_receive(name).once.ordered.and_return(true)
|
38
|
+
@mission.should_receive(name).once.ordered.and_return(true)
|
39
39
|
end
|
40
|
-
db.players.save
|
40
|
+
db.players.save(@player).should be_true
|
41
41
|
end
|
42
42
|
|
43
43
|
it 'destroy' do
|
44
|
-
db.players.save
|
44
|
+
db.players.save(@player).should be_true
|
45
45
|
|
46
|
-
%w(before_validate before_destroy after_destroy
|
47
|
-
@player.should_receive(name).once.ordered
|
48
|
-
@mission.should_receive(name).once.ordered
|
46
|
+
%w(before_validate after_validate before_destroy after_destroy).each do |name|
|
47
|
+
@player.should_receive(name).once.ordered.and_return(true)
|
48
|
+
@mission.should_receive(name).once.ordered.and_return(true)
|
49
49
|
end
|
50
|
-
db.players.destroy
|
50
|
+
db.players.destroy(@player).should be_true
|
51
51
|
end
|
52
52
|
|
53
53
|
it 'should be able skip callbacks' do
|
54
|
-
@player.should_not_receive(:
|
55
|
-
@mission.should_not_receive(:
|
54
|
+
@player.should_not_receive(:run_callbacks)
|
55
|
+
@mission.should_not_receive(:run_callbacks)
|
56
56
|
|
57
|
-
db.players.save
|
57
|
+
db.players.save(@player, callbacks: false).should be_true
|
58
58
|
db.players.count.should == 1
|
59
|
-
db.players.save
|
59
|
+
db.players.save(@player, callbacks: false).should be_true
|
60
60
|
db.players.count.should == 1
|
61
|
-
db.players.destroy
|
61
|
+
db.players.destroy(@player, callbacks: false).should be_true
|
62
62
|
db.players.count.should == 0
|
63
63
|
end
|
64
64
|
|
65
65
|
it 'should be able interrupt CRUD' do
|
66
|
-
@mission.stub! :
|
67
|
-
false if type == :before and method_name == :
|
66
|
+
@mission.stub! :run_callbacks do |type, method_name|
|
67
|
+
false if type == :before and method_name == :create
|
68
68
|
end
|
69
69
|
db.players.save(@player).should be_false
|
70
70
|
db.players.count.should == 0
|
@@ -72,26 +72,26 @@ describe 'Object callbacks' do
|
|
72
72
|
|
73
73
|
describe "embedded" do
|
74
74
|
it 'should fire :destroy on detached objects' do
|
75
|
-
db.players.save
|
75
|
+
db.players.save(@player).should be_true
|
76
76
|
@player.missions.clear
|
77
|
-
@mission.should_receive(:before_destroy).once
|
78
|
-
db.players.destroy
|
77
|
+
@mission.should_receive(:before_destroy).once.and_return(true)
|
78
|
+
db.players.destroy(@player).should be_true
|
79
79
|
end
|
80
80
|
|
81
81
|
it 'should fire :destroy on deleted objects in update' do
|
82
|
-
db.players.save
|
82
|
+
db.players.save(@player).should be_true
|
83
83
|
@player.missions.clear
|
84
|
-
@mission.should_receive(:before_destroy).once
|
85
|
-
db.players.save
|
84
|
+
@mission.should_receive(:before_destroy).once.and_return(true)
|
85
|
+
db.players.save(@player).should be_true
|
86
86
|
end
|
87
87
|
|
88
88
|
it 'should fire :create on new objects in update' do
|
89
|
-
db.players.save
|
89
|
+
db.players.save(@player).should be_true
|
90
90
|
mission2 = Player::Mission.new
|
91
91
|
@player.missions << mission2
|
92
|
-
mission2.should_receive(:before_create).once
|
92
|
+
mission2.should_receive(:before_create).once.and_return(true)
|
93
93
|
mission2.should_not_receive(:before_update)
|
94
|
-
db.players.save
|
94
|
+
db.players.save(@player).should be_true
|
95
95
|
end
|
96
96
|
end
|
97
97
|
end
|
data/spec/object/crud_spec.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'object/spec_helper'
|
2
|
-
require 'object/crud_shared'
|
2
|
+
require 'mongo/object/spec/crud_shared'
|
3
3
|
|
4
4
|
describe "Object CRUD" do
|
5
5
|
with_mongo
|
@@ -7,6 +7,8 @@ describe "Object CRUD" do
|
|
7
7
|
describe 'simple' do
|
8
8
|
before :all do
|
9
9
|
class Unit2
|
10
|
+
include Mongo::Object
|
11
|
+
|
10
12
|
def initialize name = nil, info = nil; @name, @info = name, info end
|
11
13
|
attr_accessor :name, :info
|
12
14
|
def == o; [self.class, name, info] == [o.class, o.respond_to(:name), o.respond_to(:info)] end
|
@@ -29,10 +31,14 @@ describe "Object CRUD" do
|
|
29
31
|
describe 'embedded' do
|
30
32
|
before :all do
|
31
33
|
class Player2
|
34
|
+
include Mongo::Object
|
35
|
+
|
32
36
|
attr_accessor :missions
|
33
37
|
def == o; [self.class, self.missions] == [o.class, o.respond_to(:missions)] end
|
34
38
|
|
35
39
|
class Mission
|
40
|
+
include Mongo::Object
|
41
|
+
|
36
42
|
def initialize name = nil, stats = nil; @name, @stats = name, stats end
|
37
43
|
attr_accessor :name, :stats
|
38
44
|
def == o; [self.class, self.name, self.stats] == [o.class, o.respond_to(:name), o.respond_to(:stats)] end
|
data/spec/object/spec_helper.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
require '
|
2
|
-
|
1
|
+
require 'mongo/object'
|
2
|
+
|
3
|
+
require 'rspec_ext'
|
4
|
+
require 'mongo/object/spec'
|
3
5
|
|
4
|
-
|
5
|
-
Mongo::ObjectSerializer.send :const_set, :SKIP_IV_REGEXP, /^@_|^@mock_proxy/
|
6
|
-
Mongo::ObjectSerializer::SIMPLE_TYPES << RSpec::Mocks::Proxy
|
6
|
+
require 'driver/spec_helper'
|
7
7
|
|
8
8
|
# To simplify callback expectations
|
9
9
|
module RSpec::CallbackHelper
|
10
|
-
def
|
10
|
+
def run_callbacks type, method_name
|
11
11
|
callback_method_name = :"#{type}_#{method_name}"
|
12
|
-
|
12
|
+
respond_to?(callback_method_name) ? send(callback_method_name) : true
|
13
13
|
end
|
14
14
|
end
|
@@ -5,9 +5,12 @@ describe 'Object validation' do
|
|
5
5
|
|
6
6
|
before :all do
|
7
7
|
class Player
|
8
|
+
include Mongo::Object
|
9
|
+
|
8
10
|
attr_accessor :missions
|
9
11
|
|
10
12
|
class Mission
|
13
|
+
include Mongo::Object
|
11
14
|
end
|
12
15
|
end
|
13
16
|
end
|
@@ -21,56 +24,56 @@ describe 'Object validation' do
|
|
21
24
|
|
22
25
|
it 'should not save/update/destroy invalid objects' do
|
23
26
|
# create
|
24
|
-
@player.stub!(:
|
27
|
+
@player.stub!(:valid?).and_return(false)
|
25
28
|
db.players.save(@player).should be_false
|
26
29
|
|
27
|
-
@player.stub!(:
|
30
|
+
@player.stub!(:valid?).and_return(true)
|
28
31
|
db.players.save(@player).should be_true
|
29
32
|
|
30
33
|
# update
|
31
|
-
@player.stub!(:
|
34
|
+
@player.stub!(:valid?).and_return(false)
|
32
35
|
db.players.save(@player).should be_false
|
33
36
|
|
34
|
-
@player.stub!(:
|
37
|
+
@player.stub!(:valid?).and_return(true)
|
35
38
|
db.players.save(@player).should be_true
|
36
39
|
|
37
40
|
# destroy
|
38
|
-
@player.stub!(:
|
41
|
+
@player.stub!(:valid?).and_return(false)
|
39
42
|
db.players.destroy(@player).should be_false
|
40
43
|
|
41
|
-
@player.stub!(:
|
44
|
+
@player.stub!(:valid?).and_return(true)
|
42
45
|
db.players.destroy(@player).should be_true
|
43
46
|
end
|
44
47
|
|
45
48
|
it 'should not save/update/destroy invalid embedded objects' do
|
46
49
|
# create
|
47
|
-
@mission.stub!(:
|
50
|
+
@mission.stub!(:valid?).and_return(false)
|
48
51
|
db.players.save(@player).should be_false
|
49
52
|
|
50
|
-
@mission.stub!(:
|
53
|
+
@mission.stub!(:valid?).and_return(true)
|
51
54
|
db.players.save(@player).should be_true
|
52
55
|
|
53
56
|
# update
|
54
|
-
@mission.stub!(:
|
57
|
+
@mission.stub!(:valid?).and_return(false)
|
55
58
|
db.players.save(@player).should be_false
|
56
59
|
|
57
|
-
@mission.stub!(:
|
60
|
+
@mission.stub!(:valid?).and_return(true)
|
58
61
|
db.players.save(@player).should be_true
|
59
62
|
|
60
63
|
# destroy
|
61
|
-
@mission.stub!(:
|
64
|
+
@mission.stub!(:valid?).and_return(false)
|
62
65
|
db.players.destroy(@player).should be_false
|
63
66
|
|
64
|
-
@mission.stub!(:
|
67
|
+
@mission.stub!(:valid?).and_return(true)
|
65
68
|
db.players.destroy(@player).should be_true
|
66
69
|
end
|
67
70
|
|
68
71
|
it "should be able skip validation" do
|
69
|
-
@player.stub!(:
|
72
|
+
@player.stub!(:valid?).and_return(false)
|
70
73
|
db.players.save(@player, validate: false).should be_true
|
71
74
|
|
72
|
-
@player.stub!(:
|
73
|
-
@mission.stub!(:
|
75
|
+
@player.stub!(:valid?).and_return(true)
|
76
|
+
@mission.stub!(:valid?).and_return(false)
|
74
77
|
db.players.save(@player, validate: false).should be_true
|
75
78
|
end
|
76
79
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongodb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,19 +9,8 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-08-
|
13
|
-
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: mongo
|
16
|
-
requirement: &2820900 !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ~>
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '1.3'
|
22
|
-
type: :runtime
|
23
|
-
prerelease: false
|
24
|
-
version_requirements: *2820900
|
12
|
+
date: 2011-08-30 00:00:00.000000000Z
|
13
|
+
dependencies: []
|
25
14
|
description:
|
26
15
|
email:
|
27
16
|
executables: []
|
@@ -30,19 +19,21 @@ extra_rdoc_files: []
|
|
30
19
|
files:
|
31
20
|
- Rakefile
|
32
21
|
- readme.md
|
33
|
-
- lib/
|
34
|
-
- lib/
|
35
|
-
- lib/
|
36
|
-
- lib/
|
37
|
-
- lib/
|
38
|
-
- lib/
|
39
|
-
- lib/
|
40
|
-
- lib/
|
41
|
-
- lib/
|
42
|
-
- lib/
|
43
|
-
- lib/
|
44
|
-
- lib/
|
45
|
-
- lib/
|
22
|
+
- lib/mongo/driver/collection.rb
|
23
|
+
- lib/mongo/driver/database.rb
|
24
|
+
- lib/mongo/driver/dynamic_finders.rb
|
25
|
+
- lib/mongo/driver/spec.rb
|
26
|
+
- lib/mongo/driver.rb
|
27
|
+
- lib/mongo/gems.rb
|
28
|
+
- lib/mongo/migration/definition.rb
|
29
|
+
- lib/mongo/migration/migration.rb
|
30
|
+
- lib/mongo/migration/tasks.rb
|
31
|
+
- lib/mongo/migration.rb
|
32
|
+
- lib/mongo/object/object.rb
|
33
|
+
- lib/mongo/object/object_helper.rb
|
34
|
+
- lib/mongo/object/spec/crud_shared.rb
|
35
|
+
- lib/mongo/object/spec.rb
|
36
|
+
- lib/mongo/object.rb
|
46
37
|
- spec/driver/collection_spec.rb
|
47
38
|
- spec/driver/crud_spec.rb
|
48
39
|
- spec/driver/database_spec.rb
|
@@ -52,7 +43,6 @@ files:
|
|
52
43
|
- spec/driver/spec_helper.rb
|
53
44
|
- spec/migration/migration_spec.rb
|
54
45
|
- spec/object/callbacks_spec.rb
|
55
|
-
- spec/object/crud_shared.rb
|
56
46
|
- spec/object/crud_spec.rb
|
57
47
|
- spec/object/spec_helper.rb
|
58
48
|
- spec/object/validation_spec.rb
|
data/lib/mongodb/migration.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
module Mongo::ObjectHelper
|
2
|
-
#
|
3
|
-
# CRUD
|
4
|
-
#
|
5
|
-
def save_with_object doc, opts = {}
|
6
|
-
if doc.is_a? Hash
|
7
|
-
save_without_object doc, opts
|
8
|
-
else
|
9
|
-
::Mongo::ObjectSerializer.new(doc).save opts, self
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def insert_with_object args, opts = {}
|
14
|
-
if args.is_a?(Hash) or args.is_a?(Array)
|
15
|
-
insert_without_object args, opts
|
16
|
-
else
|
17
|
-
::Mongo::ObjectSerializer.new(args).insert opts, self
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def update_with_object selector, doc, opts = {}
|
22
|
-
if doc.is_a?(Hash)
|
23
|
-
update_without_object selector, doc, opts
|
24
|
-
else
|
25
|
-
raise "can't use update selector with object (#{selector}, {#{doc}})!" unless selector == nil
|
26
|
-
::Mongo::ObjectSerializer.new(doc).update opts, self
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def remove_with_object arg = {}, opts = {}
|
31
|
-
if arg.is_a? Hash
|
32
|
-
remove_without_object arg, opts
|
33
|
-
else
|
34
|
-
::Mongo::ObjectSerializer.new(arg).remove opts, self
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def save! doc, opts = {}
|
39
|
-
save(doc, opts) || raise(Mongo::Error, "can't save #{doc.inspect}!")
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
#
|
44
|
-
# Querying
|
45
|
-
#
|
46
|
-
def first selector = {}, opts = {}, &block
|
47
|
-
opts = opts.clone
|
48
|
-
object = (opts.delete(:object) == false) ? false : true
|
49
|
-
doc = super selector, opts, &block
|
50
|
-
object ? ::Mongo::ObjectSerializer.build(doc) : doc
|
51
|
-
end
|
52
|
-
|
53
|
-
def each selector = {}, opts = {}, &block
|
54
|
-
opts = opts.clone
|
55
|
-
object = (opts.delete(:object) == false) ? false : true
|
56
|
-
super selector, opts do |doc|
|
57
|
-
doc = ::Mongo::ObjectSerializer.build(doc) if object
|
58
|
-
block.call doc
|
59
|
-
end
|
60
|
-
nil
|
61
|
-
end
|
62
|
-
end
|
@@ -1,273 +0,0 @@
|
|
1
|
-
class Mongo::ObjectSerializer
|
2
|
-
SIMPLE_TYPES = [
|
3
|
-
Fixnum, Float,
|
4
|
-
TrueClass, FalseClass,
|
5
|
-
String, Symbol,
|
6
|
-
Array, Hash, Set,
|
7
|
-
Data, DateTime,
|
8
|
-
NilClass, Time,
|
9
|
-
BSON::ObjectId
|
10
|
-
].to_set
|
11
|
-
|
12
|
-
attr_reader :object
|
13
|
-
|
14
|
-
def initialize object
|
15
|
-
@object = object
|
16
|
-
end
|
17
|
-
|
18
|
-
def save opts, collection
|
19
|
-
if _id
|
20
|
-
self.update opts.merge(upsert: true), collection
|
21
|
-
else
|
22
|
-
self.insert opts, collection
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def insert opts, collection
|
27
|
-
opts, validate, callbacks = parse_object_options opts
|
28
|
-
|
29
|
-
# before callbacks
|
30
|
-
return false if callbacks and !run_callbacks(objects, [:before, :validate], [:before, :save], [:before, :create])
|
31
|
-
|
32
|
-
# validation
|
33
|
-
return false if validate and !valid?
|
34
|
-
|
35
|
-
# saving document
|
36
|
-
doc = to_document
|
37
|
-
collection.insert_without_object doc, opts
|
38
|
-
id = doc[:_id] || doc['_id'] || raise("internal error: no id after document insertion (#{doc})!")
|
39
|
-
object.instance_variable_set :@_id, id
|
40
|
-
update_internal_state!
|
41
|
-
|
42
|
-
# after callbacks
|
43
|
-
run_callbacks(objects, [:after, :create], [:after, :save], [:after, :validate]) if callbacks
|
44
|
-
|
45
|
-
true
|
46
|
-
end
|
47
|
-
|
48
|
-
def update opts, collection
|
49
|
-
opts, validate, callbacks = parse_object_options opts
|
50
|
-
|
51
|
-
# before callbacks.
|
52
|
-
# we need to sort out embedded objects into created, updated and destroyed
|
53
|
-
created_objects, updated_objects, destroyed_objects = [], [], []
|
54
|
-
if callbacks
|
55
|
-
original_ids = original_objects.collect{|obj| obj.object_id}.to_set
|
56
|
-
objects.each do |obj|
|
57
|
-
(original_ids.include?(obj.object_id) ? updated_objects : created_objects) << obj
|
58
|
-
end
|
59
|
-
|
60
|
-
objects_ids = objects.collect{|obj| obj.object_id}.to_set
|
61
|
-
destroyed_objects = original_objects.select{|obj| !objects_ids.include?(obj.object_id)}
|
62
|
-
|
63
|
-
all_successfull = [
|
64
|
-
run_callbacks(created_objects, [:before, :validate], [:before, :save], [:before, :create]),
|
65
|
-
run_callbacks(updated_objects, [:before, :validate], [:before, :save], [:before, :update]),
|
66
|
-
run_callbacks(destroyed_objects, [:before, :validate], [:before, :destroy])
|
67
|
-
].reduce(:&)
|
68
|
-
|
69
|
-
return false unless all_successfull
|
70
|
-
end
|
71
|
-
|
72
|
-
# validation
|
73
|
-
return false if validate and !valid?
|
74
|
-
|
75
|
-
# saving document
|
76
|
-
doc = to_document
|
77
|
-
id = _id || raise("can't update document without id (#{doc})!")
|
78
|
-
collection.update_without_object({_id: id}, doc, opts)
|
79
|
-
update_internal_state!
|
80
|
-
|
81
|
-
# after callbacks
|
82
|
-
if callbacks
|
83
|
-
run_callbacks(created_objects, [:after, :create], [:after, :save], [:after, :validate])
|
84
|
-
run_callbacks(updated_objects, [:after, :update], [:after, :save], [:after, :validate])
|
85
|
-
run_callbacks(destroyed_objects, [:after, :destroy], [:after, :validate])
|
86
|
-
end
|
87
|
-
|
88
|
-
true
|
89
|
-
end
|
90
|
-
|
91
|
-
def remove opts, collection
|
92
|
-
opts, validate, callbacks = parse_object_options opts
|
93
|
-
|
94
|
-
# before callbacks
|
95
|
-
if callbacks
|
96
|
-
# we need to run :destroy callbacks also on detached embedded objects.
|
97
|
-
all_objects = (objects + original_objects).uniq{|o| o.object_id}
|
98
|
-
return false unless run_callbacks(all_objects, [:before, :validate], [:before, :destroy])
|
99
|
-
end
|
100
|
-
|
101
|
-
# validation
|
102
|
-
return false if validate and !valid?
|
103
|
-
|
104
|
-
# saving document
|
105
|
-
id = _id || "can't destroy object without _id (#{arg})!"
|
106
|
-
collection.remove_without_object({_id: id}, opts)
|
107
|
-
update_internal_state!
|
108
|
-
|
109
|
-
# after callbacks
|
110
|
-
run_callbacks(objects, [:after, :destroy], [:after, :validate]) if callbacks
|
111
|
-
|
112
|
-
true
|
113
|
-
end
|
114
|
-
|
115
|
-
def to_document
|
116
|
-
_to_document object
|
117
|
-
end
|
118
|
-
|
119
|
-
def _id
|
120
|
-
object.instance_variable_get(:@_id)
|
121
|
-
end
|
122
|
-
|
123
|
-
def valid?
|
124
|
-
objects.each do |obj|
|
125
|
-
return false if obj.respond_to?(:_valid?) and !obj._valid?
|
126
|
-
end
|
127
|
-
true
|
128
|
-
end
|
129
|
-
|
130
|
-
def run_callbacks objects, *callbacks
|
131
|
-
callbacks.each do |type, method_name|
|
132
|
-
objects.each do |obj|
|
133
|
-
if obj.respond_to? :_run_callbacks
|
134
|
-
return false if obj._run_callbacks(type, method_name) == false
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
true
|
139
|
-
end
|
140
|
-
|
141
|
-
def objects
|
142
|
-
@objects_cache ||= begin
|
143
|
-
objects = []
|
144
|
-
_each_object(object){|obj| objects << obj}
|
145
|
-
objects
|
146
|
-
end
|
147
|
-
end
|
148
|
-
|
149
|
-
def update_internal_state!
|
150
|
-
self.original_objects = objects if Mongo.defaults[:callbacks]
|
151
|
-
end
|
152
|
-
|
153
|
-
protected
|
154
|
-
def original_objects; object.instance_variable_get(:@_original_objects) end
|
155
|
-
def original_objects= objects; object.instance_variable_set(:@_original_objects, objects) end
|
156
|
-
|
157
|
-
def parse_object_options opts
|
158
|
-
opts = opts.clone
|
159
|
-
validate = opts.delete(:validate) == false ? false : true
|
160
|
-
callbacks = opts.delete(:callbacks) == false ? false : Mongo.defaults[:callbacks]
|
161
|
-
return opts, validate, callbacks
|
162
|
-
end
|
163
|
-
|
164
|
-
# need this to allow change it in specs
|
165
|
-
# RSpec adds @mock_proxy, and we need to skip it
|
166
|
-
SKIP_IV_REGEXP = /^@_/
|
167
|
-
|
168
|
-
def _each_instance_variable obj, &block
|
169
|
-
obj.instance_variables.each do |iv_name|
|
170
|
-
# skipping variables starting with _xx, usually they
|
171
|
-
# have specific meaning and used for example for cache
|
172
|
-
next if iv_name =~ SKIP_IV_REGEXP
|
173
|
-
|
174
|
-
block.call iv_name, obj.instance_variable_get(iv_name)
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
# converts object to document (also works with nested & arrays)
|
179
|
-
def _to_document obj
|
180
|
-
return obj.to_mongo if obj.respond_to? :to_mongo
|
181
|
-
|
182
|
-
if obj.is_a? Hash
|
183
|
-
doc = {}
|
184
|
-
obj.each do |k, v|
|
185
|
-
doc[k] = _to_document v
|
186
|
-
end
|
187
|
-
doc
|
188
|
-
elsif obj.is_a? Array
|
189
|
-
obj.collect{|v| _to_document v}
|
190
|
-
elsif SIMPLE_TYPES.include? obj.class
|
191
|
-
obj
|
192
|
-
else
|
193
|
-
doc = {}
|
194
|
-
|
195
|
-
# copying instance variables
|
196
|
-
_each_instance_variable obj do |iv_name, v|
|
197
|
-
k = iv_name.to_s[1..-1]
|
198
|
-
k = k.to_sym if Mongo.defaults[:symbolize]
|
199
|
-
doc[k] = _to_document v
|
200
|
-
end
|
201
|
-
|
202
|
-
# adding _id & _class
|
203
|
-
id_key, class_key = Mongo.defaults[:symbolize] ? [:_id, :_class] : ['_id', '_class']
|
204
|
-
id = instance_variable_get('@_id')
|
205
|
-
doc[id_key] = id if id
|
206
|
-
doc[class_key] = obj.class.name
|
207
|
-
|
208
|
-
doc
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
def _each_object obj, &block
|
213
|
-
if obj.is_a? Hash
|
214
|
-
obj.each{|k, v| _each_object v, &block}
|
215
|
-
elsif obj.is_a? Array
|
216
|
-
obj.each{|v| _each_object v, &block}
|
217
|
-
elsif SIMPLE_TYPES.include? obj.class
|
218
|
-
else
|
219
|
-
block.call obj
|
220
|
-
_each_instance_variable obj do |iv_name, v|
|
221
|
-
_each_object v, &block
|
222
|
-
end
|
223
|
-
end
|
224
|
-
nil
|
225
|
-
end
|
226
|
-
|
227
|
-
|
228
|
-
class << self
|
229
|
-
def build doc
|
230
|
-
obj = _build doc
|
231
|
-
serializer = Mongo::ObjectSerializer.new obj
|
232
|
-
serializer.update_internal_state!
|
233
|
-
obj
|
234
|
-
end
|
235
|
-
|
236
|
-
protected
|
237
|
-
def _build doc
|
238
|
-
if doc.is_a? Hash
|
239
|
-
if class_name = doc[:_class] || doc['_class']
|
240
|
-
klass = constantize class_name
|
241
|
-
|
242
|
-
if klass.respond_to? :to_object
|
243
|
-
klass.to_object doc
|
244
|
-
else
|
245
|
-
obj = klass.new
|
246
|
-
doc.each do |k, v|
|
247
|
-
next if k.to_sym == :_class
|
248
|
-
|
249
|
-
v = _build v
|
250
|
-
obj.instance_variable_set "@#{k}", v
|
251
|
-
end
|
252
|
-
obj
|
253
|
-
end
|
254
|
-
else
|
255
|
-
doc
|
256
|
-
end
|
257
|
-
elsif doc.is_a? Array
|
258
|
-
doc.collect{|v| _build v}
|
259
|
-
else
|
260
|
-
doc
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
def constantize class_name
|
265
|
-
@constantize_cache ||= {}
|
266
|
-
unless klass = @constantize_cache[class_name]
|
267
|
-
klass = eval class_name, TOPLEVEL_BINDING, __FILE__, __LINE__
|
268
|
-
@constantize_cache[class_name] = klass
|
269
|
-
end
|
270
|
-
klass
|
271
|
-
end
|
272
|
-
end
|
273
|
-
end
|