ably-rest 0.8.3 → 0.8.5

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/lib/submodules/ably-ruby/CHANGELOG.md +10 -0
  4. data/lib/submodules/ably-ruby/README.md +1 -1
  5. data/lib/submodules/ably-ruby/Rakefile +1 -1
  6. data/lib/submodules/ably-ruby/lib/ably/auth.rb +24 -20
  7. data/lib/submodules/ably-ruby/lib/ably/exceptions.rb +3 -0
  8. data/lib/submodules/ably-ruby/lib/ably/models/channel_state_change.rb +41 -0
  9. data/lib/submodules/ably-ruby/lib/ably/models/connection_state_change.rb +43 -0
  10. data/lib/submodules/ably-ruby/lib/ably/models/message.rb +1 -1
  11. data/lib/submodules/ably-ruby/lib/ably/models/presence_message.rb +1 -1
  12. data/lib/submodules/ably-ruby/lib/ably/models/protocol_message.rb +2 -1
  13. data/lib/submodules/ably-ruby/lib/ably/models/token_details.rb +8 -6
  14. data/lib/submodules/ably-ruby/lib/ably/modules/conversions.rb +4 -0
  15. data/lib/submodules/ably-ruby/lib/ably/modules/state_emitter.rb +4 -1
  16. data/lib/submodules/ably-ruby/lib/ably/modules/uses_state_machine.rb +35 -4
  17. data/lib/submodules/ably-ruby/lib/ably/realtime/auth.rb +13 -13
  18. data/lib/submodules/ably-ruby/lib/ably/realtime/channel.rb +13 -5
  19. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_manager.rb +27 -7
  20. data/lib/submodules/ably-ruby/lib/ably/realtime/channel/channel_state_machine.rb +22 -12
  21. data/lib/submodules/ably-ruby/lib/ably/realtime/client/incoming_message_dispatcher.rb +16 -10
  22. data/lib/submodules/ably-ruby/lib/ably/realtime/client/outgoing_message_dispatcher.rb +6 -0
  23. data/lib/submodules/ably-ruby/lib/ably/realtime/connection.rb +5 -4
  24. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_manager.rb +42 -24
  25. data/lib/submodules/ably-ruby/lib/ably/realtime/connection/connection_state_machine.rb +25 -17
  26. data/lib/submodules/ably-ruby/lib/ably/realtime/presence.rb +4 -4
  27. data/lib/submodules/ably-ruby/lib/ably/rest/channel.rb +3 -2
  28. data/lib/submodules/ably-ruby/lib/ably/rest/client.rb +2 -2
  29. data/lib/submodules/ably-ruby/lib/ably/util/crypto.rb +15 -0
  30. data/lib/submodules/ably-ruby/lib/ably/version.rb +1 -1
  31. data/lib/submodules/ably-ruby/spec/acceptance/realtime/auth_spec.rb +9 -9
  32. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_history_spec.rb +2 -2
  33. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channel_spec.rb +168 -21
  34. data/lib/submodules/ably-ruby/spec/acceptance/realtime/channels_spec.rb +6 -2
  35. data/lib/submodules/ably-ruby/spec/acceptance/realtime/client_spec.rb +6 -5
  36. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_failures_spec.rb +29 -19
  37. data/lib/submodules/ably-ruby/spec/acceptance/realtime/connection_spec.rb +150 -35
  38. data/lib/submodules/ably-ruby/spec/acceptance/realtime/message_spec.rb +146 -23
  39. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_history_spec.rb +2 -2
  40. data/lib/submodules/ably-ruby/spec/acceptance/realtime/presence_spec.rb +44 -24
  41. data/lib/submodules/ably-ruby/spec/acceptance/realtime/stats_spec.rb +1 -1
  42. data/lib/submodules/ably-ruby/spec/acceptance/realtime/time_spec.rb +1 -1
  43. data/lib/submodules/ably-ruby/spec/acceptance/rest/auth_spec.rb +77 -46
  44. data/lib/submodules/ably-ruby/spec/acceptance/rest/channel_spec.rb +31 -3
  45. data/lib/submodules/ably-ruby/spec/acceptance/rest/client_spec.rb +15 -5
  46. data/lib/submodules/ably-ruby/spec/acceptance/rest/presence_spec.rb +9 -7
  47. data/lib/submodules/ably-ruby/spec/support/event_machine_helper.rb +30 -4
  48. data/lib/submodules/ably-ruby/spec/support/protocol_helper.rb +9 -6
  49. data/lib/submodules/ably-ruby/spec/unit/auth_spec.rb +1 -1
  50. data/lib/submodules/ably-ruby/spec/unit/models/channel_state_change_spec.rb +44 -0
  51. data/lib/submodules/ably-ruby/spec/unit/models/connection_state_change_spec.rb +54 -0
  52. data/lib/submodules/ably-ruby/spec/unit/models/token_details_spec.rb +8 -0
  53. data/lib/submodules/ably-ruby/spec/unit/modules/async_wrapper_spec.rb +1 -1
  54. data/lib/submodules/ably-ruby/spec/unit/util/crypto_spec.rb +18 -0
  55. metadata +6 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6dc33fd0a8246405f3b3db4aa1adfa03711a6ccc
4
- data.tar.gz: 0de772597367cd55d99437a0bbb34302086c1ee8
3
+ metadata.gz: 1b1045e268247db9dd96742a0c11404b03fbb533
4
+ data.tar.gz: 180a9c3dfee6b05b4fc8c8f947e1081bba97b635
5
5
  SHA512:
6
- metadata.gz: 72696b8f25b34f36552978221b44f4f75bdc2772743b43d13686aabe4ed41932e88bc5e93b4b095d3abdc743d72b7d6f1cfba199f14ff7f618d9407bd9cdabd3
7
- data.tar.gz: 4252aa2885f5e75ba6ad219aa4af7edef9989f4ba122972ab6e8b9d9d1b5e08794286819d6f26fa54746b0988a6725307c566b191be6a207e15a96f03a7eefb6
6
+ metadata.gz: 163805382715a09c67f446297b49c5c4588ff2c141c3cc6173eb9917423305b3f532d076f46af854d6b869439e9e465a02eb23735e40be64fe8d017773d782a0
7
+ data.tar.gz: b024865d3a6f266681e0ed4224b6a14c1e4248e21f93958d357d3009010a662d02d779615a21d0c4616e6397fc6c1053c0afc887ef7c52dcde9c286e24960d3d
@@ -1,3 +1,4 @@
1
+ sudo: false
1
2
  env: RSPEC_RETRY=true
2
3
  language: ruby
3
4
  rvm:
@@ -6,6 +6,12 @@
6
6
 
7
7
  **Implemented enhancements:**
8
8
 
9
+ - Add compatibility support for default Crypto params [\#53](https://github.com/ably/ably-ruby/issues/53)
10
+
11
+ - EventEmitter on connection [\#52](https://github.com/ably/ably-ruby/issues/52)
12
+
13
+ - Add test for connectionId attribute for a message sent over REST [\#50](https://github.com/ably/ably-ruby/issues/50)
14
+
9
15
  - Implement :queue\_messages option [\#36](https://github.com/ably/ably-ruby/issues/36)
10
16
 
11
17
  - Check that a non 200-299 status code for REST requests uses fallback hosts [\#35](https://github.com/ably/ably-ruby/issues/35)
@@ -32,6 +38,10 @@
32
38
 
33
39
  **Merged pull requests:**
34
40
 
41
+ - Spec update to fix a number of issues [\#60](https://github.com/ably/ably-ruby/pull/60) ([mattheworiordan](https://github.com/mattheworiordan))
42
+
43
+ - Allow clientId to be provided on init if using externally created token [\#58](https://github.com/ably/ably-ruby/pull/58) ([SimonWoolf](https://github.com/SimonWoolf))
44
+
35
45
  - Separate token params for auth [\#57](https://github.com/ably/ably-ruby/pull/57) ([mattheworiordan](https://github.com/mattheworiordan))
36
46
 
37
47
  - Ensure files are required in a consistent order [\#51](https://github.com/ably/ably-ruby/pull/51) ([SimonWoolf](https://github.com/SimonWoolf))
@@ -187,7 +187,7 @@ token_details = client.auth.request_token
187
187
  token_details.token # => "xVLyHw.CLchevH3hF....MDh9ZC_Q"
188
188
  client = Ably::Rest.new(token: token_details.token)
189
189
 
190
- token = client.auth.create_token_request(token_params: { ttl: 3600 })
190
+ token = client.auth.create_token_request(ttl: 3600)
191
191
  # => {"id"=>...,
192
192
  # "clientId"=>nil,
193
193
  # "ttl"=>3600,
@@ -16,7 +16,7 @@ begin
16
16
  namespace :doc do
17
17
  desc 'Generate Markdown Specification from the RSpec public API tests'
18
18
  task :spec do
19
- ENV['TEST_LIMIT_PROTOCOLS'] = JSON.dump({ msgpack: 'JSON and MsgPack' })
19
+ ENV['PROTOCOL'] = 'json'
20
20
 
21
21
  rspec_task.rspec_opts = %w(
22
22
  --require ./spec/support/markdown_spec_formatter
@@ -43,11 +43,11 @@ module Ably
43
43
  # Creates an Auth object
44
44
  #
45
45
  # @param [Ably::Rest::Client] client {Ably::Rest::Client} this Auth object uses
46
- # @param [Hash] auth_options the authentication options used as a default future token requests
47
46
  # @param [Hash] token_params the token params used as a default for future token requests
47
+ # @param [Hash] auth_options the authentication options used as a default future token requests
48
48
  # @option (see #request_token)
49
49
  #
50
- def initialize(client, auth_options, token_params)
50
+ def initialize(client, token_params, auth_options)
51
51
  unless auth_options.kind_of?(Hash)
52
52
  raise ArgumentError, 'Expected auth_options to be a Hash'
53
53
  end
@@ -74,7 +74,7 @@ module Ably
74
74
  raise ArgumentError, 'key is missing. Either an API key, token, or token auth method must be provided'
75
75
  end
76
76
 
77
- if has_client_id?
77
+ if has_client_id? && !token_creatable_externally?
78
78
  raise ArgumentError, 'client_id cannot be provided without a complete API key. Key name & Secret is needed to authenticate with Ably and obtain a token' unless api_key_present?
79
79
  ensure_utf_8 :client_id, client_id
80
80
  end
@@ -87,8 +87,8 @@ module Ably
87
87
  #
88
88
  # In the event that a new token request is made, the provided options are used.
89
89
  #
90
- # @param [Hash] auth_options the authentication options used for future token requests
91
90
  # @param [Hash] token_params the token params used for future token requests
91
+ # @param [Hash] auth_options the authentication options used for future token requests
92
92
  # @option auth_options [Boolean] :force obtains a new token even if the current token is valid
93
93
  # @option (see #request_token)
94
94
  #
@@ -100,12 +100,12 @@ module Ably
100
100
  # token_details = client.auth.authorise
101
101
  #
102
102
  # # will use token request from block to authorise if not already authorised
103
- # token_details = client.auth.authorise auth_callback: Proc.new do
103
+ # token_details = client.auth.authorise {}, auth_callback: Proc.new do
104
104
  # # create token_request object
105
105
  # token_request
106
106
  # end
107
107
  #
108
- def authorise(auth_options = {}, token_params = {})
108
+ def authorise(token_params = {}, auth_options = {})
109
109
  ensure_valid_auth_attributes auth_options
110
110
 
111
111
  auth_options = auth_options.clone
@@ -120,7 +120,7 @@ module Ably
120
120
  token_params = (auth_options.delete(:token_params) || {}).merge(token_params)
121
121
  @token_params = @token_params.merge(token_params) # update defaults
122
122
 
123
- @current_token_details = request_token(auth_options, token_params)
123
+ @current_token_details = request_token(token_params, auth_options)
124
124
  end
125
125
 
126
126
  # Request a {Ably::Models::TokenDetails} which can be used to make authenticated token based requests
@@ -143,15 +143,15 @@ module Ably
143
143
  # token_details = client.auth.request_token
144
144
  #
145
145
  # # token request with token params
146
- # client.auth.request_token token_params: { ttl: 1.hour }
146
+ # client.auth.request_token ttl: 1.hour
147
147
  #
148
148
  # # token request using auth block
149
- # token_details = client.auth.request_token auth_callback: Proc.new do
149
+ # token_details = client.auth.request_token {}, auth_callback: Proc.new do
150
150
  # # create token_request object
151
151
  # token_request
152
152
  # end
153
153
  #
154
- def request_token(auth_options = {}, token_params = {})
154
+ def request_token(token_params = {}, auth_options = {})
155
155
  ensure_valid_auth_attributes auth_options
156
156
 
157
157
  token_params = (auth_options[:token_params] || {}).merge(token_params)
@@ -163,7 +163,7 @@ module Ably
163
163
  elsif auth_url = auth_options.delete(:auth_url)
164
164
  token_request_from_auth_url(auth_url, auth_options)
165
165
  else
166
- create_token_request(auth_options, token_params)
166
+ create_token_request(token_params, auth_options)
167
167
  end
168
168
 
169
169
  case token_request
@@ -186,12 +186,6 @@ module Ably
186
186
 
187
187
  # Creates and signs a token request that can then subsequently be used by any client to request a token
188
188
  #
189
- # @param [Hash] auth_options the authentication options for the token request
190
- # @option auth_options [String] :key API key comprising the key name and key secret in a single string
191
- # @option auth_options [String] :client_id client ID identifying this connection to other clients (will use +client_id+ specified when library was instanced if provided)
192
- # @option auth_options [Boolean] :query_time when true will query the {https://www.ably.io Ably} system for the current time instead of using the local time
193
- # @option auth_options [Hash] :token_params convenience to pass in +token_params+ within the +auth_options+ argument, this helps avoid the following +authorise({key: key}, {ttl: 23})+ by allowing +authorise(key:key,token_params:{ttl:23})+
194
- #
195
189
  # @param [Hash] token_params the token params used in the token request
196
190
  # @option token_params [String] :client_id A client ID to associate with this token. The generated token may be used to authenticate as this +client_id+
197
191
  # @option token_params [Integer] :ttl validity time in seconds for the requested {Ably::Models::TokenDetails}. Limits may apply, see {https://www.ably.io/documentation/other/authentication}
@@ -199,10 +193,16 @@ module Ably
199
193
  # @option token_params [Time] :timestamp the time of the request
200
194
  # @option token_params [String] :nonce an unquoted, unescaped random string of at least 16 characters
201
195
  #
196
+ # @param [Hash] auth_options the authentication options for the token request
197
+ # @option auth_options [String] :key API key comprising the key name and key secret in a single string
198
+ # @option auth_options [String] :client_id client ID identifying this connection to other clients (will use +client_id+ specified when library was instanced if provided)
199
+ # @option auth_options [Boolean] :query_time when true will query the {https://www.ably.io Ably} system for the current time instead of using the local time
200
+ # @option auth_options [Hash] :token_params convenience to pass in +token_params+ within the +auth_options+ argument, especially useful when setting default token_params in the client constructor
201
+ #
202
202
  # @return [Models::TokenRequest]
203
203
  #
204
204
  # @example
205
- # client.auth.create_token_request(id: 'asd.asd', token_params: { ttl: 3600 })
205
+ # client.auth.create_token_request({ ttl: 3600 }, { id: 'asd.asd' })
206
206
  # #<Ably::Models::TokenRequest:0x007fd5d919df78
207
207
  # # @hash={
208
208
  # # :id=>"asds.adsa",
@@ -214,7 +214,7 @@ module Ably
214
214
  # # :mac=>"881oZHeFo6oMim7....uE56a8gUxHw="
215
215
  # # }
216
216
  # #>>
217
- def create_token_request(auth_options = {}, token_params = {})
217
+ def create_token_request(token_params = {}, auth_options = {})
218
218
  ensure_valid_auth_attributes auth_options
219
219
 
220
220
  auth_options = auth_options.clone
@@ -401,7 +401,11 @@ module Ably
401
401
 
402
402
  # Returns the current token if it exists or authorises and retrieves a token
403
403
  def token_auth_string
404
- if token
404
+ # If a TokenDetails object has been issued by this library
405
+ # then that Token will take precedence
406
+ if @current_token_details
407
+ authorise.token
408
+ elsif token # token string was configured in the options
405
409
  token
406
410
  else
407
411
  authorise.token
@@ -58,6 +58,9 @@ module Ably
58
58
  # Connection Timeout accessing Realtime or REST service
59
59
  class ConnectionTimeout < ConnectionError; end
60
60
 
61
+ # Transport closed unexpectedly
62
+ class TransportClosed < ConnectionError; end
63
+
61
64
  # Connection closed unexpectedly
62
65
  class ConnectionClosed < ConnectionError; end
63
66
 
@@ -0,0 +1,41 @@
1
+ module Ably::Models
2
+ # ChannelStateChange is a class that is emitted by the {Ably::Realtime::Channel} object
3
+ # when a state change occurs
4
+ #
5
+ # @!attribute [r] current
6
+ # @return [Connection::STATE] Current connection state
7
+ # @!attribute [r] previous
8
+ # @return [Connection::STATE] Previous connection state
9
+ # @!attribute [r] reason
10
+ # @return [Ably::Models::ErrorInfo] Object describing the reason for a state change when not initiated by the consumer of the client library
11
+ #
12
+ class ChannelStateChange
13
+ include Ably::Modules::ModelCommon
14
+
15
+ def initialize(hash_object)
16
+ unless (hash_object.keys - [:current, :previous, :reason, :protocol_message]).empty?
17
+ raise ArgumentError, 'Invalid attributes, expecting :current, :previous, :reason'
18
+ end
19
+
20
+ @hash_object = {
21
+ current: hash_object.fetch(:current),
22
+ previous: hash_object.fetch(:previous),
23
+ retry_in: hash_object[:retry_in],
24
+ reason: hash_object[:reason],
25
+ protocol_message: hash_object[:protocol_message]
26
+ }
27
+ rescue KeyError => e
28
+ raise ArgumentError, e
29
+ end
30
+
31
+ %w(current previous reason protocol_message).each do |attribute|
32
+ define_method attribute do
33
+ @hash_object[attribute.to_sym]
34
+ end
35
+ end
36
+
37
+ def to_s
38
+ "ChannelStateChange: current state #{current}, previous state #{previous}"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,43 @@
1
+ module Ably::Models
2
+ # ConnectionStateChange is a class that is emitted by the {Ably::Realtime::Connection} object
3
+ # when a state change occurs
4
+ #
5
+ # @!attribute [r] current
6
+ # @return [Connection::STATE] Current connection state
7
+ # @!attribute [r] previous
8
+ # @return [Connection::STATE] Previous connection state
9
+ # @!attribute [r] retry_in
10
+ # @return [Integer] Time in seconds until the connection will reattempt to connect when in the +:disconnected+ or +:suspended+ state
11
+ # @!attribute [r] reason
12
+ # @return [Ably::Models::ErrorInfo] Object describing the reason for a state change when not initiated by the consumer of the client library
13
+ #
14
+ class ConnectionStateChange
15
+ include Ably::Modules::ModelCommon
16
+
17
+ def initialize(hash_object)
18
+ unless (hash_object.keys - [:current, :previous, :retry_in, :reason, :protocol_message]).empty?
19
+ raise ArgumentError, 'Invalid attributes, expecting :current, :previous, :retry_in, :reason'
20
+ end
21
+
22
+ @hash_object = {
23
+ current: hash_object.fetch(:current),
24
+ previous: hash_object.fetch(:previous),
25
+ retry_in: hash_object[:retry_in],
26
+ reason: hash_object[:reason],
27
+ protocol_message: hash_object[:protocol_message]
28
+ }
29
+ rescue KeyError => e
30
+ raise ArgumentError, e
31
+ end
32
+
33
+ %w(current previous retry_in reason protocol_message).each do |attribute|
34
+ define_method attribute do
35
+ @hash_object[attribute.to_sym]
36
+ end
37
+ end
38
+
39
+ def to_s
40
+ "ConnectionStateChange: current state #{current}, previous state #{previous}"
41
+ end
42
+ end
43
+ end
@@ -131,7 +131,7 @@ module Ably::Models
131
131
  end
132
132
 
133
133
  def logger
134
- return logger if logger
134
+ return @logger if @logger
135
135
  protocol_message.logger if protocol_message
136
136
  end
137
137
  end
@@ -154,7 +154,7 @@ module Ably::Models
154
154
  end
155
155
 
156
156
  def logger
157
- return logger if logger
157
+ return @logger if @logger
158
158
  protocol_message.logger if protocol_message
159
159
  end
160
160
  end
@@ -226,7 +226,8 @@ module Ably::Models
226
226
  !action_enum || (ack_required? && !has_serial?)
227
227
  end
228
228
 
229
- private
229
+ # @!attribute [r] logger
230
+ # @api private
230
231
  attr_reader :logger
231
232
  end
232
233
  end
@@ -34,7 +34,7 @@ module Ably::Models
34
34
  # @param attributes
35
35
  # @option attributes [String] :token token used to authenticate requests
36
36
  # @option attributes [String] :key_name API key name used to create this token
37
- # @option attributes [Time,Integer] :issued Time the token was issued as Time or Integer in milliseconds
37
+ # @option attributes [Time,Integer] :issued Time the token was issued as Time or Integer in milliseconds
38
38
  # @option attributes [Time,Integer] :expires Time the token expires as Time or Integer in milliseconds
39
39
  # @option attributes [String] :capability JSON stringified capabilities assigned to this token
40
40
  # @option attributes [String] :client_id client ID assigned to this token
@@ -52,31 +52,31 @@ module Ably::Models
52
52
  # @!attribute [r] token
53
53
  # @return [String] Token used to authenticate requests
54
54
  def token
55
- hash.fetch(:token)
55
+ hash[:token]
56
56
  end
57
57
 
58
58
  # @!attribute [r] key_name
59
59
  # @return [String] API key name used to create this token. An API key is made up of an API key name and secret delimited by a +:+
60
60
  def key_name
61
- hash.fetch(:key_name)
61
+ hash[:key_name]
62
62
  end
63
63
 
64
64
  # @!attribute [r] issued
65
65
  # @return [Time] Time the token was issued
66
66
  def issued
67
- as_time_from_epoch(hash.fetch(:issued), granularity: :ms)
67
+ as_time_from_epoch(hash[:issued], granularity: :ms, allow_nil: :true)
68
68
  end
69
69
 
70
70
  # @!attribute [r] expires
71
71
  # @return [Time] Time the token expires
72
72
  def expires
73
- as_time_from_epoch(hash.fetch(:expires), granularity: :ms)
73
+ as_time_from_epoch(hash[:expires], granularity: :ms, allow_nil: :true)
74
74
  end
75
75
 
76
76
  # @!attribute [r] capability
77
77
  # @return [Hash] Capabilities assigned to this token
78
78
  def capability
79
- JSON.parse(hash.fetch(:capability))
79
+ JSON.parse(hash.fetch(:capability)) if hash.fetch(:capability)
80
80
  end
81
81
 
82
82
  # @!attribute [r] client_id
@@ -86,9 +86,11 @@ module Ably::Models
86
86
  end
87
87
 
88
88
  # Returns true if token is expired or about to expire
89
+ # For tokens that have not got an explicit expires attribute expired? will always return true
89
90
  #
90
91
  # @return [Boolean]
91
92
  def expired?
93
+ return false if !expires
92
94
  expires < Time.now + TOKEN_EXPIRY_BUFFER
93
95
  end
94
96
 
@@ -6,6 +6,8 @@ module Ably::Modules
6
6
 
7
7
  private
8
8
  def as_since_epoch(time, options = {})
9
+ return nil if options[:allow_nil] && !time
10
+
9
11
  granularity = options.fetch(:granularity, :ms)
10
12
 
11
13
  case time
@@ -19,6 +21,8 @@ module Ably::Modules
19
21
  end
20
22
 
21
23
  def as_time_from_epoch(time, options = {})
24
+ return nil if options[:allow_nil] && !time
25
+
22
26
  granularity = options.fetch(:granularity, :ms)
23
27
 
24
28
  case time
@@ -141,7 +141,10 @@ module Ably::Modules
141
141
  #
142
142
  def deferrable_for_state_change_to(target_state)
143
143
  Ably::Util::SafeDeferrable.new(logger).tap do |deferrable|
144
- once_or_if(target_state, else: proc { |*args| deferrable.fail self, *args }) do
144
+ fail_proc = Proc.new do |state_change|
145
+ deferrable.fail state_change.reason
146
+ end
147
+ once_or_if(target_state, else: fail_proc) do
145
148
  yield self if block_given?
146
149
  deferrable.succeed self
147
150
  end
@@ -13,8 +13,8 @@ module Ably::Modules
13
13
  #
14
14
  # @return [Boolean] true if new_state can be transitioned to by state machine
15
15
  # @api private
16
- def transition_state_machine(new_state, emit_object = nil)
17
- state_machine.transition_state(new_state, emit_object)
16
+ def transition_state_machine(new_state, emit_params = {})
17
+ state_machine.transition_state(new_state, emit_object(new_state, emit_params))
18
18
  end
19
19
 
20
20
  # Call #transition_to! on the StateMachine
@@ -22,8 +22,8 @@ module Ably::Modules
22
22
  #
23
23
  # @return [void]
24
24
  # @api private
25
- def transition_state_machine!(new_state, emit_object = nil)
26
- state_machine.transition_to!(new_state, emit_object)
25
+ def transition_state_machine!(new_state, emit_params = {})
26
+ state_machine.transition_to!(new_state, emit_object(new_state, emit_params))
27
27
  end
28
28
 
29
29
  # Provides an internal method for this object's state to match the StateMachine's current state.
@@ -70,5 +70,36 @@ module Ably::Modules
70
70
  logger.debug "#{self.class.name}: Transitioned to #{state_machine.current_state}"
71
71
  end
72
72
  end
73
+
74
+ def emit_object(new_state, emit_params)
75
+ if self.class.emits_klass
76
+ self.class.emits_klass.new((emit_params || {}).merge(current: STATE(new_state), previous: STATE(state_machine.current_state)))
77
+ else
78
+ emit_params
79
+ end
80
+ end
81
+
82
+ def self.included(base)
83
+ base.extend(ClassMethods)
84
+ end
85
+
86
+ module ClassMethods
87
+ def emits_klass
88
+ @emits_klass ||= if @emits_klass_name
89
+ get_const(@emits_klass_name)
90
+ end
91
+ end
92
+
93
+ def ensure_state_machine_emits(klass)
94
+ @emits_klass_name = klass
95
+ end
96
+
97
+ def get_const(klass_name)
98
+ klass_names = klass_name.split('::')
99
+ klass_names.inject(Kernel) do |klass, name|
100
+ klass.const_get(name)
101
+ end
102
+ end
103
+ end
73
104
  end
74
105
  end