template-ruby 0.2.0 → 0.2.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f42cd4f03c1c1bacdfdcc9e454cdc19411220aa407698bc63024f59311d0a23f
4
- data.tar.gz: 59da1aed5e7e8e729c1c4a44c36c62fcaacc47780229e61b8606708e1414e4c4
3
+ metadata.gz: d5e2a863316056d011b034cc0c819984d710899e8b51657dd15636e45db058b0
4
+ data.tar.gz: 47974cad2e705fb70706b68a496523f414b3027c6f57ec6d22344c588cdce143
5
5
  SHA512:
6
- metadata.gz: 4e56e63c45fce924c3b62571a58be48846be2a0348565713a2e5de6f6a33f07d15ce4e37fc0d48a3ef964ff3d8cb8810bff55ae6f2cc5bba184df2b14182d85c
7
- data.tar.gz: 26ba43eea5b6d61a99fd358bdcded3bfcc52e0b0b57910c62f0773380f3777a4b29b8ff355937c0d716cdd5f4e7d29561d17c642de1476a06a32fdd798c3d6ad
6
+ metadata.gz: 1ba52300910fb32458e115c200842c3a2ef18a19e8fddee92c38a961d60637d3c3c73906304184ef0ec5771ad85cc5dd19d8dbe0803a872a2c5c0dd69cc82a16
7
+ data.tar.gz: d526bbd95df4375aee06d4c9cc8bb8c6f2927b725514527dd9d3e29229223235bf0c8870d917eb61ae30cbce52e2c27a5f18ba31a2b1fcc94b0dfc574bf77bd1
data/CHANGELOG.md CHANGED
@@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## 0.2.3 / 2022-08-31
9
+
10
+ - Add default timeout for code and template parsing and evaluation
11
+
12
+ ## 0.2.2 / 2022-08-31
13
+
14
+ - Fix parsing error when the template is empty, e.g. ""
15
+
16
+ ## 0.2.1 / 2022-08-31
17
+
18
+ - Fix parsing error on empty code like `Hello {`
19
+
8
20
  ## 0.2.0 / 2022-08-30
9
21
 
10
22
  - Programming language capable of solving the first 5 Project Euler problems
@@ -12,4 +24,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
12
24
  ## 0.1.0 / 2022-07-28
13
25
 
14
26
  - Initial version with interpolation
15
-
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- template-ruby (0.1.0)
4
+ template-ruby (0.2.2)
5
5
  activesupport (~> 7)
6
6
  parslet (~> 2)
7
7
  zeitwerk (~> 2.6)
@@ -21,7 +21,7 @@ GEM
21
21
  tilt
22
22
  i18n (1.12.0)
23
23
  concurrent-ruby (~> 1.0)
24
- minitest (5.16.2)
24
+ minitest (5.16.3)
25
25
  parslet (2.0.0)
26
26
  prettier (3.2.0)
27
27
  syntax_tree (>= 2.7.1)
@@ -42,9 +42,9 @@ GEM
42
42
  diff-lcs (>= 1.2.0, < 2.0)
43
43
  rspec-support (~> 3.11.0)
44
44
  rspec-support (3.11.0)
45
- syntax_tree (3.2.1)
45
+ syntax_tree (3.5.0)
46
46
  prettier_print
47
- syntax_tree-haml (1.3.0)
47
+ syntax_tree-haml (1.3.1)
48
48
  haml (>= 5.2)
49
49
  prettier_print
50
50
  syntax_tree (>= 2.0.1)
@@ -8,9 +8,10 @@ class Code
8
8
  @arguments.map! { |argument| ::Code::Node::CallArgument.new(argument) }
9
9
 
10
10
  if call.key?(:right)
11
- @right = call.fetch(:right).map do |right|
12
- ::Code::Node::ChainedCall.new(right)
13
- end
11
+ @right =
12
+ call
13
+ .fetch(:right)
14
+ .map { |right| ::Code::Node::ChainedCall.new(right) }
14
15
  end
15
16
 
16
17
  if call.key?(:block)
@@ -59,7 +59,7 @@ class Code
59
59
  else
60
60
  acc + [element]
61
61
  end
62
- end
62
+ end,
63
63
  )
64
64
  end
65
65
 
@@ -138,7 +138,7 @@ class Code
138
138
  argument.call(
139
139
  arguments: [
140
140
  ::Code::Object::Argument.new(acc),
141
- ::Code::Object::Argument.new(element)
141
+ ::Code::Object::Argument.new(element),
142
142
  ],
143
143
  context: context,
144
144
  io: io,
@@ -169,7 +169,7 @@ class Code
169
169
  context: context,
170
170
  io: io,
171
171
  ).truthy?
172
- end
172
+ end,
173
173
  )
174
174
  end
175
175
 
@@ -183,7 +183,7 @@ class Code
183
183
  context: context,
184
184
  io: io,
185
185
  )
186
- end
186
+ end,
187
187
  )
188
188
  end
189
189
 
@@ -54,13 +54,11 @@ class Code
54
54
  argument = arguments.first.value
55
55
  ::Code::Object::Boolean.new(
56
56
  raw.any? do |element|
57
- argument
58
- .call(
59
- arguments: [::Code::Object::Argument.new(element)],
60
- context: context,
61
- io: io,
62
- )
63
- .truthy?
57
+ argument.call(
58
+ arguments: [::Code::Object::Argument.new(element)],
59
+ context: context,
60
+ io: io,
61
+ ).truthy?
64
62
  end,
65
63
  )
66
64
  end
@@ -70,13 +68,11 @@ class Code
70
68
  argument = arguments.first.value
71
69
  ::Code::Object::Boolean.new(
72
70
  raw.all? do |element|
73
- argument
74
- .call(
75
- arguments: [::Code::Object::Argument.new(element)],
76
- context: context,
77
- io: io,
78
- )
79
- .truthy?
71
+ argument.call(
72
+ arguments: [::Code::Object::Argument.new(element)],
73
+ context: context,
74
+ io: io,
75
+ ).truthy?
80
76
  end,
81
77
  )
82
78
  end
@@ -104,7 +100,7 @@ class Code
104
100
  context: context,
105
101
  io: io,
106
102
  ).truthy?
107
- end
103
+ end,
108
104
  )
109
105
  end
110
106
 
@@ -118,7 +114,7 @@ class Code
118
114
  context: context,
119
115
  io: io,
120
116
  )
121
- end
117
+ end,
122
118
  )
123
119
  end
124
120
 
@@ -131,9 +127,13 @@ class Code
131
127
  list << element
132
128
 
133
129
  if @exlucde_end
134
- list << element while (element = element + argument) < @right
130
+ while (element = element + argument) < @right
131
+ list << element
132
+ end
135
133
  else
136
- list << element while (element = element + argument) <= @right
134
+ while (element = element + argument) <= @right
135
+ list << element
136
+ end
137
137
  end
138
138
 
139
139
  list
data/lib/code/object.rb CHANGED
@@ -45,11 +45,7 @@ class Code
45
45
 
46
46
  def <=>(other)
47
47
  if respond_to?(:raw)
48
- if other.respond_to?(:raw)
49
- raw <=> other.raw
50
- else
51
- raw <=> other
52
- end
48
+ other.respond_to?(:raw) ? raw <=> other.raw : raw <=> other
53
49
  else
54
50
  other <=> self
55
51
  end
@@ -57,11 +53,7 @@ class Code
57
53
 
58
54
  def ==(other)
59
55
  if respond_to?(:raw)
60
- if other.respond_to?(:raw)
61
- raw == other.raw
62
- else
63
- raw == other
64
- end
56
+ other.respond_to?(:raw) ? raw == other.raw : raw == other
65
57
  else
66
58
  other == self
67
59
  end
@@ -9,7 +9,8 @@ class Code
9
9
  rule(:whitespace?) { whitespace.maybe }
10
10
 
11
11
  rule(:code) do
12
- (whitespace? >> statement >> whitespace?).repeat(1) | whitespace?
12
+ (whitespace?.ignore >> statement >> whitespace?.ignore).repeat(1) |
13
+ whitespace?.ignore
13
14
  end
14
15
 
15
16
  root(:code)
data/lib/code.rb CHANGED
@@ -1,22 +1,27 @@
1
1
  class Code
2
- def initialize(input, io: $stdout)
2
+ def initialize(input, io: $stdout, timeout: 10)
3
3
  @input = input
4
- @parsed = ::Code::Parser::Code.new.parse(@input)
4
+ @parsed = Timeout::timeout(timeout) do
5
+ ::Code::Parser::Code.new.parse(@input)
6
+ end
5
7
  @io = io
8
+ @timeout = timeout
6
9
  end
7
10
 
8
- def self.evaluate(input, context = "", io: $stdout)
9
- new(input, io: io).evaluate(context)
11
+ def self.evaluate(input, context = "", io: $stdout, timeout: 10)
12
+ new(input, io: io, timeout: timeout).evaluate(context)
10
13
  end
11
14
 
12
15
  def evaluate(context = "")
13
- if context.present?
14
- context = ::Code.evaluate(context)
15
- else
16
- context = ::Code::Object::Dictionnary.new
17
- end
16
+ Timeout::timeout(@timeout) do
17
+ if context.present?
18
+ context = ::Code.evaluate(context, timeout: @timeout)
19
+ else
20
+ context = ::Code::Object::Dictionnary.new
21
+ end
18
22
 
19
- ::Code::Node::Code.new(parsed).evaluate(context: context, io: @io)
23
+ ::Code::Node::Code.new(parsed).evaluate(context: context, io: @io)
24
+ end
20
25
  end
21
26
 
22
27
  private
@@ -15,10 +15,14 @@ class Template
15
15
  end
16
16
 
17
17
  rule(:code_part) do
18
- left_curly_bracket >> code >> (right_curly_bracket | any.absent?)
18
+ left_curly_bracket.ignore >> code >>
19
+ (right_curly_bracket.ignore | any.absent?)
19
20
  end
20
21
 
21
- rule(:template) { (text_part.as(:text) | code_part.as(:code)).repeat(1) }
22
+ rule(:template) do
23
+ (text_part.as(:text) | code_part.as(:code)).repeat(1) |
24
+ str("").as(:text).repeat(1, 1)
25
+ end
22
26
 
23
27
  root(:template)
24
28
  end
data/lib/template-ruby.rb CHANGED
@@ -4,6 +4,7 @@ require "bigdecimal"
4
4
  require "active_support"
5
5
  require "active_support/core_ext/object/blank"
6
6
  require "stringio"
7
+ require "timeout"
7
8
 
8
9
  loader = Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
9
10
  loader.ignore(__FILE__)
data/lib/template.rb CHANGED
@@ -1,25 +1,30 @@
1
1
  class Template
2
- VERSION = Gem::Version.new("0.2.0")
2
+ VERSION = Gem::Version.new("0.2.3")
3
3
 
4
- def initialize(input, io: StringIO.new)
4
+ def initialize(input, io: StringIO.new, timeout: 10)
5
5
  @input = input
6
- @parsed = ::Template::Parser::Template.new.parse(@input)
6
+ @parsed = Timeout::timeout(timeout) do
7
+ ::Template::Parser::Template.new.parse(@input)
8
+ end
7
9
  @io = io
10
+ @timeout = timeout
8
11
  end
9
12
 
10
- def self.render(input, context = "", io: StringIO.new)
11
- new(input, io: io).render(context)
13
+ def self.render(input, context = "", io: StringIO.new, timeout: 10)
14
+ new(input, io: io, timeout: timeout).render(context)
12
15
  end
13
16
 
14
17
  def render(context = "")
15
- if context.present?
16
- context = ::Code.evaluate(context)
17
- else
18
- context = ::Code::Object::Dictionnary.new
19
- end
18
+ Timeout::timeout(@timeout) do
19
+ if context.present?
20
+ context = ::Code.evaluate(context, timeout: @timeout)
21
+ else
22
+ context = ::Code::Object::Dictionnary.new
23
+ end
20
24
 
21
- ::Template::Node::Template.new(@parsed).evaluate(context: context, io: @io)
25
+ ::Template::Node::Template.new(@parsed).evaluate(context: context, io: @io)
22
26
 
23
- @io.is_a?(StringIO) ? @io.string : nil
27
+ @io.is_a?(StringIO) ? @io.string : nil
28
+ end
24
29
  end
25
30
  end
@@ -21,9 +21,7 @@ RSpec.describe Code::Parser::Call do
21
21
  },
22
22
  },
23
23
  },
24
- right: [{
25
- name: "times",
26
- }],
24
+ right: [{ name: "times" }],
27
25
  },
28
26
  },
29
27
  ],
@@ -12,11 +12,8 @@ RSpec.describe Template do
12
12
  '{ user: { first_name: "Dorian" } }',
13
13
  "Hello Dorian",
14
14
  ],
15
- [<<~TEMPLATE, "", ""]
16
- {
17
- until true
18
- end
19
- TEMPLATE
15
+ ["Hello {", "", "Hello "],
16
+ ["", "", ""],
20
17
  ].each do |(input, input_context, expected)|
21
18
  context "#{input.inspect} #{input_context.inspect}" do
22
19
  let(:input) { input }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: template-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dorian Marié
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-30 00:00:00.000000000 Z
11
+ date: 2022-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport