code-ruby 0.10.4 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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|