ohm 2.0.0.rc1 → 2.0.0.rc2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 60d1fadf47380356ffbc44627e28f9b15ff8528a
4
- data.tar.gz: f911d9c462235f7c56f5216b10f1b2d48f3ab287
3
+ metadata.gz: 44f992bf97d394e618f9e3608a13999e6a37ffbf
4
+ data.tar.gz: 9e97ba2177d8067c64ab4e2b0b7a0a710703bb18
5
5
  SHA512:
6
- metadata.gz: 67eea41a25fd17691a9cc79700abf248438a7bccefc7624053212d6439d6252bfc2850e0a7905fe8a2ad46eadac6d9d11d150978cec4f937a2bbba89ea05e90b
7
- data.tar.gz: 1e17aace64652f6c96cd79fa6ff071a67fbed614951af15e8487d8fee78b21ec69f10313b7e8b1004292d1f97a22c3d8be74d5f892172742fe634fea84989ef2
6
+ metadata.gz: a0d5bc81d2fa070ee3b9306844bc61a1d089cf67e464fd8c3939274db918d986f3e6d97c8166ae3f1caf2c0d679c7c1802c55499d65dc0ca35a619ee9446b342
7
+ data.tar.gz: 50008d8d644b1825507db45e921e78aaa0cd19b48fc587eca43605495155d91e816e49abc75a02f6bc4aef1e5351c81940384da4eb97c8e3e8eb6934ba75ce65
data/.gems CHANGED
@@ -1,4 +1,4 @@
1
- nido -v 0.0.1
2
1
  cutest -v 1.2.0
3
- msgpack -v 0.5.4
4
- redic -v 0.0.5
2
+ msgpack -v 0.5.8
3
+ nido -v 0.0.1
4
+ redic -v 1.0.1
data/CHANGELOG.md ADDED
@@ -0,0 +1,293 @@
1
+ - Lists now respond to range.
2
+
3
+ Example:
4
+
5
+ class Comment < Ohm::Model
6
+ end
7
+
8
+ class Post < Ohm::Model
9
+ list :comments, :Comment
10
+ end
11
+
12
+ c1 = Comment.create
13
+ c2 = Comment.create
14
+ c3 = Comment.create
15
+
16
+ post = Post.create
17
+ post.comments.push(c1)
18
+ post.comments.push(c2)
19
+ post.comments.push(c3)
20
+
21
+ post.comments.range(0, 1) == [c1, c2]
22
+ # => true
23
+
24
+ - When a record is created, `#id` returns a string instead of a integer.
25
+ This ensures ID is string everywhere:
26
+
27
+ Example:
28
+
29
+ ## Before
30
+
31
+ Meetup.create(name: "Ruby").id
32
+ # => 1
33
+
34
+ Meetup.find(name: "Ruby").id
35
+ # => "1"
36
+
37
+ ## Now
38
+
39
+ Meetup.create.id
40
+ # => "1"
41
+
42
+ Meetup.find(name: "Ruby").id
43
+ # => "1"
44
+
45
+ - If an attribute is set to an empty string, Ohm won't delete the attribute.
46
+
47
+ Example:
48
+
49
+ # Before
50
+ event = Meetup.create(location: "")
51
+ Meetup[event.id].location
52
+ # => nil
53
+
54
+ # Now
55
+ event = Meetup.create(location: "")
56
+ Meetup[event.id].location
57
+ # => ""
58
+
59
+ - Include `Ohm::List#ids` in the public API. It returns an array with all
60
+ the ID's of the list.
61
+
62
+ Example:
63
+
64
+ class Comment < Ohm::Model
65
+ end
66
+
67
+ class Post < Ohm::Model
68
+ list :comments, :Comment
69
+ end
70
+
71
+ post = Post.create
72
+ post.comments.push(Comment.create)
73
+ post.comments.push(Comment.create)
74
+ post.comments.push(Comment.create)
75
+
76
+ post.comments.ids
77
+ # => ["1", "2", "3"]
78
+
79
+ - Include `Ohm::BasicSet#exists?` in the public API. This makes possible
80
+ to check if an id is included in a set. Check `Ohm::BasicSet#exists?`
81
+ documentation for more details.
82
+
83
+ Example:
84
+
85
+ class Post < Ohm::Model
86
+ end
87
+
88
+ class User < Ohm::Model
89
+ set :posts, :Post
90
+ end
91
+
92
+ user = User.create
93
+ user.posts.add(post = Post.create)
94
+
95
+ user.posts.exists?(post.id) # => true
96
+ user.posts.exists?("nonexistent") # => false
97
+
98
+
99
+ - Change `Ohm::MultiSet#except` to union keys instead of intersect them
100
+ when passing an array.
101
+
102
+ Example:
103
+
104
+ class User < Ohm::Model
105
+ attribute :name
106
+ end
107
+
108
+ john = User.create(name: "John")
109
+ jane = User.create(name: "Jane")
110
+
111
+ res = User.all.except(name: [john.name, jane.name])
112
+
113
+ # before
114
+ res.size # => 2
115
+
116
+ # now
117
+ res.size # => 0
118
+
119
+
120
+ - Move ID generation to Lua. With this change, it's no longer possible
121
+ to generate custom ids. All ids are autoincremented.
122
+
123
+
124
+ - Add `Ohm::Model.track` method to allow track of custom keys. This key
125
+ is removed when the model is deleted.
126
+
127
+ Example:
128
+
129
+ class Foo < Ohm::Model
130
+ track :notes
131
+ end
132
+
133
+ foo = Foo.create
134
+
135
+ Foo.redis.call("SET", foo.key[:notes], "something")
136
+ Foo.redis.call("KEYS", "*").include?("Foo:1:notes")
137
+ # => true
138
+
139
+ foo.delete
140
+ Foo.redis.call("KEYS", "*").include?("Foo:1:notes")
141
+ # => false
142
+
143
+
144
+ - `Ohm::Model#reference` accepts strings as model references.
145
+
146
+ Example:
147
+
148
+ class Bar < Ohm::Model
149
+ reference :foo, "SomeNamespace::Foo"
150
+ end
151
+
152
+ Bar.create().foo.class # => SomeNamespace::Foo
153
+
154
+
155
+ - `Ohm::Model#save` sanitizes attributes before sending to Lua.
156
+ This complies with the original spec in Ohm v1 where a `to_s`
157
+ is done on each value.
158
+
159
+ Example:
160
+
161
+ class Post < Ohm::Model
162
+ attribute :published
163
+ end
164
+
165
+ post = Post.create(published: true)
166
+ post = Post[post.id]
167
+
168
+ # before
169
+ post.published # => "1"
170
+
171
+ # now
172
+ post.published # => "true"
173
+
174
+
175
+ - `Ohm::Model#save` don't save values for attributes set to false.
176
+
177
+ Example:
178
+
179
+ class Post < Ohm::Model
180
+ attribute :published
181
+ end
182
+
183
+ post = Post.create(published: false)
184
+ post = Post[post.id]
185
+
186
+ # before
187
+ post.published # => "0"
188
+
189
+ # now
190
+ post.published # => nil
191
+
192
+
193
+ - `nest` dependency has been removed. Now, Ohm uses [nido][nido]
194
+ to generate the keys that hold the data.
195
+
196
+
197
+ - `scrivener` dependency has been removed. Ohm no longer supports model
198
+ validations and favors filter validation on the boundary layer. Check
199
+ [scrivener][scrivener] project for more information.
200
+
201
+
202
+ - `redis` dependency has been removed. Ohm 2 uses [redic][redic],
203
+ a lightweight Redis client. Redic uses the `hiredis` gem for the
204
+ connection and for parsing the replies. Now, it defaults to a
205
+ Redic connection to "redis://127.0.0.1:6379". To change it, you
206
+ will need to provide an instance of `Redic` through the `Ohm.redis=`
207
+ helper.
208
+
209
+ Example:
210
+
211
+ Ohm.redis = Redic.new("redis://:<passwd>@<host>:<port>/<db>")
212
+
213
+ Check Redic README for more details.
214
+
215
+
216
+ - `Ohm::Model#transaction` and `Ohm::Transaction` have been removed.
217
+
218
+
219
+ - Move `save` and `delete` operations to Lua scripts.
220
+
221
+
222
+ - Support for Ruby 1.8 and 1.9 has been removed.
223
+
224
+ [nido]: https://github.com/soveran/nido
225
+ [scrivener]: https://github.com/soveran/scrivener
226
+ [redic]: https://github.com/amakawa/redic
227
+
228
+ 1.3.2
229
+ -----
230
+
231
+ - Fetching a batch of objects is now done in batches of 1000 objects at
232
+ a time. If you are iterating over large collections, this change should
233
+ provide a significant performance boost both in used memory and total
234
+ execution time.
235
+ - MutableSet#<< is now an alias for #add.
236
+
237
+ 1.3.1
238
+ -----
239
+
240
+ - Improve memory consumption when indexing persisted attributes.
241
+
242
+ No migration is needed and old indices will be cleaned up as you save
243
+ instances.
244
+
245
+ 1.3.0
246
+ -----
247
+
248
+ - Add Model.attributes.
249
+
250
+ 1.2.0
251
+ -----
252
+
253
+ - Enumerable fix.
254
+ - Merge Ohm::PipelinedFetch into Ohm::Collection.
255
+ - Fix Set, MultiSet, and List enumerable behavior.
256
+ - Change dependencies to use latest cutest.
257
+
258
+ 1.1.0
259
+ -----
260
+
261
+ - Compatible with redis-rb 3.
262
+
263
+ 1.0.0
264
+ -----
265
+
266
+ - Fetching a batch of objects is now done through one pipeline, effectively
267
+ reducing the IO to just 2 operations (one for SMEMBERS / LRANGE, one for
268
+ the actual HGET of all the individual HASHes.)
269
+ - write_remote / read_remote have been replaced with set / get respectively.
270
+ - Ohm::Model.unique has been added.
271
+ - Ohm::Model::Set has been renamed to Ohm::Set
272
+ - Ohm::Model::List has been renamed to Ohm::List
273
+ - Ohm::Model::Collection is gone.
274
+ - Ohm::Validations is gone. Ohm now uses Scrivener::Validations.
275
+ - Ohm::Key is gone. Ohm now uses Nest directly.
276
+ - No more concept of volatile keys.
277
+ - Ohm::Model::Wrapper is gone.
278
+ - Use Symbols for constants instead of relying on Ohm::Model.const_missing.
279
+ - #sort / #sort_by now uses `limit` as it's used in redis-rb, e.g. you
280
+ have to pass in an array like so: sort(limit: [0, 1]).
281
+ - Set / List have been trimmed to contain only the minimum number
282
+ of necessary methods.
283
+ - You can no longer mutate a collection / set as before, e.g. doing
284
+ User.find(...).add(User[1]) will throw an error.
285
+ - The #union operation has been added. You can now chain it with your filters.
286
+ - Temporary keys when doing finds are now automatically cleaned up.
287
+ - Counters are now stored in their own key instead, i.e. in
288
+ User:<id>:counters.
289
+ - JSON support has to be explicitly required by doing `require
290
+ "ohm/json"`.
291
+ - All save / delete / update operations are now done using
292
+ transactions (see http://redis.io/topics/transactions).
293
+ - All indices are now stored without converting the values to base64.
data/README.md CHANGED
@@ -48,7 +48,7 @@ with the sources if you want to change some settings.
48
48
 
49
49
  If you don't have Ohm, try this:
50
50
 
51
- $ [sudo] gem install ohm
51
+ $ [sudo] gem install ohm -v 2.0.0.rc1
52
52
 
53
53
  Or you can grab the code from [http://github.com/soveran/ohm][ohm].
54
54
 
data/benchmarks/common.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require "bench"
2
2
  require_relative "../lib/ohm"
3
3
 
4
- Ohm.connect(:port => 6379, :db => 15)
4
+ Ohm.redis = Redic.new("redis://127.0.0.1:6379/15")
5
5
  Ohm.flush
6
6
 
7
7
  class Event < Ohm::Model
@@ -5,91 +5,64 @@
5
5
  # If you've ever needed to build an AJAX route handler, you may have noticed
6
6
  # the prevalence of the design pattern where you return a JSON response.
7
7
  #
8
- # post "/comments.json" do
9
- # comment = Comment.create(params[:comment])
10
- # comment.to_json
8
+ # on get, "comments" do
9
+ # res.write Comment.all.to_json
11
10
  # end
12
11
  #
13
12
  # `Ohm` helps you here by providing sensible defaults. It's not very popular,
14
13
  # but `Ohm` actually has a `to_hash` method.
15
14
 
16
- # Let's start by requiring `ohm` and `json`. In ruby 1.9, `json` is
17
- # actually part of the standard library, so you don't have to install a gem
18
- # for it. For ruby 1.8.x, a simple `[sudo] gem install json` will do it.
15
+ # Let's start by requiring `ohm` and `ohm/json`.
19
16
  require "ohm"
20
- require "json"
17
+ require "ohm/json"
21
18
 
22
- # Here we define our `Post` model with just a single `attribute` called
23
- # `title`.
24
- #
25
- # We also define a validation, asserting the presence of the `title`.
19
+ # Here we define our `Post` model with just a single `attribute` called `title`.
26
20
  class Post < Ohm::Model
27
21
  attribute :title
28
-
29
- def validate
30
- assert_present :title
31
- end
32
22
  end
33
23
 
34
- # Now let's load the test framework `cutest` to verify our code. We
35
- # also call `Ohm.flush` for each test run.
24
+ # Now let's load the test framework `cutest` to test our code.
36
25
  require "cutest"
37
26
 
27
+ # We also call `Ohm.flush` for each test run.
38
28
  prepare { Ohm.flush }
39
29
 
40
30
  # When we successfully create a `Post`, we can see that it returns
41
31
  # only the *id* and its value in the hash.
42
32
  test "hash representation when created" do
43
- post = Post.create(:title => "my post")
33
+ post = Post.create(title: "my post")
44
34
 
45
- assert({ :id => "1" } == post.to_hash)
35
+ assert_equal Hash[id: post.id], post.to_hash
46
36
  end
47
37
 
48
38
  # The JSON representation is actually just `post.to_hash.to_json`, so the
49
39
  # same result, only in JSON, is returned.
50
40
  test "json representation when created" do
51
- post = Post.create(:title => "my post")
52
-
53
- assert("{\"id\":\"1\"}" == post.to_json)
54
- end
41
+ post = Post.create(title: "my post")
55
42
 
56
- # Let's try and do the opposite now -- that is, purposely try and create
57
- # an invalid `Post`. We can see that it returns the `errors` of the
58
- # `Post`, because we added an `assert_present :title` in our code above.
59
- test "hash representation when validation failed" do
60
- post = Post.create
61
-
62
- assert({ :errors => [[:title, :not_present]]} == post.to_hash)
63
- end
64
-
65
- # As is the case for a valid record, the JSON representation is
66
- # still equivalent to `post.to_hash.to_json`.
67
- test "json representation when validation failed" do
68
- post = Post.create
69
-
70
- assert("{\"errors\":[[\"title\",\"not_present\"]]}" == post.to_json)
43
+ assert_equal "{\"id\":\"#{post.id}\"}", post.to_json
71
44
  end
72
45
 
73
46
  #### Whitelisted approach
74
47
 
75
- # Unlike in other frameworks which dumps out all attributes by default,
48
+ # Unlike other frameworks which dumps out all attributes by default,
76
49
  # `Ohm` favors a whitelisted approach where you have to explicitly
77
50
  # declare which attributes you want.
78
51
  #
79
- # By default, only `:id` and `:errors` will be available, depending if
80
- # it was successfully saved or if there were validation errors.
52
+ # By default, only `:id` will be available if the model is persisted.
81
53
 
82
54
  # Let's re-open our Post class, and add a `to_hash` method.
83
55
  class Post
84
56
  def to_hash
85
- super.merge(:title => title)
57
+ super.merge(title: title)
86
58
  end
87
59
  end
88
60
 
89
61
  # Now, let's test that the title is in fact part of `to_hash`.
90
62
  test "customized to_hash" do
91
- post = Post.create(:title => "Override FTW?")
92
- assert({ :id => "1", :title => "Override FTW?" } == post.to_hash)
63
+ post = Post.create(title: "Override FTW?")
64
+
65
+ assert_equal Hash[id: post.id, title: post.title], post.to_hash
93
66
  end
94
67
 
95
68
  #### Conclusion
data/lib/ohm.rb CHANGED
@@ -4,7 +4,7 @@ require "msgpack"
4
4
  require "nido"
5
5
  require "redic"
6
6
  require "securerandom"
7
- require "ohm/command"
7
+ require_relative "ohm/command"
8
8
 
9
9
  module Ohm
10
10
  LUA_CACHE = Hash.new { |h, k| h[k] = Hash.new }
@@ -134,11 +134,15 @@ module Ohm
134
134
 
135
135
  # Wraps the whole pipelining functionality.
136
136
  def fetch(ids)
137
- ids.each do |id|
138
- redis.queue("HGETALL", namespace[id])
139
- end
137
+ data = nil
138
+
139
+ model.synchronize do
140
+ ids.each do |id|
141
+ redis.queue("HGETALL", namespace[id])
142
+ end
140
143
 
141
- data = redis.commit
144
+ data = redis.commit
145
+ end
142
146
 
143
147
  return [] if data.nil?
144
148
 
@@ -178,6 +182,34 @@ module Ohm
178
182
  model[redis.call("LINDEX", key, -1)]
179
183
  end
180
184
 
185
+ # Returns an array of elements from the list using LRANGE.
186
+ # #range receives 2 integers, start and stop
187
+ #
188
+ # Example:
189
+ #
190
+ # class Comment < Ohm::Model
191
+ # end
192
+ #
193
+ # class Post < Ohm::Model
194
+ # list :comments, :Comment
195
+ # end
196
+ #
197
+ # c1 = Comment.create
198
+ # c2 = Comment.create
199
+ # c3 = Comment.create
200
+ #
201
+ # post = Post.create
202
+ #
203
+ # post.comments.push(c1)
204
+ # post.comments.push(c2)
205
+ # post.comments.push(c3)
206
+ #
207
+ # [c1, c2] == post.comments.range(0, 1)
208
+ # # => true
209
+ def range(start, stop)
210
+ fetch(redis.call("LRANGE", key, start, stop))
211
+ end
212
+
181
213
  # Checks if the model is part of this List.
182
214
  #
183
215
  # An important thing to note is that this method loads all of the
@@ -186,7 +218,7 @@ module Ohm
186
218
  #
187
219
  # You may want to avoid doing this if your list has say, 10K entries.
188
220
  def include?(model)
189
- ids.include?(model.id.to_s)
221
+ ids.include?(model.id)
190
222
  end
191
223
 
192
224
  # Replace all the existing elements of a list with a different
@@ -206,13 +238,15 @@ module Ohm
206
238
  # # => false
207
239
  #
208
240
  def replace(models)
209
- ids = models.map { |model| model.id }
210
-
211
- redis.queue("MULTI")
212
- redis.queue("DEL", key)
213
- ids.each { |id| redis.queue("RPUSH", key, id) }
214
- redis.queue("EXEC")
215
- redis.commit
241
+ ids = models.map(&:id)
242
+
243
+ model.synchronize do
244
+ redis.queue("MULTI")
245
+ redis.queue("DEL", key)
246
+ ids.each { |id| redis.queue("RPUSH", key, id) }
247
+ redis.queue("EXEC")
248
+ redis.commit
249
+ end
216
250
  end
217
251
 
218
252
  # Pushes the model to the _end_ of the list using RPUSH.
@@ -236,7 +270,7 @@ module Ohm
236
270
  # end
237
271
  #
238
272
  # class Post < Ohm::Model
239
- # list :comments, Comment
273
+ # list :comments, :Comment
240
274
  # end
241
275
  #
242
276
  # p = Post.create
@@ -256,11 +290,32 @@ module Ohm
256
290
  redis.call("LREM", key, 0, model.id)
257
291
  end
258
292
 
259
- private
293
+ # Returns an array with all the ID's of the list.
294
+ #
295
+ # class Comment < Ohm::Model
296
+ # end
297
+ #
298
+ # class Post < Ohm::Model
299
+ # list :comments, :Comment
300
+ # end
301
+ #
302
+ # post = Post.create
303
+ # post.comments.push(Comment.create)
304
+ # post.comments.push(Comment.create)
305
+ # post.comments.push(Comment.create)
306
+ #
307
+ # post.comments.map(&:id)
308
+ # # => ["1", "2", "3"]
309
+ #
310
+ # post.comments.ids
311
+ # # => ["1", "2", "3"]
312
+ #
260
313
  def ids
261
314
  redis.call("LRANGE", key, 0, -1)
262
315
  end
263
316
 
317
+ private
318
+
264
319
  def redis
265
320
  model.redis
266
321
  end
@@ -270,9 +325,8 @@ module Ohm
270
325
  class BasicSet
271
326
  include Collection
272
327
 
273
- # Allows you to sort by any field in your model.
274
- #
275
- # Example:
328
+ # Allows you to sort by any attribute in the hash, this doesn't include
329
+ # the +id+. If you want to sort by ID, use #sort.
276
330
  #
277
331
  # class User < Ohm::Model
278
332
  # attribute :name
@@ -365,7 +419,27 @@ module Ohm
365
419
  end
366
420
  end
367
421
 
368
- # Grab all the elements of this set using SMEMBERS.
422
+ # Returns an array with all the ID's of the set.
423
+ #
424
+ # class Post < Ohm::Model
425
+ # end
426
+ #
427
+ # class User < Ohm::Model
428
+ # attribute :name
429
+ # index :name
430
+ #
431
+ # set :posts, :Post
432
+ # end
433
+ #
434
+ # User.create(name: "John")
435
+ # User.create(name: "Jane")
436
+ #
437
+ # User.all.ids
438
+ # # => ["1", "2"]
439
+ #
440
+ # User.find(name: "John").union(name: "Jane").ids
441
+ # # => ["1", "2"]
442
+ #
369
443
  def ids
370
444
  execute { |key| redis.call("SMEMBERS", key) }
371
445
  end
@@ -524,13 +598,15 @@ module Ohm
524
598
  # # => false
525
599
  #
526
600
  def replace(models)
527
- ids = models.map { |model| model.id }
528
-
529
- redis.queue("MULTI")
530
- redis.queue("DEL", key)
531
- ids.each { |id| redis.queue("SADD", key, id) }
532
- redis.queue("EXEC")
533
- redis.commit
601
+ ids = models.map(&:id)
602
+
603
+ model.synchronize do
604
+ redis.queue("MULTI")
605
+ redis.queue("DEL", key)
606
+ ids.each { |id| redis.queue("SADD", key, id) }
607
+ redis.queue("EXEC")
608
+ redis.commit
609
+ end
534
610
  end
535
611
  end
536
612
 
@@ -695,7 +771,15 @@ module Ohm
695
771
  end
696
772
 
697
773
  def self.redis
698
- @redis ||= Redic.new(Ohm.redis.url)
774
+ defined?(@redis) ? @redis : Ohm.redis
775
+ end
776
+
777
+ def self.mutex
778
+ @mutex ||= Mutex.new
779
+ end
780
+
781
+ def self.synchronize(&block)
782
+ mutex.synchronize(&block)
699
783
  end
700
784
 
701
785
  # Returns the namespace for all the keys generated using this model.
@@ -703,6 +787,7 @@ module Ohm
703
787
  # Example:
704
788
  #
705
789
  # class User < Ohm::Model
790
+ # end
706
791
  #
707
792
  # User.key == "User"
708
793
  # User.key.kind_of?(String)
data/lib/ohm/lua/save.lua CHANGED
@@ -122,4 +122,4 @@ index(model, indices)
122
122
  remove_uniques(model, uniques)
123
123
  unique(model, uniques)
124
124
 
125
- return model.id
125
+ return tostring(model.id)
data/ohm.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "ohm"
3
- s.version = "2.0.0.rc1"
3
+ s.version = "2.0.0.rc2"
4
4
  s.summary = %{Object-hash mapping library for Redis.}
5
5
  s.description = %Q{Ohm is a library that allows to store an object in Redis, a persistent key-value database. It has very good performance.}
6
6
  s.authors = ["Michel Martens", "Damian Janowski", "Cyril David"]
data/test/association.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
2
2
 
3
3
  class User < Ohm::Model
4
4
  collection :posts, :Post
data/test/connection.rb CHANGED
@@ -1,9 +1,10 @@
1
- # encoding: UTF-8
1
+ require_relative 'helper'
2
2
 
3
- require File.expand_path("./helper", File.dirname(__FILE__))
3
+ test "model inherits Ohm.redis connection by default" do
4
+ class C < Ohm::Model
5
+ end
4
6
 
5
- unless defined?(Redic::CannotConnectError)
6
- Redic::CannotConnectError = Errno::ECONNREFUSED
7
+ assert_equal C.redis.url, Ohm.redis.url
7
8
  end
8
9
 
9
10
  test "model can define its own connection" do
@@ -13,10 +14,3 @@ test "model can define its own connection" do
13
14
 
14
15
  assert B.redis.url != Ohm.redis.url
15
16
  end
16
-
17
- test "model inherits Ohm.redis connection by default" do
18
- class C < Ohm::Model
19
- end
20
-
21
- assert_equal C.redis.url, Ohm.redis.url
22
- end
data/test/core.rb CHANGED
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class Event < Ohm::Model
6
4
  attribute :name
@@ -8,19 +6,19 @@ class Event < Ohm::Model
8
6
  end
9
7
 
10
8
  test "assign attributes from the hash" do
11
- event = Event.new(:name => "Ruby Tuesday")
9
+ event = Event.new(name: "Ruby Tuesday")
12
10
  assert_equal event.name, "Ruby Tuesday"
13
11
  end
14
12
 
15
13
  test "assign an ID and save the object" do
16
- event1 = Event.create(:name => "Ruby Tuesday")
17
- event2 = Event.create(:name => "Ruby Meetup")
14
+ event1 = Event.create(name: "Ruby Tuesday")
15
+ event2 = Event.create(name: "Ruby Meetup")
18
16
 
19
- assert_equal "1", event1.id.to_s
20
- assert_equal "2", event2.id.to_s
17
+ assert_equal "1", event1.id
18
+ assert_equal "2", event2.id
21
19
  end
22
20
 
23
21
  test "save the attributes in UTF8" do
24
- event = Event.create(:name => "32° Kisei-sen")
25
- assert "32° Kisei-sen" == Event[event.id].name
22
+ event = Event.create(name: "32° Kisei-sen")
23
+ assert_equal "32° Kisei-sen", Event[event.id].name
26
24
  end
data/test/counters.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
2
2
 
3
3
  $VERBOSE = false
4
4
 
data/test/enumerable.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
2
2
 
3
3
  scope do
4
4
  class Contact < Ohm::Model
@@ -32,7 +32,7 @@ scope do
32
32
 
33
33
  test "select" do |john, jane|
34
34
  assert_equal 2, Contact.all.count
35
- assert_equal [john], Contact.all.select { |c| c.id.to_s == john.id.to_s }
35
+ assert_equal [john], Contact.all.select { |c| c.id == john.id }
36
36
  end
37
37
  end
38
38
 
data/test/filtering.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
2
2
 
3
3
  class User < Ohm::Model
4
4
  attribute :fname
@@ -165,7 +165,7 @@ scope do
165
165
 
166
166
  assert_equal 1, res.size
167
167
  assert res.map(&:mood).include?("sad")
168
- assert res.map(&:book_id).include?(book2.id.to_s)
168
+ assert res.map(&:book_id).include?(book2.id)
169
169
  end
170
170
 
171
171
  test "@myobie usecase" do |book1, book2|
data/test/hash_key.rb CHANGED
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class Tag < Ohm::Model
6
4
  attribute :name
data/test/helper.rb CHANGED
@@ -1,7 +1,3 @@
1
- # encoding: UTF-8
2
-
3
- $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
4
-
5
1
  begin
6
2
  require "ruby-debug"
7
3
  rescue LoadError
@@ -18,7 +14,7 @@ end unless defined?(silence_warnings)
18
14
 
19
15
  $VERBOSE = true
20
16
 
21
- require "ohm"
17
+ require_relative "../lib/ohm"
22
18
 
23
19
  Ohm.redis = Redic.new("redis://127.0.0.1:6379")
24
20
 
data/test/indices.rb CHANGED
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class User < Ohm::Model
6
4
  attribute :email
data/test/json.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require_relative 'helper'
2
-
3
- require "ohm/json"
2
+ require_relative "../lib/ohm/json"
4
3
 
5
4
  class Venue < Ohm::Model
6
5
  attribute :name
data/test/list.rb CHANGED
@@ -1,4 +1,4 @@
1
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
2
2
 
3
3
  class Post < Ohm::Model
4
4
  list :comments, :Comment
@@ -67,3 +67,17 @@ test "deleting main model cleans up the collection" do |p, _, _, _|
67
67
 
68
68
  assert_equal 0, Ohm.redis.call("EXISTS", p.key[:comments])
69
69
  end
70
+
71
+ test "#ids returns an array with the ids" do |post, *comments|
72
+ assert_equal comments.map(&:id), post.comments.ids
73
+ end
74
+
75
+ test "range" do |p, c1, c2, c3|
76
+ assert_equal 3, p.comments.range(0, 100).size
77
+ assert_equal [c1, c2, c3], p.comments.range(0, 2)
78
+ assert_equal [c1, c2], p.comments.range(0, 1)
79
+ assert_equal [c2, c3], p.comments.range(1, 2)
80
+ assert_equal [c1, c2, c3], p.comments.range(0, -1)
81
+ assert_equal [c1, c2], p.comments.range(0, -2)
82
+ assert_equal [c2, c3], p.comments.range(1, -1)
83
+ end
data/test/model.rb CHANGED
@@ -1,7 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
4
-
1
+ require_relative "helper"
5
2
  require "ostruct"
6
3
 
7
4
  class Post < Ohm::Model
@@ -113,11 +110,11 @@ test "assign attributes from the hash" do
113
110
  end
114
111
 
115
112
  test "assign an ID and save the object" do
116
- event1 = Event.create(:name => "Ruby Tuesday")
117
- event2 = Event.create(:name => "Ruby Meetup")
113
+ event1 = Event.create(name: "Ruby Tuesday")
114
+ event2 = Event.create(name: "Ruby Meetup")
118
115
 
119
- assert 1 == event1.id
120
- assert 2 == event2.id
116
+ assert_equal "1", event1.id
117
+ assert_equal "2", event2.id
121
118
  end
122
119
 
123
120
  test "updates attributes" do
@@ -138,14 +135,6 @@ test "delete the attribute if set to nil" do
138
135
  assert_equal nil, Meetup[event.id].location
139
136
  end
140
137
 
141
- # FIXME: Failing test, as Meetup[event.id].location is returning "".
142
- # test "delete the attribute if set to an empty string" do
143
- # event = Meetup.create(:name => "Ruby Tuesday", :location => "Los Angeles")
144
- # assert "Los Angeles" == Meetup[event.id].location
145
- # assert event.update(:location => "")
146
- # assert_equal nil, Meetup[event.id].location
147
- # end
148
-
149
138
  test "not raise if an attribute is redefined" do
150
139
  class RedefinedModel < Ohm::Model
151
140
  attribute :name
@@ -267,8 +256,8 @@ test "assign a new id to the event" do
267
256
  assert !event1.new?
268
257
  assert !event2.new?
269
258
 
270
- assert 1 == event1.id
271
- assert 2 == event2.id
259
+ assert_equal "1", event1.id
260
+ assert_equal "2", event2.id
272
261
  end
273
262
 
274
263
  # Saving a model
@@ -703,6 +692,8 @@ end
703
692
  # Models connected to different databases
704
693
  class ::Car < Ohm::Model
705
694
  attribute :name
695
+
696
+ self.redis = Redic.new
706
697
  end
707
698
 
708
699
  class ::Make < Ohm::Model
@@ -711,7 +702,6 @@ end
711
702
 
712
703
  setup do
713
704
  Car.redis.call("SELECT", 15)
714
- Car.redis.call("FLUSHDB")
715
705
  end
716
706
 
717
707
  test "save to the selected database" do
data/test/set.rb CHANGED
@@ -4,6 +4,10 @@ class Post < Ohm::Model
4
4
  end
5
5
 
6
6
  class User < Ohm::Model
7
+ attribute :name
8
+
9
+ index :name
10
+
7
11
  set :posts, :Post
8
12
  end
9
13
 
@@ -18,3 +22,16 @@ test '#exists? returns true if the given id is included in the set' do
18
22
 
19
23
  assert user.posts.exists?(post.id)
20
24
  end
25
+
26
+ test "#ids returns an array with the ids" do
27
+ user_ids = [
28
+ User.create(name: "John").id,
29
+ User.create(name: "Jane").id
30
+ ]
31
+
32
+ assert_equal user_ids, User.all.ids
33
+
34
+ result = User.find(name: "John").union(name: "Jane")
35
+
36
+ assert_equal user_ids, result.ids
37
+ end
@@ -0,0 +1,67 @@
1
+ require_relative "helper"
2
+
3
+ class Post < Ohm::Model; end
4
+ class Role < Ohm::Model; end
5
+
6
+ class User < Ohm::Model
7
+ list :posts, :Post
8
+ set :roles, :Role
9
+ end
10
+
11
+ setup do
12
+ User.create
13
+ end
14
+
15
+ test "list#replace" do |user|
16
+ Post.mutex.lock
17
+
18
+ thread = Thread.new { user.posts.replace([Post.create]) }
19
+
20
+ sleep 0.1
21
+
22
+ assert_equal true, thread.alive?
23
+
24
+ Post.mutex.unlock
25
+
26
+ sleep 0.1
27
+
28
+ assert_equal false, thread.alive?
29
+
30
+ thread.join
31
+ end
32
+
33
+ test "set#replace" do |user|
34
+ Role.mutex.lock
35
+
36
+ thread = Thread.new { user.roles.replace([Role.create]) }
37
+
38
+ sleep 0.1
39
+
40
+ assert_equal true, thread.alive?
41
+
42
+ Role.mutex.unlock
43
+
44
+ sleep 0.1
45
+
46
+ assert_equal false, thread.alive?
47
+
48
+ thread.join
49
+ end
50
+
51
+ test "collection#fetch" do
52
+ User.mutex.lock
53
+
54
+ thread = Thread.new { User.all.to_a }
55
+
56
+ sleep 0.1
57
+
58
+ assert_equal true, thread.alive?
59
+
60
+ User.mutex.unlock
61
+
62
+ sleep 0.1
63
+
64
+ assert_equal false, thread.alive?
65
+
66
+ thread.join
67
+ end
data/test/uniques.rb CHANGED
@@ -1,6 +1,4 @@
1
- # encoding: UTF-8
2
-
3
- require File.expand_path("./helper", File.dirname(__FILE__))
1
+ require_relative "helper"
4
2
 
5
3
  class User < Ohm::Model
6
4
  attribute :email
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: 2.0.0.rc1
4
+ version: 2.0.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michel Martens
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-12-18 00:00:00.000000000 Z
13
+ date: 2014-02-25 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: redic
@@ -80,7 +80,7 @@ extra_rdoc_files: []
80
80
  files:
81
81
  - .gems
82
82
  - .gitignore
83
- - CHANGELOG
83
+ - CHANGELOG.md
84
84
  - LICENSE
85
85
  - README.md
86
86
  - Rakefile
@@ -113,12 +113,12 @@ files:
113
113
  - test/hash_key.rb
114
114
  - test/helper.rb
115
115
  - test/indices.rb
116
- - test/issue-52.rb
117
116
  - test/json.rb
118
117
  - test/list.rb
119
118
  - test/model.rb
120
119
  - test/set.rb
121
120
  - test/test.conf
121
+ - test/thread_safety.rb
122
122
  - test/to_hash.rb
123
123
  - test/uniques.rb
124
124
  homepage: http://soveran.github.io/ohm/
data/CHANGELOG DELETED
@@ -1,112 +0,0 @@
1
- (unreleased)
2
-
3
- - Include Ohm::BasicSet#exists? in the public API. This makes possible
4
- to check if an id is included in a set. Check Ohm::BasicSet#exists?
5
- documentation for more details.
6
-
7
- - Change Ohm::MultiSet#except to union keys instead of intersect them
8
- when passing an array.
9
-
10
- class User < Ohm::Model
11
- attribute :name
12
- end
13
-
14
- john = User.create(:name => "John")
15
- jane = User.create(:name => "Jane")
16
-
17
- res = User.all.except(:name => [john.name, jane.name])
18
-
19
- # before
20
- res.size # => 2
21
-
22
- # now
23
- res.size # => 0
24
-
25
- - Move ID generation to Lua. With this change, it's no longer possible
26
- to generate custom ids. All ids are autoincremented.
27
-
28
- - Ohm::Model#reference accepts strings as model references. For example:
29
-
30
- class Bar < Ohm::Model
31
- reference :foo, "SomeNamespace::Foo"
32
- end
33
-
34
- - Nest dependency has been removed. Now, Ohm uses Nido
35
- (https://github.com/soveran/nido) to generate the keys that hold
36
- the data.
37
-
38
- - Scrivener dependency has been removed.
39
-
40
- - Ohm no longer supports model validations and favors filter validation
41
- on the boundary layer. Check Scrivener project
42
- (https://github.com/soveran/scrivener) for more information.
43
-
44
- - Redis dependency has been removed. Now, Ohm uses Redic
45
- (https://github.com/amakawa/redic), a lightweight Redis client.
46
- Redic uses the hiredis gem for the connection and for parsing
47
- the replies. Check Redic's README for more details.
48
-
49
- - Ohm::Model#transaction has been removed.
50
-
51
- - Ohm::Transaction has been removed.
52
-
53
- 1.3.2
54
-
55
- - Fetching a batch of objects is now done in batches of 1000 objects at
56
- a time. If you are iterating over large collections, this change should
57
- provide a significant performance boost both in used memory and total
58
- execution time.
59
- - MutableSet#<< is now an alias for #add.
60
-
61
- 1.3.1
62
-
63
- - Improve memory consumption when indexing persisted attributes.
64
-
65
- No migration is needed and old indices will be cleaned up as you save
66
- instances.
67
-
68
- 1.3.0
69
-
70
- - Add Model.attributes.
71
-
72
- 1.2.0
73
-
74
- - Enumerable fix.
75
- - Merge Ohm::PipelinedFetch into Ohm::Collection.
76
- - Fix Set, MultiSet, and List enumerable behavior.
77
- - Change dependencies to use latest cutest.
78
-
79
- 1.1.0
80
-
81
- - Compatible with redis-rb 3.
82
-
83
- 1.0.0
84
-
85
- - Fetching a batch of objects is now done through one pipeline, effectively
86
- reducing the IO to just 2 operations (one for SMEMBERS / LRANGE, one for
87
- the actual HGET of all the individual HASHes.)
88
- - write_remote / read_remote have been replaced with set / get respectively.
89
- - Ohm::Model.unique has been added.
90
- - Ohm::Model::Set has been renamed to Ohm::Set
91
- - Ohm::Model::List has been renamed to Ohm::List
92
- - Ohm::Model::Collection is gone.
93
- - Ohm::Validations is gone. Ohm now uses Scrivener::Validations.
94
- - Ohm::Key is gone. Ohm now uses Nest directly.
95
- - No more concept of volatile keys.
96
- - Ohm::Model::Wrapper is gone.
97
- - Use Symbols for constants instead of relying on Ohm::Model.const_missing.
98
- - #sort / #sort_by now uses `limit` as it's used in redis-rb, e.g. you
99
- have to pass in an array like so: sort(limit: [0, 1]).
100
- - Set / List have been trimmed to contain only the minimum number
101
- of necessary methods.
102
- - You can no longer mutate a collection / set as before, e.g. doing
103
- User.find(...).add(User[1]) will throw an error.
104
- - The #union operation has been added. You can now chain it with your filters.
105
- - Temporary keys when doing finds are now automatically cleaned up.
106
- - Counters are now stored in their own key instead, i.e. in
107
- User:<id>:counters.
108
- - JSON support has to be explicitly required by doing `require
109
- "ohm/json"`.
110
- - All save / delete / update operations are now done using
111
- transactions (see http://redis.io/topics/transactions).
112
- - All indices are now stored without converting the values to base64.
data/test/issue-52.rb DELETED
@@ -1,34 +0,0 @@
1
- require_relative "helper"
2
-
3
- class Model < Ohm::Model
4
- attribute :hash
5
- index :hash
6
-
7
- attribute :data
8
- end
9
-
10
- test do
11
- 50.times do |i|
12
- Ohm.flush
13
-
14
- Model.create(:hash => "123")
15
-
16
- assert_equal 1, Ohm.redis.call("SCARD", "Model:all")
17
-
18
- Thread.new do
19
- a = Model.find(:hash => "123").first
20
- a.update(:data => "2")
21
- end
22
-
23
- sleep 0.01
24
-
25
- b = Model.find(:hash => "123").first
26
-
27
- if Ohm.redis.call("SCARD", "Model:indices:hash:123") != 1
28
- flunk("Failed at iteration %d" % i)
29
- end
30
-
31
- assert ! b.nil?
32
- end
33
- end
34
-