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.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/bin/code +6 -0
- data/bin/console +5 -0
- data/lib/code/node/base_10.rb +10 -10
- data/lib/code/node/base_16.rb +3 -2
- data/lib/code/node/base_2.rb +3 -2
- data/lib/code/node/base_8.rb +3 -2
- data/lib/code/node/boolean.rb +5 -4
- data/lib/code/node/call.rb +13 -19
- data/lib/code/node/call_argument.rb +8 -4
- data/lib/code/node/code.rb +4 -2
- data/lib/code/node/decimal.rb +8 -10
- data/lib/code/node/dictionary.rb +15 -8
- data/lib/code/node/function.rb +5 -9
- data/lib/code/node/function_parameter.rb +8 -4
- data/lib/code/node/if.rb +14 -12
- data/lib/code/node/left_operation.rb +10 -10
- data/lib/code/node/list.rb +4 -3
- data/lib/code/node/negation.rb +8 -4
- data/lib/code/node/not.rb +8 -4
- data/lib/code/node/nothing.rb +4 -3
- data/lib/code/node/number.rb +3 -3
- data/lib/code/node/right_operation.rb +19 -16
- data/lib/code/node/splat.rb +8 -4
- data/lib/code/node/square_bracket.rb +8 -11
- data/lib/code/node/statement.rb +27 -27
- data/lib/code/node/string.rb +14 -11
- data/lib/code/node/ternary.rb +8 -8
- data/lib/code/node/unary_minus.rb +8 -4
- data/lib/code/node/while.rb +15 -13
- data/lib/code/node.rb +1 -7
- data/lib/code/object/argument.rb +4 -3
- data/lib/code/object/boolean.rb +5 -4
- data/lib/code/object/class.rb +4 -3
- data/lib/code/object/code.rb +33 -0
- data/lib/code/object/context.rb +7 -5
- data/lib/code/object/date.rb +31 -6
- data/lib/code/object/decimal.rb +36 -31
- data/lib/code/object/dictionary.rb +4 -4
- data/lib/code/object/duration.rb +8 -5
- data/lib/code/object/function.rb +42 -28
- data/lib/code/object/global.rb +58 -38
- data/lib/code/object/integer.rb +23 -26
- data/lib/code/object/list.rb +5 -5
- data/lib/code/object/nothing.rb +2 -4
- data/lib/code/object/parameter.rb +43 -0
- data/lib/code/object/range.rb +13 -11
- data/lib/code/object/string.rb +7 -7
- data/lib/code/object/time.rb +15 -8
- data/lib/code/object.rb +104 -11
- data/lib/code/parser/code.rb +1 -1
- data/lib/code/parser/left_operation.rb +2 -2
- data/lib/code/parser/list.rb +2 -2
- data/lib/code/parser/right_operation.rb +2 -2
- data/lib/code/parser/whitespace.rb +2 -2
- data/lib/code/parser.rb +1 -1
- data/lib/code/type/sig.rb +2 -2
- data/lib/code/type.rb +12 -4
- data/lib/code/version.rb +1 -1
- data/lib/code-ruby.rb +7 -0
- data/lib/code.rb +8 -5
- data/spec/code/object/dictionary_spec.rb +0 -2
- data/spec/code_spec.rb +122 -16
- metadata +5 -3
- data/lib/code/object/number.rb +0 -11
data/lib/code/object/string.rb
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
class Code
|
4
4
|
class Object
|
5
5
|
class String < Object
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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) {
|
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
|
-
|
68
|
+
Node::Code.new(
|
69
69
|
[
|
70
70
|
{
|
71
71
|
function: {
|
data/lib/code/object/time.rb
CHANGED
@@ -5,13 +5,12 @@ class Code
|
|
5
5
|
class Time < Object
|
6
6
|
DEFAULT_ZONE = "Etc/UTC"
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
def initialize(time)
|
8
|
+
def initialize(*args, **_kargs, &_block)
|
11
9
|
::Time.zone ||= DEFAULT_ZONE
|
12
|
-
|
13
|
-
|
14
|
-
@raw = ::Time.zone.parse(
|
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
|
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
|
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
|
-
|
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
|
-
|
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(
|
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(
|
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
|
-
|
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
|
-
|
421
|
+
raw.as_json
|
329
422
|
end
|
330
423
|
end
|
331
424
|
end
|
data/lib/code/parser/code.rb
CHANGED
@@ -4,7 +4,7 @@ class Code
|
|
4
4
|
class Parser
|
5
5
|
class LeftOperation < Language
|
6
6
|
def statement
|
7
|
-
|
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
|
-
|
19
|
+
str("")
|
20
20
|
end
|
21
21
|
|
22
22
|
def right_statement
|
data/lib/code/parser/list.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
data/lib/code/type/sig.rb
CHANGED
data/lib/code/type.rb
CHANGED
@@ -2,12 +2,20 @@
|
|
2
2
|
|
3
3
|
class Code
|
4
4
|
class Type
|
5
|
-
def
|
6
|
-
|
5
|
+
def maybe
|
6
|
+
Maybe.new(self)
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
10
|
-
|
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
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
|
-
|
32
|
-
|
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
|
-
["
|
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|
|