code-ruby 3.0.13 → 3.1.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 +33 -41
- data/VERSION +1 -1
- data/lib/code/format.rb +27 -6
- data/lib/code/node/left_operation.rb +22 -5
- data/lib/code/node/square_bracket.rb +5 -2
- data/lib/code/object/dictionary.rb +46 -8
- data/lib/code/object/function.rb +28 -3
- data/lib/code/object/list.rb +22 -28
- data/spec/code/format_spec.rb +8 -1
- data/spec/code/object/dictionary_spec.rb +2 -0
- data/spec/code/object/function_spec.rb +119 -12
- data/spec/code/object/list_spec.rb +2 -0
- data/spec/code_spec.rb +12 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4fb3de0080323ce38f0bc61db99084820616f9b437d94fbf973a4a0736da7a0b
|
|
4
|
+
data.tar.gz: 476a64d5bcd78add94f15f25c3d1d086c3263aa66dd4af73443e8ad5e126fc9e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9851fd43383c19e34984f2124980f788beb59b22e2fd6cd5871a4e3107f62b908770c0b1575b58e1f84cefef574740877f9de9d18bb41ac22eaac531a85136bb
|
|
7
|
+
data.tar.gz: b620dc0c1eb65e83fe5d8ade6047fc712a1149f258a1275fc46163f4852a7efd2e5107fc979396daaa95672bb2216c43b3796176abf27d6c0f7bd35c9fba1cf4
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
code-ruby (3.
|
|
4
|
+
code-ruby (3.1.1)
|
|
5
5
|
activesupport
|
|
6
6
|
base64
|
|
7
7
|
bigdecimal
|
|
@@ -20,7 +20,7 @@ PATH
|
|
|
20
20
|
GEM
|
|
21
21
|
remote: https://rubygems.org/
|
|
22
22
|
specs:
|
|
23
|
-
activesupport (8.1.
|
|
23
|
+
activesupport (8.1.3)
|
|
24
24
|
base64
|
|
25
25
|
bigdecimal
|
|
26
26
|
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
@@ -33,11 +33,11 @@ GEM
|
|
|
33
33
|
securerandom (>= 0.3)
|
|
34
34
|
tzinfo (~> 2.0, >= 2.0.5)
|
|
35
35
|
uri (>= 0.13.1)
|
|
36
|
-
addressable (2.
|
|
36
|
+
addressable (2.9.0)
|
|
37
37
|
public_suffix (>= 2.0.2, < 8.0)
|
|
38
38
|
ast (2.4.3)
|
|
39
39
|
base64 (0.3.0)
|
|
40
|
-
bigdecimal (4.
|
|
40
|
+
bigdecimal (4.1.2)
|
|
41
41
|
bundler-audit (0.9.3)
|
|
42
42
|
bundler (>= 1.2.0)
|
|
43
43
|
thor (~> 1.0)
|
|
@@ -79,7 +79,7 @@ GEM
|
|
|
79
79
|
dorian-to_struct (2.0.2)
|
|
80
80
|
drb (2.2.3)
|
|
81
81
|
geom2d (0.4.1)
|
|
82
|
-
git (4.3.
|
|
82
|
+
git (4.3.2)
|
|
83
83
|
activesupport (>= 5.0)
|
|
84
84
|
addressable (~> 2.8)
|
|
85
85
|
process_executer (~> 4.0)
|
|
@@ -89,23 +89,20 @@ GEM
|
|
|
89
89
|
thor
|
|
90
90
|
tilt
|
|
91
91
|
hashdiff (1.2.1)
|
|
92
|
-
hexapdf (1.
|
|
92
|
+
hexapdf (1.8.0)
|
|
93
93
|
cmdparse (~> 3.0, >= 3.0.3)
|
|
94
94
|
geom2d (~> 0.4, >= 0.4.1)
|
|
95
95
|
openssl (>= 2.2.1)
|
|
96
96
|
strscan (>= 3.1.2)
|
|
97
97
|
i18n (1.14.8)
|
|
98
98
|
concurrent-ruby (~> 1.0)
|
|
99
|
-
icalendar (2.12.
|
|
99
|
+
icalendar (2.12.3)
|
|
100
100
|
base64
|
|
101
101
|
ice_cube (~> 0.16)
|
|
102
102
|
logger
|
|
103
103
|
ostruct
|
|
104
104
|
ice_cube (0.17.0)
|
|
105
|
-
json (2.
|
|
106
|
-
json-schema (6.1.0)
|
|
107
|
-
addressable (~> 2.8)
|
|
108
|
-
bigdecimal (>= 3.1, < 5)
|
|
105
|
+
json (2.19.5)
|
|
109
106
|
language-ruby (1.2.0)
|
|
110
107
|
dorian-arguments
|
|
111
108
|
zeitwerk
|
|
@@ -121,19 +118,16 @@ GEM
|
|
|
121
118
|
net-imap
|
|
122
119
|
net-pop
|
|
123
120
|
net-smtp
|
|
124
|
-
mcp (0.7.1)
|
|
125
|
-
json-schema (>= 4.1)
|
|
126
121
|
mini_mime (1.1.5)
|
|
127
|
-
mini_racer (0.
|
|
122
|
+
mini_racer (0.21.0)
|
|
128
123
|
libv8-node (~> 24.12.0.1)
|
|
129
|
-
minitest (6.0.
|
|
124
|
+
minitest (6.0.6)
|
|
130
125
|
drb (~> 2.0)
|
|
131
126
|
prism (~> 1.5)
|
|
132
|
-
mustermann (3.
|
|
133
|
-
ruby2_keywords (~> 0.0.1)
|
|
127
|
+
mustermann (3.1.1)
|
|
134
128
|
net-http (0.9.1)
|
|
135
129
|
uri (>= 0.11.1)
|
|
136
|
-
net-imap (0.6.
|
|
130
|
+
net-imap (0.6.4)
|
|
137
131
|
date
|
|
138
132
|
net-protocol
|
|
139
133
|
net-pop (0.1.2)
|
|
@@ -142,34 +136,34 @@ GEM
|
|
|
142
136
|
timeout
|
|
143
137
|
net-smtp (0.5.1)
|
|
144
138
|
net-protocol
|
|
145
|
-
nokogiri (1.19.
|
|
139
|
+
nokogiri (1.19.3-arm64-darwin)
|
|
146
140
|
racc (~> 1.4)
|
|
147
|
-
nokogiri (1.19.
|
|
141
|
+
nokogiri (1.19.3-x86_64-linux-gnu)
|
|
148
142
|
racc (~> 1.4)
|
|
149
|
-
openssl (4.0.
|
|
143
|
+
openssl (4.0.2)
|
|
150
144
|
ostruct (0.6.3)
|
|
151
|
-
parallel (1.
|
|
152
|
-
parser (3.3.
|
|
145
|
+
parallel (2.1.0)
|
|
146
|
+
parser (3.3.11.1)
|
|
153
147
|
ast (~> 2.4.1)
|
|
154
148
|
racc
|
|
155
149
|
prettier_print (1.2.1)
|
|
156
150
|
prism (1.9.0)
|
|
157
|
-
process_executer (4.0.
|
|
151
|
+
process_executer (4.0.4)
|
|
158
152
|
track_open_instances (~> 0.1)
|
|
159
|
-
public_suffix (7.0.
|
|
153
|
+
public_suffix (7.0.5)
|
|
160
154
|
racc (1.8.1)
|
|
161
|
-
rack (3.2.
|
|
155
|
+
rack (3.2.6)
|
|
162
156
|
rack-protection (4.2.1)
|
|
163
157
|
base64 (>= 0.1.0)
|
|
164
158
|
logger (>= 1.6.0)
|
|
165
159
|
rack (>= 3.0.0, < 4)
|
|
166
|
-
rack-session (2.1.
|
|
160
|
+
rack-session (2.1.2)
|
|
167
161
|
base64 (>= 0.1.0)
|
|
168
162
|
rack (>= 3.0.0)
|
|
169
163
|
rainbow (3.1.1)
|
|
170
|
-
rake (13.
|
|
164
|
+
rake (13.4.2)
|
|
171
165
|
rchardet (1.10.0)
|
|
172
|
-
regexp_parser (2.
|
|
166
|
+
regexp_parser (2.12.0)
|
|
173
167
|
rexml (3.4.4)
|
|
174
168
|
rspec (3.13.2)
|
|
175
169
|
rspec-core (~> 3.13.0)
|
|
@@ -184,24 +178,23 @@ GEM
|
|
|
184
178
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
185
179
|
rspec-support (~> 3.13.0)
|
|
186
180
|
rspec-support (3.13.7)
|
|
187
|
-
rubocop (1.
|
|
181
|
+
rubocop (1.86.2)
|
|
188
182
|
json (~> 2.3)
|
|
189
183
|
language_server-protocol (~> 3.17.0.2)
|
|
190
184
|
lint_roller (~> 1.1.0)
|
|
191
|
-
|
|
192
|
-
parallel (~> 1.10)
|
|
185
|
+
parallel (>= 1.10)
|
|
193
186
|
parser (>= 3.3.0.2)
|
|
194
187
|
rainbow (>= 2.2.2, < 4.0)
|
|
195
188
|
regexp_parser (>= 2.9.3, < 3.0)
|
|
196
189
|
rubocop-ast (>= 1.49.0, < 2.0)
|
|
197
190
|
ruby-progressbar (~> 1.7)
|
|
198
191
|
unicode-display_width (>= 2.4.0, < 4.0)
|
|
199
|
-
rubocop-ast (1.49.
|
|
192
|
+
rubocop-ast (1.49.1)
|
|
200
193
|
parser (>= 3.3.7.2)
|
|
201
194
|
prism (~> 1.7)
|
|
202
|
-
rubocop-capybara (2.
|
|
195
|
+
rubocop-capybara (2.23.0)
|
|
203
196
|
lint_roller (~> 1.1)
|
|
204
|
-
rubocop (~> 1.
|
|
197
|
+
rubocop (~> 1.81)
|
|
205
198
|
rubocop-factory_bot (2.28.0)
|
|
206
199
|
lint_roller (~> 1.1)
|
|
207
200
|
rubocop (~> 1.72, >= 1.72.1)
|
|
@@ -209,7 +202,7 @@ GEM
|
|
|
209
202
|
lint_roller (~> 1.1)
|
|
210
203
|
rubocop (>= 1.75.0, < 2.0)
|
|
211
204
|
rubocop-ast (>= 1.47.1, < 2.0)
|
|
212
|
-
rubocop-rails (2.
|
|
205
|
+
rubocop-rails (2.35.0)
|
|
213
206
|
activesupport (>= 4.2.0)
|
|
214
207
|
lint_roller (~> 1.1)
|
|
215
208
|
rack (>= 1.1)
|
|
@@ -225,11 +218,10 @@ GEM
|
|
|
225
218
|
lint_roller (~> 1.1)
|
|
226
219
|
rubocop (~> 1.72, >= 1.72.1)
|
|
227
220
|
rubocop-rspec (~> 3.5)
|
|
228
|
-
ruby-prof (2.0.
|
|
221
|
+
ruby-prof (2.0.4)
|
|
229
222
|
base64
|
|
230
223
|
ostruct
|
|
231
224
|
ruby-progressbar (1.13.0)
|
|
232
|
-
ruby2_keywords (0.0.5)
|
|
233
225
|
securerandom (0.4.1)
|
|
234
226
|
sinatra (4.2.1)
|
|
235
227
|
logger (>= 1.6.0)
|
|
@@ -238,7 +230,7 @@ GEM
|
|
|
238
230
|
rack-protection (= 4.2.1)
|
|
239
231
|
rack-session (>= 2.0.0, < 3)
|
|
240
232
|
tilt (~> 2.0)
|
|
241
|
-
strscan (3.1.
|
|
233
|
+
strscan (3.1.8)
|
|
242
234
|
syntax_tree (6.3.0)
|
|
243
235
|
prettier_print (>= 1.2.0)
|
|
244
236
|
syntax_tree-haml (4.0.3)
|
|
@@ -253,7 +245,7 @@ GEM
|
|
|
253
245
|
unicode-display_width (>= 1.1.1, < 4)
|
|
254
246
|
thor (1.5.0)
|
|
255
247
|
tilt (2.7.0)
|
|
256
|
-
timeout (0.6.
|
|
248
|
+
timeout (0.6.1)
|
|
257
249
|
track_open_instances (0.1.15)
|
|
258
250
|
tzinfo (2.0.6)
|
|
259
251
|
concurrent-ruby (~> 1.0)
|
|
@@ -264,7 +256,7 @@ GEM
|
|
|
264
256
|
w_syntax_tree-erb (0.12.0)
|
|
265
257
|
prettier_print (~> 1.2, >= 1.2.0)
|
|
266
258
|
syntax_tree (~> 6.1, >= 6.1.1)
|
|
267
|
-
webmock (3.26.
|
|
259
|
+
webmock (3.26.2)
|
|
268
260
|
addressable (>= 2.8.0)
|
|
269
261
|
crack (>= 0.3.2)
|
|
270
262
|
hashdiff (>= 0.4.0, < 2.0.0)
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.1.1
|
data/lib/code/format.rb
CHANGED
|
@@ -11,6 +11,7 @@ class Code
|
|
|
11
11
|
MAX_INLINE_CALL_ARGUMENTS_LENGTH = 80
|
|
12
12
|
MAX_INLINE_BLOCK_BODY_LENGTH = 40
|
|
13
13
|
CONTINUATION_PADDING = 4
|
|
14
|
+
BOOLEAN_WORD_OPERATORS = %w[and or].freeze
|
|
14
15
|
|
|
15
16
|
class << self
|
|
16
17
|
def format(parsed)
|
|
@@ -328,13 +329,30 @@ class Code
|
|
|
328
329
|
end
|
|
329
330
|
|
|
330
331
|
def format_dictionary_statement_code(statement_code)
|
|
331
|
-
key =
|
|
332
|
+
key =
|
|
333
|
+
format_dictionary_statement_key(statement_code[:statement]) ||
|
|
334
|
+
format_nested_statement(statement_code[:statement], indent: 0)
|
|
332
335
|
return key unless statement_code.key?(:code)
|
|
333
336
|
|
|
334
337
|
value = format_code_inline(statement_code[:code], indent: 0)
|
|
335
338
|
"#{key}: #{value}"
|
|
336
339
|
end
|
|
337
340
|
|
|
341
|
+
def format_dictionary_statement_key(statement)
|
|
342
|
+
return unless statement.is_a?(Hash) && statement.key?(:string)
|
|
343
|
+
|
|
344
|
+
parts = Array(statement[:string])
|
|
345
|
+
return unless parts.one?
|
|
346
|
+
|
|
347
|
+
part = parts.first
|
|
348
|
+
return unless part.is_a?(Hash) && part.key?(:text)
|
|
349
|
+
|
|
350
|
+
text = part[:text].to_s
|
|
351
|
+
return unless text.match?(/\A[a-z_][a-z0-9_]*\z/)
|
|
352
|
+
|
|
353
|
+
text
|
|
354
|
+
end
|
|
355
|
+
|
|
338
356
|
def format_call(call, indent:)
|
|
339
357
|
name = call[:name]
|
|
340
358
|
raw_arguments = call[:arguments].presence || []
|
|
@@ -444,8 +462,8 @@ class Code
|
|
|
444
462
|
if right.include?("\n")
|
|
445
463
|
first_line, *rest = right.lines(chomp: true)
|
|
446
464
|
if multiline_operand_statement?(other[:statement]) ||
|
|
447
|
-
|
|
448
|
-
[
|
|
465
|
+
!BOOLEAN_WORD_OPERATORS.include?(operator)
|
|
466
|
+
["#{expression} #{operator} #{first_line.lstrip}", *rest].join("\n")
|
|
449
467
|
else
|
|
450
468
|
[
|
|
451
469
|
"#{expression}\n#{INDENT * (indent + 1)}#{operator} #{first_line.lstrip}",
|
|
@@ -456,7 +474,7 @@ class Code
|
|
|
456
474
|
right_lines =
|
|
457
475
|
if right.include?("\n")
|
|
458
476
|
right.lines(chomp: true).map(&:lstrip)
|
|
459
|
-
elsif
|
|
477
|
+
elsif BOOLEAN_WORD_OPERATORS.include?(operator)
|
|
460
478
|
right.split(" #{operator} ")
|
|
461
479
|
else
|
|
462
480
|
[right]
|
|
@@ -492,7 +510,7 @@ class Code
|
|
|
492
510
|
expression
|
|
493
511
|
.lines(chomp: true)[1..]
|
|
494
512
|
.to_a
|
|
495
|
-
.reject { |line| line.strip.empty? || line.strip.match?(/\A[\)
|
|
513
|
+
.reject { |line| line.strip.empty? || line.strip.match?(/\A[\])}]+\z/) }
|
|
496
514
|
|
|
497
515
|
return false if continuation_lines.empty?
|
|
498
516
|
|
|
@@ -502,7 +520,7 @@ class Code
|
|
|
502
520
|
continuation_lines.any? do |line|
|
|
503
521
|
next false unless line[/\A */].to_s.length == base_indent
|
|
504
522
|
|
|
505
|
-
line.lstrip.match?(
|
|
523
|
+
line.lstrip.match?(%r{\A(\+|-|\*|/|%|<<|>>|\||\^|&|and\b|or\b)})
|
|
506
524
|
end
|
|
507
525
|
end
|
|
508
526
|
|
|
@@ -713,6 +731,7 @@ class Code
|
|
|
713
731
|
|
|
714
732
|
return true if statement.key?(:dictionnary) || statement.key?(:list)
|
|
715
733
|
return true if statement.key?(:call)
|
|
734
|
+
|
|
716
735
|
if statement.key?(:left_operation)
|
|
717
736
|
operation = statement[:left_operation]
|
|
718
737
|
others = Array(operation[:others])
|
|
@@ -791,6 +810,8 @@ class Code
|
|
|
791
810
|
index, token = split
|
|
792
811
|
left = line[0...index]
|
|
793
812
|
right = line[(index + token.length)..]
|
|
813
|
+
return [line] if token == "." && left.strip.empty?
|
|
814
|
+
|
|
794
815
|
continuation = "#{indent}#{INDENT}#{right.lstrip}"
|
|
795
816
|
|
|
796
817
|
first_line =
|
|
@@ -51,12 +51,20 @@ class Code
|
|
|
51
51
|
|
|
52
52
|
@others.reduce(first) do |left, right|
|
|
53
53
|
if right.call?
|
|
54
|
-
right.statement.evaluate(
|
|
54
|
+
right.statement.evaluate(
|
|
55
|
+
**args,
|
|
56
|
+
object: left,
|
|
57
|
+
previous_object: args.fetch(:object)
|
|
58
|
+
)
|
|
55
59
|
elsif right.safe_call?
|
|
56
60
|
if left.is_an?(Object::Nothing)
|
|
57
61
|
Object::Nothing.new
|
|
58
62
|
else
|
|
59
|
-
right.statement.evaluate(
|
|
63
|
+
right.statement.evaluate(
|
|
64
|
+
**args,
|
|
65
|
+
object: left,
|
|
66
|
+
previous_object: args.fetch(:object)
|
|
67
|
+
)
|
|
60
68
|
end
|
|
61
69
|
elsif (right.or? && left.truthy?) || (right.and? && left.falsy?)
|
|
62
70
|
left
|
|
@@ -76,9 +84,18 @@ class Code
|
|
|
76
84
|
list = Object::IdentifierList.new([first])
|
|
77
85
|
|
|
78
86
|
(@others || []).each do |other|
|
|
79
|
-
|
|
80
|
-
other.statement.resolve(
|
|
81
|
-
|
|
87
|
+
resolved =
|
|
88
|
+
other.statement.resolve(
|
|
89
|
+
**args,
|
|
90
|
+
object: list.code_last,
|
|
91
|
+
previous_object: args.fetch(:object)
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
if resolved.is_a?(Object::IdentifierList)
|
|
95
|
+
resolved.raw.each { |identifier| list.code_append(identifier) }
|
|
96
|
+
else
|
|
97
|
+
list.code_append(resolved)
|
|
98
|
+
end
|
|
82
99
|
end
|
|
83
100
|
|
|
84
101
|
list
|
|
@@ -13,9 +13,10 @@ class Code
|
|
|
13
13
|
|
|
14
14
|
def evaluate(**args)
|
|
15
15
|
left = @left&.evaluate(**args) || Object::Nothing.new
|
|
16
|
+
index_args = args.merge(object: args.fetch(:previous_object, args.fetch(:object)))
|
|
16
17
|
|
|
17
18
|
(@statements || []).reduce(left) do |object, statement|
|
|
18
|
-
object.code_fetch(statement.evaluate(**
|
|
19
|
+
object.code_fetch(statement.evaluate(**index_args))
|
|
19
20
|
end
|
|
20
21
|
end
|
|
21
22
|
|
|
@@ -29,8 +30,10 @@ class Code
|
|
|
29
30
|
Object::IdentifierList.new([left])
|
|
30
31
|
end
|
|
31
32
|
|
|
33
|
+
index_args = args.merge(object: args.fetch(:previous_object, args.fetch(:object)))
|
|
34
|
+
|
|
32
35
|
(@statements || []).each do |statement|
|
|
33
|
-
list.code_append(statement.evaluate(**
|
|
36
|
+
list.code_append(statement.evaluate(**index_args))
|
|
34
37
|
end
|
|
35
38
|
|
|
36
39
|
list
|
|
@@ -134,6 +134,11 @@ class Code
|
|
|
134
134
|
code_arguments = args.fetch(:arguments, List.new).to_code
|
|
135
135
|
globals = multi_fetch(args, *GLOBALS)
|
|
136
136
|
code_value = code_arguments.code_first
|
|
137
|
+
stored_value = code_fetch(code_operator)
|
|
138
|
+
|
|
139
|
+
if stored_value.is_a?(Function)
|
|
140
|
+
return stored_value.call(**args, operator: nil, bound_self: self)
|
|
141
|
+
end
|
|
137
142
|
|
|
138
143
|
case code_operator.to_s
|
|
139
144
|
when "[]", "at", "get"
|
|
@@ -146,11 +151,11 @@ class Code
|
|
|
146
151
|
sig(args)
|
|
147
152
|
code_clear
|
|
148
153
|
when "compact!"
|
|
149
|
-
sig(args)
|
|
150
|
-
code_compact!
|
|
154
|
+
sig(args) { (Function | Class).maybe }
|
|
155
|
+
code_compact!(code_value, **globals)
|
|
151
156
|
when "compact"
|
|
152
|
-
sig(args)
|
|
153
|
-
code_compact
|
|
157
|
+
sig(args) { (Function | Class).maybe }
|
|
158
|
+
code_compact(code_value, **globals)
|
|
154
159
|
when "delete"
|
|
155
160
|
sig(args) { Object.repeat(1) }
|
|
156
161
|
code_delete(*code_arguments.raw, **globals)
|
|
@@ -581,12 +586,45 @@ class Code
|
|
|
581
586
|
self
|
|
582
587
|
end
|
|
583
588
|
|
|
584
|
-
def code_compact
|
|
585
|
-
|
|
589
|
+
def code_compact(argument = nil, **globals)
|
|
590
|
+
code_argument = argument.to_code
|
|
591
|
+
|
|
592
|
+
Dictionary.new(
|
|
593
|
+
raw.reject.with_index do |(key, value), index|
|
|
594
|
+
if code_argument.nothing?
|
|
595
|
+
value.nothing?
|
|
596
|
+
elsif code_argument.is_a?(Class)
|
|
597
|
+
value.is_a?(code_argument.raw)
|
|
598
|
+
else
|
|
599
|
+
code_argument.call(
|
|
600
|
+
arguments: List.new([value, key, Integer.new(index), self]),
|
|
601
|
+
**globals
|
|
602
|
+
).truthy?
|
|
603
|
+
end
|
|
604
|
+
rescue Error::Next => e
|
|
605
|
+
e.code_value.truthy?
|
|
606
|
+
end
|
|
607
|
+
)
|
|
586
608
|
end
|
|
587
609
|
|
|
588
|
-
def code_compact!
|
|
589
|
-
|
|
610
|
+
def code_compact!(argument = nil, **globals)
|
|
611
|
+
code_argument = argument.to_code
|
|
612
|
+
|
|
613
|
+
raw.reject!.with_index do |(key, value), index|
|
|
614
|
+
if code_argument.nothing?
|
|
615
|
+
value.nothing?
|
|
616
|
+
elsif code_argument.is_a?(Class)
|
|
617
|
+
value.is_a?(code_argument.raw)
|
|
618
|
+
else
|
|
619
|
+
code_argument.call(
|
|
620
|
+
arguments: List.new([value, key, Integer.new(index), self]),
|
|
621
|
+
**globals
|
|
622
|
+
).truthy?
|
|
623
|
+
end
|
|
624
|
+
rescue Error::Next => e
|
|
625
|
+
e.code_value.truthy?
|
|
626
|
+
end
|
|
627
|
+
|
|
590
628
|
self
|
|
591
629
|
end
|
|
592
630
|
|
data/lib/code/object/function.rb
CHANGED
|
@@ -33,6 +33,7 @@ class Code
|
|
|
33
33
|
code_call(
|
|
34
34
|
*code_arguments.raw,
|
|
35
35
|
explicit_arguments: args.fetch(:explicit_arguments, true),
|
|
36
|
+
bound_self: args.fetch(:bound_self, nil),
|
|
36
37
|
**globals
|
|
37
38
|
)
|
|
38
39
|
when "extend"
|
|
@@ -64,10 +65,11 @@ class Code
|
|
|
64
65
|
code_arguments = arguments.to_code
|
|
65
66
|
code_context = Context.new({}, definition_context || globals[:context])
|
|
66
67
|
code_self = bound_self.to_code
|
|
67
|
-
code_self = captured_self if code_self.nothing? && captured_self
|
|
68
68
|
code_self = Dictionary.new if code_self.nil? || code_self.nothing?
|
|
69
|
+
code_parent = captured_self.to_code
|
|
69
70
|
|
|
70
71
|
code_context.code_set("self", code_self)
|
|
72
|
+
bind_parent(code_context, code_self, code_parent)
|
|
71
73
|
|
|
72
74
|
if parent.is_a?(Function)
|
|
73
75
|
code_context.code_set(
|
|
@@ -110,7 +112,18 @@ class Code
|
|
|
110
112
|
code_arguments.raw[index].to_code
|
|
111
113
|
end
|
|
112
114
|
|
|
113
|
-
|
|
115
|
+
if code_argument.nothing?
|
|
116
|
+
code_default = code_parameter.code_default
|
|
117
|
+
code_argument =
|
|
118
|
+
if code_default.is_a?(Code)
|
|
119
|
+
code_default.code_evaluate(
|
|
120
|
+
**globals,
|
|
121
|
+
context: code_context
|
|
122
|
+
)
|
|
123
|
+
else
|
|
124
|
+
code_default
|
|
125
|
+
end
|
|
126
|
+
end
|
|
114
127
|
|
|
115
128
|
code_context.code_set(code_parameter.code_name, code_argument)
|
|
116
129
|
end
|
|
@@ -200,6 +213,18 @@ class Code
|
|
|
200
213
|
|
|
201
214
|
private
|
|
202
215
|
|
|
216
|
+
def bind_parent(code_context, code_self, code_parent)
|
|
217
|
+
return if code_parent.nothing?
|
|
218
|
+
|
|
219
|
+
code_context.code_set("parent", code_parent)
|
|
220
|
+
|
|
221
|
+
return unless code_self.is_a?(Dictionary)
|
|
222
|
+
return if code_self == code_parent
|
|
223
|
+
return if code_self.code_has_key?("parent").truthy?
|
|
224
|
+
|
|
225
|
+
code_self.code_set("parent", code_parent)
|
|
226
|
+
end
|
|
227
|
+
|
|
203
228
|
def captured_self
|
|
204
229
|
self_from(definition_context)
|
|
205
230
|
end
|
|
@@ -241,7 +266,7 @@ class Code
|
|
|
241
266
|
if code_parameter.code_default.code_to_string.raw == "nothing"
|
|
242
267
|
[]
|
|
243
268
|
else
|
|
244
|
-
Code.parse(code_parameter.code_default.to_s)
|
|
269
|
+
::Code.parse(code_parameter.code_default.to_s)
|
|
245
270
|
end
|
|
246
271
|
)
|
|
247
272
|
end
|
data/lib/code/object/list.rb
CHANGED
|
@@ -1545,25 +1545,22 @@ class Code
|
|
|
1545
1545
|
def code_compact(argument = nil, **globals)
|
|
1546
1546
|
code_argument = argument.to_code
|
|
1547
1547
|
|
|
1548
|
-
index = 0
|
|
1549
|
-
|
|
1550
1548
|
List.new(
|
|
1551
|
-
raw.
|
|
1552
|
-
if code_argument.
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
.tap { index += 1 }
|
|
1549
|
+
raw.reject.with_index do |code_element, index|
|
|
1550
|
+
if code_argument.nothing?
|
|
1551
|
+
code_element.nothing?
|
|
1552
|
+
elsif code_argument.is_a?(Function)
|
|
1553
|
+
code_argument.call(
|
|
1554
|
+
arguments: List.new([code_element, Integer.new(index), self]),
|
|
1555
|
+
**globals
|
|
1556
|
+
).truthy?
|
|
1560
1557
|
elsif code_argument.is_a?(Class)
|
|
1561
|
-
code_element.is_a?(code_argument.raw)
|
|
1558
|
+
code_element.is_a?(code_argument.raw)
|
|
1562
1559
|
else
|
|
1563
|
-
|
|
1560
|
+
false
|
|
1564
1561
|
end
|
|
1565
1562
|
rescue Error::Next => e
|
|
1566
|
-
e.code_value.
|
|
1563
|
+
e.code_value.truthy?
|
|
1567
1564
|
end
|
|
1568
1565
|
)
|
|
1569
1566
|
end
|
|
@@ -1571,24 +1568,21 @@ class Code
|
|
|
1571
1568
|
def code_compact!(argument = nil, **globals)
|
|
1572
1569
|
code_argument = argument.to_code
|
|
1573
1570
|
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
code_argument
|
|
1579
|
-
.
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
)
|
|
1583
|
-
.truthy?
|
|
1584
|
-
.tap { index += 1 }
|
|
1571
|
+
raw.reject!.with_index do |code_element, index|
|
|
1572
|
+
if code_argument.nothing?
|
|
1573
|
+
code_element.nothing?
|
|
1574
|
+
elsif code_argument.is_a?(Function)
|
|
1575
|
+
code_argument.call(
|
|
1576
|
+
arguments: List.new([code_element, Integer.new(index), self]),
|
|
1577
|
+
**globals
|
|
1578
|
+
).truthy?
|
|
1585
1579
|
elsif code_argument.is_a?(Class)
|
|
1586
|
-
code_element.is_a?(code_argument.raw)
|
|
1580
|
+
code_element.is_a?(code_argument.raw)
|
|
1587
1581
|
else
|
|
1588
|
-
|
|
1582
|
+
false
|
|
1589
1583
|
end
|
|
1590
1584
|
rescue Error::Next => e
|
|
1591
|
-
e.code_value.
|
|
1585
|
+
e.code_value.truthy?
|
|
1592
1586
|
end
|
|
1593
1587
|
|
|
1594
1588
|
self
|
data/spec/code/format_spec.rb
CHANGED
|
@@ -16,6 +16,9 @@ RSpec.describe Code::Format do
|
|
|
16
16
|
["true || false", "true or false"],
|
|
17
17
|
["true && false", "true and false"],
|
|
18
18
|
["{a:1}", "{ a: 1 }"],
|
|
19
|
+
["{ :mobility: mobility }", "{ mobility: mobility }"],
|
|
20
|
+
['{ "hello": "world" }', "{ hello: :world }"],
|
|
21
|
+
['{ "hello" => "world" }', "{ hello: :world }"],
|
|
19
22
|
["[1,2,3]", "[1, 2, 3]"],
|
|
20
23
|
["[1, 2, 3].select { |n| n.even? }", "[1, 2, 3].select { |n| n.even? }"],
|
|
21
24
|
[
|
|
@@ -54,6 +57,10 @@ RSpec.describe Code::Format do
|
|
|
54
57
|
"blocks << { title: \"hello world\", description: \"lorem ipsum dolor es sit\", position: 1 }",
|
|
55
58
|
"blocks << {\n title: \"hello world\",\n description: \"lorem ipsum dolor es sit\",\n position: 1\n}"
|
|
56
59
|
],
|
|
60
|
+
[
|
|
61
|
+
"query = { :mobility: mobility, :unit_organization_id: unit_organization_id, :limit: limit, :offset: offset }",
|
|
62
|
+
"query = {\n mobility: mobility,\n unit_organization_id: unit_organization_id,\n limit: limit,\n offset: offset\n}"
|
|
63
|
+
],
|
|
57
64
|
[
|
|
58
65
|
"sections << Html.join([Html.p { Html.b { \"{index + 1}. {title}\" } }, Html.p { query } if query.presence, Html.p { Html.a(href: link || inline_url) { :source } } if (link || inline_url), Html.p { Html.a(href: inline_url) { Html.img(src: inline_url, alt: title) } }, Html.p { Html.a(href: attachment_url) { \"télécharger\" } }].compact)",
|
|
59
66
|
"sections << Html.join(\n [\n Html.p { Html.b { \"{index + 1}. {title}\" } },\n Html.p { query } if query.presence,\n Html.p {\n Html.a(href: link or inline_url) { :source }\n } if (link or inline_url),\n Html.p {\n Html.a(href: inline_url) { Html.img(src: inline_url, alt: title) }\n },\n Html.p {\n Html.a(href: attachment_url) { \"télécharger\" }\n }\n ].compact\n)"
|
|
@@ -140,7 +147,7 @@ RSpec.describe Code::Format do
|
|
|
140
147
|
|
|
141
148
|
formatted = described_class.format(Code.parse(input))
|
|
142
149
|
|
|
143
|
-
expect(formatted.lines.map
|
|
150
|
+
expect(formatted.lines.map { |line| line.chomp.length }.max).to be <= 80
|
|
144
151
|
end
|
|
145
152
|
end
|
|
146
153
|
end
|
|
@@ -74,6 +74,8 @@ RSpec.describe Code::Object::Dictionary do
|
|
|
74
74
|
["{ a: 1, b: [2, 3] }.flatten(1)", "[:a, 1, :b, [2, 3]]"],
|
|
75
75
|
["{ a: 1, b: [2, 3] }.to_list", "[[:a, 1], [:b, [2, 3]]]"],
|
|
76
76
|
["{ a: nothing }.compact", "{}"],
|
|
77
|
+
["{ a: nothing, b: 1, c: false, d: \"\" }.compact", '{ b: 1, c: false, d: "" }'],
|
|
78
|
+
["{ a: nothing, b: 1, c: false, d: \"\" }.compact(&:blank?)", "{ b: 1 }"],
|
|
77
79
|
["{ age: 31 }.delete_unless { |key| key == :age }", "{ age: 31 }"],
|
|
78
80
|
["{ age: 31 }.delete_unless(Integer)", "{ age: 31 }"],
|
|
79
81
|
["{ age: 31 }.keep_unless { |key| key == :age }", "{}"],
|
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
require "spec_helper"
|
|
4
4
|
|
|
5
5
|
RSpec.describe Code::Object::Function do
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
[
|
|
7
|
+
["even? = (i) => { i.even? } even?(2)", "true"],
|
|
8
|
+
["even? = (i:) => { i.even? } even?(i: 2)", "true"],
|
|
9
|
+
["add = (a, b) => { a + b } add(1, 2)", "3"],
|
|
10
|
+
["minus = (a:, b:) => { a - b } minus(b: 1, a: 2)", "1"]
|
|
11
|
+
].each do |input, expected|
|
|
12
|
+
it "#{input} == #{expected}" do
|
|
13
|
+
expect(Code.evaluate(input)).to eq(Code.evaluate(expected))
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
16
|
|
|
17
17
|
context "valid" do
|
|
18
18
|
[
|
|
19
19
|
"f = () => {} f",
|
|
20
|
-
"f = (x) => {} f(1)"
|
|
21
|
-
|
|
20
|
+
"f = (x) => {} f(1)",
|
|
21
|
+
"f = (x:) => {} f(x: 1)"
|
|
22
22
|
].each do |input|
|
|
23
23
|
it "#{input} is valid" do
|
|
24
24
|
Code.evaluate(input)
|
|
@@ -38,6 +38,46 @@ RSpec.describe Code::Object::Function do
|
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
+
it "evaluates omitted keyword argument defaults" do
|
|
42
|
+
result = Code.evaluate(<<~CODE)
|
|
43
|
+
f = (number: 1, text: "fallback", missing: nothing, headers: {}) => {
|
|
44
|
+
[
|
|
45
|
+
number,
|
|
46
|
+
text,
|
|
47
|
+
missing.nothing?,
|
|
48
|
+
headers.merge({ authorization: "Bearer x" })
|
|
49
|
+
]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
f()
|
|
53
|
+
CODE
|
|
54
|
+
|
|
55
|
+
expect(result).to eq(
|
|
56
|
+
Code.evaluate('[1, "fallback", true, { authorization: "Bearer x" }]')
|
|
57
|
+
)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "evaluates keyword defaults in the call context" do
|
|
61
|
+
expect(Code.evaluate("f = (a:, b: a + 1) => { b } f(a: 2)")).to eq(
|
|
62
|
+
Code.evaluate("3")
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "binds self when calling a function stored on a dictionary" do
|
|
67
|
+
result = Code.evaluate(<<~CODE)
|
|
68
|
+
object = {}
|
|
69
|
+
object.value = 1
|
|
70
|
+
object.fetch = () => {
|
|
71
|
+
self.value
|
|
72
|
+
}
|
|
73
|
+
object.fetch()
|
|
74
|
+
CODE
|
|
75
|
+
|
|
76
|
+
expect(result).to eq(
|
|
77
|
+
Code.evaluate("1")
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
41
81
|
it "captures self for constructor-like functions that return self" do
|
|
42
82
|
result = Code.evaluate(<<~CODE)
|
|
43
83
|
User = (given_name:, family_name:, birth_date:) => {
|
|
@@ -72,6 +112,73 @@ RSpec.describe Code::Object::Function do
|
|
|
72
112
|
)
|
|
73
113
|
end
|
|
74
114
|
|
|
115
|
+
it "binds parent to the enclosing self for nested constructor functions" do
|
|
116
|
+
result = Code.evaluate(<<~CODE)
|
|
117
|
+
Account = (name:) => {
|
|
118
|
+
self.name = name
|
|
119
|
+
|
|
120
|
+
self.Project = (name:) => {
|
|
121
|
+
self.name = name
|
|
122
|
+
|
|
123
|
+
self.Task = (name:) => {
|
|
124
|
+
self.name = name
|
|
125
|
+
|
|
126
|
+
[
|
|
127
|
+
self.name,
|
|
128
|
+
parent.name,
|
|
129
|
+
parent.parent.name
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return(self)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return(self)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
account = Account(name: "Acme")
|
|
140
|
+
Project = account.get(:Project)
|
|
141
|
+
project = Project(name: "Migration")
|
|
142
|
+
Task = project.get(:Task)
|
|
143
|
+
Task(name: "Import")
|
|
144
|
+
CODE
|
|
145
|
+
|
|
146
|
+
expect(result).to eq(
|
|
147
|
+
Code.evaluate('["Import", "Migration", "Acme"]')
|
|
148
|
+
)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "allows parent chains deeper than two levels" do
|
|
152
|
+
result = Code.evaluate(<<~CODE)
|
|
153
|
+
A = (name:) => {
|
|
154
|
+
self.name = name
|
|
155
|
+
self.B = (name:) => {
|
|
156
|
+
self.name = name
|
|
157
|
+
self.C = (name:) => {
|
|
158
|
+
self.name = name
|
|
159
|
+
self.D = (name:) => {
|
|
160
|
+
self.name = name
|
|
161
|
+
parent.parent.parent.name
|
|
162
|
+
}
|
|
163
|
+
return(self)
|
|
164
|
+
}
|
|
165
|
+
return(self)
|
|
166
|
+
}
|
|
167
|
+
return(self)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
a = A(name: "a")
|
|
171
|
+
B = a.get(:B)
|
|
172
|
+
b = B(name: "b")
|
|
173
|
+
C = b.get(:C)
|
|
174
|
+
c = C(name: "c")
|
|
175
|
+
D = c.get(:D)
|
|
176
|
+
D(name: "d")
|
|
177
|
+
CODE
|
|
178
|
+
|
|
179
|
+
expect(result).to eq(Code::Object::String.new("a"))
|
|
180
|
+
end
|
|
181
|
+
|
|
75
182
|
it "supports constructor methods on functions" do
|
|
76
183
|
result = Code.evaluate(<<~CODE)
|
|
77
184
|
User = (given_name:, family_name:) => {
|
|
@@ -5,6 +5,8 @@ require "spec_helper"
|
|
|
5
5
|
RSpec.describe Code::Object::List do
|
|
6
6
|
[
|
|
7
7
|
["[] == []", "true"],
|
|
8
|
+
["[nothing, 1, false, \"\"].compact", '[1, false, ""]'],
|
|
9
|
+
["[nothing, 1, false, \"\"].compact(&:blank?)", "[1]"],
|
|
8
10
|
["[1, 2, 3].sum", "6"],
|
|
9
11
|
["[1, 2] + [3, 4]", "[1, 2, 3, 4]"],
|
|
10
12
|
["[] + []", "[]"],
|
data/spec/code_spec.rb
CHANGED
|
@@ -328,6 +328,18 @@ RSpec.describe Code do
|
|
|
328
328
|
["[1, 2, 3]", "[1, 2, 3]"],
|
|
329
329
|
["[1, 2, 3].include?(2)", "true"],
|
|
330
330
|
["[1, 2, 3].include?(4)", "false"],
|
|
331
|
+
[
|
|
332
|
+
"summary = { by_status: { draft: 1 } } k = \"draft\" summary.by_status[k]",
|
|
333
|
+
"1"
|
|
334
|
+
],
|
|
335
|
+
[
|
|
336
|
+
"summary = { by_status: {} } k = \"draft\" summary.by_status[k] = 1 summary",
|
|
337
|
+
'{"by_status" => {"draft" => 1}}'
|
|
338
|
+
],
|
|
339
|
+
[
|
|
340
|
+
"summary = { by_status: {} } [{status: \"draft\"}].each { |track| summary.by_status[track[:status]] = 1 } summary",
|
|
341
|
+
'{"by_status" => {"draft" => 1}}'
|
|
342
|
+
],
|
|
331
343
|
["[1, 2, 3].map { |i| continue(0) if i.even? i ** 2}", "[1, 0, 9]"],
|
|
332
344
|
["[1, 2, 3].map { |i| next if i == 2 i ** 2}", "[1, nothing, 9]"],
|
|
333
345
|
["[1, 2, 3].map { |i| next(0) if i.even? i ** 2}", "[1, 0, 9]"],
|