code-ruby 0.5.5 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -4
- data/Gemfile.lock +10 -22
- data/code-ruby.gemspec +4 -3
- data/lib/code/error.rb +16 -5
- data/lib/code/node/base_10.rb +4 -2
- data/lib/code/node/base_16.rb +3 -1
- data/lib/code/node/base_2.rb +3 -1
- data/lib/code/node/base_8.rb +3 -1
- data/lib/code/node/boolean.rb +4 -2
- data/lib/code/node/call.rb +35 -12
- data/lib/code/node/call_argument.rb +16 -5
- data/lib/code/node/code.rb +5 -4
- data/lib/code/node/decimal.rb +2 -0
- data/lib/code/node/{dictionnary.rb → dictionary.rb} +14 -5
- data/lib/code/node/function.rb +7 -4
- data/lib/code/node/function_parameter.rb +3 -1
- data/lib/code/node/if.rb +5 -3
- data/lib/code/node/left_operation.rb +63 -0
- data/lib/code/node/list.rb +2 -0
- data/lib/code/node/negation.rb +2 -0
- data/lib/code/node/not.rb +2 -0
- data/lib/code/node/nothing.rb +3 -1
- data/lib/code/node/number.rb +2 -0
- data/lib/code/node/right_operation.rb +70 -0
- data/lib/code/node/splat.rb +2 -0
- data/lib/code/node/square_bracket.rb +37 -0
- data/lib/code/node/statement.rb +13 -5
- data/lib/code/node/string.rb +3 -1
- data/lib/code/node/ternary.rb +5 -3
- data/lib/code/node/unary_minus.rb +2 -0
- data/lib/code/node/while.rb +6 -4
- data/lib/code/node.rb +11 -5
- data/lib/code/object/argument.rb +13 -7
- data/lib/code/object/boolean.rb +43 -5
- data/lib/code/object/class.rb +17 -0
- data/lib/code/object/context.rb +36 -0
- data/lib/code/object/decimal.rb +252 -100
- data/lib/code/object/dictionary.rb +641 -0
- data/lib/code/object/function.rb +54 -27
- data/lib/code/object/global.rb +65 -19
- data/lib/code/object/identifier_list.rb +47 -0
- data/lib/code/object/integer.rb +320 -137
- data/lib/code/object/list.rb +140 -138
- data/lib/code/object/nothing.rb +10 -4
- data/lib/code/object/number.rb +6 -1
- data/lib/code/object/range.rb +85 -88
- data/lib/code/object/ruby_function.rb +11 -6
- data/lib/code/object/string.rb +51 -48
- data/lib/code/object.rb +117 -139
- data/lib/code/parser/addition.rb +4 -2
- data/lib/code/parser/and_operator.rb +4 -2
- data/lib/code/parser/bitwise_and.rb +4 -2
- data/lib/code/parser/bitwise_or.rb +4 -2
- data/lib/code/parser/boolean.rb +3 -1
- data/lib/code/parser/call.rb +17 -11
- data/lib/code/parser/chained_call.rb +10 -22
- data/lib/code/parser/class.rb +9 -6
- data/lib/code/parser/code.rb +6 -4
- data/lib/code/parser/{dictionnary.rb → dictionary.rb} +16 -13
- data/lib/code/parser/equal.rb +9 -36
- data/lib/code/parser/equality.rb +4 -2
- data/lib/code/parser/function.rb +24 -9
- data/lib/code/parser/greater.rb +6 -3
- data/lib/code/parser/group.rb +4 -2
- data/lib/code/parser/if.rb +6 -4
- data/lib/code/parser/if_modifier.rb +5 -25
- data/lib/code/parser/left_operation.rb +40 -0
- data/lib/code/parser/list.rb +6 -5
- data/lib/code/parser/multiplication.rb +4 -2
- data/lib/code/parser/name.rb +19 -4
- data/lib/code/parser/negation.rb +4 -2
- data/lib/code/parser/not_keyword.rb +5 -3
- data/lib/code/parser/nothing.rb +3 -10
- data/lib/code/parser/number.rb +4 -2
- data/lib/code/parser/or_keyword.rb +4 -2
- data/lib/code/parser/or_operator.rb +4 -2
- data/lib/code/parser/power.rb +4 -28
- data/lib/code/parser/range.rb +4 -2
- data/lib/code/parser/rescue.rb +6 -26
- data/lib/code/parser/right_operation.rb +40 -0
- data/lib/code/parser/shift.rb +4 -2
- data/lib/code/parser/splat.rb +5 -3
- data/lib/code/parser/square_bracket.rb +48 -0
- data/lib/code/parser/statement.rb +3 -1
- data/lib/code/parser/string.rb +12 -10
- data/lib/code/parser/ternary.rb +10 -11
- data/lib/code/parser/unary_minus.rb +5 -3
- data/lib/code/parser/while.rb +5 -3
- data/lib/code/parser/whitespace.rb +2 -0
- data/lib/code/parser.rb +10 -3
- data/lib/code/ruby.rb +4 -2
- data/lib/code/type/hash.rb +38 -0
- data/lib/code/type/maybe.rb +29 -0
- data/lib/code/type/or.rb +38 -0
- data/lib/code/type/repeat.rb +38 -0
- data/lib/code/type/sig.rb +130 -0
- data/lib/code/type.rb +25 -0
- data/lib/code/version.rb +3 -0
- data/lib/code-ruby.rb +1 -2
- data/lib/code.rb +15 -16
- data/spec/code/node/call_spec.rb +39 -0
- data/spec/code/object/boolean_spec.rb +18 -0
- data/spec/code/object/decimal_spec.rb +51 -0
- data/spec/code/object/dictionary_spec.rb +98 -0
- data/spec/code/object/function_spec.rb +42 -0
- data/spec/code/object/integer_spec.rb +43 -0
- data/spec/code/object/nothing_spec.rb +14 -0
- data/spec/code/object/range_spec.rb +23 -0
- data/spec/code/parser/boolean_spec.rb +5 -10
- data/spec/code/parser/chained_call.rb +4 -5
- data/spec/code/parser/{dictionnary_spec.rb → dictionary_spec.rb} +5 -6
- data/spec/code/parser/function_spec.rb +4 -5
- data/spec/code/parser/group_spec.rb +5 -12
- data/spec/code/parser/if_modifier_spec.rb +18 -0
- data/spec/code/parser/list_spec.rb +4 -5
- data/spec/code/parser/number_spec.rb +4 -5
- data/spec/code/parser/string_spec.rb +4 -5
- data/spec/code/parser_spec.rb +22 -16
- data/spec/code/type_spec.rb +21 -0
- data/spec/code_spec.rb +171 -0
- data/spec/spec_helper.rb +1 -6
- metadata +61 -137
- data/.cherry.js +0 -21
- data/.editorconfig +0 -9
- data/.github/workflows/rspec.yml +0 -14
- data/.gitignore +0 -2
- data/.prettierrc +0 -3
- data/.tool-versions +0 -1
- data/CHANGELOG.md +0 -55
- data/LICENSE +0 -7
- data/README.md +0 -103
- data/TODO +0 -17
- data/bin/code +0 -76
- data/bin/format +0 -3
- data/bin/publish +0 -19
- data/bin/template +0 -85
- data/bin/test +0 -17
- data/docs/class.code +0 -9
- data/docs/euler/1.template +0 -10
- data/docs/euler/2.template +0 -16
- data/docs/euler/3.template +0 -16
- data/docs/euler/4.template +0 -10
- data/docs/euler/5.template +0 -13
- data/docs/fibonnaci.template +0 -14
- data/docs/meetup.code +0 -12
- data/docs/precedence.template +0 -36
- data/docs/rain.code +0 -22
- data/docs/slack.code +0 -17
- data/docs/stripe.code +0 -7
- data/docs/twitter.code +0 -9
- data/language-ruby.gemspec +0 -17
- data/lib/code/node/chained_call.rb +0 -23
- data/lib/code/node/equal.rb +0 -34
- data/lib/code/node/if_modifier.rb +0 -47
- data/lib/code/node/operation.rb +0 -38
- data/lib/code/node/power.rb +0 -20
- data/lib/code/node/rescue.rb +0 -17
- data/lib/code/object/dictionnary.rb +0 -96
- data/lib/code/parser/equality_lower.rb +0 -9
- data/lib/code/parser/operation.rb +0 -35
- data/lib/language/atom.rb +0 -342
- data/lib/language/output.rb +0 -130
- data/lib/language/parser/absent/present.rb +0 -8
- data/lib/language/parser/absent.rb +0 -6
- data/lib/language/parser/end_of_input.rb +0 -6
- data/lib/language/parser/interuption.rb +0 -38
- data/lib/language/parser/not_end_of_input.rb +0 -6
- data/lib/language/parser/str/not_found.rb +0 -16
- data/lib/language/parser/str.rb +0 -6
- data/lib/language/parser.rb +0 -53
- data/lib/language-ruby.rb +0 -10
- data/lib/language.rb +0 -80
- data/lib/template/node/code_part.rb +0 -13
- data/lib/template/node/part.rb +0 -19
- data/lib/template/node/template.rb +0 -15
- data/lib/template/node/text_part.rb +0 -13
- data/lib/template/node.rb +0 -4
- data/lib/template/parser/template.rb +0 -39
- data/lib/template/parser.rb +0 -19
- data/lib/template/version.rb +0 -3
- data/lib/template-ruby.rb +0 -10
- data/lib/template.rb +0 -50
- data/spec/code/addition_spec.rb +0 -13
- data/spec/code/and_operator_spec.rb +0 -13
- data/spec/code/bitwise_and_spec.rb +0 -13
- data/spec/code/bitwise_or_spec.rb +0 -13
- data/spec/code/boolean_spec.rb +0 -13
- data/spec/code/call_spec.rb +0 -21
- data/spec/code/chained_call_spec.rb +0 -16
- data/spec/code/code_spec.rb +0 -11
- data/spec/code/dictionnary_spec.rb +0 -17
- data/spec/code/equal_spec.rb +0 -26
- data/spec/code/equality_spec.rb +0 -13
- data/spec/code/function_spec.rb +0 -18
- data/spec/code/greater_spec.rb +0 -18
- data/spec/code/group_spec.rb +0 -12
- data/spec/code/if_modifier_spec.rb +0 -20
- data/spec/code/if_spec.rb +0 -25
- data/spec/code/list_spec.rb +0 -19
- data/spec/code/multiplication_spec.rb +0 -18
- data/spec/code/negation_spec.rb +0 -20
- data/spec/code/not_keyword_spec.rb +0 -13
- data/spec/code/nothing_spec.rb +0 -17
- data/spec/code/number_spec.rb +0 -22
- data/spec/code/or_keyword_spec.rb +0 -17
- data/spec/code/or_operator_spec.rb +0 -16
- data/spec/code/parser/call_spec.rb +0 -26
- data/spec/code/power_spec.rb +0 -13
- data/spec/code/range_spec.rb +0 -16
- data/spec/code/rescue_spec.rb +0 -13
- data/spec/code/shift_spec.rb +0 -13
- data/spec/code/splat_spec.rb +0 -13
- data/spec/code/string_spec.rb +0 -27
- data/spec/code/ternary_spec.rb +0 -18
- data/spec/code/unary_minus_spec.rb +0 -13
- data/spec/code/while_spec.rb +0 -18
- data/template-ruby.gemspec +0 -19
data/lib/code/type.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Code
|
4
|
+
class Type
|
5
|
+
def name
|
6
|
+
raise NotImplementedError, "#{self.class}#name"
|
7
|
+
end
|
8
|
+
|
9
|
+
def valid?(argument)
|
10
|
+
raise NotImplementedError, "#{self.class}#valid?"
|
11
|
+
end
|
12
|
+
|
13
|
+
def valid_for?(expected:, actual:)
|
14
|
+
expected.is_a?(Type) ? expected.valid?(actual) : actual.is_a?(expected)
|
15
|
+
end
|
16
|
+
|
17
|
+
def min_arguments_of(clazz)
|
18
|
+
clazz.is_a?(Type) ? clazz.min_arguments : 1
|
19
|
+
end
|
20
|
+
|
21
|
+
def max_arguments_of(clazz)
|
22
|
+
clazz.is_a?(Type) ? clazz.max_arguments : 1
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/code/version.rb
ADDED
data/lib/code-ruby.rb
CHANGED
@@ -2,9 +2,8 @@ require "bigdecimal"
|
|
2
2
|
require "stringio"
|
3
3
|
require "timeout"
|
4
4
|
require "zeitwerk"
|
5
|
+
require "language-ruby"
|
5
6
|
|
6
7
|
loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
|
7
|
-
loader.ignore("#{__dir__}/template-ruby.rb")
|
8
8
|
loader.ignore("#{__dir__}/code-ruby.rb")
|
9
|
-
loader.ignore("#{__dir__}/language-ruby.rb")
|
10
9
|
loader.setup
|
data/lib/code.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Code
|
2
4
|
EMPTY_STRING = ""
|
3
|
-
GLOBALS = %i[io context object]
|
4
|
-
DEFAULT_TIMEOUT =
|
5
|
+
GLOBALS = %i[io context object].freeze
|
6
|
+
DEFAULT_TIMEOUT = 0
|
5
7
|
|
6
8
|
def initialize(input, io: StringIO.new, timeout: DEFAULT_TIMEOUT, ruby: {})
|
7
9
|
@input = input
|
8
10
|
@parsed = Timeout.timeout(timeout) { ::Code::Parser.parse(@input).to_raw }
|
9
11
|
@io = io
|
10
12
|
@timeout = timeout || DEFAULT_TIMEOUT
|
11
|
-
@ruby = ::Code::Ruby.to_code(ruby || {})
|
13
|
+
@ruby = ::Code::Ruby.to_code(ruby || {}).code_to_context
|
12
14
|
end
|
13
15
|
|
14
16
|
def self.evaluate(
|
@@ -18,26 +20,23 @@ class Code
|
|
18
20
|
timeout: DEFAULT_TIMEOUT,
|
19
21
|
ruby: {}
|
20
22
|
)
|
21
|
-
new(input, io
|
23
|
+
new(input, io:, timeout:, ruby:).evaluate(context)
|
22
24
|
end
|
23
25
|
|
24
26
|
def evaluate(context = "")
|
25
27
|
Timeout.timeout(timeout) do
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
"context must be a dictionnary"
|
35
|
-
)
|
36
|
-
end
|
28
|
+
context =
|
29
|
+
if context == EMPTY_STRING
|
30
|
+
Object::Context.new
|
31
|
+
else
|
32
|
+
Code.evaluate(context, timeout:, io:, ruby:).code_to_context
|
33
|
+
end
|
34
|
+
|
35
|
+
raise(Error::IncompatibleContext) unless context.is_a?(Object::Context)
|
37
36
|
|
38
37
|
context = context.merge(ruby)
|
39
38
|
|
40
|
-
|
39
|
+
Node::Code.new(parsed).evaluate(context:, io:)
|
41
40
|
end
|
42
41
|
end
|
43
42
|
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Code::Node::Call do
|
6
|
+
=begin
|
7
|
+
let(:context) { <<~CONTEXT }
|
8
|
+
render = (*args, **kargs, &block) => {
|
9
|
+
[args, kargs, block&.call(:dorian)]
|
10
|
+
}
|
11
|
+
|
12
|
+
{ render:, user: { name: :Dorian } }"
|
13
|
+
CONTEXT
|
14
|
+
|
15
|
+
[
|
16
|
+
["render", "[[], {}, nothing]"],
|
17
|
+
["render()", "[[], {}, nothing]"],
|
18
|
+
["render(user)", "[[user], {}, nothing]"],
|
19
|
+
[
|
20
|
+
"render(user, first_name: :Dorian)",
|
21
|
+
"[[user], { first_name: :Dorian }, nothing]"
|
22
|
+
],
|
23
|
+
["render { }", "[[], {}, nothing]"],
|
24
|
+
["render do end", "[[], {}, nothing]"],
|
25
|
+
["render { |name| name.upcase }", "[[], {}, :Dorian]"],
|
26
|
+
["render(user) { |name| name.upcase }", "[[user], {}, :Dorian]"],
|
27
|
+
["render(user) do |name| name.upcase end", "[[user], {}, :Dorian]"],
|
28
|
+
["render { :Dorian }", "[[], {}, :Dorian]"],
|
29
|
+
["render(user) { :Dorian }", "[[user], {}, :Dorian]"],
|
30
|
+
["render(user) do :Dorian end", "[[user], {}, :Dorian]"]
|
31
|
+
].each do |input, expected|
|
32
|
+
it "#{input} == #{expected}" do
|
33
|
+
expect(Code.evaluate(input, context)).to eq(
|
34
|
+
Code.evaluate(expected, context)
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
=end
|
39
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Code::Object::Boolean do
|
6
|
+
[
|
7
|
+
["true & false", "false"],
|
8
|
+
%w[true.bitwise_and(false) false],
|
9
|
+
["true | false", "true"],
|
10
|
+
%w[true.bitwise_or(false) true],
|
11
|
+
["true ^ false", "true"],
|
12
|
+
%w[true.bitwise_xor(false) true]
|
13
|
+
].each do |input, expected|
|
14
|
+
it "#{input} == #{expected}" do
|
15
|
+
expect(Code.evaluate(input)).to eq(Code.evaluate(expected))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Code::Object::Decimal do
|
6
|
+
[
|
7
|
+
["10.2 % 5.1", "0"],
|
8
|
+
["5.5 * 2.5", "13.75"],
|
9
|
+
["1.5 ** 2", "2.25"],
|
10
|
+
["1.5 + 1.5", "3"],
|
11
|
+
["1.5 - 0.5", "1"],
|
12
|
+
%w[-1.5 -3/2],
|
13
|
+
["1.5 / 2", "0.75"],
|
14
|
+
["1.1 < 1.2", "true"],
|
15
|
+
["1.1 <= 1.1", "true"],
|
16
|
+
["1.1 <=> 1.2", "-1"],
|
17
|
+
["1.1 > 0.9", "true"],
|
18
|
+
["1.1 >= 1.1", "true"],
|
19
|
+
["1.1 === 1.1", "true"],
|
20
|
+
%w[-1.1.abs 1.1],
|
21
|
+
%w[-1.1.ceil -1],
|
22
|
+
%w[-1.123.ceil(2) -1.12],
|
23
|
+
%w[-1.1.floor -2],
|
24
|
+
%w[-1.123.floor(2) -1.13],
|
25
|
+
%w[1.1.round 1],
|
26
|
+
%w[1.123.round(2) 1.12],
|
27
|
+
%w[1.2.clone 1.2],
|
28
|
+
%w[0.0.zero? true],
|
29
|
+
%w[1.2.truncate 1],
|
30
|
+
%w[1.234.truncate(2) 1.23],
|
31
|
+
%w[1.2.to_string "1.2"],
|
32
|
+
%w[1.2.to_integer 1],
|
33
|
+
%w[1.2.to_decimal 1.2],
|
34
|
+
%w[4.0.sqrt 2.0],
|
35
|
+
%w[0.0.zero? true],
|
36
|
+
%w[1.0.one? true],
|
37
|
+
%w[2.0.two? true],
|
38
|
+
%w[3.0.three? true],
|
39
|
+
%w[4.0.four? true],
|
40
|
+
%w[5.0.five? true],
|
41
|
+
%w[6.0.six? true],
|
42
|
+
%w[7.0.seven? true],
|
43
|
+
%w[8.0.eight? true],
|
44
|
+
%w[9.0.nine? true],
|
45
|
+
%w[10.0.ten? true]
|
46
|
+
].each do |input, expected|
|
47
|
+
it "#{input} == #{expected}" do
|
48
|
+
expect(Code.evaluate(input)).to eq(Code.evaluate(expected))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Code::Object::Dictionary do
|
6
|
+
let(:context) { '{ first_name: "Dorian", language: :code }' }
|
7
|
+
|
8
|
+
[
|
9
|
+
["{} == {}", "true"],
|
10
|
+
['{ "name" => "Dorian" } == { name: :Dorian }', "true"],
|
11
|
+
%w[context.first_name :Dorian],
|
12
|
+
["context[:first_name]", ":Dorian"],
|
13
|
+
%w[context.language :code],
|
14
|
+
["context > { first_name: :Dorian", "true"],
|
15
|
+
["{ first_name: :Dorian } < context", "true"],
|
16
|
+
["context <= context", "true"],
|
17
|
+
["context >= {}", "true"],
|
18
|
+
["context <=> context", "0"],
|
19
|
+
["context === context", "true"],
|
20
|
+
["{ first_name: :Dorian }.any? { |_, value| value == :Dorian }", "true"],
|
21
|
+
%w[context.any?(String) true],
|
22
|
+
["{ a: nothing }.compact", "{}"],
|
23
|
+
["d = { a: nothing } d.compact! d", "{}"],
|
24
|
+
%w[context.dig(:first_name) :Dorian],
|
25
|
+
%w[context.empty? false],
|
26
|
+
%w[context.truthy? true],
|
27
|
+
%w[context.falsy? false],
|
28
|
+
%w[context.fetch(:first_name) :Dorian],
|
29
|
+
["context.fetch(:unknown) { :Good }", ":Good"],
|
30
|
+
["context.fetch(:first_name, :language)", "context"],
|
31
|
+
[
|
32
|
+
"context.fetch(:first_name, :last_name) { :Marié }",
|
33
|
+
"{ first_name: :Dorian, last_name: :Marié }"
|
34
|
+
],
|
35
|
+
["context.delete(:last_name) { true }", "true"],
|
36
|
+
[
|
37
|
+
"context.delete(:first_name, :language)",
|
38
|
+
"{ first_name: :Dorian, language: :code }"
|
39
|
+
],
|
40
|
+
["{ first_name: :Dorian }.delete_if(String)", "{}"],
|
41
|
+
["{ age: 31 }.delete_unless(Number)", "{ age: 31 }"],
|
42
|
+
["{ age: 31 }.delete_unless(Integer)", "{ age: 31 }"],
|
43
|
+
["{ first_name: :Dorian }.delete_if { |_, value| value == :Dorian }", "{}"],
|
44
|
+
["{ age: 31 }.delete_unless { |key| key == :age }", "{ age: 31 }"],
|
45
|
+
["{ first_name: :Dorian }.keep_if(String)", "{ first_name: :Dorian }"],
|
46
|
+
["{ age: 31 }.keep_unless(Number)", "{}"],
|
47
|
+
["{ age: 31 }.keep_unless(Integer)", "{}"],
|
48
|
+
["{ first_name: :Dorian }.keep_if { |_, value| value != :Dorian }", "{}"],
|
49
|
+
["{ age: 31 }.keep_unless { |key| key == :age }", "{}"],
|
50
|
+
["context.except(:first_name, :language)", "{}"],
|
51
|
+
["context.fetch_values(:first_name, :language)", "[:Dorian, :code]"],
|
52
|
+
["context.fetch_values(:first_name)", "[:Dorian]"],
|
53
|
+
%w[context.select(String) context],
|
54
|
+
%w[context.select(Integer) {}],
|
55
|
+
["context.select(Integer) context", "context"],
|
56
|
+
%w[context.select!(Integer) {}],
|
57
|
+
["context.select!(Integer) context", "{}"],
|
58
|
+
[
|
59
|
+
"context.select { |key, value, dictionnary, index| key == :first_name }",
|
60
|
+
"{ first_name: :Dorian }"
|
61
|
+
],
|
62
|
+
[
|
63
|
+
"context.select { |key, value, dictionnary, index| value == :Dorian }",
|
64
|
+
"{ first_name: :Dorian }"
|
65
|
+
],
|
66
|
+
[
|
67
|
+
"context.select { |key, value, dictionnary, index| dictionnary.two? }",
|
68
|
+
"context"
|
69
|
+
],
|
70
|
+
[
|
71
|
+
"context.select { |key, value, dictionnary, index| index.zero? }",
|
72
|
+
"{ first_name: :Dorian }"
|
73
|
+
],
|
74
|
+
["{ a: 1, b: [2, 3] }.to_list", "[[:a, 1], [:b, [2, 3]]]"],
|
75
|
+
["{ a: 1, b: [2, 3] }.flatten", "[:a, 1, :b, 2, 3]"],
|
76
|
+
["{ a: 1, b: [2, 3] }.flatten(0)", "[[:a, 1], [:b, [2, 3]]]"],
|
77
|
+
["{ a: 1, b: [2, 3] }.flatten(1)", "[:a, 1, :b, [2, 3]]"],
|
78
|
+
["{ a: 1, b: [2, 3] }.flatten(-1)", "[:a, 1, :b, 2, 3]"],
|
79
|
+
%w[context.has_key?(:first_name) true],
|
80
|
+
%w[context.has_key?(:unknown) false],
|
81
|
+
%w[context.has_value?(:Dorian) true],
|
82
|
+
%w[context.has_value?(:Unknown) false],
|
83
|
+
["context.invert", "{ Dorian: :first_name, code: :language }"],
|
84
|
+
%w[context.key(:Dorian) :first_name],
|
85
|
+
%w[context.key(:Unknown) nothing],
|
86
|
+
["context.key(:Unknown) { true }", "true"],
|
87
|
+
["{ a: 1 }.merge(b: 2)", "{ a: 1, b: 2 }"],
|
88
|
+
["{ a: 1 }.merge({ b: 2 })", "{ a: 1, b: 2 }"],
|
89
|
+
["{ a: 1 }.merge({ a: 2 })", "{ a: 2 }"],
|
90
|
+
["{ a: 1 }.merge({ a: 2 }) { |_, old, new| old + new }", "{ a: 3 }"]
|
91
|
+
].each do |input, expected|
|
92
|
+
it "#{input} == #{expected}" do
|
93
|
+
expect(Code.evaluate(input, context)).to eq(
|
94
|
+
Code.evaluate(expected, context)
|
95
|
+
)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Code::Object::Function do
|
6
|
+
=begin
|
7
|
+
[
|
8
|
+
["even? = (i) => { i.even? } even?(2)", "true"],
|
9
|
+
["even? = (i:) => { i.even? } even?(i: 2)", "true"],
|
10
|
+
["add = (a, b) => { a + b } add(1, 2)", "3"],
|
11
|
+
["minus = (a:, b:) => { a - b } minus(b: 1, a: 2)", "1"]
|
12
|
+
].each do |input, expected|
|
13
|
+
it "#{input} == #{expected}" do
|
14
|
+
expect(Code.evaluate(input)).to eq(Code.evaluate(expected))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
=end
|
18
|
+
|
19
|
+
context "valid" do
|
20
|
+
[
|
21
|
+
"f = () => {} f",
|
22
|
+
"f = (x) => {} f(1)",
|
23
|
+
# "f = (x:) => {} f(x: 1)"
|
24
|
+
].each do |input|
|
25
|
+
it "#{input} is valid" do
|
26
|
+
Code.evaluate(input)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "invalid" do
|
32
|
+
[
|
33
|
+
"f = (x) => {} f",
|
34
|
+
"f = (x:) => {} f(1)",
|
35
|
+
"f = (x:) => {} f(y: 1)"
|
36
|
+
].each do |input|
|
37
|
+
it "#{input} is invalid" do
|
38
|
+
expect { Code.evaluate(input) }.to raise_error(Code::Error)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Code::Object::Integer do
|
6
|
+
[
|
7
|
+
["10 % 5", "0"],
|
8
|
+
["5 * 2", "10"],
|
9
|
+
["2 ** 2", "4"],
|
10
|
+
["1 + 1", "2"],
|
11
|
+
["1 - 0", "1"],
|
12
|
+
["-1", "1 - 2"],
|
13
|
+
["1 / 2", "0.5"],
|
14
|
+
["1 < 2", "true"],
|
15
|
+
["1 <= 1", "true"],
|
16
|
+
["1 <=> 2", "-1"],
|
17
|
+
["1 > 0", "true"],
|
18
|
+
["1 >= 1", "true"],
|
19
|
+
["1 === 1", "true"],
|
20
|
+
%w[-1.abs 1],
|
21
|
+
%w[-1.ceil -1],
|
22
|
+
%w[1234.ceil(-2) 1300],
|
23
|
+
%w[-1.floor -1],
|
24
|
+
%w[1234.floor(-2) 1200],
|
25
|
+
%w[1.round 1],
|
26
|
+
%w[1234.round(-2) 1200],
|
27
|
+
%w[1.clone 1],
|
28
|
+
%w[0.zero? true],
|
29
|
+
%w[1.truncate 1],
|
30
|
+
%w[1234.truncate(-2) 1200],
|
31
|
+
%w[1.to_string :1],
|
32
|
+
%w[1.to_integer 1],
|
33
|
+
%w[1.to_decimal 1.0],
|
34
|
+
%w[4.sqrt 2.0],
|
35
|
+
["1 + 2", "3"],
|
36
|
+
["2 - 1", "1"],
|
37
|
+
["a = 2 - 1 a", "1"]
|
38
|
+
].each do |input, expected|
|
39
|
+
it "#{input} == #{expected}" do
|
40
|
+
expect(Code.evaluate(input)).to eq(Code.evaluate(expected))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Code::Object::Nothing do
|
6
|
+
[
|
7
|
+
%w[nothing nothing],
|
8
|
+
["nothing nothing", "nothing"]
|
9
|
+
].each do |input, expected|
|
10
|
+
it "#{input} == #{expected}" do
|
11
|
+
expect(Code.evaluate(input)).to eq(Code.evaluate(expected))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Code::Object::Range do
|
6
|
+
[
|
7
|
+
%w[(0..1).any?(&:even?) true],
|
8
|
+
%w[(0..1).all?(&:even?) false],
|
9
|
+
["a = 0 (0..1).each { a += 1 } a", "2"],
|
10
|
+
["(0..1).select(&:even?)", "[0]"],
|
11
|
+
["(0..1).map(&:increment)", "[1, 2]"],
|
12
|
+
["(0..10).step(3)", "[0, 3, 6, 9]"],
|
13
|
+
["(0...9).step(3)", "[0, 3, 6]"],
|
14
|
+
["(0..1).to_list", "[0, 1]"],
|
15
|
+
["(0...1).to_list", "[0]"],
|
16
|
+
%w[(0..1).first 0],
|
17
|
+
%w[(0..1).last 1]
|
18
|
+
].each do |input, expected|
|
19
|
+
it "#{input} == #{expected}" do
|
20
|
+
expect(Code.evaluate(input)).to eq(Code.evaluate(expected))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,16 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
RSpec.describe Code::Parser::Boolean do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
["true", [{ boolean: "true" }]],
|
8
|
-
["false", [{ boolean: "false" }]]
|
9
|
-
].each do |input, output|
|
10
|
-
context input.inspect do
|
11
|
-
let(:input) { input }
|
12
|
-
|
13
|
-
it { expect(subject).to eq(output) }
|
6
|
+
[%w[true !false], %w[false !true]].each do |input, expected|
|
7
|
+
it "#{input} == #{expected}" do
|
8
|
+
expect(Code.evaluate(input)).to eq(Code.evaluate(expected))
|
14
9
|
end
|
15
10
|
end
|
16
11
|
end
|
@@ -1,17 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
RSpec.describe Code::Parser::ChainedCall do
|
4
|
-
subject { Code::Parser.parse(input) }
|
5
|
-
|
6
6
|
[
|
7
7
|
"a.b",
|
8
8
|
"user.first_name",
|
9
9
|
"user.admin?",
|
10
10
|
'user.update!(name: "Dorian")'
|
11
11
|
].each do |input|
|
12
|
-
|
13
|
-
|
14
|
-
it { subject }
|
12
|
+
it "parses #{input}" do
|
13
|
+
Code::Parser.parse(input)
|
15
14
|
end
|
16
15
|
end
|
17
16
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
subject { Code::Parser.parse(input) }
|
3
|
+
require "spec_helper"
|
5
4
|
|
5
|
+
RSpec.describe Code::Parser::Dictionary do
|
6
6
|
[
|
7
7
|
"{}",
|
8
8
|
"{ }",
|
@@ -10,9 +10,8 @@ RSpec.describe Code::Parser::Dictionnary do
|
|
10
10
|
"{ a: 1, b: 2, c: 3 }",
|
11
11
|
'{ "first_name": "Dorian" }'
|
12
12
|
].each do |input|
|
13
|
-
|
14
|
-
|
15
|
-
it { subject }
|
13
|
+
it "parses #{input}" do
|
14
|
+
Code::Parser.parse(input)
|
16
15
|
end
|
17
16
|
end
|
18
17
|
end
|
@@ -1,16 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
RSpec.describe Code::Parser::Function do
|
4
|
-
subject { Code::Parser.parse(input) }
|
5
|
-
|
6
6
|
[
|
7
7
|
"() => {}",
|
8
8
|
"(a, b) => { add(a, b) }",
|
9
9
|
"(a:, b:) => { add(a, b) }"
|
10
10
|
].each do |input|
|
11
|
-
|
12
|
-
|
13
|
-
it { subject }
|
11
|
+
it "parses #{input}" do
|
12
|
+
Code::Parser.parse(input)
|
14
13
|
end
|
15
14
|
end
|
16
15
|
end
|
@@ -1,18 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
RSpec.describe Code::Parser::Group do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
[
|
8
|
-
"(true (nothing))",
|
9
|
-
[{ group: [{ boolean: "true" }, { group: [{ nothing: "nothing" }] }] }]
|
10
|
-
]
|
11
|
-
].each do |input, output|
|
12
|
-
context input.inspect do
|
13
|
-
let(:input) { input }
|
14
|
-
|
15
|
-
it { expect(subject).to eq(output) }
|
6
|
+
["(true (nothing))"].each do |input|
|
7
|
+
it "parses #{input}" do
|
8
|
+
Code::Parser.parse(input)
|
16
9
|
end
|
17
10
|
end
|
18
11
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "spec_helper"
|
4
|
+
|
5
|
+
RSpec.describe Code::Parser::IfModifier do
|
6
|
+
[
|
7
|
+
["1 if true", "1"],
|
8
|
+
["1 if false", "nothing"],
|
9
|
+
["1 unless true", "nothing"],
|
10
|
+
["1 unless false", "1"],
|
11
|
+
["a = 0 a += 1 while a < 10 a", "10"],
|
12
|
+
["a = 0 a += 1 until a > 10 a", "11"]
|
13
|
+
].each do |input, expected|
|
14
|
+
it "#{input} == #{expected}" do
|
15
|
+
expect(Code.evaluate(input)).to eq(Code.evaluate(expected))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
RSpec.describe Code::Parser::List do
|
4
|
-
subject { Code::Parser.parse(input) }
|
5
|
-
|
6
6
|
[
|
7
7
|
"[]",
|
8
8
|
"[ ]",
|
@@ -10,9 +10,8 @@ RSpec.describe Code::Parser::List do
|
|
10
10
|
"[1, 2, 3]",
|
11
11
|
"['hello', 1, true, [false, nothing]]"
|
12
12
|
].each do |input|
|
13
|
-
|
14
|
-
|
15
|
-
it { subject }
|
13
|
+
it "parses #{input}" do
|
14
|
+
Code::Parser.parse(input)
|
16
15
|
end
|
17
16
|
end
|
18
17
|
end
|
@@ -1,12 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
RSpec.describe Code::Parser::Number do
|
4
|
-
subject { Code::Parser.parse(input) }
|
5
|
-
|
6
6
|
%w[0 1 1.1 123.123 1_000.12_244 0xf0 0o70 0b10].each do |input|
|
7
|
-
|
8
|
-
|
9
|
-
it { subject }
|
7
|
+
it "parses #{input}" do
|
8
|
+
Code::Parser.parse(input)
|
10
9
|
end
|
11
10
|
end
|
12
11
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
RSpec.describe Code::Parser::String do
|
4
|
-
subject { Code::Parser.parse(input) }
|
5
|
-
|
6
6
|
[
|
7
7
|
"''",
|
8
8
|
'""',
|
@@ -13,9 +13,8 @@ RSpec.describe Code::Parser::String do
|
|
13
13
|
"'Hello {name}'",
|
14
14
|
'"Hello {name}"'
|
15
15
|
].each do |input|
|
16
|
-
|
17
|
-
|
18
|
-
it { subject }
|
16
|
+
it "parses #{input}" do
|
17
|
+
Code::Parser.parse(input)
|
19
18
|
end
|
20
19
|
end
|
21
20
|
end
|