ably 0.1.1 → 0.1.2

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/ably.rb +2 -2
  3. data/lib/ably/auth.rb +39 -7
  4. data/lib/ably/modules/conversions.rb +58 -0
  5. data/lib/ably/{support.rb → modules/http_helpers.rb} +3 -3
  6. data/lib/ably/realtime.rb +5 -23
  7. data/lib/ably/realtime/channel.rb +62 -18
  8. data/lib/ably/realtime/client.rb +76 -22
  9. data/lib/ably/realtime/connection.rb +41 -14
  10. data/lib/ably/realtime/models/error_info.rb +38 -0
  11. data/lib/ably/realtime/models/message.rb +85 -0
  12. data/lib/ably/realtime/models/protocol_message.rb +149 -0
  13. data/lib/ably/realtime/models/shared.rb +17 -0
  14. data/lib/ably/rest.rb +16 -3
  15. data/lib/ably/rest/channel.rb +2 -2
  16. data/lib/ably/rest/client.rb +17 -20
  17. data/lib/ably/rest/models/message.rb +62 -0
  18. data/lib/ably/rest/models/paged_resource.rb +117 -0
  19. data/lib/ably/rest/presence.rb +4 -4
  20. data/lib/ably/token.rb +1 -1
  21. data/lib/ably/version.rb +1 -1
  22. data/spec/acceptance/realtime/channel_spec.rb +86 -0
  23. data/spec/acceptance/rest/auth_spec.rb +14 -5
  24. data/spec/acceptance/rest/channel_spec.rb +2 -2
  25. data/spec/spec_helper.rb +1 -0
  26. data/spec/support/event_machine_helper.rb +22 -0
  27. data/spec/support/model_helper.rb +67 -0
  28. data/spec/unit/realtime/error_info_spec.rb +10 -0
  29. data/spec/unit/realtime/message_spec.rb +115 -0
  30. data/spec/unit/realtime/protocol_message_spec.rb +102 -0
  31. data/spec/unit/realtime/realtime_spec.rb +20 -0
  32. data/spec/unit/rest/message_spec.rb +74 -0
  33. data/spec/unit/{rest_spec.rb → rest/rest_spec.rb} +14 -0
  34. metadata +28 -13
  35. data/lib/ably/message.rb +0 -70
  36. data/lib/ably/rest/paged_resource.rb +0 -117
  37. data/spec/acceptance/realtime_client_spec.rb +0 -12
  38. data/spec/unit/message_spec.rb +0 -73
  39. data/spec/unit/realtime_spec.rb +0 -9
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ require 'support/model_helper'
3
+
4
+ describe Ably::Realtime::Models::ErrorInfo do
5
+ subject { Ably::Realtime::Models::ErrorInfo }
6
+
7
+ it_behaves_like 'a realtime model', with_simple_attributes: %w(code status message) do
8
+ let(:model_args) { [] }
9
+ end
10
+ end
@@ -0,0 +1,115 @@
1
+ require 'spec_helper'
2
+ require 'support/model_helper'
3
+
4
+ describe Ably::Realtime::Models::Message do
5
+ subject { Ably::Realtime::Models::Message }
6
+ let(:protocol_message) { Ably::Realtime::Models::ProtocolMessage.new(action: 1) }
7
+
8
+ it_behaves_like 'a realtime model', with_simple_attributes: %w(name client_id data) do
9
+ let(:model_args) { [protocol_message] }
10
+ end
11
+
12
+ context '#sender_timestamp' do
13
+ let(:model) { subject.new({ timestamp: Time.now.to_i * 1000 }, protocol_message) }
14
+ it 'retrieves attribute :sender_timestamp' do
15
+ expect(model.sender_timestamp).to be_a(Time)
16
+ expect(model.sender_timestamp.to_i).to be_within(1).of(Time.now.to_i)
17
+ end
18
+ end
19
+
20
+ context 'Java naming' do
21
+ let(:model) { subject.new({ clientId: 'joe' }, protocol_message) }
22
+
23
+ it 'converts the attribute to ruby symbol naming convention' do
24
+ expect(model.client_id).to eql('joe')
25
+ end
26
+ end
27
+
28
+ context '#to_json' do
29
+ let(:json_object) { JSON.parse(model.to_json) }
30
+
31
+ context 'with valid data' do
32
+ let(:model) { subject.new({ name: 'test', clientId: 'joe' }, protocol_message) }
33
+
34
+ it 'converts the attribute back to Java mixedCase notation using string keys' do
35
+ expect(json_object["clientId"]).to eql('joe')
36
+ end
37
+
38
+ it 'autofills a missing timestamp for all messages' do
39
+ expect(json_object["timestamp"].to_i / 1000).to be_within(1).of(Time.now.to_i)
40
+ end
41
+ end
42
+
43
+ context 'with invalid data' do
44
+ let(:model) { subject.new({ clientId: 'joe' }, protocol_message) }
45
+
46
+ it 'raises an exception' do
47
+ expect { model.to_json }.to raise_error RuntimeError, /cannot generate valid JSON/
48
+ end
49
+ end
50
+ end
51
+
52
+ context 'part of ProtocolMessage' do
53
+ let(:ably_time) { Time.now + 5 }
54
+ let(:sender_time_0) { Time.now - 5 }
55
+ let(:sender_time_1) { Time.now - 3 }
56
+ let(:message_serial) { SecureRandom.hex }
57
+ let(:connection_id) { SecureRandom.hex }
58
+
59
+ let(:message_0_payload) do
60
+ {
61
+ 'string_key' => 'string_value',
62
+ 1 => 2,
63
+ true => false
64
+ }
65
+ end
66
+
67
+ let(:message_0_json) do
68
+ {
69
+ timestamp: sender_time_0,
70
+ name: 'zero',
71
+ data: message_0_payload
72
+ }
73
+ end
74
+
75
+ let(:message_1_json) do
76
+ {
77
+ timestamp: sender_time_1,
78
+ name: 'one',
79
+ data: 'simple string'
80
+ }
81
+ end
82
+
83
+ let(:protocol_message) do
84
+ Ably::Realtime::Models::ProtocolMessage.new({
85
+ timestamp: ably_time.to_i,
86
+ msg_serial: message_serial,
87
+ connection_id: connection_id,
88
+ messages: [
89
+ message_0_json, message_1_json
90
+ ]
91
+ })
92
+ end
93
+
94
+ let(:message_0) { protocol_message.messages.first }
95
+ let(:message_1) { protocol_message.messages.last }
96
+
97
+ it 'should generate a message ID from the index, serial and connection id' do
98
+ expect(message_0.message_id).to eql("#{connection_id}:#{message_serial}:0")
99
+ expect(message_1.message_id).to eql("#{connection_id}:#{message_serial}:1")
100
+ end
101
+
102
+ it 'should not modify the data payload' do
103
+ expect(message_0.data['string_key']).to eql('string_value')
104
+ expect(message_0.data[1]).to eql(2)
105
+ expect(message_0.data[true]).to eql(false)
106
+ expect(message_0.data).to eql(message_0_payload)
107
+
108
+ expect(message_1.data).to eql('simple string')
109
+ end
110
+
111
+ it 'should not allow changes to the payload' do
112
+ expect { message_0.data["test"] = true }.to raise_error RuntimeError, /can't modify frozen Hash/
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+ require 'support/model_helper'
3
+
4
+ describe Ably::Realtime::Models::ProtocolMessage do
5
+ subject { Ably::Realtime::Models::ProtocolMessage }
6
+
7
+ it_behaves_like 'a realtime model',
8
+ with_simple_attributes: %w(action count channel channel_serial connection_id connection_serial) do
9
+
10
+ let(:model_args) { [] }
11
+ end
12
+
13
+ context 'attributes' do
14
+ let(:unique_value) { SecureRandom.hex }
15
+
16
+ context 'Java naming' do
17
+ let(:protocol_message) { subject.new(channelSerial: unique_value) }
18
+
19
+ it 'converts the attribute to ruby symbol naming convention' do
20
+ expect(protocol_message.channel_serial).to eql(unique_value)
21
+ end
22
+ end
23
+
24
+ context '#action_sym' do
25
+ let(:protocol_message) { subject.new(action: 14) }
26
+
27
+ it 'returns the symbol equivalent' do
28
+ expect(protocol_message.action_sym).to eql(:presence)
29
+ end
30
+ end
31
+
32
+ context '#timestamp' do
33
+ let(:protocol_message) { subject.new(timestamp: Time.now.to_i * 1000) }
34
+ it 'retrieves attribute :timestamp' do
35
+ expect(protocol_message.timestamp).to be_a(Time)
36
+ expect(protocol_message.timestamp.to_i).to be_within(1).of(Time.now.to_i)
37
+ end
38
+ end
39
+
40
+ context '#error' do
41
+ context 'with no error attribute' do
42
+ let(:protocol_message) { subject.new(action: 1) }
43
+
44
+ it 'returns nil' do
45
+ expect(protocol_message.error).to be_nil
46
+ end
47
+ end
48
+
49
+ context 'with nil error' do
50
+ let(:protocol_message) { subject.new(error: nil) }
51
+
52
+ it 'returns nil' do
53
+ expect(protocol_message.error).to be_nil
54
+ end
55
+ end
56
+
57
+ context 'with error' do
58
+ let(:protocol_message) { subject.new(error: { message: 'test_error' }) }
59
+
60
+ it 'returns a valid ErrorInfo object' do
61
+ expect(protocol_message.error).to be_a(Ably::Realtime::Models::ErrorInfo)
62
+ expect(protocol_message.error.message).to eql('test_error')
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ context '#to_json' do
69
+ let(:json_object) { JSON.parse(model.to_json) }
70
+ let(:message) { { 'name' => 'event', 'clientId' => 'joe' } }
71
+ let(:attached_action) { Ably::Realtime::Models::ProtocolMessage.action!(:attached) }
72
+ let(:message_action) { Ably::Realtime::Models::ProtocolMessage.action!(:message) }
73
+
74
+ context 'with valid data' do
75
+ let(:model) { subject.new({ :action => attached_action, :channelSerial => 'unique', messages: [message] }) }
76
+
77
+ it 'converts the attribute back to Java mixedCase notation using string keys' do
78
+ expect(json_object["channelSerial"]).to eql('unique')
79
+ end
80
+
81
+ it 'populates the messages' do
82
+ expect(json_object["messages"].first).to include(message)
83
+ end
84
+ end
85
+
86
+ context 'with invalid name data' do
87
+ let(:model) { subject.new({ clientId: 'joe' }) }
88
+
89
+ it 'it raises an exception' do
90
+ expect { model.to_json }.to raise_error RuntimeError, /cannot generate valid JSON/
91
+ end
92
+ end
93
+
94
+ context 'with missing msg_serial for ack message' do
95
+ let(:model) { subject.new({ :action => message_action }) }
96
+
97
+ it 'it raises an exception' do
98
+ expect { model.to_json }.to raise_error RuntimeError, /cannot generate valid JSON/
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,20 @@
1
+ require "spec_helper"
2
+
3
+ describe Ably::Realtime do
4
+ let(:options) { { api_key: 'app.key:secret' } }
5
+
6
+ specify 'constructor returns an Ably::Realtime::Client' do
7
+ expect(Ably::Realtime.new(options)).to be_instance_of(Ably::Realtime::Client)
8
+ end
9
+
10
+ describe Ably::Realtime::Client do
11
+ describe "initializing the client" do
12
+ it "should disallow an invalid key" do
13
+ expect { Ably::Realtime::Client.new({}) }.to raise_error(ArgumentError, /api_key is missing/)
14
+ expect { Ably::Realtime::Client.new(api_key: 'invalid') }.to raise_error(ArgumentError, /api_key is invalid/)
15
+ expect { Ably::Realtime::Client.new(api_key: 'invalid:asdad') }.to raise_error(ArgumentError, /api_key is invalid/)
16
+ expect { Ably::Realtime::Client.new(api_key: 'appid.keyuid:keysecret') }.to_not raise_error
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,74 @@
1
+ require "spec_helper"
2
+
3
+ describe Ably::Rest::Models::Message do
4
+ context 'attributes' do
5
+ let(:unique_value) { 'unique_value' }
6
+
7
+ %w(name data client_id message_id).each do |attribute|
8
+ context "##{attribute}" do
9
+ subject { Ably::Rest::Models::Message.new({ attribute.to_sym => unique_value }) }
10
+
11
+ it "retrieves attribute :#{attribute}" do
12
+ expect(subject.public_send(attribute)).to eql(unique_value)
13
+ end
14
+ end
15
+ end
16
+
17
+ context '#sender_timestamp' do
18
+ subject { Ably::Rest::Models::Message.new(timestamp: Time.now.to_i * 1000) }
19
+ it 'retrieves attribute :timestamp' do
20
+ expect(subject.sender_timestamp).to be_a(Time)
21
+ expect(subject.sender_timestamp.to_i).to be_within(1).of(Time.now.to_i)
22
+ end
23
+ end
24
+
25
+ context '#json' do
26
+ let(:attributes) { { timestamp: Time.now.to_i * 1000 } }
27
+ subject { Ably::Rest::Models::Message.new(attributes) }
28
+
29
+ it 'provides access to #json' do
30
+ expect(subject.json).to eql(attributes)
31
+ end
32
+ end
33
+
34
+ context '#[]' do
35
+ subject { Ably::Rest::Models::Message.new(unusual: 'attribute') }
36
+
37
+ it 'provides accessor method to #json' do
38
+ expect(subject[:unusual]).to eql('attribute')
39
+ end
40
+ end
41
+ end
42
+
43
+ context '==' do
44
+ let(:attributes) { { client_id: 'unique' } }
45
+
46
+ it 'is true when attributes are the same' do
47
+ new_message = -> { Ably::Rest::Models::Message.new(attributes) }
48
+ expect(new_message[]).to eq(new_message[])
49
+ end
50
+
51
+ it 'is false when attributes are not the same' do
52
+ expect(Ably::Rest::Models::Message.new(client_id: 1)).to_not eq(Ably::Rest::Models::Message.new(client_id: 2))
53
+ end
54
+
55
+ it 'is false when class type differs' do
56
+ expect(Ably::Rest::Models::Message.new(client_id: 1)).to_not eq(nil)
57
+ end
58
+ end
59
+
60
+ context 'is immutable' do
61
+ let(:options) { { client_id: 'John' } }
62
+ subject { Ably::Rest::Models::Message.new(options) }
63
+
64
+ it 'prevents changes' do
65
+ expect { subject.json[:client_id] = 'Joe' }.to raise_error RuntimeError, /can't modify frozen Hash/
66
+ end
67
+
68
+ it 'dups options' do
69
+ expect(subject.json[:client_id]).to eql('John')
70
+ options[:client_id] = 'Joe'
71
+ expect(subject.json[:client_id]).to eql('John')
72
+ end
73
+ end
74
+ end
@@ -94,6 +94,20 @@ describe Ably::Rest do
94
94
  expect(client.endpoint.to_s).to eql('https://sandbox-rest.ably.io')
95
95
  end
96
96
  end
97
+
98
+ context 'delegators' do
99
+ subject { Ably::Rest::Client.new(options) }
100
+
101
+ it 'should delegate :client_id to .auth' do
102
+ expect(subject.auth).to receive(:client_id).and_return('john')
103
+ expect(subject.client_id).to eql('john')
104
+ end
105
+
106
+ it 'should delegate :auth_options to .auth' do
107
+ expect(subject.auth).to receive(:auth_options).and_return({ option: 1 })
108
+ expect(subject.auth_options).to eql({ option: 1 })
109
+ end
110
+ end
97
111
  end
98
112
  end
99
113
  end
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.1.1
4
+ version: 0.1.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-09-23 00:00:00.000000000 Z
12
+ date: 2014-09-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -168,12 +168,17 @@ files:
168
168
  - lib/ably.rb
169
169
  - lib/ably/auth.rb
170
170
  - lib/ably/exceptions.rb
171
- - lib/ably/message.rb
171
+ - lib/ably/modules/conversions.rb
172
+ - lib/ably/modules/http_helpers.rb
172
173
  - lib/ably/realtime.rb
173
174
  - lib/ably/realtime/callbacks.rb
174
175
  - lib/ably/realtime/channel.rb
175
176
  - lib/ably/realtime/client.rb
176
177
  - lib/ably/realtime/connection.rb
178
+ - lib/ably/realtime/models/error_info.rb
179
+ - lib/ably/realtime/models/message.rb
180
+ - lib/ably/realtime/models/protocol_message.rb
181
+ - lib/ably/realtime/models/shared.rb
177
182
  - lib/ably/rest.rb
178
183
  - lib/ably/rest/channel.rb
179
184
  - lib/ably/rest/channels.rb
@@ -181,12 +186,12 @@ files:
181
186
  - lib/ably/rest/middleware/exceptions.rb
182
187
  - lib/ably/rest/middleware/external_exceptions.rb
183
188
  - lib/ably/rest/middleware/parse_json.rb
184
- - lib/ably/rest/paged_resource.rb
189
+ - lib/ably/rest/models/message.rb
190
+ - lib/ably/rest/models/paged_resource.rb
185
191
  - lib/ably/rest/presence.rb
186
- - lib/ably/support.rb
187
192
  - lib/ably/token.rb
188
193
  - lib/ably/version.rb
189
- - spec/acceptance/realtime_client_spec.rb
194
+ - spec/acceptance/realtime/channel_spec.rb
190
195
  - spec/acceptance/rest/auth_spec.rb
191
196
  - spec/acceptance/rest/base_spec.rb
192
197
  - spec/acceptance/rest/channel_spec.rb
@@ -196,11 +201,16 @@ files:
196
201
  - spec/acceptance/rest/time_spec.rb
197
202
  - spec/spec_helper.rb
198
203
  - spec/support/api_helper.rb
204
+ - spec/support/event_machine_helper.rb
205
+ - spec/support/model_helper.rb
199
206
  - spec/support/test_app.rb
200
207
  - spec/unit/auth.rb
201
- - spec/unit/message_spec.rb
202
- - spec/unit/realtime_spec.rb
203
- - spec/unit/rest_spec.rb
208
+ - spec/unit/realtime/error_info_spec.rb
209
+ - spec/unit/realtime/message_spec.rb
210
+ - spec/unit/realtime/protocol_message_spec.rb
211
+ - spec/unit/realtime/realtime_spec.rb
212
+ - spec/unit/rest/message_spec.rb
213
+ - spec/unit/rest/rest_spec.rb
204
214
  - spec/unit/token_spec.rb
205
215
  homepage: http://github.com/ably/ably-ruby
206
216
  licenses:
@@ -227,7 +237,7 @@ signing_key:
227
237
  specification_version: 4
228
238
  summary: A Ruby client library for ably.io, the real-time messaging service
229
239
  test_files:
230
- - spec/acceptance/realtime_client_spec.rb
240
+ - spec/acceptance/realtime/channel_spec.rb
231
241
  - spec/acceptance/rest/auth_spec.rb
232
242
  - spec/acceptance/rest/base_spec.rb
233
243
  - spec/acceptance/rest/channel_spec.rb
@@ -237,10 +247,15 @@ test_files:
237
247
  - spec/acceptance/rest/time_spec.rb
238
248
  - spec/spec_helper.rb
239
249
  - spec/support/api_helper.rb
250
+ - spec/support/event_machine_helper.rb
251
+ - spec/support/model_helper.rb
240
252
  - spec/support/test_app.rb
241
253
  - spec/unit/auth.rb
242
- - spec/unit/message_spec.rb
243
- - spec/unit/realtime_spec.rb
244
- - spec/unit/rest_spec.rb
254
+ - spec/unit/realtime/error_info_spec.rb
255
+ - spec/unit/realtime/message_spec.rb
256
+ - spec/unit/realtime/protocol_message_spec.rb
257
+ - spec/unit/realtime/realtime_spec.rb
258
+ - spec/unit/rest/message_spec.rb
259
+ - spec/unit/rest/rest_spec.rb
245
260
  - spec/unit/token_spec.rb
246
261
  has_rdoc:
@@ -1,70 +0,0 @@
1
- module Ably
2
- # A Message encapsulates an individual message sent or received in Ably
3
- class Message
4
- def initialize(message)
5
- @message = message.dup.freeze
6
- end
7
-
8
- # Event name
9
- #
10
- # @return [String]
11
- def name
12
- @message[:name]
13
- end
14
-
15
- # Payload
16
- #
17
- # @return [Object]
18
- def data
19
- @message[:data]
20
- end
21
-
22
- # Client ID of the publisher of the message
23
- #
24
- # @return [String]
25
- def client_id
26
- @message[:client_id]
27
- end
28
-
29
- # Timestamp in milliseconds since epoch. This property is populated by the Ably system.
30
- #
31
- # @return [Integer]
32
- def timestamp
33
- @message[:timestamp]
34
- end
35
-
36
- # Timestamp as {Time}. This property is populated by the Ably system.
37
- #
38
- # @return [Time]
39
- def timestamp_at
40
- raise RuntimeError, "Timestamp is missing" unless timestamp
41
- Time.at(timestamp / 1000.0)
42
- end
43
-
44
- # Unique serial number of this message within the channel
45
- #
46
- # @return [Integer]
47
- def channel_serial
48
- @message[:channel_serial]
49
- end
50
-
51
- # Provide a normal Hash accessor to the underlying raw message object
52
- #
53
- # @return [Object]
54
- def [](key)
55
- @message[key]
56
- end
57
-
58
- # Raw message object
59
- #
60
- # @return [Hash]
61
- def raw_message
62
- @message
63
- end
64
-
65
- def ==(other)
66
- self.kind_of?(other.class) &&
67
- raw_message == other.raw_message
68
- end
69
- end
70
- end