bucketer 0.0.1 → 0.0.2

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: 91aeba943436f2464a9eb1733c5bac7846113bdc
4
- data.tar.gz: facd6e076c68d5e4ba8d8f44c5170f6df875ed33
3
+ metadata.gz: 977bcdc41c9616bd1eb50f0c6ef7b38d477d2acb
4
+ data.tar.gz: 7fc0498334f0eb657dfba2a3d6bd8129d6cea23e
5
5
  SHA512:
6
- metadata.gz: 0da5f86a6b232041663ad6c6b358b5b0f5e98b868b7138fc4132b916b4049eae1e570a673398e54454b6409c71178ec388423eaa38c2a287048d3f9b26a0daa2
7
- data.tar.gz: e0561a07c9694e9a3f0add769323f7021e10473c8035e505710d47edb567f22e34e38872db0f34100b8eeb80740c56582511a0d10feb39fa2e6eccf5d617a83d
6
+ metadata.gz: 3f10938119224521bfdc699037e64cda70193bf7f323d0a196524f62b28f46831cdbb335b81d180a709be5ea204eaf11bb71e2e23781deb8cfcf5eb18e4aa257
7
+ data.tar.gz: d326b7ff4de0a29d66d0a2821780c3a8da3ebcce3764f158b374cdbc8b07fa48112b7f806b3feb6114a93c3ef10e00bedc40b7f8a8ea1642c1e6bc8a65c1d696
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Bucketer
2
2
 
3
- This is a generic tool for putting arbitrary objects into buckets and setting callbacks to be called when any bucket exceeds a specific threshold size. The interface is intentially written using blocks/callbacks as it is suited for use in EventMachine code.
3
+ This is a generic EventMachine library for putting arbitrary objects into buckets and setting callbacks to be called when any bucket exceeds a specific threshold size. Although the `Bucketer::InMemory` is synchronous (it's just using a ruby hash) the interface is still what would be expected for an asynchronous API for consistency with other Bucketers to be implemented in future.
4
4
 
5
5
  Currently an in memory bucketer is supported, however it is intended that a redis backed bucketer will be added later and it will be using em-hiredis gem for redis interaction and it will actually be asynchronous.
6
6
 
@@ -21,17 +21,27 @@ Or install it yourself as:
21
21
  ## Usage
22
22
 
23
23
  ```ruby
24
- bucketer = Bucketer::InMemory.new(:bucket_threshold_size => 5)
25
-
26
- bucketer.on_bucket_full do |bucket_id|
27
- p "yay bucket #{bucket_id} filled up!"
24
+ require 'bucketer'
25
+ EM.run do
26
+ bucketer = Bucketer::InMemory.new(:bucket_threshold_size => 5)
27
+
28
+ bucketer.on_bucket_full do |bucket_id|
29
+ p "yay bucket #{bucket_id} filled up!"
30
+
31
+ bucketer.get_and_empty_bucket(bucket_id) do |items|
32
+ EM.stop
33
+ items.each do |item|
34
+ p "got back #{item}"
35
+ end
36
+ end
37
+ end
38
+
39
+ bucketer.add_item("1", "1", {:foo => :bar}) {EM.stop}
40
+ bucketer.add_item("1", "2", {:foo => :bar}) {}
41
+ bucketer.add_item("1", "3", {:foo => :bar}) {}
42
+ bucketer.add_item("1", "4", {:bar => :foo}) {}
43
+ bucketer.add_item("1", "5", {:bar => :foo}) {}
28
44
  end
29
-
30
- bucketer.add_item("1", "1", {:foo => :bar})
31
- bucketer.add_item("1", "2", {:foo => :bar})
32
- bucketer.add_item("1", "3", {:foo => :bar})
33
- bucketer.add_item("1", "4", {:bar => :foo})
34
- bucketer.add_item("1", "5", {:bar => :foo})
35
45
  ```
36
46
 
37
47
  ## Contributing
data/bucketer.gemspec CHANGED
@@ -17,6 +17,8 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ["lib"]
19
19
 
20
+ spec.add_runtime_dependency "eventmachine"
21
+
20
22
  spec.add_development_dependency "bundler", "~> 1.6"
21
23
  spec.add_development_dependency "rake"
22
24
  spec.add_development_dependency "rspec"
@@ -1,3 +1,5 @@
1
+ require 'eventmachine'
2
+
1
3
  module Bucketer
2
4
  # This is a purpose built class for storing arbitrary
3
5
  # objects in buckets then calling callbacks when any
@@ -37,8 +39,11 @@ module Bucketer
37
39
  # @param item [Object] the item to be
38
40
  # placed in the bucket
39
41
  def add_item(bucket_id, item_id, item, &blk)
40
- add_bucket_to_db(bucket_id, item_id, item, &blk)
41
- check_bucket_full(bucket_id)
42
+ EM::Completion.new.tap do |c|
43
+ c.callback(&blk) if block_given?
44
+ add_bucket_to_db(bucket_id, item_id, item) { c.succeed }
45
+ check_bucket_full(bucket_id)
46
+ end
42
47
  end
43
48
 
44
49
  # Used to set a callback hook for when a bucket
@@ -61,8 +66,11 @@ module Bucketer
61
66
  # @yield [Array] the items you put
62
67
  # into the bucket
63
68
  def get_bucket(bucket_id, &blk)
64
- get_bucket_from_db(bucket_id) do |bucket|
65
- blk.call bucket.values
69
+ EM::Completion.new.tap do |c|
70
+ c.callback(&blk) if block_given?
71
+ get_bucket_from_db(bucket_id) do |bucket|
72
+ c.succeed bucket.values
73
+ end
66
74
  end
67
75
  end
68
76
 
@@ -73,9 +81,12 @@ module Bucketer
73
81
  # @yield [Array] the items you put
74
82
  # into the bucket
75
83
  def get_and_empty_bucket(bucket_id, &blk)
76
- get_bucket(bucket_id) do |contents|
77
- empty_bucket(bucket_id) do
78
- blk.call contents
84
+ EM::Completion.new.tap do |c|
85
+ c.callback(&blk) if block_given?
86
+ get_bucket(bucket_id) do |contents|
87
+ empty_bucket(bucket_id) do
88
+ c.succeed contents
89
+ end
79
90
  end
80
91
  end
81
92
  end
@@ -85,8 +96,11 @@ module Bucketer
85
96
  # @param bucket_id [String] the bucket id
86
97
  # of the bucket you want to empty
87
98
  def empty_bucket(bucket_id, &blk)
88
- empty_bucket_in_db(bucket_id) do
89
- blk.call if block_given?
99
+ EM::Completion.new.tap do |c|
100
+ c.callback(&blk) if block_given?
101
+ empty_bucket_in_db(bucket_id) do
102
+ c.succeed
103
+ end
90
104
  end
91
105
  end
92
106
 
@@ -1,3 +1,3 @@
1
1
  module Bucketer
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -1,93 +1,80 @@
1
1
  require 'spec_helper'
2
2
  require 'bucketer'
3
3
 
4
- describe Bucketer do
5
- let(:bucketer) { Bucketer::InMemory.new(:bucket_threshold_size => 5) }
6
-
4
+ shared_examples "a bucketer" do
7
5
  describe '#add_item' do
8
6
  it 'adds a item to the bucket' do
9
- ran_add = false
10
- ran_get = false
11
- bucketer.add_item("1", "2", {:foo => :bar}) do
12
- ran_add = true
13
- end
14
-
15
- bucketer.get_bucket("1") do |bucket|
16
- expect(bucket).to eq([{:foo => :bar}])
17
- ran_get = true
7
+ EM.run do
8
+ EM.add_timer(1) { fail "didn't reach EM.stop" }
9
+ bucketer.add_item("1", "2", {:foo => :bar}) do
10
+ bucketer.get_bucket("1") do |bucket|
11
+ expect(bucket).to eq([{:foo => :bar}])
12
+ EM.stop
13
+ end
14
+ end
18
15
  end
19
-
20
- expect(ran_add).to eq(true)
21
- expect(ran_get).to eq(true)
22
16
  end
23
17
 
24
18
  it 'overwrites an existing item with the same id' do
25
- ran_get = false
26
- bucketer.add_item("1", "2", {:foo => :bar})
27
- bucketer.add_item("1", "2", {:bar => :foo})
28
-
29
- bucketer.get_bucket("1") do |bucket|
30
- expect(bucket).to eq([{:bar => :foo}])
31
- ran_get = true
19
+ EM.run do
20
+ EM.add_timer(1) { fail "didn't reach EM.stop" }
21
+ bucketer.add_item("1", "2", {:foo => :bar}) do
22
+ bucketer.add_item("1", "2", {:bar => :foo}) do
23
+
24
+ bucketer.get_bucket("1") do |bucket|
25
+ expect(bucket).to eq([{:bar => :foo}])
26
+ EM.stop
27
+ end
28
+ end
29
+ end
32
30
  end
33
-
34
- expect(ran_get).to eq(true)
35
31
  end
36
32
 
37
33
  it 'calls on_bucket_full when a bucket fills up' do
38
- ran = false
39
- bucketer.on_bucket_full do |bucket_id|
40
- expect(bucket_id).to eq("1")
41
- ran = true
34
+ EM.run do
35
+ EM.add_timer(1) { fail "didn't reach EM.stop" }
36
+ bucketer.on_bucket_full do |bucket_id|
37
+ expect(bucket_id).to eq("1")
38
+ EM.stop
39
+ end
40
+
41
+ add_n_items(bucketer, "1", 5) {}
42
42
  end
43
-
44
- bucketer.add_item("1", "1", {:foo => :bar})
45
- bucketer.add_item("1", "2", {:foo => :bar})
46
- bucketer.add_item("1", "3", {:foo => :bar})
47
- bucketer.add_item("1", "4", {:bar => :foo})
48
- bucketer.add_item("1", "5", {:bar => :foo})
49
-
50
- expect(ran).to eq(true)
51
43
  end
52
44
  end
53
45
 
54
46
  describe '#empty_bucket' do
55
47
  it 'emptys a bucket' do
56
- ran = false
57
- bucketer.add_item("1", "1", {:foo => :bar})
58
- bucketer.add_item("1", "2", {:foo => :bar})
59
- bucketer.add_item("1", "3", {:foo => :bar})
60
-
61
- bucketer.empty_bucket("1")
62
-
63
- bucketer.get_bucket("1") do |bucket|
64
- expect(bucket).to eq([])
65
- ran = true
48
+ EM.run do
49
+ EM.add_timer(1) { fail "didn't reach EM.stop" }
50
+ add_n_items(bucketer, "1", 3) do
51
+ bucketer.empty_bucket("1") do
52
+ bucketer.get_bucket("1") do |bucket|
53
+ expect(bucket).to eq([])
54
+ EM.stop
55
+ end
56
+ end
57
+ end
66
58
  end
67
- expect(ran).to eq(true)
68
59
  end
69
60
  end
70
61
 
71
62
  describe '#get_and_empty_bucket' do
72
63
  it 'gets the bucket then emptys the bucket' do
73
- ran_get_and_empty = false
74
- ran_get = false
75
- bucketer.add_item("1", "1", {:foo => :bar})
76
- bucketer.add_item("1", "2", {:bar => :foo})
77
- bucketer.add_item("1", "3", {:boo => :far})
78
-
79
- bucketer.get_and_empty_bucket("1") do |bucket|
80
- expect(bucket).to eq([{:foo => :bar}, {:bar => :foo}, {:boo => :far}])
81
- ran_get_and_empty = true
64
+ EM.run do
65
+ EM.add_timer(1) { fail "didn't reach EM.stop" }
66
+ add_n_items(bucketer, "1", 3) do
67
+
68
+ bucketer.get_and_empty_bucket("1") do |bucket|
69
+ expect(bucket).to eq([{:id => 0}, {:id => 1}, {:id => 2}])
70
+
71
+ bucketer.get_bucket("1") do |empty_bucket|
72
+ expect(empty_bucket).to eq([])
73
+ EM.stop
74
+ end
75
+ end
76
+ end
82
77
  end
83
-
84
- bucketer.get_bucket("1") do |bucket|
85
- expect(bucket).to eq([])
86
- ran_get = true
87
- end
88
-
89
- expect(ran_get_and_empty).to eq(true)
90
- expect(ran_get).to eq(true)
91
78
  end
92
79
  end
93
80
  end
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require 'bucketer'
3
+
4
+ describe Bucketer::InMemory do
5
+ it_behaves_like "a bucketer" do
6
+ let(:bucketer) { Bucketer::InMemory.new(:bucket_threshold_size => 5) }
7
+ end
8
+ end
data/spec/spec_helper.rb CHANGED
@@ -2,7 +2,9 @@ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
2
2
 
3
3
  require 'rspec'
4
4
  require 'pry'
5
+ require 'spec_methods'
5
6
 
6
7
  RSpec.configure do |config|
7
8
  config.order = :rand
9
+ config.include(SpecMethods)
8
10
  end
@@ -0,0 +1,10 @@
1
+ module SpecMethods
2
+ def add_n_items(bucketer, bucket, n, &blk)
3
+ worker = proc do |i, iter|
4
+ bucketer.add_item(bucket, i.to_s, {:id => i}) do
5
+ iter.next
6
+ end
7
+ end
8
+ EM::Iterator.new(0...n).each(worker, blk)
9
+ end
10
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bucketer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Heycock
@@ -11,6 +11,20 @@ bindir: bin
11
11
  cert_chain: []
12
12
  date: 2014-10-30 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: eventmachine
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: bundler
16
30
  requirement: !ruby/object:Gem::Requirement
@@ -84,7 +98,9 @@ files:
84
98
  - lib/bucketer/in_memory.rb
85
99
  - lib/bucketer/version.rb
86
100
  - spec/bucketer_spec.rb
101
+ - spec/in_memory_spec.rb
87
102
  - spec/spec_helper.rb
103
+ - spec/spec_methods.rb
88
104
  homepage: https://github.com/dgvz/bucketer
89
105
  licenses:
90
106
  - GPL
@@ -112,4 +128,6 @@ summary: A generic class for storing arbitrary objects in buckets with callbacks
112
128
  threshold reached
113
129
  test_files:
114
130
  - spec/bucketer_spec.rb
131
+ - spec/in_memory_spec.rb
115
132
  - spec/spec_helper.rb
133
+ - spec/spec_methods.rb