ohm 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,19 @@
1
+ Copyright (c) 2009 Michel Martens and Damian Janowski
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,74 @@
1
+ Ohm
2
+ ============
3
+
4
+ Object-hash mapping library for Redis.
5
+
6
+ Description
7
+ -----------
8
+
9
+ Ohm is a library that allows to store an object in
10
+ [Redis](http://code.google.com/p/redis/), a persistent key-value
11
+ database. It includes an extensible list of validations and has very
12
+ good performance.
13
+
14
+ Usage
15
+ -----
16
+
17
+ require 'ohm'
18
+
19
+ $redis = Redis.new
20
+
21
+ class Event < Ohm::Model
22
+ attribute :name
23
+ set :participants
24
+
25
+ def validate
26
+ assert_present :name
27
+ end
28
+ end
29
+
30
+ event = Event.create(:name => "Ruby Tuesday")
31
+ event.participants << "Michel Martens"
32
+ event.participants << "Damian Janowski"
33
+
34
+ another_event = Event.new
35
+ another_event.valid? #=> false
36
+ another_event.errors #=> [[:name, :nil]]
37
+
38
+ another_event.name = ""
39
+ another_event.valid? #=> false
40
+ another_event.errors #=> [[:name, :empty]]
41
+
42
+ another_event.name = "Ruby Lunch"
43
+ another_event.save #=> true
44
+
45
+ Installation
46
+ ------------
47
+
48
+ $ sudo gem install ohm
49
+
50
+ License
51
+ -------
52
+
53
+ Copyright (c) 2009 Michel Martens and Damian Janowski
54
+
55
+ Permission is hereby granted, free of charge, to any person
56
+ obtaining a copy of this software and associated documentation
57
+ files (the "Software"), to deal in the Software without
58
+ restriction, including without limitation the rights to use,
59
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
60
+ copies of the Software, and to permit persons to whom the
61
+ Software is furnished to do so, subject to the following
62
+ conditions:
63
+
64
+ The above copyright notice and this permission notice shall be
65
+ included in all copies or substantial portions of the Software.
66
+
67
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
68
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
69
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
70
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
71
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
72
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
73
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
74
+ OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,78 @@
1
+ require 'rake/clean'
2
+ require "rake/testtask"
3
+ require 'rake/gempackagetask'
4
+
5
+ task :default => :test
6
+
7
+ def gem_spec_file
8
+ 'ohm.gemspec'
9
+ end
10
+
11
+ def gem_spec
12
+ $gem_spec ||= eval(File.read(gem_spec_file)) rescue nil
13
+ end
14
+
15
+ desc 'Run all tests'
16
+ Rake::TestTask.new(:test) do |t|
17
+ t.pattern = 'test/**/*_test.rb'
18
+ t.verbose = false
19
+ end
20
+
21
+ Rake::GemPackageTask.new(gem_spec) do |pkg|
22
+ pkg.need_zip = false
23
+ pkg.need_tar = false
24
+ rm_f FileList['pkg/**/*.*']
25
+ end if gem_spec
26
+
27
+ desc "Generate the gemspec file."
28
+ task :gemspec do
29
+ require 'erb'
30
+
31
+ File.open(gem_spec_file, 'w') do |f|
32
+ f.write ERB.new(File.read("#{gem_spec_file}.erb")).result(binding)
33
+ end
34
+ end
35
+
36
+ desc "Builds and installs the gem."
37
+ task :install => :repackage do
38
+ `sudo gem install pkg/#{gem_spec.name}-#{gem_spec.version}.gem`
39
+ end
40
+
41
+ def package(ext='')
42
+ "pkg/ohm-#{gem_spec.version}" + ext
43
+ end
44
+
45
+ desc 'Build packages'
46
+ task :package => %w[.gem .tar.gz].map {|e| package(e)}
47
+
48
+ desc 'Build and install as local gem'
49
+ task :install => package('.gem') do
50
+ sh "gem install #{package('.gem')}"
51
+ end
52
+
53
+ directory 'pkg/'
54
+ CLOBBER.include('pkg')
55
+
56
+ file package('.gem') => %w[pkg/ ohm.gemspec] + gem_spec.files do |f|
57
+ sh "gem build ohm.gemspec"
58
+ mv File.basename(f.name), f.name
59
+ end
60
+
61
+ file package('.tar.gz') => %w[pkg/] + gem_spec.files do |f|
62
+ sh <<-SH
63
+ git archive \
64
+ --prefix=ohm-#{gem_spec.version}/ \
65
+ --format=tar \
66
+ HEAD | gzip > #{f.name}
67
+ SH
68
+ end
69
+
70
+ # Rubyforge Release / Publish Tasks ==================================
71
+
72
+ desc 'Publish gem and tarball to rubyforge'
73
+ task 'release' => [package('.gem'), package('.tar.gz')] do |t|
74
+ sh <<-end
75
+ rubyforge add_release ohm ohm #{gem_spec.version} #{package('.gem')} &&
76
+ rubyforge add_file ohm ohm #{gem_spec.version} #{package('.tar.gz')}
77
+ end
78
+ end
@@ -0,0 +1,242 @@
1
+ require "rubygems"
2
+ require "redis"
3
+
4
+ module Ohm
5
+ module Validations
6
+ def valid?
7
+ errors.clear
8
+ validate
9
+ errors.empty?
10
+ end
11
+
12
+ def validate
13
+ end
14
+
15
+ def errors
16
+ @errors ||= []
17
+ end
18
+
19
+ private
20
+
21
+ def assert_format(att, format)
22
+ if assert_present(att)
23
+ assert attribute(att).match(format), [att, :format]
24
+ end
25
+ end
26
+
27
+ def assert_present(att)
28
+ if assert_not_nil(att)
29
+ assert attribute(att).any?, [att, :empty]
30
+ end
31
+ end
32
+
33
+ def assert_not_nil(att)
34
+ assert attribute(att), [att, :nil]
35
+ end
36
+
37
+ def assert(value, error)
38
+ value or errors.push(error) && false
39
+ end
40
+
41
+ def attribute(att)
42
+ instance_variable_get("@#{att}")
43
+ end
44
+ end
45
+
46
+ module Attributes
47
+ class Collection < Array
48
+ attr_accessor :key, :db
49
+
50
+ def initialize(db, key)
51
+ self.db = db
52
+ self.key = key
53
+ super(retrieve)
54
+ end
55
+ end
56
+
57
+ class List < Collection
58
+ def retrieve
59
+ db.list_range(key, 0, -1)
60
+ end
61
+
62
+ def << value
63
+ super(value) if db.push_tail(key, value)
64
+ end
65
+ end
66
+
67
+ class Set < Collection
68
+ def retrieve
69
+ db.set_members(key).sort
70
+ end
71
+
72
+ def << value
73
+ super(value) if db.set_add(key, value)
74
+ end
75
+
76
+ def delete(value)
77
+ super(value) if db.set_delete(key, value)
78
+ end
79
+
80
+ def include?(value)
81
+ db.set_member?(key, value)
82
+ end
83
+ end
84
+ end
85
+
86
+ class Model
87
+ include Validations
88
+
89
+ ModelIsNew = Class.new(StandardError)
90
+
91
+ @@attributes = Hash.new { |hash, key| hash[key] = [] }
92
+ @@collections = Hash.new { |hash, key| hash[key] = [] }
93
+
94
+ attr_accessor :id
95
+
96
+ def self.attribute(name)
97
+ attr_writer(name)
98
+ attr_value_reader(name)
99
+ attributes << name
100
+ end
101
+
102
+ def self.list(name)
103
+ attr_list_reader(name)
104
+ collections << name
105
+ end
106
+
107
+ def self.set(name)
108
+ attr_set_reader(name)
109
+ collections << name
110
+ end
111
+
112
+ # TODO Encapsulate access to db?
113
+ def self.attr_value_reader(name)
114
+ class_eval <<-EOS
115
+ def #{name}
116
+ @#{name} ||= db[key("#{name}")]
117
+ end
118
+ EOS
119
+ end
120
+
121
+ def self.attr_list_reader(name)
122
+ class_eval <<-EOS
123
+ def #{name}
124
+ @#{name} ||= Attributes::List.new(db, key("#{name}"))
125
+ end
126
+ EOS
127
+ end
128
+
129
+ def self.attr_set_reader(name)
130
+ class_eval <<-EOS
131
+ def #{name}
132
+ @#{name} ||= Attributes::Set.new(db, key("#{name}"))
133
+ end
134
+ EOS
135
+ end
136
+
137
+ def self.[](id)
138
+ new(:id => id) if exists?(id)
139
+ end
140
+
141
+ def self.all
142
+ filter(:all).map do |id|
143
+ new(:id => id)
144
+ end
145
+ end
146
+
147
+ def self.attributes
148
+ @@attributes[self]
149
+ end
150
+
151
+ def self.collections
152
+ @@collections[self]
153
+ end
154
+
155
+ def self.create(*args)
156
+ new(*args).create
157
+ end
158
+
159
+ def initialize(attrs = {})
160
+ attrs.each do |key, value|
161
+ send(:"#{key}=", value)
162
+ end
163
+ end
164
+
165
+ def create
166
+ return unless valid?
167
+ initialize_id
168
+ create_model_membership
169
+ save!
170
+ end
171
+
172
+ def save
173
+ return unless valid?
174
+ save!
175
+ end
176
+
177
+ def delete
178
+ delete_attributes(collections)
179
+ delete_attributes(attributes)
180
+ delete_model_membership
181
+ self
182
+ end
183
+
184
+ def attributes
185
+ self.class.attributes
186
+ end
187
+
188
+ def collections
189
+ self.class.collections
190
+ end
191
+
192
+ private
193
+
194
+ def self.db
195
+ $redis
196
+ end
197
+
198
+ def self.key(*args)
199
+ args.unshift(self).join(":")
200
+ end
201
+
202
+ def self.filter(name)
203
+ db.set_members(key(name))
204
+ end
205
+
206
+ def self.exists?(id)
207
+ db.set_member?(key(:all), id)
208
+ end
209
+
210
+ def initialize_id
211
+ self.id = db.incr(self.class.key("id"))
212
+ end
213
+
214
+ def db
215
+ self.class.db
216
+ end
217
+
218
+ def key(*args)
219
+ raise ModelIsNew unless id
220
+ self.class.key(id, *args)
221
+ end
222
+
223
+ def delete_attributes(atts)
224
+ atts.each do |att|
225
+ db.delete(key(att))
226
+ end
227
+ end
228
+
229
+ def create_model_membership
230
+ db.set_add(self.class.key(:all), id)
231
+ end
232
+
233
+ def delete_model_membership
234
+ db.set_delete(self.class.key(:all), id)
235
+ end
236
+
237
+ def save!
238
+ attributes.each { |att| db[key(att)] = send(att) }
239
+ self
240
+ end
241
+ end
242
+ end
@@ -0,0 +1,2 @@
1
+ require File.dirname(__FILE__) + '/model_test.rb'
2
+ require File.dirname(__FILE__) + '/validations_test.rb'
@@ -0,0 +1,32 @@
1
+ require "rubygems"
2
+ require "bench"
3
+ require File.dirname(__FILE__) + "/../lib/ohm"
4
+
5
+ $redis = Redis.new(:port => 6381)
6
+ $redis.flush_db
7
+
8
+ class Event < Ohm::Model
9
+ attribute :name
10
+ set :attendees
11
+
12
+ def validate
13
+ assert_present :name
14
+ end
15
+ end
16
+
17
+ event = Event.create(:name => "Ruby Tuesday")
18
+ array = []
19
+
20
+ benchmark "redis add to set" do
21
+ $redis.set_add("foo", 1)
22
+ end
23
+
24
+ benchmark "ohm add to set" do
25
+ event.attendees << 1
26
+ end
27
+
28
+ benchmark "ruby array push" do
29
+ array.push(1)
30
+ end
31
+
32
+ run 10000
Binary file
@@ -0,0 +1 @@
1
+ 6416
@@ -0,0 +1,244 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class Event < Ohm::Model
4
+ attribute :name
5
+ set :attendees
6
+ end
7
+
8
+ class User < Ohm::Model
9
+ attribute :email
10
+ end
11
+
12
+ class Post < Ohm::Model
13
+ attribute :body
14
+ list :comments
15
+ end
16
+
17
+ class TestRedis < Test::Unit::TestCase
18
+ context "An event initialized with a hash of attributes" do
19
+ should "assign the passed attributes" do
20
+ event = Event.new(:name => "Ruby Tuesday")
21
+ assert_equal event.name, "Ruby Tuesday"
22
+ end
23
+ end
24
+
25
+ context "An event created from a hash of attributes" do
26
+ should "assign an id and save the object" do
27
+ event1 = Event.create(:name => "Ruby Tuesday")
28
+ event2 = Event.create(:name => "Ruby Meetup")
29
+ assert_equal event1.id + 1, event2.id
30
+ end
31
+ end
32
+
33
+ context "Finding an event" do
34
+ setup do
35
+ $redis.set_add("Event", 1)
36
+ $redis["Event:1:name"] = "Concert"
37
+ end
38
+
39
+ should "return an instance of Event" do
40
+ assert Event[1].kind_of?(Event)
41
+ assert_equal 1, Event[1].id
42
+ assert_equal "Concert", Event[1].name
43
+ end
44
+ end
45
+
46
+ context "Finding a user" do
47
+ setup do
48
+ $redis.set_add("User:all", 1)
49
+ $redis["User:1:email"] = "albert@example.com"
50
+ end
51
+
52
+ should "return an instance of User" do
53
+ assert User[1].kind_of?(User)
54
+ assert_equal 1, User[1].id
55
+ assert_equal "albert@example.com", User[1].email
56
+ end
57
+ end
58
+
59
+ context "Updating a user" do
60
+ setup do
61
+ $redis.set_add("User:all", 1)
62
+ $redis["User:1:email"] = "albert@example.com"
63
+
64
+ @user = User[1]
65
+ end
66
+
67
+ should "change its attributes" do
68
+ @user.email = "maria@example.com"
69
+ assert_equal "maria@example.com", @user.email
70
+ end
71
+
72
+ should "save the new values" do
73
+ @user.email = "maria@example.com"
74
+ @user.save
75
+
76
+ @user.email = "maria@example.com"
77
+ @user.save
78
+
79
+ assert_equal "maria@example.com", User[1].email
80
+ end
81
+ end
82
+
83
+ context "Creating a new model" do
84
+ should "assign a new id to the event" do
85
+ event1 = Event.new
86
+ event1.create
87
+
88
+ event2 = Event.new
89
+ event2.create
90
+
91
+ assert event1.id
92
+ assert_equal event1.id + 1, event2.id
93
+ end
94
+ end
95
+
96
+ context "Saving a model" do
97
+ should "not save a new model" do
98
+ assert_raise Ohm::Model::ModelIsNew do
99
+ Event.new.save
100
+ end
101
+ end
102
+
103
+ should "save it only if it was previously created" do
104
+ event = Event.new
105
+ event.name = "Lorem ipsum"
106
+ event.create
107
+
108
+ event.name = "Lorem"
109
+ event.save
110
+
111
+ assert_equal "Lorem", Event[event.id].name
112
+ end
113
+ end
114
+
115
+ context "Delete" do
116
+ class ModelToBeDeleted < Ohm::Model
117
+ attribute :name
118
+ set :foos
119
+ list :bars
120
+ end
121
+
122
+ setup do
123
+ @model = ModelToBeDeleted.create(:name => "Lorem")
124
+
125
+ @model.foos << "foo"
126
+ @model.bars << "bar"
127
+ end
128
+
129
+ should "delete an existing model" do
130
+ id = @model.id
131
+
132
+ @model.delete
133
+
134
+ assert_nil $redis[ModelToBeDeleted.key(id)]
135
+ assert_nil $redis[ModelToBeDeleted.key(id, :name)]
136
+ assert_equal Set.new, $redis.set_members(ModelToBeDeleted.key(id, :foos))
137
+ assert_equal Array.new, $redis.list_range(ModelToBeDeleted.key(id, :bars), 0, -1)
138
+
139
+ assert ModelToBeDeleted.all.empty?
140
+ end
141
+ end
142
+
143
+ context "Listing" do
144
+ should "find all" do
145
+ event1 = Event.new
146
+ event1.name = "Ruby Meetup"
147
+ event1.create
148
+
149
+ event2 = Event.new
150
+ event2.name = "Ruby Tuesday"
151
+ event2.create
152
+
153
+ all = Event.all
154
+
155
+ assert all.detect {|e| e.name == "Ruby Meetup" }
156
+ assert all.detect {|e| e.name == "Ruby Tuesday" }
157
+ end
158
+ end
159
+
160
+ context "Loading attributes" do
161
+ setup do
162
+ event = Event.new
163
+ event.name = "Ruby Tuesday"
164
+ @id = event.create.id
165
+ end
166
+
167
+ should "load attributes lazily" do
168
+ event = Event[@id]
169
+
170
+ assert_nil event.send(:instance_variable_get, "@name")
171
+ assert_equal "Ruby Tuesday", event.name
172
+ end
173
+
174
+ should "load attributes as a strings" do
175
+ event = Event.create(:name => 1)
176
+
177
+ assert_equal "1", Event[event.id].name
178
+ end
179
+ end
180
+
181
+ context "Attributes of type Set" do
182
+ setup do
183
+ @event = Event.new
184
+ @event.name = "Ruby Tuesday"
185
+ end
186
+
187
+ should "not be available if the model is new" do
188
+ assert_raise Ohm::Model::ModelIsNew do
189
+ @event.attendees << 1
190
+ end
191
+ end
192
+
193
+ should "return an array if the model exists" do
194
+ @event.create
195
+ assert @event.attendees.kind_of?(Array)
196
+ end
197
+
198
+ should "remove an element if sent :delete" do
199
+ @event.create
200
+ @event.attendees << "1"
201
+ @event.attendees << "2"
202
+ @event.attendees << "3"
203
+ assert_equal ["1", "2", "3"], @event.attendees
204
+ @event.attendees.delete("2")
205
+ assert_equal ["1", "3"], Event[@event.id].attendees
206
+ end
207
+
208
+ should "return true if the set includes some member" do
209
+ @event.create
210
+ @event.attendees << "1"
211
+ @event.attendees << "2"
212
+ @event.attendees << "3"
213
+ assert @event.attendees.include?("2")
214
+ assert_equal false, @event.attendees.include?("4")
215
+ end
216
+ end
217
+
218
+ context "Attributes of type List" do
219
+ setup do
220
+ @post = Post.new
221
+ @post.body = "Hello world!"
222
+ @post.create
223
+ end
224
+
225
+ should "return an array" do
226
+ assert @post.comments.kind_of?(Array)
227
+ end
228
+
229
+ should "keep the inserting order" do
230
+ @post.comments << "1"
231
+ @post.comments << "2"
232
+ @post.comments << "3"
233
+ assert_equal ["1", "2", "3"], @post.comments
234
+ end
235
+
236
+ should "keep the inserting order after saving" do
237
+ @post.comments << "1"
238
+ @post.comments << "2"
239
+ @post.comments << "3"
240
+ @post.save
241
+ assert_equal ["1", "2", "3"], Post[@post.id].comments
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,15 @@
1
+ daemonize yes
2
+ dir ./test/db
3
+ pidfile ./redis.pid
4
+ port 6381
5
+ timeout 300
6
+
7
+ save 900 1
8
+ save 300 10
9
+ save 60 10000
10
+
11
+ loglevel debug
12
+
13
+ logfile stdout
14
+
15
+ databases 16
@@ -0,0 +1,7 @@
1
+ require "rubygems"
2
+ require "ruby-debug"
3
+ require "contest"
4
+ require File.dirname(__FILE__) + "/../lib/ohm"
5
+
6
+ $redis = Redis.new(:port => 6381)
7
+ $redis.flush_db
@@ -0,0 +1,152 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ValidationsTest < Test::Unit::TestCase
4
+ class Event < Ohm::Model
5
+ attribute :name
6
+
7
+ def validate
8
+ assert_format(:name, /^\w+$/)
9
+ end
10
+ end
11
+
12
+ context "A new model with validations" do
13
+ setup do
14
+ @event = Event.new
15
+ end
16
+
17
+ context "That must have a present name" do
18
+ should "not be created if the name is never assigned" do
19
+ @event.create
20
+ assert_nil @event.id
21
+ end
22
+
23
+ should "not be created if the name assigned is empty" do
24
+ @event.name = ""
25
+ @event.create
26
+ assert_nil @event.id
27
+ end
28
+
29
+ should "be created if the name assigned is not empty" do
30
+ @event.name = "hello"
31
+ @event.create
32
+ assert_not_nil @event.id
33
+ end
34
+
35
+ context "And must have a name with only \w+" do
36
+ should "not be created if the name doesn't match /^\w+$/" do
37
+ @event.name = "hello-world"
38
+ @event.create
39
+ assert_nil @event.id
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ context "An existing model with a valid name" do
46
+ setup do
47
+ @event = Event.create(:name => "original")
48
+ end
49
+
50
+ context "That has the name changed" do
51
+ should "not be saved if the new name is nil" do
52
+ @event.name = nil
53
+ @event.save
54
+ assert_equal false, @event.valid?
55
+ assert_equal "original", Event[@event.id].name
56
+ end
57
+
58
+ should "not be saved if the name assigned is empty" do
59
+ @event.name = ""
60
+ @event.save
61
+ assert_equal false, @event.valid?
62
+ assert_equal "original", Event[@event.id].name
63
+ end
64
+
65
+ should "be saved if the name assigned is not empty" do
66
+ @event.name = "hello"
67
+ @event.save
68
+ assert @event.valid?
69
+ assert_equal "hello", Event[@event.id].name
70
+ end
71
+ end
72
+ end
73
+
74
+ context "Validations module" do
75
+ class Validatable
76
+ attr_accessor :name
77
+
78
+ include Ohm::Validations
79
+ end
80
+
81
+ setup do
82
+ @target = Validatable.new
83
+ end
84
+
85
+ context "assert" do
86
+ should "add errors to a collection" do
87
+ def @target.validate
88
+ assert(false, "Something bad")
89
+ end
90
+
91
+ @target.validate
92
+
93
+ assert_equal ["Something bad"], @target.errors
94
+ end
95
+
96
+ should "allow for nested validations" do
97
+ def @target.validate
98
+ if assert(true, "No error")
99
+ assert(false, "Chained error")
100
+ end
101
+
102
+ if assert(false, "Parent error")
103
+ assert(false, "No chained error")
104
+ end
105
+ end
106
+
107
+ @target.validate
108
+
109
+ assert_equal ["Chained error", "Parent error"], @target.errors
110
+ end
111
+ end
112
+
113
+ context "assert_present" do
114
+ setup do
115
+ def @target.validate
116
+ assert_present(:name)
117
+ end
118
+ end
119
+
120
+ should "fail when the attribute is nil" do
121
+ @target.validate
122
+
123
+ assert_equal [[:name, :nil]], @target.errors
124
+ end
125
+
126
+ should "fail when the attribute is empty" do
127
+ @target.name = ""
128
+ @target.validate
129
+
130
+ assert_equal [[:name, :empty]], @target.errors
131
+ end
132
+ end
133
+
134
+ context "assert_not_nil" do
135
+ should "fail when the attribute is nil" do
136
+ def @target.validate
137
+ assert_not_nil(:name)
138
+ end
139
+
140
+ @target.validate
141
+
142
+ assert_equal [[:name, :nil]], @target.errors
143
+
144
+ @target.errors.clear
145
+ @target.name = ""
146
+ @target.validate
147
+
148
+ assert_equal [], @target.errors
149
+ end
150
+ end
151
+ end
152
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ohm
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Michel Martens, Damian Janowski
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-13 00:00:00 -02:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: redis
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "1.0"
24
+ version:
25
+ description:
26
+ email: michel@soveran.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - lib/ohm.rb
35
+ - README.markdown
36
+ - LICENSE
37
+ - Rakefile
38
+ - test/all_tests.rb
39
+ - test/benchmarks.rb
40
+ - test/db/dump.rdb
41
+ - test/db/redis.pid
42
+ - test/model_test.rb
43
+ - test/test.conf
44
+ - test/test_helper.rb
45
+ - test/validations_test.rb
46
+ has_rdoc: false
47
+ homepage: http://github.com/soveran/ohm
48
+ licenses: []
49
+
50
+ post_install_message:
51
+ rdoc_options: []
52
+
53
+ require_paths:
54
+ - lib
55
+ required_ruby_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ requirements: []
68
+
69
+ rubyforge_project:
70
+ rubygems_version: 1.3.2
71
+ signing_key:
72
+ specification_version: 2
73
+ summary: Object-hash mapping library for Redis.
74
+ test_files: []
75
+