code-ruby 0.5.6 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -3
  3. data/Gemfile.lock +11 -21
  4. data/README.md +2 -102
  5. data/bin/code +34 -16
  6. data/code-ruby.gemspec +5 -3
  7. data/lib/code/error.rb +16 -5
  8. data/lib/code/node/base_10.rb +4 -2
  9. data/lib/code/node/base_16.rb +3 -1
  10. data/lib/code/node/base_2.rb +3 -1
  11. data/lib/code/node/base_8.rb +3 -1
  12. data/lib/code/node/boolean.rb +4 -2
  13. data/lib/code/node/call.rb +35 -12
  14. data/lib/code/node/call_argument.rb +16 -5
  15. data/lib/code/node/code.rb +5 -4
  16. data/lib/code/node/decimal.rb +2 -0
  17. data/lib/code/node/{dictionnary.rb → dictionary.rb} +14 -5
  18. data/lib/code/node/function.rb +7 -4
  19. data/lib/code/node/function_parameter.rb +3 -1
  20. data/lib/code/node/if.rb +5 -3
  21. data/lib/code/node/left_operation.rb +63 -0
  22. data/lib/code/node/list.rb +2 -0
  23. data/lib/code/node/negation.rb +2 -0
  24. data/lib/code/node/not.rb +2 -0
  25. data/lib/code/node/nothing.rb +3 -1
  26. data/lib/code/node/number.rb +2 -0
  27. data/lib/code/node/right_operation.rb +70 -0
  28. data/lib/code/node/splat.rb +2 -0
  29. data/lib/code/node/square_bracket.rb +37 -0
  30. data/lib/code/node/statement.rb +13 -5
  31. data/lib/code/node/string.rb +3 -1
  32. data/lib/code/node/ternary.rb +5 -3
  33. data/lib/code/node/unary_minus.rb +2 -0
  34. data/lib/code/node/while.rb +6 -4
  35. data/lib/code/node.rb +11 -5
  36. data/lib/code/object/argument.rb +13 -7
  37. data/lib/code/object/boolean.rb +43 -5
  38. data/lib/code/object/class.rb +17 -0
  39. data/lib/code/object/context.rb +36 -0
  40. data/lib/code/object/decimal.rb +252 -100
  41. data/lib/code/object/dictionary.rb +641 -0
  42. data/lib/code/object/function.rb +54 -27
  43. data/lib/code/object/global.rb +65 -19
  44. data/lib/code/object/identifier_list.rb +47 -0
  45. data/lib/code/object/integer.rb +320 -137
  46. data/lib/code/object/list.rb +140 -138
  47. data/lib/code/object/nothing.rb +10 -4
  48. data/lib/code/object/number.rb +6 -1
  49. data/lib/code/object/range.rb +85 -88
  50. data/lib/code/object/ruby_function.rb +11 -6
  51. data/lib/code/object/string.rb +51 -48
  52. data/lib/code/object.rb +117 -139
  53. data/lib/code/parser/addition.rb +4 -2
  54. data/lib/code/parser/and_operator.rb +4 -2
  55. data/lib/code/parser/bitwise_and.rb +4 -2
  56. data/lib/code/parser/bitwise_or.rb +4 -2
  57. data/lib/code/parser/boolean.rb +3 -1
  58. data/lib/code/parser/call.rb +17 -11
  59. data/lib/code/parser/chained_call.rb +10 -22
  60. data/lib/code/parser/class.rb +9 -6
  61. data/lib/code/parser/code.rb +6 -4
  62. data/lib/code/parser/{dictionnary.rb → dictionary.rb} +16 -13
  63. data/lib/code/parser/equal.rb +9 -36
  64. data/lib/code/parser/equality.rb +4 -2
  65. data/lib/code/parser/function.rb +24 -9
  66. data/lib/code/parser/greater.rb +6 -3
  67. data/lib/code/parser/group.rb +4 -2
  68. data/lib/code/parser/if.rb +6 -4
  69. data/lib/code/parser/if_modifier.rb +5 -25
  70. data/lib/code/parser/left_operation.rb +40 -0
  71. data/lib/code/parser/list.rb +6 -5
  72. data/lib/code/parser/multiplication.rb +4 -2
  73. data/lib/code/parser/name.rb +19 -4
  74. data/lib/code/parser/negation.rb +4 -2
  75. data/lib/code/parser/not_keyword.rb +5 -3
  76. data/lib/code/parser/nothing.rb +3 -10
  77. data/lib/code/parser/number.rb +4 -2
  78. data/lib/code/parser/or_keyword.rb +4 -2
  79. data/lib/code/parser/or_operator.rb +4 -2
  80. data/lib/code/parser/power.rb +4 -28
  81. data/lib/code/parser/range.rb +4 -2
  82. data/lib/code/parser/rescue.rb +6 -26
  83. data/lib/code/parser/right_operation.rb +40 -0
  84. data/lib/code/parser/shift.rb +4 -2
  85. data/lib/code/parser/splat.rb +5 -3
  86. data/lib/code/parser/square_bracket.rb +48 -0
  87. data/lib/code/parser/statement.rb +3 -1
  88. data/lib/code/parser/string.rb +12 -10
  89. data/lib/code/parser/ternary.rb +10 -11
  90. data/lib/code/parser/unary_minus.rb +5 -3
  91. data/lib/code/parser/while.rb +5 -3
  92. data/lib/code/parser/whitespace.rb +2 -0
  93. data/lib/code/parser.rb +10 -3
  94. data/lib/code/ruby.rb +4 -2
  95. data/lib/code/type/hash.rb +38 -0
  96. data/lib/code/type/maybe.rb +29 -0
  97. data/lib/code/type/or.rb +38 -0
  98. data/lib/code/type/repeat.rb +38 -0
  99. data/lib/code/type/sig.rb +130 -0
  100. data/lib/code/type.rb +25 -0
  101. data/lib/code/version.rb +3 -0
  102. data/lib/code-ruby.rb +1 -2
  103. data/lib/code.rb +15 -16
  104. data/spec/code/node/call_spec.rb +39 -0
  105. data/spec/code/object/boolean_spec.rb +18 -0
  106. data/spec/code/object/decimal_spec.rb +51 -0
  107. data/spec/code/object/dictionary_spec.rb +98 -0
  108. data/spec/code/object/function_spec.rb +42 -0
  109. data/spec/code/object/integer_spec.rb +43 -0
  110. data/spec/code/object/nothing_spec.rb +14 -0
  111. data/spec/code/object/range_spec.rb +23 -0
  112. data/spec/code/parser/boolean_spec.rb +5 -10
  113. data/spec/code/parser/chained_call.rb +4 -5
  114. data/spec/code/parser/{dictionnary_spec.rb → dictionary_spec.rb} +5 -6
  115. data/spec/code/parser/function_spec.rb +4 -5
  116. data/spec/code/parser/group_spec.rb +5 -12
  117. data/spec/code/parser/if_modifier_spec.rb +18 -0
  118. data/spec/code/parser/list_spec.rb +4 -5
  119. data/spec/code/parser/number_spec.rb +4 -5
  120. data/spec/code/parser/string_spec.rb +4 -5
  121. data/spec/code/parser_spec.rb +22 -16
  122. data/spec/code/type_spec.rb +21 -0
  123. data/spec/code_spec.rb +171 -0
  124. data/spec/spec_helper.rb +1 -6
  125. metadata +63 -136
  126. data/.cherry.js +0 -21
  127. data/.editorconfig +0 -9
  128. data/.github/workflows/rspec.yml +0 -14
  129. data/.gitignore +0 -2
  130. data/.prettierrc +0 -3
  131. data/.tool-versions +0 -1
  132. data/CHANGELOG.md +0 -55
  133. data/LICENSE +0 -7
  134. data/TODO +0 -17
  135. data/bin/format +0 -3
  136. data/bin/publish +0 -19
  137. data/bin/template +0 -85
  138. data/bin/test +0 -17
  139. data/docs/class.code +0 -9
  140. data/docs/euler/1.template +0 -10
  141. data/docs/euler/2.template +0 -16
  142. data/docs/euler/3.template +0 -16
  143. data/docs/euler/4.template +0 -10
  144. data/docs/euler/5.template +0 -13
  145. data/docs/fibonnaci.template +0 -14
  146. data/docs/meetup.code +0 -12
  147. data/docs/precedence.template +0 -36
  148. data/docs/rain.code +0 -22
  149. data/docs/slack.code +0 -17
  150. data/docs/stripe.code +0 -7
  151. data/docs/twitter.code +0 -9
  152. data/language-ruby.gemspec +0 -17
  153. data/lib/code/node/chained_call.rb +0 -23
  154. data/lib/code/node/equal.rb +0 -34
  155. data/lib/code/node/if_modifier.rb +0 -47
  156. data/lib/code/node/operation.rb +0 -38
  157. data/lib/code/node/power.rb +0 -20
  158. data/lib/code/node/rescue.rb +0 -17
  159. data/lib/code/object/dictionnary.rb +0 -96
  160. data/lib/code/parser/equality_lower.rb +0 -9
  161. data/lib/code/parser/operation.rb +0 -35
  162. data/lib/language/atom.rb +0 -342
  163. data/lib/language/output.rb +0 -130
  164. data/lib/language/parser/absent/present.rb +0 -8
  165. data/lib/language/parser/absent.rb +0 -6
  166. data/lib/language/parser/end_of_input.rb +0 -6
  167. data/lib/language/parser/interuption.rb +0 -38
  168. data/lib/language/parser/not_end_of_input.rb +0 -6
  169. data/lib/language/parser/str/not_found.rb +0 -16
  170. data/lib/language/parser/str.rb +0 -6
  171. data/lib/language/parser.rb +0 -53
  172. data/lib/language-ruby.rb +0 -10
  173. data/lib/language.rb +0 -80
  174. data/lib/template/node/code_part.rb +0 -13
  175. data/lib/template/node/part.rb +0 -19
  176. data/lib/template/node/template.rb +0 -15
  177. data/lib/template/node/text_part.rb +0 -13
  178. data/lib/template/node.rb +0 -4
  179. data/lib/template/parser/template.rb +0 -39
  180. data/lib/template/parser.rb +0 -19
  181. data/lib/template/version.rb +0 -3
  182. data/lib/template-ruby.rb +0 -10
  183. data/lib/template.rb +0 -50
  184. data/spec/code/addition_spec.rb +0 -13
  185. data/spec/code/and_operator_spec.rb +0 -13
  186. data/spec/code/bitwise_and_spec.rb +0 -13
  187. data/spec/code/bitwise_or_spec.rb +0 -13
  188. data/spec/code/boolean_spec.rb +0 -13
  189. data/spec/code/call_spec.rb +0 -21
  190. data/spec/code/chained_call_spec.rb +0 -16
  191. data/spec/code/code_spec.rb +0 -29
  192. data/spec/code/dictionnary_spec.rb +0 -17
  193. data/spec/code/equal_spec.rb +0 -26
  194. data/spec/code/equality_spec.rb +0 -13
  195. data/spec/code/function_spec.rb +0 -18
  196. data/spec/code/greater_spec.rb +0 -18
  197. data/spec/code/group_spec.rb +0 -12
  198. data/spec/code/if_modifier_spec.rb +0 -20
  199. data/spec/code/if_spec.rb +0 -25
  200. data/spec/code/list_spec.rb +0 -19
  201. data/spec/code/multiplication_spec.rb +0 -18
  202. data/spec/code/negation_spec.rb +0 -20
  203. data/spec/code/not_keyword_spec.rb +0 -13
  204. data/spec/code/nothing_spec.rb +0 -17
  205. data/spec/code/number_spec.rb +0 -22
  206. data/spec/code/or_keyword_spec.rb +0 -17
  207. data/spec/code/or_operator_spec.rb +0 -16
  208. data/spec/code/parser/call_spec.rb +0 -26
  209. data/spec/code/power_spec.rb +0 -13
  210. data/spec/code/range_spec.rb +0 -16
  211. data/spec/code/rescue_spec.rb +0 -13
  212. data/spec/code/shift_spec.rb +0 -13
  213. data/spec/code/splat_spec.rb +0 -13
  214. data/spec/code/string_spec.rb +0 -27
  215. data/spec/code/ternary_spec.rb +0 -18
  216. data/spec/code/unary_minus_spec.rb +0 -13
  217. data/spec/code/while_spec.rb +0 -18
  218. 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
@@ -0,0 +1,3 @@
1
+ require_relative "../code"
2
+
3
+ Code::Version = Gem::Version.new("0.6.1")
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 = Template::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: io, timeout: timeout, ruby: ruby).evaluate(context)
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
- if context != EMPTY_STRING
27
- context = ::Code.evaluate(context, timeout: timeout, io: io, ruby: ruby)
28
- else
29
- context = ::Code::Object::Dictionnary.new
30
- end
31
-
32
- if !context.is_a?(::Code::Object::Dictionnary)
33
- raise ::Code::Error::IncompatibleContext.new(
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
- ::Code::Node::Code.new(parsed).evaluate(context: context, io: io)
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
- subject { Code::Parser.parse(input) }
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
- context input do
13
- let(:input) { input }
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
- require "spec_helper"
1
+ # frozen_string_literal: true
2
2
 
3
- RSpec.describe Code::Parser::Dictionnary do
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
- context input do
14
- let(:input) { input }
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
- context input do
12
- let(:input) { input }
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
- subject { Code::Parser.parse(input) }
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
- context input do
14
- let(:input) { input }
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
- context input do
8
- let(:input) { input }
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
- context input do
17
- let(:input) { input }
18
- it { subject }
16
+ it "parses #{input}" do
17
+ Code::Parser.parse(input)
19
18
  end
20
19
  end
21
20
  end