mongo_mapper 0.8.6 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. data/UPGRADES +10 -0
  2. data/bin/mmconsole +0 -1
  3. data/examples/identity_map/automatic.rb +1 -7
  4. data/examples/plugins.rb +9 -9
  5. data/examples/safe.rb +43 -0
  6. data/lib/mongo_mapper.rb +46 -33
  7. data/lib/mongo_mapper/document.rb +33 -32
  8. data/lib/mongo_mapper/embedded_document.rb +22 -22
  9. data/lib/mongo_mapper/locale/en.yml +5 -0
  10. data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
  11. data/lib/mongo_mapper/plugins.rb +16 -3
  12. data/lib/mongo_mapper/plugins/accessible.rb +2 -0
  13. data/lib/mongo_mapper/plugins/active_model.rb +18 -0
  14. data/lib/mongo_mapper/plugins/associations.rb +37 -42
  15. data/lib/mongo_mapper/plugins/associations/base.rb +14 -50
  16. data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +58 -0
  17. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +6 -1
  18. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +30 -2
  19. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +4 -0
  20. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +12 -6
  21. data/lib/mongo_mapper/plugins/associations/many_association.rb +67 -0
  22. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +5 -5
  23. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +1 -1
  24. data/lib/mongo_mapper/plugins/associations/one_association.rb +20 -0
  25. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +5 -0
  26. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +7 -7
  27. data/lib/mongo_mapper/plugins/associations/proxy.rb +2 -2
  28. data/lib/mongo_mapper/plugins/caching.rb +3 -1
  29. data/lib/mongo_mapper/plugins/callbacks.rb +12 -221
  30. data/lib/mongo_mapper/plugins/clone.rb +3 -1
  31. data/lib/mongo_mapper/plugins/dirty.rb +38 -91
  32. data/lib/mongo_mapper/plugins/document.rb +4 -2
  33. data/lib/mongo_mapper/plugins/dynamic_querying.rb +2 -0
  34. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +43 -0
  35. data/lib/mongo_mapper/plugins/embedded_document.rb +16 -9
  36. data/lib/mongo_mapper/plugins/equality.rb +2 -0
  37. data/lib/mongo_mapper/plugins/identity_map.rb +4 -2
  38. data/lib/mongo_mapper/plugins/indexes.rb +2 -0
  39. data/lib/mongo_mapper/plugins/inspect.rb +3 -1
  40. data/lib/mongo_mapper/plugins/keys.rb +28 -22
  41. data/lib/mongo_mapper/plugins/keys/key.rb +12 -6
  42. data/lib/mongo_mapper/plugins/logger.rb +2 -0
  43. data/lib/mongo_mapper/plugins/modifiers.rb +3 -1
  44. data/lib/mongo_mapper/plugins/pagination.rb +2 -0
  45. data/lib/mongo_mapper/plugins/persistence.rb +2 -0
  46. data/lib/mongo_mapper/plugins/protected.rb +2 -0
  47. data/lib/mongo_mapper/plugins/querying.rb +5 -4
  48. data/lib/mongo_mapper/plugins/rails.rb +3 -5
  49. data/lib/mongo_mapper/plugins/safe.rb +2 -0
  50. data/lib/mongo_mapper/plugins/sci.rb +2 -0
  51. data/lib/mongo_mapper/plugins/scopes.rb +2 -0
  52. data/lib/mongo_mapper/plugins/serialization.rb +67 -46
  53. data/lib/mongo_mapper/plugins/timestamps.rb +3 -1
  54. data/lib/mongo_mapper/plugins/userstamps.rb +2 -0
  55. data/lib/mongo_mapper/plugins/validations.rb +40 -24
  56. data/lib/mongo_mapper/railtie.rb +49 -0
  57. data/lib/mongo_mapper/railtie/database.rake +60 -0
  58. data/lib/mongo_mapper/support/descendant_appends.rb +11 -11
  59. data/lib/mongo_mapper/translation.rb +10 -0
  60. data/lib/mongo_mapper/version.rb +1 -1
  61. data/lib/rails/generators/mongo_mapper/config/config_generator.rb +24 -0
  62. data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +18 -0
  63. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +23 -0
  64. data/lib/rails/generators/mongo_mapper/model/templates/model.rb +11 -0
  65. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +1 -0
  66. data/test/functional/associations/test_belongs_to_proxy.rb +131 -1
  67. data/test/functional/associations/test_in_array_proxy.rb +30 -0
  68. data/test/functional/associations/test_many_documents_proxy.rb +30 -2
  69. data/test/functional/associations/test_many_embedded_proxy.rb +33 -0
  70. data/test/functional/associations/test_many_polymorphic_proxy.rb +1 -0
  71. data/test/functional/associations/test_one_embedded_proxy.rb +21 -2
  72. data/test/functional/associations/test_one_proxy.rb +49 -9
  73. data/test/functional/test_associations.rb +2 -0
  74. data/test/functional/test_caching.rb +3 -2
  75. data/test/functional/test_callbacks.rb +25 -18
  76. data/test/functional/test_dirty.rb +123 -1
  77. data/test/functional/test_document.rb +26 -2
  78. data/test/functional/test_embedded_document.rb +68 -2
  79. data/test/functional/test_identity_map.rb +3 -4
  80. data/test/functional/test_querying.rb +11 -0
  81. data/test/functional/test_userstamps.rb +2 -2
  82. data/test/functional/test_validations.rb +31 -29
  83. data/test/models.rb +10 -0
  84. data/test/test_active_model_lint.rb +1 -1
  85. data/test/test_helper.rb +9 -10
  86. data/test/unit/associations/test_base.rb +24 -100
  87. data/test/unit/associations/test_belongs_to_association.rb +29 -0
  88. data/test/unit/associations/test_many_association.rb +63 -0
  89. data/test/unit/associations/test_one_association.rb +18 -0
  90. data/test/unit/serializers/test_json_serializer.rb +0 -1
  91. data/test/unit/test_descendant_appends.rb +8 -16
  92. data/test/unit/test_document.rb +4 -9
  93. data/test/unit/test_dynamic_finder.rb +1 -1
  94. data/test/unit/test_embedded_document.rb +51 -18
  95. data/test/unit/test_identity_map_middleware.rb +34 -0
  96. data/test/unit/test_inspect.rb +22 -0
  97. data/test/unit/test_key.rb +21 -1
  98. data/test/unit/test_keys.rb +0 -2
  99. data/test/unit/test_plugins.rb +106 -20
  100. data/test/unit/test_rails.rb +8 -8
  101. data/test/unit/test_serialization.rb +116 -1
  102. data/test/unit/test_translation.rb +27 -0
  103. data/test/unit/test_validations.rb +66 -81
  104. metadata +103 -43
  105. data/examples/identity_map/middleware.rb +0 -14
  106. data/lib/mongo_mapper/plugins/descendants.rb +0 -17
  107. data/rails/init.rb +0 -19
@@ -138,6 +138,7 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
138
138
  @hm2 = Message.create(:body => 'Hall the king!', :position => 2)
139
139
  @hall.messages = [@hm1, @hm2, @hm3]
140
140
  @hall.save
141
+ @hall.reload
141
142
  end
142
143
 
143
144
  context "dynamic finders" do
@@ -20,7 +20,7 @@ class OneEmbeddedProxyTest < Test::Unit::TestCase
20
20
  @post_class.one :author, :class => @author_class
21
21
 
22
22
  post = @post_class.create
23
- author = post.author.build(:name => "John")
23
+ author = post.build_author(:name => "John")
24
24
  post.author.should be_instance_of(@author_class)
25
25
  post.author.should be_new
26
26
  post.author.name.should == 'John'
@@ -48,7 +48,7 @@ class OneEmbeddedProxyTest < Test::Unit::TestCase
48
48
  should "not have problem loading root document if embedded one is nil" do
49
49
  @post_class.one :author, :class => @author_class
50
50
  post = @post_class.create
51
-
51
+
52
52
  lambda {
53
53
  @post_class.find(post.id)
54
54
  }.should_not raise_error
@@ -78,4 +78,23 @@ class OneEmbeddedProxyTest < Test::Unit::TestCase
78
78
  post.author?.should be_true
79
79
  end
80
80
 
81
+ should "initialize id for nested embedded document created from hash" do
82
+ @address_class = EDoc('Address') do
83
+ key :city, String
84
+ key :state, String
85
+ end
86
+ @author_class.one(:address, :class => @address_class)
87
+ @post_class.one(:author, :class => @author_class)
88
+
89
+ post = @post_class.create(:title => 'Post Title', :author => {
90
+ :name => 'Frank',
91
+ :address => {
92
+ :city => 'Boston',
93
+ :state => 'MA'
94
+ }
95
+ })
96
+
97
+ post.author.address.id.should_not be_nil
98
+ end
99
+
81
100
  end
@@ -1,4 +1,5 @@
1
1
  require 'test_helper'
2
+ require 'models'
2
3
 
3
4
  class OneProxyTest < Test::Unit::TestCase
4
5
  def setup
@@ -13,6 +14,11 @@ class OneProxyTest < Test::Unit::TestCase
13
14
  @post_class.new.author.nil?.should be_true
14
15
  end
15
16
 
17
+ should "return nil instead of a proxy" do
18
+ @post_class.one :author, :class => @author_class
19
+ nil.should === @post_class.new.author
20
+ end
21
+
16
22
  should "allow assignment of associated document using a hash" do
17
23
  @post_class.one :author, :class => @author_class
18
24
 
@@ -42,6 +48,26 @@ class OneProxyTest < Test::Unit::TestCase
42
48
  post.author = new_author
43
49
  post.author.should == new_author
44
50
  end
51
+
52
+ should "generate a new proxy instead of modifying the existing one" do
53
+ @post_class.one :author, :class => @author_class
54
+
55
+ post = @post_class.new
56
+ author = @author_class.new(:name => 'Frank')
57
+ post.author = author
58
+ post.reload
59
+
60
+ post.author.should == author
61
+ post.author.nil?.should be_false
62
+
63
+ original_author = post.author
64
+ original_author.name.should == 'Frank'
65
+ new_author = @author_class.new(:name => 'Emily')
66
+ post.author = new_author
67
+ post.author.should == new_author
68
+
69
+ original_author.name.should == 'Frank'
70
+ end
45
71
  end
46
72
 
47
73
  context "with a Hash" do
@@ -85,13 +111,12 @@ class OneProxyTest < Test::Unit::TestCase
85
111
 
86
112
  should "unset the association" do
87
113
  @post_class.one :author, :class => @author_class
88
- post = @post_class.new
89
- author = @author_class.new
90
- post.author = author
114
+ post = @post_class.create
115
+ author = @author_class.create
116
+ post.update_attributes!(:author => author)
91
117
  post.reload
92
-
93
118
  post.author = nil
94
- post.author.nil?.should be_false
119
+ post.author.nil?.should be_true
95
120
  end
96
121
 
97
122
  should "work with :dependent delete" do
@@ -136,7 +161,7 @@ class OneProxyTest < Test::Unit::TestCase
136
161
  @post_class.one :author, :class => @author_class
137
162
 
138
163
  post = @post_class.create
139
- author = post.author.build(:name => 'John')
164
+ author = post.build_author(:name => 'John')
140
165
  post.author.should be_instance_of(@author_class)
141
166
  post.author.should be_new
142
167
  post.author.name.should == 'John'
@@ -148,7 +173,7 @@ class OneProxyTest < Test::Unit::TestCase
148
173
  @post_class.one :author, :class => @author_class
149
174
 
150
175
  post = @post_class.create
151
- author = post.author.create(:name => 'John')
176
+ author = post.create_author(:name => 'John')
152
177
  post.author.should be_instance_of(@author_class)
153
178
  post.author.should_not be_new
154
179
  post.author.name.should == 'John'
@@ -165,13 +190,13 @@ class OneProxyTest < Test::Unit::TestCase
165
190
  should "raise exception if invalid" do
166
191
  post = @post_class.create
167
192
  assert_raises(MongoMapper::DocumentNotValid) do
168
- post.author.create!
193
+ post.create_author!
169
194
  end
170
195
  end
171
196
 
172
197
  should "work if valid" do
173
198
  post = @post_class.create
174
- author = post.author.create!(:name => 'John')
199
+ author = post.create_author!(:name => 'John')
175
200
  post.author.should be_instance_of(@author_class)
176
201
  post.author.should_not be_new
177
202
  post.author.name.should == 'John'
@@ -179,4 +204,19 @@ class OneProxyTest < Test::Unit::TestCase
179
204
  post.author.post_id.should == post.id
180
205
  end
181
206
  end
207
+
208
+ context "namespaced foreign keys" do
209
+ setup do
210
+ News::Paper.one :article, :class_name => 'News::Article'
211
+ News::Article.belongs_to :paper, :class_name => 'News::Paper'
212
+
213
+ @paper = News::Paper.create
214
+ end
215
+
216
+ should "properly infer the foreign key" do
217
+ article = @paper.create_article
218
+ article.should respond_to(:paper_id)
219
+ article.paper_id.should == @paper.id
220
+ end
221
+ end
182
222
  end
@@ -36,6 +36,8 @@ class AssociationsTest < Test::Unit::TestCase
36
36
  tag2 = AwesomeTag.new(:name => 'grand')
37
37
  post1 = AwesomePost.create(:creator => user, :tags => [tag1])
38
38
  post2 = AwesomePost.create(:creator => user, :tags => [tag2])
39
+
40
+ user.reload
39
41
  user.posts.should == [post1, post2]
40
42
 
41
43
  post1 = post1.reload
@@ -8,6 +8,7 @@ class CachingTest < Test::Unit::TestCase
8
8
  plugin MongoMapper::Plugins::Caching
9
9
  end
10
10
  @klass.stubs(:name).returns('Post')
11
+ @klass.any_instance.stubs(:persisted?).returns(true)
11
12
  @klass.any_instance.stubs(:[]).returns(nil)
12
13
  @klass.any_instance.stubs(:[]=).returns(nil)
13
14
  end
@@ -15,7 +16,7 @@ class CachingTest < Test::Unit::TestCase
15
16
  context "new" do
16
17
  setup do
17
18
  @doc = @klass.new
18
- @doc.stubs(:new?).returns(true)
19
+ @doc.stubs(:persisted?).returns(false)
19
20
  end
20
21
 
21
22
  should "be class/new" do
@@ -35,7 +36,7 @@ class CachingTest < Test::Unit::TestCase
35
36
  setup do
36
37
  @object_id = BSON::ObjectId.new
37
38
  @doc = @klass.new
38
- @doc.stubs(:new?).returns(false)
39
+ @doc.stubs(:persisted).returns(true)
39
40
  @doc.stubs(:id).returns(@object_id)
40
41
  end
41
42
 
@@ -4,15 +4,13 @@ module CallbacksSupport
4
4
  def self.included base
5
5
  base.key :name, String
6
6
 
7
- [ :before_validation_on_create, :before_validation_on_update,
8
- :before_validation, :after_validation,
7
+ [ :before_validation, :after_validation,
9
8
  :before_create, :after_create,
10
9
  :before_update, :after_update,
11
10
  :before_save, :after_save,
12
- :before_destroy, :after_destroy].each do |callback|
13
- callback_method = "#{callback}_callback"
14
- base.send(callback, callback_method)
15
- define_method(callback_method) do
11
+ :before_destroy, :after_destroy
12
+ ].each do |callback|
13
+ base.send(callback) do
16
14
  history << callback.to_sym
17
15
  end
18
16
  end
@@ -29,8 +27,23 @@ module CallbacksSupport
29
27
  end
30
28
 
31
29
  class CallbacksTest < Test::Unit::TestCase
32
- CreateCallbackOrder = [:before_validation, :before_validation_on_create, :after_validation, :before_save, :before_create, :after_create, :after_save]
33
- UpdateCallbackOrder = [:before_validation, :before_validation_on_update, :after_validation, :before_save, :before_update, :after_update, :after_save]
30
+ CreateCallbackOrder = [
31
+ :before_validation,
32
+ :after_validation,
33
+ :before_save,
34
+ :before_create,
35
+ :after_create,
36
+ :after_save
37
+ ]
38
+
39
+ UpdateCallbackOrder = [
40
+ :before_validation,
41
+ :after_validation,
42
+ :before_save,
43
+ :before_update,
44
+ :after_update,
45
+ :after_save
46
+ ]
34
47
 
35
48
  context "Defining and running callbacks on documents" do
36
49
  setup do
@@ -102,11 +115,8 @@ class CallbacksTest < Test::Unit::TestCase
102
115
  child = @child_class.new(:name => 'Child', :children => [grand])
103
116
  root = @root_class.create(:name => 'Parent', :children => [child])
104
117
 
105
- child = root.children.first
106
- child.history.should == CreateCallbackOrder
107
-
108
- grand = root.children.first.children.first
109
- grand.history.should == CreateCallbackOrder
118
+ root.children.first.history.should == CreateCallbackOrder
119
+ root.children.first.children.first.history.should == CreateCallbackOrder
110
120
  end
111
121
 
112
122
  should "get the order right based on root document updating" do
@@ -116,11 +126,8 @@ class CallbacksTest < Test::Unit::TestCase
116
126
  root.clear_history
117
127
  root.update_attributes(:name => 'Updated Parent')
118
128
 
119
- child = root.children.first
120
- child.history.should == UpdateCallbackOrder
121
-
122
- grand = root.children.first.children.first
123
- grand.history.should == UpdateCallbackOrder
129
+ root.children.first.history.should == UpdateCallbackOrder
130
+ root.children.first.children.first.history.should == UpdateCallbackOrder
124
131
  end
125
132
 
126
133
  should "work for before and after destroy" do
@@ -160,4 +160,126 @@ class DirtyTest < Test::Unit::TestCase
160
160
  milestone.changed.should == %w(project_id)
161
161
  end
162
162
  end
163
- end
163
+
164
+ context "save with an invalid document" do
165
+ should "not clear changes" do
166
+ validated_class = Doc do
167
+ key :name, String
168
+ key :required, String, :required=>true
169
+ end
170
+ validated_doc = validated_class.new
171
+ validated_doc.name = "I'm a changin"
172
+ validated_doc.save
173
+ validated_doc.changed?.should be_true
174
+
175
+ validated_doc.required = 1
176
+ validated_doc.save
177
+ validated_doc.changed?.should be_false
178
+ end
179
+ end
180
+
181
+ context "changing an already changed attribute" do
182
+ should "preserve the original value" do
183
+ doc = @document.create(:a=>"b")
184
+ doc.a = "c"
185
+ doc.a_change.should == ["b","c"]
186
+ doc.a = "d"
187
+ doc.a_change.should == ["b","d"]
188
+ end
189
+ should "reset changes when set back to the original value" do
190
+ doc = @document.create(:a=>"b")
191
+ doc.a = "c"
192
+ doc.a = "b"
193
+ doc.changed?.should be_false
194
+ end
195
+ end
196
+
197
+ context "reset_attribute!" do
198
+ should "reset the attribute back to the previous value" do
199
+ doc = @document.create(:a=>"b")
200
+ doc.a = "c"
201
+ doc.reset_a!
202
+ doc.changed?.should be_false
203
+ doc.a.should == "b"
204
+ end
205
+ should "reset the attribute back to the original value after several changes" do
206
+ doc = @document.create(:a=>"b")
207
+ doc.a = "c"
208
+ doc.a = "d"
209
+ doc.a = "e"
210
+ doc.reset_a!
211
+ doc.changed?.should be_false
212
+ doc.a.should == "b"
213
+ end
214
+ end
215
+
216
+ context "previous_changes" do
217
+ should "reflect previously committed change" do
218
+ doc = @document.create(:a=>"b")
219
+ doc.a = "c"
220
+ changes = doc.changes
221
+ doc.save!
222
+ doc.previous_changes.should == changes
223
+ end
224
+
225
+ should "not include attributes loaded from db" do
226
+ doc = @document.create(:a => "b")
227
+ @document.find(doc.id).previous_changes.should be_blank
228
+ end
229
+ end
230
+
231
+ context "Embedded documents" do
232
+ setup do
233
+ @edoc = EDoc('Duck') { key :name, String }
234
+ @edoc.plugin MongoMapper::Plugins::Dirty
235
+ @document = Doc('Long') { key :name, String }
236
+ @document.many :ducks, :class=>@edoc
237
+ @doc = @document.new
238
+ @duck = @doc.ducks.build
239
+ end
240
+
241
+ should "track changes" do
242
+ @duck.name = "hi"
243
+ @duck.changed?.should be_true
244
+ end
245
+
246
+ should "clear changes when saved" do
247
+ @duck.name = "hi"
248
+ @duck.changed?.should be_true
249
+ @duck.save!
250
+ @duck.changed?.should_not be_true
251
+ end
252
+
253
+ should "clear changes when the parent is saved" do
254
+ @duck.name = "hi"
255
+ @duck.changed?.should be_true
256
+ @doc.save!
257
+ @duck.changed?.should_not be_true
258
+ end
259
+
260
+ context "with nested embedded documents" do
261
+ setup do
262
+ @inner_edoc = EDoc('Dong') {key :name, String}
263
+ @inner_edoc.plugin MongoMapper::Plugins::Dirty
264
+ @edoc.many :dongs, :class=>@inner_edoc
265
+ @dong = @duck.dongs.build
266
+ end
267
+
268
+ should "track changes" do
269
+ @dong.name = "hi"
270
+ @dong.changed?.should be_true
271
+ end
272
+
273
+ should "clear changes when the root saves" do
274
+ @dong.name = "hi"
275
+ @dong.changed?.should be_true
276
+ @doc.save!
277
+ @dong.changed?.should be_false
278
+ end
279
+
280
+ end
281
+
282
+ end
283
+
284
+
285
+ end
@@ -192,11 +192,15 @@ class DocumentTest < Test::Unit::TestCase
192
192
 
193
193
  @document.many :foos, :class => @foo_class
194
194
  @document.many :bars, :class => @bar_class
195
+ @document.belongs_to :foo, :class => @foo_class
196
+ @document.one :bar, :class => @bar_class
195
197
 
196
198
  @instance = @document.create({
197
- :age => 39,
199
+ :age => 39,
198
200
  :foos => [@foo_class.new(:name => '1')],
199
201
  :bars => [@bar_class.new(:name => '1')],
202
+ :foo => @foo_class.new(:name => '2'),
203
+ :bar => @bar_class.new(:name => '2')
200
204
  })
201
205
  end
202
206
 
@@ -207,12 +211,27 @@ class DocumentTest < Test::Unit::TestCase
207
211
  @instance.age.should == 39
208
212
  end
209
213
 
210
- should "reset all associations" do
214
+ should "reset many associations" do
211
215
  @instance.foos.expects(:reset).at_least_once
212
216
  @instance.bars.expects(:reset).at_least_once
213
217
  @instance.reload
214
218
  end
215
219
 
220
+ should "reset belongs_to association" do
221
+ @instance.foo = nil
222
+ @instance.reload
223
+ @instance.foo.should_not be_nil
224
+ end
225
+
226
+ should "reset one association" do
227
+ @instance.bar = nil
228
+ @instance.reload
229
+ @instance.bar.should_not be_nil
230
+ end
231
+
232
+ should "reset nil one association" do
233
+ end
234
+
216
235
  should "reinstantiate embedded associations" do
217
236
  @instance.reload
218
237
  @instance.bars.first.name.should == '1'
@@ -250,4 +269,9 @@ class DocumentTest < Test::Unit::TestCase
250
269
  doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
251
270
  end
252
271
  end
272
+
273
+ should "not walk ObjectSpace when creating a model" do
274
+ ObjectSpace.expects(:each_object).never
275
+ Doc()
276
+ end
253
277
  end