mongodoc 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/README.textile +143 -0
  2. data/Rakefile +35 -3
  3. data/VERSION +1 -1
  4. data/examples/simple_document.rb +35 -0
  5. data/examples/simple_object.rb +32 -0
  6. data/features/finders.feature +72 -0
  7. data/features/mongodoc_base.feature +12 -2
  8. data/features/named_scopes.feature +66 -0
  9. data/features/new_record.feature +36 -0
  10. data/features/partial_updates.feature +105 -0
  11. data/features/step_definitions/criteria_steps.rb +4 -41
  12. data/features/step_definitions/document_steps.rb +56 -5
  13. data/features/step_definitions/documents.rb +14 -3
  14. data/features/step_definitions/finder_steps.rb +15 -0
  15. data/features/step_definitions/named_scope_steps.rb +18 -0
  16. data/features/step_definitions/partial_update_steps.rb +32 -0
  17. data/features/step_definitions/query_steps.rb +51 -0
  18. data/features/using_criteria.feature +5 -1
  19. data/lib/mongodoc/attributes.rb +76 -63
  20. data/lib/mongodoc/collection.rb +9 -9
  21. data/lib/mongodoc/criteria.rb +152 -161
  22. data/lib/mongodoc/cursor.rb +7 -5
  23. data/lib/mongodoc/document.rb +95 -31
  24. data/lib/mongodoc/finders.rb +29 -0
  25. data/lib/mongodoc/named_scope.rb +68 -0
  26. data/lib/mongodoc/parent_proxy.rb +15 -6
  27. data/lib/mongodoc/proxy.rb +22 -13
  28. data/lib/mongodoc.rb +3 -3
  29. data/mongodoc.gemspec +42 -14
  30. data/perf/mongodoc_runner.rb +90 -0
  31. data/perf/ruby_driver_runner.rb +64 -0
  32. data/spec/attributes_spec.rb +46 -12
  33. data/spec/collection_spec.rb +23 -23
  34. data/spec/criteria_spec.rb +124 -187
  35. data/spec/cursor_spec.rb +21 -17
  36. data/spec/document_ext.rb +2 -2
  37. data/spec/document_spec.rb +187 -218
  38. data/spec/embedded_save_spec.rb +104 -0
  39. data/spec/finders_spec.rb +81 -0
  40. data/spec/hash_matchers.rb +27 -0
  41. data/spec/named_scope_spec.rb +82 -0
  42. data/spec/new_record_spec.rb +216 -0
  43. data/spec/parent_proxy_spec.rb +8 -6
  44. data/spec/proxy_spec.rb +80 -0
  45. data/spec/spec_helper.rb +2 -0
  46. metadata +35 -7
  47. data/README.rdoc +0 -75
@@ -0,0 +1,68 @@
1
+ # Based on ActiveRecord::NamedScope
2
+ module MongoDoc
3
+ module NamedScope
4
+ def scopes
5
+ read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
6
+ end
7
+
8
+ def named_scope(name, options = {}, &block)
9
+ name = name.to_sym
10
+ scopes[name] = lambda do |parent_scope, *args|
11
+ CriteriaProxy.new(parent_scope, Hash === options ? options : options.call(*args), &block)
12
+ end
13
+ (class << self; self; end).class_eval <<-EOT
14
+ def #{name}(*args)
15
+ scopes[:#{name}].call(self, *args)
16
+ end
17
+ EOT
18
+ end
19
+
20
+ class CriteriaProxy
21
+ attr_accessor :conditions, :klass, :parent_scope
22
+
23
+ delegate :scopes, :to => :parent_scope
24
+
25
+ def initialize(parent_scope, conditions, &block)
26
+ conditions ||= {}
27
+ [conditions.delete(:extend)].flatten.each { |extension| extend extension } if conditions.include?(:extend)
28
+ extend Module.new(&block) if block_given?
29
+ self.klass = parent_scope unless CriteriaProxy === parent_scope
30
+ self.parent_scope, self.conditions = parent_scope, conditions
31
+ end
32
+
33
+ def respond_to?(method, include_private = false)
34
+ super || if klass
35
+ proxy_found.respond_to?(method, include_private)
36
+ else
37
+ parent_scope.respond_to?(method, include_private)
38
+ end
39
+ end
40
+
41
+ protected
42
+
43
+ def proxy_found
44
+ @found || load_found
45
+ end
46
+
47
+ private
48
+
49
+ def method_missing(method, *args, &block)
50
+ if scopes.include?(method)
51
+ scopes[method].call(self, *args)
52
+ elsif klass
53
+ proxy_found.send(method, *args, &block)
54
+ else
55
+ parent_scope.criteria(conditions)
56
+ parent_scope.send(method, *args, &block)
57
+ end
58
+ end
59
+
60
+ def load_found
61
+ @found = Criteria.new(klass)
62
+ @found.criteria(conditions)
63
+ @found
64
+ end
65
+ end
66
+ end
67
+ end
68
+
@@ -9,12 +9,21 @@ module MongoDoc
9
9
  @assoc_name = assoc_name
10
10
  end
11
11
 
12
- def path_to_root(attrs)
13
- assoc_attrs = attrs.inject({}) do |assoc_attrs, (key, value)|
14
- assoc_attrs["#{assoc_name}.#{key}"] = value
15
- assoc_attrs
12
+ def _path_to_root(src, attrs)
13
+ _parent._path_to_root(src, _annotated_keys(attrs))
14
+ end
15
+
16
+ def _selector_path_to_root(selector)
17
+ _parent._selector_path_to_root(_annotated_keys(selector))
18
+ end
19
+
20
+ protected
21
+
22
+ def _annotated_keys(hash)
23
+ hash.inject({}) do |annotated, (key, value)|
24
+ annotated["#{assoc_name}.#{key}"] = value
25
+ annotated
16
26
  end
17
- _parent.path_to_root(assoc_attrs)
18
27
  end
19
28
 
20
29
  private
@@ -32,4 +41,4 @@ module MongoDoc
32
41
  end
33
42
  end
34
43
  end
35
- end
44
+ end
@@ -39,15 +39,14 @@ module MongoDoc
39
39
  end
40
40
 
41
41
  alias_method :append, :<<
42
- def <<(items)
43
- items = [items] unless items.kind_of?(Array)
44
- items.each do |item|
45
- item = collection_class.new(item) if Hash === item
46
- raise NotADocumentError unless collection_class === item
47
- append item
42
+ def <<(item)
43
+ item = build(item) if Hash === item
44
+ if Document === item
48
45
  item._parent = self
49
46
  item._root = _root
47
+ _root.send(:register_save_observer, item)
50
48
  end
49
+ append item
51
50
  self
52
51
  end
53
52
  alias_method :push, :<<
@@ -60,15 +59,25 @@ module MongoDoc
60
59
  end
61
60
  alias kind_of? is_a?
62
61
 
63
- def path_to_root(attrs)
64
- _parent.path_to_root(attrs)
62
+ def _path_to_root(src, attrs)
63
+ assoc_path = "#{assoc_name}.#{index(src)}"
64
+ assoc_attrs = attrs.inject({}) do |assoc_attrs, (key, value)|
65
+ assoc_attrs["#{assoc_path}.#{key}"] = value
66
+ assoc_attrs
67
+ end
68
+ _parent._path_to_root(src, assoc_attrs)
65
69
  end
66
70
 
67
- protected
71
+ def _selector_path_to_root(selector)
72
+ annotated_selector = selector.inject({}) do |annotated, (key, value)|
73
+ annotated["#{assoc_name}.#{key}"] = value
74
+ annotated
75
+ end
76
+ _parent._selector_path_to_root(annotated_selector)
77
+ end
68
78
 
69
- def _propose_update_attributes(src, attrs, safe)
70
- src.errors.add(:base, 'update_attributes called through a has_many')
71
- false
79
+ def build(attrs)
80
+ collection_class.new(attrs)
72
81
  end
73
82
  end
74
- end
83
+ end
data/lib/mongodoc.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require 'rubygems'
2
2
 
3
- gem 'mongo', '0.18.1'
4
- gem 'mongo_ext', '0.18.1'
5
- gem 'durran-validatable', '1.8.3'
3
+ gem 'mongo', '0.18.2'
4
+ gem 'mongo_ext', '0.18.2'
5
+ gem 'durran-validatable', '2.0.1'
6
6
  gem 'leshill-will_paginate', '2.3.11'
7
7
 
8
8
  require 'mongo'
data/mongodoc.gemspec CHANGED
@@ -5,35 +5,45 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongodoc}
8
- s.version = "0.1.2"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Les Hill"]
12
- s.date = %q{2009-12-10}
12
+ s.date = %q{2010-01-18}
13
13
  s.description = %q{ODM for MongoDB}
14
14
  s.email = %q{leshill@gmail.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.rdoc"
17
+ "README.textile"
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
21
  ".gitignore",
22
22
  "LICENSE",
23
- "README.rdoc",
23
+ "README.textile",
24
24
  "Rakefile",
25
25
  "VERSION",
26
26
  "data/.gitignore",
27
+ "examples/simple_document.rb",
28
+ "examples/simple_object.rb",
29
+ "features/finders.feature",
27
30
  "features/mongodb.yml",
28
31
  "features/mongodoc_base.feature",
32
+ "features/named_scopes.feature",
33
+ "features/new_record.feature",
34
+ "features/partial_updates.feature",
29
35
  "features/saving_an_object.feature",
30
36
  "features/step_definitions/collection_steps.rb",
31
37
  "features/step_definitions/criteria_steps.rb",
32
38
  "features/step_definitions/document_steps.rb",
33
39
  "features/step_definitions/documents.rb",
40
+ "features/step_definitions/finder_steps.rb",
34
41
  "features/step_definitions/json_steps.rb",
42
+ "features/step_definitions/named_scope_steps.rb",
35
43
  "features/step_definitions/object_steps.rb",
36
44
  "features/step_definitions/objects.rb",
45
+ "features/step_definitions/partial_update_steps.rb",
46
+ "features/step_definitions/query_steps.rb",
37
47
  "features/step_definitions/util_steps.rb",
38
48
  "features/support/support.rb",
39
49
  "features/using_criteria.feature",
@@ -60,12 +70,16 @@ Gem::Specification.new do |s|
60
70
  "lib/mongodoc/ext/string.rb",
61
71
  "lib/mongodoc/ext/symbol.rb",
62
72
  "lib/mongodoc/ext/time.rb",
73
+ "lib/mongodoc/finders.rb",
74
+ "lib/mongodoc/named_scope.rb",
63
75
  "lib/mongodoc/parent_proxy.rb",
64
76
  "lib/mongodoc/proxy.rb",
65
77
  "lib/mongodoc/query.rb",
66
78
  "mongod.example.yml",
67
79
  "mongodb.example.yml",
68
80
  "mongodoc.gemspec",
81
+ "perf/mongodoc_runner.rb",
82
+ "perf/ruby_driver_runner.rb",
69
83
  "script/console",
70
84
  "spec/attributes_spec.rb",
71
85
  "spec/bson_matchers.rb",
@@ -76,9 +90,15 @@ Gem::Specification.new do |s|
76
90
  "spec/cursor_spec.rb",
77
91
  "spec/document_ext.rb",
78
92
  "spec/document_spec.rb",
93
+ "spec/embedded_save_spec.rb",
94
+ "spec/finders_spec.rb",
95
+ "spec/hash_matchers.rb",
79
96
  "spec/mongodb.yml",
80
97
  "spec/mongodb_pairs.yml",
98
+ "spec/named_scope_spec.rb",
99
+ "spec/new_record_spec.rb",
81
100
  "spec/parent_proxy_spec.rb",
101
+ "spec/proxy_spec.rb",
82
102
  "spec/query_spec.rb",
83
103
  "spec/spec.opts",
84
104
  "spec/spec_helper.rb"
@@ -98,9 +118,17 @@ Gem::Specification.new do |s|
98
118
  "spec/cursor_spec.rb",
99
119
  "spec/document_ext.rb",
100
120
  "spec/document_spec.rb",
121
+ "spec/embedded_save_spec.rb",
122
+ "spec/finders_spec.rb",
123
+ "spec/hash_matchers.rb",
124
+ "spec/named_scope_spec.rb",
125
+ "spec/new_record_spec.rb",
101
126
  "spec/parent_proxy_spec.rb",
127
+ "spec/proxy_spec.rb",
102
128
  "spec/query_spec.rb",
103
- "spec/spec_helper.rb"
129
+ "spec/spec_helper.rb",
130
+ "examples/simple_document.rb",
131
+ "examples/simple_object.rb"
104
132
  ]
105
133
 
106
134
  if s.respond_to? :specification_version then
@@ -108,24 +136,24 @@ Gem::Specification.new do |s|
108
136
  s.specification_version = 3
109
137
 
110
138
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
111
- s.add_runtime_dependency(%q<mongo>, ["= 0.18.1"])
112
- s.add_runtime_dependency(%q<mongo_ext>, ["= 0.18.1"])
113
- s.add_runtime_dependency(%q<durran-validatable>, ["= 1.8.3"])
139
+ s.add_runtime_dependency(%q<mongo>, ["= 0.18.2"])
140
+ s.add_runtime_dependency(%q<mongo_ext>, ["= 0.18.2"])
141
+ s.add_runtime_dependency(%q<durran-validatable>, ["= 1.8.4"])
114
142
  s.add_runtime_dependency(%q<leshill-will_paginate>, ["= 2.3.11"])
115
143
  s.add_development_dependency(%q<rspec>, ["= 1.2.9"])
116
144
  s.add_development_dependency(%q<cucumber>, ["= 0.4.4"])
117
145
  else
118
- s.add_dependency(%q<mongo>, ["= 0.18.1"])
119
- s.add_dependency(%q<mongo_ext>, ["= 0.18.1"])
120
- s.add_dependency(%q<durran-validatable>, ["= 1.8.3"])
146
+ s.add_dependency(%q<mongo>, ["= 0.18.2"])
147
+ s.add_dependency(%q<mongo_ext>, ["= 0.18.2"])
148
+ s.add_dependency(%q<durran-validatable>, ["= 1.8.4"])
121
149
  s.add_dependency(%q<leshill-will_paginate>, ["= 2.3.11"])
122
150
  s.add_dependency(%q<rspec>, ["= 1.2.9"])
123
151
  s.add_dependency(%q<cucumber>, ["= 0.4.4"])
124
152
  end
125
153
  else
126
- s.add_dependency(%q<mongo>, ["= 0.18.1"])
127
- s.add_dependency(%q<mongo_ext>, ["= 0.18.1"])
128
- s.add_dependency(%q<durran-validatable>, ["= 1.8.3"])
154
+ s.add_dependency(%q<mongo>, ["= 0.18.2"])
155
+ s.add_dependency(%q<mongo_ext>, ["= 0.18.2"])
156
+ s.add_dependency(%q<durran-validatable>, ["= 1.8.4"])
129
157
  s.add_dependency(%q<leshill-will_paginate>, ["= 2.3.11"])
130
158
  s.add_dependency(%q<rspec>, ["= 1.2.9"])
131
159
  s.add_dependency(%q<cucumber>, ["= 0.4.4"])
@@ -0,0 +1,90 @@
1
+ require "benchmark"
2
+ require "ruby-prof"
3
+ require "mongodoc"
4
+
5
+ class Person < MongoDoc::Document
6
+ key :birth_date
7
+ has_one :name
8
+ has_one :address
9
+ has_many :phones
10
+ end
11
+
12
+ class Name < MongoDoc::Document
13
+ key :given
14
+ key :family
15
+ key :middle
16
+ end
17
+
18
+ class Address < MongoDoc::Document
19
+ key :street
20
+ key :city
21
+ key :state
22
+ key :post_code
23
+ key :type
24
+ end
25
+
26
+ class Phone < MongoDoc::Document
27
+ key :country_code
28
+ key :number
29
+ key :type
30
+ end
31
+
32
+ class MongoDocRunner
33
+ def self.benchmark
34
+ MongoDoc.connect_to_database('mongodoc_perf_test')
35
+ MongoDoc.database.collection('people').drop
36
+
37
+ puts "Starting benchmark..."
38
+
39
+ 10.times do |n|
40
+ person = Person.new(:birth_date => Date.new(1970, 1, 1))
41
+ name = Name.new(:given => "James", :family => "Kirk", :middle => "Tiberius")
42
+ address = Address.new(:street => "1 Starfleet Command Way", :city => "San Francisco", :state => "CA", :post_code => "94133", :type => "Work")
43
+ phone = Phone.new(:country_code => 1, :number => "415-555-1212", :type => "Mobile")
44
+ person.name = name
45
+ person.address = address
46
+ person.phones << phone
47
+ person.save
48
+ end
49
+
50
+ Benchmark.bm do |bm|
51
+ bm.report('MongoDoc') do
52
+ 10000.times do |n|
53
+ person = Person.new(:birth_date => Date.new(1970, 1, 1))
54
+ name = Name.new(:given => "James", :family => "Kirk", :middle => "Tiberius")
55
+ address = Address.new(:street => "1 Starfleet Command Way", :city => "San Francisco", :state => "CA", :post_code => "94133", :type => "Work")
56
+ phone = Phone.new(:country_code => 1, :number => "415-555-1212", :type => "Mobile")
57
+ person.name = name
58
+ person.address = address
59
+ person.phones << phone
60
+ person.save
61
+ end
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ def self.profile
68
+ MongoDoc.connect_to_database('mongodoc_perf_test')
69
+ MongoDoc.database.collection('people').drop
70
+
71
+ RubyProf.start
72
+
73
+ puts "Starting profiler..."
74
+
75
+ 1000.times do |n|
76
+ person = Person.new(:birth_date => Date.new(1970, 1, 1))
77
+ name = Name.new(:given => "James", :family => "Kirk", :middle => "Tiberius")
78
+ address = Address.new(:street => "1 Starfleet Command Way", :city => "San Francisco", :state => "CA", :post_code => "94133", :type => "Work")
79
+ phone = Phone.new(:country_code => 1, :number => "415-555-1212", :type => "Mobile")
80
+ person.name = name
81
+ person.address = address
82
+ person.phones << phone
83
+ person.save
84
+ end
85
+
86
+ result = RubyProf.stop
87
+ printer = RubyProf::FlatPrinter.new(result)
88
+ printer.print(STDOUT, 0)
89
+ end
90
+ end
@@ -0,0 +1,64 @@
1
+ require "rubygems"
2
+ require "ruby-prof"
3
+ require "mongodoc"
4
+
5
+ class RubyDriverRunner
6
+ def self.benchmark
7
+ MongoDoc.connect_to_database('mongodoc_perf_test')
8
+ collection = MongoDoc.database.collection('people')
9
+ collection.drop
10
+
11
+ puts "Starting benchmark..."
12
+
13
+ 10.times do |n|
14
+ person = {:birth_date => Date.new(1970, 1, 1).to_bson, :phones => []}
15
+ name = {:given => "James", :family => "Kirk", :middle => "Tiberius"}
16
+ address = {:street => "1 Starfleet Command Way", :city => "San Francisco", :state => "CA", :post_code => "94133", :type => "Work"}
17
+ phone = {:country_code => 1, :number => "415-555-1212", :type => "Mobile"}
18
+ person[:name] = name
19
+ person[:address] = address
20
+ person[:phones] << phone
21
+ collection.save(person)
22
+ end
23
+
24
+ Benchmark.bm do |bm|
25
+ bm.report('Driver') do
26
+ 10000.times do |n|
27
+ person = {:birth_date => Date.new(1970, 1, 1).to_bson, :phones => []}
28
+ name = {:given => "James", :family => "Kirk", :middle => "Tiberius"}
29
+ address = {:street => "1 Starfleet Command Way", :city => "San Francisco", :state => "CA", :post_code => "94133", :type => "Work"}
30
+ phone = {:country_code => 1, :number => "415-555-1212", :type => "Mobile"}
31
+ person[:name] = name
32
+ person[:address] = address
33
+ person[:phones] << phone
34
+ collection.save(person)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ def self.profile
41
+ MongoDoc.connect_to_database('mongodoc_perf_test')
42
+ collection = MongoDoc.database.collection('people')
43
+ collection.drop
44
+
45
+ RubyProf.start
46
+
47
+ puts "Starting profiler..."
48
+
49
+ 1000.times do |n|
50
+ person = {:birth_date => Date.new(1970, 1, 1), :phones => []}
51
+ name = {:given => "James", :family => "Kirk", :middle => "Tiberius"}
52
+ address = { :street => "1 Starfleet Command Way", :city => "San Francisco", :state => "CA", :post_code => "94133", :type => "Work"}
53
+ phone = {:country_code => 1, :number => "415-555-1212", :type => "Mobile"}
54
+ person[:name] = name
55
+ person[:address] = address
56
+ person[:phones] << phone
57
+ collection.insert(person)
58
+ end
59
+
60
+ result = RubyProf.stop
61
+ printer = RubyProf::FlatPrinter.new(result)
62
+ printer.print(STDOUT, 0)
63
+ end
64
+ end
@@ -1,8 +1,18 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe "MongoDoc::Attributes" do
4
+ class AttributesTest
5
+ include MongoDoc::Attributes
6
+ end
7
+
8
+ it "defines _id attribute" do
9
+ AttributesTest.new.should respond_to(:_id)
10
+ AttributesTest.new.should respond_to(:_id=)
11
+ end
12
+
4
13
  context ".key" do
5
- class TestKeys < MongoDoc::Document
14
+ class TestKeys
15
+ include MongoDoc::Document
6
16
  end
7
17
 
8
18
  it "adds its arguments to _keys" do
@@ -28,7 +38,9 @@ describe "MongoDoc::Attributes" do
28
38
  end
29
39
 
30
40
  describe "used with inheritance" do
31
- class TestParent < MongoDoc::Document
41
+ class TestParent
42
+ include MongoDoc::Document
43
+
32
44
  key :parent_attr
33
45
  end
34
46
 
@@ -43,15 +55,23 @@ describe "MongoDoc::Attributes" do
43
55
  it "has the keys from the parent class" do
44
56
  TestChild._keys.should include(*TestParent._keys)
45
57
  end
58
+
59
+ it "does not add keys to the parent class" do
60
+ TestParent._keys.should_not include(:child_attr)
61
+ end
46
62
  end
47
63
  end
48
64
 
49
65
  context ".has_one" do
50
- class TestDoc < MongoDoc::Document
66
+ class TestDoc
67
+ include MongoDoc::Document
68
+
51
69
  has_one :subdoc
52
70
  end
53
71
 
54
- class SubDoc < MongoDoc::Document
72
+ class SubDoc
73
+ include MongoDoc::Document
74
+
55
75
  key :data
56
76
  end
57
77
 
@@ -77,7 +97,9 @@ describe "MongoDoc::Attributes" do
77
97
  subdoc._root.should == doc
78
98
  end
79
99
 
80
- class HasOneValidationTest < MongoDoc::Document
100
+ class HasOneValidationTest
101
+ include MongoDoc::Document
102
+
81
103
  key :data
82
104
  validates_presence_of :data
83
105
  end
@@ -90,7 +112,9 @@ describe "MongoDoc::Attributes" do
90
112
  end
91
113
 
92
114
  context "._attributes" do
93
- class TestHasOneDoc < MongoDoc::Document
115
+ class TestHasOneDoc
116
+ include MongoDoc::Document
117
+
94
118
  key :key
95
119
  has_one :has_one
96
120
  end
@@ -102,15 +126,21 @@ describe "MongoDoc::Attributes" do
102
126
 
103
127
  context ".has_many" do
104
128
 
105
- class SubHasManyDoc < MongoDoc::Document
129
+ class SubHasManyDoc
130
+ include MongoDoc::Document
131
+
106
132
  key :data
107
133
  end
108
134
 
109
- class TestHasManyDoc < MongoDoc::Document
135
+ class TestHasManyDoc
136
+ include MongoDoc::Document
137
+
110
138
  has_many :sub_docs, :class_name => 'SubHasManyDoc'
111
139
  end
112
140
 
113
- class TestImplicitHasManyDoc < MongoDoc::Document
141
+ class TestImplicitHasManyDoc
142
+ include MongoDoc::Document
143
+
114
144
  has_many :sub_has_many_docs
115
145
  end
116
146
 
@@ -135,12 +165,16 @@ describe "MongoDoc::Attributes" do
135
165
  doc = TestImplicitHasManyDoc.new(:sub_has_many_docs => [subdoc])
136
166
  end
137
167
 
138
- class HasManyValidationChild < MongoDoc::Document
168
+ class HasManyValidationChild
169
+ include MongoDoc::Document
170
+
139
171
  key :data
140
172
  validates_presence_of :data
141
173
  end
142
174
 
143
- class HasManyValidationTest < MongoDoc::Document
175
+ class HasManyValidationTest
176
+ include MongoDoc::Document
177
+
144
178
  has_many :subdocs, :class_name => 'HasManyValidationChild'
145
179
  end
146
180
 
@@ -156,4 +190,4 @@ describe "MongoDoc::Attributes" do
156
190
  invalid.should have(1).error_on(:data)
157
191
  end
158
192
  end
159
- end
193
+ end