meerkat 0.4.5 → 0.6.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 +51 -24
- data/lib/meerkat.rb +7 -7
- data/lib/meerkat/backend/amqp.rb +32 -0
- data/lib/meerkat/backend/pg.rb +5 -1
- data/lib/meerkat/rackadapter.rb +8 -9
- data/lib/meerkat/version.rb +1 -1
- data/meerkat.gemspec +5 -4
- data/spec/backend/amqp_spec.rb +34 -0
- data/spec/backend/inmemory_spec.rb +23 -21
- data/spec/backend/pg_spec.rb +30 -24
- data/spec/backend/redis_spec.rb +17 -22
- data/spec/meerkat_spec.rb +35 -29
- metadata +34 -32
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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/
|
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
|
-
|
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('
|
85
|
+
multiSource.addEventListener('foo.bar', function(e) {
|
62
86
|
// Do something
|
63
87
|
}, false);
|
64
|
-
multiSource.addEventListener('
|
88
|
+
multiSource.addEventListener('foo.foo', function(e) {
|
65
89
|
// Do something
|
66
90
|
}, false);
|
67
91
|
```
|
68
92
|
|
69
|
-
To push things from the
|
93
|
+
To push things from the server:
|
70
94
|
|
71
95
|
```ruby
|
72
|
-
Meerkat.publish "
|
73
|
-
Meerkat.publish "
|
74
|
-
Meerkat.publish "
|
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
|
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
|
|
data/lib/meerkat.rb
CHANGED
@@ -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(
|
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(
|
16
|
+
@backend.publish(topic, json)
|
18
17
|
end
|
19
18
|
|
20
|
-
def subscribe(
|
21
|
-
|
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
|
data/lib/meerkat/backend/pg.rb
CHANGED
@@ -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
|
-
|
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
|
|
data/lib/meerkat/rackadapter.rb
CHANGED
@@ -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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
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"
|
data/lib/meerkat/version.rb
CHANGED
data/meerkat.gemspec
CHANGED
@@ -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 "
|
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
|
-
|
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
|
6
|
-
|
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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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 =
|
32
|
-
|
32
|
+
sid = subject.subscribe 'route' do |topic, msg| end
|
33
|
+
subject.unsubscribe sid
|
34
|
+
EM.stop
|
33
35
|
end
|
34
36
|
end
|
data/spec/backend/pg_spec.rb
CHANGED
@@ -1,57 +1,63 @@
|
|
1
|
-
require '
|
2
|
-
require 'em/minitest/spec'
|
1
|
+
require 'eventmachine'
|
3
2
|
require './lib/meerkat/backend/pg'
|
4
3
|
|
5
4
|
describe 'Postgres backend' do
|
6
|
-
|
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
|
-
|
9
|
-
|
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
|
-
|
14
|
-
|
15
|
-
|
22
|
+
subject.subscribe '/foo/*' do |topic, msg|
|
23
|
+
topic.should == '/foo/bar'
|
24
|
+
msg.should == 'messsage'
|
16
25
|
done!
|
17
26
|
end
|
18
|
-
|
19
|
-
wait!
|
27
|
+
subject.publish '/foo/bar', 'messsage'
|
20
28
|
end
|
21
29
|
|
22
30
|
it 'can subscribe to wildcard' do
|
23
|
-
|
24
|
-
|
31
|
+
subject.subscribe '*' do |topic, msg|
|
32
|
+
msg.should == 'messsage'
|
25
33
|
done!
|
26
34
|
end
|
27
|
-
|
28
|
-
wait!
|
35
|
+
subject.publish '/', 'messsage'
|
29
36
|
end
|
30
37
|
|
31
38
|
it 'can publish and subscribe' do
|
32
|
-
|
33
|
-
|
39
|
+
subject.subscribe '/' do |topic, msg|
|
40
|
+
msg.should == 'messsage'
|
34
41
|
done!
|
35
42
|
end
|
36
|
-
|
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
|
-
|
49
|
+
subject.subscribe '/' do |topic, msg|
|
44
50
|
j += 1
|
45
|
-
|
51
|
+
msg.should == 'messsage'
|
46
52
|
done! if j == i
|
47
53
|
end
|
48
|
-
i.times {
|
49
|
-
wait!
|
54
|
+
i.times { subject.publish '/', 'messsage' }
|
50
55
|
end
|
51
56
|
|
52
57
|
it 'can unsubscribe' do
|
53
|
-
sid =
|
54
|
-
|
58
|
+
sid = subject.subscribe 'route' do |topic, msg| end
|
59
|
+
subject.unsubscribe sid
|
60
|
+
done!
|
55
61
|
end
|
56
62
|
end
|
57
63
|
|
data/spec/backend/redis_spec.rb
CHANGED
@@ -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
|
6
|
-
|
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
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
16
|
+
subject.publish '/foo/bar', 'messsage'
|
17
17
|
}
|
18
|
-
wait!
|
19
18
|
end
|
20
19
|
|
21
20
|
it 'can publish and subscribe' do
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
done!
|
21
|
+
subject.subscribe '/' do |topic, msg|
|
22
|
+
msg.should == 'messsage'
|
23
|
+
EM.stop
|
26
24
|
end
|
27
25
|
EM.next_tick {
|
28
|
-
|
26
|
+
subject.publish '/', 'messsage'
|
29
27
|
}
|
30
|
-
wait!
|
31
28
|
end
|
32
29
|
|
33
30
|
it 'can unsubscribe' do
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
|
data/spec/meerkat_spec.rb
CHANGED
@@ -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
|
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 '
|
23
|
+
it 'returns status 200 and content-type text/event-stream' do
|
25
24
|
get '/'
|
26
|
-
|
27
|
-
|
25
|
+
last_response.status.should == 200
|
26
|
+
last_response.headers['Content-Type'].should == 'text/event-stream'
|
28
27
|
end
|
29
28
|
|
30
|
-
it '
|
29
|
+
it 'start with a retry value' do
|
31
30
|
get '/'
|
32
|
-
|
31
|
+
last_response.body.lines.first.should == "retry: 3000\n"
|
33
32
|
end
|
34
33
|
|
35
|
-
it '
|
34
|
+
it 'periodically emits a comment to keep alive the connection' do
|
36
35
|
get '/'
|
37
|
-
|
36
|
+
last_response.body.split("\n")[1].should == ":"
|
38
37
|
end
|
39
|
-
|
40
|
-
it '
|
41
|
-
|
42
|
-
|
43
|
-
Meerkat.backend =
|
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
|
-
|
47
|
-
|
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 '
|
57
|
+
it 'returns error 400 when there is no "json" POST parameters' do
|
51
58
|
post '/', :foo => 'bar'
|
52
|
-
|
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
|
-
|
64
|
+
last_response.status.should == 400
|
58
65
|
end
|
59
66
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
+
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:
|
12
|
+
date: 2012-04-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
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: *
|
24
|
+
version_requirements: *70139880888460
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rack-test
|
27
|
-
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: *
|
35
|
+
version_requirements: *70139880887760
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: thin_async
|
38
|
-
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: *
|
46
|
+
version_requirements: *70139880887100
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: thin-async-test
|
49
|
-
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: *
|
57
|
+
version_requirements: *70139880886400
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
|
-
name:
|
60
|
-
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: *
|
68
|
+
version_requirements: *70139880885580
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
71
|
-
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: :
|
77
|
+
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70139880884760
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
|
-
name:
|
82
|
-
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: :
|
88
|
+
type: :development
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70139880884020
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
|
-
name:
|
93
|
-
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: *
|
101
|
+
version_requirements: *70139880883280
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
|
-
name:
|
104
|
-
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: *
|
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:
|
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:
|
164
|
+
hash: 3167433476364397664
|
164
165
|
requirements: []
|
165
166
|
rubyforge_project: meerkat
|
166
|
-
rubygems_version: 1.8.
|
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
|