ribbon-intercom 0.3.4 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6735bd14a8d50fd75364a3b6c31aaffbd08e733d
4
- data.tar.gz: 370a4652cbdcc027683b64278a57ca580b2aab88
3
+ metadata.gz: dbc66058ef3f67f202ae929f759b20a1ca45a0f7
4
+ data.tar.gz: d5eee408147e0cf447120c6f2ee8150cba30cec9
5
5
  SHA512:
6
- metadata.gz: e4e1891d25f6cb156a798abb60fb37e7839faaebcd361ad0e507e490caacc78d294248d7347719f31039c514baa5fd14032526d9c501228a6be6ae1a4ae304f0
7
- data.tar.gz: 7e09d2709f559018785c38d9724ac7797c7f28ec0b58d022ff2585baaf1e55ae48cb555467c9a413bd2c9458a4f05538db1159c102bc269279947da1f206b591
6
+ metadata.gz: ed1f4b07d38b1fca0657cc08ec4fac171ae9fc65a7132f9afe4f46a9043d6104d4fec26ade902ab93bed155102365fdf56518dfbf93b0a2695805173b8d834b3
7
+ data.tar.gz: 723e68476ea49afd0cf055e2ce6adcfb8636ea6c7d12625abfa9ff2486a1502bc4507af01a7fbfc5f4d8935ee1b0bc82de2a9e223547e99ec9513a6cd9e8fe81
@@ -9,6 +9,7 @@ module Ribbon
9
9
  autoload(:Client, 'ribbon/intercom/client')
10
10
  autoload(:Package, 'ribbon/intercom/package')
11
11
  autoload(:Packageable, 'ribbon/intercom/packageable')
12
+ autoload(:Packet, 'ribbon/intercom/packet')
12
13
  autoload(:Utils, 'ribbon/intercom/utils')
13
14
 
14
15
  module_function
@@ -18,6 +18,14 @@ module Ribbon::Intercom
18
18
  end
19
19
  end
20
20
 
21
+ def begin
22
+ Utils::MethodChain.begin { |methods|
23
+ queue = Packet::MethodQueue.new
24
+ methods.each { |meth, *args| queue.enqueue(meth, *args) }
25
+ send_packet(method_queue: queue).retval
26
+ }
27
+ end
28
+
21
29
  ##
22
30
  # Returns the headers defined for this SDK. Optionally, you may also define
23
31
  # additional headers you'd like to add/override.
@@ -34,11 +42,19 @@ module Ribbon::Intercom
34
42
  end
35
43
 
36
44
  ##
37
- # Calls the method on the adapter returning the Adapter::Response.
45
+ # Calls the method on the adapter returning the response Packet
46
+ def call(method_name, *args)
47
+ send_packet(
48
+ method_queue: Packet::MethodQueue.new.enqueue(method_name, *args)
49
+ )
50
+ end
51
+
52
+ ##
53
+ # Sends the packet with the adapter, returning the response Packet.
38
54
  #
39
55
  # Intended to be called by Package.
40
- def call(method_name, *args)
41
- _process_response(adapter.call(method_name, *args))
56
+ def send_packet(packet)
57
+ _process_response(adapter.send_packet(packet))
42
58
  end
43
59
 
44
60
  def dup
@@ -64,32 +80,20 @@ module Ribbon::Intercom
64
80
  end
65
81
 
66
82
  ##
67
- # Process an Adapter::Response object returned by Adapter#call.
68
- def _process_response(response)
69
- _handle_response_error(response) unless response.successful?
83
+ # Process a Packet object returned by Adapter#send_packet.
84
+ def _process_response(packet)
85
+ _handle_response_error(packet) if packet.error?
70
86
 
71
- _init_packages(response.retval)
72
- response
87
+ _init_packages(packet.retval)
88
+ packet
73
89
  end
74
90
 
75
91
  ##
76
92
  # Raises an error depending on what went wrong.
77
- def _handle_response_error(response)
78
- raise 'called for successful response' if response.successful?
79
-
80
- encoded_error = response.headers['X-Intercom-Error']
81
-
82
- if encoded_error && !encoded_error.empty?
83
- begin
84
- decoded_error = Base64.strict_decode64(encoded_error)
85
- error = Marshal.load(decoded_error)
86
- rescue
87
- error = Errors::ServerError.new('unknown server error')
88
- end
89
- end
90
-
91
- raise error || Errors::ServerError.new('unexpected server error')
92
- end # _handle_response
93
+ def _handle_response_error(packet)
94
+ raise 'packet contains no error' unless packet.error?
95
+ raise packet.error
96
+ end
93
97
 
94
98
  ##
95
99
  # Walks the object and initializes all packages (i.e., sets them up to be
@@ -9,11 +9,22 @@ module Ribbon::Intercom
9
9
 
10
10
  ##
11
11
  # Call the method on the service.
12
+ #
13
+ # @deprecated This method is only called by tests. Don't call it elsewhere.
12
14
  def call(method_name, *args)
13
- call!(method_name, _encode_args(*args)).tap { |response|
14
- raise TypeError, "call! should return an Adapter::Response" unless response.is_a?(Response)
15
- raise "response should have correct method name" unless response.method_name == method_name.to_sym
16
- }
15
+ send_packet(
16
+ method_queue: Packet::MethodQueue.new.enqueue(method_name, *args)
17
+ )
18
+ end
19
+
20
+ ##
21
+ # Send a packet to the service and returns the Packet returned by the service.
22
+ def send_packet(packet)
23
+ packet = Packet.new(packet) if packet.is_a?(Hash)
24
+
25
+ send_packet!(packet.encode).tap { |response|
26
+ raise TypeError, "send_packet! should return an Adapter::Response" unless response.is_a?(Response)
27
+ }.packet
17
28
  end
18
29
 
19
30
  ##
@@ -43,8 +54,8 @@ module Ribbon::Intercom
43
54
  end
44
55
 
45
56
  ##
46
- # Actually call the method on the service. Should return an Adapter::Response object.
47
- def call!(method_name, *args)
57
+ # Actually send the packet to the service. Should return an Adapter::Response object.
58
+ def send_packet!(packet)
48
59
  raise NotImplementedError
49
60
  end
50
61
 
@@ -1,37 +1,12 @@
1
1
  module Ribbon::Intercom
2
2
  class Client::SDK::Adapters::Adapter
3
3
  class Response < Rack::Response
4
- attr_reader :method_name
5
-
6
- def initialize(body, status, headers, method_name)
7
- super(body, status, headers)
8
- @method_name = method_name.to_sym
9
- end
10
-
11
- def missing_permissions
12
- @__missing_permissions ||= _intercom_permissions_missing
13
- end
14
-
15
4
  def body
16
5
  super.join
17
6
  end
18
7
 
19
- ##
20
- # Decode the response body received from the service.
21
- def retval
22
- @__retval ||= Marshal.load(Base64.strict_decode64(body)) unless body.empty?
23
- end
24
-
25
- private
26
-
27
- def _intercom_permissions_missing
28
- key = _intercom_permissions_missing_header
29
- headers[key] && headers[key].split(',').to_set
30
- end
31
-
32
- def _intercom_permissions_missing_header
33
- missing_keys = ['X-Intercom-Permissions-Missing', :x_intercom_permissions_missing]
34
- missing_keys.detect { |key| headers.key?(key) }
8
+ def packet
9
+ @__packet ||= Packet.decode(body) unless body.empty?
35
10
  end
36
11
  end # Response
37
12
  end # Client::SDK::Adapters::Adapter
@@ -17,13 +17,15 @@ module Ribbon::Intercom
17
17
  @__connection ||= Connection.new(*@_connection_args)
18
18
  end
19
19
 
20
- def call!(method_name, encoded_args)
20
+ ##
21
+ # Send the encoded packet up to the service via an HTTP PUT.
22
+ def send_packet!(encoded_packet)
21
23
  response = connection.put(
22
- headers: headers.merge("X-Intercom-Method" => method_name),
23
- body: encoded_args
24
+ headers: headers,
25
+ body: encoded_packet
24
26
  )
25
27
 
26
- Adapter::Response.new(response.body, response.code.to_i, response, method_name)
28
+ Adapter::Response.new(response.body, response.code.to_i, response)
27
29
  end
28
30
  end # HttpAdapter
29
31
  end # Client::SDK::Adapters
@@ -23,17 +23,18 @@ module Ribbon::Intercom
23
23
  !!service
24
24
  end
25
25
 
26
- def call!(method_name, encoded_args)
26
+ ##
27
+ # Mimics an HTTP PUT
28
+ def send_packet!(encoded_packet)
27
29
  response = service.call(
28
30
  _http_headers.merge(
29
31
  'HTTP_AUTHORIZATION' => _http_auth,
30
- 'HTTP_X_INTERCOM_METHOD' => method_name.to_s,
31
32
  'REQUEST_METHOD' => 'PUT',
32
- 'rack.input' => StringIO.new(encoded_args)
33
+ 'rack.input' => StringIO.new(encoded_packet)
33
34
  )
34
35
  )
35
36
 
36
- Response.new(response[2], response[0], response[1], method_name)
37
+ Adapter::Response.new(response[2], response[0], response[1])
37
38
  end
38
39
 
39
40
  private
@@ -2,6 +2,11 @@ module Ribbon::Intercom
2
2
  module Errors
3
3
  class Error < StandardError; end
4
4
 
5
+ ##
6
+ # Packet errors
7
+ class PacketError < Error; end
8
+ class InvalidEncodingError < PacketError; end
9
+
5
10
  #############
6
11
  # Http Errors
7
12
  class HttpError < Error; end
@@ -7,20 +7,20 @@ module Ribbon::Intercom
7
7
  attr_reader :sdk
8
8
 
9
9
  def initialize(subject_data=nil, data=nil)
10
- self._subject_data = subject_data
10
+ @_subject_data = subject_data
11
11
  @_data = data
12
12
  end
13
13
 
14
14
  def sdk=(sdk)
15
- _set_sdk_headers(sdk)
16
15
  @sdk = sdk
17
16
  end
18
17
 
19
- protected
20
-
21
- def _subject_data=(data)
22
- @_subject_data = data
23
- _set_sdk_headers
18
+ def begin
19
+ Utils::MethodChain.begin { |methods|
20
+ queue = Packet::MethodQueue.new
21
+ methods.each { |meth, *args| queue.enqueue(meth, *args) }
22
+ _send_method_queue(queue)
23
+ }
24
24
  end
25
25
 
26
26
  private
@@ -29,35 +29,35 @@ module Ribbon::Intercom
29
29
  if @_data && @_data.key?(meth)
30
30
  @_data[meth]
31
31
  elsif sdk
32
- _process_response(sdk.call(meth, *args))
32
+ _send_method_queue(Packet::MethodQueue.new.enqueue(meth, *args))
33
33
  else
34
34
  super
35
35
  end
36
36
  end
37
37
 
38
+ def _send_method_queue(method_queue)
39
+ _process_response(
40
+ sdk.send_packet(
41
+ subject: @_subject_data,
42
+ method_queue: method_queue
43
+ )
44
+ )
45
+ end
46
+
38
47
  def marshal_dump
39
48
  [@_subject_data, @_data]
40
49
  end
41
50
 
42
51
  def marshal_load(array)
43
- self._subject_data = array[0]
52
+ @_subject_data = array[0]
44
53
  @_data = array[1]
45
54
  end
46
55
 
47
- def _set_sdk_headers(sdk=sdk)
48
- sdk.headers('X-Intercom-Subject' => @_subject_data) if sdk
49
- end
50
-
51
- def _process_response(response)
52
- self._subject_data = response.headers['X-Intercom-Subject']
53
- @_data = _retrieve_data_from_response(response)
54
-
55
- response.retval
56
- end
56
+ def _process_response(packet)
57
+ @_subject_data = packet.subject
58
+ @_data = packet.package_data
57
59
 
58
- def _retrieve_data_from_response(response)
59
- encoded_data = response.headers['X-Intercom-Package-Data']
60
- encoded_data && Marshal.load(Base64.strict_decode64(encoded_data))
60
+ packet.retval
61
61
  end
62
62
  end # Package
63
63
  end # Ribbon::Intercom
@@ -26,10 +26,6 @@ module Ribbon::Intercom
26
26
  self.class._package_with_methods.map { |meth| [meth, public_send(meth)] }.to_h
27
27
  )
28
28
  end
29
-
30
- def encoded_package_data
31
- Base64.strict_encode64(Marshal.dump(package_data))
32
- end
33
29
  end # Mixin
34
30
  end # Service::Subject
35
31
  end # Ribbon::Intercom
@@ -0,0 +1,52 @@
1
+ require 'ostruct'
2
+ require 'base64'
3
+
4
+ module Ribbon::Intercom
5
+ ##
6
+ # Represents a collection of data to be passed between the service and client.
7
+ class Packet < OpenStruct
8
+ autoload(:MethodQueue, 'ribbon/intercom/packet/method_queue')
9
+
10
+ class << self
11
+ def decode(encoded_packet)
12
+ hash = Marshal.load(Base64.strict_decode64(encoded_packet))
13
+ raise Errors::InvalidEncodingError, hash.inspect unless hash.is_a?(Hash)
14
+ new(hash)
15
+ end
16
+ end # Class Methods
17
+
18
+ def initialize(params={})
19
+ error = params.delete(:error)
20
+ super(params)
21
+ self.error = error if error
22
+ end
23
+
24
+ ##
25
+ # Encode (marshal) the error before saving it. This allows the error to be
26
+ # decoded on the client when requested, rather than decoded at the same time
27
+ # the packet is decoded, which could cause problems if the error class doesn't
28
+ # exist on the client.
29
+ def error=(err)
30
+ self._encoded_error = Marshal.dump(err)
31
+ end
32
+
33
+ ##
34
+ # Decode the error, which may not exist on the client.
35
+ # If the error class doesn't exist on the client, raise a ServerError.
36
+ def error
37
+ error? && Marshal.load(_encoded_error)
38
+ rescue
39
+ Errors::ServerError.new('unknown server error')
40
+ end
41
+
42
+ ##
43
+ # Whether the packet contains an error
44
+ def error?
45
+ !!_encoded_error
46
+ end
47
+
48
+ def encode
49
+ Base64.strict_encode64(Marshal.dump(to_h))
50
+ end
51
+ end # Packet
52
+ end # Ribbon::Intercom
@@ -0,0 +1,28 @@
1
+ module Ribbon::Intercom
2
+ class Packet
3
+ class MethodQueue
4
+ ##
5
+ # Enqueue a method with it's arguments.
6
+ # Supports method chaining.
7
+ def enqueue(name, *args)
8
+ self.tap { _queue << [name, *Utils.sanitize(args)] }
9
+ end
10
+
11
+ ##
12
+ # Iterate through the methods and arguments.
13
+ def each(&block)
14
+ _queue.each(&block)
15
+ end
16
+
17
+ def empty?
18
+ _queue.empty?
19
+ end
20
+
21
+ private
22
+
23
+ def _queue
24
+ @__queue ||= []
25
+ end
26
+ end # MethodQueue
27
+ end # Packet
28
+ end # Ribbon::Intercom
@@ -44,6 +44,7 @@ module Ribbon::Intercom
44
44
  attr_reader :request
45
45
  attr_reader :channel
46
46
  attr_reader :subject
47
+ attr_reader :request_packet
47
48
  attr_reader :env
48
49
 
49
50
  def initialize(opts={})
@@ -65,8 +66,8 @@ module Ribbon::Intercom
65
66
  store.lookup_channel(token)
66
67
  end
67
68
 
68
- def sufficient_permissions?(intercom_method)
69
- channel.may?(Utils.method_identifier(subject, intercom_method))
69
+ def sufficient_permissions?(base, intercom_method)
70
+ Utils.basic_type?(base) || channel.may?(Utils.method_identifier(base, intercom_method))
70
71
  end
71
72
 
72
73
  def call(env)
@@ -78,8 +79,7 @@ module Ribbon::Intercom
78
79
 
79
80
  response = catch(:response) {
80
81
  begin
81
- intercom_method, args = _process_request
82
- _call_method(intercom_method, *args)
82
+ _process_request
83
83
  rescue Exception => error
84
84
  _respond_with_error!(error)
85
85
  end
@@ -97,8 +97,10 @@ module Ribbon::Intercom
97
97
  def _process_request
98
98
  _init_request
99
99
  _authenticate_request!
100
+ _load_request_packet
100
101
  _load_subject
101
- [_load_method, _load_args]
102
+ response_packet = _process_methods
103
+ _respond_with_packet(response_packet)
102
104
  end
103
105
 
104
106
  def _init_request
@@ -115,8 +117,12 @@ module Ribbon::Intercom
115
117
  end
116
118
  end
117
119
 
120
+ def _load_request_packet
121
+ @request_packet = Packet.decode(request.body.read)
122
+ end
123
+
118
124
  def _load_subject
119
- if (encoded_subject=env['HTTP_X_INTERCOM_SUBJECT']) && !encoded_subject.empty?
125
+ if (encoded_subject=request_packet.subject) && !encoded_subject.empty?
120
126
  @subject = _decode_subject(encoded_subject)
121
127
  _error!(Errors::InvalidSubjectSignatureError) unless @subject
122
128
  else
@@ -124,35 +130,27 @@ module Ribbon::Intercom
124
130
  end
125
131
  end
126
132
 
127
- def _load_method
128
- env['HTTP_X_INTERCOM_METHOD'].to_sym.tap { |intercom_method|
129
- _sufficient_permissions!(intercom_method)
130
- }
131
- end
132
-
133
- def _load_args
134
- _decode_args(request.body.read)
135
- rescue Errors::UnsafeValueError
136
- _error!(Errors::UnsafeArgumentError, "One or more argument type is invalid.")
133
+ ##
134
+ # Calls requested methods and returns a response packet for the client.
135
+ def _process_methods
136
+ retval = _call_methods
137
+ _prepare_response_packet(retval)
137
138
  end
138
139
 
139
140
  ##
140
- # Call the method on the subject with the args.
141
- def _call_method(intercom_method, *args)
142
- body = _package(subject.public_send(intercom_method, *args))
143
-
144
- headers = {}
145
- unless self == subject # Order matters here! See: issue#52
146
- # Need to send subject back in case it was modified by the method.
147
- headers['X-Intercom-Subject'] = _encode_subject(subject)
148
-
149
- if subject.is_a?(Packageable::Mixin)
150
- # Need to send the package data back in case it changed, too.
151
- headers['X-Intercom-Package-Data'] = subject.encoded_package_data
152
- end
153
- end
141
+ # Call all the methods in the method queue.
142
+ def _call_methods
143
+ method_queue = _load_method_queue
144
+
145
+ intercom_method = nil
146
+ base = subject
147
+ method_queue.each { |meth, *args|
148
+ intercom_method = meth
149
+ _sufficient_permissions!(base, meth)
150
+ base = base.public_send(meth, *args)
151
+ }
154
152
 
155
- _respond!(200, headers, body)
153
+ _package(base)
156
154
  rescue NoMethodError => error
157
155
  if error.name == intercom_method
158
156
  _error!(Errors::InvalidMethodError, intercom_method)
@@ -161,6 +159,36 @@ module Ribbon::Intercom
161
159
  end
162
160
  end
163
161
 
162
+ def _load_method_queue
163
+ request_packet.method_queue.tap { |mq|
164
+ raise "No method queue given" unless mq
165
+ raise "Expected MethodQueue, got: #{mq.inspect}" unless mq.is_a?(Packet::MethodQueue)
166
+ raise "Empty MethodQueue" if mq.empty?
167
+ }
168
+ end
169
+
170
+ ##
171
+ # Creates a successful response Packet to be returned to the client.
172
+ def _prepare_response_packet(retval)
173
+ Packet.new.tap { |packet|
174
+ unless self == subject # Order matters here! See: issue#52
175
+ # Need to send subject back in case it was modified by the methods.
176
+ packet.subject = _encode_subject(subject)
177
+
178
+ if subject.is_a?(Packageable::Mixin)
179
+ # Need to send the package data back in case it changed, too.
180
+ packet.package_data = subject.package_data
181
+ end
182
+ end
183
+
184
+ packet.retval = retval
185
+ }
186
+ end
187
+
188
+ def _respond_with_packet(packet, status=200)
189
+ _respond!(status, {}, packet.encode)
190
+ end
191
+
164
192
  ##
165
193
  # Package up any non-basic objects that include Packageable::Mixin.
166
194
  def _package(object)
@@ -187,14 +215,13 @@ module Ribbon::Intercom
187
215
  ##
188
216
  # Marshal dumps the subject and signs the resulting bytes with the channel.
189
217
  def _encode_subject(subject)
190
- Base64.strict_encode64(channel.sign(Marshal.dump(subject)))
218
+ channel.sign(Marshal.dump(subject))
191
219
  end
192
220
 
193
221
  ##
194
222
  # Decodes the subject sent from the client.
195
223
  def _decode_subject(encoded_subject)
196
- signed_subject = Base64.strict_decode64(encoded_subject)
197
- marshalled_subject = channel.verify(signed_subject)
224
+ marshalled_subject = channel.verify(encoded_subject)
198
225
  marshalled_subject && Marshal.load(marshalled_subject)
199
226
  end
200
227
 
@@ -211,15 +238,15 @@ module Ribbon::Intercom
211
238
  end
212
239
  end
213
240
 
214
- def _sufficient_permissions!(intercom_method)
215
- unless sufficient_permissions?(intercom_method)
216
- required = Utils.method_identifier(subject, intercom_method)
241
+ def _sufficient_permissions!(base, intercom_method)
242
+ unless sufficient_permissions?(base, intercom_method)
243
+ required = Utils.method_identifier(base, intercom_method)
217
244
  _error!(Errors::InsufficientPermissionsError, required)
218
245
  end
219
246
  end
220
247
 
221
248
  def _response(status, headers={}, body=EmptyResponse)
222
- body = body == EmptyResponse ? [] : [_encode_body(body)]
249
+ body = body == EmptyResponse ? [] : [body]
223
250
  headers = headers.merge("Content-Type" => "text/plain", "Transfer-Encoding" => "gzip")
224
251
  Rack::Response.new(body, status, headers)
225
252
  end
@@ -229,7 +256,7 @@ module Ribbon::Intercom
229
256
  end
230
257
 
231
258
  def _respond_with_error!(error, status=500)
232
- _respond!(status, { 'X-Intercom-Error' => _encode_error(error) })
259
+ _respond_with_packet(Packet.new(error: error), status)
233
260
  end
234
261
 
235
262
  def _error!(klass, message=nil)
@@ -256,14 +283,6 @@ module Ribbon::Intercom
256
283
  end
257
284
  end
258
285
 
259
- def _encode_body(body)
260
- Base64.strict_encode64(Marshal.dump(body))
261
- end
262
-
263
- def _encode_error(error)
264
- Base64.strict_encode64(Marshal.dump(error))
265
- end
266
-
267
286
  ##
268
287
  # Decodes the arguments.
269
288
  #
@@ -74,14 +74,24 @@ module Ribbon::Intercom
74
74
  private
75
75
 
76
76
  def _load_data(token)
77
- if token_exists?(token) && (channel_data = @_redis.hgetall(_key_name(token)))
78
- permissions = @_redis.smembers(_key_name(token, 'permissions'))
77
+ channel_data_future = nil
78
+ permissions_future = nil
79
+ signing_keys_future = nil
80
+
81
+ @_redis.pipelined {
82
+ channel_data_future = @_redis.hgetall(_key_name(token))
83
+ permissions_future = @_redis.smembers(_key_name(token, 'permissions'))
84
+ signing_keys_future = @_redis.hgetall(_key_name(token, 'signing_keys'))
85
+ }
79
86
 
80
- signing_keys = Hash[
81
- @_redis.hgetall(_key_name(token, 'signing_keys')).map { |key_id, data|
82
- [key_id.to_i, Marshal.load(Base64.strict_decode64(data))]
83
- }
84
- ]
87
+ channel_data = channel_data_future.value
88
+
89
+ if channel_data && !channel_data.empty?
90
+ permissions = permissions_future.value
91
+
92
+ signing_keys = signing_keys_future.value.map { |key_id, data|
93
+ [key_id.to_i, Marshal.load(Base64.strict_decode64(data))]
94
+ }.to_h
85
95
 
86
96
  Utils.symbolize_keys(
87
97
  channel_data.merge(
@@ -3,10 +3,13 @@ require 'date'
3
3
  module Ribbon::Intercom
4
4
  module Utils
5
5
  autoload(:Signer, 'ribbon/intercom/utils/signer')
6
+ autoload(:MethodChain, 'ribbon/intercom/utils/method_chain')
6
7
  autoload(:Mixins, 'ribbon/intercom/utils/mixins')
7
8
 
8
9
  BASIC_TYPES = [
9
- String, Symbol, TrueClass, FalseClass, Integer, Float, NilClass, Date, Time, DateTime
10
+ String, Symbol, TrueClass, FalseClass, Integer, Float, NilClass,
11
+ Date, Time, DateTime,
12
+ Hash, Array, Range
10
13
  ].freeze
11
14
 
12
15
  class << self
@@ -0,0 +1,38 @@
1
+ module Ribbon::Intercom
2
+ module Utils
3
+ class MethodChain
4
+ class << self
5
+ def begin(&block)
6
+ new(&block)
7
+ end
8
+ end # Class Methods
9
+
10
+ ##
11
+ # Need to override all public instance methods so they can be captured correctly.
12
+ public_instance_methods.each { |meth|
13
+ define_method(meth) { |*args|
14
+ _add_method(meth, *args)
15
+ }
16
+ }
17
+
18
+ def initialize(&block)
19
+ @_end_block = block
20
+ end
21
+
22
+ def end
23
+ @_end_block.call(@_methods)
24
+ end
25
+
26
+ private
27
+
28
+ def method_missing(meth, *args, &block)
29
+ _add_method(meth, *args)
30
+ end
31
+
32
+ def _add_method(meth, *args)
33
+ (@_methods ||= []) << [meth, *args]
34
+ self
35
+ end
36
+ end # MethodChain
37
+ end # Utils
38
+ end # Ribbon::Intercom
@@ -1,5 +1,5 @@
1
1
  module Ribbon
2
2
  module Intercom
3
- VERSION = '0.3.4'
3
+ VERSION = '0.4.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ribbon-intercom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Honer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-05-19 00:00:00.000000000 Z
12
+ date: 2015-05-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -172,6 +172,8 @@ files:
172
172
  - lib/ribbon/intercom/package.rb
173
173
  - lib/ribbon/intercom/packageable.rb
174
174
  - lib/ribbon/intercom/packageable/mixin.rb
175
+ - lib/ribbon/intercom/packet.rb
176
+ - lib/ribbon/intercom/packet/method_queue.rb
175
177
  - lib/ribbon/intercom/railtie.rb
176
178
  - lib/ribbon/intercom/service.rb
177
179
  - lib/ribbon/intercom/service/channel.rb
@@ -180,6 +182,7 @@ files:
180
182
  - lib/ribbon/intercom/service/channel/stores/redis_store.rb
181
183
  - lib/ribbon/intercom/service/channel/stores/store.rb
182
184
  - lib/ribbon/intercom/utils.rb
185
+ - lib/ribbon/intercom/utils/method_chain.rb
183
186
  - lib/ribbon/intercom/utils/mixins.rb
184
187
  - lib/ribbon/intercom/utils/mixins/mock_safe.rb
185
188
  - lib/ribbon/intercom/utils/signer.rb