code-ruby 0.13.1 → 0.14.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +15 -0
  3. data/.github/workflows/ci.yml +31 -0
  4. data/.rubocop.yml +8 -0
  5. data/Gemfile +2 -0
  6. data/Gemfile.lock +51 -3
  7. data/bin/bundle-audit +31 -0
  8. data/bin/bundler-audit +31 -0
  9. data/bin/console +1 -0
  10. data/bin/rspec +31 -0
  11. data/bin/rubocop +31 -0
  12. data/lib/code/error.rb +0 -3
  13. data/lib/code/node/base_10.rb +4 -3
  14. data/lib/code/node/base_16.rb +1 -0
  15. data/lib/code/node/base_2.rb +1 -0
  16. data/lib/code/node/base_8.rb +1 -0
  17. data/lib/code/node/boolean.rb +1 -0
  18. data/lib/code/node/call.rb +14 -15
  19. data/lib/code/node/call_argument.rb +4 -4
  20. data/lib/code/node/code.rb +1 -0
  21. data/lib/code/node/decimal.rb +4 -3
  22. data/lib/code/node/dictionary.rb +5 -3
  23. data/lib/code/node/function.rb +1 -0
  24. data/lib/code/node/function_parameter.rb +14 -0
  25. data/lib/code/node/if.rb +6 -4
  26. data/lib/code/node/left_operation.rb +3 -3
  27. data/lib/code/node/list.rb +1 -0
  28. data/lib/code/node/negation.rb +1 -0
  29. data/lib/code/node/not.rb +1 -0
  30. data/lib/code/node/nothing.rb +1 -0
  31. data/lib/code/node/right_operation.rb +3 -2
  32. data/lib/code/node/splat.rb +1 -0
  33. data/lib/code/node/square_bracket.rb +1 -0
  34. data/lib/code/node/string.rb +3 -0
  35. data/lib/code/node/ternary.rb +4 -3
  36. data/lib/code/node/unary_minus.rb +1 -0
  37. data/lib/code/node/while.rb +4 -3
  38. data/lib/code/object/boolean.rb +2 -2
  39. data/lib/code/object/context.rb +1 -1
  40. data/lib/code/object/decimal.rb +9 -21
  41. data/lib/code/object/dictionary.rb +43 -113
  42. data/lib/code/object/function.rb +25 -35
  43. data/lib/code/object/global.rb +33 -32
  44. data/lib/code/object/identifier_list.rb +4 -4
  45. data/lib/code/object/integer.rb +14 -23
  46. data/lib/code/object/json.rb +10 -2
  47. data/lib/code/object/list.rb +50 -23
  48. data/lib/code/object/parameter.rb +18 -10
  49. data/lib/code/object/range.rb +33 -10
  50. data/lib/code/object/string.rb +2 -2
  51. data/lib/code/object/time.rb +4 -4
  52. data/lib/code/object.rb +31 -50
  53. data/lib/code/parser/string.rb +1 -1
  54. data/lib/code/type/repeat.rb +1 -1
  55. data/lib/code/type/sig.rb +1 -3
  56. data/lib/code/version.rb +1 -1
  57. data/lib/code-ruby.rb +2 -7
  58. data/lib/code.rb +1 -3
  59. data/spec/code/object/dictionary_spec.rb +6 -6
  60. data/spec/code_spec.rb +5 -8
  61. data/yarn.lock +4 -0
  62. metadata +10 -3
  63. data/lib/code/object/argument.rb +0 -27
@@ -5,6 +5,7 @@ class Code
5
5
  class Splat < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
+
8
9
  @operator = parsed.delete(:operator).presence
9
10
  @right = Node::Statement.new(parsed.delete(:right).presence)
10
11
  end
@@ -5,6 +5,7 @@ class Code
5
5
  class SquareBracket < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
+
8
9
  @left = Node::Statement.new(parsed.delete(:left).presence)
9
10
  @statements = parsed.delete(:statements).presence || []
10
11
  @statements.map! { |statement| Node::Statement.new(statement) }
@@ -7,6 +7,7 @@ class Code
7
7
  class Code < Node
8
8
  def initialize(parsed)
9
9
  return if parsed.blank?
10
+
10
11
  @code = Node::Code.new(parsed.presence)
11
12
  end
12
13
 
@@ -18,6 +19,7 @@ class Code
18
19
  class Text < Node
19
20
  def initialize(parsed)
20
21
  return if parsed.blank?
22
+
21
23
  @text = parsed
22
24
  end
23
25
 
@@ -53,6 +55,7 @@ class Code
53
55
 
54
56
  def initialize(parsed)
55
57
  return if parsed.blank?
58
+
56
59
  @parts =
57
60
  (parsed.presence || []).map { |part| Node::String::Part.new(part) }
58
61
  end
@@ -5,11 +5,12 @@ class Code
5
5
  class Ternary < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
+
8
9
  @left = Node::Statement.new(parsed.delete(:left).presence)
9
10
  @middle = Node::Statement.new(parsed.delete(:middle).presence)
10
- if parsed.key?(:right)
11
- @right = Node::Statement.new(parsed.delete(:right).presence)
12
- end
11
+ return unless parsed.key?(:right)
12
+
13
+ @right = Node::Statement.new(parsed.delete(:right).presence)
13
14
  end
14
15
 
15
16
  def evaluate(**args)
@@ -5,6 +5,7 @@ class Code
5
5
  class UnaryMinus < Node
6
6
  def initialize(parsed)
7
7
  return if parsed.blank?
8
+
8
9
  @operator = parsed.delete(:operator).presence
9
10
  @right = Node::Statement.new(parsed.delete(:right).presence)
10
11
  end
@@ -9,10 +9,11 @@ class Code
9
9
 
10
10
  def initialize(parsed)
11
11
  return if parsed.blank?
12
+
12
13
  @operator = parsed.delete(:operator).presence
13
- if parsed.key?(:statement)
14
- @statement = Statement.new(parsed.delete(:statement))
15
- end
14
+ @statement = Statement.new(parsed.delete(:statement)) if parsed.key?(
15
+ :statement
16
+ )
16
17
  @body = Code.new(parsed.delete(:body).presence)
17
18
  end
18
19
 
@@ -11,8 +11,8 @@ class Code
11
11
 
12
12
  def call(**args)
13
13
  operator = args.fetch(:operator, nil)
14
- arguments = args.fetch(:arguments, [])
15
- value = arguments.first&.value
14
+ arguments = args.fetch(:arguments, List.new)
15
+ value = arguments.code_first
16
16
 
17
17
  case operator.to_s
18
18
  when "&", "bitwise_and"
@@ -18,7 +18,7 @@ class Code
18
18
  elsif parent?
19
19
  parent.lookup!(identifier)
20
20
  else
21
- raise Error::Undefined, "#{identifier} is not defined"
21
+ raise Error::Undefined, "#{identifier} is not defined"
22
22
  end
23
23
  end
24
24
 
@@ -9,14 +9,14 @@ class Code
9
9
  decimal = decimal.raw if decimal.is_an?(Object)
10
10
  exponent = exponent.raw if exponent.is_an?(Object)
11
11
  @raw = decimal.to_d * 10**exponent.to_d
12
- rescue FloatDomainError => e
12
+ rescue FloatDomainError
13
13
  raise Error, "#{decimal.inspect} * 10**#{exponent.inspect} is invalid"
14
14
  end
15
15
 
16
16
  def call(**args)
17
17
  operator = args.fetch(:operator, nil)
18
- arguments = args.fetch(:arguments, [])
19
- value = arguments.first&.value
18
+ arguments = args.fetch(:arguments, List.new)
19
+ value = arguments.code_first
20
20
 
21
21
  case operator.to_s
22
22
  when "%", "modulo"
@@ -33,10 +33,10 @@ class Code
33
33
  code_power(value)
34
34
  when "+", "plus"
35
35
  sig(args) { Object.maybe }
36
- value ? code_plus(value) : self
36
+ arguments.any? ? code_plus(value) : self
37
37
  when "-", "minus"
38
38
  sig(args) { (Integer | Decimal).maybe }
39
- value ? code_minus(value) : code_unary_minus
39
+ arguments.any? ? code_minus(value) : code_unary_minus
40
40
  when "/", "division"
41
41
  sig(args) { Integer | Decimal }
42
42
  code_division(value)
@@ -152,7 +152,7 @@ class Code
152
152
  end
153
153
 
154
154
  def code_ceil(n = nil)
155
- n ||= Integer.new(0)
155
+ n = Integer.new(0) if n.nil? || n.is_a?(Nothing)
156
156
  Decimal.new(raw.ceil(n.raw))
157
157
  end
158
158
 
@@ -177,7 +177,7 @@ class Code
177
177
  end
178
178
 
179
179
  def code_floor(n = nil)
180
- n ||= Integer.new(0)
180
+ n = Integer.new(0) if n.nil? || n.is_a?(Nothing)
181
181
  Decimal.new(raw.floor(n.raw))
182
182
  end
183
183
 
@@ -234,7 +234,7 @@ class Code
234
234
  end
235
235
 
236
236
  def code_round(n = nil)
237
- n ||= Integer.new(0)
237
+ n = Integer.new(0) if n.nil? || n.is_a?(Nothing)
238
238
  Decimal.new(raw.round(n.raw))
239
239
  end
240
240
 
@@ -279,7 +279,7 @@ class Code
279
279
  end
280
280
 
281
281
  def code_truncate(n = nil)
282
- n ||= Integer.new(0)
282
+ n = Integer.new(0) if n.nil? || n.is_a?(Nothing)
283
283
  Decimal.new(raw.truncate(n.raw))
284
284
  end
285
285
 
@@ -294,18 +294,6 @@ class Code
294
294
  def code_zero?
295
295
  Boolean.new(raw.zero?)
296
296
  end
297
-
298
- def whole?
299
- whole == raw
300
- end
301
-
302
- def whole
303
- raw.round
304
- end
305
-
306
- def as_json(...)
307
- whole? ? whole.as_json(...) : super
308
- end
309
297
  end
310
298
  end
311
299
  end
@@ -3,19 +3,15 @@
3
3
  class Code
4
4
  class Object
5
5
  class Dictionary < ::Code::Object
6
- def initialize(*args, **_kargs, &_block)
7
- @raw = (args.first.presence || {})
8
- .as_json
9
- .to_h
10
- .transform_keys { |key| Json.to_code(key) }
11
- .transform_values { |value| Json.to_code(value) }
6
+ def initialize(*args, **kargs, &_block)
7
+ @raw = args.map(&:to_h).reduce({}, &:merge).merge(kargs)
12
8
  end
13
9
 
14
10
  def call(**args)
15
11
  operator = args.fetch(:operator, nil)
16
- arguments = args.fetch(:arguments, [])
12
+ arguments = args.fetch(:arguments, List.new)
17
13
  globals = multi_fetch(args, *GLOBALS)
18
- value = arguments.first&.value
14
+ value = arguments.code_first
19
15
 
20
16
  case operator.to_s
21
17
  when "<", "inferior"
@@ -50,7 +46,7 @@ class Code
50
46
  code_compact
51
47
  when "delete"
52
48
  sig(args) { Object.repeat(1) }
53
- code_delete(*arguments.map(&:value), **globals)
49
+ code_delete(*arguments.raw, **globals)
54
50
  when "delete_if"
55
51
  sig(args) { Function | Class }
56
52
  code_delete_if(value, **globals)
@@ -59,7 +55,7 @@ class Code
59
55
  code_delete_unless(value, **globals)
60
56
  when "dig"
61
57
  sig(args) { Object.repeat(1) }
62
- code_dig(*arguments.map(&:value))
58
+ code_dig(*arguments.raw)
63
59
  when "each"
64
60
  sig(args) { Function }
65
61
  code_each(value, **globals)
@@ -71,13 +67,13 @@ class Code
71
67
  code_empty?
72
68
  when "except"
73
69
  sig(args) { Object.repeat(1) }
74
- code_except(*arguments.map(&:value))
70
+ code_except(*arguments.raw)
75
71
  when "fetch"
76
72
  sig(args) { Object.repeat(1) }
77
- code_fetch(*arguments.map(&:value), **globals)
73
+ code_fetch(*arguments.raw, **globals)
78
74
  when "fetch_values"
79
75
  sig(args) { Object.repeat(1) }
80
- code_fetch_values(*arguments.map(&:value))
76
+ code_fetch_values(*arguments.raw)
81
77
  when "five?"
82
78
  sig(args)
83
79
  code_five?
@@ -104,13 +100,13 @@ class Code
104
100
  code_keep_unless(value, **globals)
105
101
  when "key"
106
102
  sig(args) { [Object, Function.maybe] }
107
- code_key(*arguments.map(&:value), **globals)
103
+ code_key(*arguments.raw, **globals)
108
104
  when "keys"
109
105
  sig(args)
110
106
  code_keys
111
107
  when "merge"
112
108
  sig(args) { [Dictionary.repeat, Function.maybe] }
113
- code_merge(*arguments.map(&:value), **globals)
109
+ code_merge(*arguments.raw, **globals)
114
110
  when "nine?"
115
111
  sig(args)
116
112
  code_nine?
@@ -177,12 +173,7 @@ class Code
177
173
  raw.any? do |key, value|
178
174
  argument
179
175
  .call(
180
- arguments: [
181
- Argument.new(key),
182
- Argument.new(value),
183
- Argument.new(self),
184
- Argument.new(Integer.new(index))
185
- ],
176
+ arguments: List.new([key, value, self, Integer.new(index)]),
186
177
  **globals
187
178
  )
188
179
  .truthy?
@@ -219,22 +210,16 @@ class Code
219
210
  )
220
211
 
221
212
  arguments = arguments[..-2] if default
213
+ first = arguments.first
222
214
 
223
215
  if arguments.one?
224
- raw.delete(arguments.first) do
216
+ raw.delete(first) do
225
217
  if default
226
- default.call(
227
- arguments: [
228
- Argument.new(arguments.first),
229
- Argument.new(self),
230
- Argument.new(index)
231
- ],
232
- **globals
233
- )
218
+ default.call(arguments: List.new([first, self, index]), **globals)
234
219
  else
235
220
  raise(
236
221
  Code::Error::KeyNotFound,
237
- "#{arguments.first.inspect} not found on #{inspect}"
222
+ "#{first.inspect} not found on #{inspect}"
238
223
  )
239
224
  end
240
225
  end
@@ -271,12 +256,7 @@ class Code
271
256
  else
272
257
  raw.delete_if.with_index do |(key, value), index|
273
258
  argument.call(
274
- arguments: [
275
- Argument.new(key),
276
- Argument.new(value),
277
- Argument.new(self),
278
- Argument.new(Integer.new(index))
279
- ],
259
+ arguments: List.new([key, value, self, Integer.new(index)]),
280
260
  **globals
281
261
  ).truthy?
282
262
  end
@@ -291,12 +271,7 @@ class Code
291
271
  else
292
272
  raw.delete_if.with_index do |(key, value), index|
293
273
  argument.call(
294
- arguments: [
295
- Argument.new(key),
296
- Argument.new(value),
297
- Argument.new(self),
298
- Argument.new(Integer.new(index))
299
- ],
274
+ arguments: List.new([key, value, self, Integer.new(index)]),
300
275
  **globals
301
276
  ).falsy?
302
277
  end
@@ -312,12 +287,7 @@ class Code
312
287
  def code_each(argument, **globals)
313
288
  raw.each.with_index do |(key, value), index|
314
289
  argument.call(
315
- arguments: [
316
- Argument.new(key),
317
- Argument.new(value),
318
- Argument.new(self),
319
- Argument.new(Integer.new(index))
320
- ],
290
+ arguments: List.new([key, value, self, Integer.new(index)]),
321
291
  **globals
322
292
  )
323
293
  end
@@ -337,7 +307,7 @@ class Code
337
307
  self.class.new(raw.except(*))
338
308
  end
339
309
 
340
- def code_fetch(*arguments, index: Integer.new(0), **globals)
310
+ def code_fetch(*arguments, index: 0, **globals)
341
311
  default =
342
312
  (
343
313
  if arguments.last.is_a?(Function) && arguments.size > 1
@@ -346,45 +316,31 @@ class Code
346
316
  )
347
317
 
348
318
  arguments = arguments[..-2] if default
319
+ first = arguments.first || Nothing.new
349
320
 
350
321
  if arguments.one?
351
- raw.fetch(arguments.first) do
322
+ raw.fetch(first) do
352
323
  if default
353
324
  default.call(
354
- arguments: [
355
- Argument.new(arguments.first),
356
- Argument.new(self),
357
- Argument.new(index)
358
- ],
325
+ arguments: List.new([first, Integer.new(index), self]),
359
326
  **globals
360
327
  )
361
328
  else
362
329
  raise(
363
- Code::Error::KeyNotFound,
364
- "#{arguments.first.inspect} not found on #{inspect}"
330
+ Error::KeyNotFound,
331
+ "#{first.inspect} not found on #{inspect}"
365
332
  )
366
333
  end
367
334
  end
368
335
  else
369
- self.class.new(
336
+ Dictionary.new(
370
337
  arguments
371
338
  .map
372
339
  .with_index do |argument, index|
373
340
  if default
374
- [
375
- argument,
376
- code_fetch(
377
- argument,
378
- default,
379
- index: Integer.new(index),
380
- **globals
381
- )
382
- ]
341
+ [argument, code_fetch(argument, default, index:, **globals)]
383
342
  else
384
- [
385
- argument,
386
- code_fetch(argument, index: Integer.new(index), **globals)
387
- ]
343
+ [argument, code_fetch(argument, index:, **globals)]
388
344
  end
389
345
  end
390
346
  .to_h
@@ -401,7 +357,7 @@ class Code
401
357
  end
402
358
 
403
359
  def code_flatten(level = nil)
404
- level ||= Integer.new(-1)
360
+ level = Integer.new(-1) if level.nil? || level.falsy?
405
361
  code_to_list.code_flatten(level)
406
362
  end
407
363
 
@@ -439,12 +395,7 @@ class Code
439
395
  else
440
396
  raw.keep_if.with_index do |(key, value), index|
441
397
  argument.call(
442
- arguments: [
443
- Argument.new(key),
444
- Argument.new(value),
445
- Argument.new(self),
446
- Argument.new(Integer.new(index))
447
- ],
398
+ arguments: List.new([key, value, Integer.new(index), self]),
448
399
  **globals
449
400
  ).truthy?
450
401
  end
@@ -459,12 +410,7 @@ class Code
459
410
  else
460
411
  raw.keep_if.with_index do |(key, value), index|
461
412
  argument.call(
462
- arguments: [
463
- Argument.new(key),
464
- Argument.new(value),
465
- Argument.new(self),
466
- Argument.new(Integer.new(index))
467
- ],
413
+ arguments: List.new([key, value, Integer.new(index), self]),
468
414
  **globals
469
415
  ).falsy?
470
416
  rescue Error::Next => e
@@ -478,10 +424,7 @@ class Code
478
424
  def code_key(value, function = nil, **globals)
479
425
  if function
480
426
  raw.key(value) ||
481
- function.call(
482
- arguments: [Argument.new(value), Argument.new(self)],
483
- **globals
484
- )
427
+ function.call(arguments: List.new([value, self]), **globals)
485
428
  else
486
429
  raw.key(value) || Nothing.new
487
430
  end
@@ -510,13 +453,10 @@ class Code
510
453
  if conflict
511
454
  conflict
512
455
  .call(
513
- arguments: [
514
- Argument.new(key),
515
- Argument.new(old_value),
516
- Argument.new(new_value),
517
- Argument.new(self),
518
- Argument.new(Integer.new(index))
519
- ],
456
+ arguments:
457
+ List.new(
458
+ [key, old_value, new_value, Integer.new(index), self]
459
+ ),
520
460
  **globals
521
461
  )
522
462
  .tap { index += 1 }
@@ -544,12 +484,7 @@ class Code
544
484
  else
545
485
  raw.select!.with_index do |(key, value), index|
546
486
  argument.call(
547
- arguments: [
548
- Argument.new(key),
549
- Argument.new(value),
550
- Argument.new(self),
551
- Argument.new(Integer.new(index))
552
- ],
487
+ arguments: List.new([key, value, Integer.new(index), self]),
553
488
  **globals
554
489
  ).truthy?
555
490
  rescue Error::Next => e
@@ -567,12 +502,7 @@ class Code
567
502
  self.class.new(
568
503
  raw.select.with_index do |(key, value), index|
569
504
  argument.call(
570
- arguments: [
571
- Argument.new(key),
572
- Argument.new(value),
573
- Argument.new(self),
574
- Argument.new(Integer.new(index))
575
- ],
505
+ arguments: List.new([key, value, Integer.new(index), self]),
576
506
  **globals
577
507
  ).truthy?
578
508
  rescue Error::Next => e
@@ -623,15 +553,15 @@ class Code
623
553
  List.new(raw.to_a.map { |key_value| List.new(key_value) })
624
554
  end
625
555
 
556
+ def to_h
557
+ raw
558
+ end
559
+
626
560
  def code_transform_values(function, **globals)
627
561
  self.class.new(
628
562
  raw.transform_values.with_index do |value, index|
629
563
  function.call(
630
- arguments: [
631
- Argument.new(value),
632
- Argument.new(self),
633
- Argument.new(Integer.new(index))
634
- ],
564
+ arguments: List.new([value, Integer.new(index), self]),
635
565
  **globals
636
566
  )
637
567
  rescue Error::Next => e
@@ -14,13 +14,13 @@ class Code
14
14
 
15
15
  def call(**args)
16
16
  operator = args.fetch(:operator, nil)
17
- arguments = args.fetch(:arguments, [])
17
+ arguments = args.fetch(:arguments, List.new)
18
18
  globals = multi_fetch(args, *GLOBALS)
19
19
 
20
20
  case operator.to_s
21
21
  when "", "call"
22
22
  sig(args) { signature_for_call }
23
- code_call(*arguments, **globals)
23
+ code_call(*arguments.raw, **globals)
24
24
  else
25
25
  super
26
26
  end
@@ -30,48 +30,38 @@ class Code
30
30
  context = Context.new({}, globals[:context])
31
31
 
32
32
  parameters.raw.each.with_index do |parameter, index|
33
- if parameter.regular_splat?
34
- context.code_set(
35
- parameter.code_name,
36
- List.new(arguments.select(&:regular?).map(&:value))
37
- )
38
- elsif parameter.keyword_splat?
39
- context.code_set(
40
- parameter.code_name,
41
- Dictionary.new(
42
- arguments.select(&:keyword?).map(&:name_value).to_h
43
- )
44
- )
45
- elsif parameter.keyword?
46
- argument =
33
+ argument =
34
+ if parameter.keyword?
47
35
  arguments
48
- .detect { |argument| argument.name == parameter.code_name }
49
- &.value
50
- argument = parameter.evaluate(**globals) if argument.nil?
51
- context.code_set(parameter.code_name, argument)
52
- elsif parameter.regular?
53
- argument = arguments[index]&.value
54
- argument = parameter.evaluate(**globals) if argument.nil?
55
- context.code_set(parameter.code_name, argument)
56
- end
36
+ .detect do |dictionary|
37
+ dictionary.code_has_value?(parameter.code_name)
38
+ end
39
+ &.code_get(parameter.code_name)
40
+ else
41
+ arguments[index]
42
+ end
43
+ argument = parameter.evaluate(**globals) if argument.nil?
44
+ context.code_set(parameter.code_name, argument)
57
45
  end
58
46
 
59
47
  body.evaluate(**globals, context:)
60
48
  end
61
49
 
62
50
  def signature_for_call
63
- parameters.raw.inject([]) do |signature, parameter|
64
- if parameter.keyword?
65
- if signature.last.is_a?(::Hash)
66
- signature.last.code_set(parameter.code_name, Object)
67
- signature
51
+ parameters
52
+ .raw
53
+ .inject([]) do |signature, parameter|
54
+ if parameter.keyword?
55
+ if signature.last.is_a?(::Hash)
56
+ signature.last.code_set(parameter.code_name, Object)
57
+ signature
58
+ else
59
+ signature + [{ parameter.code_name => Object }]
60
+ end
68
61
  else
69
- signature + [{ parameter.code_name => Object }]
62
+ signature + [Object]
70
63
  end
71
- else
72
- signature + [Object]
73
- end
74
- end + [Object.repeat]
64
+ end + [Object.repeat]
75
65
  end
76
66
  end
77
67
  end