hamlit 2.1.2 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7782d0478a595899a7218a798f2e3448fe454b62
4
- data.tar.gz: 44b82b3aa85549836524a284a1fed4744efb7042
3
+ metadata.gz: 17985d049789075f9ccaa498376e506980a85eba
4
+ data.tar.gz: 31d451aa5c850358ab1c752ab8bb670666b5a8fe
5
5
  SHA512:
6
- metadata.gz: 29045e0c90085d396ee564b06607abf72c318ba0c4864e4930eba7a747ee8ad218bf879d5175cc7fc3ff0044bfb61e53377ee5e7d2201bc586164cbfd4adfdd4
7
- data.tar.gz: bdd6e4cdcbdb9e82225890a075a73a4b82303e8dba72c166d9ab771924d1b63fedc0f4c7ffea8c45d1ca56b20d8c624debe2760fc1cf35459874c796c8ee332f
6
+ metadata.gz: 2c7a0f41cc218efdfd399363b6c00cdee940b864056208ffb4f02207c0579e8eda75f6f2d77f0bef4fceb3570e79d4ae7b34544d00c1805ece39295b85c7e35b
7
+ data.tar.gz: 3065e24a52cc9ad34854ac0d3b4d17353fae2acdc2dd50d5a1c5b5cf4754a4137866be58c9e01b1a3d762644930384076c9d98648ac2bc00cc143147e8425627
data/.travis.yml CHANGED
@@ -14,6 +14,8 @@ matrix:
14
14
  env: TASK=test
15
15
  - rvm: 2.2
16
16
  env: TASK=test
17
+ - rvm: ruby-head
18
+ env: TASK=test
17
19
  - rvm: 2.2
18
20
  env: TASK=bench TEMPLATE=benchmark/boolean_attribute.haml,benchmark/class_attribute.haml,benchmark/id_attribute.haml,benchmark/data_attribute.haml,benchmark/common_attribute.haml
19
21
  - rvm: 2.2
data/CHANGELOG.md CHANGED
@@ -4,33 +4,40 @@ All notable changes to this project will be documented in this file. This
4
4
  project adheres to [Semantic Versioning](http://semver.org/). This change log is based upon
5
5
  [keep-a-changelog](https://github.com/olivierlacan/keep-a-changelog).
6
6
 
7
+ ## [2.2.0](https://github.com/k0kubun/hamlit/compare/v2.1.2...v2.2.0) - 2015-12-24
8
+
9
+ ### Added
10
+
11
+ - Optimize inline script inside a tag
12
+ - Optimize string interpolation recursively
13
+
7
14
  ## [2.1.2](https://github.com/k0kubun/hamlit/compare/v2.1.1...v2.1.2) - 2015-12-16
8
15
 
9
- ## Fixed
16
+ ### Fixed
10
17
 
11
18
  - Fix rendering failure for static integer
12
19
  [#50](https://github.com/k0kubun/hamlit/pull/50). *Thanks to @yatmsu*
13
20
 
14
21
  ## [2.1.1](https://github.com/k0kubun/hamlit/compare/v2.1.0...v2.1.1) - 2015-12-15
15
22
 
16
- ## Fixed
23
+ ### Fixed
17
24
 
18
25
  - Use faster HTML-escape method for compiling
19
26
  - Show proper line number for unbalanced brackets error
20
27
 
21
28
  ## [2.1.0](https://github.com/k0kubun/hamlit/compare/v2.0.2...v2.1.0) - 2015-12-14
22
29
 
23
- ## Added
30
+ ### Added
24
31
 
25
32
  - `-I` and `-r` options are added to `hamlit render` command
26
33
  [#37](https://github.com/k0kubun/hamlit/issues/37). *Thanks to @jhurliman*
27
34
 
28
- ## Changed
35
+ ### Changed
29
36
 
30
37
  - Dropped obsolete `escape_utils` gem dependency
31
38
  [#48](https://github.com/k0kubun/hamlit/pull/48). *Thanks to @eagletmt*
32
39
 
33
- ## Fixed
40
+ ### Fixed
34
41
 
35
42
  - Accept NUL character in attribute keys
36
43
  [#49](https://github.com/k0kubun/hamlit/pull/49). *Thanks to @eagletmt*
data/Rakefile CHANGED
@@ -1,3 +1,4 @@
1
+ require 'bundler/setup'
1
2
  require 'bundler/gem_tasks'
2
3
  require 'rake/testtask'
3
4
  require 'rake/extensiontask'
@@ -0,0 +1,123 @@
1
+ require 'hamlit/attribute_builder'
2
+ require 'hamlit/attribute_parser'
3
+ require 'hamlit/ruby_expression'
4
+ require 'hamlit/static_analyzer'
5
+
6
+ module Hamlit
7
+ class AttributeCompiler
8
+ def initialize(identity, options)
9
+ @identity = identity
10
+ @quote = options[:attr_quote]
11
+ @format = options[:format]
12
+ @escape_attrs = options[:escape_attrs]
13
+ end
14
+
15
+ def compile(node)
16
+ hashes = []
17
+ return runtime_compile(node) if node.value[:object_ref] != :nil
18
+ node.value[:attributes_hashes].each do |attribute_str|
19
+ hash = AttributeParser.parse(attribute_str)
20
+ return runtime_compile(node) unless hash
21
+ hashes << hash
22
+ end
23
+ static_compile(node.value[:attributes], hashes)
24
+ end
25
+
26
+ private
27
+
28
+ def runtime_compile(node)
29
+ attrs = node.value[:attributes_hashes]
30
+ attrs.unshift(node.value[:attributes].inspect) if node.value[:attributes] != {}
31
+
32
+ args = [@escape_attrs, @quote, @format].map(&:inspect).push(node.value[:object_ref]) + attrs
33
+ [:html, :attrs, [:dynamic, "::Hamlit::AttributeBuilder.build(#{args.join(', ')})"]]
34
+ end
35
+
36
+ def static_compile(static_hash, dynamic_hashes)
37
+ temple = [:html, :attrs]
38
+ keys = [*static_hash.keys, *dynamic_hashes.map(&:keys).flatten].uniq.sort
39
+ keys.each do |key|
40
+ values = [[:static, static_hash[key]], *dynamic_hashes.map { |h| [:dynamic, h[key]] }]
41
+ values.select! { |_, exp| exp != nil }
42
+
43
+ case key
44
+ when 'id'.freeze
45
+ compile_id!(temple, key, values)
46
+ when 'class'.freeze
47
+ compile_class!(temple, key, values)
48
+ when 'data'.freeze
49
+ compile_data!(temple, key, values)
50
+ when *AttributeBuilder::BOOLEAN_ATTRIBUTES, /\Adata-/
51
+ compile_boolean!(temple, key, values)
52
+ else
53
+ compile_common!(temple, key, values)
54
+ end
55
+ end
56
+ temple
57
+ end
58
+
59
+ def compile_id!(temple, key, values)
60
+ build_code = attribute_builder(:id, values)
61
+ if values.all? { |type, exp| type == :static || StaticAnalyzer.static?(exp) }
62
+ temple << [:html, :attr, key, [:static, eval(build_code).to_s]]
63
+ else
64
+ temple << [:html, :attr, key, [:dynamic, build_code]]
65
+ end
66
+ end
67
+
68
+ def compile_class!(temple, key, values)
69
+ build_code = attribute_builder(:class, values)
70
+ if values.all? { |type, exp| type == :static || StaticAnalyzer.static?(exp) }
71
+ temple << [:html, :attr, key, [:static, eval(build_code).to_s]]
72
+ else
73
+ temple << [:html, :attr, key, [:dynamic, build_code]]
74
+ end
75
+ end
76
+
77
+ def compile_data!(temple, key, values)
78
+ args = [@escape_attrs.inspect, @quote.inspect, values.map { |v| literal_for(v) }]
79
+ build_code = "::Hamlit::AttributeBuilder.build_data(#{args.join(', ')})"
80
+
81
+ if values.all? { |type, exp| type == :static || StaticAnalyzer.static?(exp) }
82
+ temple << [:static, eval(build_code).to_s]
83
+ else
84
+ temple << [:dynamic, build_code]
85
+ end
86
+ end
87
+
88
+ def compile_boolean!(temple, key, values)
89
+ exp = literal_for(values.last)
90
+
91
+ if StaticAnalyzer.static?(exp)
92
+ value = eval(exp)
93
+ case value
94
+ when true then temple << [:html, :attr, key, @format == :xhtml ? [:static, key] : [:multi]]
95
+ when false, nil
96
+ else temple << [:html, :attr, key, [:escape, @escape_attrs, [:static, value.to_s]]]
97
+ end
98
+ else
99
+ var = @identity.generate
100
+ temple << [
101
+ :case, "(#{var} = (#{exp}))",
102
+ ['true', [:html, :attr, key, @format == :xhtml ? [:static, key] : [:multi]]],
103
+ ['false, nil', [:multi]],
104
+ [:else, [:multi, [:static, " #{key}=#{@quote}"], [:escape, @escape_attrs, [:dynamic, var]], [:static, @quote]]],
105
+ ]
106
+ end
107
+ end
108
+
109
+ def compile_common!(temple, key, values)
110
+ temple << [:html, :attr, key, [:escape, @escape_attrs, values.last]]
111
+ end
112
+
113
+ def attribute_builder(type, values)
114
+ args = [@escape_attrs.inspect, *values.map { |v| literal_for(v) }]
115
+ "::Hamlit::AttributeBuilder.build_#{type}(#{args.join(', ')})"
116
+ end
117
+
118
+ def literal_for(value)
119
+ type, exp = value
120
+ type == :static ? exp.inspect : exp
121
+ end
122
+ end
123
+ end
@@ -1,6 +1,6 @@
1
1
  require 'hamlit/ruby_expression'
2
2
  require 'hamlit/static_analyzer'
3
- require 'hamlit/string_interpolation'
3
+ require 'hamlit/string_splitter'
4
4
 
5
5
  module Hamlit
6
6
  class Compiler
@@ -10,10 +10,13 @@ module Hamlit
10
10
  end
11
11
 
12
12
  def compile(node, &block)
13
+ no_children = node.children.empty?
13
14
  case
14
- when node.children.empty? && RubyExpression.string_literal?(node.value[:text])
15
- string_compile(node)
16
- when node.children.empty? && StaticAnalyzer.static?(node.value[:text])
15
+ when no_children && node.value[:escape_interpolation]
16
+ compile_interpolated_plain(node)
17
+ when no_children && RubyExpression.string_literal?(node.value[:text])
18
+ delegate_optimization(node)
19
+ when no_children && StaticAnalyzer.static?(node.value[:text])
17
20
  static_compile(node)
18
21
  else
19
22
  dynamic_compile(node, &block)
@@ -23,28 +26,30 @@ module Hamlit
23
26
  private
24
27
 
25
28
  # String-interpolated plain text must be compiled with this method
26
- def string_compile(node)
29
+ # because we have to escape only interpolated values.
30
+ def compile_interpolated_plain(node)
27
31
  temple = [:multi]
28
- StringInterpolation.compile(node.value[:text]).each do |type, value|
32
+ StringSplitter.compile(node.value[:text]).each do |type, value|
29
33
  case type
30
34
  when :static
31
- value = Hamlit::Utils.escape_html(value) if node.value[:escape_html]
32
35
  temple << [:static, value]
33
36
  when :dynamic
34
- if Hamlit::StaticAnalyzer.static?(value)
35
- value = eval(value).to_s
36
- value = Hamlit::Utils.escape_html(value) if node.value[:escape_html] || node.value[:escape_interpolation]
37
- temple << [:static, value]
38
- else
39
- temple << [:escape, node.value[:escape_html] || node.value[:escape_interpolation], [:dynamic, value]]
40
- end
37
+ temple << [:escape, node.value[:escape_interpolation], [:dynamic, value]]
41
38
  end
42
39
  end
43
40
  temple << [:newline]
44
41
  end
45
42
 
43
+ # :dynamic is optimized in other filter: StringSplitter
44
+ def delegate_optimization(node)
45
+ [:multi,
46
+ [:escape, node.value[:escape_html], [:dynamic, node.value[:text]]],
47
+ [:newline],
48
+ ]
49
+ end
50
+
46
51
  def static_compile(node)
47
- str = eval("(#{node.value[:text]}).to_s")
52
+ str = eval(node.value[:text]).to_s
48
53
  if node.value[:escape_html]
49
54
  str = Hamlit::Utils.escape_html(str)
50
55
  elsif node.value[:preserve]
@@ -1,6 +1,7 @@
1
1
  require 'hamlit/parser/haml_util'
2
- require 'hamlit/compiler/attribute_compiler'
3
- require 'hamlit/string_interpolation'
2
+ require 'hamlit/attribute_compiler'
3
+ require 'hamlit/static_analyzer'
4
+ require 'hamlit/string_splitter'
4
5
 
5
6
  module Hamlit
6
7
  class Compiler
@@ -26,7 +27,9 @@ module Hamlit
26
27
  when node.value[:value].nil? && self_closing?(node)
27
28
  nil
28
29
  when node.value[:parse]
29
- return compile_string(node) if RubyExpression.string_literal?(node.value[:value])
30
+ return compile_interpolated_plain(node) if node.value[:escape_interpolation]
31
+ return delegate_optimization(node) if RubyExpression.string_literal?(node.value[:value])
32
+ return delegate_optimization(node) if StaticAnalyzer.static?(node.value[:value])
30
33
 
31
34
  var = @identity.generate
32
35
  [:multi,
@@ -40,21 +43,23 @@ module Hamlit
40
43
  end
41
44
  end
42
45
 
43
- def compile_string(node)
46
+ # :dynamic is optimized in other filters: StringSplitter or StaticAnalyzer
47
+ def delegate_optimization(node)
48
+ [:multi,
49
+ [:escape, node.value[:escape_html], [:dynamic, node.value[:value]]],
50
+ [:newline],
51
+ ]
52
+ end
53
+
54
+ # We should handle interpolation here to escape only interpolated values.
55
+ def compile_interpolated_plain(node)
44
56
  temple = [:multi]
45
- StringInterpolation.compile(node.value[:value]).each do |type, value|
57
+ StringSplitter.compile(node.value[:value]).each do |type, value|
46
58
  case type
47
59
  when :static
48
- value = Hamlit::Utils.escape_html(value) if node.value[:escape_html]
49
60
  temple << [:static, value]
50
61
  when :dynamic
51
- if Hamlit::StaticAnalyzer.static?(value)
52
- value = eval(value).to_s
53
- value = Hamlit::Utils.escape_html(value) if node.value[:escape_html] || node.value[:escape_interpolation]
54
- temple << [:static, value]
55
- else
56
- temple << [:escape, node.value[:escape_html] || node.value[:escape_interpolation], [:dynamic, value]]
57
- end
62
+ temple << [:escape, node.value[:escape_interpolation], [:dynamic, value]]
58
63
  end
59
64
  end
60
65
  temple << [:newline]
data/lib/hamlit/engine.rb CHANGED
@@ -3,6 +3,8 @@ require 'hamlit/parser'
3
3
  require 'hamlit/compiler'
4
4
  require 'hamlit/escapable'
5
5
  require 'hamlit/html'
6
+ require 'hamlit/string_splitter'
7
+ require 'hamlit/static_analyzer'
6
8
 
7
9
  module Hamlit
8
10
  class Engine < Temple::Engine
@@ -21,6 +23,8 @@ module Hamlit
21
23
  use Parser
22
24
  use Compiler
23
25
  use HTML
26
+ use StringSplitter
27
+ use StaticAnalyzer
24
28
  use Escapable
25
29
  filter :ControlFlow
26
30
  filter :MultiFlattener
@@ -1,7 +1,7 @@
1
1
  require 'hamlit/ruby_expression'
2
2
 
3
3
  module Hamlit
4
- class StaticAnalyzer
4
+ class StaticAnalyzer < Temple::Filter
5
5
  STATIC_TOKENS = %i[
6
6
  on_tstring_beg on_tstring_end on_tstring_content
7
7
  on_embexpr_beg on_embexpr_end
@@ -25,11 +25,11 @@ module Hamlit
25
25
  =>
26
26
  ].freeze
27
27
 
28
- def self.static?(exp)
29
- return false if exp.nil? || exp.strip.empty?
30
- return false if RubyExpression.syntax_error?(exp)
28
+ def self.static?(code)
29
+ return false if code.nil? || code.strip.empty?
30
+ return false if RubyExpression.syntax_error?(code)
31
31
 
32
- Ripper.lex(exp).each do |(_, col), token, str|
32
+ Ripper.lex(code).each do |(_, col), token, str|
33
33
  case token
34
34
  when *STATIC_TOKENS
35
35
  # noop
@@ -45,5 +45,13 @@ module Hamlit
45
45
  end
46
46
  true
47
47
  end
48
+
49
+ def on_dynamic(code)
50
+ if StaticAnalyzer.static?(code)
51
+ [:static, eval(code).to_s]
52
+ else
53
+ [:dynamic, code]
54
+ end
55
+ end
48
56
  end
49
57
  end
@@ -0,0 +1,88 @@
1
+ require 'ripper'
2
+ require 'hamlit/ruby_expression'
3
+
4
+ module Hamlit
5
+ class StringSplitter < Temple::Filter
6
+ class << self
7
+ # `code` param must be valid string literal
8
+ def compile(code)
9
+ [].tap do |exps|
10
+ tokens = Ripper.lex(code.strip)
11
+ tokens.pop while tokens.last && %i[on_comment on_sp].include?(tokens.last[1])
12
+
13
+ if tokens.size < 2
14
+ raise Hamlit::InternalError.new("Expected token size >= 2 but got: #{tokens.size}")
15
+ end
16
+ compile_tokens!(exps, tokens)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def strip_quotes!(tokens)
23
+ _, type, beg_str = tokens.shift
24
+ if type != :on_tstring_beg
25
+ raise Hamlit::InternalError.new("Expected :on_tstring_beg but got: #{type}")
26
+ end
27
+
28
+ _, type, end_str = tokens.pop
29
+ if type != :on_tstring_end
30
+ raise Hamlit::InternalError.new("Expected :on_tstring_end but got: #{type}")
31
+ end
32
+
33
+ [beg_str, end_str]
34
+ end
35
+
36
+ def compile_tokens!(exps, tokens)
37
+ beg_str, end_str = strip_quotes!(tokens)
38
+
39
+ until tokens.empty?
40
+ _, type, str = tokens.shift
41
+
42
+ case type
43
+ when :on_tstring_content
44
+ exps << [:static, eval("#{beg_str}#{str}#{end_str}")]
45
+ when :on_embexpr_beg
46
+ embedded = shift_balanced_embexpr(tokens)
47
+ exps << [:dynamic, embedded] unless embedded.empty?
48
+ end
49
+ end
50
+ end
51
+
52
+ def shift_balanced_embexpr(tokens)
53
+ String.new.tap do |embedded|
54
+ embexpr_open = 1
55
+
56
+ until tokens.empty?
57
+ _, type, str = tokens.shift
58
+ case type
59
+ when :on_embexpr_beg
60
+ embexpr_open += 1
61
+ when :on_embexpr_end
62
+ embexpr_open -= 1
63
+ break if embexpr_open == 0
64
+ end
65
+
66
+ embedded << str
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ def on_dynamic(code)
73
+ return [:dynamic, code] unless RubyExpression.string_literal?(code)
74
+ return [:dynamic, code] if code.include?("\n")
75
+
76
+ temple = [:multi]
77
+ StringSplitter.compile(code).each do |type, content|
78
+ case type
79
+ when :static
80
+ temple << [:static, content]
81
+ when :dynamic
82
+ temple << on_dynamic(content)
83
+ end
84
+ end
85
+ temple
86
+ end
87
+ end
88
+ end
@@ -1,3 +1,3 @@
1
1
  module Hamlit
2
- VERSION = '2.1.2'
2
+ VERSION = '2.2.0'
3
3
  end
metadata CHANGED
@@ -1,251 +1,251 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hamlit
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takashi Kokubun
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-12-16 00:00:00.000000000 Z
11
+ date: 2015-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: temple
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.7.6
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.7.6
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: thor
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: tilt
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: coffee-script
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: erubis
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: faml
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - '>='
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - '>='
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: less
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - '>='
115
+ - - ">="
116
116
  - !ruby/object:Gem::Version
117
117
  version: '0'
118
118
  type: :development
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - '>='
122
+ - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: minitest-reporters
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - ~>
129
+ - - "~>"
130
130
  - !ruby/object:Gem::Version
131
131
  version: '1.1'
132
132
  type: :development
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - ~>
136
+ - - "~>"
137
137
  - !ruby/object:Gem::Version
138
138
  version: '1.1'
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: rails
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - '>='
143
+ - - ">="
144
144
  - !ruby/object:Gem::Version
145
145
  version: 4.0.0
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - '>='
150
+ - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: 4.0.0
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: rake
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - ~>
157
+ - - "~>"
158
158
  - !ruby/object:Gem::Version
159
159
  version: '10.0'
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - ~>
164
+ - - "~>"
165
165
  - !ruby/object:Gem::Version
166
166
  version: '10.0'
167
167
  - !ruby/object:Gem::Dependency
168
168
  name: rake-compiler
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
- - - '>='
171
+ - - ">="
172
172
  - !ruby/object:Gem::Version
173
173
  version: '0'
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
- - - '>='
178
+ - - ">="
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: redcarpet
183
183
  requirement: !ruby/object:Gem::Requirement
184
184
  requirements:
185
- - - '>='
185
+ - - ">="
186
186
  - !ruby/object:Gem::Version
187
187
  version: '0'
188
188
  type: :development
189
189
  prerelease: false
190
190
  version_requirements: !ruby/object:Gem::Requirement
191
191
  requirements:
192
- - - '>='
192
+ - - ">="
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
195
  - !ruby/object:Gem::Dependency
196
196
  name: sass
197
197
  requirement: !ruby/object:Gem::Requirement
198
198
  requirements:
199
- - - '>='
199
+ - - ">="
200
200
  - !ruby/object:Gem::Version
201
201
  version: '0'
202
202
  type: :development
203
203
  prerelease: false
204
204
  version_requirements: !ruby/object:Gem::Requirement
205
205
  requirements:
206
- - - '>='
206
+ - - ">="
207
207
  - !ruby/object:Gem::Version
208
208
  version: '0'
209
209
  - !ruby/object:Gem::Dependency
210
210
  name: slim
211
211
  requirement: !ruby/object:Gem::Requirement
212
212
  requirements:
213
- - - '>='
213
+ - - ">="
214
214
  - !ruby/object:Gem::Version
215
215
  version: '0'
216
216
  type: :development
217
217
  prerelease: false
218
218
  version_requirements: !ruby/object:Gem::Requirement
219
219
  requirements:
220
- - - '>='
220
+ - - ">="
221
221
  - !ruby/object:Gem::Version
222
222
  version: '0'
223
223
  - !ruby/object:Gem::Dependency
224
224
  name: therubyracer
225
225
  requirement: !ruby/object:Gem::Requirement
226
226
  requirements:
227
- - - '>='
227
+ - - ">="
228
228
  - !ruby/object:Gem::Version
229
229
  version: '0'
230
230
  type: :development
231
231
  prerelease: false
232
232
  version_requirements: !ruby/object:Gem::Requirement
233
233
  requirements:
234
- - - '>='
234
+ - - ">="
235
235
  - !ruby/object:Gem::Version
236
236
  version: '0'
237
237
  - !ruby/object:Gem::Dependency
238
238
  name: unindent
239
239
  requirement: !ruby/object:Gem::Requirement
240
240
  requirements:
241
- - - '>='
241
+ - - ">="
242
242
  - !ruby/object:Gem::Version
243
243
  version: '0'
244
244
  type: :development
245
245
  prerelease: false
246
246
  version_requirements: !ruby/object:Gem::Requirement
247
247
  requirements:
248
- - - '>='
248
+ - - ">="
249
249
  - !ruby/object:Gem::Version
250
250
  version: '0'
251
251
  description: High Performance Haml Implementation
@@ -257,9 +257,9 @@ extensions:
257
257
  - ext/hamlit/extconf.rb
258
258
  extra_rdoc_files: []
259
259
  files:
260
- - .gitignore
261
- - .gitmodules
262
- - .travis.yml
260
+ - ".gitignore"
261
+ - ".gitmodules"
262
+ - ".travis.yml"
263
263
  - CHANGELOG.md
264
264
  - Gemfile
265
265
  - LICENSE.txt
@@ -304,13 +304,33 @@ files:
304
304
  - exe/hamlit
305
305
  - ext/hamlit/extconf.rb
306
306
  - ext/hamlit/hamlit.c
307
+ - ext/hamlit/houdini/.gitignore
308
+ - ext/hamlit/houdini/COPYING
309
+ - ext/hamlit/houdini/Makefile
310
+ - ext/hamlit/houdini/README.md
311
+ - ext/hamlit/houdini/buffer.c
312
+ - ext/hamlit/houdini/buffer.h
313
+ - ext/hamlit/houdini/houdini.h
314
+ - ext/hamlit/houdini/houdini_href_e.c
315
+ - ext/hamlit/houdini/houdini_html_e.c
316
+ - ext/hamlit/houdini/houdini_html_u.c
317
+ - ext/hamlit/houdini/houdini_js_e.c
318
+ - ext/hamlit/houdini/houdini_js_u.c
319
+ - ext/hamlit/houdini/houdini_uri_e.c
320
+ - ext/hamlit/houdini/houdini_uri_u.c
321
+ - ext/hamlit/houdini/houdini_xml_e.c
322
+ - ext/hamlit/houdini/html_unescape.gperf
323
+ - ext/hamlit/houdini/html_unescape.h
324
+ - ext/hamlit/houdini/tools/build_table.py
325
+ - ext/hamlit/houdini/tools/build_tables.c
326
+ - ext/hamlit/houdini/tools/wikipedia_table.txt
307
327
  - hamlit.gemspec
308
328
  - lib/hamlit.rb
309
329
  - lib/hamlit/attribute_builder.rb
330
+ - lib/hamlit/attribute_compiler.rb
310
331
  - lib/hamlit/attribute_parser.rb
311
332
  - lib/hamlit/cli.rb
312
333
  - lib/hamlit/compiler.rb
313
- - lib/hamlit/compiler/attribute_compiler.rb
314
334
  - lib/hamlit/compiler/children_compiler.rb
315
335
  - lib/hamlit/compiler/comment_compiler.rb
316
336
  - lib/hamlit/compiler/doctype_compiler.rb
@@ -355,30 +375,10 @@ files:
355
375
  - lib/hamlit/railtie.rb
356
376
  - lib/hamlit/ruby_expression.rb
357
377
  - lib/hamlit/static_analyzer.rb
358
- - lib/hamlit/string_interpolation.rb
378
+ - lib/hamlit/string_splitter.rb
359
379
  - lib/hamlit/template.rb
360
380
  - lib/hamlit/utils.rb
361
381
  - lib/hamlit/version.rb
362
- - ext/hamlit/houdini/.gitignore
363
- - ext/hamlit/houdini/COPYING
364
- - ext/hamlit/houdini/Makefile
365
- - ext/hamlit/houdini/README.md
366
- - ext/hamlit/houdini/buffer.c
367
- - ext/hamlit/houdini/buffer.h
368
- - ext/hamlit/houdini/houdini.h
369
- - ext/hamlit/houdini/houdini_href_e.c
370
- - ext/hamlit/houdini/houdini_html_e.c
371
- - ext/hamlit/houdini/houdini_html_u.c
372
- - ext/hamlit/houdini/houdini_js_e.c
373
- - ext/hamlit/houdini/houdini_js_u.c
374
- - ext/hamlit/houdini/houdini_uri_e.c
375
- - ext/hamlit/houdini/houdini_uri_u.c
376
- - ext/hamlit/houdini/houdini_xml_e.c
377
- - ext/hamlit/houdini/html_unescape.gperf
378
- - ext/hamlit/houdini/html_unescape.h
379
- - ext/hamlit/houdini/tools/build_table.py
380
- - ext/hamlit/houdini/tools/build_tables.c
381
- - ext/hamlit/houdini/tools/wikipedia_table.txt
382
382
  homepage: https://github.com/k0kubun/hamlit
383
383
  licenses:
384
384
  - MIT
@@ -389,19 +389,18 @@ require_paths:
389
389
  - lib
390
390
  required_ruby_version: !ruby/object:Gem::Requirement
391
391
  requirements:
392
- - - '>='
392
+ - - ">="
393
393
  - !ruby/object:Gem::Version
394
394
  version: '0'
395
395
  required_rubygems_version: !ruby/object:Gem::Requirement
396
396
  requirements:
397
- - - '>='
397
+ - - ">="
398
398
  - !ruby/object:Gem::Version
399
399
  version: '0'
400
400
  requirements: []
401
401
  rubyforge_project:
402
- rubygems_version: 2.0.14.1
402
+ rubygems_version: 2.5.1
403
403
  signing_key:
404
404
  specification_version: 4
405
405
  summary: High Performance Haml Implementation
406
406
  test_files: []
407
- has_rdoc:
@@ -1,148 +0,0 @@
1
- require 'hamlit/attribute_builder'
2
- require 'hamlit/attribute_parser'
3
- require 'hamlit/ruby_expression'
4
- require 'hamlit/static_analyzer'
5
- require 'hamlit/string_interpolation'
6
-
7
- module Hamlit
8
- class Compiler
9
- class AttributeCompiler
10
- def initialize(identity, options)
11
- @identity = identity
12
- @quote = options[:attr_quote]
13
- @format = options[:format]
14
- @escape_attrs = options[:escape_attrs]
15
- end
16
-
17
- def compile(node)
18
- hashes = []
19
- return runtime_compile(node) if node.value[:object_ref] != :nil
20
- node.value[:attributes_hashes].each do |attribute_str|
21
- hash = AttributeParser.parse(attribute_str)
22
- return runtime_compile(node) unless hash
23
- hashes << hash
24
- end
25
- static_compile(node.value[:attributes], hashes)
26
- end
27
-
28
- private
29
-
30
- def runtime_compile(node)
31
- attrs = node.value[:attributes_hashes]
32
- attrs.unshift(node.value[:attributes].inspect) if node.value[:attributes] != {}
33
-
34
- args = [@escape_attrs, @quote, @format].map(&:inspect).push(node.value[:object_ref]) + attrs
35
- [:html, :attrs, [:dynamic, "::Hamlit::AttributeBuilder.build(#{args.join(', ')})"]]
36
- end
37
-
38
- def static_compile(static_hash, dynamic_hashes)
39
- temple = [:html, :attrs]
40
- keys = [*static_hash.keys, *dynamic_hashes.map(&:keys).flatten].uniq.sort
41
- keys.each do |key|
42
- values = [[:static, static_hash[key]], *dynamic_hashes.map { |h| [:dynamic, h[key]] }]
43
- values.select! { |_, exp| exp != nil }
44
-
45
- case key
46
- when 'id'.freeze
47
- compile_id!(temple, key, values)
48
- when 'class'.freeze
49
- compile_class!(temple, key, values)
50
- when 'data'.freeze
51
- compile_data!(temple, key, values)
52
- when *AttributeBuilder::BOOLEAN_ATTRIBUTES, /\Adata-/
53
- compile_boolean!(temple, key, values)
54
- else
55
- compile_common!(temple, key, values)
56
- end
57
- end
58
- temple
59
- end
60
-
61
- def compile_id!(temple, key, values)
62
- build_code = attribute_builder(:id, values)
63
- if values.all? { |type, exp| type == :static || StaticAnalyzer.static?(exp) }
64
- temple << [:html, :attr, key, [:static, eval(build_code).to_s]]
65
- else
66
- temple << [:html, :attr, key, [:dynamic, build_code]]
67
- end
68
- end
69
-
70
- def compile_class!(temple, key, values)
71
- build_code = attribute_builder(:class, values)
72
- if values.all? { |type, exp| type == :static || StaticAnalyzer.static?(exp) }
73
- temple << [:html, :attr, key, [:static, eval(build_code).to_s]]
74
- else
75
- temple << [:html, :attr, key, [:dynamic, build_code]]
76
- end
77
- end
78
-
79
- def compile_data!(temple, key, values)
80
- args = [@escape_attrs.inspect, @quote.inspect, values.map { |v| literal_for(v) }]
81
- build_code = "::Hamlit::AttributeBuilder.build_data(#{args.join(', ')})"
82
-
83
- if values.all? { |type, exp| type == :static || StaticAnalyzer.static?(exp) }
84
- temple << [:static, eval(build_code).to_s]
85
- else
86
- temple << [:dynamic, build_code]
87
- end
88
- end
89
-
90
- def compile_boolean!(temple, key, values)
91
- exp = literal_for(values.last)
92
-
93
- if StaticAnalyzer.static?(exp)
94
- value = eval(exp)
95
- case value
96
- when true then temple << [:html, :attr, key, @format == :xhtml ? [:static, key] : [:multi]]
97
- when false, nil
98
- else temple << [:html, :attr, key, [:escape, @escape_attrs, [:static, value.to_s]]]
99
- end
100
- else
101
- var = @identity.generate
102
- temple << [
103
- :case, "(#{var} = (#{exp}))",
104
- ['true', [:html, :attr, key, @format == :xhtml ? [:static, key] : [:multi]]],
105
- ['false, nil', [:multi]],
106
- [:else, [:multi, [:static, " #{key}=#{@quote}"], [:escape, @escape_attrs, [:dynamic, var]], [:static, @quote]]],
107
- ]
108
- end
109
- end
110
-
111
- def compile_common!(temple, key, values)
112
- type, exp = values.last
113
-
114
- case
115
- when type == :dynamic && StaticAnalyzer.static?(exp)
116
- temple << [:html, :attr, key, [:escape, @escape_attrs, [:static, eval(exp).to_s]]]
117
- when type == :dynamic && RubyExpression.string_literal?(exp)
118
- value_temple = [:multi]
119
- StringInterpolation.compile(exp).each do |type, v|
120
- case type
121
- when :static
122
- value_temple << [:escape, @escape_attrs, [:static, v]]
123
- when :dynamic
124
- if Hamlit::StaticAnalyzer.static?(v)
125
- value_temple << [:escape, @escape_attrs, [:static, eval(v).to_s]]
126
- else
127
- value_temple << [:escape, @escape_attrs, [:dynamic, v]]
128
- end
129
- end
130
- end
131
- temple << [:html, :attr, key, value_temple]
132
- else
133
- temple << [:html, :attr, key, [:escape, @escape_attrs, [type, exp]]]
134
- end
135
- end
136
-
137
- def attribute_builder(type, values)
138
- args = [@escape_attrs.inspect, *values.map { |v| literal_for(v) }]
139
- "::Hamlit::AttributeBuilder.build_#{type}(#{args.join(', ')})"
140
- end
141
-
142
- def literal_for(value)
143
- type, exp = value
144
- type == :static ? exp.inspect : exp
145
- end
146
- end
147
- end
148
- end
@@ -1,69 +0,0 @@
1
- require 'ripper'
2
-
3
- module Hamlit::StringInterpolation
4
- class << self
5
- # `code` param must be valid string literal
6
- def compile(code)
7
- [].tap do |exps|
8
- tokens = Ripper.lex(code.strip)
9
- tokens.pop while tokens.last && %i[on_comment on_sp].include?(tokens.last[1])
10
-
11
- if tokens.size < 2
12
- raise Hamlit::InternalError.new("Expected token size >= 2 but got: #{tokens.size}")
13
- end
14
- compile_tokens!(exps, tokens)
15
- end
16
- end
17
-
18
- private
19
-
20
- def strip_quotes!(tokens)
21
- _, type, beg_str = tokens.shift
22
- if type != :on_tstring_beg
23
- raise Hamlit::InternalError.new("Expected :on_tstring_beg but got: #{type}")
24
- end
25
-
26
- _, type, end_str = tokens.pop
27
- if type != :on_tstring_end
28
- raise Hamlit::InternalError.new("Expected :on_tstring_end but got: #{type}")
29
- end
30
-
31
- [beg_str, end_str]
32
- end
33
-
34
- def compile_tokens!(exps, tokens)
35
- beg_str, end_str = strip_quotes!(tokens)
36
-
37
- until tokens.empty?
38
- _, type, str = tokens.shift
39
-
40
- case type
41
- when :on_tstring_content
42
- exps << [:static, eval("#{beg_str}#{str}#{end_str}")]
43
- when :on_embexpr_beg
44
- embedded = shift_balanced_embexpr(tokens)
45
- exps << [:dynamic, embedded] unless embedded.empty?
46
- end
47
- end
48
- end
49
-
50
- def shift_balanced_embexpr(tokens)
51
- String.new.tap do |embedded|
52
- embexpr_open = 1
53
-
54
- until tokens.empty?
55
- _, type, str = tokens.shift
56
- case type
57
- when :on_embexpr_beg
58
- embexpr_open += 1
59
- when :on_embexpr_end
60
- embexpr_open -= 1
61
- break if embexpr_open == 0
62
- end
63
-
64
- embedded << str
65
- end
66
- end
67
- end
68
- end
69
- end