ably 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ably.gemspec +1 -0
- data/lib/ably/auth.rb +9 -13
- data/lib/ably/models/idiomatic_ruby_wrapper.rb +27 -39
- data/lib/ably/modules/conversions.rb +31 -10
- data/lib/ably/modules/enum.rb +201 -0
- data/lib/ably/modules/event_emitter.rb +81 -0
- data/lib/ably/modules/event_machine_helpers.rb +21 -0
- data/lib/ably/modules/http_helpers.rb +13 -0
- data/lib/ably/modules/state.rb +67 -0
- data/lib/ably/realtime.rb +6 -1
- data/lib/ably/realtime/channel.rb +117 -56
- data/lib/ably/realtime/client.rb +7 -50
- data/lib/ably/realtime/client/incoming_message_dispatcher.rb +116 -0
- data/lib/ably/realtime/client/outgoing_message_dispatcher.rb +63 -0
- data/lib/ably/realtime/connection.rb +97 -14
- data/lib/ably/realtime/models/error_info.rb +3 -2
- data/lib/ably/realtime/models/message.rb +28 -3
- data/lib/ably/realtime/models/nil_channel.rb +21 -0
- data/lib/ably/realtime/models/protocol_message.rb +35 -27
- data/lib/ably/rest/client.rb +39 -23
- data/lib/ably/rest/middleware/external_exceptions.rb +1 -1
- data/lib/ably/rest/middleware/parse_json.rb +7 -2
- data/lib/ably/rest/middleware/parse_message_pack.rb +23 -0
- data/lib/ably/rest/models/paged_resource.rb +4 -4
- data/lib/ably/util/pub_sub.rb +32 -0
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/channel_spec.rb +1 -0
- data/spec/acceptance/realtime/message_spec.rb +136 -0
- data/spec/acceptance/rest/base_spec.rb +51 -1
- data/spec/acceptance/rest/presence_spec.rb +7 -2
- data/spec/integration/modules/state_spec.rb +66 -0
- data/spec/{unit → integration/rest}/auth.rb +0 -0
- data/spec/support/api_helper.rb +5 -2
- data/spec/support/protocol_msgbus_helper.rb +29 -0
- data/spec/support/test_app.rb +14 -3
- data/spec/unit/{conversions.rb → modules/conversions_spec.rb} +1 -1
- data/spec/unit/modules/enum_spec.rb +263 -0
- data/spec/unit/modules/event_emitter_spec.rb +81 -0
- data/spec/unit/modules/pub_sub_spec.rb +74 -0
- data/spec/unit/realtime/channel_spec.rb +27 -0
- data/spec/unit/realtime/client_spec.rb +8 -0
- data/spec/unit/realtime/connection_spec.rb +40 -0
- data/spec/unit/realtime/error_info_spec.rb +9 -1
- data/spec/unit/realtime/incoming_message_dispatcher_spec.rb +36 -0
- data/spec/unit/realtime/message_spec.rb +2 -2
- data/spec/unit/realtime/protocol_message_spec.rb +78 -9
- data/spec/unit/rest/{rest_spec.rb → client_spec.rb} +0 -0
- data/spec/unit/rest/message_spec.rb +1 -1
- metadata +51 -9
- data/lib/ably/realtime/callbacks.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b99a13d28dd5bd7e6b1d35e6ad0d718e759fbb3
|
4
|
+
data.tar.gz: fa7e7aac5a7acf5cc74bfc1da6faf48913ef0f36
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8d2771237651cc84bc83f3de5c6e5438f6e04f57b36432d4394995f5ed7deae8e097d397d149a13e23993116d1f1f2266de046e7c1cca42e36ae776a92a6b5b6
|
7
|
+
data.tar.gz: 9f12b4aef062743e6bbfd7b40388dd7582b42d9634efb062a66ea4a181f815d5c44473e97a48b6c9b3c6862bd07d1bcf12e2d366006da5925f20f9c7d1d8a35e
|
data/ably.gemspec
CHANGED
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_runtime_dependency "faraday", "~> 0.9"
|
23
23
|
spec.add_runtime_dependency "json"
|
24
24
|
spec.add_runtime_dependency "websocket-driver"
|
25
|
+
spec.add_runtime_dependency "msgpack"
|
25
26
|
|
26
27
|
spec.add_development_dependency "bundler", "~> 1.3"
|
27
28
|
spec.add_development_dependency "rake"
|
data/lib/ably/auth.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'json'
|
2
|
+
require 'faraday'
|
3
|
+
require 'securerandom'
|
4
4
|
|
5
5
|
require "ably/rest/middleware/external_exceptions"
|
6
|
-
require "ably/rest/middleware/parse_json"
|
7
6
|
|
8
7
|
module Ably
|
9
8
|
# Auth is responsible for authentication with {https://ably.io Ably} using basic or token authentication
|
@@ -369,7 +368,7 @@ module Ably
|
|
369
368
|
@connection_options ||= {
|
370
369
|
builder: middleware,
|
371
370
|
headers: {
|
372
|
-
accept:
|
371
|
+
accept: client.mime_type,
|
373
372
|
user_agent: user_agent
|
374
373
|
},
|
375
374
|
request: {
|
@@ -384,18 +383,15 @@ module Ably
|
|
384
383
|
# @see http://mislav.uniqpath.com/2011/07/faraday-advanced-http/
|
385
384
|
def middleware
|
386
385
|
@middleware ||= Faraday::RackBuilder.new do |builder|
|
387
|
-
|
388
|
-
builder.use Faraday::Request::UrlEncoded
|
389
|
-
|
390
|
-
# Parse JSON response bodies
|
391
|
-
builder.use Ably::Rest::Middleware::ParseJson
|
392
|
-
|
393
|
-
# Log HTTP requests if debug_http option set
|
394
|
-
builder.response :logger if @debug_http
|
386
|
+
setup_middleware builder
|
395
387
|
|
396
388
|
# Raise exceptions if response code is invalid
|
397
389
|
builder.use Ably::Rest::Middleware::ExternalExceptions
|
398
390
|
|
391
|
+
|
392
|
+
# Log HTTP requests if log level is DEBUG option set
|
393
|
+
builder.response :logger if client.log_level == Logger::DEBUG
|
394
|
+
|
399
395
|
# Set Faraday's HTTP adapter
|
400
396
|
builder.adapter Faraday.default_adapter
|
401
397
|
end
|
@@ -1,30 +1,46 @@
|
|
1
1
|
require 'logger'
|
2
2
|
|
3
|
+
module Ably::Modules
|
4
|
+
module Conversions
|
5
|
+
private
|
6
|
+
# Creates or returns an {IdiomaticRubyWrapper} ensuring it never wraps itself
|
7
|
+
#
|
8
|
+
# @return {IdiomaticRubyWrapper}
|
9
|
+
def IdiomaticRubyWrapper(object, options = {})
|
10
|
+
case object
|
11
|
+
when Ably::Models::IdiomaticRubyWrapper
|
12
|
+
object
|
13
|
+
else
|
14
|
+
Ably::Models::IdiomaticRubyWrapper.new(object, options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
3
20
|
module Ably::Models
|
4
21
|
# Wraps JSON objects returned by Ably service to appear as Idiomatic Ruby Hashes with symbol keys
|
5
22
|
# It recursively wraps containing Hashes, but will stop wrapping at arrays, any other non Hash object, or any key matching the `:stops_at` options
|
6
23
|
# It also provides methods matching the symbolic keys for convenience
|
7
24
|
#
|
8
25
|
# @example
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
|
13
|
-
# ruby_hash[:key_value] # => 'true'
|
14
|
-
# ruby_hash.key_value # => 'true'
|
15
|
-
# ruby_hash[:key_value] = 'new_value'
|
16
|
-
# ruby_hash.key_value # => 'new_value'
|
26
|
+
# ruby_hash = IdiomaticRubyWrapper.new({ 'keyValue' => 'true' })
|
27
|
+
# # or recommended to avoid wrapping wrapped objects
|
28
|
+
# ruby_hash = IdiomaticRubyWrapper({ 'keyValue' => 'true' })
|
17
29
|
#
|
18
|
-
#
|
19
|
-
#
|
30
|
+
# ruby_hash[:key_value] # => 'true'
|
31
|
+
# ruby_hash.key_value # => 'true'
|
32
|
+
# ruby_hash[:key_value] = 'new_value'
|
33
|
+
# ruby_hash.key_value # => 'new_value'
|
20
34
|
#
|
21
|
-
#
|
35
|
+
# ruby_hash[:none] # => nil
|
36
|
+
# ruby_hash.none # => nil
|
22
37
|
#
|
23
38
|
# @!attribute [r] stop_at
|
24
39
|
# @return [Array<Symbol,String>] array of keys that this wrapper should stop wrapping at to preserve the underlying JSON hash as is
|
25
40
|
#
|
26
41
|
class IdiomaticRubyWrapper
|
27
42
|
include Enumerable
|
43
|
+
include Ably::Modules::Conversions
|
28
44
|
|
29
45
|
attr_reader :stop_at
|
30
46
|
|
@@ -172,33 +188,5 @@ module Ably::Models
|
|
172
188
|
|
173
189
|
preferred_format.call(symbolized_key)
|
174
190
|
end
|
175
|
-
|
176
|
-
# Convert key to mixedCase from mixed_case
|
177
|
-
def convert_to_mixed_case(key, force_camel: false)
|
178
|
-
key.to_s.
|
179
|
-
split('_').
|
180
|
-
each_with_index.map do |str, index|
|
181
|
-
if index > 0 || force_camel
|
182
|
-
str.capitalize
|
183
|
-
else
|
184
|
-
str
|
185
|
-
end
|
186
|
-
end.
|
187
|
-
join
|
188
|
-
end
|
189
|
-
|
190
|
-
# Convert key to :snake_case from snakeCase
|
191
|
-
def convert_to_snake_case_symbol(key)
|
192
|
-
key.to_s.gsub(/::/, '/').
|
193
|
-
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
194
|
-
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
195
|
-
tr("-", "_").
|
196
|
-
downcase.
|
197
|
-
to_sym
|
198
|
-
end
|
199
|
-
|
200
|
-
def convert_to_lower_case(key)
|
201
|
-
key.to_s.gsub('_', '')
|
202
|
-
end
|
203
191
|
end
|
204
192
|
end
|
@@ -1,16 +1,8 @@
|
|
1
1
|
module Ably::Modules
|
2
2
|
module Conversions
|
3
|
-
|
4
|
-
# Returns object as {IdiomaticRubyWrapper}
|
5
|
-
def IdiomaticRubyWrapper(object, options = {})
|
6
|
-
case object
|
7
|
-
when Ably::Models::IdiomaticRubyWrapper
|
8
|
-
object
|
9
|
-
else
|
10
|
-
Ably::Models::IdiomaticRubyWrapper.new(object, options)
|
11
|
-
end
|
12
|
-
end
|
3
|
+
extend self
|
13
4
|
|
5
|
+
private
|
14
6
|
def as_since_epoch(time, granularity: :ms)
|
15
7
|
case time
|
16
8
|
when Time
|
@@ -43,5 +35,34 @@ module Ably::Modules
|
|
43
35
|
raise ArgumentError, "invalid granularity"
|
44
36
|
end
|
45
37
|
end
|
38
|
+
|
39
|
+
# Convert key to mixedCase from mixed_case
|
40
|
+
def convert_to_mixed_case(key, force_camel: false)
|
41
|
+
key.to_s.
|
42
|
+
split('_').
|
43
|
+
each_with_index.map do |str, index|
|
44
|
+
if index > 0 || force_camel
|
45
|
+
str.capitalize
|
46
|
+
else
|
47
|
+
str
|
48
|
+
end
|
49
|
+
end.
|
50
|
+
join
|
51
|
+
end
|
52
|
+
|
53
|
+
# Convert key to :snake_case from snakeCase
|
54
|
+
def convert_to_snake_case_symbol(key)
|
55
|
+
key.to_s.gsub(/::/, '/').
|
56
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
57
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
58
|
+
gsub(/([a-zA-Z])(\d)/,'\1_\2').
|
59
|
+
tr("-", "_").
|
60
|
+
downcase.
|
61
|
+
to_sym
|
62
|
+
end
|
63
|
+
|
64
|
+
def convert_to_lower_case(key)
|
65
|
+
key.to_s.gsub('_', '')
|
66
|
+
end
|
46
67
|
end
|
47
68
|
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
module Ably::Modules
|
2
|
+
# Enum brings Enum like functionality used in other languages to Ruby
|
3
|
+
#
|
4
|
+
# @example
|
5
|
+
# class House
|
6
|
+
# extend Ably::Moduels::Enum
|
7
|
+
# CONSTRUCTION = ruby_enum('CONSTRUCTION',
|
8
|
+
# :brick,
|
9
|
+
# :steel,
|
10
|
+
# :wood
|
11
|
+
# )
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# House::CONSTRUCTION(:brick).to_i # => 0
|
15
|
+
# House::CONSTRUCTION('Wood').to_i # => 2
|
16
|
+
# House::CONSTRUCTION.Wood == :wood # => true
|
17
|
+
#
|
18
|
+
module Enum
|
19
|
+
private
|
20
|
+
|
21
|
+
class Base; end
|
22
|
+
|
23
|
+
# ruby_enum returns an Enum-like class that should be assigned to a constant in your class
|
24
|
+
# The first `enum_name` argument must match the constant name so that the coercion method is available
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# class House
|
28
|
+
# extend Ably::Moduels::Enum
|
29
|
+
# CONSTRUCTION = ruby_enum('CONSTRUCTION', :brick)
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # ensures the following coercion method is available
|
33
|
+
# House::CONSTRUCTION(:brick) # => CONSTRUCTION.Brick
|
34
|
+
#
|
35
|
+
def ruby_enum(enum_name, *values)
|
36
|
+
enum_class = Class.new(Enum::Base) do
|
37
|
+
include Conversions
|
38
|
+
extend Conversions
|
39
|
+
|
40
|
+
@enum_name = enum_name
|
41
|
+
@by_index = {}
|
42
|
+
@by_symbol = {}
|
43
|
+
|
44
|
+
class << self
|
45
|
+
include Enumerable
|
46
|
+
|
47
|
+
def get(identifier)
|
48
|
+
case identifier
|
49
|
+
when Symbol
|
50
|
+
by_symbol.fetch(identifier)
|
51
|
+
when String
|
52
|
+
by_symbol.fetch(convert_to_snake_case_symbol(identifier))
|
53
|
+
when Numeric
|
54
|
+
by_index.fetch(identifier)
|
55
|
+
when ancestors.first
|
56
|
+
identifier
|
57
|
+
else
|
58
|
+
if identifier.class.ancestors.include?(Enum::Base)
|
59
|
+
by_symbol.fetch(identifier.to_sym)
|
60
|
+
else
|
61
|
+
raise KeyError, "Cannot find Enum matching identifier '#{identifier}' argument as it is an unacceptable type: #{identifier.class}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def [](*args)
|
67
|
+
get(*args)
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_s
|
71
|
+
name
|
72
|
+
end
|
73
|
+
|
74
|
+
def size
|
75
|
+
by_symbol.keys.length
|
76
|
+
end
|
77
|
+
alias_method :length, :size
|
78
|
+
|
79
|
+
# Method ensuring this {Enum} is {http://ruby-doc.org/core-2.1.3/Enumerable.html Enumerable}
|
80
|
+
def each(&block)
|
81
|
+
by_symbol.each do |key, value|
|
82
|
+
yield value
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# The name provided in the constructor for this Enum
|
87
|
+
def name
|
88
|
+
@enum_name
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
attr_reader :by_index, :by_symbol
|
93
|
+
|
94
|
+
# Define constants for each of the Enum values
|
95
|
+
# e.g. define_constants(:dog) creates Enum::Dog
|
96
|
+
def define_values(values)
|
97
|
+
raise RuntimeError, "#{name} Enum cannot be modified" if by_index.frozen?
|
98
|
+
|
99
|
+
# Allow another Enum to be used as a set of values
|
100
|
+
if values.length == 1 && klass = values.first
|
101
|
+
if klass.kind_of?(Class) && klass.ancestors.include?(Enum::Base)
|
102
|
+
values = values.first.map(&:to_sym)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
values.map do |value|
|
107
|
+
# Convert any key => index_value pairs into array pairs
|
108
|
+
Array(value)
|
109
|
+
end.flatten(1).each_with_index do |name, index|
|
110
|
+
name, index = name if name.kind_of?(Array) # name is key => index_value pair
|
111
|
+
raise ArgumentError, "Index value '#{index}' is invalid" unless index.kind_of?(Numeric)
|
112
|
+
|
113
|
+
camel_name = convert_to_mixed_case(name, force_camel: true)
|
114
|
+
name_symbol = convert_to_snake_case_symbol(name)
|
115
|
+
enum = new(camel_name, name_symbol, index.to_i)
|
116
|
+
|
117
|
+
by_index[index.to_i] = enum
|
118
|
+
by_symbol[name_symbol] = enum
|
119
|
+
|
120
|
+
define_singleton_method camel_name do
|
121
|
+
enum
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
by_index.freeze
|
126
|
+
by_symbol.freeze
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def initialize(name, symbol, index)
|
131
|
+
@name = name
|
132
|
+
@index = index
|
133
|
+
@symbol = symbol
|
134
|
+
end
|
135
|
+
|
136
|
+
def to_s
|
137
|
+
"#{self.class}.#{name}"
|
138
|
+
end
|
139
|
+
|
140
|
+
def to_i
|
141
|
+
index
|
142
|
+
end
|
143
|
+
|
144
|
+
def to_sym
|
145
|
+
symbol
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_json(*args)
|
149
|
+
%{"#{symbol}"}
|
150
|
+
end
|
151
|
+
|
152
|
+
# Allow comparison of Enum objects based on:
|
153
|
+
#
|
154
|
+
# * Other equivalent Enum objects
|
155
|
+
# * Symbol
|
156
|
+
# * String
|
157
|
+
# * Integer index of Enum
|
158
|
+
#
|
159
|
+
def ==(other)
|
160
|
+
case other
|
161
|
+
when Symbol
|
162
|
+
self.to_sym == convert_to_snake_case_symbol(other)
|
163
|
+
when String
|
164
|
+
self.to_sym == convert_to_snake_case_symbol(other)
|
165
|
+
when Numeric
|
166
|
+
self.to_i == other.to_i
|
167
|
+
when self.class
|
168
|
+
self.to_i == other.to_i
|
169
|
+
else
|
170
|
+
false
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
private
|
175
|
+
attr_reader :name, :index, :symbol
|
176
|
+
|
177
|
+
define_values values
|
178
|
+
end
|
179
|
+
|
180
|
+
# Convert any comparable object into this Enum
|
181
|
+
# @example
|
182
|
+
# class Example
|
183
|
+
# DOGS = ruby_enum('DOGS', :terrier, :labrador, :great_dane)
|
184
|
+
# end
|
185
|
+
#
|
186
|
+
# Example.DOGS(:great_dane) # => <DOGS.GreatDane>
|
187
|
+
# Example.DOGS(0) # => <DOGS.Terrier>
|
188
|
+
# Example.new.DOGS(0) # => <DOGS.Terrier>
|
189
|
+
#
|
190
|
+
define_singleton_method enum_name do |val|
|
191
|
+
enum_class.get(val)
|
192
|
+
end
|
193
|
+
|
194
|
+
define_method enum_name do |val|
|
195
|
+
enum_class.get(val)
|
196
|
+
end
|
197
|
+
|
198
|
+
enum_class
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module Ably
|
2
|
+
module Modules
|
3
|
+
# EventEmitter provides methods to attach to public events and trigger events on any class instance
|
4
|
+
#
|
5
|
+
# EventEmitter are typically used for public interfaces, and as such, may be overriden in
|
6
|
+
# the classes to enforce `event` names match expected values.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# class Example
|
10
|
+
# include Modules::EventEmitter
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# event_emitter = Example.new
|
14
|
+
# event_emitter.on(:signal) { |name| puts "Signal #{name} received" }
|
15
|
+
# event_emitter.trigger :signal, "Test"
|
16
|
+
# #=> "Signal Test received"
|
17
|
+
#
|
18
|
+
module EventEmitter
|
19
|
+
module ClassMethods
|
20
|
+
attr_reader :event_emitter_coerce_proc
|
21
|
+
|
22
|
+
# Configure included EventEmitter
|
23
|
+
#
|
24
|
+
# @param [Hash] options the options for the {EventEmitter}
|
25
|
+
# @option options [Proc] :coerce_into A lambda/Proc that is used to coerce the event names for all events. This is useful to ensure the event names conform to a naming or type convention.
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# configure_event_emitter coerce_into: Proc.new { |event| event.to_sym }
|
29
|
+
#
|
30
|
+
def configure_event_emitter(options = {})
|
31
|
+
@event_emitter_coerce_proc = options[:coerce_into]
|
32
|
+
end
|
33
|
+
|
34
|
+
# Ensure @event_emitter_coerce_proc option is passed down to any classes that inherit the class with callbacks
|
35
|
+
def inherited(subclass)
|
36
|
+
subclass.instance_variable_set('@event_emitter_coerce_proc', @event_emitter_coerce_proc)
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# On receiving an event matching the event_name, call the provided block
|
42
|
+
def on(event_name, &block)
|
43
|
+
callbacks[callbacks_event_coerced(event_name)] << block
|
44
|
+
end
|
45
|
+
|
46
|
+
# Trigger an event with event_name that will in turn call all matching callbacks setup with `on`
|
47
|
+
def trigger(event_name, *args)
|
48
|
+
callbacks[callbacks_event_coerced(event_name)].each { |cb| cb.call(*args) }
|
49
|
+
end
|
50
|
+
|
51
|
+
# Remove all callbacks for event_name.
|
52
|
+
#
|
53
|
+
# If a block is provided, only callbacks matching that block signature will be removed.
|
54
|
+
# If block is not provided, all callbacks matching the event_name will be removed.
|
55
|
+
def off(event_name, &block)
|
56
|
+
if block_given?
|
57
|
+
callbacks[callbacks_event_coerced(event_name)].delete(block)
|
58
|
+
else
|
59
|
+
callbacks[callbacks_event_coerced(event_name)].clear
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def self.included(klass)
|
65
|
+
klass.extend ClassMethods
|
66
|
+
end
|
67
|
+
|
68
|
+
def callbacks
|
69
|
+
@callbacks ||= Hash.new { |hash, key| hash[key] = [] }
|
70
|
+
end
|
71
|
+
|
72
|
+
def callbacks_event_coerced(event_name)
|
73
|
+
if self.class.event_emitter_coerce_proc
|
74
|
+
self.class.event_emitter_coerce_proc.call(event_name)
|
75
|
+
else
|
76
|
+
event_name
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|