ably 0.2.0 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/ably/models/paginated_resource.rb +40 -13
- data/lib/ably/modules/async_wrapper.rb +60 -0
- data/lib/ably/realtime/channel.rb +13 -2
- data/lib/ably/realtime/client.rb +21 -8
- data/lib/ably/realtime/presence.rb +32 -6
- data/lib/ably/rest/channel.rb +8 -2
- data/lib/ably/rest/presence.rb +31 -5
- data/lib/ably/version.rb +1 -1
- data/spec/acceptance/realtime/channel_history_spec.rb +33 -21
- data/spec/acceptance/realtime/presence_history_spec.rb +14 -12
- data/spec/acceptance/realtime/stats_spec.rb +31 -0
- data/spec/acceptance/realtime/time_spec.rb +31 -0
- data/spec/acceptance/rest/presence_spec.rb +2 -0
- data/spec/acceptance/rest/stats_spec.rb +1 -1
- data/spec/acceptance/rest/time_spec.rb +2 -3
- data/spec/unit/models/paginated_resource_spec.rb +55 -13
- data/spec/unit/modules/async_wrapper_spec.rb +125 -0
- data/spec/unit/realtime/client_spec.rb +0 -10
- data/spec/unit/realtime/presence_spec.rb +3 -1
- data/spec/unit/realtime/websocket_transport_spec.rb +3 -2
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee3e7490507273d4da5f34286db1f6ee1e0bc968
|
4
|
+
data.tar.gz: a1558974a048679f9572bb607ce4ea00746364ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8b0da46c04457a191111f3c58a004d8f12dbeee12ad9f47836a86c836132d99b7e4675220644050c8c7ab1342e71c84d1477f5dc1256d593f7e028bbbe94298
|
7
|
+
data.tar.gz: da2d88e2cba687467a1b5cd79259cf6ec78cb00de7f9ae22f26641b154197dc3dfded91be3adddceed1e0e48b79ac53055af3b23c6dec3444adf4b039c31e42a
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module Ably::Models
|
2
|
-
# Wraps any Ably HTTP response that supports paging and automatically provides
|
2
|
+
# Wraps any Ably HTTP response that supports paging and automatically provides methods to iterate through
|
3
3
|
# the array of resources using {#first_page}, {#next_page}, {#first_page?} and {#last_page?}
|
4
4
|
#
|
5
5
|
# Paging information is provided by Ably in the LINK HTTP headers
|
6
6
|
class PaginatedResource
|
7
7
|
include Enumerable
|
8
|
+
include Ably::Modules::AsyncWrapper
|
8
9
|
|
9
10
|
# @param [Faraday::Response] http_response Initial HTTP response from an Ably request to a paged resource
|
10
11
|
# @param [String] base_url Base URL for request that generated the http_response so that subsequent paged requests can be made
|
@@ -12,6 +13,8 @@ module Ably::Models
|
|
12
13
|
# @param [Hash] options Options for this paged resource
|
13
14
|
# @option options [Symbol,String] :coerce_into symbol or string representing class that should be used to create each item in the PaginatedResource
|
14
15
|
#
|
16
|
+
# @yield [Object] block will be called for each resource object for the current page. This is a useful way to apply a transformation to any page resources after they are retrieved
|
17
|
+
#
|
15
18
|
# @return [PaginatedResource]
|
16
19
|
def initialize(http_response, base_url, client, options = {}, &each_block)
|
17
20
|
@http_response = http_response
|
@@ -20,6 +23,7 @@ module Ably::Models
|
|
20
23
|
@coerce_into = options[:coerce_into]
|
21
24
|
@raw_body = http_response.body
|
22
25
|
@each_block = each_block
|
26
|
+
@make_async = options.fetch(:async_blocking_operations, false)
|
23
27
|
|
24
28
|
@body = if @coerce_into
|
25
29
|
http_response.body.map do |item|
|
@@ -34,19 +38,27 @@ module Ably::Models
|
|
34
38
|
end if block_given?
|
35
39
|
end
|
36
40
|
|
37
|
-
# Retrieve the first page of results
|
41
|
+
# Retrieve the first page of results.
|
42
|
+
# When used as part of the {Ably::Realtime} library, it will return a {EventMachine::Deferrable} object,
|
43
|
+
# and allows an optional success callback block to be provided.
|
38
44
|
#
|
39
|
-
# @return [PaginatedResource]
|
40
|
-
def first_page
|
41
|
-
|
45
|
+
# @return [PaginatedResource,EventMachine::Deferrable]
|
46
|
+
def first_page(&success_callback)
|
47
|
+
async_wrap_if(make_async, success_callback) do
|
48
|
+
PaginatedResource.new(client.get(pagination_url('first')), base_url, client, pagination_options, &each_block)
|
49
|
+
end
|
42
50
|
end
|
43
51
|
|
44
|
-
# Retrieve the next page of results
|
52
|
+
# Retrieve the next page of results.
|
53
|
+
# When used as part of the {Ably::Realtime} library, it will return a {EventMachine::Deferrable} object,
|
54
|
+
# and allows an optional success callback block to be provided.
|
45
55
|
#
|
46
|
-
# @return [PaginatedResource]
|
47
|
-
def next_page
|
48
|
-
|
49
|
-
|
56
|
+
# @return [PaginatedResource,EventMachine::Deferrable]
|
57
|
+
def next_page(&success_callback)
|
58
|
+
async_wrap_if(make_async, success_callback) do
|
59
|
+
raise Ably::Exceptions::InvalidPageError, 'There are no more pages' if supports_pagination? && last_page?
|
60
|
+
PaginatedResource.new(client.get(pagination_url('next')), base_url, client, pagination_options, &each_block)
|
61
|
+
end
|
50
62
|
end
|
51
63
|
|
52
64
|
# True if this is the last page in the paged resource set
|
@@ -84,7 +96,7 @@ module Ably::Models
|
|
84
96
|
alias_method :count, :length
|
85
97
|
alias_method :size, :length
|
86
98
|
|
87
|
-
# Method
|
99
|
+
# Method to allow {PaginatedResource} to be {http://ruby-doc.org/core-2.1.3/Enumerable.html Enumerable}
|
88
100
|
def each(&block)
|
89
101
|
body.each do |item|
|
90
102
|
if block_given?
|
@@ -95,7 +107,7 @@ module Ably::Models
|
|
95
107
|
end
|
96
108
|
end
|
97
109
|
|
98
|
-
#
|
110
|
+
# First item in this page
|
99
111
|
def first
|
100
112
|
body.first
|
101
113
|
end
|
@@ -118,7 +130,7 @@ module Ably::Models
|
|
118
130
|
end
|
119
131
|
|
120
132
|
private
|
121
|
-
attr_reader :body, :http_response, :base_url, :client, :coerce_into, :raw_body, :each_block
|
133
|
+
attr_reader :body, :http_response, :base_url, :client, :coerce_into, :raw_body, :each_block, :make_async
|
122
134
|
|
123
135
|
def pagination_headers
|
124
136
|
link_regex = %r{<(?<url>[^>]+)>; rel="(?<rel>[^"]+)"}
|
@@ -146,5 +158,20 @@ module Ably::Models
|
|
146
158
|
pagination_header[id]
|
147
159
|
end
|
148
160
|
end
|
161
|
+
|
162
|
+
def pagination_options
|
163
|
+
{
|
164
|
+
coerce_into: coerce_into,
|
165
|
+
async_blocking_operations: make_async
|
166
|
+
}
|
167
|
+
end
|
168
|
+
|
169
|
+
def async_wrap_if(is_realtime, success_callback, &operation)
|
170
|
+
if is_realtime
|
171
|
+
async_wrap success_callback, &operation
|
172
|
+
else
|
173
|
+
yield
|
174
|
+
end
|
175
|
+
end
|
149
176
|
end
|
150
177
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Ably::Modules
|
2
|
+
# Provides methods to convert synchronous operations into async operations through the use of
|
3
|
+
# {EventMachine#defer http://www.rubydoc.info/github/eventmachine/eventmachine/EventMachine#defer-class_method}.
|
4
|
+
# The async_wrap method can only be called from within an EventMachine reactor, and must be thread safe.
|
5
|
+
#
|
6
|
+
# @note using this AsyncWrapper should only be used for methods that are used less frequently and typically
|
7
|
+
# not run with levels of concurrency due to the limited number of threads available to EventMachine by default.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# class BlockingOperation
|
11
|
+
# include Aby::Modules::AsyncWrapper
|
12
|
+
#
|
13
|
+
# def operation(&success_callback)
|
14
|
+
# async_wrap(success_callback) do
|
15
|
+
# sleep 1
|
16
|
+
# 'slept'
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# blocking_object = BlockingOperation.new
|
22
|
+
# deferrable = blocking_object.operation do |result|
|
23
|
+
# puts "Done with result: #{result}"
|
24
|
+
# end
|
25
|
+
# puts "Starting"
|
26
|
+
#
|
27
|
+
# # => 'Starting'
|
28
|
+
# # => 'Done with result: slept'
|
29
|
+
#
|
30
|
+
module AsyncWrapper
|
31
|
+
private
|
32
|
+
|
33
|
+
# Will yield the provided block in a new thread and return an {EventMachine::Deferrable http://www.rubydoc.info/github/eventmachine/eventmachine/EventMachine/Deferrable}
|
34
|
+
#
|
35
|
+
# @yield [Object] operation block that is run in a thread
|
36
|
+
# @return [EventMachine::Deferrable]
|
37
|
+
#
|
38
|
+
def async_wrap(success_callback = nil, &operation)
|
39
|
+
raise ArgumentError, "Operation block is missing" unless block_given?
|
40
|
+
|
41
|
+
EventMachine::DefaultDeferrable.new.tap do |deferrable|
|
42
|
+
deferrable.callback &success_callback if success_callback
|
43
|
+
|
44
|
+
operation_with_exception_handling = proc do
|
45
|
+
begin
|
46
|
+
yield
|
47
|
+
rescue StandardError => e
|
48
|
+
deferrable.fail e
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
complete_callback = proc do |result|
|
53
|
+
deferrable.succeed result
|
54
|
+
end
|
55
|
+
|
56
|
+
EventMachine.defer operation_with_exception_handling, complete_callback
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -36,6 +36,7 @@ module Ably
|
|
36
36
|
include Ably::Modules::Conversions
|
37
37
|
include Ably::Modules::EventEmitter
|
38
38
|
include Ably::Modules::EventMachineHelpers
|
39
|
+
include Ably::Modules::AsyncWrapper
|
39
40
|
extend Ably::Modules::Enum
|
40
41
|
|
41
42
|
STATE = ruby_enum('STATE',
|
@@ -102,6 +103,8 @@ module Ably
|
|
102
103
|
# @param name [String] The event name of the message to subscribe to if provided. Defaults to all events.
|
103
104
|
# @yield [Ably::Models::Message] For each message received, the block is called
|
104
105
|
#
|
106
|
+
# @return [void]
|
107
|
+
#
|
105
108
|
def subscribe(name = :all, &blk)
|
106
109
|
attach unless attached? || attaching?
|
107
110
|
subscriptions[message_name_key(name)] << blk
|
@@ -112,6 +115,8 @@ module Ably
|
|
112
115
|
#
|
113
116
|
# @param name [String] The event name of the message to subscribe to if provided. Defaults to all events.
|
114
117
|
#
|
118
|
+
# @return [void]
|
119
|
+
#
|
115
120
|
def unsubscribe(name = :all, &blk)
|
116
121
|
if message_name_key(name) == :all
|
117
122
|
subscriptions.keys
|
@@ -174,8 +179,14 @@ module Ably
|
|
174
179
|
#
|
175
180
|
# @param (see Ably::Rest::Channel#history)
|
176
181
|
# @option options (see Ably::Rest::Channel#history)
|
177
|
-
|
178
|
-
|
182
|
+
#
|
183
|
+
# @yield [Ably::Models::PaginatedResource<Ably::Models::Message>] An Array of {Ably::Models::Message} objects that supports paging (#next_page, #first_page)
|
184
|
+
#
|
185
|
+
# @return [EventMachine::Deferrable]
|
186
|
+
def history(options = {}, &callback)
|
187
|
+
async_wrap(callback) do
|
188
|
+
rest_channel.history(options.merge(async_blocking_operations: true))
|
189
|
+
end
|
179
190
|
end
|
180
191
|
|
181
192
|
# @!attribute [r] __incoming_msgbus__
|
data/lib/ably/realtime/client.rb
CHANGED
@@ -23,6 +23,7 @@ module Ably
|
|
23
23
|
# @!attribute [r] protocol_binary?
|
24
24
|
# (see Ably::Rest::Client#protocol_binary?)
|
25
25
|
class Client
|
26
|
+
include Ably::Modules::AsyncWrapper
|
26
27
|
extend Forwardable
|
27
28
|
|
28
29
|
DOMAIN = 'realtime.ably.io'
|
@@ -66,20 +67,32 @@ module Ably
|
|
66
67
|
# Return a {Ably::Realtime::Channel Realtime Channel} for the given name
|
67
68
|
#
|
68
69
|
# @param (see Ably::Realtime::Channels#get)
|
69
|
-
#
|
70
70
|
# @return (see Ably::Realtime::Channels#get)
|
71
|
+
#
|
71
72
|
def channel(name, channel_options = {})
|
72
73
|
channels.get(name, channel_options)
|
73
74
|
end
|
74
75
|
|
75
|
-
#
|
76
|
-
|
77
|
-
|
76
|
+
# Retrieve the Ably service time
|
77
|
+
#
|
78
|
+
# @yield [Time] The time as reported by the Ably service
|
79
|
+
# @return [EventMachine::Deferrable]
|
80
|
+
#
|
81
|
+
def time(&success_callback)
|
82
|
+
async_wrap(success_callback) do
|
83
|
+
rest_client.time
|
84
|
+
end
|
78
85
|
end
|
79
86
|
|
80
|
-
#
|
81
|
-
|
82
|
-
|
87
|
+
# Retrieve the stats for the application
|
88
|
+
#
|
89
|
+
# @yield [Array] An Array of hashes representing the stats
|
90
|
+
# @return [EventMachine::Deferrable]
|
91
|
+
#
|
92
|
+
def stats(params = {}, &success_callback)
|
93
|
+
async_wrap(success_callback) do
|
94
|
+
rest_client.stats(params)
|
95
|
+
end
|
83
96
|
end
|
84
97
|
|
85
98
|
# (see Ably::Realtime::Connection#close)
|
@@ -103,7 +116,7 @@ module Ably
|
|
103
116
|
end
|
104
117
|
|
105
118
|
# @!attribute [r] custom_socket_host
|
106
|
-
# @return [String,
|
119
|
+
# @return [String,NilClass] Returns the custom socket host that is being used if it was provided with the option :ws_host when the {Client} was created
|
107
120
|
def custom_socket_host
|
108
121
|
@custom_socket_host
|
109
122
|
end
|
@@ -2,6 +2,7 @@ module Ably::Realtime
|
|
2
2
|
# Presence provides access to presence operations and state for the associated Channel
|
3
3
|
class Presence
|
4
4
|
include Ably::Modules::EventEmitter
|
5
|
+
include Ably::Modules::AsyncWrapper
|
5
6
|
extend Ably::Modules::Enum
|
6
7
|
|
7
8
|
STATE = ruby_enum('STATE',
|
@@ -14,12 +15,15 @@ module Ably::Realtime
|
|
14
15
|
)
|
15
16
|
include Ably::Modules::StateEmitter
|
16
17
|
|
17
|
-
# {Ably::Realtime::Channel} this Presence object is
|
18
|
+
# {Ably::Realtime::Channel} this Presence object is associated with
|
19
|
+
# @return {Ably::Realtime::Channel}
|
18
20
|
attr_reader :channel
|
19
21
|
|
20
22
|
# A unique member identifier for this channel client, disambiguating situations where a given
|
21
23
|
# client_id is present on multiple connections simultaneously.
|
22
|
-
#
|
24
|
+
#
|
25
|
+
# @note TODO: This does not work at present as no ACK is sent from the server with a memberId
|
26
|
+
# @return {String}
|
23
27
|
attr_reader :member_id
|
24
28
|
|
25
29
|
def initialize(channel)
|
@@ -36,13 +40,16 @@ module Ably::Realtime
|
|
36
40
|
|
37
41
|
# Enter this client into this channel. This client will be added to the presence set
|
38
42
|
# and presence subscribers will see an enter message for this client.
|
43
|
+
#
|
39
44
|
# @param [Hash,String] options an options Hash to specify client data and/or client ID, or a String with the client data
|
40
45
|
# @option options [String] :data optional data (eg a status message) for this member
|
41
46
|
# @option options [String] :client_id the optional id of the client.
|
42
47
|
# This option is provided to support connections from server instances that act on behalf of
|
43
48
|
# multiple client_ids. In order to be able to enter the channel with this method, the client
|
44
49
|
# library must have been instanced either with a key, or with a token bound to the wildcard clientId.
|
50
|
+
#
|
45
51
|
# @yield [Ably::Realtime::Presence] On success, will call the block with the {Ably::Realtime::Presence}
|
52
|
+
#
|
46
53
|
# @return [Ably::Models::PresenceMessage] Deferrable {Ably::Models::PresenceMessage} that supports both success (callback) and failure (errback) callbacks
|
47
54
|
#
|
48
55
|
def enter(options = {}, &blk)
|
@@ -71,6 +78,7 @@ module Ably::Realtime
|
|
71
78
|
|
72
79
|
# Leave this client from this channel. This client will be removed from the presence
|
73
80
|
# set and presence subscribers will see a leave message for this client.
|
81
|
+
#
|
74
82
|
# @param (see Presence#enter)
|
75
83
|
# @yield (see Presence#enter)
|
76
84
|
# @return (see Presence#enter)
|
@@ -101,6 +109,7 @@ module Ably::Realtime
|
|
101
109
|
# Update the presence data for this client. If the client is not already a member of
|
102
110
|
# the presence set it will be added, and presence subscribers will see an enter or
|
103
111
|
# update message for this client.
|
112
|
+
#
|
104
113
|
# @param (see Presence#enter)
|
105
114
|
# @yield (see Presence#enter)
|
106
115
|
# @return (see Presence#enter)
|
@@ -120,9 +129,15 @@ module Ably::Realtime
|
|
120
129
|
|
121
130
|
# Get the presence state for this Channel.
|
122
131
|
# Optionally get a member's {Ably::Models::PresenceMessage} state by member_id
|
132
|
+
#
|
123
133
|
# @return [Array<Ably::Models::PresenceMessage>, Ably::Models::PresenceMessage] members on the channel
|
124
|
-
|
125
|
-
|
134
|
+
#
|
135
|
+
def get(member_id = nil)
|
136
|
+
if member_id
|
137
|
+
members.find { |key, presence| presence.member_id == member_id }
|
138
|
+
else
|
139
|
+
members.map { |key, presence| presence }
|
140
|
+
end
|
126
141
|
end
|
127
142
|
|
128
143
|
# Subscribe to presence events on the associated Channel.
|
@@ -131,6 +146,8 @@ module Ably::Realtime
|
|
131
146
|
# @param action [Ably::Models::PresenceMessage::ACTION] Optional, the state change action to subscribe to. Defaults to all presence actions
|
132
147
|
# @yield [Ably::Models::PresenceMessage] For each presence state change event, the block is called
|
133
148
|
#
|
149
|
+
# @return [void]
|
150
|
+
#
|
134
151
|
def subscribe(action = :all, &blk)
|
135
152
|
ensure_channel_attached do
|
136
153
|
subscriptions[message_action_key(action)] << blk
|
@@ -142,6 +159,8 @@ module Ably::Realtime
|
|
142
159
|
#
|
143
160
|
# @param action [Ably::Models::PresenceMessage::ACTION] Optional, the state change action to subscribe to. Defaults to all presence actions
|
144
161
|
#
|
162
|
+
# @return [void]
|
163
|
+
#
|
145
164
|
def unsubscribe(action = :all, &blk)
|
146
165
|
if message_action_key(action) == :all
|
147
166
|
subscriptions.keys
|
@@ -158,8 +177,15 @@ module Ably::Realtime
|
|
158
177
|
#
|
159
178
|
# @param (see Ably::Rest::Presence#history)
|
160
179
|
# @option options (see Ably::Rest::Presence#history)
|
161
|
-
|
162
|
-
|
180
|
+
#
|
181
|
+
# @yield [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] An Array of {Ably::Models::PresenceMessage} objects that supports paging (#next_page, #first_page)
|
182
|
+
#
|
183
|
+
# @return [EventMachine::Deferrable]
|
184
|
+
#
|
185
|
+
def history(options = {}, &callback)
|
186
|
+
async_wrap(callback) do
|
187
|
+
rest_presence.history(options.merge(async_blocking_operations: true))
|
188
|
+
end
|
163
189
|
end
|
164
190
|
|
165
191
|
# @!attribute [r] __incoming_msgbus__
|
data/lib/ably/rest/channel.rb
CHANGED
@@ -57,16 +57,22 @@ module Ably
|
|
57
57
|
# @option options [Integer] :limit Maximum number of messages to retrieve up to 10,000
|
58
58
|
# @option options [Symbol] :by `:message`, `:bundle` or `:hour`. Defaults to `:message`
|
59
59
|
#
|
60
|
-
# @return [Ably::Models::PaginatedResource<Ably::Models::Message>] An Array of
|
60
|
+
# @return [Ably::Models::PaginatedResource<Ably::Models::Message>] An Array of {Ably::Models::Message} objects that supports paging (#next_page, #first_page)
|
61
61
|
def history(options = {})
|
62
62
|
url = "#{base_path}/messages"
|
63
|
+
options = options.dup
|
63
64
|
|
64
65
|
merge_options = { live: true } # TODO: Remove live param as all history should be live
|
65
66
|
[:start, :end].each { |option| merge_options[option] = as_since_epoch(options[option]) if options.has_key?(option) }
|
66
67
|
|
68
|
+
paginated_options = {
|
69
|
+
coerce_into: 'Ably::Models::Message',
|
70
|
+
async_blocking_operations: options.delete(:async_blocking_operations),
|
71
|
+
}
|
72
|
+
|
67
73
|
response = client.get(url, options.merge(merge_options))
|
68
74
|
|
69
|
-
Ably::Models::PaginatedResource.new(response, url, client,
|
75
|
+
Ably::Models::PaginatedResource.new(response, url, client, paginated_options) do |message|
|
70
76
|
message.tap do |message|
|
71
77
|
message.decode self
|
72
78
|
end
|
data/lib/ably/rest/presence.rb
CHANGED
@@ -3,7 +3,13 @@ module Ably
|
|
3
3
|
class Presence
|
4
4
|
include Ably::Modules::Conversions
|
5
5
|
|
6
|
-
|
6
|
+
# {Ably::Rest::Client} for this Presence object
|
7
|
+
# @return {Ably::Rest::Client}
|
8
|
+
attr_reader :client
|
9
|
+
|
10
|
+
# {Ably::Rest::Channel} this Presence object is associated with
|
11
|
+
# @return {Ably::Rest::Channel}
|
12
|
+
attr_reader :channel
|
7
13
|
|
8
14
|
# Initialize a new Presence object
|
9
15
|
#
|
@@ -16,11 +22,25 @@ module Ably
|
|
16
22
|
|
17
23
|
# Obtain the set of members currently present for a channel
|
18
24
|
#
|
19
|
-
# @
|
25
|
+
# @param [Hash] options the options for the set of members present
|
26
|
+
# @option options [Integer,Time] :start Time or millisecond since epoch
|
27
|
+
# @option options [Integer,Time] :end Time or millisecond since epoch
|
28
|
+
# @option options [Symbol] :direction `:forwards` or `:backwards`
|
29
|
+
# @option options [Integer] :limit Maximum number of members to retrieve up to 10,000
|
30
|
+
#
|
31
|
+
# @return [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] An Array of {Ably::Models::PresenceMessage} objects that supports paging (#next_page, #first_page)
|
20
32
|
#
|
21
33
|
def get(options = {})
|
34
|
+
options = options.dup
|
35
|
+
|
36
|
+
paginated_options = {
|
37
|
+
coerce_into: 'Ably::Models::PresenceMessage',
|
38
|
+
async_blocking_operations: options.delete(:async_blocking_operations),
|
39
|
+
}
|
40
|
+
|
22
41
|
response = client.get(base_path, options)
|
23
|
-
|
42
|
+
|
43
|
+
Ably::Models::PaginatedResource.new(response, base_path, client, paginated_options) do |presence_message|
|
24
44
|
presence_message.tap do |message|
|
25
45
|
message.decode self.channel
|
26
46
|
end
|
@@ -35,17 +55,23 @@ module Ably
|
|
35
55
|
# @option options [Symbol] :direction `:forwards` or `:backwards`
|
36
56
|
# @option options [Integer] :limit Maximum number of presence messages to retrieve up to 10,000
|
37
57
|
#
|
38
|
-
# @return [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] An Array of
|
58
|
+
# @return [Ably::Models::PaginatedResource<Ably::Models::PresenceMessage>] An Array of {Ably::Models::PresenceMessage} objects that supports paging (#next_page, #first_page)
|
39
59
|
#
|
40
60
|
def history(options = {})
|
41
61
|
url = "#{base_path}/history"
|
62
|
+
options = options.dup
|
42
63
|
|
43
64
|
merge_options = { live: true } # TODO: Remove live param as all history should be live
|
44
65
|
[:start, :end].each { |option| merge_options[option] = as_since_epoch(options[option]) if options.has_key?(option) }
|
45
66
|
|
67
|
+
paginated_options = {
|
68
|
+
coerce_into: 'Ably::Models::PresenceMessage',
|
69
|
+
async_blocking_operations: options.delete(:async_blocking_operations),
|
70
|
+
}
|
71
|
+
|
46
72
|
response = client.get(url, options.merge(merge_options))
|
47
73
|
|
48
|
-
Ably::Models::PaginatedResource.new(response, url, client,
|
74
|
+
Ably::Models::PaginatedResource.new(response, url, client, paginated_options) do |presence_message|
|
49
75
|
presence_message.tap do |message|
|
50
76
|
message.decode self.channel
|
51
77
|
end
|
data/lib/ably/version.rb
CHANGED
@@ -4,7 +4,7 @@ require 'securerandom'
|
|
4
4
|
describe Ably::Realtime::Channel do
|
5
5
|
include RSpec::EventMachine
|
6
6
|
|
7
|
-
[:
|
7
|
+
[:json].each do |protocol| # :msgpack,
|
8
8
|
context "over #{protocol}" do
|
9
9
|
let(:default_options) { options.merge(api_key: api_key, environment: environment, protocol: protocol) }
|
10
10
|
|
@@ -24,25 +24,36 @@ describe Ably::Realtime::Channel do
|
|
24
24
|
|
25
25
|
let(:options) { { :protocol => :json } }
|
26
26
|
|
27
|
-
it '
|
27
|
+
it 'returns a Deferrable' do
|
28
28
|
run_reactor do
|
29
29
|
channel.publish('event', payload) do |message|
|
30
|
-
|
31
|
-
expect(history.length).to eql(1)
|
32
|
-
expect(history[0].data).to eql(payload)
|
30
|
+
expect(channel.history).to be_a(EventMachine::Deferrable)
|
33
31
|
stop_reactor
|
34
32
|
end
|
35
33
|
end
|
36
34
|
end
|
37
35
|
|
36
|
+
it 'retrieves real-time history' do
|
37
|
+
run_reactor do
|
38
|
+
channel.publish('event', payload) do |message|
|
39
|
+
channel.history do |history|
|
40
|
+
expect(history.length).to eql(1)
|
41
|
+
expect(history[0].data).to eql(payload)
|
42
|
+
stop_reactor
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
38
48
|
it 'retrieves real-time history across two channels' do
|
39
49
|
run_reactor do
|
40
50
|
channel.publish('event', payload) do |message|
|
41
51
|
channel2.publish('event', payload) do |message|
|
42
|
-
history
|
43
|
-
|
44
|
-
|
45
|
-
|
52
|
+
channel2.history do |history|
|
53
|
+
expect(history.length).to eql(2)
|
54
|
+
expect(history.map(&:data).uniq).to eql([payload])
|
55
|
+
stop_reactor
|
56
|
+
end
|
46
57
|
end
|
47
58
|
end
|
48
59
|
end
|
@@ -53,21 +64,22 @@ describe Ably::Realtime::Channel do
|
|
53
64
|
let(:limit) { 10 }
|
54
65
|
|
55
66
|
def check_limited_history(direction)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
67
|
+
channel.history(direction: direction, limit: limit) do |history|
|
68
|
+
expect(history.length).to eql(limit)
|
69
|
+
limit.times do |index|
|
70
|
+
expect(history[index].data).to eql("history#{index}")
|
71
|
+
end
|
61
72
|
|
62
|
-
|
73
|
+
history.next_page do |history|
|
74
|
+
expect(history.length).to eql(limit)
|
75
|
+
limit.times do |index|
|
76
|
+
expect(history[index].data).to eql("history#{index + limit}")
|
77
|
+
end
|
78
|
+
expect(history.last_page?).to eql(true)
|
63
79
|
|
64
|
-
|
65
|
-
|
66
|
-
expect(history[index].data).to eql("history#{index + limit}")
|
80
|
+
stop_reactor
|
81
|
+
end
|
67
82
|
end
|
68
|
-
expect(history.last_page?).to eql(true)
|
69
|
-
|
70
|
-
stop_reactor
|
71
83
|
end
|
72
84
|
|
73
85
|
context 'as one ProtocolMessage' do
|
@@ -24,17 +24,18 @@ describe 'Ably::Realtime::Presence Messages' do
|
|
24
24
|
run_reactor do
|
25
25
|
presence_client_one.enter(data: data) do
|
26
26
|
presence_client_one.leave do
|
27
|
-
history
|
28
|
-
|
27
|
+
presence_client_one.history do |history|
|
28
|
+
expect(history.count).to eql(2)
|
29
29
|
|
30
|
-
|
31
|
-
|
30
|
+
expect(history[1].action).to eq(:enter)
|
31
|
+
expect(history[1].client_id).to eq(client_one.client_id)
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
expect(history[0].action).to eq(:leave)
|
34
|
+
expect(history[0].client_id).to eq(client_one.client_id)
|
35
|
+
expect(history[0].data).to eql(data)
|
36
36
|
|
37
|
-
|
37
|
+
stop_reactor
|
38
|
+
end
|
38
39
|
end
|
39
40
|
end
|
40
41
|
end
|
@@ -43,11 +44,12 @@ describe 'Ably::Realtime::Presence Messages' do
|
|
43
44
|
it 'ensures REST presence history message IDs match ProtocolMessage wrapped message IDs via Realtime' do
|
44
45
|
run_reactor do
|
45
46
|
presence_client_one.subscribe(:enter) do |message|
|
46
|
-
history
|
47
|
-
|
47
|
+
presence_client_one.history do |history|
|
48
|
+
expect(history.count).to eql(1)
|
48
49
|
|
49
|
-
|
50
|
-
|
50
|
+
expect(history[0].id).to eql(message.id)
|
51
|
+
stop_reactor
|
52
|
+
end
|
51
53
|
end
|
52
54
|
|
53
55
|
presence_client_one.enter(data: data)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Ably::Realtime::Client stats' do
|
4
|
+
include RSpec::EventMachine
|
5
|
+
|
6
|
+
[:msgpack, :json].each do |protocol|
|
7
|
+
context "over #{protocol}" do
|
8
|
+
let(:client) do
|
9
|
+
Ably::Realtime::Client.new(api_key: api_key, environment: environment, protocol: protocol)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'fetching stats' do
|
13
|
+
it 'should return a Hash' do
|
14
|
+
run_reactor do
|
15
|
+
client.stats do |stats|
|
16
|
+
expect(stats).to be_a(Array)
|
17
|
+
stop_reactor
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should return a deferrable object' do
|
23
|
+
run_reactor do
|
24
|
+
expect(client.stats).to be_a(EventMachine::Deferrable)
|
25
|
+
stop_reactor
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Ably::Realtime::Client time' do
|
4
|
+
include RSpec::EventMachine
|
5
|
+
|
6
|
+
[:msgpack, :json].each do |protocol|
|
7
|
+
context "over #{protocol}" do
|
8
|
+
let(:client) do
|
9
|
+
Ably::Realtime::Client.new(api_key: api_key, environment: environment, protocol: protocol)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'fetching the service time' do
|
13
|
+
it 'should return the service time as a Time object' do
|
14
|
+
run_reactor do
|
15
|
+
client.time do |time|
|
16
|
+
expect(time).to be_within(2).of(Time.now)
|
17
|
+
stop_reactor
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should return a deferrable object' do
|
23
|
+
run_reactor do
|
24
|
+
expect(client.time).to be_a(EventMachine::Deferrable)
|
25
|
+
stop_reactor
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'securerandom'
|
3
2
|
|
4
|
-
describe 'Ably::REST time' do
|
3
|
+
describe 'Ably::REST::Client time' do
|
5
4
|
[:msgpack, :json].each do |protocol|
|
6
5
|
context "over #{protocol}" do
|
7
6
|
let(:client) do
|
@@ -9,7 +8,7 @@ describe 'Ably::REST time' do
|
|
9
8
|
end
|
10
9
|
|
11
10
|
describe 'fetching the service time' do
|
12
|
-
it
|
11
|
+
it 'should return the service time as a Time object' do
|
13
12
|
expect(client.time).to be_within(2).of(Time.now)
|
14
13
|
end
|
15
14
|
end
|
@@ -67,7 +67,7 @@ describe Ably::Models::PaginatedResource do
|
|
67
67
|
end
|
68
68
|
end
|
69
69
|
|
70
|
-
context '
|
70
|
+
context 'paged transformations' do
|
71
71
|
let(:headers) do
|
72
72
|
{
|
73
73
|
'link' => [
|
@@ -93,23 +93,65 @@ describe Ably::Models::PaginatedResource do
|
|
93
93
|
})
|
94
94
|
end
|
95
95
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
96
|
+
context 'with each block' do
|
97
|
+
subject do
|
98
|
+
paginated_resource_class.new(http_response, full_url, paged_client, paginated_resource_options) do |resource|
|
99
|
+
resource[:added_attribute_from_block] = "id:#{resource[:id]}"
|
100
|
+
resource
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'calls the block for each resource after retrieving the resources' do
|
105
|
+
expect(subject[0][:added_attribute_from_block]).to eql("id:#{body[0][:id]}")
|
100
106
|
end
|
101
|
-
end
|
102
107
|
|
103
|
-
|
104
|
-
|
108
|
+
it 'calls the block for each resource on second page after retrieving the resources' do
|
109
|
+
page_1_first_id = subject[0][:id]
|
110
|
+
next_page = subject.next_page
|
111
|
+
|
112
|
+
expect(next_page[0][:added_attribute_from_block]).to eql("id:#{body_page2[0][:id]}")
|
113
|
+
expect(next_page[0][:id]).to_not eql(page_1_first_id)
|
114
|
+
end
|
105
115
|
end
|
106
116
|
|
107
|
-
|
108
|
-
|
109
|
-
|
117
|
+
context 'with option async_blocking_operations: true' do
|
118
|
+
include RSpec::EventMachine
|
119
|
+
|
120
|
+
subject do
|
121
|
+
paginated_resource_class.new(http_response, full_url, paged_client, async_blocking_operations: true)
|
122
|
+
end
|
110
123
|
|
111
|
-
|
112
|
-
|
124
|
+
context '#next_page' do
|
125
|
+
it 'returns a deferrable object' do
|
126
|
+
run_reactor do
|
127
|
+
expect(subject.next_page).to be_a(EventMachine::Deferrable)
|
128
|
+
stop_reactor
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'allows a success callback block to be added' do
|
133
|
+
run_reactor do
|
134
|
+
subject.next_page do |paginated_resource|
|
135
|
+
expect(paginated_resource).to be_a(Ably::Models::PaginatedResource)
|
136
|
+
stop_reactor
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context '#first_page' do
|
143
|
+
it 'calls the errback callback when first page headers are missing' do
|
144
|
+
run_reactor do
|
145
|
+
subject.next_page do |paginated_resource|
|
146
|
+
deferrable = subject.first_page
|
147
|
+
deferrable.errback do |error|
|
148
|
+
expect(error).to be_a(Ably::Exceptions::InvalidPageError)
|
149
|
+
stop_reactor
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
113
155
|
end
|
114
156
|
end
|
115
157
|
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
describe Ably::Modules::AsyncWrapper do
|
5
|
+
include RSpec::EventMachine
|
6
|
+
|
7
|
+
let(:class_with_module) do
|
8
|
+
Class.new do
|
9
|
+
include Ably::Modules::AsyncWrapper
|
10
|
+
|
11
|
+
def operation(&success_callback)
|
12
|
+
async_wrap success_callback, &@block
|
13
|
+
end
|
14
|
+
|
15
|
+
def block=(block)
|
16
|
+
@block = block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
let(:subject) { class_with_module.new }
|
21
|
+
let(:result) { SecureRandom.hex }
|
22
|
+
let(:sleep_time) { 0.1 }
|
23
|
+
|
24
|
+
before do
|
25
|
+
subject.block = block
|
26
|
+
end
|
27
|
+
|
28
|
+
context '#async_wrap blocking block' do
|
29
|
+
context 'returns result' do
|
30
|
+
let(:block) do
|
31
|
+
proc do
|
32
|
+
sleep sleep_time
|
33
|
+
result
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'calls the success_callback block with result when provided' do
|
38
|
+
run_reactor do
|
39
|
+
subject.operation do |result|
|
40
|
+
expect(result).to eql(result)
|
41
|
+
stop_reactor
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'returns a deferrable that succeeds with result' do
|
47
|
+
run_reactor do
|
48
|
+
deferrable = subject.operation
|
49
|
+
expect(deferrable).to be_a(EventMachine::Deferrable)
|
50
|
+
deferrable.callback do |result|
|
51
|
+
expect(result).to eql(result)
|
52
|
+
stop_reactor
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'does not call the errback' do
|
58
|
+
run_reactor do
|
59
|
+
deferrable = subject.operation
|
60
|
+
expect(deferrable).to be_a(EventMachine::Deferrable)
|
61
|
+
deferrable.callback do |result|
|
62
|
+
expect(result).to eql(result)
|
63
|
+
EventMachine.add_timer(sleep_time * 2) { stop_reactor }
|
64
|
+
end
|
65
|
+
deferrable.errback do |result|
|
66
|
+
raise 'Errback should not have been called'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'does not block EventMachine' do
|
72
|
+
run_reactor do
|
73
|
+
timers_called = 0
|
74
|
+
EventMachine.add_periodic_timer(sleep_time / 5) { timers_called += 1 }
|
75
|
+
|
76
|
+
subject.operation do |result|
|
77
|
+
expect(timers_called).to be >= 4
|
78
|
+
stop_reactor
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'raises an Exception' do
|
85
|
+
let(:block) do
|
86
|
+
proc do
|
87
|
+
sleep sleep_time
|
88
|
+
raise RuntimeError, 'Intentional'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'calls the errback block of the deferrable' do
|
93
|
+
run_reactor do
|
94
|
+
deferrable = subject.operation
|
95
|
+
expect(deferrable).to be_a(EventMachine::Deferrable)
|
96
|
+
deferrable.errback do |error|
|
97
|
+
expect(error).to be_a(RuntimeError)
|
98
|
+
expect(error.message).to match(/Intentional/)
|
99
|
+
stop_reactor
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'does not call the success_callback block' do
|
105
|
+
run_reactor do
|
106
|
+
subject.operation do |result|
|
107
|
+
raise 'Callback should not have been called'
|
108
|
+
end
|
109
|
+
EventMachine.add_timer(sleep_time * 2) { stop_reactor }
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'does not call the callback block of the deferrable' do
|
114
|
+
run_reactor do
|
115
|
+
deferrable = subject.operation
|
116
|
+
expect(deferrable).to be_a(EventMachine::Deferrable)
|
117
|
+
deferrable.callback do |result|
|
118
|
+
raise 'Callback should not have been called'
|
119
|
+
end
|
120
|
+
EventMachine.add_timer(sleep_time * 2) { stop_reactor }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -16,16 +16,6 @@ describe Ably::Realtime::Client do
|
|
16
16
|
subject
|
17
17
|
end
|
18
18
|
|
19
|
-
specify '#time' do
|
20
|
-
expect(subject.rest_client).to receive(:time)
|
21
|
-
subject.time
|
22
|
-
end
|
23
|
-
|
24
|
-
specify '#stats' do
|
25
|
-
expect(subject.rest_client).to receive(:stats).with(options)
|
26
|
-
subject.stats options
|
27
|
-
end
|
28
|
-
|
29
19
|
context 'for attribute' do
|
30
20
|
[:environment, :use_tls?, :log_level].each do |attribute|
|
31
21
|
specify "##{attribute}" do
|
@@ -47,7 +47,9 @@ describe Ably::Realtime::Presence do
|
|
47
47
|
context 'subscriptions' do
|
48
48
|
let(:message_history) { Hash.new { |hash, key| hash[key] = 0 } }
|
49
49
|
let(:presence_action) { Ably::Models::PresenceMessage::ACTION.Enter }
|
50
|
-
let(:message)
|
50
|
+
let(:message) do
|
51
|
+
instance_double('Ably::Models::PresenceMessage', action: presence_action, member_id: SecureRandom.hex, decode: true)
|
52
|
+
end
|
51
53
|
|
52
54
|
context '#subscribe' do
|
53
55
|
specify 'to all presence state actions' do
|
@@ -3,11 +3,12 @@ require 'support/protocol_msgbus_helper'
|
|
3
3
|
|
4
4
|
describe Ably::Realtime::Connection::WebsocketTransport do
|
5
5
|
let(:client_ignored) { double('Ably::Realtime::Client').as_null_object }
|
6
|
-
let(:connection)
|
6
|
+
let(:connection) { instance_double('Ably::Realtime::Connection', client: client_ignored, id: nil) }
|
7
|
+
let(:url) { 'http://ably.io/' }
|
7
8
|
|
8
9
|
let(:websocket_transport_without_eventmachine) do
|
9
10
|
Ably::Realtime::Connection::WebsocketTransport.send(:allocate).tap do |websocket_transport|
|
10
|
-
websocket_transport.send(:initialize, connection)
|
11
|
+
websocket_transport.send(:initialize, connection, url)
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ably
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lewis Marshall
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-12-
|
12
|
+
date: 2014-12-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: eventmachine
|
@@ -210,6 +210,7 @@ files:
|
|
210
210
|
- lib/ably/models/presence_message.rb
|
211
211
|
- lib/ably/models/protocol_message.rb
|
212
212
|
- lib/ably/models/token.rb
|
213
|
+
- lib/ably/modules/async_wrapper.rb
|
213
214
|
- lib/ably/modules/channels_collection.rb
|
214
215
|
- lib/ably/modules/conversions.rb
|
215
216
|
- lib/ably/modules/encodeable.rb
|
@@ -253,6 +254,8 @@ files:
|
|
253
254
|
- spec/acceptance/realtime/message_spec.rb
|
254
255
|
- spec/acceptance/realtime/presence_history_spec.rb
|
255
256
|
- spec/acceptance/realtime/presence_spec.rb
|
257
|
+
- spec/acceptance/realtime/stats_spec.rb
|
258
|
+
- spec/acceptance/realtime/time_spec.rb
|
256
259
|
- spec/acceptance/rest/auth_spec.rb
|
257
260
|
- spec/acceptance/rest/base_spec.rb
|
258
261
|
- spec/acceptance/rest/channel_spec.rb
|
@@ -284,6 +287,7 @@ files:
|
|
284
287
|
- spec/unit/models/presence_message_spec.rb
|
285
288
|
- spec/unit/models/protocol_message_spec.rb
|
286
289
|
- spec/unit/models/token_spec.rb
|
290
|
+
- spec/unit/modules/async_wrapper_spec.rb
|
287
291
|
- spec/unit/modules/conversions_spec.rb
|
288
292
|
- spec/unit/modules/enum_spec.rb
|
289
293
|
- spec/unit/modules/event_emitter_spec.rb
|
@@ -330,6 +334,8 @@ test_files:
|
|
330
334
|
- spec/acceptance/realtime/message_spec.rb
|
331
335
|
- spec/acceptance/realtime/presence_history_spec.rb
|
332
336
|
- spec/acceptance/realtime/presence_spec.rb
|
337
|
+
- spec/acceptance/realtime/stats_spec.rb
|
338
|
+
- spec/acceptance/realtime/time_spec.rb
|
333
339
|
- spec/acceptance/rest/auth_spec.rb
|
334
340
|
- spec/acceptance/rest/base_spec.rb
|
335
341
|
- spec/acceptance/rest/channel_spec.rb
|
@@ -361,6 +367,7 @@ test_files:
|
|
361
367
|
- spec/unit/models/presence_message_spec.rb
|
362
368
|
- spec/unit/models/protocol_message_spec.rb
|
363
369
|
- spec/unit/models/token_spec.rb
|
370
|
+
- spec/unit/modules/async_wrapper_spec.rb
|
364
371
|
- spec/unit/modules/conversions_spec.rb
|
365
372
|
- spec/unit/modules/enum_spec.rb
|
366
373
|
- spec/unit/modules/event_emitter_spec.rb
|