pub 0.0.1 → 0.1.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.
data/README.md CHANGED
@@ -1,21 +1,9 @@
1
- Jotting down the idea:
1
+ # Pub
2
2
 
3
- # Configure
3
+ Pub is a Redis-backed pub with a non-blocking bar counter, or, putting aside
4
+ the metaphor for a moment, a processing queue where consumers, instead of
5
+ simply queuing jobs and getting on with their lives, queue and wait for a
6
+ response without blocking the Ruby process.
4
7
 
5
- Pub.redis = "localhost:6379"
6
- Pub.expires_in = 900
7
-
8
- # Subscriber: A request
9
-
10
- Queue["foo"].subscribe("1234") do |resp|
11
- puts resp
12
- end
13
-
14
- # Publisher: A background worker
15
-
16
- queue = Queue["foo"]
17
- # Process up to 10 requests at a time
18
- reqs = queue.pop(10)
19
- process(reqs) do |req, resp|
20
- queue.publish(req, resp)
21
- end
8
+ This is a barebone work-in-progress that I am about to give a test ride to in
9
+ an app I'm building.
data/Rakefile CHANGED
@@ -1 +1,14 @@
1
- require 'bundler/gem_tasks'
1
+ require "bundler/gem_tasks"
2
+ require "cucumber/rake/task"
3
+ require "rspec/core/rake_task"
4
+
5
+ Cucumber::Rake::Task.new(:features) do |t|
6
+ t.cucumber_opts = "features --format pretty"
7
+ end
8
+
9
+ desc "Run all specs in spec directory"
10
+ RSpec::Core::RakeTask.new(:spec) do |t|
11
+ t.pattern = "spec/**/*_spec.rb"
12
+ end
13
+
14
+ task :default => [:spec, :features]
@@ -0,0 +1,9 @@
1
+ # Pub
2
+
3
+ Pub is a Redis-backed pub with a non-blocking bar counter, or, putting aside
4
+ the metaphor for a moment, a processing queue where consumers, instead of
5
+ simply queuing jobs and getting on with their lives, queue and wait for a
6
+ response without blocking the Ruby process.
7
+
8
+ This is a barebone work-in-progress that I am about to give a test ride to in
9
+ an app I'm building.
@@ -0,0 +1,63 @@
1
+ Feature: Order beers
2
+ As a pub patron
3
+ I want bartenders to take orders asynchronously
4
+ So I do not block the counter
5
+
6
+ Below we assume a bartender can fill an order in one second.
7
+
8
+ Scenario: Order a beer
9
+ Given 1 bartender
10
+ When "John" orders:
11
+ | beer |
12
+ | Brooklyn Lager |
13
+ Then "John" should receive his beer in 1 second
14
+
15
+ Scenario: Order multiple beers
16
+ Given 1 bartender
17
+ When "John" orders:
18
+ | beer |
19
+ | Brooklyn Lager |
20
+ | Efes Pilsen |
21
+ Then "John" should receive his beers in 2 seconds
22
+
23
+ Scenario: Two bartenders
24
+ Given 2 bartenders
25
+ When "John" orders:
26
+ | beer |
27
+ | Brooklyn Lager |
28
+ | Efes Pilsen |
29
+ Then "John" should receive his beers in 1 second
30
+
31
+ Scenario: Timeout
32
+ Given 1 bartender
33
+ And "John" has no patience to wait more than 2 seconds at the counter
34
+ When "John" orders:
35
+ | beer |
36
+ | Brooklyn Lager |
37
+ | Efes Pilsen |
38
+ | Stella |
39
+ Then "John" should receive the following beers in 2 seconds:
40
+ | beer |
41
+ | A pint of Brooklyn Lager |
42
+ | A pint of Efes Pilsen |
43
+
44
+ Scenario: Two patrons order the same beer
45
+ Given 1 bartender
46
+ And "John" orders:
47
+ | beer |
48
+ | Brooklyn Lager |
49
+ And "Jane" orders:
50
+ | beer |
51
+ | Brooklyn Lager |
52
+ Then "John" should receive his beer in 1 second
53
+ And "Jane" should receive her beer in 1 second
54
+
55
+ Scenario: Crowd
56
+ Given 10 bartenders
57
+ When 10 patrons order 1 beer each
58
+ Then they should receive their beers within 1 second
59
+
60
+ Scenario: Overcrowding
61
+ Given 2 bartenders
62
+ When 4 patrons order 2 beers each
63
+ Then they should receive their beers within 4 seconds
@@ -0,0 +1,3 @@
1
+ Transform /^-?\d+$/ do |number|
2
+ number.to_i
3
+ end
@@ -0,0 +1,112 @@
1
+ module PubHelpers
2
+ def data_store(name)
3
+ patron_names << name unless patron_names.include?(name)
4
+
5
+ instance_variable_get("@hash_of_#{name}") ||
6
+ instance_variable_set("@hash_of_#{name}", Hash.new)
7
+ end
8
+
9
+ def find_or_create_patron(name)
10
+ instance_variable_get("@#{name}") ||
11
+ instance_variable_set("@#{name}", pub.new_patron)
12
+ end
13
+
14
+ def map_beers(table)
15
+ table.hashes.map { |hash| hash["beer"] }
16
+ end
17
+
18
+ def now
19
+ Time.now
20
+ end
21
+
22
+ def orders
23
+ @orders ||= Hash.new
24
+ end
25
+
26
+ def patron_names
27
+ @patron_names ||= []
28
+ end
29
+
30
+ def pub
31
+ @pub ||= Pub.new("Ye Olde Rubies")
32
+ end
33
+
34
+ def sleep_until_order_complete(name)
35
+ fiber = data_store(name)[:fiber]
36
+ EM::Synchrony.sleep(0.1) while fiber.alive?
37
+ end
38
+ end
39
+
40
+ World(PubHelpers)
41
+
42
+ Given /^(\d+) bartenders?$/ do |count|
43
+ count.times do |counter|
44
+ bartender = pub.new_bartender
45
+ EM.add_periodic_timer(1) do
46
+ Fiber.new do
47
+ orders = bartender.take_orders(1)
48
+ order = orders.first
49
+ bartender.serve(order) { "A pint of #{order}" } if order
50
+ end.resume
51
+ end
52
+ end
53
+ end
54
+
55
+ Given /^"([^"]+)" has no patience to wait more than (\d+) seconds at the counter$/ do |name, seconds|
56
+ patron = find_or_create_patron(name)
57
+ patron.instance_variable_set(:@timeout, seconds)
58
+ end
59
+
60
+ When /^"([^"]+)" orders:$/ do |name, table|
61
+ beers = map_beers(table)
62
+ patron = find_or_create_patron(name)
63
+
64
+ data_store(name)[:started_at] = Time.now
65
+
66
+ fiber = Fiber.new do
67
+ tray = patron.order(*beers)
68
+ data_store(name)[:tray] = tray
69
+ end
70
+ data_store(name)[:fiber] = fiber
71
+
72
+ EM.next_tick { fiber.resume }
73
+ end
74
+
75
+ When /^(\d+) patrons order (\d+) beers? each$/ do |patrons_count, beers_count|
76
+ patrons_count.times do |patron_counter|
77
+ raw = beers_count.times.inject("| beer |\n") do |raw, beer_counter|
78
+ raw << "| beer_#{patron_counter}_#{beer_counter} |\n"
79
+ end
80
+ name = "patron_#{patron_counter}"
81
+ When %{"#{name}" orders:}, table(raw)
82
+ end
83
+ end
84
+
85
+ Then /^"([^"]+)" should receive (?:his|her) beers? in (\d+) seconds?$/ do |name, seconds|
86
+ sleep_until_order_complete(name)
87
+
88
+ started_at = data_store(name)[:started_at]
89
+ (now - started_at).should be_within(0.2).of(seconds)
90
+ end
91
+
92
+ Then /^"([^"]+)" should receive the following beers? in (\d+) seconds?:$/ do |name, seconds, table|
93
+ sleep_until_order_complete(name)
94
+
95
+ started_at = data_store(name)[:started_at]
96
+ (now - started_at).should be_within(0.2).of(seconds)
97
+
98
+ beers = map_beers(table)
99
+ tray = data_store(name)[:tray]
100
+ tray.should =~ beers
101
+ end
102
+
103
+ Then /^they should receive their beers within (\d+) seconds?$/ do |seconds|
104
+ started_at = now
105
+ patron_names.each do |name|
106
+ patron_started_at = data_store(name)[:started_at]
107
+ started_at = patron_started_at if patron_started_at < started_at
108
+ sleep_until_order_complete(name)
109
+ end
110
+
111
+ (now - started_at).should be_within(0.2).of(seconds)
112
+ end
@@ -0,0 +1,15 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+
4
+ require "pub"
5
+
6
+ Around do |scenario, block|
7
+ EM.synchrony do
8
+ block.call
9
+ EM.stop
10
+ end
11
+ end
12
+
13
+ Before do
14
+ Pub.counter.flushall
15
+ end
data/lib/pub.rb CHANGED
@@ -1,14 +1,64 @@
1
- begin
2
- require "yajl"
3
- rescue LoadError
4
- require "json"
5
- end
6
-
7
- require "redis/connection/synchrony"
8
1
  require "redis"
2
+ require "redis/connection/synchrony"
3
+
4
+ require "pub/helpers"
5
+ require "pub/bartender"
6
+ require "pub/patron"
7
+
8
+ # A Redis-backed pub with a non-blocking bar counter.
9
+ #
10
+ # Or, putting aside the metaphor for a moment:
11
+ #
12
+ # A processing queue where consumers, instead of simply queuing jobs and
13
+ # getting on with their lives, queue and wait for a response without
14
+ # blocking the Ruby process.
15
+ #
16
+ # Each pub instance is a distinct queue.
17
+ class Pub
18
+ # The name of the pub.
19
+ attr_reader :name
20
+
21
+ class << self
22
+ # A device that dispenses beer.
23
+ attr_accessor :beer_tap
24
+
25
+ # The bar counter.
26
+ def counter
27
+ Redis.new(url: beer_tap)
28
+ end
29
+ end
30
+
31
+ # Enters a pub.
32
+ #
33
+ # Takes the name of the pub and an optional block.
34
+ #
35
+ # Pub.new('Ye Olde Rubies') do |pub|
36
+ #
37
+ # patron = pub.new_patron
38
+ #
39
+ # patron.order('Guinness') do |beer|
40
+ # JSON.parse(beer).drink
41
+ # end
42
+ #
43
+ # end
44
+ #
45
+ def initialize(name)
46
+ @name = name
47
+ EM.synchrony { yield self } if block_given?
48
+ end
49
+
50
+ # Closes the pub for the night.
51
+ def close
52
+ EM.stop
53
+ end
9
54
 
10
- require "pub/version"
55
+ # A new bartender.
56
+ def new_bartender
57
+ Bartender.new(name)
58
+ end
11
59
 
12
- module Pub
13
- # Your code goes here...
60
+ # A new patron.
61
+ def new_patron(timeout = 5)
62
+ Patron.new(name, timeout)
63
+ end
14
64
  end
@@ -0,0 +1,44 @@
1
+ class Pub
2
+ # A bartender.
3
+ #
4
+ # In other words, a producer in our processing queue.
5
+ class Bartender
6
+ include Helpers
7
+
8
+ # Creates a new bartender.
9
+ #
10
+ # Takes the name of the pub.
11
+ def initialize(pub_name)
12
+ @pub_name = pub_name
13
+ end
14
+
15
+ # Serves a beer to a thirsty patron.
16
+ #
17
+ # Takes a block which should return a glass of beer.
18
+ #
19
+ # See below for example usage.
20
+ def serve(beer, &block)
21
+ counter.lrem(@pub_name, 0, beer)
22
+ counter.publish(order_for(beer), block.call)
23
+ end
24
+
25
+ # Takes one or more orders from the queue.
26
+ #
27
+ # orders = bartender.take_orders(3)
28
+ # orders.each do |order|
29
+ # bartender.serve(order) do
30
+ # "A pint of #{order}"
31
+ # end
32
+ # end
33
+ def take_orders(count = 1)
34
+ orders = Array.new
35
+
36
+ count.times do
37
+ order = counter.lpop(@pub_name) || break
38
+ orders << order
39
+ end
40
+
41
+ orders
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,18 @@
1
+ class Pub
2
+ # Methods used by both patron and bartender.
3
+ module Helpers
4
+ # A specific order.
5
+ #
6
+ # This is a pub/sub channel through with patron and bartender communicate.
7
+ def order_for(beer)
8
+ [@pub_name, beer].join(':')
9
+ end
10
+
11
+ # The bar counter.
12
+ def counter
13
+ @counter ||= Pub.counter
14
+ end
15
+
16
+ private :order_for, :counter
17
+ end
18
+ end
@@ -0,0 +1,56 @@
1
+ class Pub
2
+ # A patron.
3
+ #
4
+ # In other words, a consumer in our processing queue.
5
+ class Patron
6
+ include Helpers
7
+
8
+ # Creates a new pub patron.
9
+ #
10
+ # Takes the name of the pub and a timeout value in seconds.
11
+ #
12
+ # The timeout designates how long a patron is willing to wait at the
13
+ # counter to receive his or her beer.
14
+ def initialize(pub_name, timeout)
15
+ @pub_name, @timeout = pub_name, timeout
16
+ end
17
+
18
+ # Orders one or more beer at the bar counter.
19
+ #
20
+ # If given a block, yields beers as they become available. Otherwise,
21
+ # returns all on a tray.
22
+ #
23
+ # If not all beers are served within specified timeout, it will return only
24
+ # the beers that are ready.
25
+ def order(*beers)
26
+ raise ArgumentError, 'Empty order' if beers.empty?
27
+
28
+ orders, tray = [], []
29
+
30
+ beers.flatten!
31
+
32
+ beers.each do |beer|
33
+ counter.rpush(@pub_name, beer)
34
+ orders << order_for(beer)
35
+ end
36
+
37
+ timer = EM.add_timer(@timeout) do
38
+ foo = counter.unsubscribe
39
+ end
40
+
41
+ counter.subscribe(*orders) do |on|
42
+ on.message do |order, beer|
43
+ counter.unsubscribe(order)
44
+ if block_given?
45
+ yield beer
46
+ else
47
+ tray << beer
48
+ end
49
+ end
50
+ end
51
+
52
+ EM.cancel_timer(timer)
53
+ block_given? ? nil : tray
54
+ end
55
+ end
56
+ end
@@ -1,3 +1,3 @@
1
- module Pub
2
- VERSION = "0.0.1"
1
+ class Pub
2
+ VERSION = "0.1.0"
3
3
  end
@@ -5,30 +5,28 @@ require "pub/version"
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "pub"
7
7
  s.version = Pub::VERSION
8
- s.authors = ["Hakan Ensari"]
9
- s.email = ["hakan.ensari@papercavalier.com"]
10
- s.homepage = "http://rubygems.com/papercavalier/pub"
11
- s.summary = %q{A Redis-backed pub/sub messaging system that processes queues}
12
- s.description = %q{Pub is a Redis-backed pub/sub messaging system that process queues.}
13
-
14
- s.rubyforge_project = "pub"
8
+ s.authors = ["Paper Cavalier"]
9
+ s.email = "code@papercavalier.com"
10
+ s.homepage = "http://github.com/papercavalier/pub"
11
+ s.summary = "A Redis-backed pub or processing queue with a non-blocking bar counter"
15
12
 
16
13
  s.files = `git ls-files`.split("\n")
17
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
14
+ s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
19
15
  s.require_paths = ["lib"]
20
16
 
21
- {
22
- "eventmachine" => "~> 1.0.0.beta.3",
17
+ s.required_ruby_version = ">= 1.9"
18
+
19
+ {
23
20
  "em-synchrony" => "~> 0.3.0.beta.1",
24
21
  "hiredis" => "~> 0.3.2",
25
- "redis" => "~> 2.2.0"
22
+ "redis" => "~> 2.2.1"
26
23
  }.each do |lib, version|
27
24
  s.add_runtime_dependency lib, version
28
25
  end
29
26
 
30
27
  {
31
- "rspec" => "~> 2.6.0"
28
+ "cucumber" => "~> 1.0",
29
+ "rspec" => "~> 2.6",
32
30
  }.each do |lib, version|
33
31
  s.add_development_dependency lib, version
34
32
  end
@@ -0,0 +1,47 @@
1
+ require "spec_helper"
2
+
3
+ class Pub
4
+ describe Bartender do
5
+ let(:pub) { Pub.new("Ye Olde Rubies") }
6
+ let(:bartender) { pub.new_bartender }
7
+ let(:counter) { double("Counter").as_null_object }
8
+
9
+ before do
10
+ bartender.stub!(:counter).and_return(counter)
11
+ end
12
+
13
+ describe "#take_order" do
14
+ before do
15
+ counter.stub!(:lpop).and_return(Time.now)
16
+ end
17
+
18
+ context "when not passed a number" do
19
+ it "pops one order from the queue" do
20
+ orders = bartender.take_orders
21
+ orders.count.should eql 1
22
+ end
23
+ end
24
+
25
+ context "when passed a number" do
26
+ it "returns that many orders from the queue" do
27
+ orders = bartender.take_orders(3)
28
+ orders.count.should eql 3
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "#serve" do
34
+ let(:beer) { "Guinness" }
35
+ after { bartender.serve(beer) { beer } }
36
+
37
+ it "removes duplicate instances of the beer from the queue" do
38
+ counter.should_receive(:lrem).with(pub.name, 0, beer)
39
+ end
40
+
41
+ it "publishes the order" do
42
+ order = bartender.send(:order_for, beer)
43
+ counter.should_receive(:publish).with(order, beer)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,66 @@
1
+ require "spec_helper"
2
+
3
+ class Pub
4
+ describe Patron do
5
+ let(:pub) { Pub.new("Ye Olde Rubies") }
6
+ let(:patron) { pub.new_patron }
7
+ let(:counter) { double("Counter").as_null_object }
8
+
9
+ before do
10
+ patron.stub!(:counter).and_return(counter)
11
+ end
12
+
13
+ describe "#order" do
14
+ context "when ordering a beer" do
15
+ let(:beer) { "Guinness" }
16
+ after { patron.order(beer) }
17
+
18
+ it "queues the beer at the counter" do
19
+ counter.should_receive(:rpush).with(pub.name, beer)
20
+ end
21
+
22
+ it "subscribes to the order" do
23
+ order = patron.send(:order_for, beer)
24
+ counter.should_receive(:subscribe).with(order)
25
+ end
26
+ end
27
+
28
+ context "when ordering two beers" do
29
+ let(:beers) { ["Guinness", "Stella"] }
30
+ after { patron.order(*beers) }
31
+
32
+ it "queues the beers at the counter" do
33
+ beers.each do |beer|
34
+ counter.should_receive(:rpush).with(pub.name, beer)
35
+ end
36
+ end
37
+
38
+ it "subscribes to the orders" do
39
+ orders = beers.map do |beer|
40
+ patron.send(:order_for, beer)
41
+ end
42
+ counter.should_receive(:subscribe).with(*orders)
43
+ end
44
+ end
45
+
46
+ context "when ordering an array of beers" do
47
+ let(:beers) { ["Guinness", "Stella"] }
48
+ after { patron.order(beers) }
49
+
50
+ it "splats the array and queues the beers at the counter" do
51
+ beers.each do |beer|
52
+ counter.should_receive(:rpush).with(pub.name, beer)
53
+ end
54
+ end
55
+ end
56
+
57
+ context "when patron does not know what he or she wants" do
58
+ it "raises an error" do
59
+ expect do
60
+ patron.order
61
+ end.to raise_error ArgumentError
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ describe Pub do
4
+ let(:pub) { Pub.new("Ye Olde Rubies") }
5
+
6
+ describe ".counter" do
7
+ it "returns a Redis connection" do
8
+ Pub.counter.should be_a Redis
9
+ end
10
+ end
11
+
12
+ describe "#new_bartender" do
13
+ it "returns a new bartender" do
14
+ pub.new_bartender.should be_a Pub::Bartender
15
+ end
16
+ end
17
+
18
+ describe "#new_patron" do
19
+ it "returns a new patron" do
20
+ pub.new_patron.should be_a Pub::Patron
21
+ end
22
+
23
+ it "optionally sets the timeout of the patron" do
24
+ patron = pub.new_patron(10)
25
+ patron.instance_variable_get(:@timeout).should eql 10
26
+ end
27
+ end
28
+ end
@@ -1,7 +1,15 @@
1
- require 'rubygems'
2
- require 'bundler/setup'
3
- require 'rspec'
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ require "rspec"
4
4
 
5
- require File.expand_path('../../lib/pub', __FILE__)
5
+ require File.expand_path("../../lib/pub", __FILE__)
6
6
 
7
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
7
+ RSpec.configure do |c|
8
+ c.around(:each) do |example|
9
+ EM.synchrony do
10
+ Pub.counter.flushall
11
+ example.run
12
+ EM.stop
13
+ end
14
+ end
15
+ end
metadata CHANGED
@@ -4,21 +4,21 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 0
8
7
  - 1
9
- version: 0.0.1
8
+ - 0
9
+ version: 0.1.0
10
10
  platform: ruby
11
11
  authors:
12
- - Hakan Ensari
12
+ - Paper Cavalier
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-06-08 00:00:00 +01:00
17
+ date: 2011-06-30 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: eventmachine
21
+ name: em-synchrony
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
24
  none: false
@@ -26,16 +26,16 @@ dependencies:
26
26
  - - ~>
27
27
  - !ruby/object:Gem::Version
28
28
  segments:
29
- - 1
30
29
  - 0
30
+ - 3
31
31
  - 0
32
32
  - beta
33
- - 3
34
- version: 1.0.0.beta.3
33
+ - 1
34
+ version: 0.3.0.beta.1
35
35
  type: :runtime
36
36
  version_requirements: *id001
37
37
  - !ruby/object:Gem::Dependency
38
- name: em-synchrony
38
+ name: hiredis
39
39
  prerelease: false
40
40
  requirement: &id002 !ruby/object:Gem::Requirement
41
41
  none: false
@@ -45,14 +45,12 @@ dependencies:
45
45
  segments:
46
46
  - 0
47
47
  - 3
48
- - 0
49
- - beta
50
- - 1
51
- version: 0.3.0.beta.1
48
+ - 2
49
+ version: 0.3.2
52
50
  type: :runtime
53
51
  version_requirements: *id002
54
52
  - !ruby/object:Gem::Dependency
55
- name: hiredis
53
+ name: redis
56
54
  prerelease: false
57
55
  requirement: &id003 !ruby/object:Gem::Requirement
58
56
  none: false
@@ -60,14 +58,14 @@ dependencies:
60
58
  - - ~>
61
59
  - !ruby/object:Gem::Version
62
60
  segments:
63
- - 0
64
- - 3
65
61
  - 2
66
- version: 0.3.2
62
+ - 2
63
+ - 1
64
+ version: 2.2.1
67
65
  type: :runtime
68
66
  version_requirements: *id003
69
67
  - !ruby/object:Gem::Dependency
70
- name: redis
68
+ name: cucumber
71
69
  prerelease: false
72
70
  requirement: &id004 !ruby/object:Gem::Requirement
73
71
  none: false
@@ -75,11 +73,10 @@ dependencies:
75
73
  - - ~>
76
74
  - !ruby/object:Gem::Version
77
75
  segments:
78
- - 2
79
- - 2
76
+ - 1
80
77
  - 0
81
- version: 2.2.0
82
- type: :runtime
78
+ version: "1.0"
79
+ type: :development
83
80
  version_requirements: *id004
84
81
  - !ruby/object:Gem::Dependency
85
82
  name: rspec
@@ -92,13 +89,11 @@ dependencies:
92
89
  segments:
93
90
  - 2
94
91
  - 6
95
- - 0
96
- version: 2.6.0
92
+ version: "2.6"
97
93
  type: :development
98
94
  version_requirements: *id005
99
- description: Pub is a Redis-backed pub/sub messaging system that process queues.
100
- email:
101
- - hakan.ensari@papercavalier.com
95
+ description:
96
+ email: code@papercavalier.com
102
97
  executables: []
103
98
 
104
99
  extensions: []
@@ -111,12 +106,23 @@ files:
111
106
  - Gemfile
112
107
  - README.md
113
108
  - Rakefile
109
+ - features/README.md
110
+ - features/order.feature
111
+ - features/step_definitions/numeric_transforms.rb
112
+ - features/step_definitions/pub_steps.rb
113
+ - features/support/env.rb
114
114
  - lib/pub.rb
115
+ - lib/pub/bartender.rb
116
+ - lib/pub/helpers.rb
117
+ - lib/pub/patron.rb
115
118
  - lib/pub/version.rb
116
119
  - pub.gemspec
120
+ - spec/pub/bartender_spec.rb
121
+ - spec/pub/patron_spec.rb
122
+ - spec/pub_spec.rb
117
123
  - spec/spec_helper.rb
118
124
  has_rdoc: true
119
- homepage: http://rubygems.com/papercavalier/pub
125
+ homepage: http://github.com/papercavalier/pub
120
126
  licenses: []
121
127
 
122
128
  post_install_message:
@@ -130,8 +136,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
130
136
  - - ">="
131
137
  - !ruby/object:Gem::Version
132
138
  segments:
133
- - 0
134
- version: "0"
139
+ - 1
140
+ - 9
141
+ version: "1.9"
135
142
  required_rubygems_version: !ruby/object:Gem::Requirement
136
143
  none: false
137
144
  requirements:
@@ -142,10 +149,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
149
  version: "0"
143
150
  requirements: []
144
151
 
145
- rubyforge_project: pub
152
+ rubyforge_project:
146
153
  rubygems_version: 1.3.7
147
154
  signing_key:
148
155
  specification_version: 3
149
- summary: A Redis-backed pub/sub messaging system that processes queues
156
+ summary: A Redis-backed pub or processing queue with a non-blocking bar counter
150
157
  test_files:
158
+ - features/README.md
159
+ - features/order.feature
160
+ - features/step_definitions/numeric_transforms.rb
161
+ - features/step_definitions/pub_steps.rb
162
+ - features/support/env.rb
163
+ - spec/pub/bartender_spec.rb
164
+ - spec/pub/patron_spec.rb
165
+ - spec/pub_spec.rb
151
166
  - spec/spec_helper.rb