code-ruby 0.3.1 → 0.5.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.
Files changed (206) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/CHANGELOG.md +5 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +28 -55
  6. data/TODO +17 -0
  7. data/bin/code +56 -31
  8. data/bin/format +3 -0
  9. data/bin/template +62 -20
  10. data/bin/test +17 -0
  11. data/code-ruby.gemspec +1 -6
  12. data/docs/class.code +9 -0
  13. data/docs/euler/1.template +1 -5
  14. data/docs/euler/5.template +0 -1
  15. data/docs/meetup.code +12 -0
  16. data/docs/precedence.template +6 -39
  17. data/docs/rain.code +22 -0
  18. data/docs/slack.code +17 -0
  19. data/docs/stripe.code +7 -0
  20. data/docs/twitter.code +9 -0
  21. data/language-ruby.gemspec +18 -0
  22. data/lib/code/error.rb +3 -0
  23. data/lib/code/node/base_10.rb +29 -0
  24. data/lib/code/node/base_16.rb +13 -0
  25. data/lib/code/node/base_2.rb +13 -0
  26. data/lib/code/node/base_8.rb +13 -0
  27. data/lib/code/node/boolean.rb +7 -7
  28. data/lib/code/node/call.rb +32 -37
  29. data/lib/code/node/call_argument.rb +11 -27
  30. data/lib/code/node/chained_call.rb +10 -25
  31. data/lib/code/node/code.rb +4 -6
  32. data/lib/code/node/decimal.rb +26 -0
  33. data/lib/code/node/dictionnary.rb +20 -9
  34. data/lib/code/node/equal.rb +18 -20
  35. data/lib/code/node/function.rb +10 -7
  36. data/lib/code/node/function_parameter.rb +31 -0
  37. data/lib/code/node/if.rb +36 -32
  38. data/lib/code/node/if_modifier.rb +35 -36
  39. data/lib/code/node/list.rb +6 -9
  40. data/lib/code/node/negation.rb +5 -23
  41. data/lib/code/node/not.rb +15 -0
  42. data/lib/code/node/nothing.rb +1 -1
  43. data/lib/code/node/number.rb +14 -12
  44. data/lib/code/node/operation.rb +21 -16
  45. data/lib/code/node/power.rb +10 -6
  46. data/lib/code/node/rescue.rb +4 -3
  47. data/lib/code/node/splat.rb +15 -0
  48. data/lib/code/node/statement.rb +47 -69
  49. data/lib/code/node/string.rb +41 -10
  50. data/lib/code/node/ternary.rb +7 -9
  51. data/lib/code/node/unary_minus.rb +5 -12
  52. data/lib/code/node/while.rb +17 -24
  53. data/lib/code/node.rb +7 -8
  54. data/lib/code/object/argument.rb +3 -12
  55. data/lib/code/object/decimal.rb +114 -27
  56. data/lib/code/object/dictionnary.rb +29 -12
  57. data/lib/code/object/function.rb +23 -24
  58. data/lib/code/object/global.rb +42 -0
  59. data/lib/code/object/integer.rb +142 -35
  60. data/lib/code/object/list.rb +74 -95
  61. data/lib/code/object/range.rb +38 -50
  62. data/lib/code/object/ruby_function.rb +31 -0
  63. data/lib/code/object/string.rb +36 -16
  64. data/lib/code/object.rb +114 -54
  65. data/lib/code/parser/addition.rb +12 -20
  66. data/lib/code/parser/and_operator.rb +9 -20
  67. data/lib/code/parser/bitwise_and.rb +9 -20
  68. data/lib/code/parser/bitwise_or.rb +12 -20
  69. data/lib/code/parser/boolean.rb +10 -7
  70. data/lib/code/parser/call.rb +92 -60
  71. data/lib/code/parser/chained_call.rb +47 -0
  72. data/lib/code/parser/class.rb +45 -0
  73. data/lib/code/parser/code.rb +17 -10
  74. data/lib/code/parser/dictionnary.rb +56 -30
  75. data/lib/code/parser/equal.rb +87 -35
  76. data/lib/code/parser/equality.rb +23 -24
  77. data/lib/code/parser/equality_lower.rb +9 -0
  78. data/lib/code/parser/function.rb +67 -40
  79. data/lib/code/parser/greater.rb +25 -0
  80. data/lib/code/parser/group.rb +13 -8
  81. data/lib/code/parser/if.rb +51 -21
  82. data/lib/code/parser/if_modifier.rb +43 -16
  83. data/lib/code/parser/list.rb +32 -19
  84. data/lib/code/parser/multiplication.rb +15 -20
  85. data/lib/code/parser/name.rb +96 -84
  86. data/lib/code/parser/negation.rb +20 -9
  87. data/lib/code/parser/not_keyword.rb +14 -12
  88. data/lib/code/parser/nothing.rb +13 -8
  89. data/lib/code/parser/number.rb +124 -68
  90. data/lib/code/parser/operation.rb +35 -0
  91. data/lib/code/parser/or_keyword.rb +12 -20
  92. data/lib/code/parser/or_operator.rb +9 -20
  93. data/lib/code/parser/power.rb +32 -14
  94. data/lib/code/parser/range.rb +9 -17
  95. data/lib/code/parser/rescue.rb +29 -13
  96. data/lib/code/parser/shift.rb +11 -21
  97. data/lib/code/parser/splat.rb +31 -0
  98. data/lib/code/parser/statement.rb +4 -3
  99. data/lib/code/parser/string.rb +53 -62
  100. data/lib/code/parser/ternary.rb +36 -15
  101. data/lib/code/parser/unary_minus.rb +23 -5
  102. data/lib/code/parser/while.rb +26 -15
  103. data/lib/code/parser/whitespace.rb +49 -0
  104. data/lib/code/parser.rb +15 -0
  105. data/lib/code/ruby.rb +162 -0
  106. data/lib/code-ruby.rb +2 -5
  107. data/lib/code.rb +24 -7
  108. data/lib/language/atom.rb +343 -0
  109. data/lib/language/output.rb +130 -0
  110. data/lib/language/parser/absent/present.rb +8 -0
  111. data/lib/language/parser/absent.rb +6 -0
  112. data/lib/language/parser/end_of_input.rb +6 -0
  113. data/lib/language/parser/interuption.rb +38 -0
  114. data/lib/language/parser/not_end_of_input.rb +6 -0
  115. data/lib/language/parser/str/not_found.rb +16 -0
  116. data/lib/language/parser/str.rb +6 -0
  117. data/lib/language/parser.rb +53 -0
  118. data/lib/language-ruby.rb +10 -0
  119. data/lib/language.rb +80 -0
  120. data/lib/template/node/code_part.rb +1 -1
  121. data/lib/template/node/part.rb +1 -1
  122. data/lib/template/node/template.rb +1 -1
  123. data/lib/template/node/text_part.rb +1 -1
  124. data/lib/template/node.rb +1 -1
  125. data/lib/template/parser/template.rb +26 -17
  126. data/lib/template/parser.rb +15 -0
  127. data/lib/template/version.rb +1 -1
  128. data/lib/template-ruby.rb +2 -5
  129. data/lib/template.rb +23 -13
  130. data/spec/code/addition_spec.rb +13 -0
  131. data/spec/code/and_operator_spec.rb +13 -0
  132. data/spec/code/bitwise_and_spec.rb +13 -0
  133. data/spec/code/bitwise_or_spec.rb +13 -0
  134. data/spec/code/boolean_spec.rb +13 -0
  135. data/spec/code/call_spec.rb +21 -0
  136. data/spec/code/chained_call_spec.rb +16 -0
  137. data/spec/code/dictionnary_spec.rb +17 -0
  138. data/spec/code/equal_spec.rb +26 -0
  139. data/spec/code/equality_spec.rb +13 -0
  140. data/spec/code/function_spec.rb +18 -0
  141. data/spec/code/greater_spec.rb +18 -0
  142. data/spec/code/group_spec.rb +12 -0
  143. data/spec/code/if_modifier_spec.rb +20 -0
  144. data/spec/code/if_spec.rb +25 -0
  145. data/spec/code/list_spec.rb +17 -0
  146. data/spec/code/multiplication_spec.rb +18 -0
  147. data/spec/code/negation_spec.rb +20 -0
  148. data/spec/code/not_keyword_spec.rb +13 -0
  149. data/spec/code/nothing_spec.rb +17 -0
  150. data/spec/code/number_spec.rb +22 -0
  151. data/spec/code/or_keyword_spec.rb +17 -0
  152. data/spec/code/or_operator_spec.rb +16 -0
  153. data/spec/code/parser/boolean_spec.rb +5 -7
  154. data/spec/code/parser/call_spec.rb +16 -56
  155. data/spec/code/parser/chained_call.rb +17 -0
  156. data/spec/code/parser/dictionnary_spec.rb +8 -9
  157. data/spec/code/parser/function_spec.rb +5 -21
  158. data/spec/code/parser/group_spec.rb +18 -0
  159. data/spec/code/parser/list_spec.rb +9 -20
  160. data/spec/code/parser/number_spec.rb +4 -109
  161. data/spec/code/parser/string_spec.rb +9 -17
  162. data/spec/code/parser_spec.rb +23 -0
  163. data/spec/code/power_spec.rb +13 -0
  164. data/spec/code/range_spec.rb +16 -0
  165. data/spec/code/rescue_spec.rb +13 -0
  166. data/spec/code/shift_spec.rb +13 -0
  167. data/spec/code/splat_spec.rb +13 -0
  168. data/spec/code/string_spec.rb +25 -0
  169. data/spec/code/ternary_spec.rb +18 -0
  170. data/spec/code/unary_minus_spec.rb +13 -0
  171. data/spec/code/while_spec.rb +18 -0
  172. data/spec/spec_helper.rb +4 -1
  173. data/template-ruby.gemspec +2 -7
  174. metadata +113 -99
  175. data/lib/code/node/base_10_decimal.rb +0 -32
  176. data/lib/code/node/base_10_integer.rb +0 -32
  177. data/lib/code/node/base_10_number.rb +0 -19
  178. data/lib/code/node/base_16_number.rb +0 -19
  179. data/lib/code/node/base_2_number.rb +0 -19
  180. data/lib/code/node/base_8_number.rb +0 -19
  181. data/lib/code/node/block.rb +0 -17
  182. data/lib/code/node/defined.rb +0 -19
  183. data/lib/code/node/dictionnary_key_value.rb +0 -23
  184. data/lib/code/node/function_argument.rb +0 -45
  185. data/lib/code/node/group.rb +0 -13
  186. data/lib/code/node/keyword_call_argument.rb +0 -30
  187. data/lib/code/node/keyword_function_argument.rb +0 -33
  188. data/lib/code/node/name.rb +0 -55
  189. data/lib/code/node/not_keyword.rb +0 -13
  190. data/lib/code/node/or_keyword.rb +0 -34
  191. data/lib/code/node/range.rb +0 -31
  192. data/lib/code/node/regular_call_argument.rb +0 -34
  193. data/lib/code/node/regular_function_argument.rb +0 -36
  194. data/lib/code/node/string_characters.rb +0 -13
  195. data/lib/code/node/string_component.rb +0 -23
  196. data/lib/code/node/string_interpolation.rb +0 -13
  197. data/lib/code/parser/defined.rb +0 -20
  198. data/lib/code/parser/greater_than.rb +0 -33
  199. data/spec/call_spec.rb +0 -22
  200. data/spec/code/error/type_error_spec.rb +0 -63
  201. data/spec/code/parser/name_spec.rb +0 -15
  202. data/spec/code/parser/nothing_spec.rb +0 -19
  203. data/spec/code_spec.rb +0 -120
  204. data/spec/function_spec.rb +0 -26
  205. data/spec/template/parser/template_spec.rb +0 -19
  206. data/spec/template_spec.rb +0 -33
@@ -0,0 +1,38 @@
1
+ class Language
2
+ class Parser
3
+ class Interuption < StandardError
4
+ def initialize(parser, atom = Atom.new)
5
+ @parser = parser
6
+ @atom = atom
7
+ end
8
+
9
+ def message
10
+ "\n#{line}#{" " * column_index}^\n"
11
+ end
12
+
13
+ def line
14
+ l = input.lines[line_index]
15
+ l += "\n" if l[-1] != "\n"
16
+ l
17
+ end
18
+
19
+ def line_index
20
+ input[...cursor].count("\n")
21
+ end
22
+
23
+ def column_index
24
+ cursor - input.lines[...line_index].map(&:size).sum
25
+ end
26
+
27
+ private
28
+
29
+ def cursor
30
+ @parser.cursor
31
+ end
32
+
33
+ def input
34
+ @parser.input
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,6 @@
1
+ class Language
2
+ class Parser
3
+ class NotEndOfInput < Interuption
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,16 @@
1
+ class Language
2
+ class Parser
3
+ class Str
4
+ class NotFound < Interuption
5
+ def initialize(parser, string)
6
+ @parser = parser
7
+ @string = string
8
+ end
9
+
10
+ def message
11
+ "#{@string} not found\n#{super}"
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ class Language
2
+ class Parser
3
+ class Str
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,53 @@
1
+ class Language
2
+ class Parser
3
+ attr_accessor :input, :buffer, :output, :root, :cursor
4
+
5
+ def initialize(root:, input:, cursor: 0, buffer: "", output: Output.new)
6
+ @root = root
7
+ @input = input
8
+ @cursor = cursor
9
+ @buffer = buffer
10
+ @output = output
11
+ end
12
+
13
+ def parse(check_end_of_input: true)
14
+ @root.parse(self)
15
+
16
+ if @cursor == @input.size || !check_end_of_input
17
+ @output.present? ? @output : Output.new(@buffer)
18
+ else
19
+ raise NotEndOfInput.new(self)
20
+ end
21
+ end
22
+
23
+ def consume(n)
24
+ if @cursor + n <= @input.size
25
+ @buffer += @input[@cursor, n]
26
+ @cursor += n
27
+ else
28
+ raise EndOfInput.new(self)
29
+ end
30
+ end
31
+
32
+ def aka(name)
33
+ if @buffer.empty?
34
+ @output = Output.new({ name => @output })
35
+ else
36
+ @output[name] = Output.new(@buffer)
37
+ @buffer = ""
38
+ end
39
+ end
40
+
41
+ def next?(string)
42
+ @input[@cursor...(@cursor + string.size)] == string
43
+ end
44
+
45
+ def buffer?
46
+ @buffer != ""
47
+ end
48
+
49
+ def output?
50
+ @output.present?
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,10 @@
1
+ require "bigdecimal"
2
+ require "stringio"
3
+ require "timeout"
4
+ require "zeitwerk"
5
+
6
+ loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
7
+ loader.ignore("#{__dir__}/template-ruby.rb")
8
+ loader.ignore("#{__dir__}/code-ruby.rb")
9
+ loader.ignore("#{__dir__}/language-ruby.rb")
10
+ loader.setup
data/lib/language.rb ADDED
@@ -0,0 +1,80 @@
1
+ class Language
2
+ def self.parse(input)
3
+ new.parse(input)
4
+ end
5
+
6
+ def self.absent
7
+ Atom::Absent.new(parent: new)
8
+ end
9
+
10
+ def self.ignore
11
+ Atom::Ignore.new(parent: new)
12
+ end
13
+
14
+ def self.maybe
15
+ Atom::Maybe.new(parent: new)
16
+ end
17
+
18
+ def self.repeat(min = 0, max = nil)
19
+ Atom::Repeat.new(parent: new, min: min, max: max)
20
+ end
21
+
22
+ def self.aka(name)
23
+ Atom::Aka.new(parent: new, name: name)
24
+ end
25
+
26
+ def self.|(other)
27
+ Atom::Or.new(left: new, right: other)
28
+ end
29
+
30
+ def self.>>(other)
31
+ Atom::And.new(left: new, right: other)
32
+ end
33
+
34
+ def self.<<(other)
35
+ Atom::And.new(left: new, right: other)
36
+ end
37
+
38
+ def self.then(&block)
39
+ Atom::Then.new(parent: new, block: block)
40
+ end
41
+
42
+ def parse(input_or_parser)
43
+ if input_or_parser.is_a?(Parser)
44
+ parser = input_or_parser
45
+ clone =
46
+ Parser.new(
47
+ root: root,
48
+ input: parser.input,
49
+ cursor: parser.cursor,
50
+ buffer: parser.buffer,
51
+ output: parser.output
52
+ )
53
+
54
+ clone.parse(check_end_of_input: false)
55
+
56
+ parser.cursor = clone.cursor
57
+ parser.buffer = clone.buffer
58
+ parser.output = clone.output
59
+ else
60
+ input = input_or_parser
61
+ Parser.new(root: root, input: input).parse
62
+ end
63
+ end
64
+
65
+ def str(string)
66
+ Atom::Str.new(string: string)
67
+ end
68
+
69
+ def any
70
+ Atom::Any.new
71
+ end
72
+
73
+ def to_s
74
+ "<#{self.class.name}>"
75
+ end
76
+
77
+ def inspect
78
+ to_s
79
+ end
80
+ end
@@ -1,6 +1,6 @@
1
1
  class Template
2
2
  class Node
3
- class CodePart
3
+ class CodePart < Node
4
4
  def initialize(code)
5
5
  @code = ::Code::Node::Code.new(code)
6
6
  end
@@ -1,6 +1,6 @@
1
1
  class Template
2
2
  class Node
3
- class Part
3
+ class Part < Node
4
4
  def initialize(part)
5
5
  if part.key?(:text)
6
6
  @part = ::Template::Node::TextPart.new(part[:text])
@@ -1,6 +1,6 @@
1
1
  class Template
2
2
  class Node
3
- class Template
3
+ class Template < Node
4
4
  def initialize(parts)
5
5
  @parts = parts.map { |part| ::Template::Node::Part.new(part) }
6
6
  end
@@ -1,6 +1,6 @@
1
1
  class Template
2
2
  class Node
3
- class TextPart
3
+ class TextPart < Node
4
4
  def initialize(text)
5
5
  @text = text
6
6
  end
data/lib/template/node.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  class Template
2
- class Node
2
+ class Node < ::Code::Node
3
3
  end
4
4
  end
@@ -1,30 +1,39 @@
1
1
  class Template
2
2
  class Parser
3
- class Template < Parslet::Parser
4
- rule(:code) { ::Code::Parser::Code.new }
3
+ class Template < Language
4
+ def code
5
+ ::Code::Parser::Code
6
+ end
7
+
8
+ def opening_curly_bracket
9
+ str("{")
10
+ end
5
11
 
6
- rule(:left_curly_bracket) { str("{") }
7
- rule(:right_curly_bracket) { str("}") }
8
- rule(:escape) { str("\\") }
12
+ def closing_curly_bracket
13
+ str("}")
14
+ end
9
15
 
10
- rule(:text_part) do
11
- (
12
- (escape.ignore >> left_curly_bracket) |
13
- (left_curly_bracket.absent? >> any)
14
- ).repeat(1)
16
+ def backslash
17
+ str("\\")
15
18
  end
16
19
 
17
- rule(:code_part) do
18
- left_curly_bracket.ignore >> code >>
19
- (right_curly_bracket.ignore | any.absent?)
20
+ def code_part
21
+ opening_curly_bracket << code << (closing_curly_bracket | any.absent)
20
22
  end
21
23
 
22
- rule(:template) do
23
- (text_part.as(:text) | code_part.as(:code)).repeat(1) |
24
- str("").as(:text).repeat(1, 1)
24
+ def text_character
25
+ (backslash.ignore << opening_curly_bracket) |
26
+ (opening_curly_bracket.absent << any)
25
27
  end
26
28
 
27
- root(:template)
29
+ def text_part
30
+ text_character.repeat(1)
31
+ end
32
+
33
+ def root
34
+ (code_part.aka(:code) | text_part.aka(:text)).repeat |
35
+ str("").aka(:text).repeat(1, 1)
36
+ end
28
37
  end
29
38
  end
30
39
  end
@@ -1,4 +1,19 @@
1
1
  class Template
2
2
  class Parser
3
+ def initialize(input)
4
+ @input = input
5
+ end
6
+
7
+ def self.parse(input)
8
+ new(input).parse
9
+ end
10
+
11
+ def parse
12
+ ::Template::Parser::Template.parse(input)
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :input
3
18
  end
4
19
  end
@@ -1,3 +1,3 @@
1
1
  require_relative "../template"
2
2
 
3
- Template::Version = Gem::Version.new("0.3.1")
3
+ Template::Version = Gem::Version.new("0.5.0")
data/lib/template-ruby.rb CHANGED
@@ -1,13 +1,10 @@
1
- require "parslet"
2
- require "zeitwerk"
3
1
  require "bigdecimal"
4
- require "active_support"
5
- require "active_support/core_ext/object/blank"
6
- require "active_support/core_ext/object/deep_dup"
7
2
  require "stringio"
8
3
  require "timeout"
4
+ require "zeitwerk"
9
5
 
10
6
  loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
11
7
  loader.ignore("#{__dir__}/template-ruby.rb")
12
8
  loader.ignore("#{__dir__}/code-ruby.rb")
9
+ loader.ignore("#{__dir__}/language-ruby.rb")
13
10
  loader.setup
data/lib/template.rb CHANGED
@@ -1,32 +1,42 @@
1
1
  class Template
2
2
  DEFAULT_TIMEOUT = 10
3
3
 
4
- def initialize(input, io: StringIO.new, timeout: DEFAULT_TIMEOUT)
4
+ def initialize(input, io: StringIO.new, timeout: DEFAULT_TIMEOUT, ruby: {})
5
5
  @input = input
6
6
  @parsed =
7
- Timeout.timeout(timeout) do
8
- ::Template::Parser::Template.new.parse(@input)
9
- end
7
+ Timeout.timeout(timeout) { ::Template::Parser.parse(@input).to_raw }
10
8
  @io = io
11
9
  @timeout = timeout || DEFAULT_TIMEOUT
10
+ @ruby = ::Code::Ruby.to_code(ruby || {})
12
11
  end
13
12
 
14
- def self.render(input, context = "", io: StringIO.new, timeout: DEFAULT_TIMEOUT)
15
- new(input, io: io, timeout: timeout).render(context)
13
+ def self.render(
14
+ input,
15
+ context = "",
16
+ io: StringIO.new,
17
+ timeout: DEFAULT_TIMEOUT,
18
+ ruby: {}
19
+ )
20
+ new(input, io: io, timeout: timeout, ruby: ruby).render(context)
16
21
  end
17
22
 
18
23
  def render(context = "")
19
24
  Timeout.timeout(timeout) do
20
- if context.present?
21
- context = ::Code.evaluate(context, timeout: timeout)
25
+ if context != ""
26
+ context = ::Code.evaluate(context, timeout: timeout, io: io, ruby: ruby)
22
27
  else
23
28
  context = ::Code::Object::Dictionnary.new
24
29
  end
25
30
 
26
- ::Template::Node::Template.new(parsed).evaluate(
27
- context: context,
28
- io: io,
29
- )
31
+ if !context.is_a?(::Code::Object::Dictionnary)
32
+ raise ::Code::Template::IncompatibleContext.new(
33
+ "context must be a dictionnary"
34
+ )
35
+ end
36
+
37
+ context = context.merge(ruby)
38
+
39
+ ::Template::Node::Template.new(parsed).evaluate(context: context, io: io)
30
40
 
31
41
  io.is_a?(StringIO) ? io.string : nil
32
42
  end
@@ -34,7 +44,7 @@ class Template
34
44
 
35
45
  private
36
46
 
37
- attr_reader :parsed, :io, :timeout
47
+ attr_reader :parsed, :io, :timeout, :ruby
38
48
  end
39
49
 
40
50
  require_relative "template/version"
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "function" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
7
+ [["1 + 2", "3"], ["2 - 1", "1"], ["a = 2 - 1 a", "1"]].each do |input, output|
8
+ context input do
9
+ let(:input) { input }
10
+ it { expect(subject).to eq(output) }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "and operator" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
7
+ [["true && false", "false"], ["true && true", "true"]].each do |input, output|
8
+ context input do
9
+ let(:input) { input }
10
+ it { expect(subject).to eq(output) }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "bitwise and" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
7
+ [["1 & 1", "1"]].each do |input, output|
8
+ context input do
9
+ let(:input) { input }
10
+ it { expect(subject).to eq(output) }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "bitwise or" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
7
+ [["1 | 2", "3"], ["1 ^ 2", "3"]].each do |input, output|
8
+ context input do
9
+ let(:input) { input }
10
+ it { expect(subject).to eq(output) }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "boolean" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
7
+ [%w[true true], %w[false false]].each do |input, output|
8
+ context input do
9
+ let(:input) { input }
10
+ it { expect(subject).to eq(output) }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "call" do
4
+ let(:timeout) { 0 }
5
+
6
+ context "inspecting the io" do
7
+ let(:io) { StringIO.new }
8
+
9
+ subject do
10
+ Code.evaluate(input, io: io, timeout: timeout)
11
+ io.string
12
+ end
13
+
14
+ [["puts(true)", "true\n"], %w[print(false) false]].each do |input, output|
15
+ context input do
16
+ let(:input) { input }
17
+ it { expect(subject).to eq(output) }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "chained call" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
7
+ [
8
+ ["[1, 2, 3].select { |n| n.even? }", "[2]"],
9
+ ["[1, 2, 3].select { |n| n.even? }.select { |n| n.odd? }", "[]"]
10
+ ].each do |input, output|
11
+ context input do
12
+ let(:input) { input }
13
+ it { expect(subject).to eq(output) }
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "dictionnary" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
7
+ [
8
+ %w[{} {}],
9
+ ["{ a: 1, b: 2, c: 3 }", '{"a" => 1, "b" => 2, "c" => 3}'],
10
+ ['{ "first_name": "Dorian" }', '{"first_name" => "Dorian"}']
11
+ ].each do |input, output|
12
+ context input do
13
+ let(:input) { input }
14
+ it { expect(subject).to eq(output) }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "function" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
7
+ [
8
+ ["a = 1 a", "1"],
9
+ ["a = 1 a += 1 a", "2"],
10
+ ["a = 1 a -= 1 a", "0"],
11
+ ["a = 1 a *= 2 a", "2"],
12
+ ["a = 1 a /= 2 a", "0.5"],
13
+ ["a = 10 a %= 2 a", "0"],
14
+ ["a = 1 a >>= 1 a", "0"],
15
+ ["a = 1 a <<= 1 a", "2"],
16
+ ["a = 1 a |= 2 a", "3"],
17
+ ["a = 1 a ^= 2 a", "3"],
18
+ ["a = false a ||= true a", "true"],
19
+ ["a = false a &&= true a", "false"]
20
+ ].each do |input, output|
21
+ context input do
22
+ let(:input) { input }
23
+ it { expect(subject).to eq(output) }
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "while" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
7
+ [["1 == 1", "true"], ["1 == 1 and 2 == 2", "true"]].each do |input, output|
8
+ context input do
9
+ let(:input) { input }
10
+ it { expect(subject).to eq(output) }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "function" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
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, output|
13
+ context input do
14
+ let(:input) { input }
15
+ it { expect(subject).to eq(output) }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "greater" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
7
+ [
8
+ ["1 > 2", "false"],
9
+ ["1 < 2", "true"],
10
+ ["1 <= 1", "true"],
11
+ ["1 >= 1", "true"]
12
+ ].each do |input, output|
13
+ context input do
14
+ let(:input) { input }
15
+ it { expect(subject).to eq(output) }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "group" do
4
+ subject { Code.evaluate(input).to_s }
5
+
6
+ [["(true false)", "false"]].each do |input, output|
7
+ context input do
8
+ let(:input) { input }
9
+ it { expect(subject).to eq(output) }
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe "if modifier" do
4
+ let(:timeout) { 0 }
5
+ subject { Code.evaluate(input, timeout: timeout).to_s }
6
+
7
+ [
8
+ ["1 if true", "1"],
9
+ ["1 if false", ""],
10
+ ["1 unless true", ""],
11
+ ["1 unless false", "1"],
12
+ ["a = 0 a += 1 while a < 10 a", "10"],
13
+ ["a = 0 a += 1 until a > 10 a", "11"]
14
+ ].each do |input, output|
15
+ context input do
16
+ let(:input) { input }
17
+ it { expect(subject).to eq(output) }
18
+ end
19
+ end
20
+ end