mongomatic 0.0.1

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.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
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.
data/README.rdoc ADDED
@@ -0,0 +1,49 @@
1
+ = Mongomatic
2
+
3
+ Mongomatic allows you to map your Ruby objects to Mongo documents. It is designed to be fast and simple.
4
+
5
+ == Usage
6
+
7
+ require 'mongomatic'
8
+
9
+ class User < Mongomatic::Base
10
+ validates_presence_of :name, :email
11
+ end
12
+
13
+ # set the db settings for all models:
14
+ Mongomatic.settings = { :connection => ["localhost", 27017, {}], :db => "mongomatic_test" }
15
+ # or you can set it for a specific model:
16
+ User.settings = { :connection => ["localhost", 27017, {}], :db => "mongomatic_test_user" }
17
+
18
+ u = User.new(:name => "Ben")
19
+ => #<User:0x00000100d0cbf8 @doc={"name"=>"Ben"}, @removed=false>
20
+ u.valid?
21
+ => false
22
+ u["email"] = "me@somewhere.com"
23
+ u.valid?
24
+ => true
25
+ u.insert
26
+ => BSON::ObjectID('4c32834f0218236321000001')
27
+ u
28
+ => #<User:0x00000100d0cbf8 @doc={"name"=>"Ben", "email"=>"me@somewhere.com", "_id"=>BSON::ObjectID('4c32834f0218236321000001')}, @removed=false, @validation_context=nil, @errors={}, @_initialized_validate_callbacks=true>
29
+
30
+ cursor = User.find({"name" => "Ben"})
31
+ => #<Mongomatic::Cursor:0x00000100acd3d8 @obj_class=User, @mongo_cursor=DBResponse(flags=, cursor_id=, start=)>
32
+ cursor.count
33
+ => 1
34
+ cursor.next
35
+ => #<User:0x00000100a61e08 @doc={"_id"=>BSON::ObjectID('4c32834f0218236321000001'), "name"=>"Ben", "email"=>"me@somewhere.com"}, @removed=false>
36
+
37
+ == Note on Patches/Pull Requests
38
+
39
+ * Fork the project.
40
+ * Make your feature addition or bug fix.
41
+ * Add tests for it. This is important so I don't break it in a
42
+ future version unintentionally.
43
+ * Commit, do not mess with rakefile, version, or history.
44
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
45
+ * Send me a pull request. Bonus points for topic branches.
46
+
47
+ == Copyright
48
+
49
+ Copyright (c) 2010 Ben Myles. See LICENSE for details.
@@ -0,0 +1,123 @@
1
+ module Mongomatic
2
+ class Base
3
+ include ActiveModel::Validations
4
+ include Mongomatic::Modifiers
5
+
6
+ class << self
7
+ def settings
8
+ @settings || Mongomatic.settings
9
+ end
10
+
11
+ def settings=(hash)
12
+ @settings = hash
13
+ reconnect!; hash
14
+ end
15
+
16
+ def reconnect!
17
+ @db = @collection = nil; true
18
+ end
19
+
20
+ def db
21
+ @db ||= Mongo::Connection.new(*self.settings[:connection]).db(self.settings[:db])
22
+ end
23
+
24
+ def collection_name
25
+ self.to_s
26
+ end
27
+
28
+ def collection
29
+ @collection ||= self.db.collection(self.collection_name)
30
+ end
31
+
32
+ def find(query={})
33
+ Mongomatic::Cursor.new(self, collection.find(query))
34
+ end
35
+
36
+ def all
37
+ find
38
+ end
39
+
40
+ def each
41
+ find.each { |found| yield(found) }
42
+ end
43
+
44
+ def first
45
+ find.limit(1).next_document
46
+ end
47
+
48
+ def count
49
+ find.count
50
+ end
51
+ end
52
+
53
+ attr_accessor :removed
54
+
55
+ def initialize(doc={})
56
+ @doc = doc.stringify_keys
57
+ self.removed = false
58
+ end
59
+
60
+ def []=(k,v)
61
+ @doc[k.to_s] = v
62
+ end
63
+
64
+ def [](k)
65
+ @doc[k.to_s]
66
+ end
67
+
68
+ def removed?
69
+ self.removed == true
70
+ end
71
+
72
+ def ==(obj)
73
+ obj.is_a?(self.class) && obj.doc["_id"] == @doc["_id"]
74
+ end
75
+
76
+ def new?
77
+ @doc["_id"] == nil
78
+ end
79
+
80
+ def reload
81
+ if obj = self.class.find({"_id" => @doc["_id"]}).next_document
82
+ @doc = obj.doc; true
83
+ end
84
+ end
85
+
86
+ def insert(opts={})
87
+ return false unless new? && valid?
88
+ if ret = self.class.collection.insert(@doc,opts)
89
+ @doc["_id"] = @doc.delete(:_id); ret
90
+ end
91
+ end
92
+
93
+ def update(opts={},update_doc=@doc)
94
+ return false if new? || removed? || !valid?
95
+ self.class.collection.update({"_id" => @doc["_id"]}, update_doc, opts)
96
+ end
97
+
98
+ def remove(opts={})
99
+ return false if new?
100
+ if ret = self.class.collection.remove({"_id" => @doc["_id"]})
101
+ self.removed = true; freeze; ret
102
+ end
103
+ end
104
+
105
+ def to_hash
106
+ @doc || {}
107
+ end
108
+
109
+ protected
110
+
111
+ def read_attribute_for_validation(key)
112
+ @doc[key.to_s]
113
+ end
114
+
115
+ def doc
116
+ @doc
117
+ end
118
+
119
+ def doc=(v)
120
+ @doc = v
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,37 @@
1
+ module Mongomatic
2
+ class Cursor
3
+ attr_accessor :mongo_cursor
4
+
5
+ def initialize(obj_class, mongo_cursor)
6
+ @obj_class = obj_class
7
+ @mongo_cursor = mongo_cursor
8
+
9
+ @mongo_cursor.public_methods(false).each do |meth|
10
+ next if ["next_document","each","to_a"].include?(meth.to_s)
11
+ (class << self; self; end).class_eval do
12
+ define_method meth do |*args|
13
+ @mongo_cursor.send meth, *args
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ def next_document
20
+ if doc = @mongo_cursor.next_document
21
+ @obj_class.new(doc)
22
+ end
23
+ end
24
+
25
+ alias :next :next_document
26
+
27
+ def each
28
+ @mongo_cursor.each do |doc|
29
+ yield(@obj_class.new(doc))
30
+ end
31
+ end
32
+
33
+ def to_a
34
+ @mongo_cursor.to_a.collect { |doc| @obj_class.new(doc) }
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,105 @@
1
+ module Mongomatic
2
+ module Modifiers
3
+
4
+ # { $push : { field : value } }
5
+ # appends value to field, if field is an existing array, otherwise sets field to the array [value]
6
+ # if field is not present. If field is present but is not an array, an error condition is raised.
7
+ def push(field, val, do_reload=true)
8
+ field = field.to_s
9
+ if update({}, { "$push" => { field => val } })
10
+ reload if do_reload; true
11
+ end
12
+ end
13
+
14
+ # { $pushAll : { field : value_array } }
15
+ # appends each value in value_array to field, if field is an existing array, otherwise sets field to
16
+ # the array value_array if field is not present. If field is present but is not an array, an error
17
+ # condition is raised.
18
+ def push_all(field, val, do_reload=true)
19
+ field = field.to_s
20
+ val = Array(val)
21
+ if update({}, { "$pushAll" => { field => val } })
22
+ reload if do_reload; true
23
+ end
24
+ end
25
+
26
+ # { $pull : { field : _value } }
27
+ # removes all occurrences of value from field, if field is an array. If field is present but is not
28
+ # an array, an error condition is raised.
29
+ def pull(field, val, do_reload=true)
30
+ field = field.to_s
31
+ if update({}, { "$pull" => { field => val } })
32
+ reload if do_reload; true
33
+ end
34
+ end
35
+
36
+ # { $pullAll : { field : value_array } }
37
+ # removes all occurrences of each value in value_array from field, if field is an array. If field is
38
+ # present but is not an array, an error condition is raised.
39
+ def pullAll(field, val, do_reload=true)
40
+ field = field.to_s
41
+ if update({}, { "$pullAll" => { field => val } })
42
+ reload if do_reload; true
43
+ end
44
+ end
45
+
46
+ # { $inc : { field : value } }
47
+ # increments field by the number value if field is present in the object, otherwise sets field to the number value.
48
+ def inc(field, val, do_reload=true)
49
+ field = field.to_s
50
+ if update({}, { "$inc" => { field => val } })
51
+ reload if do_reload; true
52
+ end
53
+ end
54
+
55
+ # { $set : { field : value } }
56
+ # sets field to value. All datatypes are supported with $set.
57
+ def set(field, val, do_reload=true)
58
+ field = field.to_s
59
+ if update({}, { "$set" => { field => val } })
60
+ reload if do_reload; true
61
+ end
62
+ end
63
+
64
+ # { $unset : { field : 1} }
65
+ # Deletes a given field. v1.3+
66
+ def unset(field, do_reload=true)
67
+ field = field.to_s
68
+ if update({}, { "$unset" => { field => 1 } })
69
+ reload if do_reload; true
70
+ end
71
+ end
72
+
73
+ # { $addToSet : { field : value } }
74
+ # Adds value to the array only if its not in the array already.
75
+ #
76
+ # To add many valuest.update
77
+ #
78
+ # { $addToSet : { a : { $each : [ 3 , 5 , 6 ] } } }
79
+ def add_to_set(field, val, do_reload=true)
80
+ field = field.to_s
81
+ if update({}, { "$addToSet" => { field => val } })
82
+ reload if do_reload; true
83
+ end
84
+ end
85
+
86
+ # { $pop : { field : 1 } }
87
+ # removes the last element in an array (ADDED in 1.1)
88
+ def pop_last(field, do_reload=true)
89
+ field = field.to_s
90
+ if update({}, { "$pop" => { field => 1 } })
91
+ reload if do_reload; true
92
+ end
93
+ end
94
+
95
+ # { $pop : { field : -1 } }
96
+ # removes the first element in an array (ADDED in 1.1)
97
+ def pop_first(field, do_reload=true)
98
+ field = field.to_s
99
+ if update({}, { "$pop" => { field => -1 } })
100
+ reload if do_reload; true
101
+ end
102
+ end
103
+
104
+ end
105
+ end
data/lib/mongomatic.rb ADDED
@@ -0,0 +1,26 @@
1
+ gem "bson", "= 1.0.3"
2
+ gem "bson_ext", "= 1.0.1"
3
+ gem "mongo", "= 1.0.3"
4
+ gem "activemodel", ">= 3.0.0.beta4"
5
+
6
+ require "bson"
7
+ require "mongo"
8
+ require "active_model"
9
+
10
+ module Mongomatic
11
+ class << self
12
+ def settings
13
+ @settings || { :connection => ["localhost", 27017, {}], :db => "main" }
14
+ end
15
+
16
+ def settings=(hash)
17
+ @settings = hash
18
+ @db = @collection = nil
19
+ hash
20
+ end
21
+ end
22
+ end
23
+
24
+ require "#{File.dirname(__FILE__)}/mongomatic/cursor"
25
+ require "#{File.dirname(__FILE__)}/mongomatic/modifiers"
26
+ require "#{File.dirname(__FILE__)}/mongomatic/base"
data/test/helper.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'pp'
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ require 'mongomatic'
9
+
10
+ Mongomatic.settings = { :connection => ["localhost", 27017, {}], :db => "mongomatic_test" }
11
+
12
+ class Person < Mongomatic::Base
13
+ validates_presence_of :name
14
+ end
15
+
16
+ class Test::Unit::TestCase
17
+ end
@@ -0,0 +1,42 @@
1
+ require 'helper'
2
+
3
+ class TestMongomatic < Test::Unit::TestCase
4
+ should "be able to insert, update, remove documents" do
5
+ Person.collection.remove
6
+
7
+ p = Person.new
8
+
9
+ assert !p.valid?
10
+ assert_equal({:name=>["can't be blank"]}, p.errors)
11
+
12
+ p["name"] = "Ben Myles"
13
+ p["birth_year"] = 1984
14
+ p["created_at"] = Time.now.utc
15
+ p["admin"] = true
16
+
17
+ assert !p.update
18
+
19
+ assert p.insert.is_a?(BSON::ObjectID)
20
+
21
+ assert_equal 1, Person.collection.count
22
+
23
+ cursor = Person.find({"_id" => p["_id"]})
24
+ found = cursor.next
25
+ assert_equal p, found
26
+ assert_equal "Ben Myles", found["name"]
27
+
28
+ p["name"] = "Benjamin"
29
+ assert p.update
30
+
31
+ cursor = Person.find({"_id" => p["_id"]})
32
+ found = cursor.next
33
+ assert_equal p, found
34
+ assert_equal "Benjamin", found["name"]
35
+
36
+ assert p.remove
37
+ assert p.removed?
38
+ cursor = Person.find({"_id" => p["_id"]})
39
+ found = cursor.next
40
+ assert_nil found
41
+ end
42
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongomatic
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Ben Myles
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-05 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: shoulda
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 2
30
+ - 11
31
+ - 1
32
+ version: 2.11.1
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: bson
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - "="
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 1
45
+ - 0
46
+ - 3
47
+ version: 1.0.3
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: bson_ext
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - "="
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 1
60
+ - 0
61
+ - 1
62
+ version: 1.0.1
63
+ type: :runtime
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: mongo
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - "="
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 1
75
+ - 0
76
+ - 3
77
+ version: 1.0.3
78
+ type: :runtime
79
+ version_requirements: *id004
80
+ - !ruby/object:Gem::Dependency
81
+ name: activemodel
82
+ prerelease: false
83
+ requirement: &id005 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 3
90
+ - 0
91
+ - 0
92
+ - beta4
93
+ version: 3.0.0.beta4
94
+ type: :runtime
95
+ version_requirements: *id005
96
+ description: Mongomatic is a simple Ruby object mapper for Mongo
97
+ email: ben.myles@gmail.com
98
+ executables: []
99
+
100
+ extensions: []
101
+
102
+ extra_rdoc_files:
103
+ - LICENSE
104
+ - README.rdoc
105
+ files:
106
+ - lib/mongomatic.rb
107
+ - lib/mongomatic/base.rb
108
+ - lib/mongomatic/cursor.rb
109
+ - lib/mongomatic/modifiers.rb
110
+ - LICENSE
111
+ - README.rdoc
112
+ - test/helper.rb
113
+ - test/test_meta_mongo.rb
114
+ has_rdoc: true
115
+ homepage: http://github.com/benmyles/mongomatic
116
+ licenses: []
117
+
118
+ post_install_message:
119
+ rdoc_options:
120
+ - --charset=UTF-8
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ segments:
129
+ - 0
130
+ version: "0"
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ none: false
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ segments:
137
+ - 0
138
+ version: "0"
139
+ requirements: []
140
+
141
+ rubyforge_project:
142
+ rubygems_version: 1.3.7
143
+ signing_key:
144
+ specification_version: 3
145
+ summary: Mongomatic is a simple Ruby object mapper for Mongo
146
+ test_files:
147
+ - test/helper.rb
148
+ - test/test_meta_mongo.rb