thorsson-mongo_mapper 0.8.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +27 -0
  3. data/bin/mmconsole +60 -0
  4. data/examples/keys.rb +40 -0
  5. data/examples/modifiers/set.rb +25 -0
  6. data/examples/plugins.rb +41 -0
  7. data/examples/querying.rb +35 -0
  8. data/examples/scopes.rb +52 -0
  9. data/lib/mongo_mapper.rb +79 -0
  10. data/lib/mongo_mapper/connection.rb +83 -0
  11. data/lib/mongo_mapper/document.rb +41 -0
  12. data/lib/mongo_mapper/embedded_document.rb +31 -0
  13. data/lib/mongo_mapper/exceptions.rb +27 -0
  14. data/lib/mongo_mapper/extensions/array.rb +19 -0
  15. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  16. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  17. data/lib/mongo_mapper/extensions/date.rb +25 -0
  18. data/lib/mongo_mapper/extensions/float.rb +14 -0
  19. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  20. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  21. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  22. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  23. data/lib/mongo_mapper/extensions/object.rb +27 -0
  24. data/lib/mongo_mapper/extensions/object_id.rb +30 -0
  25. data/lib/mongo_mapper/extensions/set.rb +20 -0
  26. data/lib/mongo_mapper/extensions/string.rb +18 -0
  27. data/lib/mongo_mapper/extensions/time.rb +29 -0
  28. data/lib/mongo_mapper/plugins.rb +16 -0
  29. data/lib/mongo_mapper/plugins/accessible.rb +44 -0
  30. data/lib/mongo_mapper/plugins/associations.rb +97 -0
  31. data/lib/mongo_mapper/plugins/associations/base.rb +124 -0
  32. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +29 -0
  33. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +24 -0
  34. data/lib/mongo_mapper/plugins/associations/collection.rb +22 -0
  35. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +40 -0
  36. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +127 -0
  37. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  38. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +110 -0
  39. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  40. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  41. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  42. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +40 -0
  43. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  44. data/lib/mongo_mapper/plugins/associations/proxy.rb +126 -0
  45. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  46. data/lib/mongo_mapper/plugins/callbacks.rb +241 -0
  47. data/lib/mongo_mapper/plugins/clone.rb +19 -0
  48. data/lib/mongo_mapper/plugins/descendants.rb +17 -0
  49. data/lib/mongo_mapper/plugins/dirty.rb +120 -0
  50. data/lib/mongo_mapper/plugins/document.rb +41 -0
  51. data/lib/mongo_mapper/plugins/dynamic_querying.rb +43 -0
  52. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  53. data/lib/mongo_mapper/plugins/embedded_document.rb +49 -0
  54. data/lib/mongo_mapper/plugins/equality.rb +17 -0
  55. data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
  56. data/lib/mongo_mapper/plugins/indexes.rb +12 -0
  57. data/lib/mongo_mapper/plugins/inspect.rb +15 -0
  58. data/lib/mongo_mapper/plugins/keys.rb +309 -0
  59. data/lib/mongo_mapper/plugins/keys/key.rb +55 -0
  60. data/lib/mongo_mapper/plugins/logger.rb +18 -0
  61. data/lib/mongo_mapper/plugins/modifiers.rb +112 -0
  62. data/lib/mongo_mapper/plugins/pagination.rb +14 -0
  63. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  64. data/lib/mongo_mapper/plugins/protected.rb +53 -0
  65. data/lib/mongo_mapper/plugins/querying.rb +176 -0
  66. data/lib/mongo_mapper/plugins/querying/decorator.rb +46 -0
  67. data/lib/mongo_mapper/plugins/querying/plucky_methods.rb +15 -0
  68. data/lib/mongo_mapper/plugins/rails.rb +58 -0
  69. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  70. data/lib/mongo_mapper/plugins/sci.rb +32 -0
  71. data/lib/mongo_mapper/plugins/scopes.rb +21 -0
  72. data/lib/mongo_mapper/plugins/serialization.rb +76 -0
  73. data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
  74. data/lib/mongo_mapper/plugins/userstamps.rb +15 -0
  75. data/lib/mongo_mapper/plugins/validations.rb +50 -0
  76. data/lib/mongo_mapper/support/descendant_appends.rb +45 -0
  77. data/lib/mongo_mapper/version.rb +4 -0
  78. data/test/_NOTE_ON_TESTING +1 -0
  79. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  80. data/test/functional/associations/test_belongs_to_proxy.rb +93 -0
  81. data/test/functional/associations/test_in_array_proxy.rb +319 -0
  82. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  83. data/test/functional/associations/test_many_documents_proxy.rb +575 -0
  84. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  85. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  86. data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
  87. data/test/functional/associations/test_one_embedded_proxy.rb +67 -0
  88. data/test/functional/associations/test_one_proxy.rb +182 -0
  89. data/test/functional/test_accessible.rb +168 -0
  90. data/test/functional/test_associations.rb +44 -0
  91. data/test/functional/test_binary.rb +27 -0
  92. data/test/functional/test_caching.rb +76 -0
  93. data/test/functional/test_callbacks.rb +151 -0
  94. data/test/functional/test_dirty.rb +163 -0
  95. data/test/functional/test_document.rb +253 -0
  96. data/test/functional/test_dynamic_querying.rb +75 -0
  97. data/test/functional/test_embedded_document.rb +210 -0
  98. data/test/functional/test_identity_map.rb +506 -0
  99. data/test/functional/test_indexes.rb +42 -0
  100. data/test/functional/test_logger.rb +20 -0
  101. data/test/functional/test_modifiers.rb +416 -0
  102. data/test/functional/test_pagination.rb +91 -0
  103. data/test/functional/test_protected.rb +175 -0
  104. data/test/functional/test_querying.rb +873 -0
  105. data/test/functional/test_safe.rb +76 -0
  106. data/test/functional/test_sci.rb +230 -0
  107. data/test/functional/test_scopes.rb +171 -0
  108. data/test/functional/test_string_id_compatibility.rb +67 -0
  109. data/test/functional/test_timestamps.rb +62 -0
  110. data/test/functional/test_userstamps.rb +27 -0
  111. data/test/functional/test_validations.rb +342 -0
  112. data/test/models.rb +233 -0
  113. data/test/test_active_model_lint.rb +13 -0
  114. data/test/test_helper.rb +104 -0
  115. data/test/unit/associations/test_base.rb +212 -0
  116. data/test/unit/associations/test_proxy.rb +105 -0
  117. data/test/unit/serializers/test_json_serializer.rb +202 -0
  118. data/test/unit/test_clone.rb +69 -0
  119. data/test/unit/test_descendant_appends.rb +71 -0
  120. data/test/unit/test_document.rb +213 -0
  121. data/test/unit/test_dynamic_finder.rb +125 -0
  122. data/test/unit/test_embedded_document.rb +644 -0
  123. data/test/unit/test_extensions.rb +380 -0
  124. data/test/unit/test_key.rb +185 -0
  125. data/test/unit/test_keys.rb +55 -0
  126. data/test/unit/test_mongo_mapper.rb +110 -0
  127. data/test/unit/test_pagination.rb +11 -0
  128. data/test/unit/test_plugins.rb +50 -0
  129. data/test/unit/test_rails.rb +181 -0
  130. data/test/unit/test_rails_compatibility.rb +52 -0
  131. data/test/unit/test_serialization.rb +51 -0
  132. data/test/unit/test_time_zones.rb +39 -0
  133. data/test/unit/test_validations.rb +544 -0
  134. metadata +316 -0
@@ -0,0 +1,76 @@
1
+ require 'test_helper'
2
+
3
+ class SafeTest < Test::Unit::TestCase
4
+ context "A Document" do
5
+ should "default safe to off" do
6
+ Doc().should_not be_safe
7
+ end
8
+
9
+ should "allow turning safe on" do
10
+ Doc() { safe }.should be_safe
11
+ end
12
+
13
+ context "inherited with safe setting on" do
14
+ should "set subclass safe setting on" do
15
+ inherited = Class.new(Doc() { safe })
16
+ inherited.should be_safe
17
+ end
18
+ end
19
+
20
+ context "inherited with safe setting off" do
21
+ should "leave subclass safe setting off" do
22
+ inherited = Class.new(Doc())
23
+ inherited.should_not be_safe
24
+ end
25
+ end
26
+ end
27
+
28
+ context "A safe document" do
29
+ setup do
30
+ @klass = Doc() do
31
+ safe
32
+ end
33
+ end
34
+ teardown { drop_indexes(@klass) }
35
+
36
+ context "#save" do
37
+ setup do
38
+ @klass.ensure_index :email, :unique => true
39
+ end
40
+
41
+ context "using safe setting from class" do
42
+ should "work fine when all is well" do
43
+ assert_nothing_raised do
44
+ @klass.new(:email => 'john@doe.com').save
45
+ end
46
+ end
47
+
48
+ should "raise error when operation fails" do
49
+ assert_raises(Mongo::OperationFailure) do
50
+ 2.times do
51
+ @klass.new(:email => 'john@doe.com').save
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ context "overriding safe setting" do
58
+ should "raise error if safe is true" do
59
+ assert_raises(Mongo::OperationFailure) do
60
+ 2.times do
61
+ @klass.new(:email => 'john@doe.com').save(:safe => true)
62
+ end
63
+ end
64
+ end
65
+
66
+ should "not raise error if safe is false" do
67
+ assert_nothing_raised do
68
+ 2.times do
69
+ @klass.new(:email => 'john@doe.com').save(:safe => false)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,230 @@
1
+ require 'test_helper'
2
+
3
+ class SciTest < Test::Unit::TestCase
4
+ context "Single collection inheritance (document)" do
5
+ setup do
6
+ class ::DocParent
7
+ include MongoMapper::Document
8
+ key :name, String
9
+ end
10
+ DocParent.collection.remove
11
+
12
+ class ::DocDaughter < ::DocParent; end
13
+ class ::DocSon < ::DocParent; end
14
+ class ::DocGrandSon < ::DocSon; end
15
+
16
+ DocSon.many :children, :class_name => 'DocGrandSon'
17
+
18
+ @parent = DocParent.new({:name => "Daddy Warbucks"})
19
+ @daughter = DocDaughter.new({:name => "Little Orphan Annie"})
20
+ end
21
+
22
+ teardown do
23
+ Object.send :remove_const, 'DocParent' if defined?(::DocParent)
24
+ Object.send :remove_const, 'DocDaughter' if defined?(::DocDaughter)
25
+ Object.send :remove_const, 'DocSon' if defined?(::DocSon)
26
+ Object.send :remove_const, 'DocGrandSon' if defined?(::DocGrandSon)
27
+ end
28
+
29
+ should "automatically add _type key to store class" do
30
+ DocParent.key?(:_type).should be_true
31
+ end
32
+
33
+ should "use the same collection in the subclass" do
34
+ DocDaughter.collection.name.should == DocParent.collection.name
35
+ end
36
+
37
+ context ".single_collection_inherited?" do
38
+ should "be false if has not inherited" do
39
+ DocParent.should_not be_single_collection_inherited
40
+ end
41
+
42
+ should "be true if inherited" do
43
+ DocDaughter.should be_single_collection_inherited
44
+ DocSon.should be_single_collection_inherited
45
+ DocGrandSon.should be_single_collection_inherited
46
+ end
47
+ end
48
+
49
+ should "set _type on initialize" do
50
+ DocDaughter.new._type.should == 'DocDaughter'
51
+ DocSon.new._type.should == 'DocSon'
52
+ DocGrandSon.new._type.should == 'DocGrandSon'
53
+ end
54
+
55
+ should "set _type based on class and ignore assigned values" do
56
+ DocSon.new(:_type => 'DocDaughter')._type.should == 'DocSon'
57
+ end
58
+
59
+ context "loading" do
60
+ should "be based on _type" do
61
+ @parent.save
62
+ @daughter.save
63
+
64
+ collection = DocParent.all
65
+ collection.size.should == 2
66
+ collection.first.should be_kind_of(DocParent)
67
+ collection.first.name.should == "Daddy Warbucks"
68
+ collection.last.should be_kind_of(DocDaughter)
69
+ collection.last.name.should == "Little Orphan Annie"
70
+ end
71
+
72
+ should "gracefully handle when _type cannot be constantized" do
73
+ doc = DocParent.new(:name => 'Nunes')
74
+ doc._type = 'FoobarBaz'
75
+ doc.save
76
+
77
+ collection = DocParent.all
78
+ collection.last.should == doc
79
+ collection.last.should be_kind_of(DocParent)
80
+ end
81
+ end
82
+
83
+ context "querying" do
84
+ should "find scoped to class" do
85
+ john = DocSon.create(:name => 'John')
86
+ steve = DocSon.create(:name => 'Steve')
87
+ steph = DocDaughter.create(:name => 'Steph')
88
+ carrie = DocDaughter.create(:name => 'Carrie')
89
+
90
+ DocGrandSon.all(:order => 'name').should == []
91
+ DocSon.all(:order => 'name').should == [john, steve]
92
+ DocDaughter.all(:order => 'name').should == [carrie, steph]
93
+ DocParent.all(:order => 'name').should == [carrie, john, steph, steve]
94
+ end
95
+
96
+ should "work with nested hash conditions" do
97
+ john = DocSon.create(:name => 'John')
98
+ steve = DocSon.create(:name => 'Steve')
99
+ DocSon.all(:name => {'$ne' => 'Steve'}).should == [john]
100
+ end
101
+
102
+ should "raise error if not found scoped to class" do
103
+ john = DocSon.create(:name => 'John')
104
+ steph = DocDaughter.create(:name => 'Steph')
105
+
106
+ lambda {
107
+ DocSon.find!(steph._id)
108
+ }.should raise_error(MongoMapper::DocumentNotFound)
109
+ end
110
+
111
+ should "not raise error for find with parent" do
112
+ john = DocSon.create(:name => 'John')
113
+
114
+ DocParent.find!(john._id).should == john
115
+ end
116
+
117
+ should "count scoped to class" do
118
+ john = DocSon.create(:name => 'John')
119
+ steve = DocSon.create(:name => 'Steve')
120
+ steph = DocDaughter.create(:name => 'Steph')
121
+ carrie = DocDaughter.create(:name => 'Carrie')
122
+
123
+ DocGrandSon.count.should == 0
124
+ DocSon.count.should == 2
125
+ DocDaughter.count.should == 2
126
+ DocParent.count.should == 4
127
+ end
128
+
129
+ should "not be able to destroy each other" do
130
+ john = DocSon.create(:name => 'John')
131
+ steph = DocDaughter.create(:name => 'Steph')
132
+
133
+ lambda {
134
+ DocSon.destroy(steph._id)
135
+ }.should raise_error(MongoMapper::DocumentNotFound)
136
+ end
137
+
138
+ should "not be able to delete each other" do
139
+ john = DocSon.create(:name => 'John')
140
+ steph = DocDaughter.create(:name => 'Steph')
141
+
142
+ lambda {
143
+ DocSon.delete(steph._id)
144
+ }.should_not change { DocParent.count }
145
+ end
146
+
147
+ should "be able to destroy using parent" do
148
+ john = DocSon.create(:name => 'John')
149
+ steph = DocDaughter.create(:name => 'Steph')
150
+
151
+ lambda {
152
+ DocParent.destroy_all
153
+ }.should change { DocParent.count }.by(-2)
154
+ end
155
+
156
+ should "be able to delete using parent" do
157
+ john = DocSon.create(:name => 'John')
158
+ steph = DocDaughter.create(:name => 'Steph')
159
+
160
+ lambda {
161
+ DocParent.delete_all
162
+ }.should change { DocParent.count }.by(-2)
163
+ end
164
+ end
165
+
166
+ should "be able to reload single collection inherited parent class" do
167
+ brian = DocParent.create(:name => 'Brian')
168
+ brian.name = 'B-Dawg'
169
+ brian.reload
170
+ brian.name.should == 'Brian'
171
+ end
172
+ end
173
+
174
+ context "Single collection inheritance (embedded document)" do
175
+ setup do
176
+ class ::Grandparent
177
+ include MongoMapper::EmbeddedDocument
178
+ key :grandparent, String
179
+ end
180
+
181
+ class ::Parent < ::Grandparent
182
+ include MongoMapper::EmbeddedDocument
183
+ key :parent, String
184
+ end
185
+
186
+ class ::Child < ::Parent
187
+ include MongoMapper::EmbeddedDocument
188
+ key :child, String
189
+ end
190
+
191
+ class ::OtherChild < ::Parent
192
+ include MongoMapper::EmbeddedDocument
193
+ key :other_child, String
194
+ end
195
+ end
196
+
197
+ teardown do
198
+ Object.send :remove_const, 'Grandparent' if defined?(::Grandparent)
199
+ Object.send :remove_const, 'Parent' if defined?(::Parent)
200
+ Object.send :remove_const, 'Child' if defined?(::Child)
201
+ Object.send :remove_const, 'OtherChild' if defined?(::OtherChild)
202
+ end
203
+
204
+ should "automatically add _type key" do
205
+ Grandparent.key?(:_type).should be_true
206
+ end
207
+
208
+ context ".single_collection_inherited?" do
209
+ should "be false if has not inherited" do
210
+ Grandparent.should_not be_single_collection_inherited
211
+ end
212
+
213
+ should "be true if inherited" do
214
+ Parent.should be_single_collection_inherited
215
+ Child.should be_single_collection_inherited
216
+ OtherChild.should be_single_collection_inherited
217
+ end
218
+ end
219
+
220
+ should "set _type on initialize" do
221
+ Parent.new._type.should == 'Parent'
222
+ Child.new._type.should == 'Child'
223
+ OtherChild.new._type.should == 'OtherChild'
224
+ end
225
+
226
+ should "set _type based on class and ignore assigned values" do
227
+ Child.new(:_type => 'OtherChild')._type.should == 'Child'
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,171 @@
1
+ require 'test_helper'
2
+
3
+ class ScopesTest < Test::Unit::TestCase
4
+ context "Scopes" do
5
+ setup do
6
+ @document = Doc() do
7
+ key :name, String
8
+ key :age, Integer
9
+ timestamps!
10
+ end
11
+ end
12
+
13
+ context "basic scopes" do
14
+ setup do
15
+ @document.class_eval do
16
+ scope :old, :age.gt => 60
17
+ scope :teens, :age.gte => 13, :age.lte => 19
18
+ end
19
+ end
20
+
21
+ should "know what scopes have been added" do
22
+ @document.scopes.size.should == 2
23
+ @document.scopes.keys.map(&:to_s).sort.should == %w(old teens)
24
+ end
25
+
26
+ should "return a plucky query" do
27
+ @document.old.should be_instance_of(Plucky::Query)
28
+ end
29
+
30
+ should "work" do
31
+ @document.create(:name => 'John', :age => 99)
32
+ @document.create(:name => 'Frank', :age => 15)
33
+ docs = @document.old.all
34
+ docs.size.should == 1
35
+ docs[0].name.should == 'John'
36
+ end
37
+ end
38
+
39
+ context "dynamic scopes" do
40
+ setup do
41
+ @document.class_eval do
42
+ scope :age, lambda { |age| {:age => age} }
43
+ scope :ages, lambda { |low, high| {:age.gte => low, :age.lte => high} }
44
+ scope :ordered, lambda { |sort| sort(sort) }
45
+ end
46
+ end
47
+
48
+ should "work with single argument" do
49
+ @document.create(:name => 'John', :age => 60)
50
+ @document.create(:name => 'Frank', :age => 50)
51
+ docs = @document.age(60).all
52
+ docs.size.should == 1
53
+ docs.first.name.should == 'John'
54
+ end
55
+
56
+ should "work with multiple arguments" do
57
+ @document.create(:name => 'John', :age => 60)
58
+ @document.create(:name => 'Frank', :age => 50)
59
+ @document.create(:name => 'Bill', :age => 40)
60
+ docs = @document.ages(50, 70).all
61
+ docs.size.should == 2
62
+ docs.map(&:name).sort.should == %w(Frank John)
63
+ end
64
+
65
+ should "work with queries" do
66
+ john = @document.create(:name => 'John', :age => 60)
67
+ frank = @document.create(:name => 'Frank', :age => 50)
68
+ bill = @document.create(:name => 'Bill', :age => 40)
69
+ @document.ordered(:age).all.should == [bill, frank, john]
70
+ end
71
+ end
72
+
73
+ context "query scopes" do
74
+ setup do
75
+ @document.class_eval do
76
+ scope :boomers, where(:age.gte => 60).sort(:age)
77
+ end
78
+ end
79
+
80
+ should "work" do
81
+ todd = @document.create(:name => 'Todd', :age => 65)
82
+ john = @document.create(:name => 'John', :age => 60)
83
+ @document.create(:name => 'Frank', :age => 50)
84
+ @document.create(:name => 'Bill', :age => 40)
85
+ docs = @document.boomers.all
86
+ docs[0].should == john
87
+ docs[1].should == todd
88
+ end
89
+ end
90
+
91
+ context "chaining" do
92
+ setup do
93
+ @document.class_eval do
94
+ scope :by_age, lambda { |age| {:age => age} }
95
+ scope :by_name, lambda { |name| {:name => name} }
96
+ end
97
+ end
98
+
99
+ should "work with scope methods" do
100
+ @document.create(:name => 'John', :age => 60)
101
+ @document.create(:name => 'Frank', :age => 60)
102
+ @document.create(:name => 'Bill', :age => 50)
103
+ docs = @document.by_age(60).by_name('John').all
104
+ docs.size.should == 1
105
+ docs.first.name.should == 'John'
106
+ end
107
+
108
+ should "work on query methods" do
109
+ @document.create(:name => 'John', :age => 60)
110
+ @document.create(:name => 'John', :age => 50)
111
+ @document.create(:name => 'Bill', :age => 50)
112
+ docs = @document.where(:name => 'John').by_age(50).all
113
+ docs.size.should == 1
114
+ docs.first.age.should == 50
115
+ end
116
+
117
+ context "with model methods" do
118
+ should "work if method returns a query" do
119
+ @document.create(:name => 'John', :age => 10)
120
+ @document.create(:name => 'John', :age => 20)
121
+ @document.class_eval do
122
+ def self.young
123
+ query(:age.lte => 12)
124
+ end
125
+ end
126
+ docs = @document.by_name('John').young.all
127
+ docs.size.should == 1
128
+ docs.first.age.should == 10
129
+ end
130
+
131
+ should "not work if method does not return a query" do
132
+ @document.class_eval { def self.age; 20 end }
133
+ lambda { @document.by_name('John').age }.should raise_error(NoMethodError)
134
+ end
135
+ end
136
+ end
137
+
138
+ context "with single collection inheritance" do
139
+ setup do
140
+ class ::Item
141
+ include MongoMapper::Document
142
+ scope :by_title, lambda { |title| {:title => title} }
143
+ scope :published, lambda { {:published_at.lte => Time.now.utc} }
144
+
145
+ key :title, String
146
+ key :published_at, Time
147
+ end
148
+ Item.collection.remove
149
+
150
+ class ::Page < ::Item; end
151
+ class ::Blog < ::Item; end
152
+ end
153
+
154
+ teardown do
155
+ Object.send :remove_const, 'Item' if defined?(::Item)
156
+ Object.send :remove_const, 'Page' if defined?(::Page)
157
+ Object.send :remove_const, 'Blog' if defined?(::Blog)
158
+ end
159
+
160
+ should "inherit scopes" do
161
+ Page.scopes.keys.map(&:to_s).sort.should == %w(by_title published)
162
+ end
163
+
164
+ should "work with _type" do
165
+ item = Item.create(:title => 'Home')
166
+ page = Page.create(:title => 'Home')
167
+ Page.by_title('Home').first.should == page
168
+ end
169
+ end
170
+ end
171
+ end