code-ruby 1.9.12 → 2.0.1

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
  SHA256:
3
- metadata.gz: 8a8c532c56c64f318cc116ef97c0bc587edde1f306d5f8e53d75be893bf38b1f
4
- data.tar.gz: ffc94431ea3528b547ab9b76e03d4efea7f9e2281a30da04e7528ea881d2d308
3
+ metadata.gz: 289eba7ee8807b4660bba3a8df2458d5d7b615deea52b66b3475eb2c306aa9e9
4
+ data.tar.gz: 6394f2e3a44499cdf85ecb315d1a303a52df7784f8c385c76b170702298d7d3c
5
5
  SHA512:
6
- metadata.gz: 468c2777dab28cabbff2e918d5ee3a9a5a417063be54ad44026d20a096d0f234c6ee7fb633c17d707dbaf565eb61614ea4d6d67bc3888aa8895d9df092c37a50
7
- data.tar.gz: 1f29b8a374565925fcbdf636bf7a1d60f45a5d5a23ba4bf24550c4f2964f695ac4691d0ea60d25825bd5e487c18e05feb14eab0b2df37c1c0c1f054c7d012b4b
6
+ metadata.gz: 1bb7bf8488694f407300e3a18258601ada0eba25cd54ab8e0184a05889ac1171c87f5c62de341a26bae7876372cec80e194c82a993277b85fc8bc11d2bba10ef
7
+ data.tar.gz: bf4b7f896dc52eb6afabcc25e863d96fbf71a801bd469344887f7cff95d3879442757b3d0723a5d0594ee11aff671d78da4abdcfad0d889672f0e407c040fa95
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- code-ruby (1.9.12)
4
+ code-ruby (2.0.1)
5
5
  activesupport
6
6
  base64
7
7
  bigdecimal
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.9.12
1
+ 2.0.1
@@ -13,8 +13,8 @@ class Code
13
13
  @body = Code.new(parsed.delete(:body).presence)
14
14
  end
15
15
 
16
- def evaluate(**_args)
17
- Object::Function.new(@parameters, @body)
16
+ def evaluate(**args)
17
+ Object::Function.new(@parameters, @body, args.fetch(:context))
18
18
  end
19
19
  end
20
20
 
@@ -22,7 +22,9 @@ class Code
22
22
  return if parsed.blank?
23
23
 
24
24
  @name = parsed.delete(:name).presence
25
+ @explicit_arguments = parsed.key?(:arguments)
25
26
  @arguments = parsed.delete(:arguments).presence || []
27
+ @arguments = [@arguments] unless @arguments.is_a?(Array)
26
28
  @arguments.map! { |argument| CallArgument.new(argument) }
27
29
 
28
30
  return unless parsed.key?(:block)
@@ -52,6 +54,7 @@ class Code
52
54
  args.fetch(:object).call(
53
55
  operator: name,
54
56
  arguments: Object::List.new(arguments),
57
+ explicit_arguments: @explicit_arguments,
55
58
  **args
56
59
  )
57
60
  end
@@ -6,6 +6,7 @@ class Code
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
8
 
9
+ @parsed = parsed.deep_dup
9
10
  @statements =
10
11
  (parsed.presence || []).map { |statement| Statement.new(statement) }
11
12
  end
@@ -57,6 +58,10 @@ class Code
57
58
  def to_code
58
59
  @statements.blank? ? Object::Nothing.new : Object::Code.new(self)
59
60
  end
61
+
62
+ def to_raw
63
+ @parsed.deep_dup
64
+ end
60
65
  end
61
66
  end
62
67
  end
@@ -12,8 +12,8 @@ class Code
12
12
  @body = Code.new(parsed.delete(:body).presence)
13
13
  end
14
14
 
15
- def evaluate(**_args)
16
- Object::Function.new(@parameters, @body)
15
+ def evaluate(**args)
16
+ Object::Function.new(@parameters, @body, args.fetch(:context))
17
17
  end
18
18
  end
19
19
  end
@@ -41,6 +41,10 @@ class Code
41
41
  right = @right&.evaluate(**args) || Object::Nothing.new
42
42
  left = @left&.resolve(**args) || Object::Nothing.new
43
43
 
44
+ if @operator != EQUAL && right.nothing?
45
+ return @left&.evaluate(**args) || Object::Nothing.new
46
+ end
47
+
44
48
  left.call(
45
49
  operator: @operator,
46
50
  arguments: Object::List.new([right]),
@@ -19,6 +19,10 @@ class Code
19
19
  def call(...)
20
20
  raw.call(...)
21
21
  end
22
+
23
+ def code_to_string
24
+ String.new(raw.name.to_s.split("::")[2..].join("::"))
25
+ end
22
26
  end
23
27
  end
24
28
  end
@@ -542,7 +542,7 @@ class Code
542
542
  result = code_fetch(code_operator)
543
543
 
544
544
  if result.is_a?(Function)
545
- result.call(**args, operator: nil)
545
+ result.call(**args, operator: nil, bound_self: self)
546
546
  else
547
547
  sig(args)
548
548
  result
@@ -3,9 +3,9 @@
3
3
  class Code
4
4
  class Object
5
5
  class Function < Object
6
- attr_reader :code_parameters, :code_body
6
+ attr_reader :code_parameters, :code_body, :definition_context, :parent
7
7
 
8
- def initialize(*args, **_kargs, &_block)
8
+ def initialize(*args, parent: nil, methods: nil, **_kargs, &_block)
9
9
  @code_parameters =
10
10
  List
11
11
  .new(args.first)
@@ -14,6 +14,10 @@ class Code
14
14
  .to_code
15
15
 
16
16
  @code_body = Code.new(args.second.presence)
17
+ @definition_context = args.third if args.third.is_a?(Context)
18
+ @parent = parent.to_code
19
+ self.methods = methods.to_code
20
+ self.methods = Dictionary.new if self.methods.nothing?
17
21
 
18
22
  self.raw = List.new([code_parameters, code_body])
19
23
  end
@@ -26,15 +30,52 @@ class Code
26
30
  case code_operator.to_s
27
31
  when "", "call"
28
32
  sig(args) { signature_for_call }
29
- code_call(*code_arguments.raw, **globals)
33
+ code_call(
34
+ *code_arguments.raw,
35
+ explicit_arguments: args.fetch(:explicit_arguments, true),
36
+ **globals
37
+ )
38
+ when "extend"
39
+ sig(args) { Function }
40
+ code_extend(code_arguments.code_first)
41
+ when /=$/
42
+ sig(args) { Object }
43
+ code_set(code_operator.to_s.chop, code_value)
44
+ when ->(operator) { code_has_key?(operator).truthy? }
45
+ result = code_fetch(code_operator)
46
+
47
+ if result.is_a?(Function)
48
+ result.call(**args, operator: nil, bound_self: self)
49
+ else
50
+ sig(args)
51
+ result
52
+ end
30
53
  else
31
54
  super
32
55
  end
33
56
  end
34
57
 
35
- def code_call(*arguments, **globals)
58
+ def code_call(*arguments, explicit_arguments: true, bound_self: nil, **globals)
36
59
  code_arguments = arguments.to_code
37
- code_context = Context.new({}, globals[:context])
60
+ code_context = Context.new({}, definition_context || globals[:context])
61
+ code_self = bound_self.to_code
62
+ code_self = captured_self if code_self.nothing? && captured_self
63
+ code_self = Dictionary.new if code_self.nil? || code_self.nothing?
64
+
65
+ code_context.code_set("self", code_self)
66
+
67
+ if parent.is_a?(Function)
68
+ code_context.code_set(
69
+ "super",
70
+ Super.new(
71
+ parent,
72
+ code_arguments,
73
+ code_self,
74
+ definition_context || globals[:context],
75
+ explicit_arguments: explicit_arguments
76
+ )
77
+ )
78
+ end
38
79
 
39
80
  code_parameters.raw.each.with_index do |code_parameter, index|
40
81
  code_argument =
@@ -111,7 +152,89 @@ class Code
111
152
  end
112
153
 
113
154
  def code_to_string
114
- String.new("<#{self.class.name} #{raw}>")
155
+ String.new(
156
+ Format.format(
157
+ [
158
+ {
159
+ function: {
160
+ parameters: code_parameters.raw.map { |parameter| parameter_to_raw(parameter) },
161
+ body: code_body.raw.to_raw
162
+ }
163
+ }
164
+ ]
165
+ )
166
+ )
167
+ end
168
+
169
+ def code_extend(function)
170
+ code_function = function.to_code
171
+
172
+ Function.new(
173
+ code_function.code_parameters,
174
+ code_function.code_body.raw,
175
+ code_function.definition_context,
176
+ parent: self,
177
+ methods: methods.code_deep_duplicate
178
+ )
179
+ end
180
+
181
+ def code_fetch(key)
182
+ methods.code_fetch(key)
183
+ end
184
+
185
+ def code_get(key)
186
+ methods.code_get(key)
187
+ end
188
+
189
+ def code_has_key?(key)
190
+ methods.code_has_key?(key)
191
+ end
192
+
193
+ def code_set(key, value)
194
+ methods.code_set(key, value)
195
+ end
196
+
197
+ private
198
+
199
+ def captured_self
200
+ self_from(definition_context)
201
+ end
202
+
203
+ def self_from(context)
204
+ return if context.blank?
205
+
206
+ current = context
207
+
208
+ while current
209
+ return current.code_fetch("self") if current.code_has_key?("self").truthy?
210
+
211
+ current = current.parent
212
+ end
213
+
214
+ nil
215
+ end
216
+
217
+ def parameter_to_raw(parameter)
218
+ code_parameter = parameter.to_code
219
+ raw_parameter = { name: code_parameter.code_name.to_s }
220
+
221
+ if code_parameter.keyword?
222
+ raw_parameter[:keyword] = ":"
223
+ elsif code_parameter.keyword_splat?
224
+ raw_parameter[:keyword_splat] = "**"
225
+ elsif code_parameter.regular_splat?
226
+ raw_parameter[:regular_splat] = "*"
227
+ elsif code_parameter.block?
228
+ raw_parameter[:block] = "&"
229
+ elsif code_parameter.spread?
230
+ raw_parameter[:spread] = "..."
231
+ end
232
+
233
+ unless code_parameter.code_default.nothing?
234
+ raw_parameter[:default] = code_parameter.code_default.code_to_string.raw == "nothing" ? [] : Code.parse(code_parameter.code_default.to_s)
235
+ end
236
+
237
+ raw_parameter
115
238
  end
116
239
  end
117
240
  end
@@ -199,7 +199,10 @@ class Code
199
199
  code_context = code_context.code_lookup!(code_operator)
200
200
  code_result = code_context.code_fetch(code_operator)
201
201
 
202
- if code_result.is_a?(Function)
202
+ if code_result.is_a?(Super)
203
+ code_result.call(**args, operator: nil)
204
+ elsif code_result.is_a?(Function) &&
205
+ args.fetch(:explicit_arguments, false)
203
206
  code_result.call(**args, operator: nil)
204
207
  else
205
208
  sig(args)
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Code
4
+ class Object
5
+ class Super < Function
6
+ def initialize(
7
+ parent,
8
+ forwarded_arguments,
9
+ code_self,
10
+ definition_context,
11
+ explicit_arguments: false
12
+ )
13
+ @parent = parent.to_code
14
+ @forwarded_arguments = forwarded_arguments.to_code
15
+ @code_self = code_self.to_code
16
+ @definition_context = definition_context
17
+ self.methods = Dictionary.new
18
+ self.raw = @parent.raw
19
+ end
20
+
21
+ def call(**args)
22
+ code_arguments = args.fetch(:arguments, List.new).to_code
23
+ explicit_arguments = args.fetch(:explicit_arguments, false)
24
+
25
+ @parent.code_call(
26
+ *(arguments_for(code_arguments, explicit_arguments).raw),
27
+ explicit_arguments: explicit_arguments,
28
+ bound_self: @code_self,
29
+ **multi_fetch(args, *GLOBALS).merge(context: parent_context)
30
+ )
31
+ end
32
+
33
+ private
34
+
35
+ def parent_context
36
+ context = Context.new({}, @definition_context)
37
+ context.code_set("self", @code_self)
38
+ context
39
+ end
40
+
41
+ def arguments_for(code_arguments, explicit_arguments)
42
+ if explicit_arguments && code_arguments.raw.empty?
43
+ List.new
44
+ elsif code_arguments.any?
45
+ code_arguments
46
+ else
47
+ @forwarded_arguments
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -151,7 +151,8 @@ class Code
151
151
 
152
152
  def root
153
153
  (
154
- name.aka(:name) << (whitespace? << arguments.aka(:arguments)).maybe <<
154
+ name.aka(:name) <<
155
+ (whiltespace_without_newline? << arguments.aka(:arguments)).maybe <<
155
156
  (whiltespace_without_newline? << block.aka(:block)).maybe
156
157
  ).aka(:call)
157
158
  end
@@ -28,7 +28,7 @@ RSpec.describe Code::Object::Function do
28
28
 
29
29
  context "invalid" do
30
30
  [
31
- "f = (x) => {} f",
31
+ "f = (x) => {} f()",
32
32
  "f = (x:) => {} f(1)",
33
33
  "f = (x:) => {} f(y: 1)"
34
34
  ].each do |input|
@@ -37,4 +37,129 @@ RSpec.describe Code::Object::Function do
37
37
  end
38
38
  end
39
39
  end
40
+
41
+ it "captures self for constructor-like functions that return self" do
42
+ result =
43
+ Code.evaluate(<<~CODE)
44
+ User = (given_name:, family_name:, birth_date:) => {
45
+ self.given_name = given_name.to_string.presence
46
+ self.family_name = family_name.to_string.presence
47
+ self.birth_date = birth_date.presence&.to_date
48
+ self.full_name = () => {
49
+ [self.given_name, self.family_name].compact.join(" ")
50
+ }
51
+ self.age = () => {
52
+ return unless(self.birth_date)
53
+
54
+ self.birth_date.year
55
+ }
56
+
57
+ return(self)
58
+ }
59
+
60
+ user = User(given_name: "Dorian", family_name: "Marie", birth_date: "1992-08-11")
61
+ [user.given_name, user.family_name, user.full_name, user.age]
62
+ CODE
63
+
64
+ expect(result).to eq(
65
+ Code::Object::List.new(
66
+ [
67
+ Code::Object::String.new("Dorian"),
68
+ Code::Object::String.new("Marie"),
69
+ Code::Object::String.new("Dorian Marie"),
70
+ Code::Object::Integer.new(1992)
71
+ ]
72
+ )
73
+ )
74
+ end
75
+
76
+ it "supports constructor methods on functions" do
77
+ result =
78
+ Code.evaluate(<<~CODE)
79
+ User = (given_name:, family_name:) => {
80
+ self.given_name = given_name
81
+ self.family_name = family_name
82
+ self.full_name = () => {
83
+ [self.given_name, self.family_name].join(" ")
84
+ }
85
+ return(self)
86
+ }
87
+
88
+ User.all = () => {
89
+ [
90
+ User(given_name: "Dorian", family_name: "Marie"),
91
+ User(given_name: "Ada", family_name: "Lovelace")
92
+ ]
93
+ }
94
+
95
+ User.first = () => {
96
+ User.all.first
97
+ }
98
+
99
+ User.first.full_name
100
+ CODE
101
+
102
+ expect(result).to eq(Code::Object::String.new("Dorian Marie"))
103
+ end
104
+
105
+ it "supports extending constructors and forwarding super arguments" do
106
+ result =
107
+ Code.evaluate(<<~CODE)
108
+ Person = (given_name:, family_name:) => {
109
+ self.given_name = given_name
110
+ self.family_name = family_name
111
+ self.full_name = () => {
112
+ [self.given_name, self.family_name].join(" ")
113
+ }
114
+ return(self)
115
+ }
116
+
117
+ Employee = Person.extend((employee_id:, given_name:, family_name:) => {
118
+ super
119
+ self.employee_id = employee_id
120
+ return(self)
121
+ })
122
+
123
+ employee = Employee(employee_id: "EMP-001", given_name: "Dorian", family_name: "Marie")
124
+ [employee.employee_id, employee.full_name]
125
+ CODE
126
+
127
+ expect(result).to eq(
128
+ Code::Object::List.new(
129
+ [
130
+ Code::Object::String.new("EMP-001"),
131
+ Code::Object::String.new("Dorian Marie")
132
+ ]
133
+ )
134
+ )
135
+ end
136
+
137
+ it "distinguishes super from super()" do
138
+ result =
139
+ Code.evaluate(<<~CODE)
140
+ Person = (given_name:, family_name:) => {
141
+ self.full_name = () => {
142
+ [given_name, family_name].join(" ")
143
+ }
144
+ return(self)
145
+ }
146
+
147
+ Anonymous = Person.extend(() => {
148
+ super()
149
+ self.full_name = () => { "anonymous" }
150
+ return(self)
151
+ })
152
+
153
+ [Anonymous().full_name, Person(given_name: "Ada", family_name: "Lovelace").full_name]
154
+ CODE
155
+
156
+ expect(result).to eq(
157
+ Code::Object::List.new(
158
+ [
159
+ Code::Object::String.new("anonymous"),
160
+ Code::Object::String.new("Ada Lovelace")
161
+ ]
162
+ )
163
+ )
164
+ end
40
165
  end
data/spec/code_spec.rb CHANGED
@@ -239,6 +239,9 @@ RSpec.describe Code do
239
239
  %w[Class(Time) Time],
240
240
  %w[Class(nothing) Nothing],
241
241
  %w[Class(true) Boolean],
242
+ %w[String String],
243
+ %w[Time Time],
244
+ %w[Class Class],
242
245
  %w[Class.new Nothing],
243
246
  %w[Class.new Nothing],
244
247
  %w[Class.new(2.days.ago) Time],
@@ -331,20 +334,16 @@ RSpec.describe Code do
331
334
  ["a = 0 [1, 2, 3].each { |i| next if i == 2 a += i } a", "4"],
332
335
  ["a = 0\nb = 0\nwhile a < 4\n a += 1\n continue if a == 2\n b += a\nend\nb", "8"],
333
336
  ["a = 0 loop a += 1 break end a", "1"],
334
- ["a = 1\nbegin\n a += 1\n break if a > 3\n retry\nend\na", "4"],
335
337
  ["x = loop break(42) end x", "42"],
336
- ["a = 0 a += 1 retry if a < 3 a", "3"],
337
338
  ["a = 0\nuntil a > 10 a += 1 end a", "11"],
338
339
  ["a = 0\nwhile a < 10 a += 1 end a", "10"],
339
- [
340
- "a = 0\nretried = false\nwhile a < 2\n a += 1\n retry if a == 1 && !retried && (retried = true)\nend\na",
341
- "2"
342
- ],
343
340
  ["a = 1 3.times { a += 1 } a", "4"],
344
341
  ["a = 1 a *= 2 a", "2"],
345
342
  ["a = 1 a += 1 a", "2"],
346
343
  ["a = 1 a += 1 a", "2"],
347
344
  ["a = 1 a -= 1 a", "0"],
345
+ ["a = 3 a -= 1 if false a", "3"],
346
+ ["a = 3\n(a -= 1) if false\na", "3"],
348
347
  ["a = 1 a /= 2 a", "0.5"],
349
348
  ["a = 1 a <<= 1 a", "2"],
350
349
  ["a = 1 a >>= 1 a", "0"],
@@ -375,7 +374,6 @@ RSpec.describe Code do
375
374
  ["next(7)", "7"],
376
375
  ["not not false", "false"],
377
376
  ["not true", "false"],
378
- ["retry(8)", "8"],
379
377
  ["return(9)", "9"],
380
378
  ["f = () => { return(3) 4 } f()", "3"],
381
379
  ["a = 1 orirginal = 2 orirginal", "2"],
@@ -486,6 +484,7 @@ RSpec.describe Code do
486
484
  ["", ""]
487
485
  ].each do |input, expected|
488
486
  it "#{input} == #{expected}" do
487
+ puts input
489
488
  formatted = format_input(input)
490
489
 
491
490
  output = StringIO.new
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.12
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dorian Marié
@@ -285,6 +285,7 @@ files:
285
285
  - lib/code/object/range.rb
286
286
  - lib/code/object/smtp.rb
287
287
  - lib/code/object/string.rb
288
+ - lib/code/object/super.rb
288
289
  - lib/code/object/time.rb
289
290
  - lib/code/object/url.rb
290
291
  - lib/code/parser.rb
@@ -345,7 +346,6 @@ files:
345
346
  - spec/code/object/decimal_spec.rb
346
347
  - spec/code/object/dictionary_spec.rb
347
348
  - spec/code/object/function_spec.rb
348
- - spec/code/object/http_spec.rb
349
349
  - spec/code/object/identifier_list_spec.rb
350
350
  - spec/code/object/integer_spec.rb
351
351
  - spec/code/object/list_spec.rb
@@ -1,99 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "spec_helper"
4
-
5
- RSpec.describe Code::Object::Http do
6
- def self.verbs
7
- %w[get head post put delete options trace patch]
8
- end
9
-
10
- def self.response_codes
11
- {
12
- continue: 100,
13
- switching_protocols: 101,
14
- processing: 102,
15
- early_hints: 103,
16
- ok: 200,
17
- created: 201,
18
- accepted: 202,
19
- non_authoritative_information: 203,
20
- no_content: 204,
21
- reset_content: 205,
22
- partial_content: 206,
23
- multi_status: 207,
24
- already_reported: 208,
25
- im_used: 226,
26
- multiple_choices: 300,
27
- moved_permanently: 301,
28
- found: 302,
29
- see_other: 303,
30
- not_modified: 304,
31
- use_proxy: 305,
32
- reserved: 306,
33
- temporary_redirect: 307,
34
- permanent_redirect: 308,
35
- bad_request: 400,
36
- unauthorized: 401,
37
- payment_required: 402,
38
- forbidden: 403,
39
- not_found: 404,
40
- method_not_allowed: 405,
41
- not_acceptable: 406,
42
- proxy_authentication_required: 407,
43
- request_timeout: 408,
44
- conflict: 409,
45
- gone: 410,
46
- length_required: 411,
47
- precondition_failed: 412,
48
- request_entity_too_large: 413,
49
- request_uri_too_long: 414,
50
- unsupported_media_type: 415,
51
- requested_range_not_satisfiable: 416,
52
- expectation_failed: 417,
53
- misdirected_request: 421,
54
- unprocessable_entity: 422,
55
- locked: 423,
56
- failed_dependency: 424,
57
- too_early: 425,
58
- upgrade_required: 426,
59
- precondition_required: 428,
60
- too_many_requests: 429,
61
- request_header_fields_too_large: 431,
62
- unavailable_for_legal_reasons: 451,
63
- internal_server_error: 500,
64
- not_implemented: 501,
65
- bad_gateway: 502,
66
- service_unavailable: 503,
67
- gateway_timeout: 504,
68
- http_version_not_supported: 505,
69
- variant_also_negotiates: 506,
70
- insufficient_storage: 507,
71
- loop_detected: 508,
72
- bandwidth_limit_exceeded: 509,
73
- not_extended: 510,
74
- network_authentication_required: 511
75
- }
76
- end
77
-
78
- verbs.each do |verb|
79
- describe ".#{verb}" do
80
- response_codes.each do |status, code|
81
- it "returns #{code} as code and #{status} as status" do
82
- expect(Code.evaluate(<<~INPUT)).to eq(Code.evaluate(<<~OUTPUT))
83
- response = Http.#{verb}("https://httpbin.org/status/#{code}")
84
- [response.code, response.status]
85
- INPUT
86
- [#{code}, "#{status}"]
87
- OUTPUT
88
-
89
- expect(Code.evaluate(<<~INPUT)).to eq(Code.evaluate(<<~OUTPUT))
90
- response = Http.fetch("#{verb}", "https://httpbin.org/status/#{code}")
91
- [response.code, response.status]
92
- INPUT
93
- [#{code}, "#{status}"]
94
- OUTPUT
95
- end
96
- end
97
- end
98
- end
99
- end