ably 0.8.8 → 0.8.9

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -2
  3. data/LICENSE +2 -2
  4. data/README.md +81 -20
  5. data/SPEC.md +235 -178
  6. data/lib/ably/auth.rb +1 -1
  7. data/lib/ably/exceptions.rb +10 -1
  8. data/lib/ably/models/cipher_params.rb +114 -0
  9. data/lib/ably/models/connection_details.rb +8 -6
  10. data/lib/ably/models/error_info.rb +3 -3
  11. data/lib/ably/models/idiomatic_ruby_wrapper.rb +27 -20
  12. data/lib/ably/models/message.rb +15 -15
  13. data/lib/ably/models/message_encoders/cipher.rb +8 -7
  14. data/lib/ably/models/presence_message.rb +17 -17
  15. data/lib/ably/models/protocol_message.rb +26 -19
  16. data/lib/ably/models/stats.rb +15 -15
  17. data/lib/ably/models/token_details.rb +14 -12
  18. data/lib/ably/models/token_request.rb +16 -14
  19. data/lib/ably/modules/async_wrapper.rb +1 -1
  20. data/lib/ably/modules/encodeable.rb +10 -10
  21. data/lib/ably/modules/model_common.rb +13 -5
  22. data/lib/ably/realtime/channel.rb +1 -2
  23. data/lib/ably/realtime/presence.rb +29 -58
  24. data/lib/ably/realtime/presence/members_map.rb +2 -2
  25. data/lib/ably/rest/channel.rb +1 -2
  26. data/lib/ably/rest/middleware/exceptions.rb +14 -4
  27. data/lib/ably/rest/presence.rb +3 -1
  28. data/lib/ably/util/crypto.rb +50 -40
  29. data/lib/ably/version.rb +1 -1
  30. data/spec/acceptance/realtime/message_spec.rb +20 -20
  31. data/spec/acceptance/realtime/presence_history_spec.rb +7 -7
  32. data/spec/acceptance/realtime/presence_spec.rb +65 -77
  33. data/spec/acceptance/rest/auth_spec.rb +8 -8
  34. data/spec/acceptance/rest/base_spec.rb +4 -4
  35. data/spec/acceptance/rest/channel_spec.rb +1 -1
  36. data/spec/acceptance/rest/client_spec.rb +1 -1
  37. data/spec/acceptance/rest/encoders_spec.rb +4 -4
  38. data/spec/acceptance/rest/message_spec.rb +15 -15
  39. data/spec/acceptance/rest/presence_spec.rb +4 -4
  40. data/spec/shared/model_behaviour.rb +7 -7
  41. data/spec/unit/models/cipher_params_spec.rb +140 -0
  42. data/spec/unit/models/idiomatic_ruby_wrapper_spec.rb +15 -8
  43. data/spec/unit/models/message_encoders/cipher_spec.rb +28 -22
  44. data/spec/unit/models/message_encoders/json_spec.rb +24 -0
  45. data/spec/unit/models/protocol_message_spec.rb +3 -3
  46. data/spec/unit/util/crypto_spec.rb +50 -17
  47. metadata +5 -2
@@ -34,7 +34,7 @@ module Ably::Models
34
34
  # Therefore, the `encoding` attribute should always be nil unless an Ably library decoding error has occurred.
35
35
  # @!attribute [r] timestamp
36
36
  # @return [Time] Timestamp when the message was received by the Ably the realtime service
37
- # @!attribute [r] hash
37
+ # @!attribute [r] attributes
38
38
  # @return [Hash] Access the protocol message Hash object ruby'fied to use symbolized keys
39
39
  #
40
40
  class PresenceMessage
@@ -54,17 +54,17 @@ module Ably::Models
54
54
 
55
55
  # {PresenceMessage} initializer
56
56
  #
57
- # @param hash_object [Hash] object with the underlying presence message details
57
+ # @param attributes [Hash] object with the underlying presence message key value attributes
58
58
  # @param [Hash] options an options Hash for this initializer
59
59
  # @option options [ProtocolMessage] :protocol_message An optional protocol message to assocate the presence message with
60
60
  # @option options [Logger] :logger An optional Logger to be used by {Ably::Modules::SafeDeferrable} if an exception is caught in a callback
61
61
  #
62
- def initialize(hash_object, options = {})
62
+ def initialize(attributes, options = {})
63
63
  @logger = options[:logger] # Logger expected for SafeDeferrable
64
64
  @protocol_message = options[:protocol_message]
65
- @raw_hash_object = hash_object
65
+ @raw_hash_object = attributes
66
66
 
67
- set_hash_object hash_object
67
+ set_attributes_object attributes
68
68
 
69
69
  ensure_utf_8 :client_id, client_id, allow_nil: true
70
70
  ensure_utf_8 :connection_id, connection_id, allow_nil: true
@@ -73,16 +73,16 @@ module Ably::Models
73
73
 
74
74
  %w( client_id data encoding ).each do |attribute|
75
75
  define_method attribute do
76
- hash[attribute.to_sym]
76
+ attributes[attribute.to_sym]
77
77
  end
78
78
  end
79
79
 
80
80
  def id
81
- hash.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
81
+ attributes.fetch(:id) { "#{protocol_message.id!}:#{protocol_message_index}" }
82
82
  end
83
83
 
84
84
  def connection_id
85
- hash.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
85
+ attributes.fetch(:connection_id) { protocol_message.connection_id if assigned_to_protocol_message? }
86
86
  end
87
87
 
88
88
  def member_key
@@ -90,24 +90,24 @@ module Ably::Models
90
90
  end
91
91
 
92
92
  def timestamp
93
- if hash[:timestamp]
94
- as_time_from_epoch(hash[:timestamp])
93
+ if attributes[:timestamp]
94
+ as_time_from_epoch(attributes[:timestamp])
95
95
  else
96
96
  protocol_message.timestamp
97
97
  end
98
98
  end
99
99
 
100
100
  def action
101
- ACTION(hash[:action])
101
+ ACTION(attributes[:action])
102
102
  end
103
103
 
104
- def hash
105
- @hash_object
104
+ def attributes
105
+ @attributes
106
106
  end
107
107
 
108
- # Return a JSON ready object from the underlying #hash using Ably naming conventions for keys
108
+ # Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys
109
109
  def as_json(*args)
110
- hash.dup.tap do |presence_message|
110
+ attributes.dup.tap do |presence_message|
111
111
  presence_message['action'] = action.to_i
112
112
  end.as_json.reject { |key, val| val.nil? }
113
113
  rescue KeyError
@@ -151,8 +151,8 @@ module Ably::Models
151
151
  protocol_message.presence.index(self)
152
152
  end
153
153
 
154
- def set_hash_object(hash)
155
- @hash_object = IdiomaticRubyWrapper(hash.clone.freeze, stop_at: [:data])
154
+ def set_attributes_object(new_attributes)
155
+ @attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze, stop_at: [:data])
156
156
  end
157
157
 
158
158
  def logger
@@ -32,7 +32,7 @@ module Ably::Models
32
32
  # @return [Array<PresenceMessage>] A {ProtocolMessage} with a `:presence` action contains one or more presence updates belonging to the channel
33
33
  # @!attribute [r] flags
34
34
  # @return [Integer] Flags indicating special ProtocolMessage states
35
- # @!attribute [r] hash
35
+ # @!attribute [r] attributes
36
36
  # @return [Hash] Access the protocol message Hash object ruby'fied to use symbolized keys
37
37
  #
38
38
  class ProtocolMessage
@@ -66,6 +66,7 @@ module Ably::Models
66
66
  )
67
67
 
68
68
  # Indicates this protocol message action will generate an ACK response such as :message or :presence
69
+ # @api private
69
70
  def self.ack_required?(for_action)
70
71
  [ACTION.Presence, ACTION.Message].include?(ACTION(for_action))
71
72
  end
@@ -90,14 +91,14 @@ module Ably::Models
90
91
 
91
92
  %w(id channel channel_serial connection_id).each do |attribute|
92
93
  define_method attribute do
93
- hash[attribute.to_sym]
94
+ attributes[attribute.to_sym]
94
95
  end
95
96
  end
96
97
 
97
98
  def connection_key
98
99
  # connection_key in connection details takes precedence over connection_key on the ProtocolMessage
99
100
  # connection_key in the ProtocolMessage will be deprecated in future protocol versions > 0.8
100
- connection_details.connection_key || hash[:connection_key]
101
+ connection_details.connection_key || attributes[:connection_key]
101
102
  end
102
103
 
103
104
  def id!
@@ -106,41 +107,43 @@ module Ably::Models
106
107
  end
107
108
 
108
109
  def action
109
- ACTION(hash[:action])
110
+ ACTION(attributes[:action])
110
111
  rescue KeyError
111
- raise KeyError, "Action '#{hash[:action]}' is not supported by ProtocolMessage"
112
+ raise KeyError, "Action '#{attributes[:action]}' is not supported by ProtocolMessage"
112
113
  end
113
114
 
114
115
  def error
115
- @error ||= ErrorInfo.new(hash[:error]) if hash[:error]
116
+ @error ||= ErrorInfo.new(attributes[:error]) if attributes[:error]
116
117
  end
117
118
 
118
119
  def timestamp
119
- as_time_from_epoch(hash[:timestamp]) if hash[:timestamp]
120
+ as_time_from_epoch(attributes[:timestamp]) if attributes[:timestamp]
120
121
  end
121
122
 
122
123
  def message_serial
123
- Integer(hash[:msg_serial])
124
+ Integer(attributes[:msg_serial])
124
125
  rescue TypeError
125
- raise TypeError, "msg_serial '#{hash[:msg_serial]}' is invalid, a positive Integer is expected for a ProtocolMessage"
126
+ raise TypeError, "msg_serial '#{attributes[:msg_serial]}' is invalid, a positive Integer is expected for a ProtocolMessage"
126
127
  end
127
128
 
128
129
  def connection_serial
129
- Integer(hash[:connection_serial])
130
+ Integer(attributes[:connection_serial])
130
131
  rescue TypeError
131
- raise TypeError, "connection_serial '#{hash[:connection_serial]}' is invalid, a positive Integer is expected for a ProtocolMessage"
132
+ raise TypeError, "connection_serial '#{attributes[:connection_serial]}' is invalid, a positive Integer is expected for a ProtocolMessage"
132
133
  end
133
134
 
134
135
  def count
135
- [1, hash[:count].to_i].max
136
+ [1, attributes[:count].to_i].max
136
137
  end
137
138
 
139
+ # @api private
138
140
  def has_message_serial?
139
141
  message_serial && true
140
142
  rescue TypeError
141
143
  false
142
144
  end
143
145
 
146
+ # @api private
144
147
  def has_connection_serial?
145
148
  connection_serial && true
146
149
  rescue TypeError
@@ -155,58 +158,62 @@ module Ably::Models
155
158
  end
156
159
  end
157
160
 
161
+ # @api private
158
162
  def has_serial?
159
163
  has_connection_serial? || has_message_serial?
160
164
  end
161
165
 
162
166
  def messages
163
167
  @messages ||=
164
- Array(hash[:messages]).map do |message|
168
+ Array(attributes[:messages]).map do |message|
165
169
  Ably::Models.Message(message, protocol_message: self)
166
170
  end
167
171
  end
168
172
 
173
+ # @api private
169
174
  def add_message(message)
170
175
  messages << message
171
176
  end
172
177
 
173
178
  def presence
174
179
  @presence ||=
175
- Array(hash[:presence]).map do |message|
180
+ Array(attributes[:presence]).map do |message|
176
181
  Ably::Models.PresenceMessage(message, protocol_message: self)
177
182
  end
178
183
  end
179
184
 
180
185
  def flags
181
- Integer(hash[:flags])
186
+ Integer(attributes[:flags])
182
187
  rescue TypeError
183
188
  0
184
189
  end
185
190
 
191
+ # @api private
186
192
  def has_presence_flag?
187
193
  flags & 1 == 1
188
194
  end
189
195
 
190
196
  def connection_details
191
- @connection_details ||= Ably::Models::ConnectionDetails(hash[:connection_details])
197
+ @connection_details ||= Ably::Models::ConnectionDetails(attributes[:connection_details])
192
198
  end
193
199
 
194
200
  # Indicates this protocol message will generate an ACK response when sent
195
201
  # Examples of protocol messages required ACK include :message and :presence
202
+ # @api private
196
203
  def ack_required?
197
204
  self.class.ack_required?(action)
198
205
  end
199
206
 
200
- def hash
207
+ def attributes
201
208
  @hash_object
202
209
  end
203
210
 
204
- # Return a JSON ready object from the underlying #hash using Ably naming conventions for keys
211
+ # Return a JSON ready object from the underlying #attributes using Ably naming conventions for keys
205
212
  def as_json(*args)
206
213
  raise TypeError, ':action is missing, cannot generate a valid Hash for ProtocolMessage' unless action
207
214
  raise TypeError, ':msg_serial or :connection_serial is missing, cannot generate a valid Hash for ProtocolMessage' if ack_required? && !has_serial?
208
215
 
209
- hash.dup.tap do |hash_object|
216
+ attributes.dup.tap do |hash_object|
210
217
  hash_object['action'] = action.to_i
211
218
  hash_object['messages'] = messages.map(&:as_json) unless messages.empty?
212
219
  hash_object['presence'] = presence.map(&:as_json) unless presence.empty?
@@ -117,61 +117,61 @@ module Ably::Models
117
117
  #
118
118
  def initialize(hash_object)
119
119
  @raw_hash_object = hash_object
120
- set_hash_object hash_object
120
+ set_attributes_object hash_object
121
121
  end
122
122
 
123
123
  # Aggregates inbound and outbound messages
124
124
  # @return {Stats::MessageTypes}
125
125
  def all
126
- @all ||= Stats::MessageTypes.new(hash[:all])
126
+ @all ||= Stats::MessageTypes.new(attributes[:all])
127
127
  end
128
128
 
129
129
  # All inbound messages i.e. received by Ably from clients
130
130
  # @return {Stats::MessageTraffic}
131
131
  def inbound
132
- @inbound ||= Stats::MessageTraffic.new(hash[:inbound])
132
+ @inbound ||= Stats::MessageTraffic.new(attributes[:inbound])
133
133
  end
134
134
 
135
135
  # All outbound messages i.e. sent from Ably to clients
136
136
  # @return {Stats::MessageTraffic}
137
137
  def outbound
138
- @outbound ||= Stats::MessageTraffic.new(hash[:outbound])
138
+ @outbound ||= Stats::MessageTraffic.new(attributes[:outbound])
139
139
  end
140
140
 
141
141
  # Messages persisted for later retrieval via the history API
142
142
  # @return {Stats::MessageTypes}
143
143
  def persisted
144
- @persisted ||= Stats::MessageTypes.new(hash[:persisted])
144
+ @persisted ||= Stats::MessageTypes.new(attributes[:persisted])
145
145
  end
146
146
 
147
147
  # Breakdown of connection stats data for different (TLS vs non-TLS) connection types
148
148
  # @return {Stats::ConnectionTypes}
149
149
  def connections
150
- @connections ||= Stats::ConnectionTypes.new(hash[:connections])
150
+ @connections ||= Stats::ConnectionTypes.new(attributes[:connections])
151
151
  end
152
152
 
153
153
  # Breakdown of channels stats
154
154
  # @return {Stats::ResourceCount}
155
155
  def channels
156
- @channels ||= Stats::ResourceCount.new(hash[:channels])
156
+ @channels ||= Stats::ResourceCount.new(attributes[:channels])
157
157
  end
158
158
 
159
159
  # Breakdown of API requests received via the REST API
160
160
  # @return {Stats::RequestCount}
161
161
  def api_requests
162
- @api_requests ||= Stats::RequestCount.new(hash[:api_requests])
162
+ @api_requests ||= Stats::RequestCount.new(attributes[:api_requests])
163
163
  end
164
164
 
165
165
  # Breakdown of Token requests received via the REST API
166
166
  # @return {Stats::RequestCount}
167
167
  def token_requests
168
- @token_requests ||= Stats::RequestCount.new(hash[:token_requests])
168
+ @token_requests ||= Stats::RequestCount.new(attributes[:token_requests])
169
169
  end
170
170
 
171
171
  # @!attribute [r] interval_id
172
172
  # @return [String] The interval that this statistic applies to, see {GRANULARITY} and {INTERVAL_FORMAT_STRING}
173
173
  def interval_id
174
- hash.fetch(:interval_id)
174
+ attributes.fetch(:interval_id)
175
175
  end
176
176
 
177
177
  # @!attribute [r] interval_time
@@ -186,12 +186,12 @@ module Ably::Models
186
186
  self.class.granularity_from_interval_id(interval_id)
187
187
  end
188
188
 
189
- def hash
190
- @hash_object
189
+ def attributes
190
+ @attributes
191
191
  end
192
192
 
193
193
  def as_json(*args)
194
- hash.as_json(*args).reject { |key, val| val.nil? }
194
+ attributes.as_json(*args).reject { |key, val| val.nil? }
195
195
  end
196
196
 
197
197
  private
@@ -199,8 +199,8 @@ module Ably::Models
199
199
  @raw_hash_object
200
200
  end
201
201
 
202
- def set_hash_object(hash)
203
- @hash_object = IdiomaticRubyWrapper(hash.clone.freeze)
202
+ def set_attributes_object(new_attributes)
203
+ @attributes = IdiomaticRubyWrapper(new_attributes.clone.freeze)
204
204
  end
205
205
  end
206
206
  end
@@ -16,7 +16,7 @@ module Ably::Models
16
16
  # TokenDetails is a class providing details of the token string and the token's associated metadata,
17
17
  # constructed from the response from Ably when request in a token via the REST API.
18
18
  #
19
- # Ruby {Time} objects are supported in place of Ably ms since epoch time fields. However, if a numeric is provided
19
+ # Ruby {http://ruby-doc.org/core/Time.html Time} objects are supported in place of Ably ms since epoch time fields. However, if a numeric is provided
20
20
  # it must always be expressed in milliseconds as the Ably API always uses milliseconds for time fields.
21
21
  #
22
22
  class TokenDetails
@@ -38,46 +38,48 @@ module Ably::Models
38
38
  @hash_object = IdiomaticRubyWrapper(attributes.clone)
39
39
 
40
40
  %w(issued expires).map(&:to_sym).each do |time_attribute|
41
- hash[time_attribute] = (hash[time_attribute].to_f * 1000).round if hash[time_attribute].kind_of?(Time)
41
+ if self.attributes[time_attribute].kind_of?(Time)
42
+ self.attributes[time_attribute] = (self.attributes[time_attribute].to_f * 1000).round
43
+ end
42
44
  end
43
45
 
44
- hash.freeze
46
+ self.attributes.freeze
45
47
  end
46
48
 
47
49
  # @!attribute [r] token
48
50
  # @return [String] Token used to authenticate requests
49
51
  def token
50
- hash[:token]
52
+ attributes[:token]
51
53
  end
52
54
 
53
55
  # @!attribute [r] key_name
54
56
  # @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 +:+
55
57
  def key_name
56
- hash[:key_name]
58
+ attributes[:key_name]
57
59
  end
58
60
 
59
61
  # @!attribute [r] issued
60
62
  # @return [Time] Time the token was issued
61
63
  def issued
62
- as_time_from_epoch(hash[:issued], granularity: :ms, allow_nil: :true)
64
+ as_time_from_epoch(attributes[:issued], granularity: :ms, allow_nil: :true)
63
65
  end
64
66
 
65
67
  # @!attribute [r] expires
66
68
  # @return [Time] Time the token expires
67
69
  def expires
68
- as_time_from_epoch(hash[:expires], granularity: :ms, allow_nil: :true)
70
+ as_time_from_epoch(attributes[:expires], granularity: :ms, allow_nil: :true)
69
71
  end
70
72
 
71
73
  # @!attribute [r] capability
72
74
  # @return [Hash] Capabilities assigned to this token
73
75
  def capability
74
- JSON.parse(hash.fetch(:capability)) if hash.has_key?(:capability)
76
+ JSON.parse(attributes.fetch(:capability)) if attributes.has_key?(:capability)
75
77
  end
76
78
 
77
79
  # @!attribute [r] client_id
78
80
  # @return [String] Optional client ID assigned to this token
79
81
  def client_id
80
- hash[:client_id]
82
+ attributes[:client_id]
81
83
  end
82
84
 
83
85
  # Returns true if token is expired or about to expire
@@ -93,12 +95,12 @@ module Ably::Models
93
95
  # @return [Boolean]
94
96
  # @api private
95
97
  def from_token_string?
96
- hash.keys == [:token]
98
+ attributes.keys == [:token]
97
99
  end
98
100
 
99
- # @!attribute [r] hash
101
+ # @!attribute [r] attributes
100
102
  # @return [Hash] Access the token details Hash object ruby'fied to use symbolized keys
101
- def hash
103
+ def attributes
102
104
  @hash_object
103
105
  end
104
106
 
@@ -16,7 +16,7 @@ module Ably::Models
16
16
 
17
17
  # TokenRequest is a class that stores the attributes of a token request
18
18
  #
19
- # Ruby {Time} objects are supported in place of Ably ms since epoch time fields. However, if a numeric is provided
19
+ # Ruby {http://ruby-doc.org/core/Time.html Time} objects are supported in place of Ably ms since epoch time fields. However, if a numeric is provided
20
20
  # it must always be expressed in milliseconds as the Ably API always uses milliseconds for time fields.
21
21
  #
22
22
  class TokenRequest
@@ -24,7 +24,7 @@ module Ably::Models
24
24
 
25
25
  # @param attributes
26
26
  # @option attributes [Integer] :ttl requested time to live for the token in milliseconds
27
- # @option attributes [Time,Integer] :timestamp the timestamp of this request in milliseconds or as a {Time}
27
+ # @option attributes [Time,Integer] :timestamp the timestamp of this request in milliseconds or as a {http://ruby-doc.org/core/Time.html Time}
28
28
  # @option attributes [String] :key_name API key name of the key against which this request is made
29
29
  # @option attributes [String] :capability JSON stringified capability of the token
30
30
  # @option attributes [String] :client_id client ID to associate with this token
@@ -33,14 +33,16 @@ module Ably::Models
33
33
  #
34
34
  def initialize(attributes = {})
35
35
  @hash_object = IdiomaticRubyWrapper(attributes.clone)
36
- hash[:timestamp] = (hash[:timestamp].to_f * 1000).round if hash[:timestamp].kind_of?(Time)
37
- hash.freeze
36
+ if self.attributes[:timestamp].kind_of?(Time)
37
+ self.attributes[:timestamp] = (self.attributes[:timestamp].to_f * 1000).round
38
+ end
39
+ self.attributes.freeze
38
40
  end
39
41
 
40
42
  # @!attribute [r] key_name
41
43
  # @return [String] API key name of the key against which this request is made. An API key is made up of an API key name and secret delimited by a +:+
42
44
  def key_name
43
- hash.fetch(:key_name)
45
+ attributes.fetch(:key_name)
44
46
  end
45
47
 
46
48
  # @!attribute [r] ttl
@@ -49,7 +51,7 @@ module Ably::Models
49
51
  # settings and the attributes of the issuing key.
50
52
  # TTL when sent to Ably is in milliseconds.
51
53
  def ttl
52
- hash.fetch(:ttl) / 1000
54
+ attributes.fetch(:ttl) / 1000
53
55
  end
54
56
 
55
57
  # @!attribute [r] capability
@@ -57,14 +59,14 @@ module Ably::Models
57
59
  # the capability of the returned token will be the intersection of
58
60
  # this capability with the capability of the issuing key.
59
61
  def capability
60
- JSON.parse(hash.fetch(:capability))
62
+ JSON.parse(attributes.fetch(:capability))
61
63
  end
62
64
 
63
65
  # @!attribute [r] client_id
64
66
  # @return [String] the client ID to associate with this token. The generated token
65
67
  # may be used to authenticate as this clientId.
66
68
  def client_id
67
- hash[:client_id]
69
+ attributes[:client_id]
68
70
  end
69
71
 
70
72
  # @!attribute [r] timestamp
@@ -73,7 +75,7 @@ module Ably::Models
73
75
  # token requests from being replayed.
74
76
  # Timestamp when sent to Ably is in milliseconds.
75
77
  def timestamp
76
- as_time_from_epoch(hash.fetch(:timestamp), granularity: :ms)
78
+ as_time_from_epoch(attributes.fetch(:timestamp), granularity: :ms)
77
79
  end
78
80
 
79
81
  # @!attribute [r] nonce
@@ -81,26 +83,26 @@ module Ably::Models
81
83
  # uniqueness of this request. Any subsequent request using the
82
84
  # same nonce will be rejected.
83
85
  def nonce
84
- hash.fetch(:nonce)
86
+ attributes.fetch(:nonce)
85
87
  end
86
88
 
87
89
  # @!attribute [r] mac
88
90
  # @return [String] the Message Authentication Code for this request. See the
89
91
  # {https://www.ably.io/documentation Ably Authentication documentation} for more details.
90
92
  def mac
91
- hash.fetch(:mac)
93
+ attributes.fetch(:mac)
92
94
  end
93
95
 
94
96
  # Requests that the token is always persisted
95
97
  # @api private
96
98
  #
97
99
  def persisted
98
- hash.fetch(:persisted)
100
+ attributes.fetch(:persisted)
99
101
  end
100
102
 
101
- # @!attribute [r] hash
103
+ # @!attribute [r] attributes
102
104
  # @return [Hash] the token request Hash object ruby'fied to use symbolized keys
103
- def hash
105
+ def attributes
104
106
  @hash_object
105
107
  end
106
108
  end