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
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ mongod.yml
7
+ nohup.out
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Les Hill
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,174 @@
1
+ h1. MongoDoc
2
+
3
+ Version: 0.2.4 2/23/10
4
+
5
+ 2010-02-23 API is *changing* significantly
6
+ 2010-01-23 Tracking MongoDoc with @git@? *READ THIS NOTE*[1]
7
+
8
+ h2. Introduction
9
+
10
+ MongoDoc is a simple and easy to use ActiveRecord-like object mapper for "mongoDB":http://www.mongodb.org in Ruby.
11
+
12
+ MongoDoc is _also_ an extension of the "Mongo Ruby Driver":http://github.com/mongodb/mongo-ruby-driver making it a snap to get Ruby in and out of mongoDB.
13
+
14
+ MongoDoc is *not* ActiveRecord for mongoDB. We do not have callbacks, nor do we have dynamic finders. We do have associations, named scopes, and other features.
15
+
16
+ MongoDoc *is* simple, easy-to-use, and fast. And it works with Rails (2.3.x at the moment, 3 soonish?).
17
+
18
+ MongoDoc is designed to work with document data, if you are looking to map relational data in mongoDB, you will have to look elsewhere.
19
+
20
+ h2. Ruby objects in mongoDB
21
+
22
+ Lets just get right into it and save some Ruby objects in mongoDB!
23
+
24
+ bc.. class Contact
25
+ attr_accessor :name, :addresses, :interests
26
+ end
27
+
28
+ class Address
29
+ attr_accessor :street, :city, :state, :zip, :phone_number
30
+ end
31
+
32
+ p. With MongoDoc, instead of saving JSON[2], we can save an object directly:
33
+
34
+ bc.. contact = Contact.new
35
+ contact.name = 'Hashrocket'
36
+ contact.interests = ['ruby', 'rails', 'agile']
37
+
38
+ address = Address.new
39
+ address.street = '320 First Street North, #712'
40
+ address.city = 'Jacksonville Beach'
41
+ address.state = 'FL'
42
+ address.zip = '32250'
43
+ address.phone_number = '877 885 8846'
44
+ contact.addresses = [address]
45
+
46
+ collection.save(contact)
47
+
48
+ p. We can query using the powerful mongoDB query syntax, and have it return Ruby objects:
49
+
50
+ bc.. results = collection.find('addresses.state' => 'FL')
51
+ hashrocket = results.to_a.find {|contact| contact.name == 'Hashrocket'}
52
+ puts hashrocket.addresses.first.phone_number
53
+
54
+ p. Take a look in the examples directory for more code.
55
+
56
+ h2. Mapping Documents
57
+
58
+ MongoDoc provides ActiveRecord-like persistence, associations, named scopes, and validations (from "Validatable":http://github.com/durran/validatable) as well as a mongoDB query language (from "Mongoid":http://mongoid.org/home). MongoDoc also plays nicely with Rails.
59
+
60
+ @MongoDoc::Document@ provides all these features as a mixin. A @MongoDoc::Document@ can either be a top-level mongoDB document, or an embedded document contained within a top-level document. Top-level documents are stored in collections named after their class: @Contact@ objects are stored in the 'contacts' collection (much like ActiveRecord).
61
+
62
+ Lets define a @Contact@ document with an @Address@ embedded document:
63
+
64
+ bc.. class Address
65
+ include MongoDoc::Document
66
+
67
+ key :street
68
+ key :city
69
+ key :state
70
+ key :zip_code
71
+ key :phone_number
72
+ end
73
+
74
+ class Contact
75
+ include MongoDoc::Document
76
+
77
+ key :name
78
+ key :interests
79
+ has_many :addresses
80
+
81
+ named_scope :in_state, lambda {|state| {:where => {'addresses.state' => state}}}
82
+ end
83
+
84
+ p. Since a mongoDB document has no fixed schema, we define the composition of a document directly in our classes. Please note we do not specify types! We can also specify @has_one@ or @has_many@ associations.
85
+
86
+ Building and saving a document is easy:
87
+
88
+ bc.. contact = Contact.new(:name => 'Hashrocket', :interests => ['ruby', 'rails', 'agile'])
89
+ contact.addresses << Address.new(:street => '320 1st Street North, #712',
90
+ :city => 'Jacksonville Beach',
91
+ :state => 'FL',
92
+ :zip_code => '32250',
93
+ :phone_number => '877 885 8846')
94
+ contact.save
95
+
96
+ p. Now that we have some data, we can query using our named scope:
97
+
98
+ bc. hashrocket = Contact.in_state('FL').find {|contact| contact.name == 'Hashrocket'}
99
+
100
+ p. And we can even perform partial updates:
101
+
102
+ bc. hashrocket.addresses.first.update_attributes(:street => '320 First Street North, #712')
103
+
104
+ h2. Installation
105
+
106
+ MongoDoc *requires* mongoDB v1.3.2 or later.
107
+
108
+ bc. sudo gem install mongodoc
109
+
110
+ h2. Connecting
111
+
112
+ By default, MongoDoc will read its configuration from @./mongodb.yml@. If that file does not exist, it will attempt to connect to a standard MongoDB local server setup and use a database name of @"mongodoc"@.
113
+
114
+ h3. With Rails
115
+
116
+ If you are using Rails, MongoDoc will look for its configuration in @config/mongodb.yml@. If that file does not exist, it will attempt to connect to a standard MongoDB local server setup and use a database name of @#{Rails.root.basename}_#{Rails.env}@.
117
+
118
+ h3. Database configuration file
119
+
120
+ The file is similar to the Rails database.yml file, with environment definitions containing the database configuration attributes. For example:
121
+
122
+ bc. development:
123
+ name: development
124
+ host: localhost
125
+ port: 27017
126
+ options:
127
+ auto_reconnect: true
128
+ test:
129
+ name: test
130
+ host: localhost
131
+ port: 27017
132
+ options:
133
+ auto_reconnect: true
134
+
135
+ If you are not using Rails, the default environment is @development@ and you can set the current environment in your code:
136
+
137
+ bc. MongoDoc::Connection.env = 'test'
138
+
139
+ You can also change the location of the configuration file:
140
+
141
+ bc. MongoDoc::Connection.config_path = './config/mongodb.yml'
142
+
143
+ h3. Programmatically setting the database connection information
144
+
145
+ Finally, if you do not want to use the database configuration file, you can also set the database name, host, port, options, and strict values directly; for example, to set the database name to @stats@:
146
+
147
+ bc. MongoDoc::Connection.name = 'stats'
148
+
149
+ h2. Credits
150
+
151
+ Les Hill, leshill on github
152
+
153
+ h3. Thanks
154
+
155
+ Thanks to Sandro and Durran for some great conversations and some lovely code.
156
+
157
+ h2. Note on Patches/Pull Requests
158
+
159
+ * Fork the project.
160
+ * Make your feature addition or bug fix.
161
+ * Add tests for it. This is important so I don't break it in a
162
+ future version unintentionally.
163
+ * Commit, do not mess with rakefile, version, or history.
164
+ (if you want to have your own version, that is fine but
165
+ bump version in a commit by itself I can ignore when I pull)
166
+ * Send me a pull request. Bonus points for topic branches.
167
+
168
+ h2. Copyright
169
+
170
+ Copyright (c) 2009 - 2010 Les Hill. See LICENSE for details.
171
+
172
+ fn1. Building from @HEAD@? MongoDoc *requires* mongoDB v1.3.2 or later. That means you must be using the 1.3.x nightly build as of 2010-01-22 .
173
+
174
+ fn2. The Ruby driver exposes an API that understands JSON.
data/Rakefile ADDED
@@ -0,0 +1,135 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "mongo_doc"
8
+ gem.summary = %Q{ODM for MongoDB}
9
+ gem.description = %Q{ODM for MongoDB}
10
+ gem.email = "leshill@gmail.com"
11
+ gem.homepage = "http://github.com/leshill/mongodoc"
12
+ gem.authors = ["Les Hill"]
13
+ gem.add_dependency "mongo", "= 0.19"
14
+ gem.add_dependency "mongo_ext", "= 0.19"
15
+ gem.add_dependency "durran-validatable", "= 2.0.1"
16
+ gem.add_dependency "leshill-will_paginate", "= 2.3.11"
17
+ gem.add_development_dependency "rspec", "= 1.3.0"
18
+ gem.add_development_dependency "cucumber", "= 0.6.2"
19
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
20
+ end
21
+ Jeweler::GemcutterTasks.new
22
+ rescue LoadError
23
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
24
+ end
25
+
26
+ require 'cucumber/rake/task'
27
+ Cucumber::Rake::Task.new(:features) do |t|
28
+ t.cucumber_opts = "--format pretty --tag ~@wip"
29
+ end
30
+
31
+ namespace :cucumber do
32
+ Cucumber::Rake::Task.new(:wip) do |t|
33
+ t.cucumber_opts = "--format pretty --tag @wip"
34
+ end
35
+ end
36
+
37
+ require 'spec/rake/spectask'
38
+ Spec::Rake::SpecTask.new(:spec) do |spec|
39
+ spec.spec_opts = ['--options', "#{File.expand_path(File.dirname(__FILE__))}/spec/spec.opts"]
40
+ spec.libs << 'lib' << 'spec'
41
+ spec.spec_files = FileList['spec/**/*_spec.rb']
42
+ end
43
+
44
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
45
+ spec.spec_opts = ['--options', "#{File.expand_path(File.dirname(__FILE__))}/spec/spec.opts"]
46
+ spec.libs << 'lib' << 'spec'
47
+ spec.pattern = 'spec/**/*_spec.rb'
48
+ spec.rcov = true
49
+ end
50
+
51
+ task :spec => :check_dependencies
52
+
53
+ task :default => :spec
54
+
55
+ require 'rake/rdoctask'
56
+ Rake::RDocTask.new do |rdoc|
57
+ if File.exist?('VERSION')
58
+ version = File.read('VERSION')
59
+ else
60
+ version = ""
61
+ end
62
+
63
+ rdoc.rdoc_dir = 'rdoc'
64
+ rdoc.title = "MongoDoc #{version}"
65
+ rdoc.rdoc_files.include('README*')
66
+ rdoc.rdoc_files.include('lib/**/*.rb')
67
+ end
68
+
69
+ namespace :mongo do
70
+ desc 'Start mongod'
71
+ task :start do
72
+ default_config = { "dbpath" => "/data/db" }
73
+ config = begin
74
+ YAML.load_file(File.join(File.dirname(__FILE__), 'mongod.yml'))
75
+ rescue Exception => e
76
+ {}
77
+ end
78
+ config = default_config.merge(config)
79
+ sh("nohup #{config['mongod'] || 'mongod'} --dbpath #{config['dbpath']} &")
80
+ puts "\n"
81
+ end
82
+ end
83
+
84
+ namespace :mongoid do
85
+ desc 'Sync criteria from Mongoid'
86
+ task :sync do
87
+ require 'pathname'
88
+
89
+ src_dir = Pathname.new('../durran-mongoid/lib/mongoid')
90
+ dest_dir = Pathname.new('lib/mongoid')
91
+ dest_dir.mkpath
92
+ %w(criteria.rb contexts/paging.rb criterion extensions/symbol/inflections.rb extensions/hash/criteria_helpers.rb matchers).each do |f|
93
+ src = src_dir + f
94
+ if src.directory?
95
+ FileUtils.cp_r(src, dest_dir)
96
+ else
97
+ dest = dest_dir + f
98
+ dest.dirname.mkpath
99
+ FileUtils.cp(src, dest)
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ namespace :bench do
106
+ desc 'Run benchmark for MongoDoc'
107
+ task 'mongo_doc' do
108
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
109
+ require 'perf/mongo_doc_runner'
110
+ MongoDocRunner.benchmark
111
+ end
112
+
113
+ desc 'Run profiler for driver'
114
+ task 'driver' do
115
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
116
+ require 'perf/ruby_driver_runner'
117
+ RubyDriverRunner.benchmark
118
+ end
119
+ end
120
+
121
+ namespace :prof do
122
+ desc 'Run profiler for MongoDoc'
123
+ task 'mongo_doc' do
124
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
125
+ require 'perf/mongo_doc_runner'
126
+ MongoDocRunner.profile
127
+ end
128
+
129
+ desc 'Run profiler for driver'
130
+ task 'driver' do
131
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
132
+ require 'perf/ruby_driver_runner'
133
+ RubyDriverRunner.profile
134
+ end
135
+ end
data/TODO ADDED
@@ -0,0 +1,31 @@
1
+ As of 2010-02-23
2
+
3
+ Associations
4
+ ------------
5
+
6
+ Pull associations out of attributes and refactor
7
+
8
+ Criteria
9
+ --------
10
+
11
+ Make critieria module, include into Document, CriteriaProxy, Association?
12
+
13
+ Documentation
14
+ -------------
15
+
16
+ How to get started with Rails
17
+ Using mongohq
18
+
19
+ Dynamic Attributes
20
+ ------------------
21
+
22
+ Document#[] => reads attribute
23
+ Document#[]= => writes attribute
24
+ Document#dynamic_attributes => key, value for each dynamic attribute
25
+ Document#dynamic_attribute_names => list of dynamic attribute names
26
+
27
+ Validations
28
+ -----------
29
+
30
+ validates_hash_keys :has_hash_name, :in => [array of names]
31
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.0
data/data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ *
2
+ !.gitignore
@@ -0,0 +1,35 @@
1
+ require 'mongo_doc'
2
+
3
+ class Address
4
+ include MongoDoc::Document
5
+
6
+ key :street
7
+ key :city
8
+ key :state
9
+ key :zip_code
10
+ key :phone_number
11
+ end
12
+
13
+ class Contact
14
+ include MongoDoc::Document
15
+
16
+ key :name
17
+ key :interests
18
+ has_many :addresses
19
+
20
+ scope :in_state, lambda {|state| where('addresses.state' => state)}
21
+ end
22
+
23
+ Contact.collection.drop
24
+
25
+ contact = Contact.new(:name => 'Hashrocket', :interests => ['ruby', 'rails', 'agile'])
26
+ contact.addresses << Address.new(:street => '320 1st Street North, #712', :city => 'Jacksonville Beach', :state => 'FL', :zip_code => '32250', :phone_number => '877 885 8846')
27
+ contact.save
28
+ puts Contact.find_one(contact.to_param).addresses.first.street
29
+
30
+ hashrocket = Contact.in_state('FL').find {|contact| contact.name == 'Hashrocket'}
31
+
32
+ hashrocket_address = hashrocket.addresses.first
33
+ hashrocket_address.update_attributes(:street => '320 First Street North, #712')
34
+
35
+ puts Contact.where(:name => 'Hashrocket').first.addresses.first.street
@@ -0,0 +1,30 @@
1
+ require 'mongo_doc'
2
+
3
+ class Contact
4
+ attr_accessor :name, :addresses, :interests
5
+ end
6
+
7
+ class Address
8
+ attr_accessor :street, :city, :state, :zip, :phone_number
9
+ end
10
+
11
+ collection = MongoDoc::Collection.new('contacts')
12
+ collection.drop
13
+
14
+ contact = Contact.new
15
+ contact.name = 'Hashrocket'
16
+ contact.interests = ['ruby', 'rails', 'agile']
17
+
18
+ address = Address.new
19
+ address.street = '320 First Street North, #712'
20
+ address.city = 'Jacksonville Beach'
21
+ address.state = 'FL'
22
+ address.zip = '32250'
23
+ address.phone_number = '877 885 8846'
24
+ contact.addresses = [address]
25
+
26
+ collection.save(contact)
27
+
28
+ results = collection.find('addresses.state' => 'FL')
29
+ hashrocket = results.to_a.find {|contact| contact.name == 'Hashrocket'}
30
+ puts hashrocket.addresses.first.phone_number
@@ -0,0 +1,76 @@
1
+ Feature: Finders
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: All
55
+ When I query contacts with find_all
56
+ Then the query result has 3 documents
57
+
58
+ Scenario: Count
59
+ When I query contacts with count
60
+ Then the query result was 3 documents
61
+
62
+ Scenario: First
63
+ When I query contacts with first
64
+ Then the query result is the document 'hashrocket'
65
+
66
+ Scenario: Last
67
+ When I query contacts with last
68
+ Then the query result is the document 'contractor'
69
+
70
+ Scenario: Find One
71
+ When I query contacts to find_one with the id of the 'contractor' document
72
+ Then the query result is the document 'contractor'
73
+
74
+ Scenario: Find One by Param
75
+ When I query contacts to find_one with the to_param of the 'contractor' document
76
+ Then the query result is the document 'contractor'
@@ -0,0 +1,7 @@
1
+ cucumber:
2
+ name: cucumber
3
+ host: localhost
4
+ port: 27017
5
+ options:
6
+ auto_reconnect: true
7
+
@@ -0,0 +1,128 @@
1
+ Feature: MongoDoc::Base
2
+
3
+ Scenario: creating a simple document
4
+ Given an empty Address document collection
5
+ And a hash named 'hashrocket':
6
+ | Street | City | State | Zip Code |
7
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
8
+ When I create an Address 'address' from the hash 'hashrocket'
9
+ Then 'address' is not a new record
10
+ And the Address collection should have 1 document
11
+ And the document 'address' roundtrips
12
+
13
+ Scenario: saving a simple document
14
+ Given an empty Address document collection
15
+ And an Address document named 'hashrocket' :
16
+ | Street | City | State | Zip Code |
17
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
18
+ When I save the document 'hashrocket'
19
+ Then 'hashrocket' is not a new record
20
+ And the Address collection should have 1 document
21
+ And the document 'hashrocket' roundtrips
22
+
23
+ Scenario: updating an attribute of a simple document
24
+ Given an empty Address document collection
25
+ And an Address document named 'hashrocket' :
26
+ | Street | City | State | Zip Code |
27
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
28
+ And a hash named 'street':
29
+ | Street |
30
+ | 320 First St N |
31
+ And I save the document 'hashrocket'
32
+ When I update the document 'hashrocket' with the hash named 'street'
33
+ And the document 'hashrocket' roundtrips
34
+ Then the attribute 'street' of 'hashrocket' is '320 First St N'
35
+
36
+ Scenario: failing to update an attribute of a simple document
37
+ Given an empty Address document collection
38
+ And an Address document named 'hashrocket' :
39
+ | Street | City | State | Zip Code |
40
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
41
+ And a hash named 'street':
42
+ | Street |
43
+ | 320 First St N |
44
+ And I save the document 'hashrocket'
45
+ And I set the id on the document 'hashrocket' to 1
46
+ When I update the document 'hashrocket' with the hash named 'street'
47
+ Then the last return value is false
48
+
49
+ Scenario: saving a has_many document
50
+ Given an empty Contact document collection
51
+ And a Contact document named 'hashrocket' :
52
+ | Name |
53
+ | Hashrocket |
54
+ And 'hashrocket' has many addresses :
55
+ | Street | City | State | Zip Code |
56
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
57
+ | 1 Main Street | Santiago | Chile | |
58
+ When I save the document 'hashrocket'
59
+ Then 'hashrocket' is not a new record
60
+ And the Contact collection should have 1 document
61
+ And the document 'hashrocket' roundtrips
62
+
63
+ Scenario: saving from a child document
64
+ Given an empty Contact document collection
65
+ And a Contact document named 'hashrocket' :
66
+ | Name |
67
+ | Hashrocket |
68
+ And 'hashrocket' has many addresses :
69
+ | Street | City | State | Zip Code |
70
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
71
+ | 1 Main Street | Santiago | Chile | |
72
+ When I save the last document
73
+ Then 'hashrocket' is not a new record
74
+ And the Contact collection should have 1 document
75
+ And the document 'hashrocket' roundtrips
76
+
77
+ Scenario: Update attributes from a has_many child document
78
+ Given an empty Contact document collection
79
+ And a Contact document named 'hashrocket' :
80
+ | Name |
81
+ | Hashrocket |
82
+ And 'hashrocket' has many addresses :
83
+ | Street | City | State | Zip Code |
84
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
85
+ | 1 Main Street | Santiago | Chile | |
86
+ And I save the last document
87
+ And that @last is named 'chile'
88
+ And a hash named 'street':
89
+ | Street |
90
+ | 1a Calle |
91
+ When I update the document 'chile' with the hash named 'street'
92
+ Then the last return value is true
93
+ And the document 'hashrocket' roundtrips
94
+
95
+ Scenario: update attributes from a has_one child document
96
+ Given an empty Place document collection
97
+ And a Place document named 'hashrocket' :
98
+ | Name |
99
+ | Hashrocket |
100
+ And 'hashrocket' has one Address as address :
101
+ | Street | City | State | Zip Code |
102
+ | 320 First Street North | Jacksonville Beach | FL | 32250 |
103
+ And I save the last document
104
+ And that @last is named 'address'
105
+ And a hash named 'street':
106
+ | Street | City |
107
+ | 320 1st St. N. | Jax Bch |
108
+ When I update the document 'address' with the hash named 'street'
109
+ Then the Place collection should have 1 document
110
+ And the document 'hashrocket' roundtrips
111
+
112
+ Scenario: Class criteria
113
+ Given an empty Contact document collection
114
+ And a Contact document named 'hashrocket' :
115
+ | Name | Type |
116
+ | Hashrocket | company |
117
+ And I save the last document
118
+ When I query contacts with criteria where('type' => 'company')
119
+ Then the size of the last return value is 1
120
+
121
+ Scenario: Finder
122
+ Given an empty Contact document collection
123
+ And a Contact document named 'hashrocket' :
124
+ | Name | Type |
125
+ | Hashrocket | company |
126
+ And I save the document 'hashrocket'
127
+ When I find a contact using the id of 'hashrocket'
128
+ Then the size of the last return value is 1