mongo_doc 0.3.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 (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
+