announcer 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/config/defaults.yml +13 -0
- data/lib/ribbon/event_bus.rb +37 -0
- data/lib/ribbon/event_bus/config.rb +132 -0
- data/lib/ribbon/event_bus/errors.rb +55 -0
- data/lib/ribbon/event_bus/event.rb +93 -0
- data/lib/ribbon/event_bus/instance.rb +160 -0
- data/lib/ribbon/event_bus/mixins.rb +7 -0
- data/lib/ribbon/event_bus/mixins/has_config.rb +45 -0
- data/lib/ribbon/event_bus/mixins/has_instance.rb +13 -0
- data/lib/ribbon/event_bus/mixins/serializable.rb +183 -0
- data/lib/ribbon/event_bus/plugins.rb +6 -0
- data/lib/ribbon/event_bus/plugins/logging_plugin.rb +68 -0
- data/lib/ribbon/event_bus/plugins/plugin.rb +22 -0
- data/lib/ribbon/event_bus/publishers.rb +54 -0
- data/lib/ribbon/event_bus/publishers/async_resque_publisher.rb +81 -0
- data/lib/ribbon/event_bus/publishers/proc_publisher.rb +22 -0
- data/lib/ribbon/event_bus/publishers/publisher.rb +30 -0
- data/lib/ribbon/event_bus/publishers/remote_resque_publisher.rb +81 -0
- data/lib/ribbon/event_bus/publishers/resque_publisher.rb +87 -0
- data/lib/ribbon/event_bus/publishers/subscriptions_publisher.rb +8 -0
- data/lib/ribbon/event_bus/subscription.rb +165 -0
- data/lib/ribbon/event_bus/version.rb +5 -0
- metadata +212 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module Ribbon::EventBus
|
2
|
+
module Publishers
|
3
|
+
class ProcPublisher < Publisher
|
4
|
+
def initialize(instance=nil, &block)
|
5
|
+
super
|
6
|
+
|
7
|
+
raise Errors::MissingProcError unless block_given?
|
8
|
+
raise Errors::InvalidArityError, 'Proc arity must be 1' unless block.arity == 1
|
9
|
+
@_block = block
|
10
|
+
end
|
11
|
+
|
12
|
+
def new(instance=nil)
|
13
|
+
self.class.new(instance, &@_block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def publish(event)
|
17
|
+
super
|
18
|
+
@_block.call(event)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Ribbon::EventBus
|
2
|
+
module Publishers
|
3
|
+
class Publisher
|
4
|
+
include Mixins::HasInstance
|
5
|
+
include Mixins::HasConfig
|
6
|
+
config_key :publishers
|
7
|
+
|
8
|
+
def initialize(instance=nil, params={})
|
9
|
+
@instance = instance
|
10
|
+
@_params = params
|
11
|
+
end
|
12
|
+
|
13
|
+
def config
|
14
|
+
@__config ||= super.merge_hash!(@_params)
|
15
|
+
end
|
16
|
+
|
17
|
+
###
|
18
|
+
# #publish(event)
|
19
|
+
#
|
20
|
+
# This method should be overridden by a subclass. Make sure to call "super"
|
21
|
+
# so that proper sanity checks can be performed.
|
22
|
+
###
|
23
|
+
def publish(event)
|
24
|
+
unless event.instance == instance
|
25
|
+
raise Errors::PublisherError, "Event for different instance"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'redis'
|
3
|
+
require 'redis/namespace'
|
4
|
+
|
5
|
+
module Ribbon::EventBus
|
6
|
+
module Publishers
|
7
|
+
class RemoteResquePublisher < Publisher
|
8
|
+
config_key :remote_resque
|
9
|
+
|
10
|
+
def publish(event)
|
11
|
+
super
|
12
|
+
|
13
|
+
# Based on Resque 1.25.2
|
14
|
+
|
15
|
+
# Resque call stack:
|
16
|
+
# -> Resque.enqueue(klass, *args)
|
17
|
+
# -> Resque.enqueue_to(queue, klass, *args)
|
18
|
+
# -> Job.create(queue, klass, *args)
|
19
|
+
# -> Resque.push(queue, class: klass.to_s, args: args)
|
20
|
+
|
21
|
+
# These should be the same as the args passed to Resque.enqueue in
|
22
|
+
# ResquePublisher#publish(event).
|
23
|
+
args = [
|
24
|
+
event.serialize
|
25
|
+
]
|
26
|
+
|
27
|
+
enqueue_to(config.queue.to_s, Publishers::ResquePublisher::PublisherJob, *args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def redis
|
31
|
+
@redis ||= _redis
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
##########################################################################
|
37
|
+
# Methods copied from Resque v1.25.2
|
38
|
+
##########################################################################
|
39
|
+
|
40
|
+
def enqueue_to(queue, klass, *args)
|
41
|
+
# This is a functionality copy, not a direct code copy.
|
42
|
+
# Here, I'm skipping the call to Job.create(queue, klass, *args) and
|
43
|
+
# calling push directly.
|
44
|
+
push(queue, class: klass.to_s, args: args)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Resque::push(queue, items)
|
48
|
+
def push(queue, item)
|
49
|
+
redis.pipelined do
|
50
|
+
watch_queue(queue)
|
51
|
+
redis.rpush "queue:#{queue}", encode(item)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Resque::watch_queue
|
56
|
+
def watch_queue(queue)
|
57
|
+
redis.sadd(:queues, queue.to_s)
|
58
|
+
end
|
59
|
+
|
60
|
+
def encode(object)
|
61
|
+
# This one we can call directly.
|
62
|
+
Resque.encode(object)
|
63
|
+
end
|
64
|
+
|
65
|
+
##########################################################################
|
66
|
+
# Helper Methods
|
67
|
+
##########################################################################
|
68
|
+
|
69
|
+
def _redis
|
70
|
+
if config.redis?
|
71
|
+
config.redis
|
72
|
+
elsif config.redis_url?
|
73
|
+
redis = Redis.connect(url: config.redis_url, thread_safe: true)
|
74
|
+
Redis::Namespace.new(config.redis_namespace.to_sym, redis: redis)
|
75
|
+
else
|
76
|
+
raise Errors::RemoteResquePublisherError, "missing redis configuration"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'resque'
|
2
|
+
|
3
|
+
module Ribbon::EventBus
|
4
|
+
module Publishers
|
5
|
+
class ResquePublisher < Publisher
|
6
|
+
config_key :resque
|
7
|
+
|
8
|
+
def initialize(instance=nil, params={})
|
9
|
+
super
|
10
|
+
_disallow_multiple_per_instance
|
11
|
+
end
|
12
|
+
|
13
|
+
def publish(event)
|
14
|
+
super
|
15
|
+
|
16
|
+
unless event.subscriptions.empty?
|
17
|
+
PublisherJob.set_queue(config.publisher_queue.to_sym)
|
18
|
+
Resque.enqueue(PublisherJob, event.serialize)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def subscription_queue_formatter
|
23
|
+
self.class.subscription_queue_formatter(config)
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def subscription_queue_formatter(config)
|
28
|
+
if config.subscription_queue_formatter?
|
29
|
+
formatter = config.subscription_queue_formatter
|
30
|
+
case formatter
|
31
|
+
when Array
|
32
|
+
formatter.last
|
33
|
+
when Proc
|
34
|
+
formatter
|
35
|
+
else
|
36
|
+
raise Errors::PublisherError, "Invalid subscription_queue_formatter: #{formatter.inspect}"
|
37
|
+
end
|
38
|
+
else
|
39
|
+
lambda { |subscription| "subscriptions_p#{subscription.priority}" }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end # Class Methods
|
43
|
+
|
44
|
+
module PublisherJob
|
45
|
+
def self.set_queue(queue)
|
46
|
+
@queue = queue
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.perform(serialized_event, publisher_name=:resque)
|
50
|
+
event = Event.deserialize(serialized_event)
|
51
|
+
instance = event.instance
|
52
|
+
|
53
|
+
publisher = instance.find_publisher(publisher_name)
|
54
|
+
raise Errors::PublisherError, 'No ResquePublisher found' unless publisher
|
55
|
+
queue_formatter = publisher.subscription_queue_formatter
|
56
|
+
|
57
|
+
instance.plugins.perform(:resque_publish, event) do |event|
|
58
|
+
event.subscriptions.each { |s|
|
59
|
+
SubscriptionJob.set_queue(queue_formatter.call(s).to_sym)
|
60
|
+
Resque.enqueue(SubscriptionJob, s.serialize, event.serialize)
|
61
|
+
}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end # PublisherJob
|
65
|
+
|
66
|
+
module SubscriptionJob
|
67
|
+
def self.set_queue(queue)
|
68
|
+
@queue = queue
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.perform(serialized_sub, serialized_event)
|
72
|
+
subscription = Subscription.deserialize(serialized_sub)
|
73
|
+
event = Event.deserialize(serialized_event)
|
74
|
+
subscription.handle(event)
|
75
|
+
end
|
76
|
+
end # SubscriptionJob
|
77
|
+
|
78
|
+
private
|
79
|
+
def _disallow_multiple_per_instance
|
80
|
+
if instance.has_publisher?(:resque)
|
81
|
+
raise Errors::PublisherError,
|
82
|
+
"cannot have multiple ResquePublishers in an EventBus instance"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'digest'
|
2
|
+
|
3
|
+
module Ribbon::EventBus
|
4
|
+
class Subscription
|
5
|
+
include Mixins::HasInstance
|
6
|
+
include Mixins::HasConfig
|
7
|
+
include Mixins::Serializable
|
8
|
+
|
9
|
+
config_key :subscriptions
|
10
|
+
serialize_with :instance, :identifier
|
11
|
+
|
12
|
+
attr_reader :name
|
13
|
+
attr_reader :event_name
|
14
|
+
attr_reader :priority
|
15
|
+
attr_reader :identifier
|
16
|
+
|
17
|
+
def initialize(event_name, params={}, &block)
|
18
|
+
@event_name = event_name.to_sym
|
19
|
+
@_block = block
|
20
|
+
|
21
|
+
_evaluate_params(params)
|
22
|
+
|
23
|
+
@identifier = _generate_identifier
|
24
|
+
|
25
|
+
if instance.find_subscription(identifier)
|
26
|
+
raise Errors::DuplicateIdentifierError, "give this subscription a unique name"
|
27
|
+
else
|
28
|
+
instance._register_subscription(self)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.load_from_serialized(instance, identifier)
|
33
|
+
instance.find_subscription(identifier)
|
34
|
+
end
|
35
|
+
|
36
|
+
def handle(event)
|
37
|
+
raise Errors::UnexpectedEventError, 'wrong name' unless event.name == event_name
|
38
|
+
raise Errors::UnexpectedEventError, 'wrong instance' unless event.instance == instance
|
39
|
+
|
40
|
+
plugins.perform(:subscription, self, event) { |subscription, event|
|
41
|
+
@_block.call(event)
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
"Subscription(on #{event_name}: #{name || _path})"
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def _path
|
52
|
+
@__path ||= _determine_path
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Determines the file path of the ruby code defining the subscription.
|
57
|
+
# It's important that this is called from within the initializer to get the
|
58
|
+
# desired effect.
|
59
|
+
def _determine_path
|
60
|
+
path = File.expand_path('../..', __FILE__)
|
61
|
+
|
62
|
+
# Will be something like:
|
63
|
+
# "/path/to/file.rb:47:in `method_name'"
|
64
|
+
non_event_bus_caller = caller.find { |c| !c.start_with?(path) }
|
65
|
+
|
66
|
+
unless non_event_bus_caller
|
67
|
+
# This is not expected to occur.
|
68
|
+
raise Errors::SubscriptionError, "Could not find non-EventBus caller"
|
69
|
+
end
|
70
|
+
|
71
|
+
non_event_bus_caller
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# Generates a unique identifier for this subscription which will be used to
|
76
|
+
# "serialize" it.
|
77
|
+
#
|
78
|
+
# The goal here is to generate a identifier that is the same across different
|
79
|
+
# processes and servers and that ideally changes infrequently between
|
80
|
+
# application versions, but when it does change, it should do so predictably.
|
81
|
+
def _generate_identifier
|
82
|
+
# Cut off everything from the line number onward. That way, the identifier
|
83
|
+
# does not change when the subscription block moves to a different line.
|
84
|
+
index = _path.rindex(/:\d+:/) - 1
|
85
|
+
path = _path[0..index]
|
86
|
+
|
87
|
+
raise Errors::SubscriptionError, "Invalid path: #{path}" unless File.exists?(path)
|
88
|
+
|
89
|
+
Digest::MD5.hexdigest("#{path}:#{event_name}:#{name}").to_sym
|
90
|
+
end
|
91
|
+
|
92
|
+
def _symbol_to_priority(sym)
|
93
|
+
(@__symbol_to_priority_map ||= _generate_priority_shortcut_map)[sym]
|
94
|
+
end
|
95
|
+
|
96
|
+
def _generate_priority_shortcut_map(max_priority=config.max_priority)
|
97
|
+
{}.tap { |map|
|
98
|
+
map.merge!(highest: 1, lowest: max_priority)
|
99
|
+
map[:medium] = (map[:lowest] / 2.0).ceil
|
100
|
+
map[:high] = (map[:medium] / 2.0).ceil
|
101
|
+
map[:low] = ((map[:lowest] + map[:medium]) / 2.0).ceil
|
102
|
+
}.freeze
|
103
|
+
end
|
104
|
+
|
105
|
+
############################################################################
|
106
|
+
# Parameter Evaluation Logic
|
107
|
+
#
|
108
|
+
# This evaluates the parameters passed to the initializer.
|
109
|
+
############################################################################
|
110
|
+
|
111
|
+
###
|
112
|
+
# Root evaluation method.
|
113
|
+
###
|
114
|
+
def _evaluate_params(params)
|
115
|
+
@instance = params[:instance]
|
116
|
+
@name = params[:name].to_s
|
117
|
+
@priority = _evaluate_priority(params[:priority])
|
118
|
+
end
|
119
|
+
|
120
|
+
###
|
121
|
+
# Priority evaluation
|
122
|
+
###
|
123
|
+
def _evaluate_priority(priority)
|
124
|
+
case priority
|
125
|
+
when Integer
|
126
|
+
_evaluate_priority_int(priority)
|
127
|
+
when String, Symbol
|
128
|
+
_evaluate_priority_symbol(priority.to_sym)
|
129
|
+
when NilClass
|
130
|
+
_evaluate_priority_nil
|
131
|
+
else
|
132
|
+
raise Errors::InvalidPriorityError, priority.inspect
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Evaluate an integer as a priority.
|
137
|
+
def _evaluate_priority_int(int)
|
138
|
+
raise Errors::InvalidPriorityError, int unless int > 0 && int <= config.max_priority
|
139
|
+
int
|
140
|
+
end
|
141
|
+
|
142
|
+
# Evaluate a symbol as a priority.
|
143
|
+
def _evaluate_priority_symbol(sym)
|
144
|
+
if (priority = _symbol_to_priority(sym))
|
145
|
+
_evaluate_priority(priority)
|
146
|
+
else
|
147
|
+
raise Errors::InvalidPriorityError, sym.inspect
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Evaluate nil as a priority.
|
152
|
+
def _evaluate_priority_nil
|
153
|
+
# Need to specify value explicitly here, otherwise in the call to
|
154
|
+
# _evaluate_priority, the case statement won't recognize it as a Symbol.
|
155
|
+
# That's because when calls Symbol::=== to evaluate a match.
|
156
|
+
priority = config.default_priority
|
157
|
+
|
158
|
+
if priority
|
159
|
+
_evaluate_priority(priority)
|
160
|
+
else
|
161
|
+
raise Errors::InvalidPriorityError, priority.inspect
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end # Event
|
165
|
+
end # Ribbon::EventBus
|
metadata
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: announcer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Robert Honer
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-10-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ribbon-plugins
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.2'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.2.4
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.2'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.2.4
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: celluloid
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 0.17.2
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 0.17.2
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rails
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 4.0.13
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: 4.0.13
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: sqlite3
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: redis
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ">="
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: redis-namespace
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: resque
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.25.2
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: 1.25.2
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: mock_redis
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: rspec
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: rspec-rails
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
type: :development
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
159
|
+
description: An asynchronous event bus for Ruby.
|
160
|
+
email:
|
161
|
+
- robert@ribbonpayments.com
|
162
|
+
executables: []
|
163
|
+
extensions: []
|
164
|
+
extra_rdoc_files: []
|
165
|
+
files:
|
166
|
+
- config/defaults.yml
|
167
|
+
- lib/ribbon/event_bus.rb
|
168
|
+
- lib/ribbon/event_bus/config.rb
|
169
|
+
- lib/ribbon/event_bus/errors.rb
|
170
|
+
- lib/ribbon/event_bus/event.rb
|
171
|
+
- lib/ribbon/event_bus/instance.rb
|
172
|
+
- lib/ribbon/event_bus/mixins.rb
|
173
|
+
- lib/ribbon/event_bus/mixins/has_config.rb
|
174
|
+
- lib/ribbon/event_bus/mixins/has_instance.rb
|
175
|
+
- lib/ribbon/event_bus/mixins/serializable.rb
|
176
|
+
- lib/ribbon/event_bus/plugins.rb
|
177
|
+
- lib/ribbon/event_bus/plugins/logging_plugin.rb
|
178
|
+
- lib/ribbon/event_bus/plugins/plugin.rb
|
179
|
+
- lib/ribbon/event_bus/publishers.rb
|
180
|
+
- lib/ribbon/event_bus/publishers/async_resque_publisher.rb
|
181
|
+
- lib/ribbon/event_bus/publishers/proc_publisher.rb
|
182
|
+
- lib/ribbon/event_bus/publishers/publisher.rb
|
183
|
+
- lib/ribbon/event_bus/publishers/remote_resque_publisher.rb
|
184
|
+
- lib/ribbon/event_bus/publishers/resque_publisher.rb
|
185
|
+
- lib/ribbon/event_bus/publishers/subscriptions_publisher.rb
|
186
|
+
- lib/ribbon/event_bus/subscription.rb
|
187
|
+
- lib/ribbon/event_bus/version.rb
|
188
|
+
homepage: http://github.com/ribbon/event_bus
|
189
|
+
licenses:
|
190
|
+
- BSD
|
191
|
+
metadata: {}
|
192
|
+
post_install_message:
|
193
|
+
rdoc_options: []
|
194
|
+
require_paths:
|
195
|
+
- lib
|
196
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '0'
|
201
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
202
|
+
requirements:
|
203
|
+
- - ">="
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: '0'
|
206
|
+
requirements: []
|
207
|
+
rubyforge_project:
|
208
|
+
rubygems_version: 2.4.3
|
209
|
+
signing_key:
|
210
|
+
specification_version: 4
|
211
|
+
summary: An asynchronous event bus for Ruby.
|
212
|
+
test_files: []
|