ohm 0.0.7 → 0.0.9
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/README.markdown +6 -4
- data/lib/ohm.rb +173 -17
- data/lib/ohm/redis.rb +6 -3
- data/lib/ohm/validations.rb +9 -9
- data/test/db/redis.pid +1 -1
- data/test/errors_test.rb +6 -6
- data/test/indices_test.rb +6 -1
- data/test/model_test.rb +72 -10
- data/test/validations_test.rb +45 -20
- metadata +2 -2
data/README.markdown
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
Ohm
|
2
|
-
|
1
|
+
Ohm ॐ
|
2
|
+
=====
|
3
3
|
|
4
4
|
Object-hash mapping library for Redis.
|
5
5
|
|
@@ -23,6 +23,8 @@ Usage
|
|
23
23
|
set :participants
|
24
24
|
list :comments
|
25
25
|
|
26
|
+
index :name
|
27
|
+
|
26
28
|
def validate
|
27
29
|
assert_present :name
|
28
30
|
end
|
@@ -31,11 +33,11 @@ Usage
|
|
31
33
|
event = Event.create(:name => "Ruby Tuesday")
|
32
34
|
event.participants << "Michel Martens"
|
33
35
|
event.participants << "Damian Janowski"
|
34
|
-
event.participants
|
36
|
+
event.participants.all #=> ["Damian Janowski", "Michel Martens"]
|
35
37
|
|
36
38
|
event.comments << "Very interesting event!"
|
37
39
|
event.comments << "Agree"
|
38
|
-
event.comments
|
40
|
+
event.comments.all #=> ["Very interesting event!", "Agree"]
|
39
41
|
|
40
42
|
another_event = Event.new
|
41
43
|
another_event.valid? #=> false
|
data/lib/ohm.rb
CHANGED
@@ -1,19 +1,33 @@
|
|
1
|
+
require "base64"
|
1
2
|
require File.join(File.dirname(__FILE__), "ohm", "redis")
|
2
3
|
require File.join(File.dirname(__FILE__), "ohm", "validations")
|
3
4
|
|
4
5
|
module Ohm
|
6
|
+
|
7
|
+
# Provides access to the redis database. This is shared accross all models and instances.
|
5
8
|
def redis
|
6
9
|
@redis
|
7
10
|
end
|
8
11
|
|
9
|
-
|
10
|
-
|
12
|
+
# Connect to a redis database.
|
13
|
+
#
|
14
|
+
# @param options [Hash] options to create a message with.
|
15
|
+
# @option options [#to_s] :host ('127.0.0.1') Host of the redis database.
|
16
|
+
# @option options [#to_s] :port (6379) Port number.
|
17
|
+
# @option options [#to_s] :db (0) Database number.
|
18
|
+
# @option options [#to_s] :timeout (0) Database timeout in seconds.
|
19
|
+
# @example Connect to a database in port 6380.
|
20
|
+
# Ohm.connect(:port => 6380)
|
21
|
+
def connect(*options)
|
22
|
+
@redis = Ohm::Redis.new(*options)
|
11
23
|
end
|
12
24
|
|
25
|
+
# Clear the database.
|
13
26
|
def flush
|
14
27
|
@redis.flushdb
|
15
28
|
end
|
16
29
|
|
30
|
+
# Join the parameters with ":" to create a key.
|
17
31
|
def key(*args)
|
18
32
|
args.join(":")
|
19
33
|
end
|
@@ -21,42 +35,93 @@ module Ohm
|
|
21
35
|
module_function :key, :connect, :flush, :redis
|
22
36
|
|
23
37
|
module Attributes
|
24
|
-
class Collection
|
38
|
+
class Collection
|
39
|
+
include Enumerable
|
40
|
+
|
25
41
|
attr_accessor :key, :db
|
26
42
|
|
27
43
|
def initialize(db, key)
|
28
44
|
self.db = db
|
29
45
|
self.key = key
|
30
|
-
|
46
|
+
end
|
47
|
+
|
48
|
+
def each(&block)
|
49
|
+
all.each(&block)
|
50
|
+
end
|
51
|
+
|
52
|
+
def all(model = nil)
|
53
|
+
model ? raw.collect { |id| model[id] } : raw
|
31
54
|
end
|
32
55
|
end
|
33
56
|
|
57
|
+
# Represents a Redis list.
|
58
|
+
#
|
59
|
+
# @example Use a list attribute.
|
60
|
+
#
|
61
|
+
# class Event < Ohm::Model
|
62
|
+
# attribute :name
|
63
|
+
# list :participants
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# event = Event.create :name => "Redis Meeting"
|
67
|
+
# event.participants << "Albert"
|
68
|
+
# event.participants << "Benoit"
|
69
|
+
# event.participants.all #=> ["Albert", "Benoit"]
|
34
70
|
class List < Collection
|
35
|
-
def retrieve
|
36
|
-
db.list(key)
|
37
|
-
end
|
38
71
|
|
72
|
+
# @param value [#to_s] Pushes value to the list.
|
39
73
|
def << value
|
40
|
-
|
74
|
+
db.rpush(key, value)
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def raw
|
80
|
+
db.list(key)
|
41
81
|
end
|
42
82
|
end
|
43
83
|
|
84
|
+
# Represents a Redis set.
|
85
|
+
#
|
86
|
+
# @example Use a set attribute.
|
87
|
+
#
|
88
|
+
# class Company < Ohm::Model
|
89
|
+
# attribute :name
|
90
|
+
# set :employees
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# company = Company.create :name => "Redis Co."
|
94
|
+
# company.employees << "Albert"
|
95
|
+
# company.employees << "Benoit"
|
96
|
+
# company.employees.all #=> ["Albert", "Benoit"]
|
97
|
+
# company.include?("Albert") #=> true
|
44
98
|
class Set < Collection
|
45
|
-
def retrieve
|
46
|
-
db.smembers(key).sort
|
47
|
-
end
|
48
99
|
|
100
|
+
# @param value [#to_s] Adds value to the list.
|
49
101
|
def << value
|
50
|
-
|
102
|
+
db.sadd(key, value)
|
103
|
+
end
|
104
|
+
|
105
|
+
# @param value [Ohm::Model#id] Adds the id of the object if it's an Ohm::Model.
|
106
|
+
def add model
|
107
|
+
raise ArgumentError unless model.kind_of?(Ohm::Model)
|
108
|
+
raise ArgumentError unless model.id
|
109
|
+
self << model.id
|
51
110
|
end
|
52
111
|
|
53
112
|
def delete(value)
|
54
|
-
|
113
|
+
db.srem(key, value)
|
55
114
|
end
|
56
115
|
|
57
116
|
def include?(value)
|
58
117
|
db.sismember(key, value)
|
59
118
|
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def raw
|
123
|
+
db.smembers(key).sort
|
124
|
+
end
|
60
125
|
end
|
61
126
|
end
|
62
127
|
|
@@ -64,6 +129,13 @@ module Ohm
|
|
64
129
|
module Validations
|
65
130
|
include Ohm::Validations
|
66
131
|
|
132
|
+
# Validates that the attribute or array of attributes are unique. For this,
|
133
|
+
# an index of the same kind must exist.
|
134
|
+
#
|
135
|
+
# @overload assert_unique :name
|
136
|
+
# Validates that the name attribute is unique.
|
137
|
+
# @overload assert_unique [:street, :city]
|
138
|
+
# Validates that the :street and :city pair is unique.
|
67
139
|
def assert_unique(attrs)
|
68
140
|
index_key = index_key_for(Array(attrs), read_locals(Array(attrs)))
|
69
141
|
assert(db.scard(index_key).zero? || db.sismember(index_key, id), [Array(attrs), :not_unique])
|
@@ -76,10 +148,15 @@ module Ohm
|
|
76
148
|
|
77
149
|
@@attributes = Hash.new { |hash, key| hash[key] = [] }
|
78
150
|
@@collections = Hash.new { |hash, key| hash[key] = [] }
|
151
|
+
@@counters = Hash.new { |hash, key| hash[key] = [] }
|
79
152
|
@@indices = Hash.new { |hash, key| hash[key] = [] }
|
80
153
|
|
81
154
|
attr_accessor :id
|
82
155
|
|
156
|
+
# Defines a string attribute for the model. This attribute will be persisted by Redis
|
157
|
+
# as a string. Any value stored here will be retrieved in its string representation.
|
158
|
+
#
|
159
|
+
# @param name [Symbol] Name of the attribute.
|
83
160
|
def self.attribute(name)
|
84
161
|
define_method(name) do
|
85
162
|
read_local(name)
|
@@ -92,16 +169,58 @@ module Ohm
|
|
92
169
|
attributes << name
|
93
170
|
end
|
94
171
|
|
172
|
+
# Defines a counter attribute for the model. This attribute can't be assigned, only incremented
|
173
|
+
# or decremented. It will be zero by default.
|
174
|
+
#
|
175
|
+
# @param name [Symbol] Name of the counter.
|
176
|
+
def self.counter(name)
|
177
|
+
define_method(name) do
|
178
|
+
read_local(name).to_i
|
179
|
+
end
|
180
|
+
|
181
|
+
counters << name
|
182
|
+
end
|
183
|
+
|
184
|
+
# Defines a list attribute for the model. It can be accessed only after the model instance
|
185
|
+
# is created.
|
186
|
+
#
|
187
|
+
# @param name [Symbol] Name of the list.
|
95
188
|
def self.list(name)
|
96
189
|
attr_list_reader(name)
|
97
190
|
collections << name
|
98
191
|
end
|
99
192
|
|
193
|
+
# Defines a set attribute for the model. It can be accessed only after the model instance
|
194
|
+
# is created. Sets are recommended when insertion and retrival order is irrelevant, and
|
195
|
+
# operations like union, join, and membership checks are important.
|
196
|
+
#
|
197
|
+
# @param name [Symbol] Name of the set.
|
100
198
|
def self.set(name)
|
101
199
|
attr_set_reader(name)
|
102
200
|
collections << name
|
103
201
|
end
|
104
202
|
|
203
|
+
# Creates an index (a set) that will be used for finding instances.
|
204
|
+
#
|
205
|
+
# If you want to find a model instance by some attribute value, then an index for that
|
206
|
+
# attribute must exist.
|
207
|
+
#
|
208
|
+
# Each index declaration creates an index. It can be either an index on one particular attribute,
|
209
|
+
# or an index accross many attributes.
|
210
|
+
#
|
211
|
+
# @example
|
212
|
+
# class User < Ohm::Model
|
213
|
+
# attribute :email
|
214
|
+
# index :email
|
215
|
+
# end
|
216
|
+
#
|
217
|
+
# # Now this is possible:
|
218
|
+
# User.find :email, "ohm@example.com"
|
219
|
+
#
|
220
|
+
# @overload index :name
|
221
|
+
# Creates an index for the name attribute.
|
222
|
+
# @overload index [:street, :city]
|
223
|
+
# Creates a composite index for street and city.
|
105
224
|
def self.index(attrs)
|
106
225
|
indices << Array(attrs)
|
107
226
|
end
|
@@ -134,6 +253,10 @@ module Ohm
|
|
134
253
|
@@attributes[self]
|
135
254
|
end
|
136
255
|
|
256
|
+
def self.counters
|
257
|
+
@@counters[self]
|
258
|
+
end
|
259
|
+
|
137
260
|
def self.collections
|
138
261
|
@@collections[self]
|
139
262
|
end
|
@@ -143,11 +266,23 @@ module Ohm
|
|
143
266
|
end
|
144
267
|
|
145
268
|
def self.create(*args)
|
146
|
-
new(*args)
|
269
|
+
model = new(*args)
|
270
|
+
model.create
|
271
|
+
model
|
147
272
|
end
|
148
273
|
|
149
274
|
def self.find(attribute, value)
|
150
|
-
filter(Ohm.key(attribute, value))
|
275
|
+
filter(Ohm.key(attribute, encode(value)))
|
276
|
+
end
|
277
|
+
|
278
|
+
def self.encode(value)
|
279
|
+
Base64.encode64(value.to_s).chomp
|
280
|
+
end
|
281
|
+
|
282
|
+
def self.encode_each(values)
|
283
|
+
values.collect do |value|
|
284
|
+
encode(value)
|
285
|
+
end
|
151
286
|
end
|
152
287
|
|
153
288
|
def initialize(attrs = {})
|
@@ -179,16 +314,37 @@ module Ohm
|
|
179
314
|
|
180
315
|
def delete
|
181
316
|
delete_from_indices
|
182
|
-
delete_attributes(collections)
|
183
317
|
delete_attributes(attributes)
|
318
|
+
delete_attributes(counters)
|
319
|
+
delete_attributes(collections)
|
184
320
|
delete_model_membership
|
185
321
|
self
|
186
322
|
end
|
187
323
|
|
324
|
+
# Increment the attribute denoted by :att.
|
325
|
+
#
|
326
|
+
# @param att [Symbol] Attribute to increment.
|
327
|
+
def incr(att)
|
328
|
+
raise ArgumentError unless counters.include?(att)
|
329
|
+
write_local(att, db.incr(key(att)))
|
330
|
+
end
|
331
|
+
|
332
|
+
# Decrement the attribute denoted by :att.
|
333
|
+
#
|
334
|
+
# @param att [Symbol] Attribute to decrement.
|
335
|
+
def decr(att)
|
336
|
+
raise ArgumentError unless counters.include?(att)
|
337
|
+
write_local(att, db.decr(key(att)))
|
338
|
+
end
|
339
|
+
|
188
340
|
def attributes
|
189
341
|
self.class.attributes
|
190
342
|
end
|
191
343
|
|
344
|
+
def counters
|
345
|
+
self.class.counters
|
346
|
+
end
|
347
|
+
|
192
348
|
def collections
|
193
349
|
self.class.collections
|
194
350
|
end
|
@@ -303,7 +459,7 @@ module Ohm
|
|
303
459
|
end
|
304
460
|
|
305
461
|
def index_key_for(attrs, values)
|
306
|
-
self.class.key *(attrs + values)
|
462
|
+
self.class.key *(attrs + self.class.encode_each(values))
|
307
463
|
end
|
308
464
|
end
|
309
465
|
end
|
data/lib/ohm/redis.rb
CHANGED
@@ -157,9 +157,12 @@ module Ohm
|
|
157
157
|
def call_command(argv)
|
158
158
|
connect unless connected?
|
159
159
|
raw_call_command(argv.dup)
|
160
|
-
rescue Errno::ECONNRESET
|
161
|
-
reconnect
|
162
|
-
|
160
|
+
rescue Errno::ECONNRESET, Errno::EPIPE
|
161
|
+
if reconnect
|
162
|
+
raw_call_command(argv.dup)
|
163
|
+
else
|
164
|
+
raise Errno::ECONNRESET
|
165
|
+
end
|
163
166
|
end
|
164
167
|
|
165
168
|
def raw_call_command(argv)
|
data/lib/ohm/validations.rb
CHANGED
@@ -72,20 +72,20 @@ module Ohm
|
|
72
72
|
|
73
73
|
protected
|
74
74
|
|
75
|
-
def assert_format(att, format)
|
76
|
-
if assert_present(att)
|
77
|
-
assert
|
75
|
+
def assert_format(att, format, error = [att, :format])
|
76
|
+
if assert_present(att, error)
|
77
|
+
assert(send(att).to_s.match(format), error)
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
def assert_present(att)
|
82
|
-
|
83
|
-
assert !send(att).empty?, [att, :empty]
|
84
|
-
end
|
81
|
+
def assert_present(att, error = [att, :not_present])
|
82
|
+
assert(!send(att).to_s.empty?, error)
|
85
83
|
end
|
86
84
|
|
87
|
-
def
|
88
|
-
|
85
|
+
def assert_numeric(att, error = [att, :not_numeric])
|
86
|
+
if assert_present(att, error)
|
87
|
+
assert_format(att, /^\d+$/, error)
|
88
|
+
end
|
89
89
|
end
|
90
90
|
|
91
91
|
def assert(value, error)
|
data/test/db/redis.pid
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
65913
|
data/test/errors_test.rb
CHANGED
@@ -31,11 +31,11 @@ class ErrorsTest < Test::Unit::TestCase
|
|
31
31
|
values = []
|
32
32
|
|
33
33
|
@model.errors.present do |e|
|
34
|
-
e.on [:name, :
|
34
|
+
e.on [:name, :not_present] do
|
35
35
|
values << 1
|
36
36
|
end
|
37
37
|
|
38
|
-
e.on [:account, :
|
38
|
+
e.on [:account, :not_present] do
|
39
39
|
values << 2
|
40
40
|
end
|
41
41
|
|
@@ -65,8 +65,8 @@ class ErrorsTest < Test::Unit::TestCase
|
|
65
65
|
|
66
66
|
should "accept multiple matches for an error" do
|
67
67
|
values = @model.errors.present do |e|
|
68
|
-
e.on [:name, :
|
69
|
-
e.on [:account, :
|
68
|
+
e.on [:name, :not_present], "A"
|
69
|
+
e.on [:account, :not_present] do
|
70
70
|
"B"
|
71
71
|
end
|
72
72
|
e.on :terrible_error, "C"
|
@@ -85,8 +85,8 @@ class ErrorsTest < Test::Unit::TestCase
|
|
85
85
|
|
86
86
|
should "take a custom presenter" do
|
87
87
|
values = @model.errors.present(MyPresenter) do |e|
|
88
|
-
e.on([:name, :
|
89
|
-
e.on([:account, :
|
88
|
+
e.on([:name, :not_present]) { "A" }
|
89
|
+
e.on([:account, :not_present]) { "B" }
|
90
90
|
e.on(:terrible_error) { "C" }
|
91
91
|
end
|
92
92
|
|
data/test/indices_test.rb
CHANGED
@@ -9,10 +9,11 @@ class IndicesTest < Test::Unit::TestCase
|
|
9
9
|
|
10
10
|
context "A model with an indexed attribute" do
|
11
11
|
setup do
|
12
|
-
Ohm.
|
12
|
+
Ohm.flush
|
13
13
|
|
14
14
|
@user1 = User.create(:email => "foo")
|
15
15
|
@user2 = User.create(:email => "bar")
|
16
|
+
@user3 = User.create(:email => "baz qux")
|
16
17
|
end
|
17
18
|
|
18
19
|
should "be able to find by the given attribute" do
|
@@ -32,5 +33,9 @@ class IndicesTest < Test::Unit::TestCase
|
|
32
33
|
|
33
34
|
assert_equal [], User.find(:email, "bar")
|
34
35
|
end
|
36
|
+
|
37
|
+
should "work with attributes that contain spaces" do
|
38
|
+
assert_equal [@user3], User.find(:email, "baz qux")
|
39
|
+
end
|
35
40
|
end
|
36
41
|
end
|
data/test/model_test.rb
CHANGED
@@ -2,6 +2,7 @@ require File.join(File.dirname(__FILE__), "test_helper")
|
|
2
2
|
|
3
3
|
class Event < Ohm::Model
|
4
4
|
attribute :name
|
5
|
+
counter :votes
|
5
6
|
set :attendees
|
6
7
|
end
|
7
8
|
|
@@ -14,6 +15,14 @@ class Post < Ohm::Model
|
|
14
15
|
list :comments
|
15
16
|
end
|
16
17
|
|
18
|
+
class Person < Ohm::Model
|
19
|
+
attribute :name
|
20
|
+
|
21
|
+
def validate
|
22
|
+
assert_present :name
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
17
26
|
class TestRedis < Test::Unit::TestCase
|
18
27
|
context "An event initialized with a hash of attributes" do
|
19
28
|
should "assign the passed attributes" do
|
@@ -28,6 +37,10 @@ class TestRedis < Test::Unit::TestCase
|
|
28
37
|
event2 = Event.create(:name => "Ruby Meetup")
|
29
38
|
assert_equal event1.id + 1, event2.id
|
30
39
|
end
|
40
|
+
|
41
|
+
should "return the unsaved object if validation fails" do
|
42
|
+
assert Person.create(:name => nil).kind_of?(Person)
|
43
|
+
end
|
31
44
|
end
|
32
45
|
|
33
46
|
context "Finding an event" do
|
@@ -189,19 +202,14 @@ class TestRedis < Test::Unit::TestCase
|
|
189
202
|
end
|
190
203
|
end
|
191
204
|
|
192
|
-
should "return an array if the model exists" do
|
193
|
-
@event.create
|
194
|
-
assert @event.attendees.kind_of?(Array)
|
195
|
-
end
|
196
|
-
|
197
205
|
should "remove an element if sent :delete" do
|
198
206
|
@event.create
|
199
207
|
@event.attendees << "1"
|
200
208
|
@event.attendees << "2"
|
201
209
|
@event.attendees << "3"
|
202
|
-
assert_equal ["1", "2", "3"], @event.attendees
|
210
|
+
assert_equal ["1", "2", "3"], @event.attendees.all
|
203
211
|
@event.attendees.delete("2")
|
204
|
-
assert_equal ["1", "3"], Event[@event.id].attendees
|
212
|
+
assert_equal ["1", "3"], Event[@event.id].attendees.all
|
205
213
|
end
|
206
214
|
|
207
215
|
should "return true if the set includes some member" do
|
@@ -212,6 +220,22 @@ class TestRedis < Test::Unit::TestCase
|
|
212
220
|
assert @event.attendees.include?("2")
|
213
221
|
assert_equal false, @event.attendees.include?("4")
|
214
222
|
end
|
223
|
+
|
224
|
+
should "return instances of the passed model if the call to all includes a class" do
|
225
|
+
@event.create
|
226
|
+
@person = Person.create :name => "albert"
|
227
|
+
@event.attendees << @person.id
|
228
|
+
|
229
|
+
assert_equal [@person], @event.attendees.all(Person)
|
230
|
+
end
|
231
|
+
|
232
|
+
should "insert the model instance id instead of the object if using add" do
|
233
|
+
@event.create
|
234
|
+
@person = Person.create :name => "albert"
|
235
|
+
@event.attendees.add(@person)
|
236
|
+
|
237
|
+
assert_equal [@person.id.to_s], @event.attendees.all
|
238
|
+
end
|
215
239
|
end
|
216
240
|
|
217
241
|
context "Attributes of type List" do
|
@@ -222,14 +246,14 @@ class TestRedis < Test::Unit::TestCase
|
|
222
246
|
end
|
223
247
|
|
224
248
|
should "return an array" do
|
225
|
-
assert @post.comments.kind_of?(Array)
|
249
|
+
assert @post.comments.all.kind_of?(Array)
|
226
250
|
end
|
227
251
|
|
228
252
|
should "keep the inserting order" do
|
229
253
|
@post.comments << "1"
|
230
254
|
@post.comments << "2"
|
231
255
|
@post.comments << "3"
|
232
|
-
assert_equal ["1", "2", "3"], @post.comments
|
256
|
+
assert_equal ["1", "2", "3"], @post.comments.all
|
233
257
|
end
|
234
258
|
|
235
259
|
should "keep the inserting order after saving" do
|
@@ -237,7 +261,45 @@ class TestRedis < Test::Unit::TestCase
|
|
237
261
|
@post.comments << "2"
|
238
262
|
@post.comments << "3"
|
239
263
|
@post.save
|
240
|
-
assert_equal ["1", "2", "3"], Post[@post.id].comments
|
264
|
+
assert_equal ["1", "2", "3"], Post[@post.id].comments.all
|
265
|
+
end
|
266
|
+
|
267
|
+
should "respond to each" do
|
268
|
+
@post.comments << "1"
|
269
|
+
@post.comments << "2"
|
270
|
+
@post.comments << "3"
|
271
|
+
|
272
|
+
i = 1
|
273
|
+
@post.comments.each do |c|
|
274
|
+
assert_equal i, c.to_i
|
275
|
+
i += 1
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
context "Counters" do
|
281
|
+
setup do
|
282
|
+
@event = Event.create(:name => "Ruby Tuesday")
|
283
|
+
end
|
284
|
+
|
285
|
+
should "raise ArgumentError if the attribute is not a counter" do
|
286
|
+
assert_raise ArgumentError do
|
287
|
+
@event.incr(:name)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
should "be zero if not initialized" do
|
292
|
+
assert_equal 0, @event.votes
|
293
|
+
end
|
294
|
+
|
295
|
+
should "be able to increment a counter" do
|
296
|
+
@event.incr(:votes)
|
297
|
+
assert_equal 1, @event.votes
|
298
|
+
end
|
299
|
+
|
300
|
+
should "be able to decrement a counter" do
|
301
|
+
@event.decr(:votes)
|
302
|
+
assert_equal -1, @event.votes
|
241
303
|
end
|
242
304
|
end
|
243
305
|
|
data/test/validations_test.rb
CHANGED
@@ -4,6 +4,7 @@ class ValidationsTest < Test::Unit::TestCase
|
|
4
4
|
class Event < Ohm::Model
|
5
5
|
attribute :name
|
6
6
|
attribute :place
|
7
|
+
attribute :capacity
|
7
8
|
|
8
9
|
index :name
|
9
10
|
index [:name, :place]
|
@@ -45,6 +46,48 @@ class ValidationsTest < Test::Unit::TestCase
|
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
49
|
+
context "That must have a numeric attribute :capacity" do
|
50
|
+
should "fail when the value is nil" do
|
51
|
+
def @event.validate
|
52
|
+
assert_numeric :capacity
|
53
|
+
end
|
54
|
+
|
55
|
+
@event.name = "foo"
|
56
|
+
@event.place = "bar"
|
57
|
+
@event.create
|
58
|
+
|
59
|
+
assert_nil @event.id
|
60
|
+
assert_equal [[:capacity, :not_numeric]], @event.errors
|
61
|
+
end
|
62
|
+
|
63
|
+
should "fail when the value is not numeric" do
|
64
|
+
def @event.validate
|
65
|
+
assert_numeric :capacity
|
66
|
+
end
|
67
|
+
|
68
|
+
@event.name = "foo"
|
69
|
+
@event.place = "bar"
|
70
|
+
@event.capacity = "baz"
|
71
|
+
@event.create
|
72
|
+
|
73
|
+
assert_nil @event.id
|
74
|
+
assert_equal [[:capacity, :not_numeric]], @event.errors
|
75
|
+
end
|
76
|
+
|
77
|
+
should "succeed when the value is numeric" do
|
78
|
+
def @event.validate
|
79
|
+
assert_numeric :capacity
|
80
|
+
end
|
81
|
+
|
82
|
+
@event.name = "foo"
|
83
|
+
@event.place = "bar"
|
84
|
+
@event.capacity = 42
|
85
|
+
@event.create
|
86
|
+
|
87
|
+
assert_not_nil @event.id
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
48
91
|
context "That must have a unique name" do
|
49
92
|
should "fail when the value already exists" do
|
50
93
|
def @event.validate
|
@@ -160,32 +203,14 @@ class ValidationsTest < Test::Unit::TestCase
|
|
160
203
|
should "fail when the attribute is nil" do
|
161
204
|
@target.validate
|
162
205
|
|
163
|
-
assert_equal [[:name, :
|
206
|
+
assert_equal [[:name, :not_present]], @target.errors
|
164
207
|
end
|
165
208
|
|
166
209
|
should "fail when the attribute is empty" do
|
167
210
|
@target.name = ""
|
168
211
|
@target.validate
|
169
212
|
|
170
|
-
assert_equal [[:name, :
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
context "assert_not_nil" do
|
175
|
-
should "fail when the attribute is nil" do
|
176
|
-
def @target.validate
|
177
|
-
assert_not_nil(:name)
|
178
|
-
end
|
179
|
-
|
180
|
-
@target.validate
|
181
|
-
|
182
|
-
assert_equal [[:name, :nil]], @target.errors
|
183
|
-
|
184
|
-
@target.errors.clear
|
185
|
-
@target.name = ""
|
186
|
-
@target.validate
|
187
|
-
|
188
|
-
assert_equal [], @target.errors
|
213
|
+
assert_equal [[:name, :not_present]], @target.errors
|
189
214
|
end
|
190
215
|
end
|
191
216
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ohm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michel Martens
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-
|
13
|
+
date: 2009-07-22 00:00:00 -03:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|