bucketer 0.0.1 → 0.0.2

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: 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