mongomatic 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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