temple 0.7.7 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 70234f9ea5cb84da4b1a8cdcfc8f63056d8af5ce
4
- data.tar.gz: 4b76d19c5643183eb268c83dffc968f777c8d97a
3
+ metadata.gz: 524637aaba62c678fcfe02760bb49ec94a2073c3
4
+ data.tar.gz: a342126edf52f3e3578c4cc9f70540aed6b32b84
5
5
  SHA512:
6
- metadata.gz: 9c7ec6543f4fc8d3d95fc5046a606135605886b5e0ab67deb50e311ae50b5ff7b3030971173ca42d1ca8b67a45c33427b2b2cbaaac0b071f02d17dfcae0ef274
7
- data.tar.gz: a8fb82e723319e0b4f1b11cd33c7b155f1cebda73345bf418b22626bd23b566b85904e45474535c8406fdd9693c6e1a7d75547b9c9d323d8b298cb9bffa86c50
6
+ metadata.gz: 1bbc62f26373b9fb48c57cad57672ef3c379af1b991ba2538f3d7b699f6f0c22b19199520849869463349af07b810946a52029c345e7ec532aa81fb8b893d1e8
7
+ data.tar.gz: 98da558eb0435b349b4c5ee44c407c92c07ee7eba8d08619d8a5158e447c423e16693707a052077ac4822aea810b1784f7fa0cc446fcf2648267b17dced0f421
@@ -1,13 +1,17 @@
1
1
  language: ruby
2
+ dist: trusty
3
+
4
+ cache: bundler
2
5
 
3
6
  rvm:
4
7
  - 1.9.3
5
8
  - 2.0.0
6
- - 2.1.0
7
- - 2.3.0
9
+ - 2.1.10
10
+ - 2.2.6
11
+ - 2.3.3
8
12
  - ruby-head
9
13
  - jruby-19mode
10
- - rbx-2
14
+ - rbx-3
11
15
 
12
16
  sudo: false
13
17
 
@@ -18,3 +22,9 @@ env:
18
22
  matrix:
19
23
  allow_failures:
20
24
  - rvm: ruby-head
25
+ - rvm: rbx-3
26
+ exclude:
27
+ - rvm: jruby-19mode
28
+ env: ESCAPE_UTILS=1
29
+ - rvm: rbx-3
30
+ env: ESCAPE_UTILS=1
data/CHANGES CHANGED
@@ -1,6 +1,15 @@
1
+ 0.8.0
2
+
3
+ * Add Temple::StaticAnalyzer to analyze Ruby expressions
4
+ * Support newlines in Temple::Filters::StaticAnalyzer
5
+
6
+ 0.7.8
7
+
8
+ * Fix an warning in StaticAnalyzer
9
+
1
10
  0.7.7
2
11
 
3
- * Add StaticAnalyzer, StringSplitter
12
+ * Add Temple::Filters::StaticAnalyzer, Temple::Filters::StringSplitter
4
13
  * Freeze string literals
5
14
 
6
15
  0.7.6
@@ -227,6 +227,7 @@ Example:
227
227
  [:html, :tag, 'img', [:html, :attrs, [:html, :attr, 'src', 'image.png']]]
228
228
  [:html, :tag, 'p', [:multi], [:static, 'Content']]
229
229
  generates:
230
+
230
231
  <img src="image.png"/>
231
232
  <p>Content</p>
232
233
 
@@ -13,6 +13,7 @@ module Temple
13
13
  autoload :ImmutableMap, 'temple/map'
14
14
  autoload :MutableMap, 'temple/map'
15
15
  autoload :OptionMap, 'temple/map'
16
+ autoload :StaticAnalyzer, 'temple/static_analyzer'
16
17
 
17
18
  module Mixins
18
19
  autoload :Dispatcher, 'temple/mixins/dispatcher'
@@ -1,85 +1,28 @@
1
- begin
2
- require 'ripper'
3
- rescue LoadError
4
- end
5
-
6
1
  module Temple
7
2
  module Filters
8
3
  # Convert [:dynamic, code] to [:static, text] if code is static Ruby expression.
9
4
  class StaticAnalyzer < Filter
10
- STATIC_TOKENS = [
11
- :on_tstring_beg, :on_tstring_end, :on_tstring_content,
12
- :on_embexpr_beg, :on_embexpr_end,
13
- :on_lbracket, :on_rbracket,
14
- :on_qwords_beg, :on_words_sep, :on_qwords_sep,
15
- :on_lparen, :on_rparen,
16
- :on_lbrace, :on_rbrace, :on_label,
17
- :on_int, :on_float, :on_imaginary,
18
- :on_comma, :on_sp,
19
- ].freeze
20
-
21
- DYNAMIC_TOKENS = [
22
- :on_ident, :on_period,
23
- ].freeze
24
-
25
- STATIC_KEYWORDS = [
26
- 'true', 'false', 'nil',
27
- ].freeze
28
-
29
- STATIC_OPERATORS = [
30
- '=>',
31
- ].freeze
32
-
33
- if defined?(Ripper)
34
- def self.static?(code)
35
- return false if code.nil? || code.strip.empty?
36
- return false if SyntaxChecker.syntax_error?(code)
37
-
38
- Ripper.lex(code).each do |(_, col), token, str|
39
- case token
40
- when *STATIC_TOKENS
41
- # noop
42
- when :on_kw
43
- return false unless STATIC_KEYWORDS.include?(str)
44
- when :on_op
45
- return false unless STATIC_OPERATORS.include?(str)
46
- when *DYNAMIC_TOKENS
47
- return false
48
- else
49
- return false
50
- end
51
- end
52
- true
53
- end
54
-
55
- def on_dynamic(code)
56
- if StaticAnalyzer.static?(code)
57
- [:static, eval(code).to_s]
58
- else
59
- [:dynamic, code]
60
- end
5
+ def call(exp)
6
+ # Optimize only when Ripper is available.
7
+ if ::Temple::StaticAnalyzer.available?
8
+ super
9
+ else
10
+ exp
61
11
  end
12
+ end
62
13
 
63
- class SyntaxChecker < Ripper
64
- class ParseError < StandardError; end
65
-
66
- def self.syntax_error?(code)
67
- self.new(code).parse
68
- false
69
- rescue ParseError
70
- true
71
- end
72
-
73
- private
14
+ def on_dynamic(code)
15
+ if ::Temple::StaticAnalyzer.static?(code)
16
+ exp = [:static, eval(code).to_s]
74
17
 
75
- def on_parse_error(*)
76
- raise ParseError
18
+ newlines = code.count("\n")
19
+ if newlines == 0
20
+ exp
21
+ else
22
+ [:multi, exp, *newlines.times.map { [:newline] }]
77
23
  end
78
- end
79
- else
80
- # Do nothing if ripper is unavailable
81
- def call(ast)
82
- ast
24
+ else
25
+ [:dynamic, code]
83
26
  end
84
27
  end
85
28
  end
@@ -16,7 +16,7 @@ module Temple
16
16
  tokens.pop while tokens.last && [:on_comment, :on_sp].include?(tokens.last[1])
17
17
 
18
18
  if tokens.size < 2
19
- raise "Expected token size >= 2 but got: #{tokens.size}"
19
+ raise(FilterError, "Expected token size >= 2 but got: #{tokens.size}")
20
20
  end
21
21
  compile_tokens!(exps, tokens)
22
22
  end
@@ -27,12 +27,12 @@ module Temple
27
27
  def strip_quotes!(tokens)
28
28
  _, type, beg_str = tokens.shift
29
29
  if type != :on_tstring_beg
30
- raise "Expected :on_tstring_beg but got: #{type}"
30
+ raise(FilterError, "Expected :on_tstring_beg but got: #{type}")
31
31
  end
32
32
 
33
33
  _, type, end_str = tokens.pop
34
34
  if type != :on_tstring_end
35
- raise "Expected :on_tstring_end but got: #{type}"
35
+ raise(FilterError, "Expected :on_tstring_end but got: #{type}")
36
36
  end
37
37
 
38
38
  [beg_str, end_str]
@@ -0,0 +1,77 @@
1
+ begin
2
+ require 'ripper'
3
+ rescue LoadError
4
+ end
5
+
6
+ module Temple
7
+ module StaticAnalyzer
8
+ STATIC_TOKENS = [
9
+ :on_tstring_beg, :on_tstring_end, :on_tstring_content,
10
+ :on_embexpr_beg, :on_embexpr_end,
11
+ :on_lbracket, :on_rbracket,
12
+ :on_qwords_beg, :on_words_sep, :on_qwords_sep,
13
+ :on_lparen, :on_rparen,
14
+ :on_lbrace, :on_rbrace, :on_label,
15
+ :on_int, :on_float, :on_imaginary,
16
+ :on_comma, :on_sp, :on_ignored_nl,
17
+ ].freeze
18
+
19
+ DYNAMIC_TOKENS = [
20
+ :on_ident, :on_period,
21
+ ].freeze
22
+
23
+ STATIC_KEYWORDS = [
24
+ 'true', 'false', 'nil',
25
+ ].freeze
26
+
27
+ STATIC_OPERATORS = [
28
+ '=>',
29
+ ].freeze
30
+
31
+ class << self
32
+ def available?
33
+ defined?(Ripper)
34
+ end
35
+
36
+ def static?(code)
37
+ return false if code.nil? || code.strip.empty?
38
+ return false if syntax_error?(code)
39
+
40
+ Ripper.lex(code).each do |_, token, str|
41
+ case token
42
+ when *STATIC_TOKENS
43
+ # noop
44
+ when :on_kw
45
+ return false unless STATIC_KEYWORDS.include?(str)
46
+ when :on_op
47
+ return false unless STATIC_OPERATORS.include?(str)
48
+ when *DYNAMIC_TOKENS
49
+ return false
50
+ else
51
+ return false
52
+ end
53
+ end
54
+ true
55
+ end
56
+
57
+ def syntax_error?(code)
58
+ SyntaxChecker.new(code).parse
59
+ false
60
+ rescue SyntaxChecker::ParseError
61
+ true
62
+ end
63
+ end
64
+
65
+ if defined?(Ripper)
66
+ class SyntaxChecker < Ripper
67
+ class ParseError < StandardError; end
68
+
69
+ private
70
+
71
+ def on_parse_error(*)
72
+ raise ParseError
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,3 +1,3 @@
1
1
  module Temple
2
- VERSION = '0.7.7'
2
+ VERSION = '0.8.0'
3
3
  end
@@ -1,15 +1,12 @@
1
1
  require 'helper'
2
- begin
3
- require 'ripper'
4
- rescue LoadError
5
- end
6
2
 
7
- if defined?(Ripper)
8
- describe Temple::Filters::StaticAnalyzer do
9
- before do
10
- @filter = Temple::Filters::StaticAnalyzer.new
11
- end
3
+ describe Temple::Filters::StaticAnalyzer do
4
+ before do
5
+ @filter = Temple::Filters::StaticAnalyzer.new
6
+ @generator = Temple::Generator.new
7
+ end
12
8
 
9
+ if Temple::StaticAnalyzer.available?
13
10
  it 'should convert :dynamic to :static if code is static' do
14
11
  @filter.call([:dynamic, '"#{"hello"}#{100}"']
15
12
  ).should.equal [:static, 'hello100']
@@ -19,5 +16,22 @@ if defined?(Ripper)
19
16
  exp = [:dynamic, '"#{hello}#{100}"']
20
17
  @filter.call(exp).should.equal(exp)
21
18
  end
19
+
20
+ it 'should not change number of newlines in generated code' do
21
+ exp = [:dynamic, "[100,\n200,\n]"]
22
+ @filter.call(exp).should.equal([:multi, [:static, '[100, 200]'], [:newline], [:newline]])
23
+
24
+ @generator.call(@filter.call(exp)).count("\n").
25
+ should.equal(@generator.call(exp).count("\n"))
26
+ end
27
+ else
28
+ it 'should do nothing' do
29
+ [
30
+ [:dynamic, '"#{"hello"}#{100}"'],
31
+ [:dynamic, '"#{hello}#{100}"'],
32
+ ].each do |exp|
33
+ @filter.call(exp).should.equal(exp)
34
+ end
35
+ end
22
36
  end
23
37
  end
@@ -14,5 +14,12 @@ if defined?(Ripper) && RUBY_VERSION >= "2.0.0"
14
14
  @filter.call([:dynamic, '"static#{dynamic}"']
15
15
  ).should.equal [:multi, [:static, 'static'], [:dynamic, 'dynamic']]
16
16
  end
17
+
18
+ describe '.compile' do
19
+ it 'should raise CompileError for non-string literals' do
20
+ lambda { Temple::Filters::StringSplitter.compile('1') }.
21
+ should.raise(Temple::FilterError)
22
+ end
23
+ end
17
24
  end
18
25
  end
@@ -0,0 +1,39 @@
1
+ require 'helper'
2
+
3
+ describe Temple::StaticAnalyzer do
4
+ describe '.available?' do
5
+ it 'should return true if its dependency is available' do
6
+ Temple::StaticAnalyzer.available?.should.equal(defined?(Ripper))
7
+ end
8
+ end
9
+
10
+ if Temple::StaticAnalyzer.available?
11
+ describe '.static?' do
12
+ it 'should return true if given Ruby expression is static' do
13
+ ['true', 'false', '"hello world"', "[1, { 2 => 3 }]", "[\n1,\n]"].each do |exp|
14
+ Temple::StaticAnalyzer.static?(exp).should.equal(true)
15
+ end
16
+ end
17
+
18
+ it 'should return false if given Ruby expression is dynamic' do
19
+ ['1 + 2', 'variable', 'method_call(a)', 'CONSTANT'].each do |exp|
20
+ Temple::StaticAnalyzer.static?(exp).should.equal(false)
21
+ end
22
+ end
23
+ end
24
+
25
+ describe '.syntax_error?' do
26
+ it 'should return false if given Ruby expression is valid' do
27
+ ['Foo.bar.baz { |c| c.d! }', '{ foo: bar }'].each do |exp|
28
+ Temple::StaticAnalyzer.syntax_error?(exp).should.equal(false)
29
+ end
30
+ end
31
+
32
+ it 'should return true if given Ruby expression is invalid' do
33
+ ['Foo.bar.baz { |c| c.d! ', ' foo: bar '].each do |exp|
34
+ Temple::StaticAnalyzer.syntax_error?(exp).should.equal(true)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: temple
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.7
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Magnus Holm
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-05-22 00:00:00.000000000 Z
12
+ date: 2017-02-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: tilt
@@ -126,6 +126,7 @@ files:
126
126
  - lib/temple/mixins/options.rb
127
127
  - lib/temple/mixins/template.rb
128
128
  - lib/temple/parser.rb
129
+ - lib/temple/static_analyzer.rb
129
130
  - lib/temple/templates.rb
130
131
  - lib/temple/templates/rails.rb
131
132
  - lib/temple/templates/tilt.rb
@@ -155,6 +156,7 @@ files:
155
156
  - test/test_generator.rb
156
157
  - test/test_grammar.rb
157
158
  - test/test_map.rb
159
+ - test/test_static_analyzer.rb
158
160
  - test/test_utils.rb
159
161
  homepage: https://github.com/judofyr/temple
160
162
  licenses:
@@ -176,8 +178,33 @@ required_rubygems_version: !ruby/object:Gem::Requirement
176
178
  version: '0'
177
179
  requirements: []
178
180
  rubyforge_project:
179
- rubygems_version: 2.2.2
181
+ rubygems_version: 2.6.8
180
182
  signing_key:
181
183
  specification_version: 4
182
184
  summary: Template compilation framework in Ruby
183
- test_files: []
185
+ test_files:
186
+ - test/filters/test_code_merger.rb
187
+ - test/filters/test_control_flow.rb
188
+ - test/filters/test_dynamic_inliner.rb
189
+ - test/filters/test_eraser.rb
190
+ - test/filters/test_escapable.rb
191
+ - test/filters/test_multi_flattener.rb
192
+ - test/filters/test_static_analyzer.rb
193
+ - test/filters/test_static_merger.rb
194
+ - test/filters/test_string_splitter.rb
195
+ - test/helper.rb
196
+ - test/html/test_attribute_merger.rb
197
+ - test/html/test_attribute_remover.rb
198
+ - test/html/test_attribute_sorter.rb
199
+ - test/html/test_fast.rb
200
+ - test/html/test_pretty.rb
201
+ - test/mixins/test_dispatcher.rb
202
+ - test/mixins/test_grammar_dsl.rb
203
+ - test/test_engine.rb
204
+ - test/test_erb.rb
205
+ - test/test_filter.rb
206
+ - test/test_generator.rb
207
+ - test/test_grammar.rb
208
+ - test/test_map.rb
209
+ - test/test_static_analyzer.rb
210
+ - test/test_utils.rb