mongo_mapper 0.6.10 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. data/README.rdoc +5 -14
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/lib/mongo_mapper.rb +48 -56
  5. data/lib/mongo_mapper/document.rb +136 -164
  6. data/lib/mongo_mapper/embedded_document.rb +29 -354
  7. data/lib/mongo_mapper/plugins.rb +31 -0
  8. data/lib/mongo_mapper/plugins/associations.rb +105 -0
  9. data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
  10. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  11. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  12. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  13. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
  14. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  15. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  16. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  17. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  18. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  19. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  20. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  21. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  22. data/lib/mongo_mapper/plugins/callbacks.rb +65 -0
  23. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  24. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  25. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  26. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  27. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  28. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  29. data/lib/mongo_mapper/plugins/keys.rb +324 -0
  30. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  31. data/lib/mongo_mapper/plugins/pagination.rb +24 -0
  32. data/lib/mongo_mapper/plugins/pagination/proxy.rb +68 -0
  33. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  34. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  35. data/lib/mongo_mapper/plugins/serialization.rb +105 -0
  36. data/lib/mongo_mapper/plugins/validations.rb +46 -0
  37. data/lib/mongo_mapper/query.rb +130 -0
  38. data/lib/mongo_mapper/support.rb +40 -17
  39. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  40. data/lib/mongo_mapper/support/find.rb +77 -0
  41. data/mongo_mapper.gemspec +55 -38
  42. data/performance/read_write.rb +52 -0
  43. data/specs.watchr +23 -2
  44. data/test/functional/associations/test_belongs_to_proxy.rb +12 -10
  45. data/test/functional/associations/test_many_documents_as_proxy.rb +4 -21
  46. data/test/functional/associations/test_many_documents_proxy.rb +2 -8
  47. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +59 -39
  48. data/test/functional/associations/test_many_embedded_proxy.rb +145 -81
  49. data/test/functional/associations/test_many_polymorphic_proxy.rb +2 -40
  50. data/test/functional/associations/test_one_proxy.rb +25 -10
  51. data/test/functional/test_binary.rb +2 -8
  52. data/test/functional/test_callbacks.rb +1 -5
  53. data/test/functional/test_dirty.rb +27 -23
  54. data/test/functional/test_document.rb +224 -165
  55. data/test/functional/test_embedded_document.rb +72 -82
  56. data/test/functional/test_identity_map.rb +508 -0
  57. data/test/functional/test_modifiers.rb +15 -5
  58. data/test/functional/test_pagination.rb +1 -3
  59. data/test/functional/test_protected.rb +155 -0
  60. data/test/functional/test_string_id_compatibility.rb +7 -12
  61. data/test/functional/test_validations.rb +26 -58
  62. data/test/models.rb +0 -39
  63. data/test/test_helper.rb +37 -3
  64. data/test/unit/associations/test_base.rb +5 -5
  65. data/test/unit/associations/test_proxy.rb +8 -6
  66. data/test/unit/test_descendant_appends.rb +71 -0
  67. data/test/unit/test_document.rb +71 -76
  68. data/test/unit/test_dynamic_finder.rb +27 -29
  69. data/test/unit/test_embedded_document.rb +555 -601
  70. data/test/unit/{test_key.rb → test_keys.rb} +2 -5
  71. data/test/unit/test_mongo_mapper.rb +69 -9
  72. data/test/unit/test_pagination.rb +40 -32
  73. data/test/unit/test_plugins.rb +50 -0
  74. data/test/unit/{test_finder_options.rb → test_query.rb} +74 -65
  75. data/test/unit/test_rails.rb +123 -0
  76. data/test/unit/{test_serializations.rb → test_serialization.rb} +1 -2
  77. data/test/unit/test_support.rb +23 -7
  78. data/test/unit/test_time_zones.rb +3 -4
  79. data/test/unit/test_validations.rb +58 -17
  80. metadata +53 -36
  81. data/lib/mongo_mapper/associations.rb +0 -78
  82. data/lib/mongo_mapper/associations/base.rb +0 -119
  83. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +0 -26
  84. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +0 -21
  85. data/lib/mongo_mapper/associations/collection.rb +0 -19
  86. data/lib/mongo_mapper/associations/in_array_proxy.rb +0 -137
  87. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +0 -26
  88. data/lib/mongo_mapper/associations/many_documents_proxy.rb +0 -115
  89. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +0 -31
  90. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +0 -54
  91. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +0 -11
  92. data/lib/mongo_mapper/associations/one_proxy.rb +0 -64
  93. data/lib/mongo_mapper/associations/proxy.rb +0 -116
  94. data/lib/mongo_mapper/callbacks.rb +0 -61
  95. data/lib/mongo_mapper/dirty.rb +0 -117
  96. data/lib/mongo_mapper/dynamic_finder.rb +0 -74
  97. data/lib/mongo_mapper/finder_options.rb +0 -145
  98. data/lib/mongo_mapper/key.rb +0 -36
  99. data/lib/mongo_mapper/mongo_mapper.rb +0 -125
  100. data/lib/mongo_mapper/pagination.rb +0 -66
  101. data/lib/mongo_mapper/rails_compatibility/document.rb +0 -15
  102. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +0 -28
  103. data/lib/mongo_mapper/serialization.rb +0 -54
  104. data/lib/mongo_mapper/serializers/json_serializer.rb +0 -48
  105. data/lib/mongo_mapper/validations.rb +0 -39
  106. data/test/functional/test_rails_compatibility.rb +0 -25
@@ -1,125 +1,123 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class DynamicFinderTest < Test::Unit::TestCase
4
- include MongoMapper
5
-
6
4
  should "initialize with method" do
7
- finder = DynamicFinder.new(:foobar)
5
+ finder = MongoMapper::Support::Find::DynamicFinder.new(:foobar)
8
6
  finder.method.should == :foobar
9
7
  end
10
8
 
11
9
  context "found?" do
12
10
  should "be true for find_by" do
13
- DynamicFinder.new(:find_by_foo).found?.should be_true
11
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo).found?.should be_true
14
12
  end
15
13
 
16
14
  should "be true for find_by with !" do
17
- DynamicFinder.new(:find_by_foo!).found?.should be_true
15
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo!).found?.should be_true
18
16
  end
19
17
 
20
18
  should "be true for find_all_by" do
21
- DynamicFinder.new(:find_all_by_foo).found?.should be_true
19
+ MongoMapper::Support::Find::DynamicFinder.new(:find_all_by_foo).found?.should be_true
22
20
  end
23
21
 
24
22
  should "be true for find_or_initialize_by" do
25
- DynamicFinder.new(:find_or_initialize_by_foo).found?.should be_true
23
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_initialize_by_foo).found?.should be_true
26
24
  end
27
25
 
28
26
  should "be true for find_or_create_by" do
29
- DynamicFinder.new(:find_or_create_by_foo).found?.should be_true
27
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_create_by_foo).found?.should be_true
30
28
  end
31
29
 
32
30
  should "be false for anything else" do
33
31
  [:foobar, :bazwick].each do |method|
34
- DynamicFinder.new(method).found?.should be_false
32
+ MongoMapper::Support::Find::DynamicFinder.new(method).found?.should be_false
35
33
  end
36
34
  end
37
35
  end
38
36
 
39
37
  context "find_all_by" do
40
38
  should "parse one attribute" do
41
- DynamicFinder.new(:find_all_by_foo).attributes.should == %w(foo)
39
+ MongoMapper::Support::Find::DynamicFinder.new(:find_all_by_foo).attributes.should == %w(foo)
42
40
  end
43
41
 
44
42
  should "parse multiple attributes" do
45
- DynamicFinder.new(:find_all_by_foo_and_bar).attributes.should == %w(foo bar)
46
- DynamicFinder.new(:find_all_by_foo_and_bar_and_baz).attributes.should == %w(foo bar baz)
43
+ MongoMapper::Support::Find::DynamicFinder.new(:find_all_by_foo_and_bar).attributes.should == %w(foo bar)
44
+ MongoMapper::Support::Find::DynamicFinder.new(:find_all_by_foo_and_bar_and_baz).attributes.should == %w(foo bar baz)
47
45
  end
48
46
 
49
47
  should "set finder to :all" do
50
- DynamicFinder.new(:find_all_by_foo_and_bar).finder.should == :all
48
+ MongoMapper::Support::Find::DynamicFinder.new(:find_all_by_foo_and_bar).finder.should == :all
51
49
  end
52
50
  end
53
51
 
54
52
  context "find_by" do
55
53
  should "parse one attribute" do
56
- DynamicFinder.new(:find_by_foo).attributes.should == %w(foo)
54
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo).attributes.should == %w(foo)
57
55
  end
58
56
 
59
57
  should "parse multiple attributes" do
60
- DynamicFinder.new(:find_by_foo_and_bar).attributes.should == %w(foo bar)
58
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo_and_bar).attributes.should == %w(foo bar)
61
59
  end
62
60
 
63
61
  should "set finder to :first" do
64
- DynamicFinder.new(:find_by_foo).finder.should == :first
62
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo).finder.should == :first
65
63
  end
66
64
 
67
65
  should "set bang to false" do
68
- DynamicFinder.new(:find_by_foo).bang.should be_false
66
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo).bang.should be_false
69
67
  end
70
68
  end
71
69
 
72
70
  context "find_by with !" do
73
71
  should "parse one attribute" do
74
- DynamicFinder.new(:find_by_foo!).attributes.should == %w(foo)
72
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo!).attributes.should == %w(foo)
75
73
  end
76
74
 
77
75
  should "parse multiple attributes" do
78
- DynamicFinder.new(:find_by_foo_and_bar!).attributes.should == %w(foo bar)
76
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo_and_bar!).attributes.should == %w(foo bar)
79
77
  end
80
78
 
81
79
  should "set finder to :first" do
82
- DynamicFinder.new(:find_by_foo!).finder.should == :first
80
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo!).finder.should == :first
83
81
  end
84
82
 
85
83
  should "set bang to true" do
86
- DynamicFinder.new(:find_by_foo!).bang.should be_true
84
+ MongoMapper::Support::Find::DynamicFinder.new(:find_by_foo!).bang.should be_true
87
85
  end
88
86
  end
89
87
 
90
88
  context "find_or_initialize_by" do
91
89
  should "parse one attribute" do
92
- DynamicFinder.new(:find_or_initialize_by_foo).attributes.should == %w(foo)
90
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_initialize_by_foo).attributes.should == %w(foo)
93
91
  end
94
92
 
95
93
  should "parse multiple attributes" do
96
- DynamicFinder.new(:find_or_initialize_by_foo_and_bar).attributes.should == %w(foo bar)
94
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_initialize_by_foo_and_bar).attributes.should == %w(foo bar)
97
95
  end
98
96
 
99
97
  should "set finder to :first" do
100
- DynamicFinder.new(:find_or_initialize_by_foo).finder.should == :first
98
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_initialize_by_foo).finder.should == :first
101
99
  end
102
100
 
103
101
  should "set instantiator to new" do
104
- DynamicFinder.new(:find_or_initialize_by_foo).instantiator.should == :new
102
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_initialize_by_foo).instantiator.should == :new
105
103
  end
106
104
  end
107
105
 
108
106
  context "find_or_create_by" do
109
107
  should "parse one attribute" do
110
- DynamicFinder.new(:find_or_create_by_foo).attributes.should == %w(foo)
108
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_create_by_foo).attributes.should == %w(foo)
111
109
  end
112
110
 
113
111
  should "parse multiple attributes" do
114
- DynamicFinder.new(:find_or_create_by_foo_and_bar).attributes.should == %w(foo bar)
112
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_create_by_foo_and_bar).attributes.should == %w(foo bar)
115
113
  end
116
114
 
117
115
  should "set finder to :first" do
118
- DynamicFinder.new(:find_or_create_by_foo).finder.should == :first
116
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_create_by_foo).finder.should == :first
119
117
  end
120
118
 
121
119
  should "set instantiator to new" do
122
- DynamicFinder.new(:find_or_create_by_foo).instantiator.should == :create
120
+ MongoMapper::Support::Find::DynamicFinder.new(:find_or_create_by_foo).instantiator.should == :create
123
121
  end
124
122
  end
125
123
  end
@@ -1,709 +1,663 @@
1
1
  require 'test_helper'
2
2
 
3
- class Grandparent
4
- include MongoMapper::EmbeddedDocument
5
- key :grandparent, String
6
- end
7
-
8
- class Parent < Grandparent
9
- include MongoMapper::EmbeddedDocument
10
- key :parent, String
11
- end
12
-
13
- class Child < Parent
14
- include MongoMapper::EmbeddedDocument
15
- key :child, String
16
- end
17
-
18
3
  module KeyOverride
19
4
  def other_child
20
- read_attribute(:other_child) || "special result"
5
+ self[:other_child] || "special result"
21
6
  end
22
-
7
+
23
8
  def other_child=(value)
24
9
  super(value + " modified")
25
10
  end
26
11
  end
27
12
 
28
- class OtherChild < Parent
29
- include MongoMapper::EmbeddedDocument
30
- include KeyOverride
31
-
32
- key :other_child, String
33
- end
34
-
35
- class EmbeddedDocumentTest < Test::Unit::TestCase
36
- context "Including MongoMapper::EmbeddedDocument in a class" do
13
+ class EmbeddedDocumentTest < Test::Unit::TestCase
14
+ context "" do
37
15
  setup do
38
- @klass = Class.new do
16
+ class ::Grandparent
39
17
  include MongoMapper::EmbeddedDocument
18
+ key :grandparent, String
40
19
  end
41
- end
42
-
43
- should "give class access to logger" do
44
- @klass.logger.should == MongoMapper.logger
45
- @klass.logger.should be_instance_of(Logger)
46
- end
47
-
48
- should "add _id key" do
49
- @klass.keys['_id'].should_not be_nil
50
- end
51
-
52
- should "know it is using object id" do
53
- @klass.using_object_id?.should be_true
54
- end
55
-
56
- should "know it is not using object id if _id type is changed" do
57
- @klass.key :_id, String
58
- @klass.using_object_id?.should be_false
59
- end
60
-
61
- context "#to_mongo" do
62
- should "be nil if nil" do
63
- @klass.to_mongo(nil).should be_nil
64
- end
65
-
66
- should "convert to_mongo for other values" do
67
- doc = @klass.new(:foo => 'bar')
68
- to_mongo = @klass.to_mongo(doc)
69
- to_mongo.is_a?(Hash).should be_true
70
- to_mongo['foo'].should == 'bar'
71
- end
72
- end
73
-
74
- context "#from_mongo" do
75
- should "be nil if nil" do
76
- @klass.from_mongo(nil).should be_nil
77
- end
78
-
79
- should "be instance if instance of class" do
80
- doc = @klass.new
81
- @klass.from_mongo(doc).should == doc
82
- end
83
-
84
- should "be instance if hash of attributes" do
85
- doc = @klass.from_mongo({:foo => 'bar'})
86
- doc.instance_of?(@klass).should be_true
87
- doc.foo.should == 'bar'
88
- end
89
- end
90
- end
91
-
92
- context "looking up type constants" do
93
- should "not raise an error" do
94
- klass = Class.new do
95
- include MongoMapper::EmbeddedDocument
96
- key :file, Binary
97
- end
98
- end
99
- end
100
-
101
- context "parent_model" do
102
- should "be nil if none of parents ancestors include EmbeddedDocument" do
103
- parent = Class.new
104
- document = Class.new(parent) do
105
- include MongoMapper::EmbeddedDocument
106
- end
107
- document.parent_model.should be_nil
108
- end
109
20
 
110
- should "work when other modules have been included" do
111
- grandparent = Class.new
112
- parent = Class.new grandparent do
21
+ class ::Parent < ::Grandparent
113
22
  include MongoMapper::EmbeddedDocument
23
+ key :parent, String
114
24
  end
115
-
116
- example_module = Module.new
117
- document = Class.new(parent) do
118
- include MongoMapper::EmbeddedDocument
119
- include example_module
120
- end
121
-
122
- document.parent_model.should == parent
123
- end
124
-
125
- should "find parent" do
126
- Parent.parent_model.should == Grandparent
127
- Child.parent_model.should == Parent
128
- end
129
- end
130
-
131
- context "defining a key" do
132
- setup do
133
- @document = Class.new do
25
+
26
+ class ::Child < ::Parent
134
27
  include MongoMapper::EmbeddedDocument
28
+ key :child, String
135
29
  end
136
- end
137
-
138
- should "work with name" do
139
- key = @document.key(:name)
140
- key.name.should == 'name'
141
- end
142
-
143
- should "work with name and type" do
144
- key = @document.key(:name, String)
145
- key.name.should == 'name'
146
- key.type.should == String
147
- end
148
-
149
- should "work with name, type and options" do
150
- key = @document.key(:name, String, :required => true)
151
- key.name.should == 'name'
152
- key.type.should == String
153
- key.options[:required].should be_true
154
- end
155
-
156
- should "work with name and options" do
157
- key = @document.key(:name, :required => true)
158
- key.name.should == 'name'
159
- key.options[:required].should be_true
160
- end
161
-
162
- should "be tracked per document" do
163
- @document.key(:name, String)
164
- @document.key(:age, Integer)
165
- @document.keys['name'].name.should == 'name'
166
- @document.keys['name'].type.should == String
167
- @document.keys['age'].name.should == 'age'
168
- @document.keys['age'].type.should == Integer
169
- end
170
-
171
- should "be redefinable" do
172
- @document.key(:foo, String)
173
- @document.keys['foo'].type.should == String
174
- @document.key(:foo, Integer)
175
- @document.keys['foo'].type.should == Integer
176
- end
177
-
178
- should "create reader method" do
179
- @document.new.should_not respond_to(:foo)
180
- @document.key(:foo, String)
181
- @document.new.should respond_to(:foo)
182
- end
183
-
184
- should "create reader before typecast method" do
185
- @document.new.should_not respond_to(:foo_before_typecast)
186
- @document.key(:foo, String)
187
- @document.new.should respond_to(:foo_before_typecast)
188
- end
189
-
190
- should "create writer method" do
191
- @document.new.should_not respond_to(:foo=)
192
- @document.key(:foo, String)
193
- @document.new.should respond_to(:foo=)
194
- end
195
-
196
- should "create boolean method" do
197
- @document.new.should_not respond_to(:foo?)
198
- @document.key(:foo, String)
199
- @document.new.should respond_to(:foo?)
200
- end
201
- end
202
-
203
- context "keys" do
204
- should "be inherited" do
205
- Grandparent.keys.keys.sort.should == ['_id', 'grandparent']
206
- Parent.keys.keys.sort.should == ['_id', 'grandparent', 'parent']
207
- Child.keys.keys.sort.should == ['_id', 'child', 'grandparent', 'parent']
208
- end
209
-
210
- should "propogate to subclasses if key added after class definition" do
211
- Grandparent.key :_type, String
212
-
213
- Grandparent.keys.keys.sort.should == ['_id', '_type', 'grandparent']
214
- Parent.keys.keys.sort.should == ['_id', '_type', 'grandparent', 'parent']
215
- Child.keys.keys.sort.should == ['_id', '_type', 'child', 'grandparent', 'parent']
216
- end
217
-
218
- should "not add anonymous objects to the ancestor tree" do
219
- OtherChild.ancestors.any? { |a| a.name.blank? }.should be_false
220
- end
221
30
 
222
- should "not include descendant keys" do
223
- lambda { Parent.new.other_child }.should raise_error
224
- end
225
- end
31
+ class ::OtherChild < ::Parent
32
+ include MongoMapper::EmbeddedDocument
33
+ include KeyOverride
226
34
 
227
- context "#inspect" do
228
- setup do
229
- @document = Class.new do
230
- include MongoMapper::Document
231
- key :animals
35
+ key :other_child, String
232
36
  end
233
37
  end
234
38
 
235
- should "call inspect on the document's attributes instead of to_s" do
236
- doc = @document.new
237
- doc.animals = %w(dog cat)
238
- doc.inspect.should include(%(animals: ["dog", "cat"]))
239
- end
240
- end
241
-
242
- context "subclasses" do
243
- should "default to nil" do
244
- Child.subclasses.should be_nil
245
- end
246
-
247
- should "be recorded" do
248
- Grandparent.subclasses.should == [Parent]
249
- Parent.subclasses.should == [Child, OtherChild]
250
- end
251
- end
252
-
253
- context "Applying default values for keys" do
254
- setup do
255
- @document = Class.new do
256
- include MongoMapper::EmbeddedDocument
257
-
258
- key :name, String, :default => 'foo'
259
- key :age, Integer, :default => 20
260
- key :net_worth, Float, :default => 100.00
261
- key :active, Boolean, :default => true
262
- key :smart, Boolean, :default => false
263
- key :skills, Array, :default => [1]
264
- key :options, Hash, :default => {'foo' => 'bar'}
265
- end
266
-
267
- @doc = @document.new
268
- end
269
-
270
- should "work for strings" do
271
- @doc.name.should == 'foo'
272
- end
273
-
274
- should "work for integers" do
275
- @doc.age.should == 20
276
- end
277
-
278
- should "work for floats" do
279
- @doc.net_worth.should == 100.00
39
+ teardown do
40
+ Object.send :remove_const, 'Grandparent' if defined?(::Grandparent)
41
+ Object.send :remove_const, 'Parent' if defined?(::Parent)
42
+ Object.send :remove_const, 'Child' if defined?(::Child)
43
+ Object.send :remove_const, 'OtherChild' if defined?(::OtherChild)
280
44
  end
281
45
 
282
- should "work for booleans" do
283
- @doc.active.should == true
284
- @doc.smart.should == false
285
- end
286
-
287
- should "work for arrays" do
288
- @doc.skills.should == [1]
289
- @doc.skills << 2
290
- @doc.skills.should == [1, 2]
291
- end
292
-
293
- should "work for hashes" do
294
- @doc.options['foo'].should == 'bar'
295
- @doc.options['baz'] = 'wick'
296
- @doc.options['baz'].should == 'wick'
297
- end
298
- end
299
-
300
- context "An instance of an embedded document" do
301
- setup do
302
- @document = Class.new do
303
- include MongoMapper::EmbeddedDocument
46
+ context "Including MongoMapper::EmbeddedDocument in a class" do
47
+ setup do
48
+ @klass = EDoc()
49
+ end
304
50
 
305
- key :name, String
306
- key :age, Integer
51
+ should "add _id key" do
52
+ @klass.keys['_id'].should_not be_nil
307
53
  end
308
- end
309
-
310
- should "have to_param that is string representation of id" do
311
- doc = @document.new
312
- doc.to_param.should == doc.id.to_s
313
- doc.to_param.should be_instance_of(String)
314
- end
315
-
316
- should "have access to class logger" do
317
- doc = @document.new
318
- doc.logger.should == @document.logger
319
- doc.logger.should be_instance_of(Logger)
320
- end
321
-
322
- should "automatically have an _id key" do
323
- @document.keys.keys.should include('_id')
324
- end
325
-
326
- should "have id method returns _id" do
327
- id = Mongo::ObjectID.new
328
- doc = @document.new(:_id => id)
329
- doc.id.should == id
330
- end
331
-
332
- context "assigning id with _id ObjectId type" do
333
- should "not set custom id flag" do
334
- doc = @document.new
335
- doc.using_custom_id?.should be_false
336
- doc.id = Mongo::ObjectID.new
337
- doc.using_custom_id?.should be_false
54
+
55
+ should "know it is using object id" do
56
+ @klass.using_object_id?.should be_true
338
57
  end
339
-
340
- should "convert string object id to mongo object id" do
341
- id = Mongo::ObjectID.new
342
- doc = @document.new(:id => id.to_s)
343
- doc._id.should == id
344
- doc.id.should == id
345
- doc.using_custom_id?.should be_false
58
+
59
+ should "know it is not using object id if _id type is changed" do
60
+ @klass.key :_id, String
61
+ @klass.using_object_id?.should be_false
346
62
  end
347
63
  end
348
64
 
349
- context "setting custom id" do
350
- should "set _id" do
351
- @document.key :_id, String
352
- doc = @document.new(:id => '1234')
353
- doc._id.should == '1234'
65
+ context "Class Methods" do
66
+ should "include logger" do
67
+ @klass = EDoc()
68
+ @klass.logger.should == MongoMapper.logger
69
+ @klass.logger.should be_instance_of(Logger)
354
70
  end
355
-
356
- should "know that custom id is set" do
357
- @document.key :_id, String
358
- doc = @document.new
359
- doc.using_custom_id?.should be_false
360
- doc.id = '1234'
361
- doc.using_custom_id?.should be_true
71
+
72
+ should "return false for embeddable" do
73
+ EDoc().embeddable?.should be_true
362
74
  end
363
- end
364
75
 
365
- should "have a nil _root_document" do
366
- @document.new._root_document.should be_nil
367
- end
76
+ context "#to_mongo" do
77
+ setup { @klass = EDoc() }
368
78
 
369
- context "being initialized" do
370
- should "accept a hash that sets keys and values" do
371
- doc = @document.new(:name => 'John', :age => 23)
372
- doc.attributes.keys.sort.should == ['_id', 'age', 'name']
373
- doc.attributes['name'].should == 'John'
374
- doc.attributes['age'].should == 23
375
- end
376
-
377
- should "be able to assign keys dynamically" do
378
- doc = @document.new(:name => 'John', :skills => ['ruby', 'rails'])
379
- doc.name.should == 'John'
380
- doc.skills.should == ['ruby', 'rails']
79
+ should "be nil if nil" do
80
+ @klass.to_mongo(nil).should be_nil
81
+ end
82
+
83
+ should "convert to_mongo for other values" do
84
+ doc = @klass.new(:foo => 'bar')
85
+ to_mongo = @klass.to_mongo(doc)
86
+ to_mongo.is_a?(Hash).should be_true
87
+ to_mongo['foo'].should == 'bar'
88
+ end
381
89
  end
382
90
 
383
- should "set the root on embedded documents" do
384
- document = Class.new(@document) do
385
- many :children
91
+ context "#from_mongo" do
92
+ setup { @klass = EDoc() }
93
+
94
+ should "be nil if nil" do
95
+ @klass.from_mongo(nil).should be_nil
386
96
  end
387
97
 
388
- doc = document.new :_root_document => 'document', 'children' => [{}]
389
- doc.children.first._root_document.should == 'document'
390
- end
98
+ should "be instance if instance of class" do
99
+ doc = @klass.new
100
+ @klass.from_mongo(doc).should == doc
101
+ end
391
102
 
392
- should "not throw error if initialized with nil" do
393
- lambda {
394
- @document.new(nil)
395
- }.should_not raise_error
396
- end
397
- end
398
-
399
- context "initialized when _type key present" do
400
- setup do
401
- ::FooBar = Class.new do
402
- include MongoMapper::EmbeddedDocument
403
- key :_type, String
103
+ should "be instance if hash of attributes" do
104
+ doc = @klass.from_mongo({:foo => 'bar'})
105
+ doc.instance_of?(@klass).should be_true
106
+ doc.foo.should == 'bar'
404
107
  end
405
108
  end
406
-
407
- teardown do
408
- Object.send(:remove_const, :FooBar)
409
- end
410
109
 
411
- should "set _type to class name" do
412
- FooBar.new._type.should == 'FooBar'
413
- end
414
-
415
- should "not change _type if already set" do
416
- FooBar.new(:_type => 'Foo')._type.should == 'Foo'
417
- end
418
- end
110
+ context "defining a key" do
111
+ setup do
112
+ @document = EDoc()
113
+ end
419
114
 
420
- context "mass assigning keys" do
421
- should "update values for keys provided" do
422
- doc = @document.new(:name => 'foobar', :age => 10)
423
- doc.attributes = {:name => 'new value', :age => 5}
424
- doc.attributes[:name].should == 'new value'
425
- doc.attributes[:age].should == 5
426
- end
115
+ should "work with name" do
116
+ key = @document.key(:name)
117
+ key.name.should == 'name'
118
+ end
119
+
120
+ should "work with name and type" do
121
+ key = @document.key(:name, String)
122
+ key.name.should == 'name'
123
+ key.type.should == String
124
+ end
125
+
126
+ should "work with name, type and options" do
127
+ key = @document.key(:name, String, :required => true)
128
+ key.name.should == 'name'
129
+ key.type.should == String
130
+ key.options[:required].should be_true
131
+ end
132
+
133
+ should "work with name and options" do
134
+ key = @document.key(:name, :required => true)
135
+ key.name.should == 'name'
136
+ key.options[:required].should be_true
137
+ end
138
+
139
+ should "be tracked per document" do
140
+ @document.key(:name, String)
141
+ @document.key(:age, Integer)
142
+ @document.keys['name'].name.should == 'name'
143
+ @document.keys['name'].type.should == String
144
+ @document.keys['age'].name.should == 'age'
145
+ @document.keys['age'].type.should == Integer
146
+ end
147
+
148
+ should "be redefinable" do
149
+ @document.key(:foo, String)
150
+ @document.keys['foo'].type.should == String
151
+ @document.key(:foo, Integer)
152
+ @document.keys['foo'].type.should == Integer
153
+ end
154
+
155
+ should "create reader method" do
156
+ @document.new.should_not respond_to(:foo)
157
+ @document.key(:foo, String)
158
+ @document.new.should respond_to(:foo)
159
+ end
160
+
161
+ should "create reader before typecast method" do
162
+ @document.new.should_not respond_to(:foo_before_typecast)
163
+ @document.key(:foo, String)
164
+ @document.new.should respond_to(:foo_before_typecast)
165
+ end
427
166
 
428
- should "not update values for keys that were not provided" do
429
- doc = @document.new(:name => 'foobar', :age => 10)
430
- doc.attributes = {:name => 'new value'}
431
- doc.attributes[:name].should == 'new value'
432
- doc.attributes[:age].should == 10
167
+ should "create writer method" do
168
+ @document.new.should_not respond_to(:foo=)
169
+ @document.key(:foo, String)
170
+ @document.new.should respond_to(:foo=)
171
+ end
172
+
173
+ should "create boolean method" do
174
+ @document.new.should_not respond_to(:foo?)
175
+ @document.key(:foo, String)
176
+ @document.new.should respond_to(:foo?)
177
+ end
433
178
  end
434
179
 
435
- should "not ignore keys that have methods defined" do
436
- @document.class_eval do
437
- attr_writer :password
180
+ context "keys" do
181
+ should "be inherited" do
182
+ Grandparent.keys.keys.sort.should == ['_id', 'grandparent']
183
+ Parent.keys.keys.sort.should == ['_id', 'grandparent', 'parent']
184
+ Child.keys.keys.sort.should == ['_id', 'child', 'grandparent', 'parent']
185
+ end
438
186
 
439
- def passwd
440
- @password
441
- end
187
+ should "propogate to descendants if key added after class definition" do
188
+ Grandparent.key :_type, String
189
+
190
+ Grandparent.keys.keys.sort.should == ['_id', '_type', 'grandparent']
191
+ Parent.keys.keys.sort.should == ['_id', '_type', 'grandparent', 'parent']
192
+ Child.keys.keys.sort.should == ['_id', '_type', 'child', 'grandparent', 'parent']
193
+ end
194
+
195
+ should "not add anonymous objects to the ancestor tree" do
196
+ OtherChild.ancestors.any? { |a| a.name.blank? }.should be_false
442
197
  end
443
198
 
444
- doc = @document.new(:name => 'foobar', :password => 'secret')
445
- doc.passwd.should == 'secret'
199
+ should "not include descendant keys" do
200
+ lambda { Parent.new.other_child }.should raise_error
201
+ end
446
202
  end
447
203
 
448
- should "typecast key values" do
449
- doc = @document.new(:name => 1234, :age => '21')
450
- doc.name.should == '1234'
451
- doc.age.should == 21
204
+ context "descendants" do
205
+ should "default to nil" do
206
+ Child.descendants.should be_nil
207
+ end
208
+
209
+ should "be recorded" do
210
+ Grandparent.descendants.should == [Parent]
211
+ Parent.descendants.should == [Child, OtherChild]
212
+ end
452
213
  end
453
214
  end
454
215
 
455
- context "attributes" do
456
- should "default to hash with all keys" do
457
- doc = @document.new
458
- doc.attributes.keys.sort.should == ['_id', 'age', 'name']
216
+ context "An instance of an embedded document" do
217
+ setup do
218
+ @document = EDoc do
219
+ key :name, String
220
+ key :age, Integer
221
+ end
459
222
  end
460
223
 
461
- should "return all keys with values" do
462
- doc = @document.new(:name => 'string', :age => nil)
463
- doc.attributes.keys.sort.should == ['_id', 'age', 'name']
464
- doc.attributes.values.should include('string')
465
- doc.attributes.values.should include(nil)
224
+ should "have to_param that is string representation of id" do
225
+ doc = @document.new
226
+ doc.to_param.should == doc.id.to_s
227
+ doc.to_param.should be_instance_of(String)
466
228
  end
467
- end
468
-
469
- context "to_mongo" do
470
- should "default to hash with _id key" do
229
+
230
+ should "have access to class logger" do
471
231
  doc = @document.new
472
- doc.to_mongo.keys.should == ['_id']
232
+ doc.logger.should == @document.logger
233
+ doc.logger.should be_instance_of(Logger)
473
234
  end
474
-
475
- should "return all keys with non nil values" do
476
- doc = @document.new(:name => 'string', :age => nil)
477
- doc.to_mongo.keys.sort.should == ['_id', 'name']
478
- doc.to_mongo.values.should include('string')
479
- doc.to_mongo.values.should_not include(nil)
235
+
236
+ should "automatically have an _id key" do
237
+ @document.keys.keys.should include('_id')
480
238
  end
481
- end
482
-
483
- should "convert dates into times" do
484
- document = Class.new(@document) do
485
- key :start_date, Date
239
+
240
+ should "create id during initialization" do
241
+ @document.new._id.should be_instance_of(Mongo::ObjectID)
486
242
  end
487
- doc = document.new :start_date => "12/05/2009"
488
- doc.start_date.should == Date.new(2009, 12, 05)
489
- end
490
243
 
491
- context "clone" do
492
- should "regenerate the id" do
493
- doc = @document.new(:name => "foo", :age => 27)
494
- doc_id = doc.id
495
- clone = doc.clone
496
- clone_id = clone.id
497
- clone_id.should_not == doc_id
244
+ should "have id method returns _id" do
245
+ id = Mongo::ObjectID.new
246
+ doc = @document.new(:_id => id)
247
+ doc.id.should == id
498
248
  end
499
249
 
500
- should "copy the attributes" do
501
- doc = @document.new(:name => "foo", :age => 27)
502
- clone = doc.clone
503
- clone.name.should == "foo"
504
- clone.age.should == 27
250
+ should "convert string object id to mongo object id when assigning id with _id object id type" do
251
+ id = Mongo::ObjectID.new
252
+
253
+ doc = @document.new(:id => id.to_s)
254
+ doc._id.should == id
255
+ doc.id.should == id
256
+
257
+ doc = @document.new(:_id => id.to_s)
258
+ doc._id.should == id
259
+ doc.id.should == id
505
260
  end
506
- end
507
-
508
- context "key shorcut access" do
509
- context "[]" do
510
- should "work when key found" do
511
- doc = @document.new(:name => 'string')
512
- doc[:name].should == 'string'
261
+
262
+ context "_root_document" do
263
+ should "default to nil" do
264
+ @document.new._root_document.should be_nil
513
265
  end
514
-
515
- should "raise exception when key not found" do
516
- doc = @document.new(:name => 'string')
517
- lambda {
518
- doc[:not_here]
519
- }.should raise_error(MongoMapper::KeyNotFound)
266
+
267
+ should "allow setting when initialized" do
268
+ root = Doc().new
269
+ doc = @document.new :_root_document => root
270
+
271
+ doc._root_document.should be(root)
272
+ end
273
+
274
+ should "also be set on many embedded documents" do
275
+ root = Doc().new
276
+ klass = EDoc { many :children }
277
+ doc = klass.new(:_root_document => root, :children => [{}])
278
+
279
+ doc.children.first._root_document.should == root
520
280
  end
521
281
  end
522
-
523
- context "[]=" do
524
- should "write key value for existing key" do
525
- doc = @document.new
526
- doc[:name] = 'string'
527
- doc[:name].should == 'string'
282
+
283
+ context "being initialized" do
284
+ should "accept a hash that sets keys and values" do
285
+ doc = @document.new(:name => 'John', :age => 23)
286
+ doc.attributes.keys.sort.should == ['_id', 'age', 'name']
287
+ doc.attributes['name'].should == 'John'
288
+ doc.attributes['age'].should == 23
528
289
  end
529
-
530
- should "create key and write value for missing key" do
531
- doc = @document.new
532
- doc[:foo] = 'string'
533
- doc.metaclass.keys.include?('foo').should be_true
534
- doc[:foo].should == 'string'
290
+
291
+ should "be able to assign keys dynamically" do
292
+ doc = @document.new(:name => 'John', :skills => ['ruby', 'rails'])
293
+ doc.name.should == 'John'
294
+ doc.skills.should == ['ruby', 'rails']
535
295
  end
536
296
 
537
- should "not share the new key" do
538
- doc = @document.new
539
- doc[:foo] = 'string'
540
- @document.keys.should_not include('foo')
541
- end
542
- end
543
- end
544
-
545
- context "indifferent access" do
546
- should "be enabled for keys" do
547
- doc = @document.new(:name => 'string')
548
- doc.attributes[:name].should == 'string'
549
- doc.attributes['name'].should == 'string'
297
+ should "not throw error if initialized with nil" do
298
+ assert_nothing_raised { @document.new(nil) }
299
+ end
550
300
  end
551
- end
552
301
 
553
- context "reading an attribute" do
554
- should "work for defined keys" do
555
- doc = @document.new(:name => 'string')
556
- doc.name.should == 'string'
557
- end
302
+ context "initialized when _type key present" do
303
+ setup do
304
+ @klass = EDoc('FooBar') { key :_type, String }
305
+ end
558
306
 
559
- should "raise no method error for undefined keys" do
560
- doc = @document.new
561
- lambda { doc.fart }.should raise_error(NoMethodError)
307
+ should "set _type to class name" do
308
+ @klass.new._type.should == 'FooBar'
309
+ end
310
+
311
+ should "not change _type if already set" do
312
+ @klass.new(:_type => 'Foo')._type.should == 'Foo'
313
+ end
562
314
  end
563
315
 
564
- should "be accessible for use in the model" do
565
- @document.class_eval do
566
- def name_and_age
567
- "#{read_attribute(:name)} (#{read_attribute(:age)})"
316
+ context "attributes=" do
317
+ should "update values for keys provided" do
318
+ doc = @document.new(:name => 'foobar', :age => 10)
319
+ doc.attributes = {:name => 'new value', :age => 5}
320
+ doc.attributes[:name].should == 'new value'
321
+ doc.attributes[:age].should == 5
322
+ end
323
+
324
+ should "not update values for keys that were not provided" do
325
+ doc = @document.new(:name => 'foobar', :age => 10)
326
+ doc.attributes = {:name => 'new value'}
327
+ doc.attributes[:name].should == 'new value'
328
+ doc.attributes[:age].should == 10
329
+ end
330
+
331
+ should "work with pre-defined methods" do
332
+ @document.class_eval do
333
+ attr_writer :password
334
+
335
+ def passwd
336
+ @password
337
+ end
568
338
  end
339
+
340
+ doc = @document.new(:name => 'foobar', :password => 'secret')
341
+ doc.passwd.should == 'secret'
569
342
  end
570
343
 
571
- doc = @document.new(:name => 'John', :age => 27)
572
- doc.name_and_age.should == 'John (27)'
344
+ should "typecast key values" do
345
+ doc = @document.new(:name => 1234, :age => '21')
346
+ doc.name.should == '1234'
347
+ doc.age.should == 21
348
+ end
573
349
  end
574
-
575
- should "set instance variable" do
576
- @document.key :foo, Array
577
- doc = @document.new
578
- doc.instance_variable_get("@foo").should be_nil
579
- doc.foo
580
- doc.instance_variable_get("@foo").should == []
581
- end
582
-
583
- should "be overrideable by modules" do
584
- @document = Class.new do
585
- include MongoMapper::Document
586
- key :other_child, String
587
- end
588
-
589
- child = @document.new
590
- child.other_child.should be_nil
591
-
592
- @document.send :include, KeyOverride
593
-
594
- overriden_child = @document.new
595
- overriden_child.other_child.should == 'special result'
350
+
351
+ context "attributes" do
352
+ should "default to hash with all keys" do
353
+ doc = @document.new
354
+ doc.attributes.keys.sort.should == ['_id', 'age', 'name']
355
+ end
356
+
357
+ should "return all keys with values" do
358
+ doc = @document.new(:name => 'string', :age => nil)
359
+ doc.attributes.keys.sort.should == ['_id', 'age', 'name']
360
+ doc.attributes.values.should include('string')
361
+ doc.attributes.values.should include(nil)
362
+ end
363
+
364
+ should "have indifferent access" do
365
+ doc = @document.new(:name => 'string')
366
+ doc.attributes[:name].should == 'string'
367
+ doc.attributes['name'].should == 'string'
368
+ end
596
369
  end
597
- end
598
370
 
599
- context "reading an attribute before typcasting" do
600
- should "work for defined keys" do
601
- doc = @document.new(:name => 12)
602
- doc.name_before_typecast.should == 12
371
+ context "to_mongo" do
372
+ should "default to hash with _id key" do
373
+ doc = @document.new
374
+ doc.to_mongo.keys.sort.should == ['_id', 'age', 'name']
375
+ end
376
+
377
+ should "return all keys" do
378
+ doc = @document.new(:name => 'string', :age => nil)
379
+ doc.to_mongo.keys.sort.should == ['_id', 'age', 'name']
380
+ doc.to_mongo.values.should include('string')
381
+ doc.to_mongo.values.should include(nil)
382
+ end
603
383
  end
604
384
 
605
- should "raise no method error for undefined keys" do
606
- doc = @document.new
607
- lambda { doc.foo_before_typecast }.should raise_error(NoMethodError)
385
+ context "clone" do
386
+ should "regenerate the id" do
387
+ doc = @document.new(:name => "foo", :age => 27)
388
+ doc_id = doc.id
389
+ clone = doc.clone
390
+ clone_id = clone.id
391
+ clone_id.should_not == doc_id
392
+ end
393
+
394
+ should "copy the attributes" do
395
+ doc = @document.new(:name => "foo", :age => 27)
396
+ clone = doc.clone
397
+ clone.name.should == "foo"
398
+ clone.age.should == 27
399
+ end
608
400
  end
609
401
 
610
- should "be accessible for use in a document" do
611
- @document.class_eval do
612
- def untypcasted_name
613
- read_attribute_before_typecast(:name)
402
+ context "key shorcut access" do
403
+ context "[]" do
404
+ should "work when key found" do
405
+ doc = @document.new(:name => 'string')
406
+ doc[:name].should == 'string'
407
+ end
408
+
409
+ should "raise exception when key not found" do
410
+ doc = @document.new(:name => 'string')
411
+ assert_raises(MongoMapper::KeyNotFound) { doc[:not_here] }
614
412
  end
615
413
  end
616
414
 
617
- doc = @document.new(:name => 12)
618
- doc.name.should == '12'
619
- doc.untypcasted_name.should == 12
620
- end
621
- end
415
+ context "[]=" do
416
+ should "write key value for existing key" do
417
+ doc = @document.new
418
+ doc[:name] = 'string'
419
+ doc[:name].should == 'string'
420
+ end
622
421
 
623
- context "writing an attribute" do
624
- should "work for defined keys" do
625
- doc = @document.new
626
- doc.name = 'John'
627
- doc.name.should == 'John'
628
- end
422
+ should "create key and write value for missing key" do
423
+ doc = @document.new
424
+ doc[:foo] = 'string'
425
+ doc.class.keys.include?('foo').should be_true
426
+ doc[:foo].should == 'string'
427
+ end
629
428
 
630
- should "raise no method error for undefined keys" do
631
- doc = @document.new
632
- lambda { doc.fart = 'poof!' }.should raise_error(NoMethodError)
429
+ should "share the new key with the class" do
430
+ doc = @document.new
431
+ doc[:foo] = 'string'
432
+ @document.keys.should include('foo')
433
+ end
434
+ end
633
435
  end
634
436
 
635
- should "typecast value" do
636
- doc = @document.new
637
- doc.name = 1234
638
- doc.name.should == '1234'
639
- doc.age = '21'
640
- doc.age.should == 21
641
- end
642
-
643
- should "be accessible for use in the model" do
644
- @document.class_eval do
645
- def name_and_age=(new_value)
646
- new_value.match(/([^\(\s]+) \((.*)\)/)
647
- write_attribute :name, $1
648
- write_attribute :age, $2
437
+ context "reading a key" do
438
+ should "work for defined keys" do
439
+ doc = @document.new(:name => 'string')
440
+ doc.name.should == 'string'
441
+ end
442
+
443
+ should "raise no method error for undefined keys" do
444
+ doc = @document.new
445
+ lambda { doc.fart }.should raise_error(NoMethodError)
446
+ end
447
+
448
+ should "be accessible for use in the model" do
449
+ @document.class_eval do
450
+ def name_and_age
451
+ "#{self[:name]} (#{self[:age]})"
452
+ end
649
453
  end
454
+
455
+ doc = @document.new(:name => 'John', :age => 27)
456
+ doc.name_and_age.should == 'John (27)'
650
457
  end
651
458
 
652
- doc = @document.new
653
- doc.name_and_age = 'Frank (62)'
654
- doc.name.should == 'Frank'
655
- doc.age.should == 62
656
- end
657
-
658
- should "be overrideable by modules" do
659
- @document = Class.new do
660
- include MongoMapper::Document
661
- key :other_child, String
662
- end
663
-
664
- child = @document.new(:other_child => 'foo')
665
- child.other_child.should == 'foo'
666
-
667
- @document.send :include, KeyOverride
668
-
669
- overriden_child = @document.new(:other_child => 'foo')
670
- overriden_child.other_child.should == 'foo modified'
671
- end
672
- end # writing an attribute
673
-
674
- context "checking if an attributes value is present" do
675
- should "work for defined keys" do
676
- doc = @document.new
677
- doc.name?.should be_false
678
- doc.name = 'John'
679
- doc.name?.should be_true
459
+ should "set instance variable" do
460
+ @document.key :foo, Array
461
+ doc = @document.new
462
+ doc.instance_variable_get("@foo").should be_nil
463
+ doc.foo
464
+ doc.instance_variable_get("@foo").should == []
465
+ end
466
+
467
+ should "be overrideable by modules" do
468
+ @document = Doc do
469
+ key :other_child, String
470
+ end
471
+
472
+ child = @document.new
473
+ child.other_child.should be_nil
474
+
475
+ @document.send :include, KeyOverride
476
+
477
+ overriden_child = @document.new
478
+ overriden_child.other_child.should == 'special result'
479
+ end
680
480
  end
681
-
682
- should "raise no method error for undefined keys" do
683
- doc = @document.new
684
- lambda { doc.fart? }.should raise_error(NoMethodError)
481
+
482
+ context "reading a key before typcasting" do
483
+ should "work for defined keys" do
484
+ doc = @document.new(:name => 12)
485
+ doc.name_before_typecast.should == 12
486
+ end
487
+
488
+ should "raise no method error for undefined keys" do
489
+ doc = @document.new
490
+ lambda { doc.foo_before_typecast }.should raise_error(NoMethodError)
491
+ end
492
+
493
+ should "be accessible for use in a document" do
494
+ @document.class_eval do
495
+ def untypcasted_name
496
+ read_key_before_typecast(:name)
497
+ end
498
+ end
499
+
500
+ doc = @document.new(:name => 12)
501
+ doc.name.should == '12'
502
+ doc.untypcasted_name.should == 12
503
+ end
685
504
  end
686
- end
687
-
688
- context "equality" do
689
- setup do
690
- @oid = Mongo::ObjectID.new
505
+
506
+ context "writing a key" do
507
+ should "work for defined keys" do
508
+ doc = @document.new
509
+ doc.name = 'John'
510
+ doc.name.should == 'John'
511
+ end
512
+
513
+ should "raise no method error for undefined keys" do
514
+ doc = @document.new
515
+ lambda { doc.fart = 'poof!' }.should raise_error(NoMethodError)
516
+ end
517
+
518
+ should "typecast value" do
519
+ doc = @document.new
520
+ doc.name = 1234
521
+ doc.name.should == '1234'
522
+ doc.age = '21'
523
+ doc.age.should == 21
524
+ end
525
+
526
+ should "be accessible for use in the model" do
527
+ @document.class_eval do
528
+ def name_and_age=(new_value)
529
+ new_value.match(/([^\(\s]+) \((.*)\)/)
530
+ write_key :name, $1
531
+ write_key :age, $2
532
+ end
533
+ end
534
+
535
+ doc = @document.new
536
+ doc.name_and_age = 'Frank (62)'
537
+ doc.name.should == 'Frank'
538
+ doc.age.should == 62
539
+ end
540
+
541
+ should "be overrideable by modules" do
542
+ @document = Doc do
543
+ key :other_child, String
544
+ end
545
+
546
+ child = @document.new(:other_child => 'foo')
547
+ child.other_child.should == 'foo'
548
+
549
+ @document.send :include, KeyOverride
550
+
551
+ overriden_child = @document.new(:other_child => 'foo')
552
+ overriden_child.other_child.should == 'foo modified'
553
+ end
554
+ end # writing a key
555
+
556
+ context "checking if a keys value is present" do
557
+ should "work for defined keys" do
558
+ doc = @document.new
559
+ doc.name?.should be_false
560
+ doc.name = 'John'
561
+ doc.name?.should be_true
562
+ end
563
+
564
+ should "raise no method error for undefined keys" do
565
+ doc = @document.new
566
+ lambda { doc.fart? }.should raise_error(NoMethodError)
567
+ end
691
568
  end
692
- should "be equal if id and class are the same" do
693
- (@document.new('_id' => @oid) == @document.new('_id' => @oid)).should be(true)
569
+
570
+ should "call inspect on the document's attributes instead of to_s when inspecting the document" do
571
+ doc = @document.new(:animals => %w(dog cat))
572
+ doc.inspect.should include(%(animals: ["dog", "cat"]))
694
573
  end
695
574
 
696
- should "not be equal if class same but id different" do
697
- (@document.new('_id' => @oid) == @document.new('_id' => Mongo::ObjectID.new)).should be(false)
575
+ context "equality" do
576
+ setup do
577
+ @oid = Mongo::ObjectID.new
578
+ end
579
+
580
+ should "delegate hash to _id" do
581
+ doc = @document.new
582
+ doc.hash.should == doc._id.hash
583
+ end
584
+
585
+ should "delegate eql to ==" do
586
+ doc = @document.new
587
+ other = @document.new
588
+ doc.eql?(other).should == (doc == other)
589
+ doc.eql?(doc).should == (doc == doc)
590
+ end
591
+
592
+ should "know if same object as another" do
593
+ doc = @document.new
594
+ doc.should equal(doc)
595
+ doc.should_not equal(@document.new)
596
+ end
597
+
598
+ should "allow set operations on array of documents" do
599
+ doc = @document.new
600
+ ([doc] & [doc]).should == [doc]
601
+ end
602
+
603
+ should "be equal if id and class are the same" do
604
+ (@document.new('_id' => @oid) == @document.new('_id' => @oid)).should be_true
605
+ end
606
+
607
+ should "not be equal if class same but id different" do
608
+ (@document.new('_id' => @oid) == @document.new('_id' => Mongo::ObjectID.new)).should be_false
609
+ end
610
+
611
+ should "not be equal if id same but class different" do
612
+ another_document = Doc()
613
+ (@document.new('_id' => @oid) == another_document.new('_id' => @oid)).should be_false
614
+ end
698
615
  end
699
616
 
700
- should "not be equal if id same but class different" do
701
- @another_document = Class.new do
702
- include MongoMapper::Document
617
+ context "reading keys with default values" do
618
+ setup do
619
+ @document = EDoc do
620
+ key :name, String, :default => 'foo'
621
+ key :age, Integer, :default => 20
622
+ key :net_worth, Float, :default => 100.00
623
+ key :active, Boolean, :default => true
624
+ key :smart, Boolean, :default => false
625
+ key :skills, Array, :default => [1]
626
+ key :options, Hash, :default => {'foo' => 'bar'}
627
+ end
628
+
629
+ @doc = @document.new
703
630
  end
704
631
 
705
- (@document.new('_id' => @oid) == @another_document.new('_id' => @oid)).should be(false)
632
+ should "work for strings" do
633
+ @doc.name.should == 'foo'
634
+ end
635
+
636
+ should "work for integers" do
637
+ @doc.age.should == 20
638
+ end
639
+
640
+ should "work for floats" do
641
+ @doc.net_worth.should == 100.00
642
+ end
643
+
644
+ should "work for booleans" do
645
+ @doc.active.should == true
646
+ @doc.smart.should == false
647
+ end
648
+
649
+ should "work for arrays" do
650
+ @doc.skills.should == [1]
651
+ @doc.skills << 2
652
+ @doc.skills.should == [1, 2]
653
+ end
654
+
655
+ should "work for hashes" do
656
+ @doc.options['foo'].should == 'bar'
657
+ @doc.options['baz'] = 'wick'
658
+ @doc.options['baz'].should == 'wick'
659
+ end
706
660
  end
707
- end
708
- end # instance of a embedded document
661
+ end # instance of a embedded document
662
+ end
709
663
  end