ably 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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