mongomatic 0.8.2 → 0.9.0.pre

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,4 +1,5 @@
1
1
  = 0.9.pre
2
+ * Add Mongomatic::Base#find_or_initialize method (jsmestad)
2
3
 
3
4
  Internal:
4
5
  * Updated development dependencies and Jeweler definitions (jsmestad)
data/Gemfile CHANGED
@@ -2,8 +2,8 @@ source "http://rubygems.org"
2
2
  # Add dependencies required to use your gem here.
3
3
  # Example:
4
4
  gem "activesupport", ">= 3.0.0"
5
- gem "mongo", ">= 1.2.4"
6
- gem "bson", ">= 1.2.4"
5
+ gem "mongo", ">= 1.3.1"
6
+ gem "bson", ">= 1.3.1"
7
7
  gem "i18n", ">= 0.5.0"
8
8
 
9
9
  # Add dependencies to develop your gem here.
data/LICENSE CHANGED
@@ -1,20 +1,190 @@
1
- Copyright (c) 2009 Ben Myles
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.
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ Copyright 2010-2011 Ben Myles
179
+
180
+ Licensed under the Apache License, Version 2.0 (the "License");
181
+ you may not use this file except in compliance with the License.
182
+ You may obtain a copy of the License at
183
+
184
+ http://www.apache.org/licenses/LICENSE-2.0
185
+
186
+ Unless required by applicable law or agreed to in writing, software
187
+ distributed under the License is distributed on an "AS IS" BASIS,
188
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189
+ See the License for the specific language governing permissions and
190
+ limitations under the License.
data/README.rdoc CHANGED
@@ -230,6 +230,14 @@ You can add your own observers to CollectionName using CollectionName.add_observ
230
230
 
231
231
  It is worth noting that you should be careful the operations you perform on the instance of your class passed to the observer callbacks. Calling operations that invoke callbacks can result in an infinite loop if improperly structured.
232
232
 
233
+ == Contributors
234
+
235
+ * Ben Myles -- http://github.com/benmyles
236
+ * Justin Smestad -- http://github.com/jsmestad
237
+ * Jordan West -- http://github.com/jrwest
238
+
239
+ Additional contributors can be viewed at: https://github.com/mongomachine/mongomatic/contributors
240
+
233
241
  == Copyright
234
242
 
235
- Copyright (c) 2010 Ben Myles. See LICENSE for details.
243
+ Copyright (c) 2010-2011 Ben Myles. See LICENSE for details.
data/Rakefile CHANGED
@@ -7,10 +7,9 @@ begin
7
7
  gem.name = "mongomatic"
8
8
  gem.summary = %Q{Mongomatic is a modular Ruby object mapper for Mongo}
9
9
  gem.description = %Q{Mongomatic is a modular Ruby object mapper for Mongo}
10
- gem.email = "ben.myles@gmail.com"
11
- gem.homepage = "http://mongomatic.com/"
10
+ gem.email = ["ben.myles@gmail.com", "justin.smestad@gmail.com"]
11
+ gem.homepage = "http://github.com/mongomachine/mongomatic"
12
12
  gem.authors = ["Ben Myles", "Justin Smestad"]
13
- gem.license = "MIT"
14
13
  end
15
14
  Jeweler::RubygemsDotOrgTasks.new
16
15
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.8.2
1
+ 0.9.0.pre
@@ -4,13 +4,13 @@ module Mongomatic
4
4
  include Mongomatic::Util
5
5
  include Mongomatic::ActiveModelCompliancy
6
6
  include Mongomatic::TypedFields
7
-
7
+
8
8
  class << self
9
9
  # Returns this models own db attribute if set, otherwise will return Mongomatic.db
10
10
  def db
11
11
  @db || Mongomatic.db || raise(ArgumentError, "No db supplied")
12
12
  end
13
-
13
+
14
14
  # Override Mongomatic.db with a Mongo::DB instance for this model specifically
15
15
  # MyModel.db = Mongo::Connection.new().db('mydb_mymodel')
16
16
  def db=(obj)
@@ -33,33 +33,38 @@ module Mongomatic
33
33
  def find(query={}, opts={})
34
34
  Mongomatic::Cursor.new(self, collection.find(query, opts))
35
35
  end
36
-
36
+
37
+ # Query MongoDB for existing document. If found, return existing or initialize a new object with the parameters
38
+ def find_or_initialize(query={}, opts={})
39
+ find_one(query, opts) || new(query, true)
40
+ end
41
+
37
42
  # Query MongoDB and return one document only. Same arguments as http://api.mongodb.org/ruby/current/Mongo/Collection.html#find_one-instance_method
38
43
  def find_one(query={}, opts={})
39
44
  return nil unless doc = self.collection.find_one(query, opts)
40
45
  self.new(doc, false)
41
46
  end
42
-
47
+
43
48
  # Return a Mongomatic::Cursor instance of all documents in the collection.
44
49
  def all
45
50
  find
46
51
  end
47
-
52
+
48
53
  # Iterate over all documents in the collection (uses a Mongomatic::Cursor)
49
54
  def each
50
55
  find.each { |found| yield(found) }
51
56
  end
52
-
57
+
53
58
  # Return the first document in the collection
54
59
  def first
55
60
  find.limit(1).next_document
56
61
  end
57
-
62
+
58
63
  # Is the collection empty? This method is much more efficient than doing Collection.count == 0
59
64
  def empty?
60
65
  find.limit(1).has_next? == false
61
66
  end
62
-
67
+
63
68
  # Return the number of documents in the collection
64
69
  def count
65
70
  find.count
@@ -70,17 +75,17 @@ module Mongomatic
70
75
  collection.drop
71
76
  do_callback(:after_drop)
72
77
  end
73
-
78
+
74
79
  def do_callback(meth)
75
80
  return false unless respond_to?(meth, true)
76
81
  send(meth)
77
82
  end
78
-
83
+
79
84
  def insert(doc_hash, opts={})
80
85
  d = new(doc_hash)
81
86
  d.insert(opts)
82
87
  end
83
-
88
+
84
89
  def insert!(doc_hash, opts={})
85
90
  insert(doc_hash, opts.merge(:safe => true))
86
91
  end
@@ -95,16 +100,16 @@ module Mongomatic
95
100
  self.errors = Mongomatic::Errors.new
96
101
  do_callback(:after_initialize)
97
102
  end
98
-
103
+
99
104
  def doc=(hash)
100
105
  hash = Mongomatic::MHash.new(hash) unless hash.is_a?(Mongomatic::MHash)
101
106
  @doc = hash
102
107
  end
103
-
108
+
104
109
  def doc
105
110
  @doc
106
111
  end
107
-
112
+
108
113
  # Override this with your own validate() method for validations.
109
114
  # Simply push your errors into the self.errors property and
110
115
  # if self.errors remains empty your document will be valid.
@@ -114,7 +119,7 @@ module Mongomatic
114
119
  def validate
115
120
  true
116
121
  end
117
-
122
+
118
123
  def valid?
119
124
  check_typed_fields!
120
125
  self.errors = Mongomatic::Errors.new
@@ -123,38 +128,38 @@ module Mongomatic
123
128
  do_callback(:after_validate)
124
129
  self.errors.empty?
125
130
  end
126
-
127
- def is_new?
128
- self.is_new == true
129
- end
130
-
131
+
131
132
  def new?
132
133
  self.is_new == true
133
134
  end
134
-
135
+
136
+ def is_new?
137
+ !!new?
138
+ end
139
+
135
140
  # Set a field on this document:
136
141
  # mydoc["name"] = "Ben"
137
142
  # mydoc["address"] = { "city" => "San Francisco" }
138
143
  def []=(k,v)
139
144
  @doc[k.to_s] = v
140
145
  end
141
-
146
+
142
147
  # Returns true if document contains key
143
148
  def has_key?(key)
144
149
  field, hash = hash_for_field(key.to_s, true)
145
150
  hash.has_key?(field)
146
151
  end
147
-
152
+
148
153
  def set_value_for_key(key, value)
149
154
  field, hash = hash_for_field(key.to_s)
150
155
  hash[field] = value
151
156
  end
152
-
157
+
153
158
  def value_for_key(key)
154
159
  field, hash = hash_for_field(key.to_s, true)
155
160
  hash[field]
156
161
  end
157
-
162
+
158
163
  ##
159
164
  # Same as Hash#delete
160
165
  #
@@ -172,18 +177,18 @@ module Mongomatic
172
177
  def [](k)
173
178
  @doc[k.to_s]
174
179
  end
175
-
180
+
176
181
  # Merge this document with the supplied hash. Useful for updates:
177
182
  # mydoc.merge(params[:user])
178
183
  def merge(hash)
179
184
  hash.each { |k,v| self[k] = v }; @doc
180
185
  end
181
-
186
+
182
187
  # Will return true if the document has been removed.
183
188
  def removed?
184
189
  self.removed == true
185
190
  end
186
-
191
+
187
192
  # Check equality with another Mongomatic document
188
193
  def ==(obj)
189
194
  obj.is_a?(self.class) && obj.doc["_id"] == @doc["_id"]
@@ -222,7 +227,7 @@ module Mongomatic
222
227
  do_callback(:after_insert_or_update)
223
228
  ret
224
229
  end
225
-
230
+
226
231
  # Calls insert(...) with {:safe => true} passed in as an option.
227
232
  # * Raises Mongo::OperationError if there was a DB error on inserting
228
233
  # If you want to raise the following errors also, pass in {:raise => true}
@@ -231,7 +236,7 @@ module Mongomatic
231
236
  def insert!(opts={})
232
237
  insert(opts.merge(:safe => true))
233
238
  end
234
-
239
+
235
240
  # Will persist any changes you have made to the document. Silently fails on
236
241
  # db update error. Use update! or pass in {:safe => true} to raise a
237
242
  # Mongo::OperationError if that's what you want.
@@ -254,7 +259,7 @@ module Mongomatic
254
259
  do_callback(:after_insert_or_update)
255
260
  ret
256
261
  end
257
-
262
+
258
263
  # Calls update(...) with {:safe => true} passed in as an option.
259
264
  # * Raises Mongo::OperationError if there was a DB error on updating
260
265
  # If you want to raise the following errors also, pass in {:raise => true}
@@ -264,7 +269,7 @@ module Mongomatic
264
269
  def update!(opts={},update_doc=@doc)
265
270
  update(opts.merge(:safe => true),update_doc)
266
271
  end
267
-
272
+
268
273
  # Remove this document from the collection. Silently fails on db error,
269
274
  # use remove! or pass in {:safe => true} if you want an exception raised.
270
275
  # If you want to raise the following errors also, pass in {:raise => true}
@@ -284,8 +289,8 @@ module Mongomatic
284
289
  do_callback(:after_remove)
285
290
  ret
286
291
  end
287
-
288
- # Calls remove(...) with {:safe => true} passed in as an option.
292
+
293
+ # Calls remove(...) with {:safe => true} passed in as an option.
289
294
  # * Raises Mongo::OperationError if there was a DB error on removing
290
295
  # If you want to raise the following errors also, pass in {:raise => true}
291
296
  # * Raises Mongomatic::Exceptions::DocumentIsNew if document is new
@@ -293,32 +298,33 @@ module Mongomatic
293
298
  def remove!(opts={})
294
299
  remove(opts.merge(:safe => true))
295
300
  end
296
-
301
+
297
302
  # Return this document as a hash.
298
303
  def to_hash
299
304
  @doc || {}
300
305
  end
301
-
306
+
302
307
  def hash_for_field(field, break_if_dne=false)
303
308
  parts = field.split(".")
304
309
  curr_hash = self.doc
305
310
  return [parts[0], curr_hash] if parts.size == 1
306
311
  field = parts.pop # last one is the field
307
312
  parts.each_with_index do |part, i|
308
- return [part, curr_hash] if break_if_dne && !curr_hash.has_key?(part)
309
- curr_hash[part] ||= {}
310
- return [field, curr_hash[part]] if parts.size == i+1
311
- curr_hash = curr_hash[part]
313
+ part_accessor = curr_hash.kind_of?(Array) ? part.to_i : part
314
+ return [part, curr_hash] if break_if_dne && !curr_hash.has_key?(part_accessor)
315
+ curr_hash[part_accessor] ||= {}
316
+ return [field, curr_hash[part_accessor]] if parts.size == i+1
317
+ curr_hash = curr_hash[part_accessor]
312
318
  end
313
319
  end
314
-
320
+
315
321
  def do_callback(meth)
316
322
  notify(meth) if self.class.included_modules.include?(Mongomatic::Observable) # TODO entire block is smelly, doesnt belong here
317
-
323
+
318
324
  return false unless respond_to?(meth, true)
319
325
  send(meth)
320
326
  end
321
-
327
+
322
328
  def transaction(key=nil, duration=5, &block)
323
329
  raise Mongomatic::Exceptions::DocumentIsNew if new?
324
330
  if key.is_a?(Hash) && key[:scope]
@@ -8,9 +8,9 @@ module Mongomatic
8
8
  # User.find({"zip" => 94107}).count
9
9
  class Cursor
10
10
  include Enumerable
11
-
11
+
12
12
  attr_accessor :mongo_cursor
13
-
13
+
14
14
  def initialize(obj_class, mongo_cursor)
15
15
  @obj_class = obj_class
16
16
  @mongo_cursor = mongo_cursor
@@ -19,42 +19,42 @@ module Mongomatic
19
19
  def method_missing(name, *args)
20
20
  @mongo_cursor.send name, *args
21
21
  end
22
-
22
+
23
23
  # Is the cursor empty? This method is much more efficient than doing cursor.count == 0
24
24
  def empty?
25
25
  @mongo_cursor.has_next? == false
26
26
  end
27
-
27
+
28
28
  def next_document
29
29
  if doc = @mongo_cursor.next_document
30
30
  @obj_class.new(doc, false)
31
31
  end
32
32
  end
33
-
33
+
34
34
  alias :next :next_document
35
-
35
+
36
36
  def each
37
37
  @mongo_cursor.each do |doc|
38
38
  yield(@obj_class.new(doc, false))
39
39
  end
40
40
  end
41
-
41
+
42
42
  def current_limit
43
43
  @mongo_cursor.limit
44
44
  end
45
-
45
+
46
46
  def limit(number_to_return)
47
47
  @mongo_cursor.limit(number_to_return); self
48
48
  end
49
-
49
+
50
50
  def current_skip
51
51
  @mongo_cursor.skip
52
52
  end
53
-
53
+
54
54
  def skip(number_to_skip)
55
55
  @mongo_cursor.skip(number_to_skip); self
56
56
  end
57
-
57
+
58
58
  def sort(key_or_list, direction = nil)
59
59
  @mongo_cursor.sort(key_or_list, direction); self
60
60
  end
data/mongomatic.gemspec CHANGED
@@ -5,13 +5,13 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongomatic}
8
- s.version = "0.8.2"
8
+ s.version = "0.9.0.pre"
9
9
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ben Myles", "Justin Smestad"]
12
- s.date = %q{2011-05-07}
12
+ s.date = %q{2011-05-24}
13
13
  s.description = %q{Mongomatic is a modular Ruby object mapper for Mongo}
14
- s.email = %q{ben.myles@gmail.com}
14
+ s.email = ["ben.myles@gmail.com", "justin.smestad@gmail.com"]
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
17
  "README.rdoc"
@@ -57,31 +57,18 @@ Gem::Specification.new do |s|
57
57
  "test/test_typed_fields.rb",
58
58
  "test/test_validations.rb"
59
59
  ]
60
- s.homepage = %q{http://mongomatic.com/}
61
- s.licenses = ["MIT"]
60
+ s.homepage = %q{http://github.com/mongomachine/mongomatic}
62
61
  s.require_paths = ["lib"]
63
62
  s.rubygems_version = %q{1.7.2}
64
63
  s.summary = %q{Mongomatic is a modular Ruby object mapper for Mongo}
65
- s.test_files = [
66
- "test/helper.rb",
67
- "test/test_exceptions.rb",
68
- "test/test_find.rb",
69
- "test/test_misc.rb",
70
- "test/test_modifiers.rb",
71
- "test/test_observable.rb",
72
- "test/test_persistence.rb",
73
- "test/test_transaction_lock.rb",
74
- "test/test_typed_fields.rb",
75
- "test/test_validations.rb"
76
- ]
77
64
 
78
65
  if s.respond_to? :specification_version then
79
66
  s.specification_version = 3
80
67
 
81
68
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
82
69
  s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0"])
83
- s.add_runtime_dependency(%q<mongo>, [">= 1.2.4"])
84
- s.add_runtime_dependency(%q<bson>, [">= 1.2.4"])
70
+ s.add_runtime_dependency(%q<mongo>, [">= 1.3.1"])
71
+ s.add_runtime_dependency(%q<bson>, [">= 1.3.1"])
85
72
  s.add_runtime_dependency(%q<i18n>, [">= 0.5.0"])
86
73
  s.add_development_dependency(%q<minitest>, [">= 0"])
87
74
  s.add_development_dependency(%q<bundler>, ["~> 1.0.11"])
@@ -91,8 +78,8 @@ Gem::Specification.new do |s|
91
78
  s.add_development_dependency(%q<yard>, ["~> 0.6.5"])
92
79
  else
93
80
  s.add_dependency(%q<activesupport>, [">= 3.0.0"])
94
- s.add_dependency(%q<mongo>, [">= 1.2.4"])
95
- s.add_dependency(%q<bson>, [">= 1.2.4"])
81
+ s.add_dependency(%q<mongo>, [">= 1.3.1"])
82
+ s.add_dependency(%q<bson>, [">= 1.3.1"])
96
83
  s.add_dependency(%q<i18n>, [">= 0.5.0"])
97
84
  s.add_dependency(%q<minitest>, [">= 0"])
98
85
  s.add_dependency(%q<bundler>, ["~> 1.0.11"])
@@ -103,8 +90,8 @@ Gem::Specification.new do |s|
103
90
  end
104
91
  else
105
92
  s.add_dependency(%q<activesupport>, [">= 3.0.0"])
106
- s.add_dependency(%q<mongo>, [">= 1.2.4"])
107
- s.add_dependency(%q<bson>, [">= 1.2.4"])
93
+ s.add_dependency(%q<mongo>, [">= 1.3.1"])
94
+ s.add_dependency(%q<bson>, [">= 1.3.1"])
108
95
  s.add_dependency(%q<i18n>, [">= 0.5.0"])
109
96
  s.add_dependency(%q<minitest>, [">= 0"])
110
97
  s.add_dependency(%q<bundler>, ["~> 1.0.11"])
data/test/helper.rb CHANGED
@@ -7,12 +7,15 @@ require 'pp'
7
7
  require "#{File.dirname(__FILE__)}/../lib/mongomatic"
8
8
  #require 'mongomatic'
9
9
 
10
- Mongomatic.db = Mongo::Connection.new.db("mongomatic_test")
10
+ Mongomatic.db = Mongo::Connection.new('127.0.0.1', 27017, {
11
+ :connect => true,
12
+ :auths => [{'db_name' => 'admin', 'username' => 'admin', 'password' => 'admin'}]
13
+ }).db("mongomatic_test")
11
14
 
12
15
  class Person < Mongomatic::Base
13
16
  include Mongomatic::Expectations::Helper
14
17
  attr_accessor :callback_tests
15
-
18
+
16
19
  class << self
17
20
  attr_accessor :class_callbacks
18
21
  def create_indexes
@@ -33,34 +36,34 @@ class Person < Mongomatic::Base
33
36
  def validate
34
37
  self.errors.add "name", "can't be empty" if self["name"].blank?
35
38
  end
36
-
39
+
37
40
  private
38
-
41
+
39
42
  def before_validate
40
43
  self.callback_tests ||= []
41
44
  self.callback_tests << :before_validate
42
45
  end
43
-
46
+
44
47
  def after_validate
45
48
  self.callback_tests ||= []
46
49
  self.callback_tests << :after_validate
47
50
  end
48
-
51
+
49
52
  def before_insert
50
53
  self.callback_tests ||= []
51
54
  self.callback_tests << :before_insert
52
55
  end
53
-
56
+
54
57
  def before_insert_or_update
55
58
  self.callback_tests ||= []
56
59
  self.callback_tests << :before_insert_or_update
57
60
  end
58
-
61
+
59
62
  def after_insert_or_update
60
63
  self.callback_tests ||= []
61
64
  self.callback_tests << :after_insert_or_update
62
65
  end
63
-
66
+
64
67
  def after_insert
65
68
  self.callback_tests ||= []
66
69
  self.callback_tests << :after_insert
@@ -70,22 +73,22 @@ class Person < Mongomatic::Base
70
73
  self.callback_tests ||= []
71
74
  self.callback_tests << :before_update
72
75
  end
73
-
76
+
74
77
  def after_update
75
78
  self.callback_tests ||= []
76
79
  self.callback_tests << :after_update
77
80
  end
78
-
81
+
79
82
  def before_remove
80
83
  self.callback_tests ||= []
81
84
  self.callback_tests << :before_remove
82
85
  end
83
-
86
+
84
87
  def after_remove
85
88
  self.callback_tests ||= []
86
89
  self.callback_tests << :after_remove
87
90
  end
88
-
91
+
89
92
  end
90
93
 
91
94
  class Thing < Mongomatic::Base
@@ -101,7 +104,7 @@ end
101
104
  class Foobar < Mongomatic::Base
102
105
  include Mongomatic::Observable
103
106
  observer :FoobarObserver
104
-
107
+
105
108
  def validate
106
109
  errors << ["color", "must not be blank"] if self["color"].blank?
107
110
  errors << "missing style" if self["style"].blank?
@@ -113,7 +116,7 @@ end
113
116
 
114
117
  class Rig < Mongomatic::Base
115
118
  include Mongomatic::Observable
116
-
119
+
117
120
  # :cast => true, :raise => false is the default
118
121
  typed_field "age", :type => :fixnum, :cast => true
119
122
  typed_field "manufacturer.name", :type => :string, :cast => true
@@ -124,7 +127,7 @@ end
124
127
 
125
128
  class Clock < Mongomatic::Base
126
129
  typed_field "ticks", :type => :fixnum, :cast => true
127
-
130
+
128
131
  def tick!
129
132
  transaction do
130
133
  self.reload
@@ -133,4 +136,4 @@ class Clock < Mongomatic::Base
133
136
  self.update!
134
137
  end
135
138
  end
136
- end
139
+ end
data/test/test_find.rb CHANGED
@@ -6,38 +6,52 @@ class TestFind < MiniTest::Unit::TestCase
6
6
  Person.collection.drop
7
7
  p1 = Person.new(:name => "Jordan")
8
8
  p1.insert
9
-
9
+
10
10
  assert_equal p1, Person.find_one(:name => "Jordan")
11
11
  end
12
-
12
+
13
13
  def test_find_one_with_id
14
14
  Person.collection.drop
15
15
  p1 = Person.new(:name => "Jordan")
16
16
  p1.insert
17
-
17
+
18
18
  assert_equal p1, Person.find_one(p1['_id'])
19
19
  end
20
-
20
+
21
21
  def test_find_one_with_id_or_hash
22
22
  Person.collection.drop
23
23
  Person.create_indexes
24
-
24
+
25
25
  p = Person.new(:name => "Ben1", :birth_year => 1984, :created_at => Time.now.utc, :admin => true)
26
26
  assert p.insert!.is_a?(BSON::ObjectId)
27
27
  assert_equal 1, Person.count
28
-
28
+
29
29
  found = Person.find({"_id" => BSON::ObjectId(p["_id"].to_s)}).next
30
30
  assert_equal found, p
31
-
31
+
32
32
  assert_raises(TypeError) { Person.find_one(p["_id"].to_s) }
33
-
33
+
34
34
  found = Person.find_one({"_id" => p["_id"].to_s})
35
35
  assert_equal found, nil
36
-
36
+
37
37
  found = Person.find_one({"_id" => BSON::ObjectId(p["_id"].to_s)})
38
38
  assert_equal found, p
39
39
  end
40
-
40
+
41
+ def test_find_or_initialize_with_query
42
+ Person.collection.drop
43
+ p1 = Person.new(:name => 'Jordan')
44
+ p1.insert
45
+ assert_equal p1, Person.find_one(:name => "Jordan")
46
+
47
+ r1 = Person.find_or_initialize({:name => 'Jordan'})
48
+ assert_equal r1.is_new?, false
49
+ assert_equal r1, p1
50
+
51
+ r2 = Person.find_or_initialize({:name => 'Jason'})
52
+ assert_equal r2.is_new?, true
53
+ end
54
+
41
55
  def test_limit_and_sort
42
56
  Person.collection.drop
43
57
  p = Person.new(:name => "Ben", :birth_year => 1984, :created_at => Time.now.utc, :admin => true)
@@ -46,11 +60,11 @@ class TestFind < MiniTest::Unit::TestCase
46
60
  p2 = Person.new(:name => "Ben2", :birth_year => 1984, :created_at => Time.now.utc, :admin => true)
47
61
  assert p2.insert.is_a?(BSON::ObjectId)
48
62
  assert_equal 2, Person.collection.count
49
-
63
+
50
64
  cursor = Person.find({"_id" => p["_id"]})
51
65
  found = cursor.next
52
66
  assert_equal p, found
53
-
67
+
54
68
  cursor = Person.find()
55
69
  assert_equal 0, cursor.current_limit
56
70
  assert_equal 2, cursor.to_a.size
@@ -69,13 +83,13 @@ class TestFind < MiniTest::Unit::TestCase
69
83
  cursor = Person.find().sort("name", Mongo::DESCENDING)
70
84
  assert_equal p2, cursor.next
71
85
  end
72
-
86
+
73
87
  def test_instance_of_class_returned_on_find_one
74
88
  Person.collection.drop
75
89
  p1 = Person.new(:name => "Jordan")
76
90
  p1.insert
77
-
91
+
78
92
  assert_equal Person, Person.find_one(:name => "Jordan").class
79
93
  end
80
-
81
- end
94
+
95
+ end
@@ -153,6 +153,14 @@ class TestModifiers < MiniTest::Unit::TestCase
153
153
  p1 = Person.find_one(p1["_id"])
154
154
  assert_equal "Ben", p1["l1"]["l2"]["l3"]["l4"]["name"]
155
155
  end
156
+
157
+ def test_set_for_embedded_hash_of_nested_document_collection
158
+ p1 = Person.new(:name => "Tony")
159
+ p1.push('friends', Person.new(:name => "Jordan").doc)
160
+ assert p1.insert!
161
+ p1.set!("friends.0.isAwesome", "Absolutely!")
162
+ assert_equal "Absolutely!", p1["friends"][0]["isAwesome"]
163
+ end
156
164
 
157
165
  def test_unset
158
166
  p1 = Person.new(:name => "Jordan")
@@ -16,7 +16,7 @@ class TestTypedFields < MiniTest::Unit::TestCase
16
16
  assert_equal true, r.valid?
17
17
  assert_equal "(800) 123 456 789", r["manufacturer"]["phone"]
18
18
  end
19
-
19
+
20
20
  def test_cast_string
21
21
  r = Rig.new
22
22
  r["manufacturer"] = {}
@@ -25,7 +25,7 @@ class TestTypedFields < MiniTest::Unit::TestCase
25
25
  assert r.valid?
26
26
  assert_equal ["Wings","Parachuting","Company"].to_s, r["manufacturer"]["name"]
27
27
  end
28
-
28
+
29
29
  def test_cast_number
30
30
  r = Rig.new
31
31
  r["age"] = "4"
@@ -33,7 +33,7 @@ class TestTypedFields < MiniTest::Unit::TestCase
33
33
  assert r.valid?
34
34
  assert_equal 4, r["age"]
35
35
  end
36
-
36
+
37
37
  def test_cast_float
38
38
  r = Rig.new
39
39
  r["waist_measurement"] = "34.3"
@@ -41,7 +41,7 @@ class TestTypedFields < MiniTest::Unit::TestCase
41
41
  assert r.valid?
42
42
  assert_equal 34.3, r["waist_measurement"]
43
43
  end
44
-
44
+
45
45
  def test_cast_object_id
46
46
  r = Rig.new
47
47
  assert r.insert
@@ -50,4 +50,4 @@ class TestTypedFields < MiniTest::Unit::TestCase
50
50
  r2.insert
51
51
  assert_equal "BSON::ObjectId", r2["friends_rig_id"].class.to_s
52
52
  end
53
- end
53
+ end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongomatic
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.8.2
4
+ prerelease: 6
5
+ version: 0.9.0.pre
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ben Myles
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2011-05-07 00:00:00 Z
14
+ date: 2011-05-24 00:00:00 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -31,7 +31,7 @@ dependencies:
31
31
  requirements:
32
32
  - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: 1.2.4
34
+ version: 1.3.1
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: *id002
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ">="
44
44
  - !ruby/object:Gem::Version
45
- version: 1.2.4
45
+ version: 1.3.1
46
46
  type: :runtime
47
47
  prerelease: false
48
48
  version_requirements: *id003
@@ -124,7 +124,9 @@ dependencies:
124
124
  prerelease: false
125
125
  version_requirements: *id010
126
126
  description: Mongomatic is a modular Ruby object mapper for Mongo
127
- email: ben.myles@gmail.com
127
+ email:
128
+ - ben.myles@gmail.com
129
+ - justin.smestad@gmail.com
128
130
  executables: []
129
131
 
130
132
  extensions: []
@@ -172,9 +174,9 @@ files:
172
174
  - test/test_transaction_lock.rb
173
175
  - test/test_typed_fields.rb
174
176
  - test/test_validations.rb
175
- homepage: http://mongomatic.com/
176
- licenses:
177
- - MIT
177
+ homepage: http://github.com/mongomachine/mongomatic
178
+ licenses: []
179
+
178
180
  post_install_message:
179
181
  rdoc_options: []
180
182
 
@@ -189,9 +191,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
189
191
  required_rubygems_version: !ruby/object:Gem::Requirement
190
192
  none: false
191
193
  requirements:
192
- - - ">="
194
+ - - ">"
193
195
  - !ruby/object:Gem::Version
194
- version: "0"
196
+ version: 1.3.1
195
197
  requirements: []
196
198
 
197
199
  rubyforge_project:
@@ -199,14 +201,5 @@ rubygems_version: 1.7.2
199
201
  signing_key:
200
202
  specification_version: 3
201
203
  summary: Mongomatic is a modular Ruby object mapper for Mongo
202
- test_files:
203
- - test/helper.rb
204
- - test/test_exceptions.rb
205
- - test/test_find.rb
206
- - test/test_misc.rb
207
- - test/test_modifiers.rb
208
- - test/test_observable.rb
209
- - test/test_persistence.rb
210
- - test/test_transaction_lock.rb
211
- - test/test_typed_fields.rb
212
- - test/test_validations.rb
204
+ test_files: []
205
+