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
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