hamlit 2.9.4 → 2.11.1
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 +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +12 -10
- data/CHANGELOG.md +37 -0
- data/Gemfile +2 -4
- data/REFERENCE.md +13 -4
- data/benchmark/dynamic_merger/benchmark.rb +25 -0
- data/benchmark/dynamic_merger/hello.haml +50 -0
- data/benchmark/dynamic_merger/hello.string +50 -0
- data/bin/bench +3 -3
- data/hamlit.gemspec +3 -1
- data/lib/hamlit/compiler/children_compiler.rb +17 -3
- data/lib/hamlit/compiler/comment_compiler.rb +7 -5
- data/lib/hamlit/compiler/tag_compiler.rb +0 -4
- data/lib/hamlit/dynamic_merger.rb +67 -0
- data/lib/hamlit/engine.rb +5 -6
- data/lib/hamlit/filters/plain.rb +0 -3
- data/lib/hamlit/html.rb +8 -0
- data/lib/hamlit/string_splitter.rb +9 -78
- data/lib/hamlit/template.rb +1 -1
- data/lib/hamlit/temple_line_counter.rb +31 -0
- data/lib/hamlit/version.rb +1 -1
- metadata +38 -6
- data/lib/hamlit/hamlit.su +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 315b433bd4a2af17f13b1a8ff54787c65b25beabcbdb1274dd86b29248e75f60
|
|
4
|
+
data.tar.gz: cd02934b413dd1cf6891f35f5cb1ee8731d68e0f82eb300bf92679b7574ec598
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 128daeb6d3f1d34fd33718b90b20b75117cda4147e8783d039b2daf0e019d836ac580d78fd3e01561f53f4348e442d3a04169761048cc2105ef1e3cae5c5c131
|
|
7
|
+
data.tar.gz: 0c11bc8dce803aa8d2adfdc78c7b91274678371adb7d30a8a36d997b60ada32320349712cd39c1feec7d965f5e1bbf6b6ab878a3769d4e20ee245afd1772bf79
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
|
@@ -9,11 +9,13 @@ matrix:
|
|
|
9
9
|
include:
|
|
10
10
|
- rvm: 2.3.8
|
|
11
11
|
env: TASK=test
|
|
12
|
-
- rvm: 2.4.
|
|
12
|
+
- rvm: 2.4.9
|
|
13
13
|
env: TASK=test
|
|
14
|
-
- rvm: 2.5.
|
|
14
|
+
- rvm: 2.5.7
|
|
15
15
|
env: TASK=test
|
|
16
|
-
- rvm: 2.6.
|
|
16
|
+
- rvm: 2.6.5
|
|
17
|
+
env: TASK=test
|
|
18
|
+
- rvm: 2.7.0
|
|
17
19
|
env: TASK=test
|
|
18
20
|
- rvm: ruby-head
|
|
19
21
|
env: TASK=test
|
|
@@ -21,19 +23,19 @@ matrix:
|
|
|
21
23
|
env: TASK=test
|
|
22
24
|
- rvm: truffleruby
|
|
23
25
|
env: TASK=test
|
|
24
|
-
- rvm: 2.
|
|
26
|
+
- rvm: 2.7.0
|
|
25
27
|
env: TASK=bench TEMPLATE=benchmark/boolean_attribute.haml,benchmark/class_attribute.haml,benchmark/id_attribute.haml,benchmark/data_attribute.haml,benchmark/common_attribute.haml
|
|
26
|
-
- rvm: 2.
|
|
28
|
+
- rvm: 2.7.0
|
|
27
29
|
env: TASK=bench TEMPLATE=benchmark/dynamic_attributes/boolean_attribute.haml,benchmark/dynamic_attributes/class_attribute.haml,benchmark/dynamic_attributes/id_attribute.haml,benchmark/dynamic_attributes/data_attribute.haml,benchmark/dynamic_attributes/common_attribute.haml
|
|
28
|
-
- rvm: 2.
|
|
30
|
+
- rvm: 2.7.0
|
|
29
31
|
env: TASK=bench SLIM_BENCH=1
|
|
30
|
-
- rvm: 2.
|
|
32
|
+
- rvm: 2.7.0
|
|
31
33
|
env: TASK=bench TEMPLATE=benchmark/etc/attribute_builder.haml
|
|
32
|
-
- rvm: 2.
|
|
34
|
+
- rvm: 2.7.0
|
|
33
35
|
env: TASK=bench TEMPLATE=benchmark/etc/static_analyzer.haml
|
|
34
|
-
- rvm: 2.
|
|
36
|
+
- rvm: 2.7.0
|
|
35
37
|
env: TASK=bench TEMPLATE=benchmark/etc/string_interpolation.haml
|
|
36
|
-
- rvm: 2.
|
|
38
|
+
- rvm: 2.7.0
|
|
37
39
|
env: TASK=bench TEMPLATE=test/haml/templates/standard.haml COMPILE=1
|
|
38
40
|
allow_failures:
|
|
39
41
|
- rvm: ruby-head
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,43 @@ 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.11.1](https://github.com/k0kubun/hamlit/compare/v2.11.0...v2.11.1) - 2020-08-25
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Fix a line number on an error after filters like preserve, plain, and ruby.
|
|
12
|
+
*Thanks to @rgisiger*
|
|
13
|
+
|
|
14
|
+
## [2.11.0](https://github.com/k0kubun/hamlit/compare/v2.10.1...v2.11.0) - 2019-12-12
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Support Haml's _revealed_ conditional comment feature on `/![if !IE]` [#153](https://github.com/k0kubun/hamlit/issues/153).
|
|
19
|
+
*Thanks to @esb*
|
|
20
|
+
|
|
21
|
+
## [2.10.1](https://github.com/k0kubun/hamlit/compare/v2.10.0...v2.10.1) - 2019-11-28
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- Register `Hamlit::Template` to Tilt as :hamlit as well, in addition to :haml
|
|
26
|
+
|
|
27
|
+
## [2.10.0](https://github.com/k0kubun/hamlit/compare/v2.9.5...v2.10.0) - 2019-09-15
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
|
|
31
|
+
- Optimize template rendering by string interpolation [#146](https://github.com/k0kubun/hamlit/issues/146)
|
|
32
|
+
- Exploiting pre-allocation of string interpolation introduced in Ruby 2.5 [ruby/ruby#1626](https://github.com/ruby/ruby/pull/1626)
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Require temple.gem >= 0.8.2
|
|
37
|
+
|
|
38
|
+
## [2.9.5](https://github.com/k0kubun/hamlit/compare/v2.9.4...v2.9.5) - 2019-09-08
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- Supported `:plain` filter in truffleruby
|
|
43
|
+
|
|
7
44
|
## [2.9.4](https://github.com/k0kubun/hamlit/compare/v2.9.3...v2.9.4) - 2019-09-08
|
|
8
45
|
|
|
9
46
|
### Added
|
data/Gemfile
CHANGED
|
@@ -14,17 +14,15 @@ end
|
|
|
14
14
|
|
|
15
15
|
gem 'benchmark-ips', '2.3.0'
|
|
16
16
|
gem 'maxitest'
|
|
17
|
+
gem 'pry'
|
|
17
18
|
|
|
18
19
|
if /java/ === RUBY_PLATFORM # JRuby
|
|
19
20
|
gem 'pandoc-ruby'
|
|
20
21
|
else
|
|
21
|
-
gem 'pry-byebug'
|
|
22
22
|
gem 'redcarpet'
|
|
23
23
|
|
|
24
24
|
if RUBY_PLATFORM !~ /mswin|mingw/ && RUBY_ENGINE != 'truffleruby'
|
|
25
|
-
|
|
26
|
-
gem 'faml'
|
|
27
|
-
end
|
|
25
|
+
gem 'faml'
|
|
28
26
|
gem 'stackprof'
|
|
29
27
|
end
|
|
30
28
|
end
|
data/REFERENCE.md
CHANGED
|
@@ -57,6 +57,7 @@ for full features in original implementation.
|
|
|
57
57
|
- [x] :plain
|
|
58
58
|
- [x] :preserve
|
|
59
59
|
- [x] :ruby
|
|
60
|
+
- `haml_io` API is not supported. Use [hamlit-haml\_io.gem](https://github.com/hamlit/hamlit-haml_io) if you need.
|
|
60
61
|
- [x] :sass
|
|
61
62
|
- [x] :scss
|
|
62
63
|
- [ ] :textile
|
|
@@ -121,10 +122,10 @@ and merging multiple ids results in concatenation by "\_".
|
|
|
121
122
|
%div{ id: false }
|
|
122
123
|
|
|
123
124
|
# Output
|
|
124
|
-
<div id='foo_bar'></
|
|
125
|
-
<div id='foo_bar'></
|
|
126
|
-
<div id='foo_bar'></
|
|
127
|
-
<div id=''></
|
|
125
|
+
<div id='foo_bar'></div>
|
|
126
|
+
<div id='foo_bar'></div>
|
|
127
|
+
<div id='foo_bar'></div>
|
|
128
|
+
<div id=''></div>
|
|
128
129
|
```
|
|
129
130
|
|
|
130
131
|
### class attribute
|
|
@@ -224,6 +225,14 @@ Hamlit::RailsTemplate.set_options attr_quote: '"'
|
|
|
224
225
|
set :haml, { attr_quote: '"' }
|
|
225
226
|
```
|
|
226
227
|
|
|
228
|
+
## Ruby module
|
|
229
|
+
|
|
230
|
+
`Hamlit::Template` is a module registered to `Tilt`. You can use it like:
|
|
231
|
+
|
|
232
|
+
```rb
|
|
233
|
+
Hamlit::Template.new { "%strong Yay for HAML!" }.render
|
|
234
|
+
```
|
|
235
|
+
|
|
227
236
|
## Creating a custom filter
|
|
228
237
|
|
|
229
238
|
Currently it doesn't have filter registering interface compatible with Haml.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Original: https://github.com/amatsuda/string_template/blob/master/benchmark.rb
|
|
2
|
+
require 'benchmark_driver'
|
|
3
|
+
|
|
4
|
+
Benchmark.driver(repeat_count: 8) do |x|
|
|
5
|
+
x.prelude %{
|
|
6
|
+
require 'rails'
|
|
7
|
+
require 'action_view'
|
|
8
|
+
require 'string_template'
|
|
9
|
+
StringTemplate::Railtie.run_initializers
|
|
10
|
+
require 'hamlit'
|
|
11
|
+
Hamlit::Railtie.run_initializers
|
|
12
|
+
Hamlit::RailsTemplate.set_options(escape_html: false, generator: Temple::Generators::ArrayBuffer)
|
|
13
|
+
require 'action_view/base'
|
|
14
|
+
|
|
15
|
+
(view = Class.new(ActionView::Base).new(ActionView::LookupContext.new(''))).instance_variable_set(:@world, 'world!')
|
|
16
|
+
|
|
17
|
+
# compile template
|
|
18
|
+
hello = 'benchmark/dynamic_merger/hello'
|
|
19
|
+
view.render(template: hello, handlers: 'string')
|
|
20
|
+
view.render(template: hello, handlers: 'haml')
|
|
21
|
+
}
|
|
22
|
+
x.report 'string', %{ view.render(template: hello, handlers: 'string') }
|
|
23
|
+
x.report 'hamlit', %{ view.render(template: hello, handlers: 'haml') }
|
|
24
|
+
x.loop_count 100_000
|
|
25
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
hello, #{ @world }
|
|
2
|
+
hello, #{ @world }
|
|
3
|
+
hello, #{ @world }
|
|
4
|
+
hello, #{ @world }
|
|
5
|
+
hello, #{ @world }
|
|
6
|
+
hello, #{ @world }
|
|
7
|
+
hello, #{ @world }
|
|
8
|
+
hello, #{ @world }
|
|
9
|
+
hello, #{ @world }
|
|
10
|
+
hello, #{ @world }
|
|
11
|
+
hello, #{ @world }
|
|
12
|
+
hello, #{ @world }
|
|
13
|
+
hello, #{ @world }
|
|
14
|
+
hello, #{ @world }
|
|
15
|
+
hello, #{ @world }
|
|
16
|
+
hello, #{ @world }
|
|
17
|
+
hello, #{ @world }
|
|
18
|
+
hello, #{ @world }
|
|
19
|
+
hello, #{ @world }
|
|
20
|
+
hello, #{ @world }
|
|
21
|
+
hello, #{ @world }
|
|
22
|
+
hello, #{ @world }
|
|
23
|
+
hello, #{ @world }
|
|
24
|
+
hello, #{ @world }
|
|
25
|
+
hello, #{ @world }
|
|
26
|
+
hello, #{ @world }
|
|
27
|
+
hello, #{ @world }
|
|
28
|
+
hello, #{ @world }
|
|
29
|
+
hello, #{ @world }
|
|
30
|
+
hello, #{ @world }
|
|
31
|
+
hello, #{ @world }
|
|
32
|
+
hello, #{ @world }
|
|
33
|
+
hello, #{ @world }
|
|
34
|
+
hello, #{ @world }
|
|
35
|
+
hello, #{ @world }
|
|
36
|
+
hello, #{ @world }
|
|
37
|
+
hello, #{ @world }
|
|
38
|
+
hello, #{ @world }
|
|
39
|
+
hello, #{ @world }
|
|
40
|
+
hello, #{ @world }
|
|
41
|
+
hello, #{ @world }
|
|
42
|
+
hello, #{ @world }
|
|
43
|
+
hello, #{ @world }
|
|
44
|
+
hello, #{ @world }
|
|
45
|
+
hello, #{ @world }
|
|
46
|
+
hello, #{ @world }
|
|
47
|
+
hello, #{ @world }
|
|
48
|
+
hello, #{ @world }
|
|
49
|
+
hello, #{ @world }
|
|
50
|
+
hello, #{ @world }
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
hello, #{ @world }
|
|
2
|
+
hello, #{ @world }
|
|
3
|
+
hello, #{ @world }
|
|
4
|
+
hello, #{ @world }
|
|
5
|
+
hello, #{ @world }
|
|
6
|
+
hello, #{ @world }
|
|
7
|
+
hello, #{ @world }
|
|
8
|
+
hello, #{ @world }
|
|
9
|
+
hello, #{ @world }
|
|
10
|
+
hello, #{ @world }
|
|
11
|
+
hello, #{ @world }
|
|
12
|
+
hello, #{ @world }
|
|
13
|
+
hello, #{ @world }
|
|
14
|
+
hello, #{ @world }
|
|
15
|
+
hello, #{ @world }
|
|
16
|
+
hello, #{ @world }
|
|
17
|
+
hello, #{ @world }
|
|
18
|
+
hello, #{ @world }
|
|
19
|
+
hello, #{ @world }
|
|
20
|
+
hello, #{ @world }
|
|
21
|
+
hello, #{ @world }
|
|
22
|
+
hello, #{ @world }
|
|
23
|
+
hello, #{ @world }
|
|
24
|
+
hello, #{ @world }
|
|
25
|
+
hello, #{ @world }
|
|
26
|
+
hello, #{ @world }
|
|
27
|
+
hello, #{ @world }
|
|
28
|
+
hello, #{ @world }
|
|
29
|
+
hello, #{ @world }
|
|
30
|
+
hello, #{ @world }
|
|
31
|
+
hello, #{ @world }
|
|
32
|
+
hello, #{ @world }
|
|
33
|
+
hello, #{ @world }
|
|
34
|
+
hello, #{ @world }
|
|
35
|
+
hello, #{ @world }
|
|
36
|
+
hello, #{ @world }
|
|
37
|
+
hello, #{ @world }
|
|
38
|
+
hello, #{ @world }
|
|
39
|
+
hello, #{ @world }
|
|
40
|
+
hello, #{ @world }
|
|
41
|
+
hello, #{ @world }
|
|
42
|
+
hello, #{ @world }
|
|
43
|
+
hello, #{ @world }
|
|
44
|
+
hello, #{ @world }
|
|
45
|
+
hello, #{ @world }
|
|
46
|
+
hello, #{ @world }
|
|
47
|
+
hello, #{ @world }
|
|
48
|
+
hello, #{ @world }
|
|
49
|
+
hello, #{ @world }
|
|
50
|
+
hello, #{ @world }
|
data/bin/bench
CHANGED
|
@@ -25,7 +25,7 @@ class Bench < Thor
|
|
|
25
25
|
haml = File.read(file)
|
|
26
26
|
|
|
27
27
|
Benchmark.ips do |x|
|
|
28
|
-
x.report("haml v#{Haml::VERSION}") { Haml::Engine.new(haml, escape_html: true, escape_attrs: true
|
|
28
|
+
x.report("haml v#{Haml::VERSION}") { Haml::Engine.new(haml, escape_html: true, escape_attrs: true).precompiled }
|
|
29
29
|
x.report("faml v#{Faml::VERSION}") { Faml::Engine.new.call(haml) }
|
|
30
30
|
x.report("hamlit v#{Hamlit::VERSION}") { Hamlit::Engine.new.call(haml) }
|
|
31
31
|
x.compare!
|
|
@@ -43,7 +43,7 @@ class Bench < Thor
|
|
|
43
43
|
object.instance_eval(File.read(ruby_file))
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
Haml::Engine.new(haml, escape_html: true, escape_attrs: true
|
|
46
|
+
Haml::Engine.new(haml, escape_html: true, escape_attrs: true).def_method(object, :haml)
|
|
47
47
|
object.instance_eval "def faml; #{Faml::Engine.new.call(haml)}; end"
|
|
48
48
|
object.instance_eval "def hamlit; #{Hamlit::Engine.new.call(haml)}; end"
|
|
49
49
|
|
|
@@ -59,7 +59,7 @@ class Bench < Thor
|
|
|
59
59
|
def code(file)
|
|
60
60
|
haml = File.read(file)
|
|
61
61
|
puts "#{?= * 49}\n Haml Source: #{file}\n#{?= * 49}"
|
|
62
|
-
puts Haml::Engine.new(haml, escape_html: true, escape_attrs: true
|
|
62
|
+
puts Haml::Engine.new(haml, escape_html: true, escape_attrs: true).precompiled
|
|
63
63
|
puts "\n#{?= * 49}\n Faml Source: #{file}\n#{?= * 49}"
|
|
64
64
|
puts Faml::Engine.new.call(haml)
|
|
65
65
|
puts "\n#{?= * 49}\n Hamlit Source: #{file}\n#{?= * 49}"
|
data/hamlit.gemspec
CHANGED
|
@@ -26,10 +26,11 @@ Gem::Specification.new do |spec|
|
|
|
26
26
|
spec.required_ruby_version = '>= 2.1.0'
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
spec.add_dependency 'temple', '>= 0.8.
|
|
29
|
+
spec.add_dependency 'temple', '>= 0.8.2'
|
|
30
30
|
spec.add_dependency 'thor'
|
|
31
31
|
spec.add_dependency 'tilt'
|
|
32
32
|
|
|
33
|
+
spec.add_development_dependency 'benchmark_driver'
|
|
33
34
|
spec.add_development_dependency 'bundler'
|
|
34
35
|
spec.add_development_dependency 'coffee-script'
|
|
35
36
|
spec.add_development_dependency 'erubi'
|
|
@@ -41,5 +42,6 @@ Gem::Specification.new do |spec|
|
|
|
41
42
|
spec.add_development_dependency 'rake-compiler'
|
|
42
43
|
spec.add_development_dependency 'sass'
|
|
43
44
|
spec.add_development_dependency 'slim'
|
|
45
|
+
spec.add_development_dependency 'string_template'
|
|
44
46
|
spec.add_development_dependency 'unindent'
|
|
45
47
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
require 'hamlit/temple_line_counter'
|
|
3
|
+
|
|
2
4
|
module Hamlit
|
|
3
5
|
class Compiler
|
|
4
6
|
class ChildrenCompiler
|
|
@@ -14,7 +16,7 @@ module Hamlit
|
|
|
14
16
|
node.children.each do |n|
|
|
15
17
|
rstrip_whitespace!(temple) if nuke_prev_whitespace?(n)
|
|
16
18
|
insert_newlines!(temple, n)
|
|
17
|
-
temple <<
|
|
19
|
+
temple << moving_lineno(n) { block.call(n) }
|
|
18
20
|
temple << :whitespace if insert_whitespace?(n)
|
|
19
21
|
end
|
|
20
22
|
rstrip_whitespace!(temple) if nuke_inner_whitespace?(node)
|
|
@@ -27,19 +29,31 @@ module Hamlit
|
|
|
27
29
|
(node.line - @lineno).times do
|
|
28
30
|
temple << [:newline]
|
|
29
31
|
end
|
|
32
|
+
|
|
30
33
|
@lineno = node.line
|
|
34
|
+
end
|
|
31
35
|
|
|
36
|
+
def moving_lineno(node, &block)
|
|
37
|
+
# before: As they may have children, we need to increment lineno before compilation.
|
|
32
38
|
case node.type
|
|
33
39
|
when :script, :silent_script
|
|
34
40
|
@lineno += 1
|
|
35
|
-
when :filter
|
|
36
|
-
@lineno += (node.value[:text] || '').split("\n").size
|
|
37
41
|
when :tag
|
|
38
42
|
node.value[:attributes_hashes].each do |attribute_hash|
|
|
39
43
|
@lineno += attribute_hash.count("\n")
|
|
40
44
|
end
|
|
41
45
|
@lineno += 1 if node.children.empty? && node.value[:parse]
|
|
42
46
|
end
|
|
47
|
+
|
|
48
|
+
temple = block.call # compile
|
|
49
|
+
|
|
50
|
+
# after: filter may not have children, and for some dynamic filters we can't predict the number of lines.
|
|
51
|
+
case node.type
|
|
52
|
+
when :filter
|
|
53
|
+
@lineno += TempleLineCounter.count_lines(temple)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
temple
|
|
43
57
|
end
|
|
44
58
|
|
|
45
59
|
def confirm_whitespace(temple)
|
|
@@ -25,11 +25,13 @@ module Hamlit
|
|
|
25
25
|
condition = $1
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
content =
|
|
29
|
+
if node.children.empty?
|
|
30
|
+
[:static, " #{node.value[:text]} "]
|
|
31
|
+
else
|
|
32
|
+
yield(node)
|
|
33
|
+
end
|
|
34
|
+
[:html, :condcomment, condition, content, node.value[:revealed]]
|
|
33
35
|
end
|
|
34
36
|
end
|
|
35
37
|
end
|
|
@@ -55,10 +55,6 @@ module Hamlit
|
|
|
55
55
|
|
|
56
56
|
# We should handle interpolation here to escape only interpolated values.
|
|
57
57
|
def compile_interpolated_plain(node)
|
|
58
|
-
unless Ripper.respond_to?(:lex) # No Ripper.lex in truffleruby
|
|
59
|
-
return [:multi, [:escape, node.value[:escape_interpolation], [:dynamic, "%Q[#{node.value[:value]}]"]], [:newline]]
|
|
60
|
-
end
|
|
61
|
-
|
|
62
58
|
temple = [:multi]
|
|
63
59
|
StringSplitter.compile(node.value[:value]).each do |type, value|
|
|
64
60
|
case type
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Hamlit
|
|
3
|
+
# Compile [:multi, [:static, 'foo'], [:dynamic, 'bar']] to [:dynamic, '"foo#{bar}"']
|
|
4
|
+
class DynamicMerger < Temple::Filter
|
|
5
|
+
def on_multi(*exps)
|
|
6
|
+
exps = exps.dup
|
|
7
|
+
result = [:multi]
|
|
8
|
+
buffer = []
|
|
9
|
+
|
|
10
|
+
until exps.empty?
|
|
11
|
+
type, arg = exps.first
|
|
12
|
+
if type == :dynamic && arg.count("\n") == 0
|
|
13
|
+
buffer << exps.shift
|
|
14
|
+
elsif type == :static && exps.size > (count = arg.count("\n")) &&
|
|
15
|
+
exps[1, count].all? { |e| e == [:newline] }
|
|
16
|
+
(1 + count).times { buffer << exps.shift }
|
|
17
|
+
elsif type == :newline && exps.size > (count = count_newline(exps)) &&
|
|
18
|
+
exps[count].first == :static && count == exps[count].last.count("\n")
|
|
19
|
+
(count + 1).times { buffer << exps.shift }
|
|
20
|
+
else
|
|
21
|
+
result.concat(merge_dynamic(buffer))
|
|
22
|
+
buffer = []
|
|
23
|
+
result << compile(exps.shift)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
result.concat(merge_dynamic(buffer))
|
|
27
|
+
|
|
28
|
+
result.size == 2 ? result[1] : result
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def merge_dynamic(exps)
|
|
34
|
+
# Merge exps only when they have both :static and :dynamic
|
|
35
|
+
unless exps.any? { |type,| type == :static } && exps.any? { |type,| type == :dynamic }
|
|
36
|
+
return exps
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
strlit_body = String.new
|
|
40
|
+
exps.each do |type, arg|
|
|
41
|
+
case type
|
|
42
|
+
when :static
|
|
43
|
+
strlit_body << arg.dump.sub!(/\A"/, '').sub!(/"\z/, '').gsub('\n', "\n")
|
|
44
|
+
when :dynamic
|
|
45
|
+
strlit_body << "\#{#{arg}}"
|
|
46
|
+
when :newline
|
|
47
|
+
# newline is added by `gsub('\n', "\n")`
|
|
48
|
+
else
|
|
49
|
+
raise "unexpected type #{type.inspect} is given to #merge_dynamic"
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
[[:dynamic, "%Q\0#{strlit_body}\0"]]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def count_newline(exps)
|
|
56
|
+
count = 0
|
|
57
|
+
exps.each do |exp|
|
|
58
|
+
if exp == [:newline]
|
|
59
|
+
count += 1
|
|
60
|
+
else
|
|
61
|
+
return count
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
return count
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/lib/hamlit/engine.rb
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
require 'temple'
|
|
3
3
|
require 'hamlit/parser'
|
|
4
4
|
require 'hamlit/compiler'
|
|
5
|
+
require 'hamlit/html'
|
|
5
6
|
require 'hamlit/escapable'
|
|
6
7
|
require 'hamlit/force_escapable'
|
|
7
|
-
require 'hamlit/
|
|
8
|
-
require 'hamlit/string_splitter'
|
|
8
|
+
require 'hamlit/dynamic_merger'
|
|
9
9
|
|
|
10
10
|
module Hamlit
|
|
11
11
|
class Engine < Temple::Engine
|
|
@@ -25,15 +25,14 @@ module Hamlit
|
|
|
25
25
|
use Parser
|
|
26
26
|
use Compiler
|
|
27
27
|
use HTML
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
filter :StaticAnalyzer
|
|
31
|
-
end
|
|
28
|
+
filter :StringSplitter
|
|
29
|
+
filter :StaticAnalyzer
|
|
32
30
|
use Escapable
|
|
33
31
|
use ForceEscapable
|
|
34
32
|
filter :ControlFlow
|
|
35
33
|
filter :MultiFlattener
|
|
36
34
|
filter :StaticMerger
|
|
35
|
+
use DynamicMerger
|
|
37
36
|
use :Generator, -> { options[:generator] }
|
|
38
37
|
end
|
|
39
38
|
end
|
data/lib/hamlit/filters/plain.rb
CHANGED
|
@@ -5,9 +5,6 @@ module Hamlit
|
|
|
5
5
|
class Filters
|
|
6
6
|
class Plain < Base
|
|
7
7
|
def compile(node)
|
|
8
|
-
unless Ripper.respond_to?(:lex)
|
|
9
|
-
raise NotImplementedError.new('This platform does not have Ripper.lex required for :plain filter')
|
|
10
|
-
end
|
|
11
8
|
text = node.value[:text]
|
|
12
9
|
text = text.rstrip unless ::Hamlit::HamlUtil.contains_interpolation?(text) # for compatibility
|
|
13
10
|
[:multi, *compile_plain(text)]
|
data/lib/hamlit/html.rb
CHANGED
|
@@ -10,5 +10,13 @@ module Hamlit
|
|
|
10
10
|
end
|
|
11
11
|
super(opts)
|
|
12
12
|
end
|
|
13
|
+
|
|
14
|
+
# This dispatcher supports Haml's "revealed" conditional comment.
|
|
15
|
+
def on_html_condcomment(condition, content, revealed = false)
|
|
16
|
+
on_html_comment [:multi,
|
|
17
|
+
[:static, "[#{condition}]>#{'<!-->' if revealed}"],
|
|
18
|
+
content,
|
|
19
|
+
[:static, "#{'<!--' if revealed}<![endif]"]]
|
|
20
|
+
end
|
|
13
21
|
end
|
|
14
22
|
end
|
|
@@ -2,87 +2,18 @@ require 'ripper'
|
|
|
2
2
|
require 'hamlit/ruby_expression'
|
|
3
3
|
|
|
4
4
|
module Hamlit
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
[]
|
|
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
|
|
5
|
+
module StringSplitter
|
|
6
|
+
# `code` param must be valid string literal
|
|
7
|
+
def self.compile(code)
|
|
8
|
+
unless Ripper.respond_to?(:lex) # truffleruby doesn't have Ripper.lex
|
|
9
|
+
return [[:dynamic, code]]
|
|
69
10
|
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
11
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
temple << [:static, content]
|
|
81
|
-
when :dynamic
|
|
82
|
-
temple << on_dynamic(content)
|
|
83
|
-
end
|
|
12
|
+
begin
|
|
13
|
+
Temple::Filters::StringSplitter.compile(code)
|
|
14
|
+
rescue Temple::FilterError => e
|
|
15
|
+
raise Hamlit::InternalError.new(e.message)
|
|
84
16
|
end
|
|
85
|
-
temple
|
|
86
17
|
end
|
|
87
18
|
end
|
|
88
19
|
end
|
data/lib/hamlit/template.rb
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Hamlit
|
|
3
|
+
# A module to count lines of expected code. This would be faster than actual code generation
|
|
4
|
+
# and counting newlines in it.
|
|
5
|
+
module TempleLineCounter
|
|
6
|
+
class UnexpectedExpression < StandardError; end
|
|
7
|
+
|
|
8
|
+
def self.count_lines(exp)
|
|
9
|
+
type, *args = exp
|
|
10
|
+
case type
|
|
11
|
+
when :multi
|
|
12
|
+
args.map { |a| count_lines(a) }.reduce(:+) || 0
|
|
13
|
+
when :dynamic, :code
|
|
14
|
+
args.first.count("\n")
|
|
15
|
+
when :static
|
|
16
|
+
0 # It has not real newline "\n" but escaped "\\n".
|
|
17
|
+
when :case
|
|
18
|
+
arg, *cases = args
|
|
19
|
+
arg.count("\n") + cases.map do |cond, e|
|
|
20
|
+
(cond == :else ? 0 : cond.count("\n")) + count_lines(e)
|
|
21
|
+
end.reduce(:+)
|
|
22
|
+
when :escape
|
|
23
|
+
count_lines(args[1])
|
|
24
|
+
when :newline
|
|
25
|
+
1
|
|
26
|
+
else
|
|
27
|
+
raise UnexpectedExpression.new("[HAML BUG] Unexpected Temple expression '#{type}' is given!")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/lib/hamlit/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hamlit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.11.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Takashi Kokubun
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-08-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: temple
|
|
@@ -16,14 +16,14 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 0.8.
|
|
19
|
+
version: 0.8.2
|
|
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
|
-
version: 0.8.
|
|
26
|
+
version: 0.8.2
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: thor
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,6 +52,20 @@ dependencies:
|
|
|
52
52
|
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: benchmark_driver
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
55
69
|
- !ruby/object:Gem::Dependency
|
|
56
70
|
name: bundler
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -206,6 +220,20 @@ dependencies:
|
|
|
206
220
|
- - ">="
|
|
207
221
|
- !ruby/object:Gem::Version
|
|
208
222
|
version: '0'
|
|
223
|
+
- !ruby/object:Gem::Dependency
|
|
224
|
+
name: string_template
|
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
|
226
|
+
requirements:
|
|
227
|
+
- - ">="
|
|
228
|
+
- !ruby/object:Gem::Version
|
|
229
|
+
version: '0'
|
|
230
|
+
type: :development
|
|
231
|
+
prerelease: false
|
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
233
|
+
requirements:
|
|
234
|
+
- - ">="
|
|
235
|
+
- !ruby/object:Gem::Version
|
|
236
|
+
version: '0'
|
|
209
237
|
- !ruby/object:Gem::Dependency
|
|
210
238
|
name: unindent
|
|
211
239
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -247,6 +275,9 @@ files:
|
|
|
247
275
|
- benchmark/dynamic_attributes/data_attribute.haml
|
|
248
276
|
- benchmark/dynamic_attributes/id_attribute.haml
|
|
249
277
|
- benchmark/dynamic_boolean_attribute.haml
|
|
278
|
+
- benchmark/dynamic_merger/benchmark.rb
|
|
279
|
+
- benchmark/dynamic_merger/hello.haml
|
|
280
|
+
- benchmark/dynamic_merger/hello.string
|
|
250
281
|
- benchmark/etc/attribute_builder.haml
|
|
251
282
|
- benchmark/etc/real_sample.haml
|
|
252
283
|
- benchmark/etc/real_sample.rb
|
|
@@ -290,6 +321,7 @@ files:
|
|
|
290
321
|
- lib/hamlit/compiler/script_compiler.rb
|
|
291
322
|
- lib/hamlit/compiler/silent_script_compiler.rb
|
|
292
323
|
- lib/hamlit/compiler/tag_compiler.rb
|
|
324
|
+
- lib/hamlit/dynamic_merger.rb
|
|
293
325
|
- lib/hamlit/engine.rb
|
|
294
326
|
- lib/hamlit/error.rb
|
|
295
327
|
- lib/hamlit/escapable.rb
|
|
@@ -311,7 +343,6 @@ files:
|
|
|
311
343
|
- lib/hamlit/filters/text_base.rb
|
|
312
344
|
- lib/hamlit/filters/tilt_base.rb
|
|
313
345
|
- lib/hamlit/force_escapable.rb
|
|
314
|
-
- lib/hamlit/hamlit.su
|
|
315
346
|
- lib/hamlit/helpers.rb
|
|
316
347
|
- lib/hamlit/html.rb
|
|
317
348
|
- lib/hamlit/identity.rb
|
|
@@ -333,6 +364,7 @@ files:
|
|
|
333
364
|
- lib/hamlit/ruby_expression.rb
|
|
334
365
|
- lib/hamlit/string_splitter.rb
|
|
335
366
|
- lib/hamlit/template.rb
|
|
367
|
+
- lib/hamlit/temple_line_counter.rb
|
|
336
368
|
- lib/hamlit/utils.rb
|
|
337
369
|
- lib/hamlit/version.rb
|
|
338
370
|
homepage: https://github.com/k0kubun/hamlit
|
|
@@ -354,7 +386,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
354
386
|
- !ruby/object:Gem::Version
|
|
355
387
|
version: '0'
|
|
356
388
|
requirements: []
|
|
357
|
-
rubygems_version: 3.
|
|
389
|
+
rubygems_version: 3.1.2
|
|
358
390
|
signing_key:
|
|
359
391
|
specification_version: 4
|
|
360
392
|
summary: High Performance Haml Implementation
|
data/lib/hamlit/hamlit.su
DELETED
|
Binary file
|