code-ruby 0.10.4 → 0.12.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +2 -2
  3. data/bin/code +6 -0
  4. data/bin/console +5 -0
  5. data/lib/code/node/base_10.rb +10 -10
  6. data/lib/code/node/base_16.rb +3 -2
  7. data/lib/code/node/base_2.rb +3 -2
  8. data/lib/code/node/base_8.rb +3 -2
  9. data/lib/code/node/boolean.rb +5 -4
  10. data/lib/code/node/call.rb +13 -19
  11. data/lib/code/node/call_argument.rb +8 -4
  12. data/lib/code/node/code.rb +4 -2
  13. data/lib/code/node/decimal.rb +8 -10
  14. data/lib/code/node/dictionary.rb +15 -8
  15. data/lib/code/node/function.rb +5 -9
  16. data/lib/code/node/function_parameter.rb +8 -4
  17. data/lib/code/node/if.rb +14 -12
  18. data/lib/code/node/left_operation.rb +10 -10
  19. data/lib/code/node/list.rb +4 -3
  20. data/lib/code/node/negation.rb +8 -4
  21. data/lib/code/node/not.rb +8 -4
  22. data/lib/code/node/nothing.rb +4 -3
  23. data/lib/code/node/number.rb +3 -3
  24. data/lib/code/node/right_operation.rb +19 -16
  25. data/lib/code/node/splat.rb +8 -4
  26. data/lib/code/node/square_bracket.rb +8 -11
  27. data/lib/code/node/statement.rb +27 -27
  28. data/lib/code/node/string.rb +14 -11
  29. data/lib/code/node/ternary.rb +8 -8
  30. data/lib/code/node/unary_minus.rb +8 -4
  31. data/lib/code/node/while.rb +15 -13
  32. data/lib/code/node.rb +1 -7
  33. data/lib/code/object/argument.rb +4 -3
  34. data/lib/code/object/boolean.rb +5 -4
  35. data/lib/code/object/class.rb +4 -3
  36. data/lib/code/object/code.rb +33 -0
  37. data/lib/code/object/context.rb +7 -5
  38. data/lib/code/object/date.rb +31 -6
  39. data/lib/code/object/decimal.rb +36 -31
  40. data/lib/code/object/dictionary.rb +4 -4
  41. data/lib/code/object/duration.rb +8 -5
  42. data/lib/code/object/function.rb +42 -28
  43. data/lib/code/object/global.rb +58 -38
  44. data/lib/code/object/integer.rb +23 -26
  45. data/lib/code/object/list.rb +5 -5
  46. data/lib/code/object/nothing.rb +2 -4
  47. data/lib/code/object/parameter.rb +43 -0
  48. data/lib/code/object/range.rb +13 -11
  49. data/lib/code/object/string.rb +7 -7
  50. data/lib/code/object/time.rb +15 -8
  51. data/lib/code/object.rb +104 -11
  52. data/lib/code/parser/code.rb +1 -1
  53. data/lib/code/parser/left_operation.rb +2 -2
  54. data/lib/code/parser/list.rb +2 -2
  55. data/lib/code/parser/right_operation.rb +2 -2
  56. data/lib/code/parser/whitespace.rb +2 -2
  57. data/lib/code/parser.rb +1 -1
  58. data/lib/code/type/sig.rb +2 -2
  59. data/lib/code/type.rb +12 -4
  60. data/lib/code/version.rb +1 -1
  61. data/lib/code-ruby.rb +7 -0
  62. data/lib/code.rb +8 -5
  63. data/spec/code/object/dictionary_spec.rb +0 -2
  64. data/spec/code_spec.rb +122 -16
  65. metadata +5 -3
  66. data/lib/code/object/number.rb +0 -11
@@ -3,11 +3,11 @@
3
3
  class Code
4
4
  class Object
5
5
  class String < Object
6
- attr_reader :raw
7
-
8
- def initialize(string)
9
- string = string.raw if string.is_a?(String)
10
- @raw = string.to_s
6
+ def initialize(*args, **_kargs, &_block)
7
+ raw = args.first || Nothing.new
8
+ raw = raw.raw if raw.is_a?(Object)
9
+ @raw = raw.to_s
10
+ super
11
11
  end
12
12
 
13
13
  def self.name
@@ -25,7 +25,7 @@ class Code
25
25
  sig(args)
26
26
  code_to_function(**globals)
27
27
  when "*"
28
- sig(args) { Number }
28
+ sig(args) { Integer | Decimal }
29
29
  code_multiplication(value)
30
30
  when "+"
31
31
  sig(args) { Object }
@@ -65,7 +65,7 @@ class Code
65
65
  end
66
66
 
67
67
  def code_to_function(**globals)
68
- Code::Node::Code.new(
68
+ Node::Code.new(
69
69
  [
70
70
  {
71
71
  function: {
@@ -5,13 +5,12 @@ class Code
5
5
  class Time < Object
6
6
  DEFAULT_ZONE = "Etc/UTC"
7
7
 
8
- attr_reader :raw
9
-
10
- def initialize(time)
8
+ def initialize(*args, **_kargs, &_block)
11
9
  ::Time.zone ||= DEFAULT_ZONE
12
- time = time.raw if time.is_a?(Time)
13
- time = time.to_s if time.is_a?(::Time)
14
- @raw = ::Time.zone.parse(time)
10
+ raw = args.first.presence || ::Time.zone.now
11
+ raw = raw.raw if raw.is_an?(Object)
12
+ @raw = ::Time.zone.parse(raw.to_s)
13
+ super
15
14
  end
16
15
 
17
16
  def self.name
@@ -28,6 +27,9 @@ class Code
28
27
  when "tomorrow"
29
28
  sig(args)
30
29
  code_tomorrow
30
+ when "yesterday"
31
+ sig(args)
32
+ code_yesterday
31
33
  else
32
34
  super
33
35
  end
@@ -35,12 +37,17 @@ class Code
35
37
 
36
38
  def self.code_tomorrow
37
39
  ::Time.zone ||= DEFAULT_ZONE
38
- new(::Time.zone.tomorrow.beginning_of_day)
40
+ new(::Time.zone.tomorrow)
41
+ end
42
+
43
+ def self.code_yesterday
44
+ ::Time.zone ||= DEFAULT_ZONE
45
+ new(::Time.zone.yesterday)
39
46
  end
40
47
 
41
48
  def self.code_now
42
49
  ::Time.zone ||= DEFAULT_ZONE
43
- new(::Time.zone.now.beginning_of_day)
50
+ new(::Time.zone.now)
44
51
  end
45
52
 
46
53
  def call(**args)
data/lib/code/object.rb CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  class Code
4
4
  class Object
5
+ attr_reader :raw
6
+
7
+ def initialize(*_args, **_kargs, &_block)
8
+ @raw = nil unless defined?(@raw)
9
+ end
10
+
5
11
  def self.maybe
6
12
  Type::Maybe.new(self)
7
13
  end
@@ -29,6 +35,9 @@ class Code
29
35
  value = arguments.first&.value
30
36
 
31
37
  case operator.to_s
38
+ when "new"
39
+ sig(args) { Object.repeat }
40
+ code_new(*arguments.map(&:value))
32
41
  when "!", "not"
33
42
  sig(args)
34
43
  code_exclamation_point
@@ -65,6 +74,42 @@ class Code
65
74
  when "||", "or"
66
75
  sig(args) { Object }
67
76
  code_or_operator(value)
77
+ when "to_boolean"
78
+ sig(args)
79
+ Boolean.new(self)
80
+ when "to_class"
81
+ sig(args)
82
+ Class.new(self)
83
+ when "to_date"
84
+ sig(args)
85
+ Date.new(self)
86
+ when "to_decimal"
87
+ sig(args)
88
+ Decimal.new(self)
89
+ when "to_dictionary"
90
+ sig(args)
91
+ Dictionary.new(self)
92
+ when "to_duration"
93
+ sig(args)
94
+ Duration.new(self)
95
+ when "to_integer"
96
+ sig(args)
97
+ Integer.new(self)
98
+ when "to_list"
99
+ sig(args)
100
+ List.new(self)
101
+ when "to_nothing"
102
+ sig(args)
103
+ Nothing.new(self)
104
+ when "to_range"
105
+ sig(args)
106
+ Range.new(self)
107
+ when "to_string"
108
+ sig(args)
109
+ String.new(self)
110
+ when "to_time"
111
+ sig(args)
112
+ Time.new(self)
68
113
  when /=$/
69
114
  sig(args) { Object }
70
115
 
@@ -86,12 +131,16 @@ class Code
86
131
  context.code_fetch(self)
87
132
  else
88
133
  raise(
89
- Code::Error::Undefined,
134
+ Error::Undefined,
90
135
  "#{operator} not defined on #{inspect}:Class"
91
136
  )
92
137
  end
93
138
  end
94
139
 
140
+ def self.code_new(*arguments)
141
+ new(*arguments)
142
+ end
143
+
95
144
  def self.code_and_operator(other)
96
145
  truthy? ? other : self
97
146
  end
@@ -220,6 +269,42 @@ class Code
220
269
  when "||", "or"
221
270
  sig(args) { Object }
222
271
  code_or_operator(value)
272
+ when "to_boolean"
273
+ sig(args)
274
+ Boolean.new(self)
275
+ when "to_class"
276
+ sig(args)
277
+ Class.new(self)
278
+ when "to_date"
279
+ sig(args)
280
+ Date.new(self)
281
+ when "to_decimal"
282
+ sig(args)
283
+ Decimal.new(self)
284
+ when "to_duration"
285
+ sig(args)
286
+ Duration.new(self)
287
+ when "to_dictionary"
288
+ sig(args)
289
+ Dictionary.new(self)
290
+ when "to_integer"
291
+ sig(args)
292
+ Integer.new(self)
293
+ when "to_list"
294
+ sig(args)
295
+ List.new(self)
296
+ when "to_nothing"
297
+ sig(args)
298
+ Nothing.new(self)
299
+ when "to_range"
300
+ sig(args)
301
+ Range.new(self)
302
+ when "to_string"
303
+ sig(args)
304
+ String.new(self)
305
+ when "to_time"
306
+ sig(args)
307
+ Time.new(self)
223
308
  when /=$/
224
309
  sig(args) { Object }
225
310
 
@@ -241,8 +326,8 @@ class Code
241
326
  context.code_fetch(self)
242
327
  else
243
328
  raise(
244
- Code::Error::Undefined,
245
- "#{operator} not defined on #{inspect}:#{self.class.name}"
329
+ Error::Undefined,
330
+ "#{operator.inspect} not defined on #{inspect}:#{self.class.name}"
246
331
  )
247
332
  end
248
333
  end
@@ -264,11 +349,23 @@ class Code
264
349
  end
265
350
 
266
351
  def code_exclusive_range(value)
267
- Range.new(self, value, exclude_end: true)
352
+ Range.new(
353
+ self,
354
+ value,
355
+ Dictionary.new({
356
+ String.new(:exclude_end) => Boolean.new(true)
357
+ })
358
+ )
268
359
  end
269
360
 
270
361
  def code_inclusive_range(value)
271
- Range.new(self, value, exclude_end: false)
362
+ Range.new(
363
+ self,
364
+ value,
365
+ Dictionary.new({
366
+ String.new(:exclude_end) => Boolean.new(false)
367
+ })
368
+ )
272
369
  end
273
370
 
274
371
  def code_or_operator(other)
@@ -292,10 +389,6 @@ class Code
292
389
  end
293
390
 
294
391
  def hash
295
- unless respond_to?(:raw)
296
- raise NotImplementedError, "#{self.class.name}#hash"
297
- end
298
-
299
392
  [self.class, raw].hash
300
393
  end
301
394
 
@@ -309,7 +402,7 @@ class Code
309
402
  end
310
403
 
311
404
  def to_s
312
- raise NotImplementedError, "#{self.class.name}#to_s"
405
+ raw.to_s
313
406
  end
314
407
 
315
408
  def inspect
@@ -325,7 +418,7 @@ class Code
325
418
  end
326
419
 
327
420
  def as_json(...)
328
- raise NotImplementedError, "#{self.class}#as_json"
421
+ raw.as_json
329
422
  end
330
423
  end
331
424
  end
@@ -20,7 +20,7 @@ class Code
20
20
  end
21
21
 
22
22
  def root
23
- present | whitespace?.aka(:whitespace).then { [] }
23
+ present | whitespace?
24
24
  end
25
25
  end
26
26
  end
@@ -4,7 +4,7 @@ class Code
4
4
  class Parser
5
5
  class LeftOperation < Language
6
6
  def statement
7
- raise NotImplementedError
7
+ Statement
8
8
  end
9
9
 
10
10
  def whitespace
@@ -16,7 +16,7 @@ class Code
16
16
  end
17
17
 
18
18
  def operator
19
- raise NotImplementedError
19
+ str("")
20
20
  end
21
21
 
22
22
  def right_statement
@@ -32,8 +32,8 @@ class Code
32
32
  end
33
33
 
34
34
  def element
35
- (whitespace? << code_present << (whitespace? << comma).maybe) |
36
- (whitespace? << code << whitespace? << comma)
35
+ (whitespace? << code_present << (whitespace? << comma.ignore).maybe) |
36
+ (whitespace? << code << whitespace? << comma.ignore)
37
37
  end
38
38
 
39
39
  def root
@@ -4,7 +4,7 @@ class Code
4
4
  class Parser
5
5
  class RightOperation < Language
6
6
  def statement
7
- raise NotImplementedError
7
+ Statement
8
8
  end
9
9
 
10
10
  def whitespace
@@ -16,7 +16,7 @@ class Code
16
16
  end
17
17
 
18
18
  def operator
19
- raise NotImplementedError
19
+ str("")
20
20
  end
21
21
 
22
22
  def right_statement
@@ -37,14 +37,14 @@ class Code
37
37
  end
38
38
 
39
39
  def without_newline
40
- (space | multi_line_comment).repeat(1)
40
+ (space | multi_line_comment).repeat(1).ignore
41
41
  end
42
42
 
43
43
  def root
44
44
  (
45
45
  space | newline | hash_comment | double_slash_comment |
46
46
  multi_line_comment
47
- ).repeat(1) | any.absent
47
+ ).repeat(1).ignore | any.absent
48
48
  end
49
49
  end
50
50
  end
data/lib/code/parser.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  class Code
4
4
  class Parser
5
- class Error < ::Code::Error
5
+ class Error < Error
6
6
  end
7
7
 
8
8
  def initialize(input)
data/lib/code/type/sig.rb CHANGED
@@ -40,11 +40,11 @@ class Code
40
40
  end
41
41
 
42
42
  def actual_arguments
43
- args[:arguments].map(&:value)
43
+ args.fetch(:arguments, []).map(&:value)
44
44
  end
45
45
 
46
46
  def operator
47
- args[:operator] || "call"
47
+ args.fetch(:operator, nil) || "call"
48
48
  end
49
49
 
50
50
  def function
data/lib/code/type.rb CHANGED
@@ -2,12 +2,20 @@
2
2
 
3
3
  class Code
4
4
  class Type
5
- def name
6
- raise NotImplementedError, "#{self.class}#name"
5
+ def maybe
6
+ Maybe.new(self)
7
7
  end
8
8
 
9
- def valid?(argument)
10
- raise NotImplementedError, "#{self.class}#valid?"
9
+ def repeat(minimum = 0, maximum = nil)
10
+ Repeat.new(self, minimum:, maximum:)
11
+ end
12
+
13
+ def |(other)
14
+ Or.new(self, other)
15
+ end
16
+
17
+ def valid?(_argument)
18
+ false
11
19
  end
12
20
 
13
21
  def valid_for?(expected:, actual:)
data/lib/code/version.rb CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  require_relative "../code"
4
4
 
5
- Code::Version = Gem::Version.new("0.10.4")
5
+ Code::Version = Gem::Version.new("0.12.0")
data/lib/code-ruby.rb CHANGED
@@ -4,7 +4,10 @@ require "active_support"
4
4
  require "active_support/core_ext/date/conversions"
5
5
  require "active_support/core_ext/numeric/time"
6
6
  require "active_support/core_ext/object/json"
7
+ require "active_support/core_ext/object/blank"
8
+ require "active_support/core_ext/array/access"
7
9
  require "bigdecimal"
10
+ require "bigdecimal/util"
8
11
  require "json"
9
12
  require "language-ruby"
10
13
  require "stringio"
@@ -14,3 +17,7 @@ require "zeitwerk"
14
17
  loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
15
18
  loader.ignore("#{__dir__}/code-ruby.rb")
16
19
  loader.setup
20
+
21
+ class Object
22
+ alias is_an? is_a?
23
+ end
data/lib/code.rb CHANGED
@@ -17,6 +17,12 @@ class Code
17
17
  @context = Object::Context.new
18
18
  end
19
19
 
20
+ def self.parse(input, timeout: DEFAULT_TIMEOUT)
21
+ Timeout.timeout(timeout) do
22
+ Parser.parse(input).to_raw
23
+ end
24
+ end
25
+
20
26
  def self.evaluate(
21
27
  input,
22
28
  output: StringIO.new,
@@ -28,11 +34,8 @@ class Code
28
34
 
29
35
  def evaluate
30
36
  Timeout.timeout(timeout) do
31
- Node::Code.new(::Code::Parser.parse(input).to_raw).evaluate(
32
- context:,
33
- output:,
34
- error:
35
- )
37
+ parsed = Code.parse(input)
38
+ Node::Code.new(parsed).evaluate(context:, output:, error:)
36
39
  end
37
40
  end
38
41
 
@@ -76,10 +76,8 @@ RSpec.describe Code::Object::Dictionary do
76
76
  ["{ a: nothing }.compact", "{}"],
77
77
  ["{ age: 31 }.delete_unless { |key| key == :age }", "{ age: 31 }"],
78
78
  ["{ age: 31 }.delete_unless(Integer)", "{ age: 31 }"],
79
- ["{ age: 31 }.delete_unless(Number)", "{ age: 31 }"],
80
79
  ["{ age: 31 }.keep_unless { |key| key == :age }", "{}"],
81
80
  ["{ age: 31 }.keep_unless(Integer)", "{}"],
82
- ["{ age: 31 }.keep_unless(Number)", "{}"],
83
81
  ["{ first_name: :Dorian } < dictionary", "true"],
84
82
  ["{ first_name: :Dorian }.any? { |_, value| value == :Dorian }", "true"],
85
83
  ["{ first_name: :Dorian }.delete_if { |_, value| value == :Dorian }", "{}"],
data/spec/code_spec.rb CHANGED
@@ -31,13 +31,65 @@ RSpec.describe Code do
31
31
  %w[0x10 16],
32
32
  %w[1.0e1 10.0],
33
33
  %w[1.1 1.1],
34
+ %w[1.day.ago.after? false],
35
+ %w[1.day.ago.after?(1.day.from_now) false],
36
+ %w[1.day.ago.before? true],
37
+ %w[1.day.ago.before?(1.day.from_now) true],
38
+ %w[1.day.from_now.after? true],
39
+ %w[1.day.from_now.after?(1.day.ago) true],
40
+ %w[1.day.from_now.before? false],
41
+ %w[1.day.from_now.before?(1.day.ago) false],
34
42
  %w[10e1.0 100.0],
35
43
  %w[1e1 10],
44
+ %w[2.days.ago.future? false],
45
+ %w[2.days.ago.past? true],
46
+ %w[2.days.from_now.future? true],
47
+ %w[2.days.from_now.past? false],
36
48
  %w[9975×14÷8 17456.25],
37
49
  %w[:Hello.include?(:H) true],
38
50
  %w[:admin? :admin?],
39
51
  %w[:hello :hello],
40
52
  %w[:update!.to_string :update!],
53
+ %w[Boolean(1) true],
54
+ %w[Boolean(2.days.ago) true],
55
+ %w[Boolean(2.days.ago) true],
56
+ %w[Boolean(false) false],
57
+ %w[Boolean(nothing) false],
58
+ %w[Boolean(true) true],
59
+ %w[Boolean({}) true],
60
+ %w[Boolean.new false],
61
+ %w[Boolean.new(1) true],
62
+ %w[Boolean.new(2.days.ago) true],
63
+ %w[Boolean.new(2.days.ago) true],
64
+ %w[Boolean.new(false) false],
65
+ %w[Boolean.new(nothing) false],
66
+ %w[Boolean.new(true) true],
67
+ %w[Boolean.new({}) true],
68
+ %w[Class(2.days.ago) Time],
69
+ %w[Class(Boolean) Boolean],
70
+ %w[Class(Time) Time],
71
+ %w[Class(nothing) Nothing],
72
+ %w[Class(true) Boolean],
73
+ %w[Class.new Nothing],
74
+ %w[Class.new Nothing],
75
+ %w[Class.new(2.days.ago) Time],
76
+ %w[Class.new(Boolean) Boolean],
77
+ %w[Class.new(Date) Date],
78
+ %w[Class.new(Time) Time],
79
+ %w[Class.new(nothing) Nothing],
80
+ %w[Class.new(true) Boolean],
81
+ %w[Date Date],
82
+ %w[Date("0001-01-01").to_string :0001-01-01],
83
+ %w[Date("2024-03-02").to_string :2024-03-02],
84
+ %w[Decimal(1) 1.0],
85
+ %w[Decimal(1) 1],
86
+ %w[Decimal(:1) 1.0],
87
+ %w[Decimal(:1) 1],
88
+ %w[Decimal.new 0],
89
+ %w[Decimal.new(1) 1.0],
90
+ %w[Decimal.new(1) 1],
91
+ %w[Decimal.new(:1) 1.0],
92
+ %w[Decimal.new(:1) 1],
41
93
  %w[false false],
42
94
  %w[true true],
43
95
  %w[{} {}],
@@ -57,14 +109,6 @@ RSpec.describe Code do
57
109
  ["1 >> 1", "0"],
58
110
  ["1 ^ 2", "3"],
59
111
  ["1 | 2", "3"],
60
- %w[1.day.ago.after?(1.day.from_now) false],
61
- %w[1.day.ago.before?(1.day.from_now) true],
62
- %w[1.day.from_now.after?(1.day.ago) true],
63
- %w[1.day.from_now.before?(1.day.ago) false],
64
- %w[1.day.ago.after? false],
65
- %w[1.day.ago.before? true],
66
- %w[1.day.from_now.after? true],
67
- %w[1.day.from_now.before? false],
68
112
  ["2 * 3 + 2", "8"],
69
113
  ["2 * 3", "6"],
70
114
  ["2 ** 3 ** 2", "512"],
@@ -73,6 +117,20 @@ RSpec.describe Code do
73
117
  ["2 / 4", "0.5"],
74
118
  ["3.times {}", "3"],
75
119
  ["4 % 3", "1"],
120
+ ["Boolean([])", "true"],
121
+ ["Boolean(true, false)", "true"],
122
+ ["Boolean.new([])", "true"],
123
+ ["Boolean.new(false, true)", "false"],
124
+ ["Boolean.new(true, false)", "true"],
125
+ ["Class(true, 1)", "Boolean"],
126
+ ["Class.new(Boolean, Time)", "Boolean"],
127
+ ["Class.new(Time, Boolean)", "Time"],
128
+ ["Date(2024, 3, 2).to_string", ":2024-03-02"],
129
+ ["Date(2024,3, 2).to_string", ":2024-03-02"],
130
+ ["Decimal(1, :2)", "100"],
131
+ ["Decimal(:1, 2)", "100.0"],
132
+ ["Decimal.new(1, :2)", "100"],
133
+ ["Decimal.new(:1, 2)", "100.0"],
76
134
  ["[,,].include?(4)", "false"],
77
135
  ["[,].include?(4)", "false"],
78
136
  ["[1, 2, 3, \n ].include?(4)", "false"],
@@ -80,6 +138,8 @@ RSpec.describe Code do
80
138
  ["[1, 2, 3]", "[1, 2, 3]"],
81
139
  ["[1, 2, 3].include?(2)", "true"],
82
140
  ["[1, 2, 3].include?(4)", "false"],
141
+ ["[1, 2, 3].map { |i| next if i == 2 i ** 2}", "[1, nothing, 9]"],
142
+ ["[1, 2, 3].map { |i| next(0) if i.even? i ** 2}", "[1, 0, 9]"],
83
143
  ["[1, 2, 3].select { |n| n.even? }", "[2]"],
84
144
  ["[1, 2, 3].select { |n| n.even? }.select { |n| n.odd? }", "[]"],
85
145
  ["[1, 2].map(&:to_string)", "[:1, :2]"],
@@ -89,6 +149,8 @@ RSpec.describe Code do
89
149
  ["[[true]]", "[[true]]"],
90
150
  ["[]", "[]"],
91
151
  ["\r\n", "nothing"],
152
+ ["a = 0 [1, 2, 3].each { |i| next if i == 2 a += i } a", "4"],
153
+ ["a = 0 loop a += 1 break end a", "1"],
92
154
  ["a = 0\nuntil a > 10 a += 1 end a", "11"],
93
155
  ["a = 0\nwhile a < 10 a += 1 end a", "10"],
94
156
  ["a = 1 3.times { a += 1 } a", "4"],
@@ -142,14 +204,7 @@ RSpec.describe Code do
142
204
  ['user = {} user.name = "Dorian" user.name', ":Dorian"],
143
205
  ['user = {} user[:name] = "Dorian" user[:name]', ":Dorian"],
144
206
  ['{ "first_name": "Dorian" }', '{"first_name" => "Dorian"}'],
145
- ["a = 0 loop a += 1 break end a", "1"],
146
- ["a = 0 [1, 2, 3].each { |i| next if i == 2 a += i } a", "4"],
147
- ["[1, 2, 3].map { |i| next if i == 2 i ** 2}", "[1, nothing, 9]"],
148
- ["[1, 2, 3].map { |i| next(0) if i.even? i ** 2}", "[1, 0, 9]"],
149
- %w[2.days.ago.past? true],
150
- %w[2.days.from_now.past? false],
151
- %w[2.days.ago.future? false],
152
- %w[2.days.from_now.future? true]
207
+ ["", ""]
153
208
  ].each do |input, expected|
154
209
  it "#{input} == #{expected}" do
155
210
  expect(Code.evaluate(input)).to eq(Code.evaluate(expected))
@@ -168,8 +223,59 @@ RSpec.describe Code do
168
223
  2.days.from_now
169
224
  2.hours.ago
170
225
  2.hours.from_now
226
+ Boolean.new
227
+ Boolean.new(true)
228
+ Boolean.new(false)
229
+ Class.new
230
+ Class.new(Boolean)
231
+ Class.new(Class)
232
+ Context.new
233
+ Context.new(a:1)
234
+ Date.new
235
+ Date.new("2024-03-05")
236
+ Date.today
237
+ Date.yesterday
171
238
  Date.tomorrow
239
+ Decimal.new
240
+ Decimal.new(0)
241
+ Decimal.new(1.2)
242
+ Dictionary.new
243
+ Dictionary.new(a:1)
244
+ Duration.new
245
+ Duration.new(1.day)
246
+ Duration.new("P1D")
247
+ Function.new
248
+ Integer.new
249
+ Integer.new(0)
250
+ Integer.new(1)
251
+ Integer.new(1.2)
252
+ List.new
253
+ List.new([])
254
+ List.new([1,2])
255
+ Nothing.new
256
+ Nothing.new(1)
257
+ Object.new
258
+ Object.new(1)
259
+ Range.new
260
+ Range.new(1,2)
261
+ Range.new(-1)
262
+ Range.new(1,2,exclude_end:false)
263
+ Range.new(1,2,exclude_end:true)
264
+ String.new
265
+ String.new(:hello)
266
+ Time.new
267
+ Time.new("2024-03-05.06:10:59.UTC")
268
+ Time.now
269
+ Time.tomorrow
270
+ Time.yesterday
172
271
  Time.tomorrow
272
+ Code.new
273
+ Parameter.new
274
+ Argument.new
275
+ Argument.new(1)
276
+ Argument.new(1,name:"index")
277
+ IdentifierList.new
278
+ IdentifierList.new([])
173
279
  ].each { |input| it(input) { Code.evaluate(input) } }
174
280
 
175
281
  [["puts(true)", "true\n"], %w[print(false) false]].each do |input, expected|