code-ruby 0.2.4

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 (140) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +9 -0
  3. data/.github/workflows/rspec.yml +14 -0
  4. data/.gitignore +2 -0
  5. data/.prettierrc +3 -0
  6. data/.rspec +1 -0
  7. data/CHANGELOG.md +31 -0
  8. data/Gemfile +3 -0
  9. data/Gemfile.lock +70 -0
  10. data/LICENSE +7 -0
  11. data/README.md +103 -0
  12. data/TODO.md +1 -0
  13. data/bin/template +39 -0
  14. data/code-ruby.gemspec +22 -0
  15. data/docs/euler/1.template +14 -0
  16. data/docs/euler/2.template +16 -0
  17. data/docs/euler/3.template +16 -0
  18. data/docs/euler/4.template +11 -0
  19. data/docs/euler/5.template +14 -0
  20. data/docs/precedence.template +94 -0
  21. data/lib/code/error.rb +15 -0
  22. data/lib/code/node/base_10_decimal.rb +32 -0
  23. data/lib/code/node/base_10_integer.rb +32 -0
  24. data/lib/code/node/base_10_number.rb +19 -0
  25. data/lib/code/node/base_16_number.rb +19 -0
  26. data/lib/code/node/base_2_number.rb +19 -0
  27. data/lib/code/node/base_8_number.rb +19 -0
  28. data/lib/code/node/block.rb +17 -0
  29. data/lib/code/node/boolean.rb +22 -0
  30. data/lib/code/node/call.rb +52 -0
  31. data/lib/code/node/call_argument.rb +37 -0
  32. data/lib/code/node/chained_call.rb +38 -0
  33. data/lib/code/node/code.rb +16 -0
  34. data/lib/code/node/defined.rb +19 -0
  35. data/lib/code/node/dictionnary.rb +22 -0
  36. data/lib/code/node/dictionnary_key_value.rb +23 -0
  37. data/lib/code/node/equal.rb +36 -0
  38. data/lib/code/node/function.rb +17 -0
  39. data/lib/code/node/function_argument.rb +45 -0
  40. data/lib/code/node/group.rb +13 -0
  41. data/lib/code/node/if.rb +55 -0
  42. data/lib/code/node/if_modifier.rb +48 -0
  43. data/lib/code/node/keyword_call_argument.rb +30 -0
  44. data/lib/code/node/keyword_function_argument.rb +33 -0
  45. data/lib/code/node/list.rb +19 -0
  46. data/lib/code/node/name.rb +50 -0
  47. data/lib/code/node/negation.rb +33 -0
  48. data/lib/code/node/not_keyword.rb +13 -0
  49. data/lib/code/node/nothing.rb +12 -0
  50. data/lib/code/node/number.rb +23 -0
  51. data/lib/code/node/operation.rb +33 -0
  52. data/lib/code/node/or_keyword.rb +34 -0
  53. data/lib/code/node/power.rb +16 -0
  54. data/lib/code/node/range.rb +31 -0
  55. data/lib/code/node/regular_call_argument.rb +34 -0
  56. data/lib/code/node/regular_function_argument.rb +36 -0
  57. data/lib/code/node/rescue.rb +16 -0
  58. data/lib/code/node/statement.rb +81 -0
  59. data/lib/code/node/string.rb +17 -0
  60. data/lib/code/node/ternary.rb +26 -0
  61. data/lib/code/node/unary_minus.rb +22 -0
  62. data/lib/code/node/while.rb +42 -0
  63. data/lib/code/node.rb +14 -0
  64. data/lib/code/object/argument.rb +41 -0
  65. data/lib/code/object/boolean.rb +27 -0
  66. data/lib/code/object/decimal.rb +54 -0
  67. data/lib/code/object/dictionnary.rb +55 -0
  68. data/lib/code/object/function.rb +64 -0
  69. data/lib/code/object/integer.rb +116 -0
  70. data/lib/code/object/list.rb +217 -0
  71. data/lib/code/object/nothing.rb +23 -0
  72. data/lib/code/object/number.rb +6 -0
  73. data/lib/code/object/range.rb +158 -0
  74. data/lib/code/object/string.rb +68 -0
  75. data/lib/code/object.rb +130 -0
  76. data/lib/code/parser/addition.rb +29 -0
  77. data/lib/code/parser/and_operator.rb +28 -0
  78. data/lib/code/parser/bitwise_and.rb +28 -0
  79. data/lib/code/parser/bitwise_or.rb +29 -0
  80. data/lib/code/parser/boolean.rb +14 -0
  81. data/lib/code/parser/call.rb +90 -0
  82. data/lib/code/parser/code.rb +19 -0
  83. data/lib/code/parser/defined.rb +20 -0
  84. data/lib/code/parser/dictionnary.rb +41 -0
  85. data/lib/code/parser/equal.rb +42 -0
  86. data/lib/code/parser/equality.rb +36 -0
  87. data/lib/code/parser/function.rb +57 -0
  88. data/lib/code/parser/greater_than.rb +33 -0
  89. data/lib/code/parser/group.rb +17 -0
  90. data/lib/code/parser/if.rb +33 -0
  91. data/lib/code/parser/if_modifier.rb +28 -0
  92. data/lib/code/parser/list.rb +29 -0
  93. data/lib/code/parser/multiplication.rb +30 -0
  94. data/lib/code/parser/name.rb +89 -0
  95. data/lib/code/parser/negation.rb +19 -0
  96. data/lib/code/parser/not_keyword.rb +21 -0
  97. data/lib/code/parser/nothing.rb +17 -0
  98. data/lib/code/parser/number.rb +98 -0
  99. data/lib/code/parser/or_keyword.rb +29 -0
  100. data/lib/code/parser/or_operator.rb +28 -0
  101. data/lib/code/parser/power.rb +25 -0
  102. data/lib/code/parser/range.rb +25 -0
  103. data/lib/code/parser/rescue.rb +23 -0
  104. data/lib/code/parser/shift.rb +31 -0
  105. data/lib/code/parser/statement.rb +8 -0
  106. data/lib/code/parser/string.rb +72 -0
  107. data/lib/code/parser/ternary.rb +25 -0
  108. data/lib/code/parser/unary_minus.rb +13 -0
  109. data/lib/code/parser/while.rb +25 -0
  110. data/lib/code/parser.rb +4 -0
  111. data/lib/code-ruby.rb +11 -0
  112. data/lib/code.rb +29 -0
  113. data/lib/template/node/code_part.rb +13 -0
  114. data/lib/template/node/part.rb +19 -0
  115. data/lib/template/node/template.rb +15 -0
  116. data/lib/template/node/text_part.rb +13 -0
  117. data/lib/template/node.rb +4 -0
  118. data/lib/template/parser/template.rb +30 -0
  119. data/lib/template/parser.rb +4 -0
  120. data/lib/template/version.rb +3 -0
  121. data/lib/template-ruby.rb +11 -0
  122. data/lib/template.rb +34 -0
  123. data/spec/call_spec.rb +22 -0
  124. data/spec/code/error/type_error_spec.rb +65 -0
  125. data/spec/code/parser/boolean_spec.rb +18 -0
  126. data/spec/code/parser/call_spec.rb +66 -0
  127. data/spec/code/parser/dictionnary_spec.rb +46 -0
  128. data/spec/code/parser/function_spec.rb +32 -0
  129. data/spec/code/parser/list_spec.rb +29 -0
  130. data/spec/code/parser/name_spec.rb +15 -0
  131. data/spec/code/parser/nothing_spec.rb +19 -0
  132. data/spec/code/parser/number_spec.rb +117 -0
  133. data/spec/code/parser/string_spec.rb +30 -0
  134. data/spec/code_spec.rb +108 -0
  135. data/spec/function_spec.rb +26 -0
  136. data/spec/spec_helper.rb +3 -0
  137. data/spec/template/parser/template_spec.rb +19 -0
  138. data/spec/template_spec.rb +27 -0
  139. data/template-ruby.gemspec +24 -0
  140. metadata +266 -0
@@ -0,0 +1,30 @@
1
+ class Template
2
+ class Parser
3
+ class Template < Parslet::Parser
4
+ rule(:code) { ::Code::Parser::Code.new }
5
+
6
+ rule(:left_curly_bracket) { str("{") }
7
+ rule(:right_curly_bracket) { str("}") }
8
+ rule(:escape) { str("\\") }
9
+
10
+ rule(:text_part) do
11
+ (
12
+ (escape.ignore >> left_curly_bracket) |
13
+ (left_curly_bracket.absent? >> any)
14
+ ).repeat(1)
15
+ end
16
+
17
+ rule(:code_part) do
18
+ left_curly_bracket.ignore >> code >>
19
+ (right_curly_bracket.ignore | any.absent?)
20
+ end
21
+
22
+ rule(:template) do
23
+ (text_part.as(:text) | code_part.as(:code)).repeat(1) |
24
+ str("").as(:text).repeat(1, 1)
25
+ end
26
+
27
+ root(:template)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ class Template
2
+ class Parser
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ require_relative "../template"
2
+
3
+ Template::Version = Gem::Version.new("0.2.4")
@@ -0,0 +1,11 @@
1
+ require "parslet"
2
+ require "zeitwerk"
3
+ require "bigdecimal"
4
+ require "active_support"
5
+ require "active_support/core_ext/object/blank"
6
+ require "stringio"
7
+ require "timeout"
8
+
9
+ loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
10
+ loader.ignore(__FILE__)
11
+ loader.setup
data/lib/template.rb ADDED
@@ -0,0 +1,34 @@
1
+ class Template
2
+ def initialize(input, io: StringIO.new, timeout: 10)
3
+ @input = input
4
+ @parsed =
5
+ Timeout.timeout(timeout) do
6
+ ::Template::Parser::Template.new.parse(@input)
7
+ end
8
+ @io = io
9
+ @timeout = timeout
10
+ end
11
+
12
+ def self.render(input, context = "", io: StringIO.new, timeout: 10)
13
+ new(input, io: io, timeout: timeout).render(context)
14
+ end
15
+
16
+ def render(context = "")
17
+ Timeout.timeout(@timeout) do
18
+ if context.present?
19
+ context = ::Code.evaluate(context, timeout: @timeout)
20
+ else
21
+ context = ::Code::Object::Dictionnary.new
22
+ end
23
+
24
+ ::Template::Node::Template.new(@parsed).evaluate(
25
+ context: context,
26
+ io: @io,
27
+ )
28
+
29
+ @io.is_a?(StringIO) ? @io.string : nil
30
+ end
31
+ end
32
+ end
33
+
34
+ require_relative "template/version"
data/spec/call_spec.rb ADDED
@@ -0,0 +1,22 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code do
4
+ subject { described_class.evaluate(input).to_s }
5
+
6
+ [
7
+ %w[(1..2).any?(&:even?) true],
8
+ %w[(1..1).any?(&:even?) false],
9
+ %w[(3..3).any?(&:even?) false],
10
+ %w[(2..5).any?(&:even?) true],
11
+ ["(2..5).any? { |n| n.even? }", "true"],
12
+ ["(2..5).select { |i| i.even? }.any? { |n| n.even? }", "true"],
13
+ ].each do |(input, expected)|
14
+ context input.inspect do
15
+ let(:input) { input }
16
+
17
+ it "succeeds" do
18
+ expect(subject).to eq(expected)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,65 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe ::Code::Error::TypeError do
4
+ describe "Integer" do
5
+ context "creating an integer with a non-number exponent" do
6
+ it "raises" do
7
+ expect { ::Code::Object::Integer.new(1, exponent: "2") }.to raise_error(
8
+ described_class,
9
+ )
10
+ end
11
+ end
12
+
13
+ [
14
+ '1 / ""',
15
+ '1 ** ""',
16
+ '1 % ""',
17
+ '1 + ""',
18
+ '1 - ""',
19
+ '1 << ""',
20
+ '1 >> ""',
21
+ '1 & ""',
22
+ '1 | ""',
23
+ '1 ^ ""',
24
+ '1 > ""',
25
+ '1 >= ""',
26
+ '1 < ""',
27
+ '1 <= ""',
28
+ ].each do |input|
29
+ context input.inspect do
30
+ it "raises" do
31
+ expect { ::Code.evaluate(input) }.to raise_error(described_class)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "Decimal" do
38
+ context "creating an integer with a non-number exponent" do
39
+ it "raises" do
40
+ expect { ::Code::Object::Decimal.new(1, exponent: "2") }.to raise_error(
41
+ described_class,
42
+ )
43
+ end
44
+ end
45
+
46
+ [
47
+ '1.0 / ""',
48
+ '1.0 ** ""',
49
+ '1.0 * ""',
50
+ '1.0 % ""',
51
+ '1.0 + ""',
52
+ '1.0 - ""',
53
+ '1.0 > ""',
54
+ '1.0 >= ""',
55
+ '1.0 < ""',
56
+ '1.0 <= ""',
57
+ ].each do |input|
58
+ context input.inspect do
59
+ it "raises" do
60
+ expect { ::Code.evaluate(input) }.to raise_error(described_class)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::Boolean do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ ["true", { boolean: "true" }],
8
+ ["false", { boolean: "false" }],
9
+ ].each do |(input, expected)|
10
+ context input.inspect do
11
+ let(:input) { input }
12
+
13
+ it "succeeds" do
14
+ expect(subject).to eq(expected)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,66 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::Call do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ [
8
+ "user.first_name",
9
+ { call: { left: { name: "user" }, right: [{ name: "first_name" }] } },
10
+ ],
11
+ [
12
+ "3.times",
13
+ {
14
+ call: {
15
+ left: {
16
+ number: {
17
+ base_10: {
18
+ integer: {
19
+ whole: "3",
20
+ },
21
+ },
22
+ },
23
+ },
24
+ right: [{ name: "times" }],
25
+ },
26
+ },
27
+ ],
28
+ ].each do |(input, expected)|
29
+ context input.inspect do
30
+ let(:input) { input }
31
+
32
+ it "succeeds" do
33
+ expect(subject).to eq(expected)
34
+ end
35
+ end
36
+ end
37
+
38
+ [
39
+ "User.first",
40
+ "User.first(10)",
41
+ 'User.find_by(name: "Dorian")',
42
+ "User.update_all(**attributes)",
43
+ "User.each(&block)",
44
+ "user.update(*args)",
45
+ "sort([1, 2, 3], :asc)",
46
+ "render()",
47
+ "render(item)",
48
+ "Renderer.render(item)",
49
+ "render(item) { 'Hello' }",
50
+ "render(item) { |item| item * 2 }",
51
+ "render(item) { |item1, item2| item1 + item2 }",
52
+ "render(item) do 'Hello' end",
53
+ "render(item) do |item| item * 2 end",
54
+ "render(item) do |item1, item2| item1 + item2 end",
55
+ "(1..2).any?(&:even?)",
56
+ "(2..5).select { |i| i.even? }.any? { |n| n.even? }",
57
+ ].each do |input|
58
+ context input.inspect do
59
+ let(:input) { input }
60
+
61
+ it "succeeds" do
62
+ expect { subject }.to_not raise_error
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,46 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::Dictionnary do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ [
8
+ '{name: "Dorian"}',
9
+ {
10
+ dictionnary: [{ key: { name: "name" }, value: [{ string: "Dorian" }] }],
11
+ },
12
+ ],
13
+ [
14
+ '{a: true, "b": false}',
15
+ {
16
+ dictionnary: [
17
+ { key: { name: "a" }, value: [{ boolean: "true" }] },
18
+ { key: { string: "b" }, value: [{ boolean: "false" }] },
19
+ ],
20
+ },
21
+ ],
22
+ [
23
+ "{ true => 1, false => 2}",
24
+ {
25
+ dictionnary: [
26
+ {
27
+ key: [{ boolean: "true" }],
28
+ value: [{ number: { base_10: { integer: { whole: "1" } } } }],
29
+ },
30
+ {
31
+ key: [{ boolean: "false" }],
32
+ value: [{ number: { base_10: { integer: { whole: "2" } } } }],
33
+ },
34
+ ],
35
+ },
36
+ ],
37
+ ].each do |(input, expected)|
38
+ context input.inspect do
39
+ let(:input) { input }
40
+
41
+ it "succeeds" do
42
+ expect(subject).to eq(expected)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,32 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::Function do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ "() => {}",
8
+ '() => { "Hello" }',
9
+ "(a) => { }",
10
+ "(a = 1)=> {}",
11
+ "(a, b) =>{}",
12
+ "(a, b = 2, c = b)=>{}",
13
+ "(a:)=>{}",
14
+ "(a:, b:)=>{}",
15
+ "(a, b:, c)=>{}",
16
+ "(a:, b: 1)=>{}",
17
+ "(a, b: 1, c)=>{}",
18
+ "(*args)=>{}",
19
+ "(*args, **kargs)=>{}",
20
+ "(&block)=>{}",
21
+ "(a = b = 1 + 1 b)=>{}",
22
+ "(a: b = 1 + 1 b)=>{}",
23
+ ].each do |input|
24
+ context input.inspect do
25
+ let(:input) { input }
26
+
27
+ it "succeeds" do
28
+ expect { subject }.to_not raise_error
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::List do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ [
8
+ "[true, false]",
9
+ {
10
+ list: [
11
+ { code: [{ boolean: "true" }] },
12
+ { code: [{ boolean: "false" }] },
13
+ ],
14
+ },
15
+ ],
16
+ [
17
+ "[nothing, a]",
18
+ { list: [{ code: [{ nothing: "nothing" }] }, { code: [{ name: "a" }] }] },
19
+ ],
20
+ ].each do |(input, expected)|
21
+ context input.inspect do
22
+ let(:input) { input }
23
+
24
+ it "succeeds" do
25
+ expect(subject).to eq(expected)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,15 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::Name do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ %w[user dorian User RSpec describe?].each do |(input, expected)|
7
+ context input.inspect do
8
+ let(:input) { input }
9
+
10
+ it "succeeds" do
11
+ expect(subject).to eq({ name: input })
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::Nothing do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ ["nothing", { nothing: "nothing" }],
8
+ ["null", { nothing: "null" }],
9
+ ["nil", { nothing: "nil" }],
10
+ ].each do |(input, expected)|
11
+ context input.inspect do
12
+ let(:input) { input }
13
+
14
+ it "succeeds" do
15
+ expect(subject).to eq(expected)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,117 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::Number do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ ["1", { number: { base_10: { integer: { whole: "1" } } } }],
8
+ ["3", { number: { base_10: { integer: { whole: "3" } } } }],
9
+ ["1.0", { number: { base_10: { decimal: { whole: "1", decimal: "0" } } } }],
10
+ [
11
+ "-1.0",
12
+ {
13
+ number: {
14
+ base_10: {
15
+ decimal: {
16
+ sign: "-",
17
+ whole: "1",
18
+ decimal: "0",
19
+ },
20
+ },
21
+ },
22
+ },
23
+ ],
24
+ [
25
+ "+1.0",
26
+ {
27
+ number: {
28
+ base_10: {
29
+ decimal: {
30
+ sign: "+",
31
+ whole: "1",
32
+ decimal: "0",
33
+ },
34
+ },
35
+ },
36
+ },
37
+ ],
38
+ ["0", { number: { base_10: { integer: { whole: "0" } } } }],
39
+ ["+0", { number: { base_10: { integer: { sign: "+", whole: "0" } } } }],
40
+ ["-0", { number: { base_10: { integer: { sign: "-", whole: "0" } } } }],
41
+ ["0b010", { number: { base_2: "010" } }],
42
+ ["0o01234567", { number: { base_8: "01234567" } }],
43
+ [
44
+ "0x0123456789aAbBcCdDeEfF",
45
+ { number: { base_16: "0123456789aAbBcCdDeEfF" } },
46
+ ],
47
+ [
48
+ "10e20",
49
+ {
50
+ number: {
51
+ base_10: {
52
+ integer: {
53
+ whole: "10",
54
+ exponent: {
55
+ integer: {
56
+ whole: "20",
57
+ },
58
+ },
59
+ },
60
+ },
61
+ },
62
+ },
63
+ ],
64
+ [
65
+ "10.34e23.45",
66
+ {
67
+ number: {
68
+ base_10: {
69
+ decimal: {
70
+ whole: "10",
71
+ decimal: "34",
72
+ exponent: {
73
+ decimal: {
74
+ whole: "23",
75
+ decimal: "45",
76
+ },
77
+ },
78
+ },
79
+ },
80
+ },
81
+ },
82
+ ],
83
+ [
84
+ "+10e-20e1.0",
85
+ {
86
+ number: {
87
+ base_10: {
88
+ integer: {
89
+ sign: "+",
90
+ whole: "10",
91
+ exponent: {
92
+ integer: {
93
+ sign: "-",
94
+ whole: "20",
95
+ exponent: {
96
+ decimal: {
97
+ whole: "1",
98
+ decimal: "0",
99
+ },
100
+ },
101
+ },
102
+ },
103
+ },
104
+ },
105
+ },
106
+ },
107
+ ],
108
+ ].each do |(input, expected)|
109
+ context input.inspect do
110
+ let(:input) { input }
111
+
112
+ it "succeeds" do
113
+ expect(subject).to eq(expected)
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,30 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code::Parser::String do
4
+ subject { described_class.new.parse(input) }
5
+
6
+ [
7
+ ["'hello'", { string: "hello" }],
8
+ ['"hello"', { string: "hello" }],
9
+ ["''", { string: "" }],
10
+ ['""', { string: "" }],
11
+ ["'\\''", { string: "'" }],
12
+ ['"\\t"', { string: "\\t" }],
13
+ ["'\\r'", { string: "\\r" }],
14
+ ['"\\b\\f\\n\\r\\t"', { string: "\\b\\f\\n\\r\\t" }],
15
+ ['"\\uABCG"', { string: "uABCG" }],
16
+ [
17
+ "'\\u0123\\u4567\\u89aA\\ubBcC\\UdDeE\\ufFfF'",
18
+ { string: "\\u0123\\u4567\\u89aA\\ubBcC\\UdDeE\\ufFfF" },
19
+ ],
20
+ [":asc", { string: "asc" }],
21
+ ].each do |(input, expected)|
22
+ context input.inspect do
23
+ let(:input) { input }
24
+
25
+ it "succeeds" do
26
+ expect(subject).to eq(expected)
27
+ end
28
+ end
29
+ end
30
+ end
data/spec/code_spec.rb ADDED
@@ -0,0 +1,108 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code do
4
+ subject { described_class.evaluate(input).to_s }
5
+
6
+ [
7
+ ["nothing", ""],
8
+ ["null", ""],
9
+ ["nil", ""],
10
+ %w[true true],
11
+ %w[false false],
12
+ %w[1 1],
13
+ %w[1.2 1.2],
14
+ %w[0b10 2],
15
+ %w[0o10 8],
16
+ %w[0x10 16],
17
+ %w[1e2 100],
18
+ %w[1.2e2.2 190.1871830953336182242521644],
19
+ %w[1e1e1 10000000000],
20
+ %w['hello' hello],
21
+ %w["hello" hello],
22
+ ["[true, 1, nothing]", "[true, 1, nothing]"],
23
+ ['{a: 1, "b": 2}', '{"a" => 1, "b" => 2}'],
24
+ %w[!true false],
25
+ %w[!!true true],
26
+ %w[!!nothing false],
27
+ %w[!!1 true],
28
+ %w[+1 1],
29
+ %w[++++1 1],
30
+ ["++++nothing", ""],
31
+ %w[+{} {}],
32
+ ["2 ** 2", "4"],
33
+ ["2 ** 2 ** 3", "256"],
34
+ %w[-2 -2],
35
+ %w[--2 2],
36
+ ["2 * 3", "6"],
37
+ ["1 / 2", "0.5"],
38
+ ["1 / 2 / 2", "0.25"],
39
+ ["12 % 10", "2"],
40
+ ["8 / -2 ** 3", "-1.0"],
41
+ ["1 + 2 * 3 + 4", "11"],
42
+ ["1e1.1 * 2", "25.1785082358833442084790822"],
43
+ ["1 / 3 * 3", "0.999999999999999999999999999999999999"],
44
+ ['3 * "hello"', "hellohellohello"],
45
+ ['"Go" + "od"', "Good"],
46
+ ["1 << 2", "4"],
47
+ ["4 >> 2", "1"],
48
+ ["2 & 1", "0"],
49
+ ["2 | 1", "3"],
50
+ ["5 ^ 6", "3"],
51
+ ["5 > 6", "false"],
52
+ ["5 > 5", "false"],
53
+ ["5 > 4", "true"],
54
+ ["2 > 1 == 3 > 2", "true"],
55
+ ["true && false", "false"],
56
+ ["true || false", "true"],
57
+ %w[1..3 1..3],
58
+ ['1 > 3 ? "Impossible" : "Sounds about right"', "Sounds about right"],
59
+ ['1 < 3 ? "OK"', "OK"],
60
+ ['1 < "" rescue "oops"', "oops"],
61
+ ['"fine" rescue "oops"', "fine"],
62
+ ["a = 1", "1"],
63
+ ["a = 1 a * 2", "2"],
64
+ ["a = 1 a += 1 a", "2"],
65
+ ["a = 1 a -= 1 a", "0"],
66
+ %w[defined?(a) false],
67
+ ["a = 1 defined?(a)", "true"],
68
+ ["not true", "false"],
69
+ ["not false", "true"],
70
+ ["not not 1", "true"],
71
+ ["1 or 2", "1"],
72
+ ["true or false", "true"],
73
+ ["1 and 2", "2"],
74
+ ["false and 2", "false"],
75
+ ["true and false", "false"],
76
+ ["true and true", "true"],
77
+ ["1 if false", ""],
78
+ ["1 if true", "1"],
79
+ ["1 if true if true", "1"],
80
+ ["1 unless false", "1"],
81
+ ["1 unless true", ""],
82
+ ["a = 0 a += 1 while a < 10 a", "10"],
83
+ ["a = 0 a += 1 until a > 10 a", "11"],
84
+ ["if true 1 end", "1"],
85
+ ["if false 1 end", ""],
86
+ ["if false 1 else 2 end", "2"],
87
+ ["unless false 1 end", "1"],
88
+ ["unless true 1 end", ""],
89
+ ["if false 1 else if true 2 else 3 end", "2"],
90
+ ["if false 1 else if false 2 else 3 end", "3"],
91
+ ["unless false 1 else if false 2 else 3 end", "1"],
92
+ ["if false 1 else unless false 2 else 3 end", "2"],
93
+ ["a = 0\n while a < 10 a += 1 end a", "10"],
94
+ ["a = 0\n until a > 10 a += 1 end a", "11"],
95
+ ["until true end", ""],
96
+ ["until true\nend", ""],
97
+ %w[("Good".."Bad").first Good],
98
+ ['"Dorian " * 2', "Dorian Dorian "],
99
+ ].each do |(input, expected)|
100
+ context input.inspect do
101
+ let(:input) { input }
102
+
103
+ it "succeeds" do
104
+ expect(subject).to eq(expected)
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Code do
4
+ subject { described_class.evaluate(input).to_s }
5
+
6
+ [
7
+ ['hello = () => { "Hello" } hello', "Hello"],
8
+ ["add = (a, b) => { a + b } add(1, 2)", "3"],
9
+ ["add = (a:, b:) => { a + b } add(a: 1, b: 2)", "3"],
10
+ ["add = (a = 1, b = 2) => { a + b } add", "3"],
11
+ ["add = (a: 1, b: 2) => { a + b } add", "3"],
12
+ ["add = (*args) => { args.first + args.last } add(1, 2)", "3"],
13
+ [
14
+ "add = (**kargs) => { kargs.values.first + kargs.values.last } add(a: 1, b: 2)",
15
+ "3",
16
+ ],
17
+ ].each do |(input, expected)|
18
+ context input.inspect do
19
+ let(:input) { input }
20
+
21
+ it "succeeds" do
22
+ expect(subject).to eq(expected)
23
+ end
24
+ end
25
+ end
26
+ end