candy 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.markdown +8 -0
- data/Rakefile +3 -1
- data/VERSION +1 -1
- data/candy.gemspec +11 -5
- data/lib/candy/crunch.rb +77 -4
- data/lib/candy/wrapper.rb +5 -12
- data/spec/candy/crunch_spec.rb +37 -2
- data/spec/candy/piece_spec.rb +2 -2
- data/spec/candy/wrapper_spec.rb +3 -3
- metadata +38 -10
data/HISTORY.markdown
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
|
3
3
|
This document aims to provide only an overview. Further, we've only really been tracking things since **v0.2**. For obsessive detail, just check out the `git log`.
|
4
4
|
|
5
|
+
## v0.2.2 - 2010-04-12 (the "I hate reporting bugs to the MongoDB team" release)
|
6
|
+
|
7
|
+
The Mongo gem has broken the BSON functions out into a separate bson gem, so I had to fix things. This means Candy is no longer compatible with the Mongo gem < 0.20.1. Que sera. (Also, the bson_ext gem **must** be installed due to a bug. I'll remove the dependency when they fix it.) Additional minor bonus: authentication.
|
8
|
+
|
9
|
+
* New BSON::* classes correctly referenced in Candy::Wrapper
|
10
|
+
* Candy.username and Candy.password properties to automatically authenticate at the global level
|
11
|
+
* Class-specific .username and .password properties for class-specific databases
|
12
|
+
|
5
13
|
## v0.2.1 - 2010-04-04 (the "Oops" release)
|
6
14
|
|
7
15
|
I screwed up in my use of Jeweler, and managed to get my versions out of sync between Github and Rubygems.org. I tried to `gem yank` the one from Rubygems, but it won't let me push again with the same version number. To justify bumping the patch number, I added this changelog. Yeah, I know. Pathetic.
|
data/Rakefile
CHANGED
@@ -16,7 +16,9 @@ DESCRIPTION
|
|
16
16
|
gem.email = "sfeley@gmail.com"
|
17
17
|
gem.homepage = "http://github.com/SFEley/candy"
|
18
18
|
gem.authors = ["Stephen Eley"]
|
19
|
-
gem.add_dependency "
|
19
|
+
gem.add_dependency "bson", ">= 0.20.1"
|
20
|
+
gem.add_dependency "bson_ext", '>= 0.20.1'
|
21
|
+
gem.add_dependency "mongo", ">= 0.20.1"
|
20
22
|
gem.add_development_dependency "rspec", ">= 1.2.9"
|
21
23
|
# gem.add_development_dependency "yard", ">= 0"
|
22
24
|
gem.add_development_dependency "mocha", ">= 0.9.8"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.2
|
data/candy.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{candy}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Stephen Eley"]
|
12
|
-
s.date = %q{2010-04-
|
12
|
+
s.date = %q{2010-04-12}
|
13
13
|
s.description = %q{Candy provides simple, transparent object persistence for the MongoDB database. Classes that
|
14
14
|
include Candy modules save all properties to Mongo automatically, can be recursively embedded,
|
15
15
|
and can retrieve records with chainable open-ended class methods, eliminating the need for
|
@@ -76,16 +76,22 @@ method calls like 'save' and 'find.'
|
|
76
76
|
s.specification_version = 3
|
77
77
|
|
78
78
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
79
|
-
s.add_runtime_dependency(%q<
|
79
|
+
s.add_runtime_dependency(%q<bson>, [">= 0.20.1"])
|
80
|
+
s.add_runtime_dependency(%q<bson_ext>, [">= 0.20.1"])
|
81
|
+
s.add_runtime_dependency(%q<mongo>, [">= 0.20.1"])
|
80
82
|
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
81
83
|
s.add_development_dependency(%q<mocha>, [">= 0.9.8"])
|
82
84
|
else
|
83
|
-
s.add_dependency(%q<
|
85
|
+
s.add_dependency(%q<bson>, [">= 0.20.1"])
|
86
|
+
s.add_dependency(%q<bson_ext>, [">= 0.20.1"])
|
87
|
+
s.add_dependency(%q<mongo>, [">= 0.20.1"])
|
84
88
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
85
89
|
s.add_dependency(%q<mocha>, [">= 0.9.8"])
|
86
90
|
end
|
87
91
|
else
|
88
|
-
s.add_dependency(%q<
|
92
|
+
s.add_dependency(%q<bson>, [">= 0.20.1"])
|
93
|
+
s.add_dependency(%q<bson_ext>, [">= 0.20.1"])
|
94
|
+
s.add_dependency(%q<mongo>, [">= 0.20.1"])
|
89
95
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
90
96
|
s.add_dependency(%q<mocha>, [">= 0.9.8"])
|
91
97
|
end
|
data/lib/candy/crunch.rb
CHANGED
@@ -58,7 +58,7 @@ module Candy
|
|
58
58
|
when Mongo::DB
|
59
59
|
@db = val
|
60
60
|
when String
|
61
|
-
@db = Mongo::DB.new(val, connection)
|
61
|
+
@db = maybe_authenticate(Mongo::DB.new(val, connection))
|
62
62
|
when nil
|
63
63
|
@db = nil
|
64
64
|
else
|
@@ -69,7 +69,29 @@ module Candy
|
|
69
69
|
# Returns the database you gave, or creates a default database named for your username (or 'candy' if it
|
70
70
|
# can't find a username).
|
71
71
|
def self.db
|
72
|
-
@db ||= Mongo::DB.new(Etc.getlogin || 'candy', connection, :strict => false)
|
72
|
+
@db ||= maybe_authenticate(Mongo::DB.new(Etc.getlogin || 'candy', connection, :strict => false))
|
73
|
+
end
|
74
|
+
|
75
|
+
# Sets the user for Mongo authentication. Both username AND password must be set or nothing will happen.
|
76
|
+
# Also ignored if you supply your own Mongo::DB object instead of a string.
|
77
|
+
def self.username=(val)
|
78
|
+
@username = val
|
79
|
+
end
|
80
|
+
|
81
|
+
# The user for Mongo authentication.
|
82
|
+
def self.username
|
83
|
+
@username
|
84
|
+
end
|
85
|
+
|
86
|
+
# Sets the password for Mongo authentication. Both username AND password must be set or nothing will happen.
|
87
|
+
# Also ignored if you supply your own Mongo::DB object instead of a string.
|
88
|
+
def self.password=(val)
|
89
|
+
@password = val
|
90
|
+
end
|
91
|
+
|
92
|
+
# The password for Mongo authentication
|
93
|
+
def self.password
|
94
|
+
@password
|
73
95
|
end
|
74
96
|
|
75
97
|
# All of the hard crunchy bits that connect us to a collection within a Mongo database.
|
@@ -97,7 +119,7 @@ module Candy
|
|
97
119
|
when Mongo::DB
|
98
120
|
@db = val
|
99
121
|
when String
|
100
|
-
@db = Mongo::DB.new(val, connection)
|
122
|
+
@db = maybe_authenticate(Mongo::DB.new(val, connection))
|
101
123
|
when nil
|
102
124
|
@db = nil
|
103
125
|
else
|
@@ -110,6 +132,30 @@ module Candy
|
|
110
132
|
@db ||= Candy.db
|
111
133
|
end
|
112
134
|
|
135
|
+
# Sets the user for Mongo authentication. Defaults to the global Candy.username.
|
136
|
+
# Both username AND password must be set or nothing will happen.
|
137
|
+
# Also ignored if you supply your own Mongo::DB object instead of a string.
|
138
|
+
def username=(val)
|
139
|
+
@username = val
|
140
|
+
end
|
141
|
+
|
142
|
+
# The user for Mongo authentication.
|
143
|
+
def username
|
144
|
+
@username ||= Candy.username
|
145
|
+
end
|
146
|
+
|
147
|
+
# Sets the password for Mongo authentication. Defaults to the global Candy.password.
|
148
|
+
# Both username AND password must be set or nothing will happen.
|
149
|
+
# Also ignored if you supply your own Mongo::DB object instead of a string.
|
150
|
+
def password=(val)
|
151
|
+
@password = val
|
152
|
+
end
|
153
|
+
|
154
|
+
# The password for Mongo authentication
|
155
|
+
def password
|
156
|
+
@password ||= Candy.password
|
157
|
+
end
|
158
|
+
|
113
159
|
# Accepts either a Mongo::Collection object or a string with the collection name. If you provide a
|
114
160
|
# Mongo::Collection object, the default database and connection are not used.
|
115
161
|
def collection=(val)
|
@@ -140,10 +186,23 @@ module Candy
|
|
140
186
|
else
|
141
187
|
raise TypeError, "Index direction should be :asc or :desc"
|
142
188
|
end
|
143
|
-
collection.create_index(property
|
189
|
+
collection.create_index([[property, mongo_direction]])
|
144
190
|
end
|
191
|
+
|
192
|
+
private
|
193
|
+
# If we don't have a username AND password, returns the DB given. If we do, returns the DB if-and-only-if
|
194
|
+
# we can authenticate on that DB.
|
195
|
+
def maybe_authenticate(db)
|
196
|
+
if @username && @password
|
197
|
+
db if db.authenticate(@username, @password)
|
198
|
+
else
|
199
|
+
db
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
145
203
|
end
|
146
204
|
|
205
|
+
|
147
206
|
# We're implementing FindAndModify on Mongo 1.4 until the Ruby driver gets around to being updated...
|
148
207
|
def findAndModify(query, update, sort={})
|
149
208
|
command = OrderedHash[
|
@@ -154,9 +213,23 @@ module Candy
|
|
154
213
|
]
|
155
214
|
result = self.class.db.command(command)
|
156
215
|
end
|
216
|
+
|
157
217
|
|
158
218
|
def self.included(receiver)
|
159
219
|
receiver.extend ClassMethods
|
160
220
|
end
|
221
|
+
|
161
222
|
end
|
223
|
+
|
224
|
+
private
|
225
|
+
# If we don't have a username AND password, returns the DB given. If we do, returns the DB if-and-only-if
|
226
|
+
# we can authenticate on that DB.
|
227
|
+
def self.maybe_authenticate(db)
|
228
|
+
if @username && @password
|
229
|
+
db if db.authenticate(@username, @password)
|
230
|
+
else
|
231
|
+
db
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
162
235
|
end
|
data/lib/candy/wrapper.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'bson'
|
2
2
|
require 'date' # Only so we know what one is. Argh.
|
3
3
|
require 'candy/qualified_const_get'
|
4
4
|
|
@@ -16,10 +16,10 @@ module Candy
|
|
16
16
|
Float,
|
17
17
|
Time,
|
18
18
|
Regexp,
|
19
|
-
ByteBuffer,
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
BSON::ByteBuffer,
|
20
|
+
BSON::ObjectID,
|
21
|
+
BSON::Code,
|
22
|
+
BSON::DBRef]
|
23
23
|
|
24
24
|
# Makes an object safe for the sharp pointy edges of MongoDB. Types properly serialized
|
25
25
|
# by the BSON.serialize call get passed through unmolested; others are unpacked and their
|
@@ -28,8 +28,6 @@ module Candy
|
|
28
28
|
# Pass the simple cases through
|
29
29
|
return thing if BSON_SAFE.include?(thing.class)
|
30
30
|
case thing
|
31
|
-
# when Symbol
|
32
|
-
# wrap_symbol(thing)
|
33
31
|
when Array
|
34
32
|
wrap_array(thing)
|
35
33
|
when Hash
|
@@ -71,11 +69,6 @@ module Candy
|
|
71
69
|
wrapped
|
72
70
|
end
|
73
71
|
|
74
|
-
# Returns a string that's distinctive enough for us to unwrap later and produce the same symbol.
|
75
|
-
def self.wrap_symbol(symbol)
|
76
|
-
"__:" + symbol.to_s
|
77
|
-
end
|
78
|
-
|
79
72
|
# Returns a nested hash containing the class and instance variables of the object. It's not the
|
80
73
|
# deepest we could ever go (it doesn't handle singleton methods, etc.) but it's a start.
|
81
74
|
def self.wrap_object(object)
|
data/spec/candy/crunch_spec.rb
CHANGED
@@ -47,6 +47,8 @@ describe Candy::Crunch do
|
|
47
47
|
PeanutBrittle.connection = nil
|
48
48
|
PeanutBrittle.instance_variable_get(:@db).should be_nil
|
49
49
|
end
|
50
|
+
|
51
|
+
|
50
52
|
|
51
53
|
after(:each) do
|
52
54
|
Candy.host = nil
|
@@ -98,6 +100,39 @@ describe Candy::Crunch do
|
|
98
100
|
PeanutBrittle.instance_variable_get(:@collection).should be_nil
|
99
101
|
end
|
100
102
|
|
103
|
+
it "takes a username and password if you provide them globally" do
|
104
|
+
Mongo::DB.any_instance.expects(:authenticate).with('johnny5','is_alive').returns(true)
|
105
|
+
Candy.username = 'johnny5'
|
106
|
+
Candy.password = 'is_alive'
|
107
|
+
PeanutBrittle.db.collection_names.should_not be_nil
|
108
|
+
end
|
109
|
+
|
110
|
+
it "takes a username and password if you provide them at the class level" do
|
111
|
+
Mongo::DB.any_instance.expects(:authenticate).with('johnny5','is_alive').returns(true)
|
112
|
+
PeanutBrittle.username = 'johnny5'
|
113
|
+
PeanutBrittle.password = 'is_alive'
|
114
|
+
PeanutBrittle.db = 'candy_test'
|
115
|
+
PeanutBrittle.db.collection_names.should_not be_nil
|
116
|
+
end
|
117
|
+
|
118
|
+
it "does not authenticate if only a username is given" do
|
119
|
+
Mongo::DB.any_instance.expects(:authenticate).never
|
120
|
+
Candy.username = 'johnny5'
|
121
|
+
PeanutBrittle.db.collection_names.should_not be_nil
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
it "does not authenticate if only a password is given" do
|
126
|
+
Mongo::DB.any_instance.expects(:authenticate).never
|
127
|
+
Candy.password = 'is_alive'
|
128
|
+
PeanutBrittle.db.collection_names.should_not be_nil
|
129
|
+
end
|
130
|
+
|
131
|
+
after(:each) do
|
132
|
+
Candy.username = nil
|
133
|
+
Candy.password = nil
|
134
|
+
end
|
135
|
+
|
101
136
|
after(:all) do
|
102
137
|
Candy.db = 'candy_test' # Get back to our starting point
|
103
138
|
end
|
@@ -128,12 +163,12 @@ describe Candy::Crunch do
|
|
128
163
|
describe "index" do
|
129
164
|
it "can be created with just a property name" do
|
130
165
|
PeanutBrittle.index(:blah)
|
131
|
-
PeanutBrittle.collection.index_information.values[1].should ==
|
166
|
+
PeanutBrittle.collection.index_information.values[1]['key'].should == {"blah" => Mongo::ASCENDING}
|
132
167
|
end
|
133
168
|
|
134
169
|
it "can be created with a direction" do
|
135
170
|
PeanutBrittle.index(:fwah, :desc)
|
136
|
-
PeanutBrittle.collection.index_information.values[1].should ==
|
171
|
+
PeanutBrittle.collection.index_information.values[1]['key'].should == {"fwah" => Mongo::DESCENDING}
|
137
172
|
end
|
138
173
|
|
139
174
|
it "throws an exception if you give it a type other than :asc or :desc" do
|
data/spec/candy/piece_spec.rb
CHANGED
@@ -21,7 +21,7 @@ describe Candy::Piece do
|
|
21
21
|
|
22
22
|
it "knows its ID after inserting" do
|
23
23
|
@this.name = 'Zagnut'
|
24
|
-
@this.id.should be_a(
|
24
|
+
@this.id.should be_a(BSON::ObjectID)
|
25
25
|
end
|
26
26
|
|
27
27
|
|
@@ -112,7 +112,7 @@ describe Candy::Piece do
|
|
112
112
|
end
|
113
113
|
|
114
114
|
it "returns nil on an object that can't be found" do
|
115
|
-
id =
|
115
|
+
id = BSON::ObjectID.new
|
116
116
|
Zagnut(id).should be_nil
|
117
117
|
end
|
118
118
|
|
data/spec/candy/wrapper_spec.rb
CHANGED
@@ -50,7 +50,7 @@ module Candy
|
|
50
50
|
end
|
51
51
|
|
52
52
|
it "can wrap an ObjectID" do
|
53
|
-
i =
|
53
|
+
i = BSON::ObjectID.new
|
54
54
|
Wrapper.wrap(i).should == i
|
55
55
|
end
|
56
56
|
|
@@ -65,12 +65,12 @@ module Candy
|
|
65
65
|
end
|
66
66
|
|
67
67
|
it "can wrap a Mongo code object (if we ever need to)" do
|
68
|
-
c =
|
68
|
+
c = BSON::Code.new('5')
|
69
69
|
Wrapper.wrap(c).should == c
|
70
70
|
end
|
71
71
|
|
72
72
|
it "can wrap a Mongo DBRef (if we ever need to)" do
|
73
|
-
d =
|
73
|
+
d = BSON::DBRef.new('foo', BSON::ObjectID.new)
|
74
74
|
Wrapper.wrap(d).should == d
|
75
75
|
end
|
76
76
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 2
|
9
|
+
version: 0.2.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Stephen Eley
|
@@ -14,11 +14,11 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-04-
|
17
|
+
date: 2010-04-12 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
21
|
+
name: bson
|
22
22
|
prerelease: false
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
@@ -26,15 +26,43 @@ dependencies:
|
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
segments:
|
28
28
|
- 0
|
29
|
-
-
|
29
|
+
- 20
|
30
30
|
- 1
|
31
|
-
version: 0.
|
31
|
+
version: 0.20.1
|
32
32
|
type: :runtime
|
33
33
|
version_requirements: *id001
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
35
|
+
name: bson_ext
|
36
36
|
prerelease: false
|
37
37
|
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
- 20
|
44
|
+
- 1
|
45
|
+
version: 0.20.1
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: mongo
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
- 20
|
58
|
+
- 1
|
59
|
+
version: 0.20.1
|
60
|
+
type: :runtime
|
61
|
+
version_requirements: *id003
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
prerelease: false
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
38
66
|
requirements:
|
39
67
|
- - ">="
|
40
68
|
- !ruby/object:Gem::Version
|
@@ -44,11 +72,11 @@ dependencies:
|
|
44
72
|
- 9
|
45
73
|
version: 1.2.9
|
46
74
|
type: :development
|
47
|
-
version_requirements: *
|
75
|
+
version_requirements: *id004
|
48
76
|
- !ruby/object:Gem::Dependency
|
49
77
|
name: mocha
|
50
78
|
prerelease: false
|
51
|
-
requirement: &
|
79
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
52
80
|
requirements:
|
53
81
|
- - ">="
|
54
82
|
- !ruby/object:Gem::Version
|
@@ -58,7 +86,7 @@ dependencies:
|
|
58
86
|
- 8
|
59
87
|
version: 0.9.8
|
60
88
|
type: :development
|
61
|
-
version_requirements: *
|
89
|
+
version_requirements: *id005
|
62
90
|
description: |
|
63
91
|
Candy provides simple, transparent object persistence for the MongoDB database. Classes that
|
64
92
|
include Candy modules save all properties to Mongo automatically, can be recursively embedded,
|