template-ruby 0.2.3 → 0.3.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec.yml +14 -0
  3. data/CHANGELOG.md +20 -0
  4. data/Gemfile +2 -1
  5. data/Gemfile.lock +6 -1
  6. data/LICENSE +7 -0
  7. data/README.md +98 -5
  8. data/bin/code +51 -0
  9. data/bin/template +9 -5
  10. data/code-ruby.gemspec +22 -0
  11. data/docs/euler/4.template +0 -1
  12. data/docs/fibonnaci.template +14 -0
  13. data/docs/precedence.template +6 -31
  14. data/lib/code/node/code.rb +7 -1
  15. data/lib/code/node/list.rb +7 -7
  16. data/lib/code/node/name.rb +6 -1
  17. data/lib/code/node/string.rb +11 -6
  18. data/lib/code/node/string_characters.rb +13 -0
  19. data/lib/code/node/string_component.rb +23 -0
  20. data/lib/code/node/string_interpolation.rb +13 -0
  21. data/lib/code/object/argument.rb +1 -1
  22. data/lib/code/object/decimal.rb +22 -1
  23. data/lib/code/object/dictionnary.rb +24 -0
  24. data/lib/code/object/function.rb +2 -1
  25. data/lib/code/object/integer.rb +18 -20
  26. data/lib/code/object/list.rb +4 -0
  27. data/lib/code/object/string.rb +10 -2
  28. data/lib/code/object.rb +7 -0
  29. data/lib/code/parser/and_operator.rb +4 -4
  30. data/lib/code/parser/call.rb +3 -3
  31. data/lib/code/parser/code.rb +3 -4
  32. data/lib/code/parser/defined.rb +2 -2
  33. data/lib/code/parser/dictionnary.rb +1 -1
  34. data/lib/code/parser/equality.rb +4 -4
  35. data/lib/code/parser/function.rb +3 -2
  36. data/lib/code/parser/group.rb +1 -1
  37. data/lib/code/parser/if.rb +3 -3
  38. data/lib/code/parser/list.rb +1 -1
  39. data/lib/code/parser/not_keyword.rb +2 -2
  40. data/lib/code/parser/statement.rb +1 -1
  41. data/lib/code/parser/string.rb +19 -4
  42. data/lib/code/parser/ternary.rb +3 -3
  43. data/lib/code-ruby.rb +12 -0
  44. data/lib/code.rb +10 -10
  45. data/lib/template/version.rb +3 -0
  46. data/lib/template-ruby.rb +3 -1
  47. data/lib/template.rb +21 -11
  48. data/spec/code/error/type_error_spec.rb +0 -2
  49. data/spec/code/parser/dictionnary_spec.rb +5 -32
  50. data/spec/code/parser/string_spec.rb +15 -16
  51. data/spec/code_spec.rb +13 -0
  52. data/spec/template_spec.rb +6 -0
  53. data/template-ruby.gemspec +3 -2
  54. metadata +15 -4
@@ -21,13 +21,13 @@ class Code
21
21
 
22
22
  if operator == "even?"
23
23
  even?(arguments)
24
- elsif operator == "to_string"
25
- code_to_s(arguments)
26
24
  elsif operator == "*"
27
25
  multiplication(arguments)
28
26
  elsif operator == "/"
29
27
  division(arguments)
30
- elsif %w[% - + **].detect { |o| operator == o }
28
+ elsif operator == "+"
29
+ plus(arguments)
30
+ elsif %w[% - **].detect { |o| operator == o }
31
31
  integer_or_decimal_operation(operator.to_sym, arguments)
32
32
  elsif %w[> >= < <=].detect { |o| operator == o }
33
33
  comparaison(operator.to_sym, arguments)
@@ -38,16 +38,6 @@ class Code
38
38
  end
39
39
  end
40
40
 
41
- def +(other)
42
- if other.is_a?(::Code::Object::Integer)
43
- ::Code::Object::Integer.new(raw + other.raw)
44
- elsif other.is_a?(::Code::Object::Decimal)
45
- ::Code::Object::Decimal.new(raw + other.raw)
46
- else
47
- raise ::Code::Error::TypeError
48
- end
49
- end
50
-
51
41
  def succ
52
42
  ::Code::Object::Integer.new(raw + 1)
53
43
  end
@@ -67,11 +57,6 @@ class Code
67
57
  ::Code::Object::Boolean.new(raw.even?)
68
58
  end
69
59
 
70
- def code_to_s(arguments)
71
- sig(arguments)
72
- ::Code::Object::String.new(raw.to_s)
73
- end
74
-
75
60
  def multiplication(arguments)
76
61
  sig(arguments, [::Code::Object::Number, ::Code::Object::String])
77
62
  other = arguments.first.value
@@ -84,6 +69,19 @@ class Code
84
69
  end
85
70
  end
86
71
 
72
+ def plus(arguments)
73
+ sig(arguments, ::Code::Object)
74
+ other = arguments.first.value
75
+
76
+ if other.is_a?(::Code::Object::Integer)
77
+ ::Code::Object::Integer.new(raw + other.raw)
78
+ elsif other.is_a?(::Code::Object::Decimal)
79
+ ::Code::Object::Decimal.new(raw + other.raw)
80
+ else
81
+ ::Code::Object::String.new(to_s + other.to_s)
82
+ end
83
+ end
84
+
87
85
  def division(arguments)
88
86
  sig(arguments, ::Code::Object::Number)
89
87
  other = arguments.first.value
@@ -101,9 +99,9 @@ class Code
101
99
  end
102
100
 
103
101
  def integer_operation(operator, arguments)
104
- sig(arguments, ::Code::Object::Integer)
102
+ sig(arguments, ::Code::Object::Number)
105
103
  other = arguments.first.value
106
- ::Code::Object::Integer.new(raw.public_send(operator, other.raw))
104
+ ::Code::Object::Integer.new(raw.to_i.public_send(operator, other.raw.to_i))
107
105
  end
108
106
 
109
107
  def comparaison(operator, arguments)
@@ -63,6 +63,10 @@ class Code
63
63
  )
64
64
  end
65
65
 
66
+ def deep_dup
67
+ ::Code::Object::List.new(raw.deep_dup)
68
+ end
69
+
66
70
  def to_s
67
71
  "[#{raw.map(&:inspect).join(", ")}]"
68
72
  end
@@ -15,6 +15,8 @@ class Code
15
15
  to_function(arguments)
16
16
  elsif operator == "+"
17
17
  plus(arguments)
18
+ elsif operator == "*"
19
+ multiplication(arguments)
18
20
  elsif operator == "reverse"
19
21
  reverse(arguments)
20
22
  else
@@ -46,9 +48,15 @@ class Code
46
48
  end
47
49
 
48
50
  def plus(arguments)
49
- sig(arguments, ::Code::Object::String)
51
+ sig(arguments, ::Code::Object)
50
52
  other = arguments.first.value
51
- ::Code::Object::String.new(raw + other.raw)
53
+ ::Code::Object::String.new(raw + other.to_s)
54
+ end
55
+
56
+ def multiplication(arguments)
57
+ sig(arguments, ::Code::Object::Number)
58
+ other = arguments.first.value
59
+ ::Code::Object::String.new(raw * other.raw)
52
60
  end
53
61
 
54
62
  def reverse(arguments)
data/lib/code/object.rb CHANGED
@@ -13,6 +13,8 @@ class Code
13
13
  and_operator(arguments)
14
14
  elsif operator == "||"
15
15
  or_operator(arguments)
16
+ elsif operator == "to_string"
17
+ to_string(arguments)
16
18
  else
17
19
  raise ::Code::Error::Undefined.new(
18
20
  "#{operator} not defined on #{inspect}",
@@ -126,5 +128,10 @@ class Code
126
128
  other = arguments.first.value
127
129
  truthy? ? self : other
128
130
  end
131
+
132
+ def to_string(arguments)
133
+ sig(arguments)
134
+ ::Code::Object::String.new(to_s)
135
+ end
129
136
  end
130
137
  end
@@ -1,7 +1,7 @@
1
1
  class Code
2
2
  class Parser
3
3
  class AndOperator < Parslet::Parser
4
- rule(:equality) { ::Code::Parser::Equality.new }
4
+ rule(:greater_than) { ::Code::Parser::GreaterThan.new }
5
5
 
6
6
  rule(:ampersand) { str("&") }
7
7
 
@@ -14,12 +14,12 @@ class Code
14
14
 
15
15
  rule(:and_operator) do
16
16
  (
17
- equality.as(:first) >>
17
+ greater_than.as(:first) >>
18
18
  (
19
19
  whitespace? >> operator.as(:operator) >> whitespace? >>
20
- equality.as(:statement)
20
+ greater_than.as(:statement)
21
21
  ).repeat(1).as(:rest)
22
- ).as(:and_operator) | equality
22
+ ).as(:and_operator) | greater_than
23
23
  end
24
24
 
25
25
  root(:and_operator)
@@ -2,7 +2,7 @@ class Code
2
2
  class Parser
3
3
  class Call < Parslet::Parser
4
4
  rule(:dictionnary) { ::Code::Parser::Dictionnary.new }
5
- rule(:code) { ::Code::Parser::Code.new }
5
+ rule(:code) { ::Code::Parser::Code.new.present }
6
6
  rule(:name) { ::Code::Parser::Name.new }
7
7
  rule(:function_arguments) { ::Code::Parser::Function.new.arguments }
8
8
 
@@ -72,12 +72,12 @@ class Code
72
72
  rule(:block) do
73
73
  (
74
74
  whitespace >> do_keyword >> whitespace >>
75
- block_arguments.as(:arguments).maybe >> code.as(:body) >>
75
+ block_arguments.as(:arguments).maybe >> code.as(:body).maybe >>
76
76
  end_keyword
77
77
  ) |
78
78
  (
79
79
  whitespace? >> opening_curly_bracket >> whitespace >>
80
- block_arguments.as(:arguments).maybe >> code.as(:body) >>
80
+ block_arguments.as(:arguments).maybe >> code.as(:body).maybe >>
81
81
  closing_curly_bracket
82
82
  )
83
83
  end
@@ -8,11 +8,10 @@ class Code
8
8
  rule(:whitespace) { (space | newline).repeat(1) }
9
9
  rule(:whitespace?) { whitespace.maybe }
10
10
 
11
- rule(:code) do
12
- (whitespace?.ignore >> statement >> whitespace?.ignore).repeat(1) |
13
- whitespace?.ignore
11
+ rule(:present) do
12
+ (whitespace?.ignore >> statement >> whitespace?.ignore).repeat(1)
14
13
  end
15
-
14
+ rule(:code) { present | whitespace?.ignore }
16
15
  root(:code)
17
16
  end
18
17
  end
@@ -1,7 +1,7 @@
1
1
  class Code
2
2
  class Parser
3
3
  class Defined < Parslet::Parser
4
- rule(:equal) { ::Code::Parser::Equal.new }
4
+ rule(:range) { ::Code::Parser::Range.new }
5
5
  rule(:name) { ::Code::Parser::Name.new }
6
6
 
7
7
  rule(:defined_keyword) { str("defined?") }
@@ -11,7 +11,7 @@ class Code
11
11
  rule(:defined) do
12
12
  (
13
13
  defined_keyword >> opening_parenthesis >> name >> closing_parenthesis
14
- ).as(:defined) | equal
14
+ ).as(:defined) | range
15
15
  end
16
16
 
17
17
  root(:defined)
@@ -2,7 +2,7 @@ class Code
2
2
  class Parser
3
3
  class Dictionnary < Parslet::Parser
4
4
  rule(:list) { ::Code::Parser::List.new }
5
- rule(:code) { ::Code::Parser::Code.new }
5
+ rule(:code) { ::Code::Parser::Code.new.present }
6
6
  rule(:string) { ::Code::Parser::String.new }
7
7
 
8
8
  rule(:opening_curly_bracket) { str("{") }
@@ -1,7 +1,7 @@
1
1
  class Code
2
2
  class Parser
3
3
  class Equality < Parslet::Parser
4
- rule(:greater_than) { ::Code::Parser::GreaterThan.new }
4
+ rule(:while_parser) { ::Code::Parser::While.new }
5
5
 
6
6
  rule(:right_caret) { str(">") }
7
7
  rule(:left_caret) { str("<") }
@@ -22,12 +22,12 @@ class Code
22
22
 
23
23
  rule(:equality) do
24
24
  (
25
- greater_than.as(:first) >>
25
+ while_parser.as(:first) >>
26
26
  (
27
27
  whitespace? >> operator.as(:operator) >> whitespace? >>
28
- greater_than.as(:statement)
28
+ while_parser.as(:statement)
29
29
  ).repeat(1).as(:rest)
30
- ).as(:equality) | greater_than
30
+ ).as(:equality) | while_parser
31
31
  end
32
32
 
33
33
  root(:equality)
@@ -2,6 +2,7 @@ class Code
2
2
  class Parser
3
3
  class Function < Parslet::Parser
4
4
  rule(:call) { ::Code::Parser::Call.new }
5
+ rule(:code_present) { ::Code::Parser::Code.new.present }
5
6
  rule(:code) { ::Code::Parser::Code.new }
6
7
  rule(:name) { ::Code::Parser::Name.new }
7
8
 
@@ -22,14 +23,14 @@ class Code
22
23
  rule(:whitespace?) { whitespace.maybe }
23
24
 
24
25
  rule(:keyword_argument) do
25
- name >> whitespace? >> colon >> (whitespace? >> code.as(:default)).maybe
26
+ name >> whitespace? >> colon >> code_present.as(:default).maybe
26
27
  end
27
28
 
28
29
  rule(:regular_argument) do
29
30
  ampersand.as(:block).maybe >>
30
31
  (asterisk >> asterisk).as(:keyword_splat).maybe >>
31
32
  asterisk.as(:splat).maybe >> name >>
32
- (whitespace? >> equal >> whitespace? >> code.as(:default)).maybe
33
+ (whitespace? >> equal >> whitespace? >> code_present.as(:default)).maybe
33
34
  end
34
35
 
35
36
  rule(:argument) do
@@ -2,7 +2,7 @@ class Code
2
2
  class Parser
3
3
  class Group < Parslet::Parser
4
4
  rule(:name) { ::Code::Parser::Name.new }
5
- rule(:code) { ::Code::Parser::Code.new }
5
+ rule(:code) { ::Code::Parser::Code.new.present }
6
6
 
7
7
  rule(:opening_parenthesis) { str("(") }
8
8
  rule(:closing_parenthesis) { str(")") }
@@ -2,7 +2,7 @@ class Code
2
2
  class Parser
3
3
  class If < Parslet::Parser
4
4
  rule(:if_modifier) { ::Code::Parser::IfModifier.new }
5
- rule(:code) { ::Code::Parser::Code.new }
5
+ rule(:code) { ::Code::Parser::Code.new.present }
6
6
 
7
7
  rule(:if_keyword) { str("if") }
8
8
  rule(:else_keyword) { str("else") }
@@ -16,13 +16,13 @@ class Code
16
16
  rule(:if_rule) do
17
17
  (
18
18
  (if_keyword | unless_keyword).as(:if_operator) >> whitespace >>
19
- if_modifier.as(:if_statement) >> code.as(:if_body) >>
19
+ if_modifier.as(:if_statement) >> code.as(:if_body).maybe >>
20
20
  (
21
21
  else_keyword >>
22
22
  (
23
23
  whitespace >> (if_keyword | unless_keyword).as(:operator) >>
24
24
  whitespace >> if_modifier.as(:statement)
25
- ).maybe >> code.as(:body)
25
+ ).maybe >> code.as(:body).maybe
26
26
  ).repeat(1).as(:elses).maybe >> end_keyword
27
27
  ).as(:if) | if_modifier
28
28
  end
@@ -2,7 +2,7 @@ class Code
2
2
  class Parser
3
3
  class List < Parslet::Parser
4
4
  rule(:string) { ::Code::Parser::String.new }
5
- rule(:code) { ::Code::Parser::Code.new }
5
+ rule(:code) { ::Code::Parser::Code.new.present }
6
6
 
7
7
  rule(:opening_square_bracket) { str("[") }
8
8
  rule(:closing_square_bracket) { str("]") }
@@ -1,7 +1,7 @@
1
1
  class Code
2
2
  class Parser
3
3
  class NotKeyword < Parslet::Parser
4
- rule(:defined) { ::Code::Parser::Defined.new }
4
+ rule(:equal) { ::Code::Parser::Equal.new }
5
5
 
6
6
  rule(:not_keyword) { str("not") }
7
7
 
@@ -12,7 +12,7 @@ class Code
12
12
  rule(:whitespace) { (space | newline).repeat(1) }
13
13
 
14
14
  rule(:not_rule) do
15
- (not_keyword >> whitespace >> not_rule).as(:not_keyword) | defined
15
+ (not_keyword >> whitespace >> not_rule).as(:not_keyword) | equal
16
16
  end
17
17
 
18
18
  root(:not_rule)
@@ -1,7 +1,7 @@
1
1
  class Code
2
2
  class Parser
3
3
  class Statement < Parslet::Parser
4
- rule(:statement) { ::Code::Parser::While.new }
4
+ rule(:statement) { ::Code::Parser::Equality.new }
5
5
  root(:statement)
6
6
  end
7
7
  end
@@ -3,11 +3,14 @@ class Code
3
3
  class String < Parslet::Parser
4
4
  rule(:number) { ::Code::Parser::Number.new }
5
5
  rule(:name) { ::Code::Parser::Name.new.name }
6
+ rule(:code) { ::Code::Parser::Code.new }
6
7
 
7
8
  rule(:single_quote) { str("'") }
8
9
  rule(:double_quote) { str('"') }
9
10
  rule(:backslash) { str("\\") }
10
11
  rule(:colon) { str(":") }
12
+ rule(:opening_curly_bracket) { str("{") }
13
+ rule(:closing_curly_bracket) { str("}") }
11
14
 
12
15
  rule(:zero) { str("0") }
13
16
  rule(:one) { str("1") }
@@ -31,6 +34,10 @@ class Code
31
34
  rule(:t) { str("t") | str("T") }
32
35
  rule(:u) { str("u") | str("U") }
33
36
 
37
+ rule(:interpolation) do
38
+ opening_curly_bracket >> code >> closing_curly_bracket
39
+ end
40
+
34
41
  rule(:base_16_digit) do
35
42
  zero | one | two | three | four | five | six | seven | eight | nine |
36
43
  a | b | c | d | e | f
@@ -42,20 +49,28 @@ class Code
42
49
  end
43
50
 
44
51
  rule(:single_quoted_character) do
45
- escaped_character | (single_quote.absent? >> any)
52
+ escaped_character | (opening_curly_bracket.absent? >> single_quote.absent? >> any)
46
53
  end
47
54
 
48
55
  rule(:double_quoted_character) do
49
- escaped_character | (double_quote.absent? >> any)
56
+ escaped_character | (opening_curly_bracket.absent? >> double_quote.absent? >> any)
50
57
  end
51
58
 
52
59
  rule(:single_quoted_string) do
53
- single_quote.ignore >> single_quoted_character.repeat >>
60
+ single_quote.ignore >>
61
+ (
62
+ interpolation.as(:interpolation) |
63
+ single_quoted_character.repeat(1).as(:characters)
64
+ ).repeat >>
54
65
  single_quote.ignore
55
66
  end
56
67
 
57
68
  rule(:double_quoted_string) do
58
- double_quote.ignore >> double_quoted_character.repeat >>
69
+ double_quote.ignore >>
70
+ (
71
+ interpolation.as(:interpolation) |
72
+ double_quoted_character.repeat(1).as(:characters)
73
+ ).repeat >>
59
74
  double_quote.ignore
60
75
  end
61
76
 
@@ -1,7 +1,7 @@
1
1
  class Code
2
2
  class Parser
3
3
  class Ternary < Parslet::Parser
4
- rule(:range) { ::Code::Parser::Range.new }
4
+ rule(:defined) { ::Code::Parser::Defined.new }
5
5
 
6
6
  rule(:question_mark) { str("?") }
7
7
  rule(:colon) { str(":") }
@@ -13,10 +13,10 @@ class Code
13
13
 
14
14
  rule(:ternary) do
15
15
  (
16
- range.as(:left) >> whitespace >> question_mark >> whitespace? >>
16
+ defined.as(:left) >> whitespace >> question_mark >> whitespace? >>
17
17
  ternary.as(:middle) >>
18
18
  (whitespace? >> colon >> whitespace? >> ternary.as(:right)).maybe
19
- ).as(:ternary) | range
19
+ ).as(:ternary) | defined
20
20
  end
21
21
 
22
22
  root(:ternary)
data/lib/code-ruby.rb ADDED
@@ -0,0 +1,12 @@
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.expand_path("lib/template-ruby.rb"))
11
+ loader.ignore(File.expand_path("lib/code-ruby.rb"))
12
+ loader.setup
data/lib/code.rb CHANGED
@@ -1,30 +1,30 @@
1
1
  class Code
2
- def initialize(input, io: $stdout, timeout: 10)
2
+ DEFAULT_TIMEOUT = Template::DEFAULT_TIMEOUT
3
+
4
+ def initialize(input, io: $stdout, timeout: DEFAULT_TIMEOUT)
3
5
  @input = input
4
- @parsed = Timeout::timeout(timeout) do
5
- ::Code::Parser::Code.new.parse(@input)
6
- end
6
+ @parsed = Timeout.timeout(timeout) { ::Code::Parser::Code.new.parse(@input) }
7
7
  @io = io
8
- @timeout = timeout
8
+ @timeout = timeout || DEFAULT_TIMEOUT
9
9
  end
10
10
 
11
- def self.evaluate(input, context = "", io: $stdout, timeout: 10)
11
+ def self.evaluate(input, context = "", io: $stdout, timeout: DEFAULT_TIMEOUT)
12
12
  new(input, io: io, timeout: timeout).evaluate(context)
13
13
  end
14
14
 
15
15
  def evaluate(context = "")
16
- Timeout::timeout(@timeout) do
16
+ Timeout.timeout(timeout) do
17
17
  if context.present?
18
- context = ::Code.evaluate(context, timeout: @timeout)
18
+ context = ::Code.evaluate(context, timeout: timeout)
19
19
  else
20
20
  context = ::Code::Object::Dictionnary.new
21
21
  end
22
22
 
23
- ::Code::Node::Code.new(parsed).evaluate(context: context, io: @io)
23
+ ::Code::Node::Code.new(parsed).evaluate(context: context, io: io)
24
24
  end
25
25
  end
26
26
 
27
27
  private
28
28
 
29
- attr_reader :input, :parsed
29
+ attr_reader :input, :parsed, :timeout, :io
30
30
  end
@@ -0,0 +1,3 @@
1
+ require_relative "../template"
2
+
3
+ Template::Version = Gem::Version.new("0.3.0")
data/lib/template-ruby.rb CHANGED
@@ -3,9 +3,11 @@ require "zeitwerk"
3
3
  require "bigdecimal"
4
4
  require "active_support"
5
5
  require "active_support/core_ext/object/blank"
6
+ require "active_support/core_ext/object/deep_dup"
6
7
  require "stringio"
7
8
  require "timeout"
8
9
 
9
10
  loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
10
- loader.ignore(__FILE__)
11
+ loader.ignore(File.expand_path("lib/template-ruby.rb"))
12
+ loader.ignore(File.expand_path("lib/code-ruby.rb"))
11
13
  loader.setup
data/lib/template.rb CHANGED
@@ -1,30 +1,40 @@
1
1
  class Template
2
- VERSION = Gem::Version.new("0.2.3")
2
+ DEFAULT_TIMEOUT = 10
3
3
 
4
- def initialize(input, io: StringIO.new, timeout: 10)
4
+ def initialize(input, io: StringIO.new, timeout: DEFAULT_TIMEOUT)
5
5
  @input = input
6
- @parsed = Timeout::timeout(timeout) do
7
- ::Template::Parser::Template.new.parse(@input)
8
- end
6
+ @parsed =
7
+ Timeout.timeout(timeout) do
8
+ ::Template::Parser::Template.new.parse(@input)
9
+ end
9
10
  @io = io
10
- @timeout = timeout
11
+ @timeout = timeout || DEFAULT_TIMEOUT
11
12
  end
12
13
 
13
- def self.render(input, context = "", io: StringIO.new, timeout: 10)
14
+ def self.render(input, context = "", io: StringIO.new, timeout: DEFAULT_TIMEOUT)
14
15
  new(input, io: io, timeout: timeout).render(context)
15
16
  end
16
17
 
17
18
  def render(context = "")
18
- Timeout::timeout(@timeout) do
19
+ Timeout.timeout(timeout) do
19
20
  if context.present?
20
- context = ::Code.evaluate(context, timeout: @timeout)
21
+ context = ::Code.evaluate(context, timeout: timeout)
21
22
  else
22
23
  context = ::Code::Object::Dictionnary.new
23
24
  end
24
25
 
25
- ::Template::Node::Template.new(@parsed).evaluate(context: context, io: @io)
26
+ ::Template::Node::Template.new(parsed).evaluate(
27
+ context: context,
28
+ io: io,
29
+ )
26
30
 
27
- @io.is_a?(StringIO) ? @io.string : nil
31
+ io.is_a?(StringIO) ? io.string : nil
28
32
  end
29
33
  end
34
+
35
+ private
36
+
37
+ attr_reader :parsed, :io, :timeout
30
38
  end
39
+
40
+ require_relative "template/version"
@@ -14,7 +14,6 @@ RSpec.describe ::Code::Error::TypeError do
14
14
  '1 / ""',
15
15
  '1 ** ""',
16
16
  '1 % ""',
17
- '1 + ""',
18
17
  '1 - ""',
19
18
  '1 << ""',
20
19
  '1 >> ""',
@@ -48,7 +47,6 @@ RSpec.describe ::Code::Error::TypeError do
48
47
  '1.0 ** ""',
49
48
  '1.0 * ""',
50
49
  '1.0 % ""',
51
- '1.0 + ""',
52
50
  '1.0 - ""',
53
51
  '1.0 > ""',
54
52
  '1.0 >= ""',
@@ -4,42 +4,15 @@ RSpec.describe Code::Parser::Dictionnary do
4
4
  subject { described_class.new.parse(input) }
5
5
 
6
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)|
7
+ '{name: "Dorian"}',
8
+ '{a: true, "b": false}',
9
+ "{ true => 1, false => 2}",
10
+ ].each do |input|
38
11
  context input.inspect do
39
12
  let(:input) { input }
40
13
 
41
14
  it "succeeds" do
42
- expect(subject).to eq(expected)
15
+ expect { subject }.to_not raise_error
43
16
  end
44
17
  end
45
18
  end