ohm 0.1.5 → 1.0.0.alpha1

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/lib/ohm/version.rb DELETED
@@ -1,5 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- module Ohm
4
- VERSION = "0.1.5"
5
- end
@@ -1,101 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
4
-
5
- prepare.clear
6
-
7
- test "connects lazily" do
8
- Ohm.connect(:port => 9876)
9
-
10
- begin
11
- Ohm.redis.get "foo"
12
- rescue => e
13
- assert Errno::ECONNREFUSED == e.class
14
- end
15
- end
16
-
17
- test "provides a separate connection for each thread" do
18
- assert Ohm.redis == Ohm.redis
19
-
20
- conn1, conn2 = nil
21
-
22
- threads = []
23
-
24
- threads << Thread.new do
25
- conn1 = Ohm.redis
26
- end
27
-
28
- threads << Thread.new do
29
- conn2 = Ohm.redis
30
- end
31
-
32
- threads.each { |t| t.join }
33
-
34
- assert conn1 != conn2
35
- end
36
-
37
- test "supports connecting by URL" do
38
- Ohm.connect(:url => "redis://localhost:9876")
39
-
40
- begin
41
- Ohm.redis.get "foo"
42
- rescue => e
43
- assert Errno::ECONNREFUSED == e.class
44
- end
45
- end
46
-
47
- test "Model.db is the same as Ohm.redis by default" do
48
- class U < Ohm::Model
49
- end
50
-
51
- assert_equal U.db.object_id, Ohm.redis.object_id
52
- end
53
-
54
- test "provides a unique Model.db connection in one thread" do
55
- class U < Ohm::Model
56
- end
57
-
58
- U.connect(db: 9876)
59
-
60
- r1 = U.db
61
- r2 = U.db
62
-
63
- assert_equal r1.object_id, r2.object_id
64
- end
65
-
66
- test "provides distinct Model.db connections per thread" do
67
- class U < Ohm::Model
68
- end
69
-
70
- U.connect(db: 9876)
71
-
72
- r1 = nil
73
- r2 = nil
74
-
75
- Thread.new { r1 = U.db }.join
76
- Thread.new { r2 = U.db }.join
77
-
78
- assert r1.object_id != r2.object_id
79
- end
80
-
81
- test "busts threaded cache when doing Model.connect" do
82
- class U < Ohm::Model
83
- end
84
-
85
- U.connect(db: 9876)
86
- r1 = U.db
87
-
88
- U.connect(db: 9876)
89
- r2 = U.db
90
-
91
- assert r1.object_id != r2.object_id
92
- end
93
-
94
- test "disallows the non-thread safe writing of Model.db" do
95
- class U < Ohm::Model
96
- end
97
-
98
- assert_raise NoMethodError do
99
- U.db = Redis.connect
100
- end
101
- end
data/test/errors_test.rb DELETED
@@ -1,120 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
4
-
5
- class User < Ohm::Model
6
- attribute :name
7
- attribute :account
8
-
9
- def validate
10
- assert_present :name
11
- assert_present :account
12
- assert false, :terrible_error
13
- end
14
- end
15
-
16
- setup do
17
- @model = User.new(:account => "")
18
- @model.valid?
19
- end
20
-
21
- test "raise an error if the errors are not handled" do
22
- begin
23
- @model.errors.present do |e|
24
- e.on :terrible_error do
25
- end
26
- end
27
- rescue => e
28
- assert e.class == Ohm::Validations::Presenter::UnhandledErrors
29
- end
30
- end
31
-
32
- test "evaluate blocks when errors match" do
33
- values = []
34
-
35
- @model.errors.present do |e|
36
- e.on [:name, :not_present] do
37
- values << 1
38
- end
39
-
40
- e.on [:account, :not_present] do
41
- values << 2
42
- end
43
-
44
- e.on :terrible_error do
45
- values << 3
46
- end
47
- end
48
-
49
- assert [1, 2, 3] == values
50
- end
51
-
52
- test "accept case-like matches for an error" do
53
- values = []
54
-
55
- @model.errors.present do |e|
56
- e.on Array do
57
- values << 1
58
- end
59
-
60
- e.on :terrible_error do
61
- values << 3
62
- end
63
- end
64
-
65
- assert [1, 3] == values
66
- end
67
-
68
- test "accept multiple matches for an error" do
69
- values = @model.errors.present do |e|
70
- e.on [:name, :not_present], "A"
71
- e.on [:account, :not_present] do
72
- "B"
73
- end
74
- e.on :terrible_error, "C"
75
- end
76
-
77
- assert %w{A B C} == values
78
- end
79
-
80
- class MyPresenter < Ohm::Validations::Presenter
81
- def on(*args)
82
- super(*args) do
83
- yield.downcase
84
- end
85
- end
86
- end
87
-
88
- test "take a custom presenter" do
89
- values = @model.errors.present(MyPresenter) do |e|
90
- e.on([:name, :not_present]) { "A" }
91
- e.on([:account, :not_present]) { "B" }
92
- e.on(:terrible_error) { "C" }
93
- end
94
-
95
- assert %w{a b c} == values
96
- end
97
-
98
- test "raise an error if neither a message nor a block are supplied" do
99
- begin
100
- Ohm::Validations::Presenter.new([:custom]).present do |e|
101
- e.on(:custom)
102
- end
103
- rescue => e
104
- assert e.class == ArgumentError
105
- end
106
- end
107
-
108
- test "not raise an error if the message passed is nil" do
109
- values = Ohm::Validations::Presenter.new([:custom]).present do |e|
110
- e.on(:custom, nil)
111
- end
112
-
113
- assert [nil] == values
114
-
115
- Ohm::Validations::Presenter.new([:custom]).present do |e|
116
- e.on(:custom, nil) do
117
- raise "Should not call block"
118
- end
119
- end
120
- end
data/test/indices_test.rb DELETED
@@ -1,213 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
4
-
5
- class User < Ohm::Model
6
- attribute :email
7
- attribute :update
8
- attribute :activation_code
9
- attribute :sandunga
10
-
11
- index :email
12
- index :email_provider
13
- index :working_days
14
- index :update
15
- index :activation_code
16
-
17
- def email_provider
18
- email.split("@").last
19
- end
20
-
21
- def working_days
22
- @working_days ||= []
23
- end
24
-
25
- def write
26
- self.activation_code ||= "user:#{id}"
27
- super
28
- end
29
- end
30
-
31
- setup do
32
- @user1 = User.create(:email => "foo", :activation_code => "bar", :update => "baz")
33
- @user2 = User.create(:email => "bar")
34
- @user3 = User.create(:email => "baz qux")
35
- end
36
-
37
- test "be able to find by the given attribute" do
38
- assert @user1 == User.find(:email => "foo").first
39
- end
40
-
41
- test "raise an error if the parameter supplied is not a hash" do
42
- begin
43
- User.find(1)
44
- rescue => ex
45
- ensure
46
- assert ex.kind_of?(ArgumentError)
47
- assert ex.message == "You need to supply a hash with filters. If you want to find by ID, use User[id] instead."
48
- end
49
- end
50
-
51
- test "avoid intersections with the all collection" do
52
- assert "User:email:#{Ohm::Model.encode "foo"}" == User.find(:email => "foo").key.to_s
53
-
54
- assert "~:User:email:Zm9v+User:activation_code:" ==
55
- User.find(:email => "foo").find(:activation_code => "").key.to_s
56
-
57
- assert "~:User:email:Zm9v+User:activation_code:YmFy+User:update:YmF6" ==
58
- result = User.find(:email => "foo").find(:activation_code => "bar").find(:update => "baz").key.to_s
59
- end
60
-
61
- test "use a special namespace for set operations" do
62
- assert User.find(:email => "foo", :activation_code => "bar").key.to_s.match(/^~:/)
63
-
64
- assert Ohm.redis.keys("~:*").size > 0
65
- end
66
-
67
- test "allow multiple chained finds" do
68
- assert 1 == User.find(:email => "foo").find(:activation_code => "bar").find(:update => "baz").size
69
- end
70
-
71
- test "raise if the field is not indexed" do
72
- assert_raise(Ohm::Model::IndexNotFound) do
73
- User.find(:sandunga => "foo")
74
- end
75
- end
76
-
77
- test "return nil if no results are found" do
78
- assert User.find(:email => "foobar").empty?
79
- assert nil == User.find(:email => "foobar").first
80
- end
81
-
82
- test "update indices when changing attribute values" do
83
- @user1.email = "baz"
84
- @user1.save
85
-
86
- assert [] == User.find(:email => "foo").all
87
- assert [@user1] == User.find(:email => "baz").all
88
- end
89
-
90
- test "remove from the index after deleting" do
91
- @user2.delete
92
-
93
- assert [] == User.find(:email => "bar").all
94
- end
95
-
96
- test "work with attributes that contain spaces" do
97
- assert [@user3] == User.find(:email => "baz qux").all
98
- end
99
-
100
- # Indexing arbitrary attributes
101
- setup do
102
- @user1 = User.create(:email => "foo@gmail.com")
103
- @user2 = User.create(:email => "bar@gmail.com")
104
- @user3 = User.create(:email => "bazqux@yahoo.com")
105
- end
106
-
107
- test "allow indexing by an arbitrary attribute" do
108
- assert [@user1, @user2] == User.find(:email_provider => "gmail.com").to_a.sort_by { |u| u.id }
109
- assert [@user3] == User.find(:email_provider => "yahoo.com").all
110
- end
111
-
112
- test "allow indexing by an attribute that is lazily set" do
113
- assert [@user1] == User.find(:activation_code => "user:1").to_a
114
- end
115
-
116
- # Indexing enumerables
117
- setup do
118
- @user1 = User.create(:email => "foo@gmail.com")
119
- @user2 = User.create(:email => "bar@gmail.com")
120
-
121
- @user1.working_days << "Mon"
122
- @user1.working_days << "Tue"
123
- @user2.working_days << "Mon"
124
- @user2.working_days << "Wed"
125
-
126
- @user1.save
127
- @user2.save
128
- end
129
-
130
- test "index each item" do
131
- assert [@user1, @user2] == User.find(:working_days => "Mon").to_a.sort_by { |u| u.id }
132
- end
133
-
134
- # TODO If we deal with Ohm collections, the updates are atomic but the reindexing never happens.
135
- # One solution may be to reindex after inserts or deletes in collection.
136
- test "remove the indices when the object changes" do
137
- @user2.working_days.delete "Mon"
138
- @user2.save
139
- assert [@user1] == User.find(:working_days => "Mon").all
140
- end
141
-
142
- # Intersection and difference
143
- class Event < Ohm::Model
144
- attr_writer :days
145
-
146
- attribute :timeline
147
- index :timeline
148
- index :days
149
-
150
- def days
151
- @days ||= []
152
- end
153
- end
154
-
155
- setup do
156
- @event1 = Event.create(:timeline => 1).update(:days => [1, 2])
157
- @event2 = Event.create(:timeline => 1).update(:days => [2, 3])
158
- @event3 = Event.create(:timeline => 2).update(:days => [3, 4])
159
- @event4 = Event.create(:timeline => 2).update(:days => [1, 3])
160
- end
161
-
162
- test "intersect multiple sets of results" do
163
- assert [@event1] == Event.find(:days => [1, 2]).all
164
- assert [@event1] == Event.find(:timeline => 1, :days => [1, 2]).all
165
- assert [@event1] == Event.find(:timeline => 1).find(:days => [1, 2]).all
166
- end
167
-
168
- test "compute the difference between sets" do
169
- assert [@event2] == Event.find(:timeline => 1).except(:days => 1).all
170
- end
171
-
172
- test "raise if the argument is not an index" do
173
- assert_raise(Ohm::Model::IndexNotFound) do
174
- Event.find(:timeline => 1).except(:not_an_index => 1)
175
- end
176
- end
177
-
178
- test "work with strings that generate a new line when encoded" do
179
- user = User.create(:email => "foo@bar", :update => "CORRECTED - UPDATE 2-Suspected US missile strike kills 5 in Pakistan")
180
- assert [user] == User.find(:update => "CORRECTED - UPDATE 2-Suspected US missile strike kills 5 in Pakistan").all
181
- end
182
-
183
- # New indices
184
- test "populate a new index when the model is saved" do
185
- class Event < Ohm::Model
186
- attribute :name
187
- end
188
-
189
- foo = Event.create(:name => "Foo")
190
-
191
- assert_raise(Ohm::Model::IndexNotFound) { Event.find(:name => "Foo") }
192
-
193
- class Event < Ohm::Model
194
- index :name
195
- end
196
-
197
- # Find works correctly once the index is added.
198
- Event.find(:name => "Foo")
199
-
200
- # The index was added after foo was created.
201
- assert Event.find(:name => "Foo").empty?
202
-
203
- bar = Event.create(:name => "Bar")
204
-
205
- # Bar was indexed properly.
206
- assert bar == Event.find(:name => "Bar").first
207
-
208
- # Saving all the objects populates the indices.
209
- Event.all.each { |e| e.save }
210
-
211
- # Now foo is indexed.
212
- assert foo == Event.find(:name => "Foo").first
213
- end
data/test/mutex_test.rb DELETED
@@ -1,84 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
4
-
5
- class Person < Ohm::Model
6
- attribute :name
7
- end
8
-
9
- setup do
10
- @p1 = Person.create :name => "Albert"
11
- @p2 = Person[1]
12
- end
13
-
14
- test "prevent other instances of the same object from grabing a locked record" do
15
- t1 = t2 = nil
16
- p1 = Thread.new do
17
- @p1.mutex do
18
- sleep 0.01
19
- t1 = Time.now
20
- end
21
- end
22
-
23
- p2 = Thread.new do
24
- sleep 0.01
25
- @p2.mutex do
26
- t2 = Time.now
27
- end
28
- end
29
-
30
- p1.join
31
- p2.join
32
- assert t2 > t1
33
- end
34
-
35
- test "allow an instance to lock a record if the previous lock is expired" do
36
- @p1.send(:lock!)
37
- @p2.mutex do
38
- assert true
39
- end
40
- end
41
-
42
- test "work if two clients are fighting for the lock" do
43
- @p1.send(:lock!)
44
- @p3 = Person[1]
45
- @p4 = Person[1]
46
-
47
- p1 = Thread.new { @p1.mutex {} }
48
- p2 = Thread.new { @p2.mutex {} }
49
- p3 = Thread.new { @p3.mutex {} }
50
- p4 = Thread.new { @p4.mutex {} }
51
- p1.join
52
- p2.join
53
- p3.join
54
- p4.join
55
- end
56
-
57
- test "yield the right result after a lock fight" do
58
- class Candidate < Ohm::Model
59
- attribute :name
60
- counter :votes
61
- end
62
-
63
- @candidate = Candidate.create :name => "Foo"
64
- @candidate.send(:lock!)
65
-
66
- threads = []
67
-
68
- n = 3
69
- m = 2
70
-
71
- n.times do
72
- threads << Thread.new do
73
- m.times do
74
- @candidate.mutex do
75
- sleep 0.01
76
- @candidate.incr(:votes)
77
- end
78
- end
79
- end
80
- end
81
-
82
- threads.each { |t| t.join }
83
- assert n * m == @candidate.votes
84
- end