em-bucketer 0.1.1 → 0.2.0
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 +4 -4
- data/README.md +37 -1
- data/lib/em-bucketer/base.rb +1 -3
- data/lib/em-bucketer/ordered.rb +8 -0
- data/lib/em-bucketer/ordered/base.rb +191 -0
- data/lib/em-bucketer/ordered/database.rb +6 -0
- data/lib/em-bucketer/ordered/database/hash.rb +64 -0
- data/lib/em-bucketer/ordered/in_memory.rb +24 -0
- data/lib/em-bucketer/version.rb +1 -1
- data/spec/em_bucketer_ordered_examples.rb +133 -0
- data/spec/in_memory_ordered_spec.rb +8 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/spec_methods.rb +9 -0
- metadata +10 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa43207fc878f4d9f0f15851590ec66803f45694
|
4
|
+
data.tar.gz: 9cd15644641ffccdd96552f45bbc5b420de5a262
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b4ee20c2e7ad8cb933b5a0de2dfea6cd9b05ee7375cd156ea8659feda615890e8a6d52490e63dafb6d71e44b992eb33b066889b207b21efe693862fcff19fd7
|
7
|
+
data.tar.gz: 96447882b8d6cdf6a20dc62a25f69af698de3708eb523735fcec40ae503edab3237b919ba72aa69ae9861d2350e7ec9b3a0110383eb5e857db439ed075e44a0d
|
data/README.md
CHANGED
@@ -21,7 +21,43 @@ Or install it yourself as:
|
|
21
21
|
|
22
22
|
$ gem install em-bucketer
|
23
23
|
|
24
|
-
##
|
24
|
+
## Ordered Bucketer
|
25
|
+
The ordered bucketer adds items to buckets and gives them back in the same
|
26
|
+
order in which they were put in.
|
27
|
+
|
28
|
+
### Usage
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require 'em-bucketer'
|
32
|
+
EM.run do
|
33
|
+
bucketer = EM::Bucketer::Ordered::InMemory.new(:bucket_threshold_size => 5)
|
34
|
+
|
35
|
+
bucketer.on_bucket_full do |bucket_id|
|
36
|
+
p "yay bucket #{bucket_id} filled up!"
|
37
|
+
|
38
|
+
bucketer.pop_all(bucket_id) do |items|
|
39
|
+
EM.stop
|
40
|
+
items.each do |item|
|
41
|
+
p "got back #{item}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
bucketer.add_item("1", {:foo => :bar})
|
47
|
+
bucketer.add_item("1", {:foo => :bar})
|
48
|
+
bucketer.add_item("1", {:foo => :bar})
|
49
|
+
bucketer.add_item("1", {:bar => :foo})
|
50
|
+
bucketer.add_item("1", {:bar => :foo})
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
## Unordered Bucketer
|
55
|
+
The unordered bucketer requires you to pass in an 'id' which is used to ensure
|
56
|
+
that no duplicates occur. This bucketer type should be used if you want to not
|
57
|
+
have two of the same item in a bucket at one time. This type of bucketer does
|
58
|
+
not guarantee that you get back items in the same order that they went in.
|
59
|
+
|
60
|
+
### Usage
|
25
61
|
|
26
62
|
```ruby
|
27
63
|
require 'em-bucketer'
|
data/lib/em-bucketer/base.rb
CHANGED
@@ -153,11 +153,9 @@ module EventMachine::Bucketer
|
|
153
153
|
private
|
154
154
|
|
155
155
|
def get_and_remove_iterator(bucket_id, count, values, completion)
|
156
|
-
added = 0
|
157
156
|
proc do |tuple, iter|
|
158
157
|
key, val = tuple[0], tuple[1]
|
159
|
-
if
|
160
|
-
added += 1
|
158
|
+
if values.count < count
|
161
159
|
values << val
|
162
160
|
iter.next
|
163
161
|
else
|
@@ -0,0 +1,191 @@
|
|
1
|
+
module EventMachine::Bucketer
|
2
|
+
module Ordered::Base
|
3
|
+
def setup(bucket_threshold_size, bucket_max_age)
|
4
|
+
@bucket_threshold_size = bucket_threshold_size
|
5
|
+
@bucket_max_age = bucket_max_age
|
6
|
+
@buckets = {}
|
7
|
+
@on_bucket_full_callbacks = []
|
8
|
+
@on_bucket_timeout_callbacks = []
|
9
|
+
@timers = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
# Adds a item to the specified bucket and
|
13
|
+
# calls the block when it is done
|
14
|
+
#
|
15
|
+
# @param bucket_id [String] the bucket id of
|
16
|
+
# the bucket to put the item in
|
17
|
+
# @param item [Object] the item to be
|
18
|
+
# placed in the bucket
|
19
|
+
def add_item(bucket_id, item, &blk)
|
20
|
+
add_timer_if_first(bucket_id)
|
21
|
+
EM::Completion.new.tap do |c|
|
22
|
+
c.callback(&blk) if block_given?
|
23
|
+
add_item_to_db(bucket_id, item).callback do
|
24
|
+
c.succeed
|
25
|
+
check_bucket_full(bucket_id)
|
26
|
+
end.errback do |e|
|
27
|
+
c.fail e
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Get at most `count` items back from a
|
33
|
+
# specific bucket and remove them from
|
34
|
+
# the bucket. These should be the first
|
35
|
+
# `count` items you added to the bucket
|
36
|
+
# that have not yet been removed from the
|
37
|
+
# bucket.
|
38
|
+
#
|
39
|
+
# @param bucket_id [String] the bucket id
|
40
|
+
# you want the items from
|
41
|
+
# @param count [Integer] the number of
|
42
|
+
# items you want from the bucket
|
43
|
+
# @yield [Array] the first `count`
|
44
|
+
# items in the bucket
|
45
|
+
def pop_count(bucket_id, count, reset_timer: true, &blk)
|
46
|
+
EM::Completion.new.tap do |c|
|
47
|
+
c.callback(&blk) if block_given?
|
48
|
+
pop_count_from_db(bucket_id, count, &blk).callback do |items|
|
49
|
+
reset_timer(bucket_id) if reset_timer
|
50
|
+
c.succeed items
|
51
|
+
end.errback do |e|
|
52
|
+
c.fail e
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Get all items back from a specific bucket
|
58
|
+
# and remove them from the bucket.
|
59
|
+
#
|
60
|
+
# @param bucket_id [String] the bucket id
|
61
|
+
# you want the items from
|
62
|
+
# @yield [Array] all items in the bucket
|
63
|
+
def pop_all(bucket_id, &blk)
|
64
|
+
clear_timer(bucket_id)
|
65
|
+
EM::Completion.new.tap do |c|
|
66
|
+
c.callback(&blk) if block_given?
|
67
|
+
pop_all_from_db(bucket_id, &blk).callback do |items|
|
68
|
+
c.succeed items
|
69
|
+
end.errback do |e|
|
70
|
+
c.fail e
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Used to set a callback hook for when a bucket
|
76
|
+
# reaches the threshold size. It is IMPORTANT
|
77
|
+
# to note that the bucket will not automatically
|
78
|
+
# be emptied you must call empty_bucket if you
|
79
|
+
# want the bucket to be emptied. Also the callback
|
80
|
+
# will be called every time a item is added
|
81
|
+
# until the bucket is emptied.
|
82
|
+
#
|
83
|
+
# @yield [String] The bucket id of the full bucket
|
84
|
+
def on_bucket_full(&blk)
|
85
|
+
@on_bucket_full_callbacks << blk
|
86
|
+
end
|
87
|
+
|
88
|
+
# Used to set a callback hook for when a bucket
|
89
|
+
# reaches the time limit. It is IMPORTANT
|
90
|
+
# to note that the bucket will not automatically
|
91
|
+
# be emptied you must call empty_bucket if you
|
92
|
+
# want the bucket to be emptied.
|
93
|
+
#
|
94
|
+
# This timer is started once the bucket gets its
|
95
|
+
# first item and is cleared only when the
|
96
|
+
# bucket is emptied. The callback will only be
|
97
|
+
# called once at this time and then not again
|
98
|
+
# unless you empty the bucket and add something
|
99
|
+
# again.
|
100
|
+
#
|
101
|
+
# @yield [String] The bucket id of the full bucket
|
102
|
+
def on_bucket_timeout(&blk)
|
103
|
+
@on_bucket_timeout_callbacks << blk
|
104
|
+
end
|
105
|
+
|
106
|
+
# Get the contents of a bucket.
|
107
|
+
#
|
108
|
+
# @param bucket_id [String] the bucket id
|
109
|
+
# of the bucket you want to get
|
110
|
+
# @yield [Array] the items you put
|
111
|
+
# into the bucket
|
112
|
+
def get_bucket(bucket_id, &blk)
|
113
|
+
get_bucket_from_db(bucket_id, &blk)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Empty a bucket
|
117
|
+
#
|
118
|
+
# @param bucket_id [String] the bucket id
|
119
|
+
# of the bucket you want to empty
|
120
|
+
def empty_bucket(bucket_id, &blk)
|
121
|
+
EM::Completion.new.tap do |c|
|
122
|
+
c.callback(&blk) if block_given?
|
123
|
+
empty_bucket_in_db(bucket_id).callback do
|
124
|
+
clear_timer(bucket_id)
|
125
|
+
c.succeed
|
126
|
+
end.errback do |e|
|
127
|
+
c.fail e
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def get_and_remove_iterator(bucket_id, count, values, completion)
|
135
|
+
proc do |tuple, iter|
|
136
|
+
key, val = tuple[0], tuple[1]
|
137
|
+
if values.count < count
|
138
|
+
values << val
|
139
|
+
iter.next
|
140
|
+
else
|
141
|
+
add_item(bucket_id, key, val).callback do
|
142
|
+
iter.next
|
143
|
+
end.errback do |e|
|
144
|
+
completion.fail e
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def bucket_full?(bucket_id, &blk)
|
151
|
+
bucket_size_from_db(bucket_id).callback do |size|
|
152
|
+
blk.call size >= @bucket_threshold_size
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def check_bucket_full(bucket_id)
|
157
|
+
bucket_full?(bucket_id) do |is_full|
|
158
|
+
if is_full
|
159
|
+
@on_bucket_full_callbacks.each do |callback|
|
160
|
+
callback.call bucket_id
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def add_timer_if_first(bucket_id)
|
167
|
+
return unless @bucket_max_age
|
168
|
+
@timers[bucket_id] ||= EM::Timer.new(@bucket_max_age, timeout_callback(bucket_id))
|
169
|
+
end
|
170
|
+
|
171
|
+
def timeout_callback(bucket_id)
|
172
|
+
proc do |bar|
|
173
|
+
@on_bucket_timeout_callbacks.each do |callback|
|
174
|
+
callback.call bucket_id
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def clear_timer(bucket_id)
|
180
|
+
return unless @bucket_max_age
|
181
|
+
timer = @timers.delete(bucket_id)
|
182
|
+
timer.cancel if timer
|
183
|
+
end
|
184
|
+
|
185
|
+
def reset_timer(bucket_id)
|
186
|
+
return unless @bucket_max_age
|
187
|
+
clear_timer(bucket_id)
|
188
|
+
@timers[bucket_id] = EM::Timer.new(@bucket_max_age, timeout_callback(bucket_id))
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'em-bucketer/ordered/database'
|
2
|
+
|
3
|
+
module EventMachine::Bucketer
|
4
|
+
module Ordered
|
5
|
+
module Database
|
6
|
+
module Hash
|
7
|
+
private
|
8
|
+
|
9
|
+
def pop_all_from_db(bucket_id, &blk)
|
10
|
+
EM::Completion.new.tap do |c|
|
11
|
+
c.callback(&blk) if block_given?
|
12
|
+
all = bucket_by_id(bucket_id)
|
13
|
+
@buckets[bucket_id] = []
|
14
|
+
c.succeed all
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def pop_count_from_db(bucket_id, count, &blk)
|
19
|
+
EM::Completion.new.tap do |c|
|
20
|
+
c.callback(&blk) if block_given?
|
21
|
+
all = bucket_by_id(bucket_id)
|
22
|
+
result = all.first(count)
|
23
|
+
@buckets[bucket_id] = all[count..-1]
|
24
|
+
c.succeed result
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def bucket_size_from_db(bucket_id, &blk)
|
29
|
+
EM::Completion.new.tap do |c|
|
30
|
+
c.callback(&blk) if block_given?
|
31
|
+
c.succeed bucket_by_id(bucket_id).count
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def add_item_to_db(bucket_id, item, &blk)
|
36
|
+
EM::Completion.new.tap do |c|
|
37
|
+
c.callback(&blk) if block_given?
|
38
|
+
bucket_by_id(bucket_id) << item
|
39
|
+
c.succeed
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_bucket_from_db(bucket_id, &blk)
|
44
|
+
EM::Completion.new.tap do |c|
|
45
|
+
c.callback(&blk) if block_given?
|
46
|
+
c.succeed bucket_by_id(bucket_id)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def empty_bucket_in_db(bucket_id, &blk)
|
51
|
+
EM::Completion.new.tap do |c|
|
52
|
+
c.callback(&blk) if block_given?
|
53
|
+
@buckets[bucket_id] = []
|
54
|
+
c.succeed
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def bucket_by_id(bucket_id)
|
59
|
+
@buckets[bucket_id] ||= []
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'em-bucketer/ordered/database/hash'
|
3
|
+
require 'em-bucketer/ordered/base'
|
4
|
+
|
5
|
+
module EventMachine::Bucketer
|
6
|
+
class Ordered::InMemory
|
7
|
+
include Ordered::Database::Hash
|
8
|
+
include Ordered::Base
|
9
|
+
|
10
|
+
BUCKET_THRESHOLD_SIZE_DEFAULT = 1000
|
11
|
+
BUCKET_MAX_AGE_DEFAULT = 3600
|
12
|
+
|
13
|
+
# Creates a new in memory Bucketer with the requested
|
14
|
+
# configurations
|
15
|
+
#
|
16
|
+
# @param bucket_threshold_size [Integer] the max size of the bucket
|
17
|
+
# after which the on_bucket_full callback is called
|
18
|
+
# @param bucket_max_age [Integer] max number of seconds a bucket
|
19
|
+
# can remain before the on_bucket_timed_out is called
|
20
|
+
def initialize(bucket_threshold_size: BUCKET_THRESHOLD_SIZE_DEFAULT, bucket_max_age: BUCKET_MAX_AGE_DEFAULT)
|
21
|
+
setup(bucket_threshold_size, bucket_max_age)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/em-bucketer/version.rb
CHANGED
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'em-bucketer/ordered'
|
3
|
+
|
4
|
+
shared_examples "an ordered bucketer" do
|
5
|
+
describe '#add_item' do
|
6
|
+
it 'adds a item to the bucket' do
|
7
|
+
EM.run do
|
8
|
+
EM.add_timer(0.1) { fail "didn't reach EM.stop" }
|
9
|
+
bucketer.add_item("1", {:foo => :bar}) do
|
10
|
+
bucketer.get_bucket("1") do |bucket|
|
11
|
+
expect(bucket).to eq([{:foo => :bar}])
|
12
|
+
EM.stop
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'handles multiple buckets' do
|
19
|
+
EM.run do
|
20
|
+
EM.add_timer(0.1) { fail "didn't reach EM.stop" }
|
21
|
+
bucketer.on_bucket_full do |bucket_id|
|
22
|
+
fail "shouldn't have called full"
|
23
|
+
end
|
24
|
+
|
25
|
+
add_n_items_ordered(bucketer, "1", 3) do
|
26
|
+
add_n_items_ordered(bucketer, "2", 3) do
|
27
|
+
|
28
|
+
bucketer.get_bucket("1") do |bucket|
|
29
|
+
expect(bucket).to eq([{:id => 0}, {:id => 1}, {:id => 2}])
|
30
|
+
EM.stop
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'calls on_bucket_full when a bucket fills up' do
|
38
|
+
EM.run do
|
39
|
+
EM.add_timer(0.1) { fail "didn't reach EM.stop" }
|
40
|
+
bucketer.on_bucket_full do |bucket_id|
|
41
|
+
expect(bucket_id).to eq("1")
|
42
|
+
EM.stop
|
43
|
+
end
|
44
|
+
|
45
|
+
add_n_items_ordered(bucketer, "1", 5)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#empty_bucket' do
|
51
|
+
it 'emptys a bucket' do
|
52
|
+
EM.run do
|
53
|
+
EM.add_timer(0.1) { fail "didn't reach EM.stop" }
|
54
|
+
add_n_items_ordered(bucketer, "1", 3) do
|
55
|
+
bucketer.empty_bucket("1") do
|
56
|
+
bucketer.get_bucket("1") do |bucket|
|
57
|
+
expect(bucket).to eq([])
|
58
|
+
EM.stop
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#on_bucket_timeout' do
|
67
|
+
it 'calls the block when the timer times out' do
|
68
|
+
ran = false
|
69
|
+
EM.run do
|
70
|
+
EM.add_timer(0.05) { EM.stop }
|
71
|
+
# Stub out the timer that the bucketer uses
|
72
|
+
allow(EM).to receive(:add_timer) { |age, callback| callback.call }
|
73
|
+
bucketer.on_bucket_timeout do |bucket_id|
|
74
|
+
ran = true
|
75
|
+
expect(bucket_id).to eq("1")
|
76
|
+
end
|
77
|
+
bucketer.add_item("1", :foo => :bar)
|
78
|
+
end
|
79
|
+
fail "didn't call timeout" unless ran
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'doesnt call the block when the timer doesnt time out' do
|
83
|
+
EM.run do
|
84
|
+
EM.add_timer(0.1) { EM.stop }
|
85
|
+
allow(EM).to receive(:add_timer)
|
86
|
+
bucketer.on_bucket_timeout do |bucket_id|
|
87
|
+
fail "shouldn't have called timeout"
|
88
|
+
end
|
89
|
+
bucketer.add_item("1", :foo => :bar)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#pop_all' do
|
95
|
+
it 'gets and emptys the bucket' do
|
96
|
+
EM.run do
|
97
|
+
EM.add_timer(0.1) { fail "didn't reach EM.stop" }
|
98
|
+
add_n_items_ordered(bucketer, "1", 3) do
|
99
|
+
|
100
|
+
bucketer.pop_all("1") do |bucket|
|
101
|
+
expect(bucket).to eq([{:id => 0}, {:id => 1}, {:id => 2}])
|
102
|
+
|
103
|
+
bucketer.get_bucket("1") do |empty_bucket|
|
104
|
+
expect(empty_bucket).to eq([])
|
105
|
+
EM.stop
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#pop_count' do
|
114
|
+
it 'gets 2 items and removes them' do
|
115
|
+
EM.run do
|
116
|
+
EM.add_timer(0.1) { fail "didn't reach EM.stop" }
|
117
|
+
add_n_items_ordered(bucketer, "1", 3) do
|
118
|
+
bucketer.get_bucket("1") do |total_bucket|
|
119
|
+
expect(total_bucket.count).to eq(3)
|
120
|
+
bucketer.pop_count("1", 2) do |bucket|
|
121
|
+
expect(bucket.count).to eq(2)
|
122
|
+
|
123
|
+
bucketer.get_bucket("1") do |remaining_bucket|
|
124
|
+
expect(remaining_bucket.count).to eq(1)
|
125
|
+
EM.stop
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/spec_methods.rb
CHANGED
@@ -7,4 +7,13 @@ module SpecMethods
|
|
7
7
|
end
|
8
8
|
EM::Iterator.new(0...n).each(worker, blk)
|
9
9
|
end
|
10
|
+
|
11
|
+
def add_n_items_ordered(bucketer, bucket, n, &blk)
|
12
|
+
worker = proc do |i, iter|
|
13
|
+
bucketer.add_item(bucket, {:id => i}) do
|
14
|
+
iter.next
|
15
|
+
end
|
16
|
+
end
|
17
|
+
EM::Iterator.new(0...n).each(worker, blk)
|
18
|
+
end
|
10
19
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-bucketer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Heycock
|
@@ -143,9 +143,16 @@ files:
|
|
143
143
|
- lib/em-bucketer/database/hash.rb
|
144
144
|
- lib/em-bucketer/database/redis.rb
|
145
145
|
- lib/em-bucketer/in_memory.rb
|
146
|
+
- lib/em-bucketer/ordered.rb
|
147
|
+
- lib/em-bucketer/ordered/base.rb
|
148
|
+
- lib/em-bucketer/ordered/database.rb
|
149
|
+
- lib/em-bucketer/ordered/database/hash.rb
|
150
|
+
- lib/em-bucketer/ordered/in_memory.rb
|
146
151
|
- lib/em-bucketer/redis.rb
|
147
152
|
- lib/em-bucketer/version.rb
|
148
153
|
- spec/em_bucketer_examples.rb
|
154
|
+
- spec/em_bucketer_ordered_examples.rb
|
155
|
+
- spec/in_memory_ordered_spec.rb
|
149
156
|
- spec/in_memory_spec.rb
|
150
157
|
- spec/redis_spec.rb
|
151
158
|
- spec/spec_helper.rb
|
@@ -177,6 +184,8 @@ summary: A generic eventmachine library for storing arbitrary objects in buckets
|
|
177
184
|
callbacks on threshold reached
|
178
185
|
test_files:
|
179
186
|
- spec/em_bucketer_examples.rb
|
187
|
+
- spec/em_bucketer_ordered_examples.rb
|
188
|
+
- spec/in_memory_ordered_spec.rb
|
180
189
|
- spec/in_memory_spec.rb
|
181
190
|
- spec/redis_spec.rb
|
182
191
|
- spec/spec_helper.rb
|