meerkat 0.4.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -6,36 +6,59 @@ Rack middleware for [Server-Sent Events (HTML5 SSE)](http://www.html5rocks.com/e
6
6
  Requires an [EventMachine](https://github.com/eventmachine/eventmachine#readme) backed server, like [Thin](http://code.macournoyer.com/thin/) or [Rainbows](http://rainbows.rubyforge.org/) (with the EventMachine backend only).
7
7
 
8
8
  Features:
9
- * Subscribe for single events
10
- * Subscribe for multiple events with patterns
11
- * Low memory and CPU usage
12
- * Works with all proxies (unlike WebSockets)
13
- * Allows publishing from server side as well as from the client side (with POST request)
9
+
10
+ * Realtime events
11
+ * Extremely efficent
12
+ * Broad browser support (both desktop and mobile browsers)
13
+ * Works with all proxies (unlike WebSockets)
14
+ * Subscribe to single events
15
+ * Subscribe to multiple events via patterns
16
+ * Publish messages from the server
17
+ * Publish messages from the client (via POST)
14
18
 
15
19
  Supported backends:
16
20
 
17
- * In memory, using [EventMachine Channels](http://eventmachine.rubyforge.org/EventMachine/Channel.html), good for single server usage.
18
- * Redis, using [em-hiredis](https://github.com/mloughran/em-hiredis#readme) and the [Pub/Sub API](http://redis.io/topics/pubsub).
19
- * Postgres, using the [Notify/Listen API](http://www.postgresql.org/docs/9.1/static/sql-notify.html).
20
- * When a message is published the topic and json payload is inserted into the 'meerkat_pubsub' table, and then a NOTIFY is issued.
21
- * Listening clients recivies the notification and reads the message from the table and writes it to the Event Stream of its clients.
22
- * On the next publish all messages older than 5 seconds are deleted.
23
- * No polling is ever done.
24
- * This works with PostgreSQL 8 and higher (tested with 8.3 and 9.1).
21
+ * In memory, using [EventMachine Channels](http://eventmachine.rubyforge.org/EventMachine/Channel.html), good for single server usage.
22
+ * RabbitMQ (AMQP), using the [AMQP gem](https://github.com/amqp/amqp-ruby) and the Pub/Sub pattern (Topic exchange + anonymous queues with pattern matching). AMQP is the most recommened alternative.
23
+ * Redis, using [em-hiredis](https://github.com/mloughran/em-hiredis#readme) and the [Pub/Sub API](http://redis.io/topics/pubsub).
24
+ * Postgres, using the [Notify/Listen API](http://www.postgresql.org/docs/9.1/static/sql-notify.html).
25
+ * When a message is published the topic and json payload is inserted into the 'meerkat_pubsub' table, and then a NOTIFY is issued.
26
+ * Listening clients recivies the notification and reads the message from the table and writes it to the Event Stream of its clients.
27
+ * On the next publish all messages older than 5 seconds are deleted.
28
+ * No polling is ever done.
29
+ * This works with PostgreSQL 8 and higher (tested with 8.3 and 9.1).
25
30
 
26
31
  Usage
27
32
  -----
28
33
 
34
+ Put meerkat and pg or em-hiredis in your Gemfile, depending on which backend you plan to use.
35
+ Gemfile:
36
+
37
+ ```ruby
38
+ gem 'meerkat'
39
+ gem 'amqp'
40
+ # or
41
+ gem 'pg'
42
+ # or
43
+ gem 'em-hiredis'
44
+ ```
45
+ Require meerkat and the backend you would like to use.
46
+
29
47
  config.ru:
30
48
 
31
49
  ```ruby
32
50
  require 'bundler/setup'
33
51
  require 'meerkat'
52
+ require 'meerkat/backend/amqp'
53
+ #require 'meerkat/backend/pg'
54
+ #require 'meerkat/backend/redis'
55
+ #require 'meerkat/backend/inmemory'
34
56
  require './app'
35
57
 
36
58
  #Meerkat.backend = Meerkat::Backend::InMemory.new
59
+ Meerkat.backend = Meerkat::Backend::AMQP.new 'amqp://guest:guest@localhost'
37
60
  #Meerkat.backend = Meerkat::Backend::Redis.new 'redis://localhost/0'
38
- Meerkat.backend = Meerkat::Backend::PG.new :dbname => 'postgres'
61
+ #Meerkat.backend = Meerkat::Backend::PG.new :dbname => 'postgres'
39
62
  map '/' do
40
63
  run App
41
64
  end
@@ -47,7 +70,7 @@ end
47
70
  On the client:
48
71
 
49
72
  ```javascript
50
- var source = new EventSource('/stream/mychannel');
73
+ var source = new EventSource('/stream/foo');
51
74
  var streamList = document.getElementById('stream');
52
75
  // Use #onmessage if you only listen to one topic
53
76
  source.onmessage = function(e) {
@@ -55,23 +78,24 @@ source.onmessage = function(e) {
55
78
  li.innerHTML = JSON.parse(e.data);
56
79
  streamList.appendChild(li);
57
80
  }
58
- var multiSource = new EventSource('/my/event/*');
81
+
82
+ var multiSource = new EventSource('/stream/foo.*');
59
83
  // You have to add custom event listerns when you
60
84
  // listen on multiple topics
61
- multiSource.addEventListener('/my/event/foo', function(e) {
85
+ multiSource.addEventListener('foo.bar', function(e) {
62
86
  // Do something
63
87
  }, false);
64
- multiSource.addEventListener('/my/event/bar', function(e) {
88
+ multiSource.addEventListener('foo.foo', function(e) {
65
89
  // Do something
66
90
  }, false);
67
91
  ```
68
92
 
69
- To push things from the client:
93
+ To push things from the server:
70
94
 
71
95
  ```ruby
72
- Meerkat.publish "/mychannel", {:any => hash}
73
- Meerkat.publish "/mychannel/2", 'any string'
74
- Meerkat.publish "/mychannel/3", any_object
96
+ Meerkat.publish "foo.bar", { :any => 'hash' } # the hash will automatically be json encoded
97
+ Meerkat.publish "foo.bar", 'any string'
98
+ Meerkat.publish "foo.foo", myobj.to_json, true # the third parameter indicates that the message already is json encoded
75
99
  ```
76
100
 
77
101
  The published objects will be JSON serialized before sent to the backend. You'll have to deserialize it in the client.
@@ -79,10 +103,13 @@ The published objects will be JSON serialized before sent to the backend. You'll
79
103
  From the client:
80
104
 
81
105
  ```javascript
82
- $.post('/stream/mychannel/2', { json: JSON.stringify(my_object) })
106
+ $.post('/stream', { topic: 'foo.bar', data: JSON.stringify(my_object) })
107
+ $.post('/stream/foo.bar', { data: JSON.stringify(my_object) })
83
108
  ```
84
109
 
85
- A simple POST request, with a parameter called 'json' containing a JSON string.
110
+ A simple POST request, with a parameter called 'data' (or 'json' or 'msg') containing a JSON string.
111
+
112
+ The topic can be specified other as a post parameter or in the path.
86
113
 
87
114
  Read more about Server-Sent Events and the EventSource API on [HTML5Rocks](http://www.html5rocks.com/en/tutorials/eventsource/basics/).
88
115
 
@@ -1,8 +1,5 @@
1
1
  require_relative 'meerkat/version'
2
2
  require_relative 'meerkat/rackadapter'
3
- require_relative 'meerkat/backend/inmemory'
4
- require_relative 'meerkat/backend/redis'
5
- require_relative 'meerkat/backend/pg'
6
3
  require 'multi_json'
7
4
 
8
5
  module Meerkat
@@ -12,13 +9,16 @@ module Meerkat
12
9
  @backend = backend
13
10
  end
14
11
 
15
- def publish(route, message, is_json = false)
12
+ def publish(topic, message, is_json = false)
13
+ raise "Topic is required" if topic.nil?
14
+ raise "Message is required" if message.nil?
16
15
  json = is_json ? message : MultiJson.encode(message)
17
- @backend.publish(route, json)
16
+ @backend.publish(topic, json)
18
17
  end
19
18
 
20
- def subscribe(route, &callback)
21
- @backend.subscribe(route, &callback)
19
+ def subscribe(topic, &callback)
20
+ raise "Topic is required" if topic.nil?
21
+ @backend.subscribe(topic, &callback)
22
22
  end
23
23
 
24
24
  def unsubscribe(sid)
@@ -0,0 +1,32 @@
1
+ require 'amqp'
2
+
3
+ module Meerkat
4
+ module Backend
5
+ class AMQP
6
+ def initialize(amqp_url = 'amqp://guest:guest@localhost')
7
+ @conn = ::AMQP.connect amqp_url
8
+ end
9
+
10
+ def publish(topic, json)
11
+ ::AMQP::Channel.new @conn do |ch|
12
+ ch.topic("meerkat").publish(json, :routing_key => topic)
13
+ end
14
+ end
15
+
16
+ def subscribe(topic, &callback)
17
+ ::AMQP::Channel.new @conn do |ch|
18
+ ch.queue('', :auto_delete => true) do |queue|
19
+ queue.bind(ch.topic("meerkat"), :routing_key => topic)
20
+ queue.subscribe do |headers, payload|
21
+ callback.call headers.routing_key, payload
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ def unsubscribe(channel)
28
+ channel.close
29
+ end
30
+ end
31
+ end
32
+ end
@@ -47,7 +47,11 @@ module Meerkat
47
47
  def create_table
48
48
  @pg.transaction do |conn|
49
49
  table = conn.exec "SELECT true FROM pg_tables WHERE tablename = $1", [TABLENAME]
50
- conn.exec "CREATE TABLE #{TABLENAME} (topic varchar(1024), json text, timestamp timestamp default now())" if table.count == 0
50
+ return unless table.count == 0
51
+ conn.exec "CREATE TABLE #{TABLENAME} (
52
+ topic varchar(1024),
53
+ json text,
54
+ timestamp timestamp default now())"
51
55
  end
52
56
  end
53
57
 
@@ -26,15 +26,14 @@ module Meerkat
26
26
 
27
27
  def post(env)
28
28
  req = Rack::Request.new env
29
+ topic = req.path_info[1..-1]
30
+ topic = req.params['topic'] if topic.empty?
29
31
  data = req.params['data'] || req.params['msg'] || req.params['json']
30
- if data
31
- Meerkat.publish(req.path_info, data, true)
32
- [204, {}, []]
33
- else
34
- [400,
35
- {'Content-Type' => 'text/plain'},
36
- ['Required POST parameter "data", "msg" or "json" is missing']]
37
- end
32
+
33
+ Meerkat.publish(topic, data, true)
34
+ [204, {}, []]
35
+ rescue Exception => e
36
+ [400, {'Content-Type' => 'text/plain'}, [e.message]]
38
37
  end
39
38
 
40
39
  def listen(env)
@@ -49,7 +48,7 @@ module Meerkat
49
48
  EM.add_periodic_timer(@keep_alive) { body << ":\n" }
50
49
  EM.add_timer(@timeout) { body.succeed } if @timeout
51
50
 
52
- path_info = Rack::Utils.unescape env["PATH_INFO"]
51
+ path_info = Rack::Utils.unescape(env["PATH_INFO"])[1..-1]
53
52
  sub = Meerkat.subscribe(path_info) do |topic, json|
54
53
  body << "event: #{topic}\n" unless path_info == topic
55
54
  body << "data: #{json}\n\n"
@@ -1,3 +1,3 @@
1
1
  module Meerkat
2
- VERSION = "0.4.5"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -18,14 +18,15 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
- s.add_development_dependency "minitest"
21
+ s.add_development_dependency "rspec"
22
22
  s.add_development_dependency "rack-test"
23
23
  s.add_development_dependency "thin_async"
24
24
  s.add_development_dependency "thin-async-test"
25
- s.add_development_dependency "em-minitest-spec"
25
+
26
+ s.add_development_dependency "pg"
27
+ s.add_development_dependency "amqp"
28
+ s.add_development_dependency "em-hiredis"
26
29
 
27
30
  s.add_runtime_dependency "multi_json"
28
31
  s.add_runtime_dependency "eventmachine"
29
- s.add_runtime_dependency "em-hiredis"
30
- s.add_runtime_dependency "pg"
31
32
  end
@@ -0,0 +1,34 @@
1
+ require './lib/meerkat/backend/amqp'
2
+ require 'eventmachine'
3
+
4
+ describe Meerkat::Backend::AMQP do
5
+ around do |spec|
6
+ EM.run { spec.call }
7
+ end
8
+
9
+ it 'can publish and subscribe' do
10
+ subject.subscribe 'route' do |topic, msg|
11
+ topic.should == 'route'
12
+ msg.should == 'foo'
13
+ EM.stop
14
+ end
15
+ EM.add_timer(0.1) { subject.publish 'route', 'foo' }
16
+ end
17
+
18
+ it 'can subscribe to wildcards' do
19
+ subject.subscribe 'foo.*' do |topic, msg|
20
+ topic.should == 'foo.bar'
21
+ msg.should == 'barfoo'
22
+ EM.stop
23
+ end
24
+ EM.add_timer(0.1) { subject.publish 'foo.bar', 'barfoo' }
25
+ end
26
+
27
+ it 'can unsubscribe' do
28
+ sid = subject.subscribe('route') { |topic, msg| }
29
+ EM.add_timer(0.1) do
30
+ subject.unsubscribe sid
31
+ EM.stop
32
+ end
33
+ end
34
+ end
@@ -1,34 +1,36 @@
1
- require 'minitest/autorun'
2
- require 'em/minitest/spec'
3
1
  require './lib/meerkat/backend/inmemory'
2
+ require 'eventmachine'
4
3
 
5
- describe 'The in memory backend' do
6
- include EM::MiniTest::Spec
7
-
8
- before do
9
- @im = Meerkat::Backend::InMemory.new
4
+ describe Meerkat::Backend::InMemory do
5
+ around do |spec|
6
+ EM.run { spec.call }
10
7
  end
11
8
 
12
9
  it 'can publish and subscribe' do
13
- @im.subscribe 'route' do |topic, msg|
14
- assert_equal 'route', topic
15
- assert_equal 'foo', msg
16
- done!
10
+ subject.subscribe 'route' do |topic, msg|
11
+ topic.should == 'route'
12
+ msg.should == 'foo'
13
+ EM.stop
14
+ end
15
+ EM.next_tick do
16
+ subject.publish 'route', 'foo'
17
17
  end
18
- @im.publish 'route', 'foo'
19
- wait!
20
18
  end
19
+
21
20
  it 'can subscribe to wildcards' do
22
- @im.subscribe '/foo/*' do |topic, msg|
23
- assert_equal '/foo/bar', topic
24
- assert_equal 'barfoo', msg
25
- done!
21
+ subject.subscribe '/foo/*' do |topic, msg|
22
+ topic.should == '/foo/bar'
23
+ msg.should == 'barfoo'
24
+ EM.stop
25
+ end
26
+ EM.next_tick do
27
+ subject.publish '/foo/bar', 'barfoo'
26
28
  end
27
- @im.publish '/foo/bar', 'barfoo'
28
- wait!
29
29
  end
30
+
30
31
  it 'can unbsubscribe' do
31
- sid = @im.subscribe 'route' do |topic, msg| end
32
- @im.unsubscribe sid
32
+ sid = subject.subscribe 'route' do |topic, msg| end
33
+ subject.unsubscribe sid
34
+ EM.stop
33
35
  end
34
36
  end
@@ -1,57 +1,63 @@
1
- require 'minitest/autorun'
2
- require 'em/minitest/spec'
1
+ require 'eventmachine'
3
2
  require './lib/meerkat/backend/pg'
4
3
 
5
4
  describe 'Postgres backend' do
6
- include EM::MiniTest::Spec
5
+ around do |spec|
6
+ EM.run { spec.call }
7
+ end
8
+
9
+ def done!
10
+ EM.stop
11
+ end
12
+
13
+ subject { Meerkat::Backend::PG.new :dbname => 'postgres' }
7
14
 
8
- before do
9
- @b = Meerkat::Backend::PG.new :dbname => 'postgres'
15
+ it 'create required table only once' do
16
+ subject.send :create_table
17
+ subject.send :create_table
18
+ done!
10
19
  end
11
20
 
12
21
  it 'can subscribe to partial wildcard' do
13
- @b.subscribe '/foo/*' do |topic, msg|
14
- assert_equal '/foo/bar', topic
15
- assert_equal 'messsage', msg
22
+ subject.subscribe '/foo/*' do |topic, msg|
23
+ topic.should == '/foo/bar'
24
+ msg.should == 'messsage'
16
25
  done!
17
26
  end
18
- @b.publish '/foo/bar', 'messsage'
19
- wait!
27
+ subject.publish '/foo/bar', 'messsage'
20
28
  end
21
29
 
22
30
  it 'can subscribe to wildcard' do
23
- @b.subscribe '*' do |topic, msg|
24
- assert_equal 'messsage', msg
31
+ subject.subscribe '*' do |topic, msg|
32
+ msg.should == 'messsage'
25
33
  done!
26
34
  end
27
- @b.publish '/', 'messsage'
28
- wait!
35
+ subject.publish '/', 'messsage'
29
36
  end
30
37
 
31
38
  it 'can publish and subscribe' do
32
- @b.subscribe '/' do |topic, msg|
33
- assert_equal 'messsage', msg
39
+ subject.subscribe '/' do |topic, msg|
40
+ msg.should == 'messsage'
34
41
  done!
35
42
  end
36
- @b.publish '/', 'messsage'
37
- wait!
43
+ subject.publish '/', 'messsage'
38
44
  end
39
45
 
40
46
  it 'can publish and subscribe multiple messages' do
41
47
  i = 5
42
48
  j = 0
43
- @b.subscribe '/' do |topic, msg|
49
+ subject.subscribe '/' do |topic, msg|
44
50
  j += 1
45
- assert_equal 'messsage', msg
51
+ msg.should == 'messsage'
46
52
  done! if j == i
47
53
  end
48
- i.times { @b.publish '/', 'messsage' }
49
- wait!
54
+ i.times { subject.publish '/', 'messsage' }
50
55
  end
51
56
 
52
57
  it 'can unsubscribe' do
53
- sid = @b.subscribe 'route' do |topic, msg| end
54
- @b.unsubscribe sid
58
+ sid = subject.subscribe 'route' do |topic, msg| end
59
+ subject.unsubscribe sid
60
+ done!
55
61
  end
56
62
  end
57
63
 
@@ -1,41 +1,36 @@
1
- require 'minitest/autorun'
2
- require 'em/minitest/spec'
3
1
  require './lib/meerkat/backend/redis'
2
+ require 'eventmachine'
4
3
 
5
- describe 'Redis backend' do
6
- include EM::MiniTest::Spec
4
+ describe Meerkat::Backend::Redis do
5
+ around do |spec|
6
+ EM.run { spec.call }
7
+ end
7
8
 
8
9
  it 'can publish and subscribe to wildcards' do
9
- b = Meerkat::Backend::Redis.new
10
- b.subscribe '/foo/*' do |topic, msg|
11
- assert_equal '/foo/bar', topic
12
- assert_equal 'messsage', msg
13
- done!
10
+ subject.subscribe '/foo/*' do |topic, msg|
11
+ topic.should == '/foo/bar'
12
+ msg.should == 'messsage'
13
+ EM.stop
14
14
  end
15
15
  EM.next_tick {
16
- b.publish '/foo/bar', 'messsage'
16
+ subject.publish '/foo/bar', 'messsage'
17
17
  }
18
- wait!
19
18
  end
20
19
 
21
20
  it 'can publish and subscribe' do
22
- b = Meerkat::Backend::Redis.new
23
- b.subscribe '/' do |topic, msg|
24
- assert_equal 'messsage', msg
25
- done!
21
+ subject.subscribe '/' do |topic, msg|
22
+ msg.should == 'messsage'
23
+ EM.stop
26
24
  end
27
25
  EM.next_tick {
28
- b.publish '/', 'messsage'
26
+ subject.publish '/', 'messsage'
29
27
  }
30
- wait!
31
28
  end
32
29
 
33
30
  it 'can unsubscribe' do
34
- b = Meerkat::Backend::Redis.new
35
- sid = b.subscribe 'route' do |msg|
36
- @recivied = msg
37
- end
38
- b.unsubscribe sid
31
+ sid = subject.subscribe('route')
32
+ subject.unsubscribe sid
33
+ EM.stop
39
34
  end
40
35
  end
41
36
 
@@ -1,10 +1,9 @@
1
- require 'bundler/setup'
2
- require 'minitest/autorun'
3
1
  require 'rack/test'
4
2
  require 'thin/async/test'
5
3
  require './lib/meerkat'
4
+ require './lib/meerkat/backend/inmemory'
6
5
 
7
- describe 'Meerkat' do
6
+ describe Meerkat do
8
7
  include Rack::Test::Methods
9
8
 
10
9
  before do
@@ -21,50 +20,57 @@ describe 'Meerkat' do
21
20
  }.to_app
22
21
  end
23
22
 
24
- it 'should return status 200 and content-type text/event-stream' do
23
+ it 'returns status 200 and content-type text/event-stream' do
25
24
  get '/'
26
- assert_equal 200, last_response.status
27
- assert_equal 'text/event-stream', last_response.headers['Content-Type']
25
+ last_response.status.should == 200
26
+ last_response.headers['Content-Type'].should == 'text/event-stream'
28
27
  end
29
28
 
30
- it 'first return a retry value' do
29
+ it 'start with a retry value' do
31
30
  get '/'
32
- assert_equal "retry: 3000\n", last_response.body.lines.first
31
+ last_response.body.lines.first.should == "retry: 3000\n"
33
32
  end
34
33
 
35
- it 'should periodically emit a comment to keep alive the connection' do
34
+ it 'periodically emits a comment to keep alive the connection' do
36
35
  get '/'
37
- assert_equal ":", last_response.body.split("\n")[1]
36
+ last_response.body.split("\n")[1].should == ":"
38
37
  end
39
-
40
- it 'should publish POST data and treat it like JSON' do
41
- mock = MiniTest::Mock.new
42
- mock.expect(:publish, nil, ['/foo', '"bar"'])
43
- Meerkat.backend = mock
38
+
39
+ it 'publishes POST data and treat it like JSON' do
40
+ backend = stub
41
+ backend.should_receive(:publish).with('foo', '"bar"')
42
+ Meerkat.backend = backend
44
43
  post '/foo', :json => '"bar"'
44
+ last_response.status.should == 204
45
+ end
46
+
47
+ it 'uses path info as topic' do
48
+ post '/foo.bar', msg: 'foobar'
49
+ last_response.status.should == 204
50
+ end
45
51
 
46
- assert_equal 204, last_response.status
47
- assert mock.verify
52
+ it 'can use topic post params as topic' do
53
+ post '/', topic: 'foo.bar', msg: 'foobar'
54
+ last_response.status.should == 204
48
55
  end
49
56
 
50
- it 'should return error 400 when there is no "json" POST parameters' do
57
+ it 'returns error 400 when there is no "json" POST parameters' do
51
58
  post '/', :foo => 'bar'
52
- assert_equal 400, last_response.status
59
+ last_response.status.should == 400
53
60
  end
54
61
 
55
62
  it 'should return error 400 when there is no POST data' do
56
63
  post '/foo'
57
- assert_equal 400, last_response.status
64
+ last_response.status.should == 400
58
65
  end
59
66
 
60
- it 'should return 404 for anything but GET and POST requests' do
61
- delete '/foo'
62
- assert_equal 404, last_response.status
63
- options '/foo'
64
- assert_equal 404, last_response.status
65
- head '/foo'
66
- assert_equal 404, last_response.status
67
- put '/foo'
68
- assert_equal 404, last_response.status
67
+ context 'return 404 for anything but GET and POST requests' do
68
+ after do
69
+ last_response.status.should == 404
70
+ end
71
+ it { delete '/foo' }
72
+ it { options '/foo' }
73
+ it { head '/foo' }
74
+ it { put '/foo' }
69
75
  end
70
76
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meerkat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
4
+ version: 0.6.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-11 00:00:00.000000000 Z
12
+ date: 2012-04-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: minitest
16
- requirement: &70099588426600 !ruby/object:Gem::Requirement
15
+ name: rspec
16
+ requirement: &70139880888460 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70099588426600
24
+ version_requirements: *70139880888460
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rack-test
27
- requirement: &70099588426100 !ruby/object:Gem::Requirement
27
+ requirement: &70139880887760 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70099588426100
35
+ version_requirements: *70139880887760
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: thin_async
38
- requirement: &70099588425680 !ruby/object:Gem::Requirement
38
+ requirement: &70139880887100 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70099588425680
46
+ version_requirements: *70139880887100
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: thin-async-test
49
- requirement: &70099588425240 !ruby/object:Gem::Requirement
49
+ requirement: &70139880886400 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *70099588425240
57
+ version_requirements: *70139880886400
58
58
  - !ruby/object:Gem::Dependency
59
- name: em-minitest-spec
60
- requirement: &70099588424820 !ruby/object:Gem::Requirement
59
+ name: pg
60
+ requirement: &70139880885580 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,32 +65,32 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70099588424820
68
+ version_requirements: *70139880885580
69
69
  - !ruby/object:Gem::Dependency
70
- name: multi_json
71
- requirement: &70099588424380 !ruby/object:Gem::Requirement
70
+ name: amqp
71
+ requirement: &70139880884760 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
75
75
  - !ruby/object:Gem::Version
76
76
  version: '0'
77
- type: :runtime
77
+ type: :development
78
78
  prerelease: false
79
- version_requirements: *70099588424380
79
+ version_requirements: *70139880884760
80
80
  - !ruby/object:Gem::Dependency
81
- name: eventmachine
82
- requirement: &70099588423940 !ruby/object:Gem::Requirement
81
+ name: em-hiredis
82
+ requirement: &70139880884020 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
86
86
  - !ruby/object:Gem::Version
87
87
  version: '0'
88
- type: :runtime
88
+ type: :development
89
89
  prerelease: false
90
- version_requirements: *70099588423940
90
+ version_requirements: *70139880884020
91
91
  - !ruby/object:Gem::Dependency
92
- name: em-hiredis
93
- requirement: &70099588423520 !ruby/object:Gem::Requirement
92
+ name: multi_json
93
+ requirement: &70139880883280 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - ! '>='
@@ -98,10 +98,10 @@ dependencies:
98
98
  version: '0'
99
99
  type: :runtime
100
100
  prerelease: false
101
- version_requirements: *70099588423520
101
+ version_requirements: *70139880883280
102
102
  - !ruby/object:Gem::Dependency
103
- name: pg
104
- requirement: &70099588423100 !ruby/object:Gem::Requirement
103
+ name: eventmachine
104
+ requirement: &70139880882700 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - ! '>='
@@ -109,7 +109,7 @@ dependencies:
109
109
  version: '0'
110
110
  type: :runtime
111
111
  prerelease: false
112
- version_requirements: *70099588423100
112
+ version_requirements: *70139880882700
113
113
  description: Requires an evented Ruby dispatcher, like Thin
114
114
  email:
115
115
  - carl.hoerberg@gmail.com
@@ -119,7 +119,6 @@ extra_rdoc_files: []
119
119
  files:
120
120
  - .gitignore
121
121
  - Gemfile
122
- - Gemfile.lock
123
122
  - README.md
124
123
  - Rakefile
125
124
  - examples/Gemfile
@@ -127,12 +126,14 @@ files:
127
126
  - examples/config.ru
128
127
  - examples/views/index.haml
129
128
  - lib/meerkat.rb
129
+ - lib/meerkat/backend/amqp.rb
130
130
  - lib/meerkat/backend/inmemory.rb
131
131
  - lib/meerkat/backend/pg.rb
132
132
  - lib/meerkat/backend/redis.rb
133
133
  - lib/meerkat/rackadapter.rb
134
134
  - lib/meerkat/version.rb
135
135
  - meerkat.gemspec
136
+ - spec/backend/amqp_spec.rb
136
137
  - spec/backend/inmemory_spec.rb
137
138
  - spec/backend/pg_spec.rb
138
139
  - spec/backend/redis_spec.rb
@@ -151,7 +152,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
151
152
  version: '0'
152
153
  segments:
153
154
  - 0
154
- hash: -2331619758487538772
155
+ hash: 3167433476364397664
155
156
  required_rubygems_version: !ruby/object:Gem::Requirement
156
157
  none: false
157
158
  requirements:
@@ -160,14 +161,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
160
161
  version: '0'
161
162
  segments:
162
163
  - 0
163
- hash: -2331619758487538772
164
+ hash: 3167433476364397664
164
165
  requirements: []
165
166
  rubyforge_project: meerkat
166
- rubygems_version: 1.8.10
167
+ rubygems_version: 1.8.17
167
168
  signing_key:
168
169
  specification_version: 3
169
170
  summary: Rack middleware for HTML5 Server-Sent Events, with swappable backends
170
171
  test_files:
172
+ - spec/backend/amqp_spec.rb
171
173
  - spec/backend/inmemory_spec.rb
172
174
  - spec/backend/pg_spec.rb
173
175
  - spec/backend/redis_spec.rb