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 +4 -4
- data/Gemfile.lock +1 -1
- data/VERSION +1 -1
- data/lib/code/node/call.rb +5 -2
- data/lib/code/node/code.rb +5 -0
- data/lib/code/node/function.rb +2 -2
- data/lib/code/node/right_operation.rb +4 -0
- data/lib/code/object/class.rb +4 -0
- data/lib/code/object/dictionary.rb +1 -1
- data/lib/code/object/function.rb +129 -6
- data/lib/code/object/global.rb +4 -1
- data/lib/code/object/super.rb +52 -0
- data/lib/code/parser/call.rb +2 -1
- data/spec/code/object/function_spec.rb +126 -1
- data/spec/code_spec.rb +6 -7
- metadata +2 -2
- data/spec/code/object/http_spec.rb +0 -99
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 289eba7ee8807b4660bba3a8df2458d5d7b615deea52b66b3475eb2c306aa9e9
|
|
4
|
+
data.tar.gz: 6394f2e3a44499cdf85ecb315d1a303a52df7784f8c385c76b170702298d7d3c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1bb7bf8488694f407300e3a18258601ada0eba25cd54ab8e0184a05889ac1171c87f5c62de341a26bae7876372cec80e194c82a993277b85fc8bc11d2bba10ef
|
|
7
|
+
data.tar.gz: bf4b7f896dc52eb6afabcc25e863d96fbf71a801bd469344887f7cff95d3879442757b3d0723a5d0594ee11aff671d78da4abdcfad0d889672f0e407c040fa95
|
data/Gemfile.lock
CHANGED
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
2.0.1
|
data/lib/code/node/call.rb
CHANGED
|
@@ -13,8 +13,8 @@ class Code
|
|
|
13
13
|
@body = Code.new(parsed.delete(:body).presence)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def evaluate(**
|
|
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
|
data/lib/code/node/code.rb
CHANGED
|
@@ -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
|
data/lib/code/node/function.rb
CHANGED
|
@@ -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]),
|
data/lib/code/object/class.rb
CHANGED
data/lib/code/object/function.rb
CHANGED
|
@@ -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(
|
|
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(
|
|
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
|
data/lib/code/object/global.rb
CHANGED
|
@@ -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?(
|
|
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
|
data/lib/code/parser/call.rb
CHANGED
|
@@ -151,7 +151,8 @@ class Code
|
|
|
151
151
|
|
|
152
152
|
def root
|
|
153
153
|
(
|
|
154
|
-
name.aka(:name) <<
|
|
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:
|
|
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
|