mongo_doc 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. data/.document +5 -0
  2. data/.gitignore +7 -0
  3. data/LICENSE +20 -0
  4. data/README.textile +174 -0
  5. data/Rakefile +135 -0
  6. data/TODO +31 -0
  7. data/VERSION +1 -0
  8. data/data/.gitignore +2 -0
  9. data/examples/simple_document.rb +35 -0
  10. data/examples/simple_object.rb +30 -0
  11. data/features/finders.feature +76 -0
  12. data/features/mongodb.yml +7 -0
  13. data/features/mongodoc_base.feature +128 -0
  14. data/features/new_record.feature +36 -0
  15. data/features/partial_updates.feature +105 -0
  16. data/features/removing_documents.feature +68 -0
  17. data/features/saving_an_object.feature +15 -0
  18. data/features/scopes.feature +66 -0
  19. data/features/step_definitions/collection_steps.rb +14 -0
  20. data/features/step_definitions/document_steps.rb +149 -0
  21. data/features/step_definitions/documents.rb +30 -0
  22. data/features/step_definitions/finder_steps.rb +15 -0
  23. data/features/step_definitions/json_steps.rb +9 -0
  24. data/features/step_definitions/object_steps.rb +50 -0
  25. data/features/step_definitions/objects.rb +24 -0
  26. data/features/step_definitions/partial_update_steps.rb +32 -0
  27. data/features/step_definitions/query_steps.rb +54 -0
  28. data/features/step_definitions/removing_documents_steps.rb +14 -0
  29. data/features/step_definitions/scope_steps.rb +18 -0
  30. data/features/step_definitions/util_steps.rb +7 -0
  31. data/features/support/support.rb +10 -0
  32. data/features/using_criteria.feature +128 -0
  33. data/lib/mongo_doc/associations/collection_proxy.rb +105 -0
  34. data/lib/mongo_doc/associations/document_proxy.rb +56 -0
  35. data/lib/mongo_doc/associations/hash_proxy.rb +98 -0
  36. data/lib/mongo_doc/associations/proxy_base.rb +53 -0
  37. data/lib/mongo_doc/attributes.rb +140 -0
  38. data/lib/mongo_doc/bson.rb +45 -0
  39. data/lib/mongo_doc/collection.rb +55 -0
  40. data/lib/mongo_doc/connection.rb +88 -0
  41. data/lib/mongo_doc/contexts/enumerable.rb +128 -0
  42. data/lib/mongo_doc/contexts/ids.rb +41 -0
  43. data/lib/mongo_doc/contexts/mongo.rb +232 -0
  44. data/lib/mongo_doc/contexts.rb +25 -0
  45. data/lib/mongo_doc/criteria.rb +38 -0
  46. data/lib/mongo_doc/cursor.rb +32 -0
  47. data/lib/mongo_doc/document.rb +216 -0
  48. data/lib/mongo_doc/ext/array.rb +5 -0
  49. data/lib/mongo_doc/ext/binary.rb +7 -0
  50. data/lib/mongo_doc/ext/boolean_class.rb +11 -0
  51. data/lib/mongo_doc/ext/date.rb +16 -0
  52. data/lib/mongo_doc/ext/date_time.rb +13 -0
  53. data/lib/mongo_doc/ext/dbref.rb +7 -0
  54. data/lib/mongo_doc/ext/hash.rb +7 -0
  55. data/lib/mongo_doc/ext/nil_class.rb +5 -0
  56. data/lib/mongo_doc/ext/numeric.rb +17 -0
  57. data/lib/mongo_doc/ext/object.rb +17 -0
  58. data/lib/mongo_doc/ext/object_id.rb +7 -0
  59. data/lib/mongo_doc/ext/regexp.rb +5 -0
  60. data/lib/mongo_doc/ext/string.rb +5 -0
  61. data/lib/mongo_doc/ext/symbol.rb +5 -0
  62. data/lib/mongo_doc/ext/time.rb +5 -0
  63. data/lib/mongo_doc/finders.rb +49 -0
  64. data/lib/mongo_doc/matchers.rb +35 -0
  65. data/lib/mongo_doc/query.rb +7 -0
  66. data/lib/mongo_doc/scope.rb +64 -0
  67. data/lib/mongo_doc/validations/macros.rb +11 -0
  68. data/lib/mongo_doc/validations/validates_embedded.rb +13 -0
  69. data/lib/mongo_doc.rb +19 -0
  70. data/lib/mongoid/contexts/paging.rb +42 -0
  71. data/lib/mongoid/criteria.rb +247 -0
  72. data/lib/mongoid/criterion/complex.rb +21 -0
  73. data/lib/mongoid/criterion/exclusion.rb +65 -0
  74. data/lib/mongoid/criterion/inclusion.rb +92 -0
  75. data/lib/mongoid/criterion/optional.rb +136 -0
  76. data/lib/mongoid/extensions/hash/criteria_helpers.rb +20 -0
  77. data/lib/mongoid/extensions/symbol/inflections.rb +36 -0
  78. data/lib/mongoid/matchers/all.rb +11 -0
  79. data/lib/mongoid/matchers/default.rb +26 -0
  80. data/lib/mongoid/matchers/exists.rb +13 -0
  81. data/lib/mongoid/matchers/gt.rb +11 -0
  82. data/lib/mongoid/matchers/gte.rb +11 -0
  83. data/lib/mongoid/matchers/in.rb +11 -0
  84. data/lib/mongoid/matchers/lt.rb +11 -0
  85. data/lib/mongoid/matchers/lte.rb +11 -0
  86. data/lib/mongoid/matchers/ne.rb +11 -0
  87. data/lib/mongoid/matchers/nin.rb +11 -0
  88. data/lib/mongoid/matchers/size.rb +11 -0
  89. data/mongo_doc.gemspec +205 -0
  90. data/mongod.example.yml +2 -0
  91. data/mongodb.example.yml +14 -0
  92. data/perf/mongo_doc_runner.rb +90 -0
  93. data/perf/ruby_driver_runner.rb +64 -0
  94. data/script/console +8 -0
  95. data/spec/associations/collection_proxy_spec.rb +200 -0
  96. data/spec/associations/document_proxy_spec.rb +42 -0
  97. data/spec/associations/hash_proxy_spec.rb +163 -0
  98. data/spec/attributes_spec.rb +273 -0
  99. data/spec/bson_matchers.rb +54 -0
  100. data/spec/bson_spec.rb +196 -0
  101. data/spec/collection_spec.rb +161 -0
  102. data/spec/connection_spec.rb +147 -0
  103. data/spec/contexts/enumerable_spec.rb +274 -0
  104. data/spec/contexts/ids_spec.rb +49 -0
  105. data/spec/contexts/mongo_spec.rb +198 -0
  106. data/spec/contexts_spec.rb +28 -0
  107. data/spec/criteria_spec.rb +33 -0
  108. data/spec/cursor_spec.rb +91 -0
  109. data/spec/document_ext.rb +9 -0
  110. data/spec/document_spec.rb +664 -0
  111. data/spec/embedded_save_spec.rb +109 -0
  112. data/spec/finders_spec.rb +73 -0
  113. data/spec/hash_matchers.rb +27 -0
  114. data/spec/matchers_spec.rb +342 -0
  115. data/spec/mongodb.yml +6 -0
  116. data/spec/mongodb_pairs.yml +8 -0
  117. data/spec/new_record_spec.rb +128 -0
  118. data/spec/query_spec.rb +12 -0
  119. data/spec/scope_spec.rb +79 -0
  120. data/spec/spec.opts +2 -0
  121. data/spec/spec_helper.rb +13 -0
  122. metadata +290 -0
@@ -0,0 +1,36 @@
1
+ Feature: New record
2
+
3
+ Scenario: saving a has_many children document
4
+ Given an empty Contact document collection
5
+ And a Contact document named 'hashrocket' :
6
+ | Name |
7
+ | Hashrocket |
8
+ And 'hashrocket' has many addresses :
9
+ | Street | City | State | Zip Code |
10
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
11
+ | 1 Main Street | Santiago | Chile | |
12
+ When I save the document 'hashrocket'
13
+ Then the first address of 'hashrocket' is not a new record
14
+
15
+ Scenario: saving a has_one child document
16
+ Given an empty Place document collection
17
+ And a Place document named 'hashrocket' :
18
+ | Name |
19
+ | Hashrocket |
20
+ And 'hashrocket' has one Address as address :
21
+ | Street | City | State | Zip Code |
22
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
23
+ When I save the document 'hashrocket'
24
+ Then the address of 'hashrocket' is not a new record
25
+
26
+ Scenario: id is roundtripped when saving a has_one child document
27
+ Given an empty Place document collection
28
+ And a Place document named 'hashrocket' :
29
+ | Name |
30
+ | Hashrocket |
31
+ And 'hashrocket' has one Address as address :
32
+ | Street | City | State | Zip Code |
33
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
34
+ When I save the document 'hashrocket'
35
+ Then the address of 'hashrocket' roundtrips
36
+
@@ -0,0 +1,105 @@
1
+ Feature: Partial Updates
2
+
3
+ Background:
4
+ Given an empty Contact document collection
5
+ And a Contact document named 'hashrocket' :
6
+ | Name | Type | Note |
7
+ | Hashrocket | company | Premier Rails development shop! |
8
+ And 'hashrocket' has interests, an array of:
9
+ | Interest |
10
+ | ruby |
11
+ | rails |
12
+ | employment |
13
+ | contract work |
14
+ | restaurants |
15
+ | hotels |
16
+ | flights |
17
+ | car rentals |
18
+ And 'hashrocket' has many addresses :
19
+ | Street | City | State | Zip Code |
20
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
21
+ | 1 Lake Michigan Street | Chicago | IL | 60611 |
22
+ | 1 Main Street | Santiago | Chile | |
23
+ And I save the document 'hashrocket'
24
+ And a Contact document named 'rocketeer' :
25
+ | Name | Note |
26
+ | Rocketeer Mike | Fantastic developer |
27
+ And 'rocketeer' has interests, an array of:
28
+ | Interest |
29
+ | ruby |
30
+ | rails |
31
+ | restaurants |
32
+ | employment |
33
+ And 'rocketeer' has many addresses :
34
+ | Street | City | State | Zip Code |
35
+ | 1 Main Street | Atlantic Beach | FL | 32233 |
36
+ And I save the document 'rocketeer'
37
+ And a Contact document named 'contractor' :
38
+ | Name | Note |
39
+ | Contractor Joe | Knows MongoDB |
40
+ And 'contractor' has interests, an array of:
41
+ | Interest |
42
+ | ruby |
43
+ | rails |
44
+ | contract work |
45
+ | flights |
46
+ | car rentals |
47
+ | hotels |
48
+ | restaurants |
49
+ And 'contractor' has many addresses :
50
+ | Street | City | State | Zip Code |
51
+ | 1 Main St. | Jacksonville | FL | 32218 |
52
+ And I save the document 'contractor'
53
+ And an empty Place document collection
54
+ And a Place document named 'hashrocket_hq' :
55
+ | Name | Type |
56
+ | Hashrocket | company |
57
+ And 'hashrocket_hq' has one Address as address (identified by 'hq_address'):
58
+ | Street | City | State | Zip Code |
59
+ | 1 Main St. | Jacksonville | FL | 32218 |
60
+ And I save the document 'hashrocket_hq'
61
+
62
+ Scenario: Naive Update
63
+ When I update the 'note' for 'contractor' to 'Knows MongoDB and MongoDoc'
64
+ Then the document 'contractor' roundtrips
65
+
66
+ Scenario: Naive Update on a has one
67
+ When I update the 'street' for 'hq_address' to '320 1st Street North'
68
+ Then the document 'hashrocket_hq' roundtrips
69
+
70
+ Scenario: Naive Update on a has many
71
+ When 'hq_address' is the first address of 'hashrocket'
72
+ And I update the 'street' for 'hq_address' to '320 1st Street North'
73
+ Then the document 'hashrocket' roundtrips
74
+
75
+ Scenario: Strict Update
76
+ When I strict update the 'note' for 'contractor' to 'Knows MongoDB and MongoDoc'
77
+ Then the document 'contractor' roundtrips
78
+
79
+ Scenario: Strict Update on a has one
80
+ When I strict update the 'street' for 'hq_address' to '320 1st Street North'
81
+ Then the document 'hashrocket_hq' roundtrips
82
+
83
+ Scenario: Strict Update on a has many
84
+ When 'hq_address' is the first address of 'hashrocket'
85
+ And I strict update the 'street' for 'hq_address' to '320 1st Street North'
86
+ Then the document 'hashrocket' roundtrips
87
+
88
+ Scenario: Failing Strict Update on a has one
89
+ When someone else changes the Address 'address' of 'hashrocket_hq' to
90
+ | Street | City | State | Zip Code |
91
+ | 1 Ocean Blvd. | Jacksonville | FL | 32218 |
92
+ And I strict update the 'street' for 'hq_address' to '320 1st Street North'
93
+ Then the last return value is false
94
+ And the document 'hashrocket_hq' does not roundtrip
95
+
96
+ Scenario: Failing Strict Update on a has many
97
+ When 'hq_address' is the first address of 'hashrocket'
98
+ And someone else changes the addresses of 'hashrocket':
99
+ | Street | City | State | Zip Code |
100
+ | 320 1st N, #712 | Jacksonville Beach | FL | 32250 |
101
+ | 1001 Mulligan Street | Chicago | IL | 60611 |
102
+ | 345 Avenida Grande | Santiago | Chile | |
103
+ And I strict update the 'street' for 'hq_address' to '320 1st Street North'
104
+ Then the last return value is false
105
+ And the document 'hashrocket' does not roundtrip
@@ -0,0 +1,68 @@
1
+ Feature: Removing Documents
2
+
3
+ Background:
4
+ Given an empty Contact document collection
5
+ And a Contact document named 'hashrocket' :
6
+ | Name | Type | Note |
7
+ | Hashrocket | company | Premier Rails development shop! |
8
+ And 'hashrocket' has interests, an array of:
9
+ | Interest |
10
+ | ruby |
11
+ | rails |
12
+ | employment |
13
+ | contract work |
14
+ | restaurants |
15
+ | hotels |
16
+ | flights |
17
+ | car rentals |
18
+ And 'hashrocket' has many addresses :
19
+ | Street | City | State | Zip Code |
20
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
21
+ | 1 Lake Michigan Street | Chicago | IL | 60611 |
22
+ | 1 Main Street | Santiago | Chile | |
23
+ And I save the document 'hashrocket'
24
+ And a Contact document named 'rocketeer' :
25
+ | Name | Note |
26
+ | Rocketeer Mike | Fantastic developer |
27
+ And 'rocketeer' has interests, an array of:
28
+ | Interest |
29
+ | ruby |
30
+ | rails |
31
+ | restaurants |
32
+ | employment |
33
+ And 'rocketeer' has many addresses :
34
+ | Street | City | State | Zip Code |
35
+ | 1 Main Street | Atlantic Beach | FL | 32233 |
36
+ And I save the document 'rocketeer'
37
+ And a Contact document named 'contractor' :
38
+ | Name | Note |
39
+ | Contractor Joe | Knows MongoDB |
40
+ And 'contractor' has interests, an array of:
41
+ | Interest |
42
+ | ruby |
43
+ | rails |
44
+ | contract work |
45
+ | flights |
46
+ | car rentals |
47
+ | hotels |
48
+ | restaurants |
49
+ And 'contractor' has many addresses :
50
+ | Street | City | State | Zip Code |
51
+ | 1 Main St. | Jacksonville | FL | 32218 |
52
+ And I save the document 'contractor'
53
+ And a Place document named 'hashrocket_hq' :
54
+ | Name | Type |
55
+ | Hashrocket | company |
56
+ And 'hashrocket_hq' has one Address as address (identified by 'hq_address'):
57
+ | Street | City | State | Zip Code |
58
+ | 1 Main St. | Jacksonville | FL | 32218 |
59
+ And I save the document 'hashrocket_hq'
60
+
61
+ Scenario: Simple Remove
62
+ Given the document 'contractor' roundtrips
63
+ When I remove 'contractor'
64
+ Then the document 'contractor' is not found
65
+
66
+ Scenario: Embedded Remove
67
+ When the document 'hashrocket_hq' roundtrips
68
+ Then an exception is raised if I remove 'hq_address'
@@ -0,0 +1,15 @@
1
+ Feature: saving an object
2
+
3
+ Scenario: saving simple json
4
+ Given a new collection named 'test'
5
+ When I save the json '{"name":"name"}'
6
+ Then the collection should have 1 document
7
+ And the json '{"name":"name"}' roundtrips
8
+
9
+ Scenario: saving a ruby object
10
+ Given a new collection named 'test'
11
+ And an object 'movie'
12
+ When I save the object 'movie'
13
+ Then the collection should have 1 document
14
+ And the object 'movie' roundtrips
15
+
@@ -0,0 +1,66 @@
1
+ Feature: Named Scopes
2
+
3
+ Background:
4
+ Given an empty Contact document collection
5
+ And a Contact document named 'hashrocket' :
6
+ | Name | Type |
7
+ | Hashrocket | company |
8
+ And 'hashrocket' has interests, an array of:
9
+ | Interest |
10
+ | ruby |
11
+ | rails |
12
+ | employment |
13
+ | contract work |
14
+ | restaurants |
15
+ | hotels |
16
+ | flights |
17
+ | car rentals |
18
+ And 'hashrocket' has many addresses :
19
+ | Street | City | State | Zip Code |
20
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
21
+ | 1 Lake Michigan Street | Chicago | IL | 60611 |
22
+ | 1 Main Street | Santiago | Chile | |
23
+ And I save the document 'hashrocket'
24
+ And a Contact document named 'rocketeer' :
25
+ | Name |
26
+ | Rocketeer Mike |
27
+ And 'rocketeer' has interests, an array of:
28
+ | Interest |
29
+ | ruby |
30
+ | rails |
31
+ | restaurants |
32
+ | employment |
33
+ And 'rocketeer' has many addresses :
34
+ | Street | City | State | Zip Code |
35
+ | 1 Main Street | Atlantic Beach | FL | 32233 |
36
+ And I save the document 'rocketeer'
37
+ And a Contact document named 'contractor' :
38
+ | Name |
39
+ | Contractor Joe |
40
+ And 'contractor' has interests, an array of:
41
+ | Interest |
42
+ | ruby |
43
+ | rails |
44
+ | contract work |
45
+ | flights |
46
+ | car rentals |
47
+ | hotels |
48
+ | restaurants |
49
+ And 'contractor' has many addresses :
50
+ | Street | City | State | Zip Code |
51
+ | 1 Main St. | Jacksonville | FL | 32218 |
52
+ And I save the document 'contractor'
53
+
54
+ Scenario: Simple named scope
55
+ When I query contacts with scope 'rubyists'
56
+ Then the query result has 3 documents
57
+
58
+ Scenario: Simple chained scope
59
+ When I query contacts with scopes 'rubyists, contract_work'
60
+ Then the query result has 2 documents
61
+ And one of the query results is the document 'contractor'
62
+
63
+ Scenario: Named scope with lambda
64
+ When I query contacts with lambda scope 'in_state' with parameters 'IL'
65
+ Then the query result has 1 documents
66
+ And one of the query results is the document 'hashrocket'
@@ -0,0 +1,14 @@
1
+ Given /a new collection named '(.*)'/ do |name|
2
+ MongoDoc::Connection.database.drop_collection(name)
3
+ @collection = MongoDoc::Collection.new(name)
4
+ end
5
+
6
+ Given /^an empty (\w+) collection$/ do |name|
7
+ MongoDoc::Connection.database.drop_collection(name)
8
+ MongoDoc::Connection.database.create_collection(name, :strict => true)
9
+ end
10
+
11
+ Then /the collection should have (\d+) documents?/ do |count|
12
+ @collection.count.should == count.to_i
13
+ end
14
+
@@ -0,0 +1,149 @@
1
+ Given /^an empty (\w+) document collection$/ do |doc|
2
+ klass = doc.constantize
3
+ Given "an empty #{klass.collection_name} collection"
4
+ end
5
+
6
+ Given /^an? (\w+) document named '(.*)' :$/ do |doc, name, table|
7
+ @all = []
8
+ klass = doc.constantize
9
+ table.hashes.each do |hash|
10
+ @last = klass.new
11
+ hash.each do |attr, value|
12
+ @last.send("#{attr.underscore.gsub(' ', '_')}=", value)
13
+ end
14
+ @all << @last
15
+ end
16
+ instance_variable_set("@#{name}", @last)
17
+ end
18
+
19
+ Given /^'(.*)' has one (.*?) as (.*) :$/ do |doc_name, class_name, assoc_name, table|
20
+ doc = instance_variable_get("@#{doc_name}")
21
+ obj = class_name.constantize.new
22
+ table.hashes.each do |hash|
23
+ hash.each do |key, value|
24
+ obj.send("#{key.underscore.gsub(' ', '_')}=", value)
25
+ end
26
+ end
27
+ doc.send("#{assoc_name.underscore.gsub(' ', '_')}=", obj)
28
+ @last = obj
29
+ end
30
+
31
+ Given /^'(.*)' has (?:a|an|many) (.*) :$/ do |doc_name, assoc_name, table|
32
+ doc = instance_variable_get("@#{doc_name}")
33
+ table.hashes.each do |hash|
34
+ doc.send(assoc_name).build(hash.inject({}) do |attrs, (attr, value)|
35
+ attrs["#{attr.underscore.gsub(' ', '_')}"] = value
36
+ attrs
37
+ end)
38
+ end
39
+ @all = doc.send(assoc_name)
40
+ @last = @all.last
41
+ end
42
+
43
+ Given /^I set the id on the document '(.*)' to (.*)$/ do |doc_name, value|
44
+ doc = instance_variable_get("@#{doc_name}")
45
+ doc._id = Mongo::ObjectID.from_string("%024x" % value.to_i(16))
46
+ end
47
+
48
+ Given /^'(.+)' has one (.+?) as (.+?) \(identified by '(.+)'\):$/ do |doc_name, class_name, assoc_name, var_name, table|
49
+ doc = instance_variable_get("@#{doc_name}")
50
+ obj = class_name.constantize.new
51
+ table.hashes.each do |hash|
52
+ hash.each do |key, value|
53
+ obj.send("#{key.underscore.gsub(' ', '_')}=", value)
54
+ end
55
+ end
56
+ instance_variable_set("@#{var_name}", obj)
57
+ doc.send("#{assoc_name.underscore.gsub(' ', '_')}=", obj)
58
+ @last = obj
59
+ end
60
+
61
+ When /^I save the document '(.*)'$/ do |name|
62
+ object = instance_variable_get("@#{name}")
63
+ @last_return = object.save
64
+ end
65
+
66
+ When /^I save the last document$/ do
67
+ @last_return = @last.save
68
+ end
69
+
70
+ When /^I create an (.*) '(.*)' from the hash '(.*)'$/ do |doc, name, hash|
71
+ klass = doc.constantize
72
+ attrs = instance_variable_get("@#{hash}")
73
+ instance_variable_set("@#{name}", klass.create(attrs))
74
+ end
75
+
76
+ When /^I update the document '(.*)' with the hash named '(.*)'$/ do |doc_name, hash_name|
77
+ doc = instance_variable_get("@#{doc_name}")
78
+ attrs = instance_variable_get("@#{hash_name}")
79
+ @last_return = doc.update_attributes(attrs)
80
+ end
81
+
82
+ When /^I query (.*) with criteria (.*)$/ do |doc, criteria_text|
83
+ klass = doc.singularize.camelize
84
+ @query = @last_return = eval("#{klass}.criteria.#{criteria_text}")
85
+ end
86
+
87
+ When /^I query (.*) with the '(.*)' id$/ do |doc, name|
88
+ klass = doc.singularize.camelize.constantize
89
+ doc = instance_variable_get("@#{name}")
90
+ @query = @last_return = klass.criteria.id(doc.id).entries
91
+ end
92
+
93
+ When /^I find a (.*) using the id of '(.*)'$/ do |type, doc_name|
94
+ klass = type.camelize.constantize
95
+ doc = instance_variable_get("@#{doc_name}")
96
+ @last_return = klass.find(doc.id)
97
+ end
98
+
99
+ When /^'(.+)' is the first (.+?) of '(.+)'$/ do |var_name, single_assoc, doc_name|
100
+ doc = instance_variable_get("@#{doc_name}")
101
+ instance_variable_set("@#{var_name}", doc.send(single_assoc.pluralize).first)
102
+ end
103
+
104
+ Then /^'(.*)' is not a new record$/ do |name|
105
+ instance_variable_get("@#{name}").new_record?.should be_false
106
+ end
107
+
108
+ Then /the (.*) collection should have (\d+) documents?/ do |doc, count|
109
+ klass = doc.constantize
110
+ klass.count.should == count.to_i
111
+ end
112
+
113
+ Then /^the document '(.*)' roundtrips$/ do |name|
114
+ object = instance_variable_get("@#{name}")
115
+ from_db = object.class.find_one(object._id)
116
+ from_db.should == object
117
+ instance_variable_set("@#{name}", from_db)
118
+ end
119
+
120
+ Then /^the document '(.+)' does not roundtrip$/ do |name|
121
+ object = instance_variable_get("@#{name}")
122
+ from_db = object.class.find_one(object._id)
123
+ from_db.should_not == object
124
+ end
125
+
126
+ Then /^the last return value is (.+)$/ do |bool_val|
127
+ @last_return.should send("be_#{bool_val}")
128
+ end
129
+
130
+ Then /^the first (.*) of '(.*)' is not a new record$/ do |assoc, name|
131
+ object = instance_variable_get("@#{name}")
132
+ plural = assoc.pluralize
133
+ object.send(plural).first.should_not be_new_record
134
+ end
135
+
136
+ Then /^the (\w*) of '(.*)' is not a new record$/ do |assoc, name|
137
+ object = instance_variable_get("@#{name}")
138
+ object.send(assoc).should_not be_new_record
139
+ end
140
+
141
+ Then /^the (\w*) of '(.*)' roundtrips$/ do |assoc, name|
142
+ object = instance_variable_get("@#{name}")
143
+ from_db = object.class.find_one(object._id)
144
+ object.send(assoc).id.should == from_db.send(assoc).id
145
+ end
146
+
147
+ Then /^the size of the last return value is (.*)$/ do |count|
148
+ @last_return.size.should == count.to_i
149
+ end
@@ -0,0 +1,30 @@
1
+ class Address
2
+ include MongoDoc::Document
3
+
4
+ key :street
5
+ key :city
6
+ key :state
7
+ key :zip_code
8
+ end
9
+
10
+ class Place
11
+ include MongoDoc::Document
12
+
13
+ key :name
14
+ key :type
15
+ has_one :address
16
+ end
17
+
18
+ class Contact
19
+ include MongoDoc::Document
20
+
21
+ key :name
22
+ key :type
23
+ key :note
24
+ key :interests
25
+ has_many :addresses
26
+
27
+ scope :rubyists, any_in(:interests => ['ruby'])
28
+ scope :contract_work, any_in(:interests => ['contract work'])
29
+ scope :in_state, lambda {|state| where('addresses.state' => state)}
30
+ end
@@ -0,0 +1,15 @@
1
+ def finder_query=(finder)
2
+ @query = finder
3
+ end
4
+
5
+ When /^I query (.+) with (\w+)$/ do |doc, finder|
6
+ self.finder_query = klass(doc).send(finder)
7
+ end
8
+
9
+ When /^I query (.+) to find_one with the (.+) of the '(.+)' document$/ do |collection, id, doc_name|
10
+ self.finder_query = klass(collection).find_one(instance_variable_get("@#{doc_name}").send(id))
11
+ end
12
+
13
+ Then /^the query result was (\d+) documents$/ do |count|
14
+ query.should == count.to_i
15
+ end
@@ -0,0 +1,9 @@
1
+ When /^I save the json '(\{.*\})'$/ do |json_text|
2
+ json = JSON.parse(json_text)
3
+ @last_save = @collection.save(json)
4
+ end
5
+
6
+ Then /^the json '(\{.*\})' roundtrips$/ do |json_text|
7
+ json = JSON.parse(json_text)
8
+ @collection.find_one(@last_save).should be_mongo_eql(json, false)
9
+ end
@@ -0,0 +1,50 @@
1
+ Given /^an object '(.*)'$/ do |name|
2
+ @movie = Movie.new
3
+ @movie.title = 'Gone with the Wind'
4
+ @movie.director = 'Victor Fleming'
5
+ @movie.writers = ['Sidney Howard']
6
+ @director = Director.new
7
+ @director.name = 'Victor Fleming'
8
+ @award = AcademyAward.new
9
+ @award.year = '1940'
10
+ @award.category = 'Best Director'
11
+ @director.awards = [@award]
12
+ @movie.director = @director
13
+ end
14
+
15
+ Given /^a hash named '(.*)':$/ do |name, table|
16
+ @all = []
17
+ table.hashes.each do |hash|
18
+ @last = hash.inject({}) do |h, (key, value)|
19
+ h["#{key.underscore.gsub(' ', '_')}"] = value
20
+ h
21
+ end
22
+ @all << @last
23
+ end
24
+ instance_variable_set("@#{name}", @last)
25
+ end
26
+
27
+ Given /^'(.*)' has (.*), an array of:$/ do |name, attribute, table|
28
+ object = instance_variable_get("@#{name}")
29
+ object.send(attribute + "=", [])
30
+ table.hashes.each do |hash|
31
+ hash.each {|key, value| object.send(attribute) << value}
32
+ end
33
+ end
34
+
35
+
36
+ When /^I save the object '(.*)'$/ do |name|
37
+ object = instance_variable_get("@#{name}")
38
+ @last_save = @collection.save(object)
39
+ end
40
+
41
+ Then /^the object '(.*)' roundtrips$/ do |name|
42
+ object = instance_variable_get("@#{name}")
43
+ object.instance_variable_set("@_id", @last_save)
44
+ @collection.find_one(@last_save).should == object
45
+ end
46
+
47
+ Then /^the attribute '(.*)' of '(.*)' is '(.*)'$/ do |attr, var, value|
48
+ object = instance_variable_get("@#{var}")
49
+ object.send(attr).to_s.should == value
50
+ end
@@ -0,0 +1,24 @@
1
+ module ValueEquals
2
+ def ==(other)
3
+ return false unless instance_variables.size == other.instance_variables.size
4
+ instance_variables.all? {|var| self.instance_variable_get(var) == other.instance_variable_get(var)}
5
+ end
6
+ end
7
+
8
+ class Movie
9
+ include ValueEquals
10
+
11
+ attr_accessor :title, :director, :writers
12
+ end
13
+
14
+ class Director
15
+ include ValueEquals
16
+
17
+ attr_accessor :name, :awards
18
+ end
19
+
20
+ class AcademyAward
21
+ include ValueEquals
22
+
23
+ attr_accessor :year, :category
24
+ end
@@ -0,0 +1,32 @@
1
+ When /^I(\sstrict\s|\s)update the '(.+)' for '(.+)' to '(.+)'$/ do |strict, attr, doc_name, value|
2
+ doc = instance_variable_get("@#{doc_name}")
3
+ attrs = {attr => value}
4
+ attrs.merge!(:__strict__ => true) unless strict.blank?
5
+ @last_return = doc.update_attributes(attrs)
6
+ end
7
+
8
+ When /^someone else changes the (.+?) '(.+)' of '(.+)' to$/ do |assoc_klass, assoc_name, name, table|
9
+ orig = instance_variable_get("@#{name}")
10
+ doc = orig.class.find_one(orig._id)
11
+ obj = assoc_klass.constantize.new
12
+ table.hashes.each do |hash|
13
+ hash.each do |key, value|
14
+ obj.send("#{key.underscore.gsub(' ', '_')}=", value)
15
+ end
16
+ end
17
+ doc.send("#{assoc_name.underscore.gsub(' ', '_')}=", obj)
18
+ doc.save
19
+ end
20
+
21
+ When /^someone else changes the (.+) of '(.+)':$/ do |assoc_name, name, table|
22
+ orig = instance_variable_get("@#{name}")
23
+ doc = orig.class.find_one(orig._id)
24
+ doc.send(assoc_name).clear
25
+ table.hashes.each do |hash|
26
+ doc.send(assoc_name) << hash.inject({}) do |attrs, (attr, value)|
27
+ attrs["#{attr.underscore.gsub(' ', '_')}"] = value
28
+ attrs
29
+ end
30
+ end
31
+ doc.save
32
+ end
@@ -0,0 +1,54 @@
1
+ def klass(klass_name = nil)
2
+ @klass ||= klass_name.singularize.camelize.constantize
3
+ end
4
+
5
+ def query(klass_name = nil)
6
+ @query ||= klass(klass_name).criteria
7
+ end
8
+
9
+ Then /^the query result is equal to the document '(.*)'$/ do |name|
10
+ doc = instance_variable_get("@#{name}")
11
+ query.should == doc
12
+ end
13
+
14
+ Then /^one of the query results is the document '(.*)'$/ do |name|
15
+ doc = instance_variable_get("@#{name}")
16
+ query.any? {|d| d == doc}.should be_true
17
+ end
18
+
19
+ Then /^the query result with "(.*)" == "(.*)" has a count of (.*)$/ do |key, value, count|
20
+ query.find {|r| r.has_key?(key) and r[key] == value }['count'].should == count.to_i
21
+ end
22
+
23
+ Then /^the query result with "([^\"]*)" == "([^\"]*)" has the document '(.*)'$/ do |key, value, name|
24
+ doc = instance_variable_get("@#{name}")
25
+ query.find {|r| r.has_key?(key) and r[key] == value }['group'].should include(doc)
26
+ end
27
+
28
+ Then /^the query result has (.*) documents*$/ do |count|
29
+ if query.respond_to?(:size)
30
+ query.size.should == count.to_i
31
+ else
32
+ query.count.should == count.to_i
33
+ end
34
+ end
35
+
36
+ Then /^the (first|last) query result is the document '(.*)'$/ do |position, name|
37
+ doc = instance_variable_get("@#{name}")
38
+ query.entries.send(position).should == doc
39
+ end
40
+
41
+ Then /^the size of the query result is (.*)$/ do |count|
42
+ query.to_a.size.should == count.to_i
43
+ end
44
+
45
+ Then /^the query result is the document '(.*)'$/ do |name|
46
+ object = instance_variable_get("@#{name}")
47
+ if query.kind_of?(Array)
48
+ query.size.should == 1
49
+ query.first.should == object
50
+ else
51
+ query.should == object
52
+ end
53
+ end
54
+