ohm 2.1.0 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 879b753fd8424a547c5cf83753b2f4d7dd817a14
4
- data.tar.gz: fab1f4b6971328047ed17e37d589ebc47c32d082
3
+ metadata.gz: 9c7c0f6876c2563f59ad8e20dcbab465e5cffcb8
4
+ data.tar.gz: e4f06f406172d073ff4ae25ac2d4f9ebad74c034
5
5
  SHA512:
6
- metadata.gz: 3538cccef143743083a6a31c672e4e5bacec42f743196fbcf52f1c68ca4ca3bcc3169f9633a40cdfc1633d48428c60e53e999641e252b640767d85b6b8db3117
7
- data.tar.gz: b51d4ad91623b2357492837a37d1f0f03928e4a2e526849afe4cd558987089fab2a930233065d1230e6dd82c70c6c0341435c0fbbf7f9a467953480e09ec99c4
6
+ metadata.gz: 9a55ef1b2043b4950a617ffa984a01a410a2aea17d656072c4732a995d7dcff550b38437a60ad382b9f30f9b87a2541064597ccb40c3e70043cf38f2cb77638e
7
+ data.tar.gz: ef38056726cf8956480bf728150168a1d2dd1337b5987b9ce6845c771c05f1c53fc38d84d92bab4c8fa015e3069ddfb141f548eee6d68b051417608a9dd2cc23
data/.gems CHANGED
@@ -1,4 +1,5 @@
1
- cutest -v 1.2.1
2
1
  msgpack -v 0.5.8
3
2
  nido -v 0.0.1
4
- redic -v 1.1.0
3
+ redic -v 1.3.0
4
+ cutest -v 1.2.2
5
+ stal -v 0.1.0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 2.2.0
2
+
3
+ - Use Stal for set operations
4
+
5
+ ## 2.1.0
6
+
7
+ - Add `combine` filter
8
+
1
9
  ## 2.0.0
2
10
 
3
11
  - Lists now respond to range.
@@ -228,6 +236,10 @@
228
236
  [scrivener]: https://github.com/soveran/scrivener
229
237
  [redic]: https://github.com/amakawa/redic
230
238
 
239
+ ## 1.4.0
240
+
241
+ - Add `combine` filter
242
+
231
243
  ## 1.3.2
232
244
 
233
245
  - Fetching a batch of objects is now done in batches of 1000 objects at
@@ -29,18 +29,18 @@ class User < Ohm::Model
29
29
  # Because a `User` literally has a `list` of activities, using a Redis
30
30
  # `list` to model the activities would be a good choice. We default to
31
31
  # getting the first 100 activities, and use
32
- # [lrange](http://code.google.com/p/redis/wiki/LrangeCommand) directly.
32
+ # [lrange](http://redis.io/commands/lrange) directly.
33
33
  def activities(start = 0, limit = 100)
34
- key[:activities].lrange(start, start + limit)
34
+ redis.call 'LRANGE', key[:activities], start, start + limit
35
35
  end
36
36
 
37
37
  # Broadcasting a message to all the `followers` of a user would simply
38
38
  # be prepending the message for each if his `followers`. We also use
39
39
  # the Redis command
40
- # [lpush](http://code.google.com/p/redis/wiki/RpushCommand) directly.
40
+ # [lpush](http://redis.io/commands/lpush) directly.
41
41
  def broadcast(str)
42
42
  followers.each do |user|
43
- user.key[:activities].lpush(str)
43
+ redis.call 'LPUSH', user.key[:activities], str
44
44
  end
45
45
  end
46
46
 
@@ -81,8 +81,8 @@ end
81
81
  test "jane following john" do |john, jane|
82
82
  jane.follow(john)
83
83
 
84
- assert [john] == jane.following.to_a
85
- assert [jane] == john.followers.to_a
84
+ assert_equal [john], jane.following.to_a
85
+ assert_equal [jane], john.followers.to_a
86
86
  end
87
87
 
88
88
  # Broadcasting a message should simply notify all the followers of the
@@ -125,17 +125,12 @@ class User
125
125
  # We define a constant where we set the maximum number of activity entries.
126
126
  MAX = 10
127
127
 
128
- # Using `MAX` as the reference, we check if the number of activities exceeds
129
- # `MAX`, and use
130
- # [ltrim](http://code.google.com/p/redis/wiki/LtrimCommand) to truncate
131
- # the activities.
128
+ # Using `MAX` as the reference, we truncate the activities feed using
129
+ # [ltrim](http://redis.io/commands/ltrim).
132
130
  def broadcast(str)
133
131
  followers.each do |user|
134
- user.key[:activities].lpush(str)
135
-
136
- if user.key[:activities].llen > MAX
137
- user.key[:activities].ltrim(0, MAX - 1)
138
- end
132
+ redis.call 'LPUSH', user.key[:activities], str
133
+ redis.call 'LTRIM', user.key[:activities], 0, MAX - 1
139
134
  end
140
135
  end
141
136
  end
@@ -158,5 +153,5 @@ end
158
153
  #
159
154
  # As a final note, keep in mind that the Ohm solution would still need
160
155
  # sharding for large datasets, but that would be again trivial to implement
161
- # using [redis-rb](http://github.com/ezmobius/redis-rb)'s distributed support
156
+ # using [redis-rb](http://github.com/redis/redis-rb)'s distributed support
162
157
  # and sharding it against the *user_id*.
@@ -29,11 +29,11 @@ require "ohm"
29
29
 
30
30
  # We define both a `Video` and `Audio` model, with a `list` of *comments*.
31
31
  class Video < Ohm::Model
32
- list :comments, Comment
32
+ list :comments, :Comment
33
33
  end
34
34
 
35
35
  class Audio < Ohm::Model
36
- list :comments, Comment
36
+ list :comments, :Comment
37
37
  end
38
38
 
39
39
  # The `Comment` model for this example will just contain one attribute called
@@ -65,10 +65,10 @@ test "adding all sorts of comments" do
65
65
  audio.comments.push(audio_comment)
66
66
 
67
67
  assert video.comments.include?(video_comment)
68
- assert video.comments.size == 1
68
+ assert_equal video.comments.size, 1
69
69
 
70
70
  assert audio.comments.include?(audio_comment)
71
- assert audio.comments.size == 1
71
+ assert_equal audio.comments.size, 1
72
72
  end
73
73
 
74
74
 
@@ -100,14 +100,8 @@ test "getting paged chunks of comments" do
100
100
 
101
101
  20.times { |i| video.comments.push(Comment.create(:body => "C#{i + 1}")) }
102
102
 
103
- assert %w(C1 C2 C3 C4 C5) == video.comments[0, 4].map(&:body)
104
- assert %w(C6 C7 C8 C9 C10) == video.comments[5, 9].map(&:body)
105
-
106
- # ** Range style is also supported.
107
- assert %w(C11 C12 C13 C14 C15) == video.comments[10..14].map(&:body)
108
-
109
- # ** Also you can just pass in a single number.
110
- assert "C16" == video.comments[15].body
103
+ assert_equal %w(C1 C2 C3 C4 C5), video.comments.range(0, 4).map(&:body)
104
+ assert_equal %w(C6 C7 C8 C9 C10), video.comments.range(5, 9).map(&:body)
111
105
  end
112
106
 
113
107
  #### Caveats
@@ -121,4 +115,4 @@ end
121
115
  # `SORTED SET`, and to use the timestamp (or the negative of the timestamp) as
122
116
  # the score to maintain the desired order. Deleting a comment from a
123
117
  # `SORTED SET` would be a simple
124
- # [ZREM](http://code.google.com/p/redis/wiki/ZremCommand) call.
118
+ # [ZREM](http://redis.io/commands/zrem) call.
data/lib/ohm.rb CHANGED
@@ -3,8 +3,7 @@
3
3
  require "msgpack"
4
4
  require "nido"
5
5
  require "redic"
6
- require "securerandom"
7
- require_relative "ohm/command"
6
+ require "stal"
8
7
 
9
8
  module Ohm
10
9
  LUA_CACHE = Hash.new { |h, k| h[k] = Hash.new }
@@ -76,7 +75,7 @@ module Ohm
76
75
  Hash[*arr]
77
76
  end
78
77
 
79
- def self.sort(redis, key, options)
78
+ def self.sort_options(options)
80
79
  args = []
81
80
 
82
81
  args.concat(["BY", options[:by]]) if options[:by]
@@ -85,7 +84,7 @@ module Ohm
85
84
  args.concat(options[:order].split(" ")) if options[:order]
86
85
  args.concat(["STORE", options[:store]]) if options[:store]
87
86
 
88
- redis.call("SORT", key, *args)
87
+ return args
89
88
  end
90
89
  end
91
90
 
@@ -285,6 +284,7 @@ module Ohm
285
284
  # # => true
286
285
  #
287
286
  def delete(model)
287
+
288
288
  # LREM key 0 <id> means remove all elements matching <id>
289
289
  # @see http://redis.io/commands/lrem
290
290
  redis.call("LREM", key, 0, model.id)
@@ -321,27 +321,103 @@ module Ohm
321
321
  end
322
322
  end
323
323
 
324
- # Defines most of the methods used by `Set` and `MultiSet`.
325
- class BasicSet
324
+ class Set
326
325
  include Collection
327
326
 
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.
327
+ attr :key
328
+ attr :model
329
+ attr :namespace
330
+
331
+ def initialize(model, namespace, key)
332
+ @model = model
333
+ @namespace = namespace
334
+ @key = key
335
+ end
336
+
337
+ # Retrieve a specific element using an ID from this set.
338
+ #
339
+ # Example:
340
+ #
341
+ # # Let's say we got the ID 1 from a request parameter.
342
+ # id = 1
343
+ #
344
+ # # Retrieve the post if it's included in the user's posts.
345
+ # post = user.posts[id]
346
+ #
347
+ def [](id)
348
+ model[id] if exists?(id)
349
+ end
350
+
351
+ # Returns an array with all the ID's of the set.
352
+ #
353
+ # class Post < Ohm::Model
354
+ # end
330
355
  #
331
356
  # class User < Ohm::Model
332
357
  # attribute :name
358
+ # index :name
359
+ #
360
+ # set :posts, :Post
333
361
  # end
334
362
  #
335
- # User.all.sort_by(:name, :order => "ALPHA")
336
- # User.all.sort_by(:name, :order => "ALPHA DESC")
337
- # User.all.sort_by(:name, :order => "ALPHA DESC", :limit => [0, 10])
363
+ # User.create(name: "John")
364
+ # User.create(name: "Jane")
338
365
  #
339
- # Note: This is slower compared to just doing `sort`, specifically
340
- # because Redis has to read each individual hash in order to sort
341
- # them.
366
+ # User.all.ids
367
+ # # => ["1", "2"]
342
368
  #
343
- def sort_by(att, options = {})
344
- sort(options.merge(:by => to_key(att)))
369
+ # User.find(name: "John").union(name: "Jane").ids
370
+ # # => ["1", "2"]
371
+ #
372
+ def ids
373
+ if Array === key
374
+ Stal.solve(redis, key)
375
+ else
376
+ redis.call("SMEMBERS", key)
377
+ end
378
+ end
379
+
380
+ # Returns the total size of the set using SCARD.
381
+ def size
382
+ Stal.solve(redis, ["SCARD", key])
383
+ end
384
+
385
+ # Returns +true+ if +id+ is included in the set. Otherwise, returns +false+.
386
+ #
387
+ # Example:
388
+ #
389
+ # class Post < Ohm::Model
390
+ # end
391
+ #
392
+ # class User < Ohm::Model
393
+ # set :posts, :Post
394
+ # end
395
+ #
396
+ # user = User.create
397
+ # post = Post.create
398
+ # user.posts.add(post)
399
+ #
400
+ # user.posts.exists?('nonexistent') # => false
401
+ # user.posts.exists?(post.id) # => true
402
+ #
403
+ def exists?(id)
404
+ Stal.solve(redis, ["SISMEMBER", key, id]) == 1
405
+ end
406
+
407
+ # Check if a model is included in this set.
408
+ #
409
+ # Example:
410
+ #
411
+ # u = User.create
412
+ #
413
+ # User.all.include?(u)
414
+ # # => true
415
+ #
416
+ # Note: Ohm simply checks that the model's ID is included in the
417
+ # set. It doesn't do any form of type checking.
418
+ #
419
+ def include?(model)
420
+ exists?(model.id)
345
421
  end
346
422
 
347
423
  # Allows you to sort your models using their IDs. This is much
@@ -370,31 +446,30 @@ module Ohm
370
446
  def sort(options = {})
371
447
  if options.has_key?(:get)
372
448
  options[:get] = to_key(options[:get])
373
- return execute { |key| Utils.sort(redis, key, options) }
374
- end
375
449
 
376
- fetch(execute { |key| Utils.sort(redis, key, options) })
450
+ Stal.solve(redis, ["SORT", key, *Utils.sort_options(options)])
451
+ else
452
+ fetch(Stal.solve(redis, ["SORT", key, *Utils.sort_options(options)]))
453
+ end
377
454
  end
378
455
 
379
- # Check if a model is included in this set.
380
- #
381
- # Example:
456
+ # Allows you to sort by any attribute in the hash, this doesn't include
457
+ # the +id+. If you want to sort by ID, use #sort.
382
458
  #
383
- # u = User.create
459
+ # class User < Ohm::Model
460
+ # attribute :name
461
+ # end
384
462
  #
385
- # User.all.include?(u)
386
- # # => true
463
+ # User.all.sort_by(:name, :order => "ALPHA")
464
+ # User.all.sort_by(:name, :order => "ALPHA DESC")
465
+ # User.all.sort_by(:name, :order => "ALPHA DESC", :limit => [0, 10])
387
466
  #
388
- # Note: Ohm simply checks that the model's ID is included in the
389
- # set. It doesn't do any form of type checking.
467
+ # Note: This is slower compared to just doing `sort`, specifically
468
+ # because Redis has to read each individual hash in order to sort
469
+ # them.
390
470
  #
391
- def include?(model)
392
- exists?(model.id)
393
- end
394
-
395
- # Returns the total size of the set using SCARD.
396
- def size
397
- execute { |key| redis.call("SCARD", key) }
471
+ def sort_by(att, options = {})
472
+ sort(options.merge(:by => to_key(att)))
398
473
  end
399
474
 
400
475
  # Syntactic sugar for `sort_by` or `sort` when you only need the
@@ -419,88 +494,6 @@ module Ohm
419
494
  end
420
495
  end
421
496
 
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
- #
443
- def ids
444
- execute { |key| redis.call("SMEMBERS", key) }
445
- end
446
-
447
- # Retrieve a specific element using an ID from this set.
448
- #
449
- # Example:
450
- #
451
- # # Let's say we got the ID 1 from a request parameter.
452
- # id = 1
453
- #
454
- # # Retrieve the post if it's included in the user's posts.
455
- # post = user.posts[id]
456
- #
457
- def [](id)
458
- model[id] if exists?(id)
459
- end
460
-
461
- # Returns +true+ if +id+ is included in the set. Otherwise, returns +false+.
462
- #
463
- # Example:
464
- #
465
- # class Post < Ohm::Model
466
- # end
467
- #
468
- # class User < Ohm::Model
469
- # set :posts, :Post
470
- # end
471
- #
472
- # user = User.create
473
- # post = Post.create
474
- # user.posts.add(post)
475
- #
476
- # user.posts.exists?('nonexistent') # => false
477
- # user.posts.exists?(post.id) # => true
478
- #
479
- def exists?(id)
480
- execute { |key| redis.call("SISMEMBER", key, id) == 1 }
481
- end
482
-
483
- private
484
- def to_key(att)
485
- if model.counters.include?(att)
486
- namespace["*:counters->%s" % att]
487
- else
488
- namespace["*->%s" % att]
489
- end
490
- end
491
- end
492
-
493
- class Set < BasicSet
494
- attr :key
495
- attr :namespace
496
- attr :model
497
-
498
- def initialize(key, namespace, model)
499
- @key = key
500
- @namespace = namespace
501
- @model = model
502
- end
503
-
504
497
  # Chain new fiters on an existing set.
505
498
  #
506
499
  # Example:
@@ -509,8 +502,8 @@ module Ohm
509
502
  # set.find(:age => 30)
510
503
  #
511
504
  def find(dict)
512
- MultiSet.new(
513
- namespace, model, Command[:sinterstore, key, *model.filters(dict)]
505
+ Ohm::Set.new(
506
+ model, namespace, [:SINTER, key, *model.filters(dict)]
514
507
  )
515
508
  end
516
509
 
@@ -525,7 +518,9 @@ module Ohm
525
518
  # User.find(:name => "John").except(:country => "US")
526
519
  #
527
520
  def except(dict)
528
- MultiSet.new(namespace, model, key).except(dict)
521
+ Ohm::Set.new(
522
+ model, namespace, [:SDIFF, key, [:SUNION, *model.filters(dict)]]
523
+ )
529
524
  end
530
525
 
531
526
  # Perform an intersection between the existent set and
@@ -539,7 +534,9 @@ module Ohm
539
534
  # # The result will include all users with active status
540
535
  # # and with names "John" or "Jane".
541
536
  def combine(dict)
542
- MultiSet.new(namespace, model, key).combine(dict)
537
+ Ohm::Set.new(
538
+ model, namespace, [:SINTER, key, [:SUNION, *model.filters(dict)]]
539
+ )
543
540
  end
544
541
 
545
542
  # Do a union to the existing set using any number of filters.
@@ -553,12 +550,18 @@ module Ohm
553
550
  # User.find(:name => "John").union(:name => "Jane")
554
551
  #
555
552
  def union(dict)
556
- MultiSet.new(namespace, model, key).union(dict)
553
+ Ohm::Set.new(
554
+ model, namespace, [:SUNION, key, [:SINTER, *model.filters(dict)]]
555
+ )
557
556
  end
558
557
 
559
558
  private
560
- def execute
561
- yield key
559
+ def to_key(att)
560
+ if model.counters.include?(att)
561
+ namespace["*:counters->%s" % att]
562
+ else
563
+ namespace["*->%s" % att]
564
+ end
562
565
  end
563
566
 
564
567
  def redis
@@ -567,6 +570,7 @@ module Ohm
567
570
  end
568
571
 
569
572
  class MutableSet < Set
573
+
570
574
  # Add a model directly to the set.
571
575
  #
572
576
  # Example:
@@ -624,128 +628,6 @@ module Ohm
624
628
  end
625
629
  end
626
630
 
627
- # Anytime you filter a set with more than one requirement, you
628
- # internally use a `MultiSet`. `MultiSet` is a bit slower than just
629
- # a `Set` because it has to `SINTERSTORE` all the keys prior to
630
- # retrieving the members, size, etc.
631
- #
632
- # Example:
633
- #
634
- # User.all.kind_of?(Ohm::Set)
635
- # # => true
636
- #
637
- # User.find(:name => "John").kind_of?(Ohm::Set)
638
- # # => true
639
- #
640
- # User.find(:name => "John", :age => 30).kind_of?(Ohm::MultiSet)
641
- # # => true
642
- #
643
- class MultiSet < BasicSet
644
- attr :namespace
645
- attr :model
646
- attr :command
647
-
648
- def initialize(namespace, model, command)
649
- @namespace = namespace
650
- @model = model
651
- @command = command
652
- end
653
-
654
- # Chain new fiters on an existing set.
655
- #
656
- # Example:
657
- #
658
- # set = User.find(:name => "John", :age => 30)
659
- # set.find(:status => 'pending')
660
- #
661
- def find(dict)
662
- MultiSet.new(
663
- namespace, model, Command[:sinterstore, command, intersected(dict)]
664
- )
665
- end
666
-
667
- # Reduce the set using any number of filters.
668
- #
669
- # Example:
670
- #
671
- # set = User.find(:name => "John")
672
- # set.except(:country => "US")
673
- #
674
- # # You can also do it in one line.
675
- # User.find(:name => "John").except(:country => "US")
676
- #
677
- def except(dict)
678
- MultiSet.new(
679
- namespace, model, Command[:sdiffstore, command, unioned(dict)]
680
- )
681
- end
682
-
683
- # Perform an intersection between the existent set and
684
- # the new set created by the union of the passed filters.
685
- #
686
- # Example:
687
- #
688
- # set = User.find(:status => "active")
689
- # set.combine(:name => ["John", "Jane"])
690
- #
691
- # # The result will include all users with active status
692
- # # and with names "John" or "Jane".
693
- def combine(dict)
694
- MultiSet.new(
695
- namespace, model, Command[:sinterstore, command, unioned(dict)]
696
- )
697
- end
698
-
699
- # Do a union to the existing set using any number of filters.
700
- #
701
- # Example:
702
- #
703
- # set = User.find(:name => "John")
704
- # set.union(:name => "Jane")
705
- #
706
- # # You can also do it in one line.
707
- # User.find(:name => "John").union(:name => "Jane")
708
- #
709
- def union(dict)
710
- MultiSet.new(
711
- namespace, model, Command[:sunionstore, command, intersected(dict)]
712
- )
713
- end
714
-
715
- private
716
- def redis
717
- model.redis
718
- end
719
-
720
- def intersected(dict)
721
- Command[:sinterstore, *model.filters(dict)]
722
- end
723
-
724
- def unioned(dict)
725
- Command[:sunionstore, *model.filters(dict)]
726
- end
727
-
728
- def execute
729
- # namespace[:tmp] is where all the temp keys should be stored in.
730
- # redis will be where all the commands are executed against.
731
- response = command.call(namespace[:tmp], redis)
732
-
733
- begin
734
-
735
- # At this point, we have the final aggregated set, which we yield
736
- # to the caller. the caller can do all the normal set operations,
737
- # i.e. SCARD, SMEMBERS, etc.
738
- yield response
739
-
740
- ensure
741
-
742
- # We have to make sure we clean up the temporary keys to avoid
743
- # memory leaks and the unintended explosion of memory usage.
744
- command.clean
745
- end
746
- end
747
- end
748
-
749
631
  # The base class for all your models. In order to better understand
750
632
  # it, here is a semi-realtime explanation of the details involved
751
633
  # when creating a User instance.
@@ -927,9 +809,9 @@ module Ohm
927
809
  keys = filters(dict)
928
810
 
929
811
  if keys.size == 1
930
- Ohm::Set.new(keys.first, key, self)
812
+ Ohm::Set.new(self, key, keys.first)
931
813
  else
932
- Ohm::MultiSet.new(key, self, Command.new(:sinterstore, *keys))
814
+ Ohm::Set.new(self, key, [:SINTER, *keys])
933
815
  end
934
816
  end
935
817
 
@@ -980,7 +862,7 @@ module Ohm
980
862
  define_method name do
981
863
  model = Utils.const(self.class, model)
982
864
 
983
- Ohm::MutableSet.new(key[name], model.key, model)
865
+ Ohm::MutableSet.new(model, model.key, key[name])
984
866
  end
985
867
  end
986
868
 
@@ -1190,7 +1072,7 @@ module Ohm
1190
1072
 
1191
1073
  # An Ohm::Set wrapper for Model.key[:all].
1192
1074
  def self.all
1193
- Set.new(key[:all], key, self)
1075
+ Ohm::Set.new(self, key, key[:all])
1194
1076
  end
1195
1077
 
1196
1078
  # Syntactic sugar for Model.new(atts).save
data/makefile CHANGED
@@ -1,4 +1,9 @@
1
- .PHONY: test
1
+ .PHONY: all test examples
2
+
3
+ all: test
2
4
 
3
5
  test:
4
6
  cutest -r ./test/helper.rb ./test/*.rb
7
+
8
+ examples:
9
+ RUBYLIB="./lib" cutest ./examples/*.rb
data/ohm.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "ohm"
3
- s.version = "2.1.0"
3
+ s.version = "2.2.0"
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"]
@@ -14,6 +14,7 @@ Gem::Specification.new do |s|
14
14
 
15
15
  s.add_dependency "redic"
16
16
  s.add_dependency "nido"
17
+ s.add_dependency "stal"
17
18
  s.add_dependency "msgpack"
18
19
 
19
20
  s.add_development_dependency "cutest"
data/test/indices.rb CHANGED
@@ -54,12 +54,6 @@ test "avoid intersections with the all collection" do
54
54
  assert_equal "User:indices:email:foo", User.find(:email => "foo").key
55
55
  end
56
56
 
57
- test "cleanup the temporary key after use" do
58
- assert User.find(:email => "foo", :activation_code => "bar").to_a
59
-
60
- assert Ohm.redis.call("KEYS", "User:temp:*").empty?
61
- end
62
-
63
57
  test "allow multiple chained finds" do
64
58
  assert 1 == User.find(:email => "foo").find(:activation_code => "bar").find(:update => "baz").size
65
59
  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: 2.1.0
4
+ version: 2.2.0
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: 2015-01-22 00:00:00.000000000 Z
13
+ date: 2015-03-03 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: redic
@@ -40,6 +40,20 @@ dependencies:
40
40
  - - '>='
41
41
  - !ruby/object:Gem::Version
42
42
  version: '0'
43
+ - !ruby/object:Gem::Dependency
44
+ name: stal
45
+ requirement: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ type: :runtime
51
+ prerelease: false
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - '>='
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
43
57
  - !ruby/object:Gem::Dependency
44
58
  name: msgpack
45
59
  requirement: !ruby/object:Gem::Requirement
@@ -95,14 +109,12 @@ files:
95
109
  - examples/slug.rb
96
110
  - examples/tagging.rb
97
111
  - lib/ohm.rb
98
- - lib/ohm/command.rb
99
112
  - lib/ohm/json.rb
100
113
  - lib/ohm/lua/delete.lua
101
114
  - lib/ohm/lua/save.lua
102
115
  - makefile
103
116
  - ohm.gemspec
104
117
  - test/association.rb
105
- - test/command.rb
106
118
  - test/connection.rb
107
119
  - test/core.rb
108
120
  - test/counters.rb
@@ -143,4 +155,3 @@ signing_key:
143
155
  specification_version: 4
144
156
  summary: Object-hash mapping library for Redis.
145
157
  test_files: []
146
- has_rdoc:
data/lib/ohm/command.rb DELETED
@@ -1,51 +0,0 @@
1
- module Ohm
2
- class Command
3
- def self.[](operation, head, *tail)
4
- return head if tail.empty?
5
-
6
- new(operation, head, *tail)
7
- end
8
-
9
- attr :operation
10
- attr :args
11
- attr :keys
12
-
13
- def initialize(operation, *args)
14
- @operation = operation
15
- @args = args
16
- @keys = []
17
- end
18
-
19
- def call(nido, redis)
20
- newkey(nido, redis) do |key|
21
- redis.call(@operation, key, *params(nido, redis))
22
- end
23
- end
24
-
25
- def clean
26
- keys.each do |key, redis|
27
- redis.call("DEL", key)
28
- end
29
-
30
- subcommands.each { |cmd| cmd.clean }
31
- end
32
-
33
- private
34
- def subcommands
35
- args.select { |arg| arg.respond_to?(:call) }
36
- end
37
-
38
- def params(nido, redis)
39
- args.map { |arg| arg.respond_to?(:call) ? arg.call(nido, redis) : arg }
40
- end
41
-
42
- def newkey(nido, redis)
43
- key = nido[SecureRandom.hex(32)]
44
- keys << [key, redis]
45
-
46
- yield key
47
-
48
- return key
49
- end
50
- end
51
- end
data/test/command.rb DELETED
@@ -1,55 +0,0 @@
1
- require_relative "helper"
2
-
3
- scope do
4
- setup do
5
- redis = Redic.new
6
- redis.call("FLUSHDB")
7
-
8
- nido = Nido.new("User:tmp")
9
-
10
- [1, 2, 3].each { |i| redis.call("SADD", "A", i) }
11
- [1, 4, 5].each { |i| redis.call("SADD", "B", i) }
12
-
13
- [10, 11, 12].each { |i| redis.call("SADD", "C", i) }
14
- [11, 12, 13].each { |i| redis.call("SADD", "D", i) }
15
- [12, 13, 14].each { |i| redis.call("SADD", "E", i) }
16
-
17
- [10, 11, 12].each { |i| redis.call("SADD", "F", i) }
18
- [11, 12, 13].each { |i| redis.call("SADD", "G", i) }
19
- [12, 13, 14].each { |i| redis.call("SADD", "H", i) }
20
-
21
- [redis, nido]
22
- end
23
-
24
- test "special condition: single argument returns that arg" do
25
- assert_equal "A", Ohm::Command[:sinterstore, "A"]
26
- end
27
-
28
- test "full stack test" do |redis, nido|
29
- cmd1 = Ohm::Command[:sinterstore, "A", "B"]
30
-
31
- res = cmd1.call(nido, redis)
32
- assert_equal ["1"], redis.call("SMEMBERS", res)
33
-
34
- cmd1.clean
35
- assert_equal 0, redis.call("EXISTS", res)
36
-
37
- cmd2 = Ohm::Command[:sinterstore, "C", "D", "E"]
38
- cmd3 = Ohm::Command[:sunionstore, cmd1, cmd2]
39
-
40
- res = cmd3.call(nido, redis)
41
- assert_equal ["1", "12"], redis.call("SMEMBERS", res)
42
-
43
- cmd3.clean
44
- assert redis.call("KEYS", nido["*"]).empty?
45
-
46
- cmd4 = Ohm::Command[:sinterstore, "F", "G", "H"]
47
- cmd5 = Ohm::Command[:sdiffstore, cmd3, cmd4]
48
-
49
- res = cmd5.call(nido, redis)
50
- assert_equal ["1"], redis.call("SMEMBERS", res)
51
-
52
- cmd5.clean
53
- assert redis.call("KEYS", nido["*"]).empty?
54
- end
55
- end