waffle 0.3.5 → 0.4.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/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +12 -2
- data/Gemfile.lock +36 -0
- data/README.md +44 -4
- data/Rakefile +8 -6
- data/config/waffle.yml +8 -0
- data/lib/waffle.rb +87 -5
- data/lib/waffle/config.rb +39 -26
- data/lib/waffle/encoders/json.rb +7 -12
- data/lib/waffle/encoders/marshal.rb +7 -12
- data/lib/waffle/event.rb +7 -25
- data/lib/waffle/transports/base.rb +28 -0
- data/lib/waffle/transports/rabbitmq.rb +23 -39
- data/lib/waffle/transports/redis.rb +28 -0
- data/lib/waffle/version.rb +1 -3
- data/spec/spec_helper.rb +9 -0
- data/spec/waffle/encoders/json_spec.rb +12 -0
- data/spec/waffle/encoders/marshal_spec.rb +17 -0
- data/spec/waffle/event_spec.rb +23 -0
- data/spec/waffle/transports/rabbitmq_spec.rb +35 -0
- data/spec/waffle/transports/redis_spec.rb +30 -0
- data/spec/waffle_spec.rb +74 -0
- data/waffle.gemspec +8 -9
- metadata +29 -19
- data/lib/waffle/base.rb +0 -17
- data/test/test_config.rb +0 -11
- data/test/test_rabbitmq.rb +0 -20
data/.rspec
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.9.3-p125@waffle --create
|
data/Gemfile
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
3
|
gem 'rake'
|
4
|
-
|
5
|
-
|
4
|
+
|
5
|
+
group :development, :test do
|
6
|
+
gem 'pry'
|
7
|
+
gem 'yajl-ruby', require: 'yajl'
|
8
|
+
gem 'bunny'
|
9
|
+
gem "hiredis", "~> 0.3.1", :platforms => :ruby
|
10
|
+
gem "redis", "~> 2.2.0", require: RUBY_PLATFORM =~ /mingw|mswin/ ? 'redis' : ["redis/connection/hiredis", "redis"]
|
11
|
+
end
|
12
|
+
|
13
|
+
group :test do
|
14
|
+
gem 'rspec'
|
15
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
bunny (0.7.9)
|
5
|
+
coderay (1.0.6)
|
6
|
+
diff-lcs (1.1.3)
|
7
|
+
hiredis (0.3.2)
|
8
|
+
method_source (0.7.1)
|
9
|
+
pry (0.9.9.6)
|
10
|
+
coderay (~> 1.0.5)
|
11
|
+
method_source (~> 0.7.1)
|
12
|
+
slop (>= 2.4.4, < 3)
|
13
|
+
rake (0.9.2.2)
|
14
|
+
redis (2.2.2)
|
15
|
+
rspec (2.10.0)
|
16
|
+
rspec-core (~> 2.10.0)
|
17
|
+
rspec-expectations (~> 2.10.0)
|
18
|
+
rspec-mocks (~> 2.10.0)
|
19
|
+
rspec-core (2.10.1)
|
20
|
+
rspec-expectations (2.10.0)
|
21
|
+
diff-lcs (~> 1.1.3)
|
22
|
+
rspec-mocks (2.10.1)
|
23
|
+
slop (2.4.4)
|
24
|
+
yajl-ruby (1.1.0)
|
25
|
+
|
26
|
+
PLATFORMS
|
27
|
+
ruby
|
28
|
+
|
29
|
+
DEPENDENCIES
|
30
|
+
bunny
|
31
|
+
hiredis (~> 0.3.1)
|
32
|
+
pry
|
33
|
+
rake
|
34
|
+
redis (~> 2.2.0)
|
35
|
+
rspec
|
36
|
+
yajl-ruby
|
data/README.md
CHANGED
@@ -2,13 +2,18 @@
|
|
2
2
|
|
3
3
|
An abstract flow publisher and subscriber.
|
4
4
|
|
5
|
-
[](http://travis-ci.org/undr/waffle)
|
6
6
|
|
7
|
-
|
7
|
+
It supports the following transports:
|
8
8
|
|
9
|
-
|
9
|
+
- RabbitMQ.
|
10
|
+
- Redis.
|
10
11
|
|
11
|
-
|
12
|
+
## Configuration
|
13
|
+
|
14
|
+
Insert in your Gemfile:
|
15
|
+
|
16
|
+
gem 'waffle', :gem => 'git://github.com/undr/waffle.git'
|
12
17
|
|
13
18
|
and create config file:
|
14
19
|
|
@@ -17,8 +22,30 @@ and create config file:
|
|
17
22
|
encoder: marshal
|
18
23
|
url: amqp://anyhost.com:5678
|
19
24
|
|
25
|
+
and load config file:
|
26
|
+
|
27
|
+
Waffle.configure(:path => 'config/waffle.yml')
|
28
|
+
|
29
|
+
You also can configure Waffle programmatically:
|
30
|
+
|
31
|
+
Waffle.configure({
|
32
|
+
:transport => 'redis',
|
33
|
+
:url => 'redis://localhost:6379/0',
|
34
|
+
:encoder => 'json'
|
35
|
+
})
|
36
|
+
|
37
|
+
or:
|
38
|
+
|
39
|
+
Waffle.configure do |config|
|
40
|
+
config.transport = 'redis'
|
41
|
+
config.url = 'redis://localhost:6379/0'
|
42
|
+
config.encoder = 'json'
|
43
|
+
end
|
44
|
+
|
20
45
|
## Usage
|
21
46
|
|
47
|
+
### Event
|
48
|
+
|
22
49
|
When you want to performan event, just insert this code in place, where it must occur:
|
23
50
|
|
24
51
|
Waffle::Event.occurred 'index_page_load'
|
@@ -30,3 +57,16 @@ You can attach meta data to event like this:
|
|
30
57
|
or like this:
|
31
58
|
|
32
59
|
Waffle::Event.occurred 'index_page_load', 'bingo!'
|
60
|
+
|
61
|
+
### Pub/Sub
|
62
|
+
|
63
|
+
Waffle.publish('event.name', message_hash_or_string)
|
64
|
+
|
65
|
+
Waffle.subscribe('event.name') do |message_type, message_hash_or_string|
|
66
|
+
pp message_type
|
67
|
+
pp message_hash_or_string
|
68
|
+
end
|
69
|
+
|
70
|
+
### Reconnect
|
71
|
+
|
72
|
+
Don't care about any reconnects when transport server is down. Waffle just waits for server ready and reconnects automatically.
|
data/Rakefile
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
require 'rake
|
1
|
+
require 'rake'
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../..", __FILE__)
|
3
|
+
Dir[File.join('lib', 'tasks', '**', '*.rake')].each{|file| load file}
|
4
|
+
Bundler::GemHelper.install_tasks
|
2
5
|
|
3
|
-
|
4
|
-
|
5
|
-
end
|
6
|
+
require 'rspec/core'
|
7
|
+
require 'rspec/core/rake_task'
|
6
8
|
|
7
|
-
|
8
|
-
task :default => :
|
9
|
+
RSpec::Core::RakeTask.new(:spec)
|
10
|
+
task :default => [:spec]
|
data/config/waffle.yml
ADDED
data/lib/waffle.rb
CHANGED
@@ -1,15 +1,97 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
2
|
+
require 'rubygems'
|
3
|
+
require 'bundler'
|
4
|
+
environment = defined?(Rails) && Rails.respond_to?(:env) ? Rails.env : (ENV['RACK_ENV'] || 'development')
|
5
|
+
Bundler.require :default, environment.to_sym
|
1
6
|
require 'waffle/version'
|
2
|
-
require '
|
3
|
-
require 'waffle/config'
|
4
|
-
require 'waffle/event'
|
7
|
+
require 'time'
|
5
8
|
|
6
9
|
module Waffle
|
10
|
+
extend self
|
7
11
|
module Transports
|
8
|
-
autoload :
|
12
|
+
autoload :Base, 'waffle/transports/base'
|
13
|
+
autoload :Rabbitmq, 'waffle/transports/rabbitmq' if defined?(Bunny)
|
14
|
+
autoload :Redis, 'waffle/transports/redis' if defined?(::Redis)
|
9
15
|
end
|
10
16
|
|
17
|
+
autoload :Config, 'waffle/config'
|
18
|
+
autoload :Event, 'waffle/event'
|
19
|
+
|
11
20
|
module Encoders
|
12
|
-
autoload :Json, 'waffle/encoders/json'
|
21
|
+
autoload :Json, 'waffle/encoders/json' if defined?(Yajl)
|
13
22
|
autoload :Marshal, 'waffle/encoders/marshal'
|
14
23
|
end
|
24
|
+
|
25
|
+
def reset_config!
|
26
|
+
@configured = false
|
27
|
+
end
|
28
|
+
|
29
|
+
def configure options=nil
|
30
|
+
@configured ||= begin
|
31
|
+
options = {:path => 'config/waffle.yml'} unless options
|
32
|
+
Config.load!(options)
|
33
|
+
true
|
34
|
+
end
|
35
|
+
block_given? ? yield(Config) : Config
|
36
|
+
end
|
37
|
+
|
38
|
+
def publish flow = 'events', message = ''
|
39
|
+
transport.publish(flow, message)
|
40
|
+
rescue *transport.connection_exceptions => e
|
41
|
+
transport.reconnect && retry if transport.ready_to_connect?
|
42
|
+
end
|
43
|
+
|
44
|
+
def subscribe flow = '', &block
|
45
|
+
transport.subscribe(flow, &block)
|
46
|
+
rescue *transport.connection_exceptions => e
|
47
|
+
until transport.reconnect do
|
48
|
+
sleep(config.connection_attempt_timeout)
|
49
|
+
end
|
50
|
+
retry
|
51
|
+
end
|
52
|
+
|
53
|
+
def transport
|
54
|
+
@transport ||= "Waffle::Transports::#{Waffle.config.transport.camelize}".constantize.new
|
55
|
+
end
|
56
|
+
|
57
|
+
def encoder
|
58
|
+
@encoder ||= "Waffle::Encoders::#{Waffle.config.encoder.camelize}".constantize
|
59
|
+
end
|
60
|
+
|
61
|
+
alias :config :configure
|
62
|
+
end
|
63
|
+
|
64
|
+
unless defined?(ActiveSupport::Inflector)
|
65
|
+
class String
|
66
|
+
def constantize
|
67
|
+
names = self.split('::')
|
68
|
+
names.shift if names.empty? || names.first.empty?
|
69
|
+
|
70
|
+
constant = Object
|
71
|
+
names.each do |name|
|
72
|
+
constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
|
73
|
+
end
|
74
|
+
constant
|
75
|
+
end
|
76
|
+
|
77
|
+
def camelize
|
78
|
+
string = sub(/^[a-z\d]*/){$&.capitalize}
|
79
|
+
string.gsub(/(?:_|(\/))([a-z\d]*)/){ "#{$1}#{$2.capitalize}" }.gsub('/', '::')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
unless defined?(ActiveSupport)
|
85
|
+
class Hash
|
86
|
+
def symbolize_keys!
|
87
|
+
keys.each do |key|
|
88
|
+
self[(key.to_sym rescue key) || key] = delete(key)
|
89
|
+
end
|
90
|
+
self
|
91
|
+
end
|
92
|
+
|
93
|
+
def symbolize_keys
|
94
|
+
dup.symbolize_keys!
|
95
|
+
end
|
96
|
+
end
|
15
97
|
end
|
data/lib/waffle/config.rb
CHANGED
@@ -1,44 +1,57 @@
|
|
1
|
-
require 'singleton'
|
2
1
|
require 'yaml'
|
3
2
|
|
4
3
|
module Waffle
|
5
|
-
|
6
|
-
|
4
|
+
module Config
|
5
|
+
extend self
|
6
|
+
attr_accessor :settings, :defaults
|
7
7
|
|
8
|
-
|
8
|
+
@settings = {}
|
9
|
+
@defaults = {}
|
9
10
|
|
10
|
-
def
|
11
|
-
|
11
|
+
def option(name, options = {})
|
12
|
+
defaults[name] = settings[name] = options[:default]
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
end
|
14
|
+
class_eval <<-RUBY
|
15
|
+
def #{name}
|
16
|
+
settings[#{name.inspect}]
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
def #{name}=(value)
|
20
|
+
settings[#{name.inspect}] = value
|
21
|
+
end
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
else
|
25
|
-
@config_hash.merge! loaded_config
|
23
|
+
def #{name}?
|
24
|
+
#{name}
|
26
25
|
end
|
27
|
-
|
26
|
+
RUBY
|
27
|
+
end
|
28
28
|
|
29
|
+
option :url, :default => nil
|
30
|
+
option :encoder, :default => 'json'
|
31
|
+
option :transport, :default => nil
|
32
|
+
option :connection_attempt_timeout, :default => 30
|
33
|
+
|
34
|
+
def load! options=nil
|
35
|
+
options[:path] ? load_from_yaml!(options[:path]) : load_from_hash!(options)
|
36
|
+
self
|
29
37
|
end
|
30
38
|
|
31
|
-
|
39
|
+
def load_from_yaml! filename
|
40
|
+
filename = Rails.root.join(filename) if defined?(Rails)
|
41
|
+
filename = File.expand_path(filename)
|
32
42
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
else
|
37
|
-
super
|
38
|
-
end
|
43
|
+
if File.exists?(filename)
|
44
|
+
settings_hash = YAML.load_file(filename)[environment]
|
45
|
+
@settings = defaults.merge(settings_hash.symbolize_keys) if settings_hash
|
39
46
|
end
|
40
|
-
|
41
47
|
end
|
42
48
|
|
49
|
+
def load_from_hash! options
|
50
|
+
@settings = defaults.merge(options)
|
51
|
+
end
|
52
|
+
|
53
|
+
def environment
|
54
|
+
defined?(Rails) && Rails.respond_to?(:env) ? Rails.env : (ENV['RACK_ENV'] || 'development')
|
55
|
+
end
|
43
56
|
end
|
44
57
|
end
|
data/lib/waffle/encoders/json.rb
CHANGED
@@ -2,20 +2,15 @@ require 'yajl'
|
|
2
2
|
|
3
3
|
module Waffle
|
4
4
|
module Encoders
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
def encode(message = nil)
|
10
|
-
Yajl::Encoder.encode message
|
11
|
-
end
|
12
|
-
|
13
|
-
def decode(message = '')
|
14
|
-
Yajl::Parser.parse message
|
15
|
-
end
|
16
|
-
|
5
|
+
module Json
|
6
|
+
module_function
|
7
|
+
def encode message
|
8
|
+
Yajl::Encoder.encode(message)
|
17
9
|
end
|
18
10
|
|
11
|
+
def decode message
|
12
|
+
Yajl::Parser.parse(message)
|
13
|
+
end
|
19
14
|
end
|
20
15
|
end
|
21
16
|
end
|
@@ -1,19 +1,14 @@
|
|
1
1
|
module Waffle
|
2
2
|
module Encoders
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
def encode(message = nil)
|
8
|
-
::Marshal.dump message
|
9
|
-
end
|
10
|
-
|
11
|
-
def decode(message = '')
|
12
|
-
::Marshal.restore message
|
13
|
-
end
|
14
|
-
|
3
|
+
module Marshal
|
4
|
+
module_function
|
5
|
+
def encode message
|
6
|
+
::Marshal.dump(message)
|
15
7
|
end
|
16
8
|
|
9
|
+
def decode message
|
10
|
+
::Marshal.restore(message)
|
11
|
+
end
|
17
12
|
end
|
18
13
|
end
|
19
14
|
end
|
data/lib/waffle/event.rb
CHANGED
@@ -1,34 +1,16 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
|
3
1
|
module Waffle
|
4
2
|
class Event
|
5
|
-
include Singleton
|
6
|
-
|
7
3
|
class << self
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
alias :occurred :occured
|
13
|
-
end
|
14
|
-
|
15
|
-
def transport
|
16
|
-
@transport ||= Waffle::Base.new eval("Waffle::Transports::#{Waffle::Config.transport.capitalize}").new
|
17
|
-
end
|
4
|
+
def occured(event_name = 'event', event_data = nil)
|
5
|
+
unless event_data.is_a?(Hash)
|
6
|
+
event_data = {'body' => event_data.to_s}
|
7
|
+
end
|
18
8
|
|
19
|
-
|
20
|
-
@encoder ||= eval("Waffle::Encoders::#{Waffle::Config.encoder.capitalize}")
|
21
|
-
end
|
9
|
+
event_data.merge!({'occured_at' => Time.now})
|
22
10
|
|
23
|
-
|
24
|
-
unless event_data.is_a? Hash
|
25
|
-
event_data = {'body' => event_data.to_s}
|
11
|
+
Waffle.publish(event_name, event_data)
|
26
12
|
end
|
27
|
-
|
28
|
-
event_data.merge!({'occured_at' => Time.now})
|
29
|
-
|
30
|
-
transport.publish event_name, encoder.encode(event_data)
|
13
|
+
alias :occurred :occured
|
31
14
|
end
|
32
|
-
|
33
15
|
end
|
34
16
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Waffle
|
2
|
+
module Transports
|
3
|
+
class Base
|
4
|
+
def initialize
|
5
|
+
connect!
|
6
|
+
end
|
7
|
+
|
8
|
+
def ready_to_connect?
|
9
|
+
(Time.now - @last_connection_attempt) > Waffle.config.connection_attempt_timeout
|
10
|
+
end
|
11
|
+
|
12
|
+
def reconnect
|
13
|
+
connect!
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
def connect!
|
18
|
+
@last_connection_attempt = Time.now
|
19
|
+
do_connect
|
20
|
+
rescue
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
def do_connect
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -3,60 +3,44 @@ require 'bunny'
|
|
3
3
|
|
4
4
|
module Waffle
|
5
5
|
module Transports
|
6
|
-
class Rabbitmq
|
7
|
-
|
8
|
-
CONNECTION_ATTEMPT_TIMEOUT = 30
|
9
|
-
|
6
|
+
class Rabbitmq < Base
|
10
7
|
EXCHANGE = 'events'
|
11
8
|
|
12
|
-
@@last_connection_attempt = Time.now
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
@bunny = Bunny.new Waffle::Config.url
|
16
|
-
connect
|
17
|
-
end
|
18
|
-
|
19
|
-
def encoder
|
20
|
-
@encoder ||= eval("Waffle::Encoders::#{Waffle::Config.encoder.capitalize}")
|
21
|
-
end
|
22
|
-
|
23
9
|
def publish(flow = 'events', message = '')
|
24
|
-
|
25
|
-
@exchange = @bunny.exchange EXCHANGE
|
26
|
-
@exchange.publish message, :key => flow
|
27
|
-
rescue
|
28
|
-
if (Time.now - @@last_connection_attempt) > CONNECTION_ATTEMPT_TIMEOUT
|
29
|
-
connect
|
30
|
-
end
|
31
|
-
end
|
10
|
+
exchange.publish(Waffle.encoder.encode(message), :key => flow)
|
32
11
|
end
|
33
12
|
|
34
13
|
def subscribe(flow = 'events')
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
if flow.is_a? Array
|
39
|
-
flow.each{ |f| @queue.bind @exchange, :key => f }
|
14
|
+
if flow.is_a?(Array)
|
15
|
+
flow.each{|f| queue.bind(exchange, :key => f)}
|
40
16
|
else
|
41
|
-
|
17
|
+
queue.bind(exchange, :key => flow)
|
42
18
|
end
|
43
19
|
|
44
|
-
|
45
|
-
yield
|
20
|
+
queue.subscribe do |message|
|
21
|
+
yield(message[:delivery_details][:routing_key], Waffle.encoder.decode(message[:payload]))
|
46
22
|
end
|
47
23
|
end
|
48
24
|
|
25
|
+
def connection_exceptions
|
26
|
+
[Bunny::ServerDownError, Bunny::ConnectionError, Errno::ECONNRESET]
|
27
|
+
end
|
28
|
+
|
49
29
|
private
|
30
|
+
def exchange
|
31
|
+
@exchange ||= @bunny.exchange(EXCHANGE)
|
32
|
+
end
|
50
33
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
@bunny.start
|
55
|
-
rescue
|
56
|
-
nil
|
57
|
-
end
|
58
|
-
end
|
34
|
+
def queue
|
35
|
+
@queue ||= @bunny.queue('', :durable => true, :auto_delete => true)
|
36
|
+
end
|
59
37
|
|
38
|
+
def do_connect
|
39
|
+
@exchange = nil
|
40
|
+
@queue = nil
|
41
|
+
@bunny = Bunny.new(Waffle.config.url)
|
42
|
+
@bunny.start
|
43
|
+
end
|
60
44
|
end
|
61
45
|
end
|
62
46
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Waffle
|
2
|
+
module Transports
|
3
|
+
class Redis < Base
|
4
|
+
attr_reader :db
|
5
|
+
|
6
|
+
def publish(flow = 'events', message = '')
|
7
|
+
db.publish(flow, Waffle.encoder.encode(message))
|
8
|
+
end
|
9
|
+
|
10
|
+
def subscribe(flow = 'events')
|
11
|
+
db.subscribe(*flow) do |on|
|
12
|
+
on.message do |channel, message|
|
13
|
+
yield(channel, Waffle.encoder.decode(message))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def connection_exceptions
|
19
|
+
[Errno::ECONNREFUSED, Errno::ECONNRESET]
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
def do_connect
|
24
|
+
@db = ::Redis.new(:url => Waffle.config.url)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/waffle/version.rb
CHANGED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Waffle::Encoders::Json do
|
4
|
+
let(:message){{"data" => 'message data', "occured_at" => 'DateTime'}}
|
5
|
+
describe '.encode' do
|
6
|
+
specify{Waffle::Encoders::Json.encode(message).should == '{"data":"message data","occured_at":"DateTime"}'}
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '.decode' do
|
10
|
+
specify{Waffle::Encoders::Json.decode('{"data":"message data","occured_at":"DateTime"}').should == message}
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Waffle::Encoders::Marshal do
|
4
|
+
let(:message){{:data => 'message data', :occured_at => 'DateTime'}}
|
5
|
+
let(:marshalized_message){Marshal.dump(message)}
|
6
|
+
describe '.encode' do
|
7
|
+
specify do
|
8
|
+
Waffle::Encoders::Marshal.encode(message).should == marshalized_message
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.decode' do
|
13
|
+
specify do
|
14
|
+
Waffle::Encoders::Marshal.decode(marshalized_message).should == message
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Waffle::Event do
|
4
|
+
describe '.occured' do
|
5
|
+
let(:flow){'event'}
|
6
|
+
let(:now){Time.now}
|
7
|
+
|
8
|
+
before do
|
9
|
+
Time.stub(:now => now)
|
10
|
+
Waffle.should_receive(:publish).with(flow, message)
|
11
|
+
end
|
12
|
+
|
13
|
+
context do
|
14
|
+
let(:message){{"key1" => "value1", "key2" => "value2", "occured_at" => now}}
|
15
|
+
specify{Waffle::Event.occured(flow, {'key1' => 'value1', 'key2' => 'value2'})}
|
16
|
+
end
|
17
|
+
|
18
|
+
context do
|
19
|
+
let(:message){{"body" => "message data", "occured_at" => now}}
|
20
|
+
specify{Waffle::Event.occured(flow, 'message data')}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Waffle::Transports::Rabbitmq
|
4
|
+
def initialize
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Waffle::Transports::Rabbitmq do
|
9
|
+
subject{Waffle::Transports::Rabbitmq.new}
|
10
|
+
|
11
|
+
let(:exchange){mock(:exchange)}
|
12
|
+
|
13
|
+
before do
|
14
|
+
subject.stub(:exchange => exchange)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '.publish' do
|
18
|
+
before{exchange.should_receive(:publish).with('"message"', :key => 'events')}
|
19
|
+
specify{subject.publish('events', 'message')}
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '.subscribe' do
|
23
|
+
let(:queue){mock(:queue, :bind => nil)}
|
24
|
+
|
25
|
+
before do
|
26
|
+
subject.stub(:queue => queue)
|
27
|
+
queue.should_receive(:subscribe).and_yield({
|
28
|
+
:payload => '{"data":"message"}',
|
29
|
+
:delivery_details => {:routing_key => 'event'}
|
30
|
+
})
|
31
|
+
end
|
32
|
+
|
33
|
+
specify{subject.subscribe('events'){}}
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class Waffle::Transports::Redis
|
4
|
+
def initialize
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Waffle::Transports::Redis do
|
9
|
+
subject{Waffle::Transports::Redis.new}
|
10
|
+
|
11
|
+
let(:redis){mock(:redis)}
|
12
|
+
let(:subscription){mock(:subscription)}
|
13
|
+
|
14
|
+
before do
|
15
|
+
subject.stub(:db => redis)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '.publish' do
|
19
|
+
before{redis.should_receive(:publish).with('events', '"message"')}
|
20
|
+
specify{subject.publish('events', 'message')}
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.subscribe' do
|
24
|
+
before do
|
25
|
+
redis.should_receive(:subscribe).with('events').and_yield(subscription)
|
26
|
+
subscription.should_receive(:message).and_yield('event', '{"data":"message"}')
|
27
|
+
end
|
28
|
+
specify{subject.subscribe('events'){}}
|
29
|
+
end
|
30
|
+
end
|
data/spec/waffle_spec.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Waffle do
|
4
|
+
describe ".configure" do
|
5
|
+
after do
|
6
|
+
Waffle.reset_config!
|
7
|
+
end
|
8
|
+
|
9
|
+
context "when no block supplied" do
|
10
|
+
let(:config_hash){{
|
11
|
+
'development' => {
|
12
|
+
'transport' => 'redis',
|
13
|
+
'url' => 'redis://localhost:port/0',
|
14
|
+
'encoder' => 'json'
|
15
|
+
}
|
16
|
+
}}
|
17
|
+
|
18
|
+
before do
|
19
|
+
YAML.stub(:load_file => config_hash)
|
20
|
+
File.stub(:exists? => true)
|
21
|
+
Waffle::Config.stub(:environment => 'development')
|
22
|
+
end
|
23
|
+
|
24
|
+
specify{Waffle.configure.should == Waffle::Config}
|
25
|
+
specify{Waffle.config.should == Waffle::Config}
|
26
|
+
specify{Waffle.config.transport.should == 'redis'}
|
27
|
+
specify{Waffle.config.encoder.should == 'json'}
|
28
|
+
specify{Waffle.config.connection_attempt_timeout.should == 30}
|
29
|
+
specify{Waffle.config.url.should == 'redis://localhost:port/0'}
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when a block is supplied" do
|
33
|
+
before do
|
34
|
+
Waffle.configure do |config|
|
35
|
+
config.transport = 'redis'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
after do
|
40
|
+
Waffle.configure do |config|
|
41
|
+
config.transport = nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
specify{Waffle.config.transport.should == 'redis'}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context do
|
50
|
+
before do
|
51
|
+
Waffle.stub(:transport => transport)
|
52
|
+
end
|
53
|
+
|
54
|
+
let(:transport){mock(:transport)}
|
55
|
+
|
56
|
+
describe '#publish' do
|
57
|
+
let(:args){['flow', 'message']}
|
58
|
+
|
59
|
+
before do
|
60
|
+
transport.should_receive(:publish).with(*args)
|
61
|
+
end
|
62
|
+
|
63
|
+
specify{Waffle.publish(*args)}
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#subscribe' do
|
67
|
+
before do
|
68
|
+
transport.should_receive(:subscribe).with('flow').and_yield
|
69
|
+
end
|
70
|
+
|
71
|
+
specify{Waffle.subscribe('flow'){}}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/waffle.gemspec
CHANGED
@@ -3,18 +3,17 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
require "waffle/version"
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
|
-
s.name
|
6
|
+
s.name = 'waffle'
|
7
7
|
s.version = Waffle::VERSION
|
8
|
+
s.rubyforge_project = "waffle"
|
8
9
|
|
9
|
-
s.homepage = 'http://github.com/
|
10
|
-
s.authors
|
11
|
-
s.email
|
10
|
+
s.homepage = 'http://github.com/undr/waffle'
|
11
|
+
s.authors = ['Alexander Lomakin', 'Andrey Lepeshkin']
|
12
|
+
s.email = ['alexander.lomakin@gmail.com', 'lilipoper@gmail.com']
|
12
13
|
|
13
|
-
s.summary
|
14
|
-
s.description = '
|
14
|
+
s.summary = 'Abstract flow publisher and subscriber'
|
15
|
+
s.description = 'Abstract flow publisher and subscriber'
|
15
16
|
|
16
17
|
s.files = `git ls-files`.split("\n")
|
17
|
-
|
18
|
-
s.add_runtime_dependency 'bunny'
|
19
|
-
s.add_runtime_dependency 'yajl-ruby'
|
18
|
+
s.add_dependency("rake")
|
20
19
|
end
|
metadata
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: waffle
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Alexander Lomakin
|
9
|
+
- Andrey Lepeshkin
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2012-
|
13
|
+
date: 2012-07-06 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement:
|
16
|
+
name: rake
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
17
18
|
none: false
|
18
19
|
requirements:
|
19
20
|
- - ! '>='
|
@@ -21,40 +22,46 @@ dependencies:
|
|
21
22
|
version: '0'
|
22
23
|
type: :runtime
|
23
24
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: yajl-ruby
|
27
|
-
requirement: &75330060 !ruby/object:Gem::Requirement
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
28
26
|
none: false
|
29
27
|
requirements:
|
30
28
|
- - ! '>='
|
31
29
|
- !ruby/object:Gem::Version
|
32
30
|
version: '0'
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
email: alexander.lomakin@gmail.com
|
31
|
+
description: Abstract flow publisher and subscriber
|
32
|
+
email:
|
33
|
+
- alexander.lomakin@gmail.com
|
34
|
+
- lilipoper@gmail.com
|
38
35
|
executables: []
|
39
36
|
extensions: []
|
40
37
|
extra_rdoc_files: []
|
41
38
|
files:
|
39
|
+
- .rspec
|
40
|
+
- .rvmrc
|
42
41
|
- .travis.yml
|
43
42
|
- Gemfile
|
43
|
+
- Gemfile.lock
|
44
44
|
- README.md
|
45
45
|
- Rakefile
|
46
|
+
- config/waffle.yml
|
46
47
|
- lib/waffle.rb
|
47
|
-
- lib/waffle/base.rb
|
48
48
|
- lib/waffle/config.rb
|
49
49
|
- lib/waffle/encoders/json.rb
|
50
50
|
- lib/waffle/encoders/marshal.rb
|
51
51
|
- lib/waffle/event.rb
|
52
|
+
- lib/waffle/transports/base.rb
|
52
53
|
- lib/waffle/transports/rabbitmq.rb
|
54
|
+
- lib/waffle/transports/redis.rb
|
53
55
|
- lib/waffle/version.rb
|
54
|
-
-
|
55
|
-
-
|
56
|
+
- spec/spec_helper.rb
|
57
|
+
- spec/waffle/encoders/json_spec.rb
|
58
|
+
- spec/waffle/encoders/marshal_spec.rb
|
59
|
+
- spec/waffle/event_spec.rb
|
60
|
+
- spec/waffle/transports/rabbitmq_spec.rb
|
61
|
+
- spec/waffle/transports/redis_spec.rb
|
62
|
+
- spec/waffle_spec.rb
|
56
63
|
- waffle.gemspec
|
57
|
-
homepage: http://github.com/
|
64
|
+
homepage: http://github.com/undr/waffle
|
58
65
|
licenses: []
|
59
66
|
post_install_message:
|
60
67
|
rdoc_options: []
|
@@ -66,6 +73,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
66
73
|
- - ! '>='
|
67
74
|
- !ruby/object:Gem::Version
|
68
75
|
version: '0'
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
hash: 2130519817389681143
|
69
79
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
80
|
none: false
|
71
81
|
requirements:
|
@@ -73,8 +83,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
73
83
|
- !ruby/object:Gem::Version
|
74
84
|
version: '0'
|
75
85
|
requirements: []
|
76
|
-
rubyforge_project:
|
77
|
-
rubygems_version: 1.8.
|
86
|
+
rubyforge_project: waffle
|
87
|
+
rubygems_version: 1.8.24
|
78
88
|
signing_key:
|
79
89
|
specification_version: 3
|
80
90
|
summary: Abstract flow publisher and subscriber
|
data/lib/waffle/base.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
module Waffle
|
2
|
-
class Base
|
3
|
-
|
4
|
-
def initialize(transport = nil)
|
5
|
-
@transport = transport
|
6
|
-
end
|
7
|
-
|
8
|
-
def publish(flow = 'events', message = '')
|
9
|
-
@transport.publish flow, message
|
10
|
-
end
|
11
|
-
|
12
|
-
def subscribe(flow = '', &block)
|
13
|
-
@transport.subscribe flow, &block
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|
data/test/test_config.rb
DELETED
data/test/test_rabbitmq.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
require 'mocha'
|
3
|
-
require 'bunny'
|
4
|
-
require 'waffle/transports/rabbitmq'
|
5
|
-
|
6
|
-
class RabbitmqTest < Test::Unit::TestCase
|
7
|
-
|
8
|
-
def test_publish
|
9
|
-
Bunny.setup nil
|
10
|
-
Bunny::Exchange.any_instance.stubs(:publish).returns(nil)
|
11
|
-
assert_equal nil, Waffle::Transports::Rabbitmq.new.publish('events', 'message')
|
12
|
-
end
|
13
|
-
|
14
|
-
def test_subscribe
|
15
|
-
Bunny.setup nil
|
16
|
-
Bunny::Queue.any_instance.stubs(:subscribe).returns(nil)
|
17
|
-
assert_equal nil, Waffle::Transports::Rabbitmq.new.subscribe{ |m| puts m }
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|