ribbon-intercom 0.3.4 → 0.4.0

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.
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