hamlit 1.7.2 → 2.0.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 +4 -3
- data/.gitmodules +3 -0
- data/.travis.yml +25 -37
- data/CHANGELOG.md +18 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +23 -2
- data/README.md +106 -48
- data/REFERENCE.md +222 -0
- data/Rakefile +77 -19
- data/benchmark/boolean_attribute.haml +6 -0
- data/benchmark/class_attribute.haml +5 -0
- data/benchmark/common_attribute.haml +3 -0
- data/benchmark/data_attribute.haml +4 -0
- data/benchmark/dynamic_attributes/boolean_attribute.haml +4 -0
- data/benchmark/dynamic_attributes/class_attribute.haml +4 -0
- data/benchmark/dynamic_attributes/common_attribute.haml +2 -0
- data/benchmark/dynamic_attributes/data_attribute.haml +2 -0
- data/benchmark/dynamic_attributes/id_attribute.haml +2 -0
- data/benchmark/etc/attribute_builder.haml +5 -0
- data/benchmark/etc/real_sample.haml +888 -0
- data/benchmark/etc/real_sample.rb +11 -0
- data/benchmark/etc/static_analyzer.haml +1 -0
- data/benchmark/etc/tags.haml +3 -0
- data/benchmark/ext/build_data.rb +15 -0
- data/benchmark/ext/build_id.rb +13 -0
- data/benchmark/id_attribute.haml +3 -0
- data/benchmark/plain.haml +4 -0
- data/benchmark/script.haml +4 -0
- data/benchmark/slim/LICENSE +21 -0
- data/{benchmarks → benchmark/slim}/context.rb +2 -4
- data/benchmark/slim/run-benchmarks.rb +94 -0
- data/{benchmarks → benchmark/slim}/view.erb +3 -3
- data/{benchmarks → benchmark/slim}/view.haml +0 -0
- data/{benchmarks/view.escaped.slim → benchmark/slim/view.slim} +1 -1
- data/benchmark/string_interpolation.haml +2 -0
- data/benchmark/utils/benchmark_ips_extension.rb +43 -0
- data/bin/bench +85 -0
- data/bin/clone +14 -0
- data/bin/console +11 -0
- data/bin/lineprof +48 -0
- data/bin/ruby +3 -0
- data/bin/setup +7 -0
- data/bin/stackprof +27 -0
- data/{test → bin/test} +6 -10
- data/{bin → exe}/hamlit +0 -0
- data/ext/hamlit/extconf.rb +14 -0
- data/ext/hamlit/hamlit.c +512 -0
- data/ext/hamlit/houdini/.gitignore +3 -0
- data/ext/hamlit/houdini/COPYING +7 -0
- data/ext/hamlit/houdini/Makefile +79 -0
- data/ext/hamlit/houdini/README.md +59 -0
- data/ext/hamlit/houdini/buffer.c +249 -0
- data/ext/hamlit/houdini/buffer.h +113 -0
- data/ext/hamlit/houdini/houdini.h +46 -0
- data/ext/hamlit/houdini/houdini_href_e.c +115 -0
- data/ext/hamlit/houdini/houdini_html_e.c +90 -0
- data/ext/hamlit/houdini/houdini_html_u.c +122 -0
- data/ext/hamlit/houdini/houdini_js_e.c +90 -0
- data/ext/hamlit/houdini/houdini_js_u.c +60 -0
- data/ext/hamlit/houdini/houdini_uri_e.c +107 -0
- data/ext/hamlit/houdini/houdini_uri_u.c +68 -0
- data/ext/hamlit/houdini/houdini_xml_e.c +136 -0
- data/ext/hamlit/houdini/html_unescape.gperf +258 -0
- data/ext/hamlit/houdini/html_unescape.h +754 -0
- data/ext/hamlit/houdini/tools/build_table.py +13 -0
- data/ext/hamlit/houdini/tools/build_tables.c +51 -0
- data/ext/hamlit/houdini/tools/wikipedia_table.txt +2025 -0
- data/hamlit.gemspec +30 -31
- data/lib/hamlit.rb +3 -1
- data/lib/hamlit/attribute_builder.rb +12 -0
- data/lib/hamlit/cli.rb +44 -43
- data/lib/hamlit/compiler.rb +92 -16
- data/lib/hamlit/compiler/attribute_compiler.rb +148 -0
- data/lib/hamlit/compiler/children_compiler.rb +111 -0
- data/lib/hamlit/compiler/comment_compiler.rb +36 -0
- data/lib/hamlit/compiler/doctype_compiler.rb +45 -0
- data/lib/hamlit/compiler/script_compiler.rb +97 -0
- data/lib/hamlit/compiler/silent_script_compiler.rb +24 -0
- data/lib/hamlit/compiler/tag_compiler.rb +69 -0
- data/lib/hamlit/engine.rb +12 -7
- data/lib/hamlit/error.rb +14 -0
- data/lib/hamlit/escapable.rb +12 -0
- data/lib/hamlit/filters.rb +65 -0
- data/lib/hamlit/filters/base.rb +4 -62
- data/lib/hamlit/filters/coffee.rb +9 -7
- data/lib/hamlit/filters/css.rb +25 -8
- data/lib/hamlit/filters/erb.rb +4 -6
- data/lib/hamlit/filters/escaped.rb +11 -9
- data/lib/hamlit/filters/javascript.rb +25 -8
- data/lib/hamlit/filters/less.rb +9 -7
- data/lib/hamlit/filters/markdown.rb +5 -6
- data/lib/hamlit/filters/plain.rb +11 -15
- data/lib/hamlit/filters/preserve.rb +15 -5
- data/lib/hamlit/filters/ruby.rb +3 -5
- data/lib/hamlit/filters/sass.rb +9 -7
- data/lib/hamlit/filters/scss.rb +9 -7
- data/lib/hamlit/filters/text_base.rb +24 -0
- data/lib/hamlit/filters/tilt_base.rb +47 -0
- data/lib/hamlit/hash_parser.rb +107 -0
- data/lib/hamlit/html.rb +9 -6
- data/lib/hamlit/identity.rb +12 -0
- data/lib/hamlit/object_ref.rb +29 -0
- data/lib/hamlit/parser.rb +25 -142
- data/lib/hamlit/parser/MIT-LICENSE +20 -0
- data/lib/hamlit/parser/README.md +28 -0
- data/lib/hamlit/parser/haml_buffer.rb +348 -0
- data/lib/hamlit/parser/haml_compiler.rb +553 -0
- data/lib/hamlit/parser/haml_error.rb +61 -0
- data/lib/hamlit/parser/haml_helpers.rb +727 -0
- data/lib/hamlit/parser/haml_options.rb +286 -0
- data/lib/hamlit/parser/haml_parser.rb +801 -0
- data/lib/hamlit/parser/haml_util.rb +283 -0
- data/lib/hamlit/parser/haml_xss_mods.rb +109 -0
- data/lib/hamlit/{helpers.rb → rails_helpers.rb} +2 -7
- data/lib/hamlit/rails_template.rb +30 -0
- data/lib/hamlit/railtie.rb +1 -12
- data/lib/hamlit/ruby_expression.rb +31 -0
- data/lib/hamlit/static_analyzer.rb +49 -0
- data/lib/hamlit/string_interpolation.rb +69 -0
- data/lib/hamlit/template.rb +8 -0
- data/lib/hamlit/utils.rb +9 -0
- data/lib/hamlit/version.rb +1 -1
- metadata +116 -324
- data/.rspec +0 -2
- data/benchmarks/benchmark.rb +0 -110
- data/benchmarks/view.slim +0 -17
- data/doc/README.md +0 -19
- data/doc/engine/indent.md +0 -48
- data/doc/engine/new_attribute.md +0 -77
- data/doc/engine/old_attributes.md +0 -198
- data/doc/engine/silent_script.md +0 -97
- data/doc/engine/tag.md +0 -48
- data/doc/engine/text.md +0 -64
- data/doc/faml/README.md +0 -16
- data/doc/faml/engine/indent.md +0 -48
- data/doc/faml/engine/old_attributes.md +0 -111
- data/doc/faml/engine/silent_script.md +0 -97
- data/doc/faml/engine/text.md +0 -59
- data/doc/faml/filters/erb.md +0 -24
- data/doc/faml/filters/javascript.md +0 -27
- data/doc/faml/filters/less.md +0 -57
- data/doc/faml/filters/plain.md +0 -25
- data/doc/filters/erb.md +0 -31
- data/doc/filters/javascript.md +0 -83
- data/doc/filters/less.md +0 -57
- data/doc/filters/markdown.md +0 -31
- data/doc/filters/plain.md +0 -25
- data/doc/haml/README.md +0 -15
- data/doc/haml/engine/new_attribute.md +0 -77
- data/doc/haml/engine/old_attributes.md +0 -142
- data/doc/haml/engine/tag.md +0 -48
- data/doc/haml/engine/text.md +0 -29
- data/doc/haml/filters/erb.md +0 -26
- data/doc/haml/filters/javascript.md +0 -76
- data/doc/haml/filters/markdown.md +0 -31
- data/lib/hamlit/attribute.rb +0 -78
- data/lib/hamlit/compilers/attributes.rb +0 -108
- data/lib/hamlit/compilers/comment.rb +0 -13
- data/lib/hamlit/compilers/doctype.rb +0 -39
- data/lib/hamlit/compilers/filter.rb +0 -53
- data/lib/hamlit/compilers/new_attribute.rb +0 -115
- data/lib/hamlit/compilers/old_attribute.rb +0 -241
- data/lib/hamlit/compilers/runtime_attribute.rb +0 -58
- data/lib/hamlit/compilers/script.rb +0 -31
- data/lib/hamlit/compilers/strip.rb +0 -19
- data/lib/hamlit/compilers/text.rb +0 -111
- data/lib/hamlit/concerns/attribute_builder.rb +0 -22
- data/lib/hamlit/concerns/balanceable.rb +0 -68
- data/lib/hamlit/concerns/deprecation.rb +0 -20
- data/lib/hamlit/concerns/error.rb +0 -31
- data/lib/hamlit/concerns/escapable.rb +0 -17
- data/lib/hamlit/concerns/included.rb +0 -28
- data/lib/hamlit/concerns/indentable.rb +0 -117
- data/lib/hamlit/concerns/lexable.rb +0 -32
- data/lib/hamlit/concerns/line_reader.rb +0 -62
- data/lib/hamlit/concerns/registerable.rb +0 -24
- data/lib/hamlit/concerns/string_interpolation.rb +0 -48
- data/lib/hamlit/concerns/whitespace.rb +0 -91
- data/lib/hamlit/filters/tilt.rb +0 -41
- data/lib/hamlit/parsers/attribute.rb +0 -71
- data/lib/hamlit/parsers/comment.rb +0 -30
- data/lib/hamlit/parsers/doctype.rb +0 -18
- data/lib/hamlit/parsers/filter.rb +0 -18
- data/lib/hamlit/parsers/multiline.rb +0 -58
- data/lib/hamlit/parsers/script.rb +0 -126
- data/lib/hamlit/parsers/tag.rb +0 -83
- data/lib/hamlit/parsers/text.rb +0 -28
- data/lib/hamlit/temple.rb +0 -9
- data/release +0 -6
- data/spec/Rakefile +0 -72
- data/spec/hamlit/engine/comment_spec.rb +0 -56
- data/spec/hamlit/engine/doctype_spec.rb +0 -19
- data/spec/hamlit/engine/error_spec.rb +0 -135
- data/spec/hamlit/engine/indent_spec.rb +0 -42
- data/spec/hamlit/engine/multiline_spec.rb +0 -44
- data/spec/hamlit/engine/new_attribute_spec.rb +0 -110
- data/spec/hamlit/engine/old_attributes_spec.rb +0 -404
- data/spec/hamlit/engine/script_spec.rb +0 -116
- data/spec/hamlit/engine/silent_script_spec.rb +0 -213
- data/spec/hamlit/engine/tag_spec.rb +0 -295
- data/spec/hamlit/engine/text_spec.rb +0 -239
- data/spec/hamlit/engine_spec.rb +0 -58
- data/spec/hamlit/filters/coffee_spec.rb +0 -60
- data/spec/hamlit/filters/css_spec.rb +0 -33
- data/spec/hamlit/filters/erb_spec.rb +0 -16
- data/spec/hamlit/filters/javascript_spec.rb +0 -82
- data/spec/hamlit/filters/less_spec.rb +0 -37
- data/spec/hamlit/filters/markdown_spec.rb +0 -30
- data/spec/hamlit/filters/plain_spec.rb +0 -15
- data/spec/hamlit/filters/ruby_spec.rb +0 -24
- data/spec/hamlit/filters/sass_spec.rb +0 -33
- data/spec/hamlit/filters/scss_spec.rb +0 -37
- data/spec/hamlit/haml_spec.rb +0 -910
- data/spec/rails/.gitignore +0 -18
- data/spec/rails/.rspec +0 -2
- data/spec/rails/Gemfile +0 -19
- data/spec/rails/README.rdoc +0 -28
- data/spec/rails/Rakefile +0 -6
- data/spec/rails/app/assets/images/.keep +0 -0
- data/spec/rails/app/assets/javascripts/application.js +0 -15
- data/spec/rails/app/assets/stylesheets/application.css +0 -15
- data/spec/rails/app/controllers/application_controller.rb +0 -8
- data/spec/rails/app/controllers/concerns/.keep +0 -0
- data/spec/rails/app/controllers/users_controller.rb +0 -23
- data/spec/rails/app/helpers/application_helper.rb +0 -2
- data/spec/rails/app/mailers/.keep +0 -0
- data/spec/rails/app/models/.keep +0 -0
- data/spec/rails/app/models/concerns/.keep +0 -0
- data/spec/rails/app/views/application/index.html.haml +0 -18
- data/spec/rails/app/views/layouts/application.html.haml +0 -12
- data/spec/rails/app/views/users/capture.html.haml +0 -5
- data/spec/rails/app/views/users/capture_haml.html.haml +0 -5
- data/spec/rails/app/views/users/form.html.haml +0 -2
- data/spec/rails/app/views/users/helpers.html.haml +0 -10
- data/spec/rails/app/views/users/index.html.haml +0 -9
- data/spec/rails/app/views/users/inline.html.haml +0 -6
- data/spec/rails/app/views/users/old_attributes.html.haml +0 -5
- data/spec/rails/app/views/users/safe_buffer.html.haml +0 -4
- data/spec/rails/app/views/users/whitespace.html.haml +0 -4
- data/spec/rails/bin/bundle +0 -3
- data/spec/rails/bin/rails +0 -8
- data/spec/rails/bin/rake +0 -8
- data/spec/rails/bin/setup +0 -29
- data/spec/rails/bin/spring +0 -15
- data/spec/rails/config.ru +0 -4
- data/spec/rails/config/application.rb +0 -34
- data/spec/rails/config/boot.rb +0 -3
- data/spec/rails/config/database.yml +0 -25
- data/spec/rails/config/environment.rb +0 -5
- data/spec/rails/config/environments/development.rb +0 -41
- data/spec/rails/config/environments/production.rb +0 -79
- data/spec/rails/config/environments/test.rb +0 -42
- data/spec/rails/config/initializers/assets.rb +0 -11
- data/spec/rails/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/rails/config/initializers/cookies_serializer.rb +0 -3
- data/spec/rails/config/initializers/filter_parameter_logging.rb +0 -4
- data/spec/rails/config/initializers/inflections.rb +0 -16
- data/spec/rails/config/initializers/mime_types.rb +0 -4
- data/spec/rails/config/initializers/session_store.rb +0 -3
- data/spec/rails/config/initializers/wrap_parameters.rb +0 -14
- data/spec/rails/config/locales/en.yml +0 -24
- data/spec/rails/config/routes.rb +0 -16
- data/spec/rails/config/secrets.yml +0 -22
- data/spec/rails/db/schema.rb +0 -16
- data/spec/rails/db/seeds.rb +0 -7
- data/spec/rails/lib/assets/.keep +0 -0
- data/spec/rails/lib/tasks/.keep +0 -0
- data/spec/rails/log/.keep +0 -0
- data/spec/rails/public/404.html +0 -67
- data/spec/rails/public/422.html +0 -67
- data/spec/rails/public/500.html +0 -66
- data/spec/rails/public/favicon.ico +0 -0
- data/spec/rails/public/robots.txt +0 -5
- data/spec/rails/spec/hamlit_spec.rb +0 -123
- data/spec/rails/spec/rails_helper.rb +0 -56
- data/spec/rails/spec/spec_helper.rb +0 -91
- data/spec/rails/vendor/assets/javascripts/.keep +0 -0
- data/spec/rails/vendor/assets/stylesheets/.keep +0 -0
- data/spec/spec_helper.rb +0 -36
- data/spec/spec_helper/document_generator.rb +0 -93
- data/spec/spec_helper/render_helper.rb +0 -120
- data/spec/spec_helper/test_case.rb +0 -55
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 28a84db73fc904f991af638d917007332547d58d
|
|
4
|
+
data.tar.gz: f1d1b3f015fb126cb5b4f17bbe98ed9d544e93a1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 03d00832e894a37163e28f1ff2f635d9c77cc456be27b335b653a2367e3fe2cb5804524a7db955f564612ff5453b0b900751ed9c815a7342e303180312f47ae8
|
|
7
|
+
data.tar.gz: 4aecd7d189befada1018c846c0059ff093d84fa03c414840e8454add6888725039eebd76035cec8b5d65716c5123baf528fb80bea113538b337d78d535c8c212
|
data/.gitignore
CHANGED
data/.gitmodules
ADDED
data/.travis.yml
CHANGED
|
@@ -1,42 +1,30 @@
|
|
|
1
1
|
language: ruby
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
- 2.2
|
|
6
|
-
sudo: false
|
|
7
|
-
cache: bundler
|
|
2
|
+
branches:
|
|
3
|
+
only:
|
|
4
|
+
- master
|
|
8
5
|
script:
|
|
9
6
|
- "bundle exec rake $TASK"
|
|
10
|
-
gemfile:
|
|
11
|
-
- Gemfile
|
|
12
|
-
- spec/rails/Gemfile
|
|
13
|
-
env:
|
|
14
|
-
- TASK=spec
|
|
15
|
-
- TASK=rails:spec
|
|
16
|
-
- TASK=bench TIME=20
|
|
17
|
-
- TASK=bench TIME=20 HTML_ESCAPE=1
|
|
18
7
|
matrix:
|
|
19
|
-
|
|
20
|
-
- env: TASK=bench TIME=20
|
|
21
|
-
- env: TASK=bench TIME=20 HTML_ESCAPE=1
|
|
22
|
-
exclude:
|
|
23
|
-
- env: TASK=spec
|
|
24
|
-
gemfile: spec/rails/Gemfile
|
|
25
|
-
- env: TASK=rails:spec
|
|
26
|
-
gemfile: Gemfile
|
|
27
|
-
- env: TASK=bench TIME=20
|
|
28
|
-
gemfile: spec/rails/Gemfile
|
|
29
|
-
- env: TASK=bench TIME=20 HTML_ESCAPE=1
|
|
30
|
-
gemfile: spec/rails/Gemfile
|
|
31
|
-
- rvm: 2.1
|
|
32
|
-
env: TASK=rails:spec
|
|
33
|
-
- rvm: 2.1
|
|
34
|
-
env: TASK=bench TIME=20
|
|
35
|
-
- rvm: 2.1
|
|
36
|
-
env: TASK=bench TIME=20 HTML_ESCAPE=1
|
|
8
|
+
include:
|
|
37
9
|
- rvm: 2.0.0
|
|
38
|
-
env: TASK=
|
|
39
|
-
- rvm: 2.
|
|
40
|
-
env: TASK=
|
|
41
|
-
- rvm: 2.
|
|
42
|
-
env: TASK=
|
|
10
|
+
env: TASK=test
|
|
11
|
+
- rvm: 2.1
|
|
12
|
+
env: TASK=test
|
|
13
|
+
- rvm: 2.2
|
|
14
|
+
env: TASK=test
|
|
15
|
+
- rvm: 2.2
|
|
16
|
+
env: TASK=bench TEMPLATE=benchmark/boolean_attribute.haml,benchmark/class_attribute.haml,benchmark/id_attribute.haml,benchmark/data_attribute.haml,benchmark/common_attribute.haml
|
|
17
|
+
- rvm: 2.2
|
|
18
|
+
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
|
|
19
|
+
- rvm: 2.2
|
|
20
|
+
env: TASK=bench TEMPLATE=benchmark/etc/attribute_builder.haml
|
|
21
|
+
- rvm: 2.2
|
|
22
|
+
env: TASK=bench SLIM_BENCH=1
|
|
23
|
+
- rvm: 2.2
|
|
24
|
+
env: TASK=bench TEMPLATE=test/haml/templates/standard.haml COMPILE=1
|
|
25
|
+
allow_failures:
|
|
26
|
+
- env: TASK=bench TEMPLATE=benchmark/boolean_attribute.haml,benchmark/class_attribute.haml,benchmark/id_attribute.haml,benchmark/data_attribute.haml,benchmark/common_attribute.haml
|
|
27
|
+
- 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
|
+
- env: TASK=bench TEMPLATE=benchmark/etc/attribute_builder.haml
|
|
29
|
+
- env: TASK=bench SLIM_BENCH=1
|
|
30
|
+
- env: TASK=bench TEMPLATE=test/haml/templates/standard.haml COMPILE=1
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## v2.0.0
|
|
2
|
+
|
|
3
|
+
- Full scratch of internal implementation
|
|
4
|
+
- Rendering is strongly optimized
|
|
5
|
+
- Static analyzer is introduced
|
|
6
|
+
- Built with C extension for runtime rendering
|
|
7
|
+
- Optimized compilation for 5 types of attributes
|
|
8
|
+
- Compilation became faster too
|
|
9
|
+
- Many rendering incompatibilities are resolved
|
|
10
|
+
- Object reference support
|
|
11
|
+
- Breaking changes:
|
|
12
|
+
- Replaced parser with original Haml's one
|
|
13
|
+
- Incompatible parsing error will never happen, but we can no longer parse attributes with Ripper
|
|
14
|
+
- Unified behavior for both static and dynamic attributes, see [5 types of attributes](REFERENCE.md#5-types-of-attributes)
|
|
15
|
+
- Though inconsistent behavior is removed, we can no longer rely on completely-Haml-compatible behavior of static attributes and pass haml-spec
|
|
16
|
+
- Added :escape\_attrs option
|
|
17
|
+
- You should specify HTML-escaping availability for script and attrs separately.
|
|
18
|
+
|
|
1
19
|
## v1.7.2
|
|
2
20
|
|
|
3
21
|
- Bugfix about parsing a content of tag
|
data/Gemfile
CHANGED
|
@@ -2,3 +2,19 @@ source 'https://rubygems.org'
|
|
|
2
2
|
|
|
3
3
|
# Specify your gem's dependencies in hamlit.gemspec
|
|
4
4
|
gemspec
|
|
5
|
+
|
|
6
|
+
# maintain compatibility against master
|
|
7
|
+
gem 'haml', github: 'haml/haml'
|
|
8
|
+
|
|
9
|
+
gem 'benchmark-ips', '2.3.0'
|
|
10
|
+
gem 'minitest-line'
|
|
11
|
+
gem 'pry-byebug'
|
|
12
|
+
|
|
13
|
+
if File.exist?('hamlit1')
|
|
14
|
+
gem 'hamlit1', path: 'hamlit1'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
if RUBY_VERSION >= '2.1.0'
|
|
18
|
+
gem 'lineprof'
|
|
19
|
+
gem 'stackprof'
|
|
20
|
+
end
|
data/LICENSE.txt
CHANGED
|
@@ -1,7 +1,28 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
1
3
|
Copyright (c) 2015 Takashi Kokubun
|
|
2
|
-
Copyright (c) 2006-2009 Hampton Catlin and Natalie Weizenbaum
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
22
|
+
|
|
23
|
+
lib/hamlit/parser/*.rb and test/haml/* are:
|
|
24
|
+
|
|
25
|
+
Copyright (c) 2006-2009 Hampton Catlin and Natalie Weizenbaum
|
|
5
26
|
|
|
6
27
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
7
28
|
a copy of this software and associated documentation files (the
|
data/README.md
CHANGED
|
@@ -2,27 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
[](http://badge.fury.io/rb/hamlit)
|
|
4
4
|
[](https://travis-ci.org/k0kubun/hamlit)
|
|
5
|
-
[](https://coveralls.io/r/k0kubun/hamlit?branch=master)
|
|
6
|
-
[](https://codeclimate.com/github/k0kubun/hamlit)
|
|
7
5
|
|
|
8
|
-
Hamlit is a high performance [
|
|
6
|
+
Hamlit is a high performance [Haml](https://github.com/haml/haml) implementation.
|
|
9
7
|
|
|
10
|
-
##
|
|
8
|
+
## Introduction
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
### What is Hamlit?
|
|
11
|
+
Hamlit is another implementation of [Haml](https://github.com/haml/haml).
|
|
12
|
+
With some [limitations](REFERENCE.md#limitations) by design for performance,
|
|
13
|
+
Hamlit is **7.16x times faster** than original haml gem in [this benchmark](benchmark/slim/run-benchmarks.rb),
|
|
14
|
+
which is an HTML-escaped version of [slim-template/slim's one](https://github.com/slim-template/slim/blob/v3.0.6/benchmarks/run-benchmarks.rb) for fairness.
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
gem 'hamlit'
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
or just replace `gem "haml"` with `gem "hamlit"`.
|
|
19
|
-
|
|
20
|
-
## Features
|
|
21
|
-
### Fast rendering
|
|
22
|
-
|
|
23
|
-

|
|
24
|
-
|
|
25
|
-
Hamlit's rendering is **7.16x times faster** than original haml.
|
|
16
|
+

|
|
26
17
|
|
|
27
18
|
```
|
|
28
19
|
erubis: 114501.6 i/s
|
|
@@ -32,56 +23,123 @@ Hamlit's rendering is **7.16x times faster** than original haml.
|
|
|
32
23
|
haml: 15750.6 i/s - 7.27x slower
|
|
33
24
|
```
|
|
34
25
|
|
|
35
|
-
|
|
36
|
-
is the same as [slim-template/slim](https://github.com/slim-template/slim)'s one for fairness.
|
|
37
|
-
([The result on travis CI](https://travis-ci.org/k0kubun/hamlit/jobs/58162910))
|
|
26
|
+
### Why is Hamlit faster?
|
|
38
27
|
|
|
39
|
-
|
|
28
|
+
#### Less string concatenation by design
|
|
29
|
+
As written in [limitations](REFERENCE.md#limitations), Hamlit drops some not-so-important features which require
|
|
30
|
+
works on runtime. With the optimized language design, we can reduce the string concatenation
|
|
31
|
+
to build attributes.
|
|
40
32
|
|
|
41
|
-
|
|
42
|
-
Hamlit
|
|
43
|
-
|
|
33
|
+
#### Temple optimizers
|
|
34
|
+
Hamlit is built with [Temple](https://github.com/judofyr/temple), which is a framework to build
|
|
35
|
+
template engines and also used in Slim. By using the framework and its optimizers, Hamlit can
|
|
36
|
+
reduce string allocation and concatenation easily.
|
|
44
37
|
|
|
45
|
-
|
|
38
|
+
#### Static analyzer
|
|
39
|
+
Hamlit analyzes Ruby expressions with Ripper and render it on compilation if the expression
|
|
40
|
+
is static. And Hamlit can also compile string literal with string interpolation to reduce
|
|
41
|
+
string allocation and concatenation on runtime.
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
#### C extension to build attributes
|
|
44
|
+
While Hamlit has static analyzer and static attributes are rendered on compilation,
|
|
45
|
+
dynamic attributes must be rendered on runtime. So Hamlit optimizes rendering on runtime
|
|
46
|
+
with C extension.
|
|
51
47
|
|
|
52
48
|
## Usage
|
|
53
49
|
|
|
54
|
-
|
|
55
|
-
Check out the [reference documentation](http://haml.info/docs/yardoc/file.REFERENCE.html) for details.
|
|
50
|
+
See [REFERENCE.md](REFERENCE.md) for detail features of Hamlit.
|
|
56
51
|
|
|
57
52
|
### Rails
|
|
58
|
-
|
|
53
|
+
|
|
54
|
+
Add this line to your application's Gemfile or just replace `gem "haml"` with `gem "hamlit"`.
|
|
55
|
+
It enables rendering by Hamlit for \*.haml automatically.
|
|
56
|
+
|
|
57
|
+
```rb
|
|
58
|
+
gem 'hamlit'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If you want to use view generator, consider using [hamlit-rails](https://github.com/mfung/hamlit-rails).
|
|
59
62
|
|
|
60
63
|
### Sinatra
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
|
|
65
|
+
Replace `gem "haml"` with `gem "hamlit"` in Gemfile, and require "hamlit".
|
|
66
|
+
See [sample/sinatra](sample/sinatra) for working sample.
|
|
67
|
+
|
|
68
|
+
While Haml disables `escape_html` option by default, Hamlit enables it for security.
|
|
69
|
+
If you want to disable it, please write:
|
|
63
70
|
|
|
64
71
|
```rb
|
|
65
72
|
set :haml, { escape_html: false }
|
|
66
73
|
```
|
|
67
74
|
|
|
68
|
-
## Why high performance?
|
|
69
|
-
### Less work on runtime
|
|
70
|
-
Haml's rendering is very slow because generated code by haml runs many operations on runtime.
|
|
71
|
-
For example, Haml::Util is extended on view, attribute rendering runs even if it is a
|
|
72
|
-
static value and the values in attribute is sorted. All of them is achieved on runtime.
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
## Command line interface
|
|
77
|
+
|
|
78
|
+
You can see compiled code or rendering result with "hamlit" command.
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
$ gem install hamlit
|
|
82
|
+
$ hamlit --help
|
|
83
|
+
Commands:
|
|
84
|
+
hamlit compile HAML # Show compile result
|
|
85
|
+
hamlit help [COMMAND] # Describe available commands or one specific command
|
|
86
|
+
hamlit parse HAML # Show parse result
|
|
87
|
+
hamlit render HAML # Render haml template
|
|
88
|
+
hamlit temple HAML # Show temple intermediate expression
|
|
89
|
+
|
|
90
|
+
$ cat in.haml
|
|
91
|
+
- user_id = 123
|
|
92
|
+
%a{ href: "/users/#{user_id}" }
|
|
93
|
+
|
|
94
|
+
# Show compiled code
|
|
95
|
+
$ hamlit compile in.haml
|
|
96
|
+
_buf = []; user_id = 123;
|
|
97
|
+
; _buf << ("<a href='/users/".freeze); _buf << (::Hamlit::Utils.escape_html((user_id))); _buf << ("'></a>\n".freeze); _buf = _buf.join
|
|
98
|
+
|
|
99
|
+
# Render html
|
|
100
|
+
$ hamlit render in.haml
|
|
101
|
+
<a href='/users/123'></a>
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Contributing
|
|
105
|
+
|
|
106
|
+
### Development
|
|
107
|
+
|
|
108
|
+
Contributions are welcomed. It'd be good to see
|
|
109
|
+
[Temple's EXPRESSIONS.md](https://github.com/judofyr/temple/blob/v0.7.6/EXPRESSIONS.md)
|
|
110
|
+
to learn Temple which is a template engine framework used in Hamlit.
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
$ git clone https://github.com/k0kubun/hamlit
|
|
114
|
+
$ cd hamlit
|
|
115
|
+
$ bundle install
|
|
116
|
+
|
|
117
|
+
# Run all tests
|
|
118
|
+
$ bundle exec rake test
|
|
119
|
+
|
|
120
|
+
# Run one test
|
|
121
|
+
$ bundle exec ruby -Ilib:test -rtest_helper test/hamlit/line_number_test.rb -l 12
|
|
122
|
+
|
|
123
|
+
# Show compiling/rendering result of some template
|
|
124
|
+
$ bundle exec exe/hamlit compile in.haml
|
|
125
|
+
$ bundle exec exe/hamlit render in.haml
|
|
126
|
+
|
|
127
|
+
# Use rails app to debug Hamlit
|
|
128
|
+
$ cd sample/rails
|
|
129
|
+
$ bundle install
|
|
130
|
+
$ bundle exec rails s
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Reporting an issue
|
|
76
134
|
|
|
77
|
-
|
|
78
|
-
Hamlit is implemented with [temple](https://github.com/judofyr/temple), which is a template
|
|
79
|
-
engine framework for Ruby. Temple has some great optimizers for generated code. Thus generated
|
|
80
|
-
code by Hamlit is very fast.
|
|
135
|
+
Please report an issue with following information:
|
|
81
136
|
|
|
82
|
-
|
|
83
|
-
|
|
137
|
+
- Full error backtrace
|
|
138
|
+
- Haml template
|
|
139
|
+
- Ruby version
|
|
140
|
+
- Hamlit version
|
|
141
|
+
- Rails/Sinatra version
|
|
84
142
|
|
|
85
143
|
## License
|
|
86
144
|
|
|
87
|
-
|
|
145
|
+
Copyright (c) 2015 Takashi Kokubun
|
data/REFERENCE.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Hamlit
|
|
2
|
+
|
|
3
|
+
Basically Hamlit is the same as Haml.
|
|
4
|
+
See [Haml's tutorial](http://haml.info/tutorial.html) if you are not familiar with Haml's syntax.
|
|
5
|
+
|
|
6
|
+
[REFERENCE - Haml Documentation](http://haml.info/docs/yardoc/file.REFERENCE.html)
|
|
7
|
+
|
|
8
|
+
## Supported features
|
|
9
|
+
|
|
10
|
+
See [Haml's reference](http://haml.info/docs/yardoc/file.REFERENCE.html)
|
|
11
|
+
for full features in original implementation.
|
|
12
|
+
|
|
13
|
+
- [x] Using Haml
|
|
14
|
+
- [x] Rails XSS Protection
|
|
15
|
+
- [x] Ruby Module
|
|
16
|
+
- [x] Options
|
|
17
|
+
- [ ] Encodings
|
|
18
|
+
- [x] Plain Text
|
|
19
|
+
- [x] Escaping: \
|
|
20
|
+
- [x] HTML Elements
|
|
21
|
+
- [x] Element Name: %
|
|
22
|
+
- [x] Attributes: `
|
|
23
|
+
- [x] :class and :id Attributes
|
|
24
|
+
- [x] HTML-style Attributes: ()
|
|
25
|
+
- [x] Ruby 1.9-style Hashes
|
|
26
|
+
- [ ] Attribute Methods
|
|
27
|
+
- [x] Boolean Attributes
|
|
28
|
+
- [x] HTML5 Custom Data Attributes
|
|
29
|
+
- [x] Class and ID: . and #
|
|
30
|
+
- Implicit Div Elements
|
|
31
|
+
- [x] Empty (void) Tags: /
|
|
32
|
+
- [x] Whitespace Removal: > and <
|
|
33
|
+
- [x] Object Reference: []
|
|
34
|
+
- [x] Doctype: !!!
|
|
35
|
+
- [x] Comments
|
|
36
|
+
- [x] HTML Comments: /
|
|
37
|
+
- [x] Conditional Comments: /[]
|
|
38
|
+
- [x] Haml Comments: -#
|
|
39
|
+
- [x] Ruby Evaluation
|
|
40
|
+
- [x] Inserting Ruby: =
|
|
41
|
+
- [x] Running Ruby: -
|
|
42
|
+
- [x] Ruby Blocks
|
|
43
|
+
- [x] Whitespace Preservation: ~
|
|
44
|
+
- [x] Ruby Interpolation: #{}
|
|
45
|
+
- [x] Escaping HTML: &=
|
|
46
|
+
- [x] Unescaping HTML: !=
|
|
47
|
+
- [x] Filters
|
|
48
|
+
- [ ] :cdata
|
|
49
|
+
- [x] :coffee
|
|
50
|
+
- [x] :css
|
|
51
|
+
- [x] :erb
|
|
52
|
+
- [x] :escaped
|
|
53
|
+
- [x] :javascript
|
|
54
|
+
- [x] :less
|
|
55
|
+
- [x] :markdown
|
|
56
|
+
- [ ] :maruku
|
|
57
|
+
- [x] :plain
|
|
58
|
+
- [x] :preserve
|
|
59
|
+
- [x] :ruby
|
|
60
|
+
- [x] :sass
|
|
61
|
+
- [x] :scss
|
|
62
|
+
- [ ] :textile
|
|
63
|
+
- [ ] Custom Filters
|
|
64
|
+
- [ ] Helper Methods
|
|
65
|
+
- [x] surround
|
|
66
|
+
- [x] precede
|
|
67
|
+
- [x] succeed
|
|
68
|
+
- [x] Multiline: |
|
|
69
|
+
- [x] Whitespace Preservation
|
|
70
|
+
- [ ] Helpers
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
## Limitations
|
|
74
|
+
|
|
75
|
+
### No pretty mode
|
|
76
|
+
Haml has :pretty mode and :ugly mode. :pretty mode is used on development and indented beautifully.
|
|
77
|
+
On production environemnt, :ugly mode is used and Hamlit currently supports only this mode.
|
|
78
|
+
|
|
79
|
+
So you'll see difference rendering result on development environment, but it'll be the same on production.
|
|
80
|
+
|
|
81
|
+
### No Haml buffer
|
|
82
|
+
Hamlit uses `Array` as buffer for performance. So you can't touch Haml::Buffer from template when using Hamlit.
|
|
83
|
+
|
|
84
|
+
### Haml helpers are still in development
|
|
85
|
+
At the same time, because some methods in `Haml::Helpers` require `Haml::Buffer`, they are not supported now.
|
|
86
|
+
But some helpers are supported on Rails. Some of not-implemented methods are planned to be supported.
|
|
87
|
+
|
|
88
|
+
### Limited attributes hyphenation
|
|
89
|
+
In Haml, `%a{ foo: { bar: 'baz' } }` is rendered as `<a foo-bar='baz'></a>`, whatever foo is.
|
|
90
|
+
In Hamlit, this feature is supported only for data attribute. Hamlit renders `%a{ data: { foo: 'bar' } }`
|
|
91
|
+
as `<a data-foo='bar'></a>` because it's data attribute. This design allows us to reduce work on runtime
|
|
92
|
+
and the idea is originally in [Faml](https://github.com/eagletmt/faml).
|
|
93
|
+
|
|
94
|
+
### Limited boolean attributes
|
|
95
|
+
In Haml, `%a{ foo: false }` is rendered as `<a></a>`, whatever `foo` is.
|
|
96
|
+
In Hamlit, this feature is supported for only boolean attributes, which are defined by
|
|
97
|
+
http://www.w3.org/TR/xhtml1/guidelines.html or https://html.spec.whatwg.org/.
|
|
98
|
+
The list is the same as `ActionView::Helpers::TagHelper::BOOLEAN_ATTRIBUTES`.
|
|
99
|
+
In addition, data-\* is also regarded as boolean.
|
|
100
|
+
|
|
101
|
+
Since `foo` is not boolean attribute, `%a{ foo: false }` is rendered as `<a foo='false'></a>`
|
|
102
|
+
This is the same behavior as Rails helpers. Also for `%a{ foo: nil }`,
|
|
103
|
+
Hamlit does not remove non-boolean attributes and render `<a foo=''></a>`
|
|
104
|
+
(`foo` is not removed). This design allows us to reduce string concatenation and
|
|
105
|
+
is the only difference between Faml and Hamlit.
|
|
106
|
+
|
|
107
|
+
## 5 Types of Attributes
|
|
108
|
+
|
|
109
|
+
Haml has 3 types of attributes: id, class and others.
|
|
110
|
+
In addition, Hamlit treats data and boolean attributes specially.
|
|
111
|
+
So there are 5 types of attributes in Hamlit.
|
|
112
|
+
|
|
113
|
+
### id attribute
|
|
114
|
+
Almost the same behavior as Haml, except no hyphenation and boolean support.
|
|
115
|
+
Arrays are flattened, falsey values are removed (but attribute itself is not removed)
|
|
116
|
+
and merging multiple ids results in concatenation by "\_".
|
|
117
|
+
|
|
118
|
+
```rb
|
|
119
|
+
# Input
|
|
120
|
+
#foo{ id: 'bar' }
|
|
121
|
+
%div{ id: %w[foo bar] }
|
|
122
|
+
%div{ id: ['foo', false, ['bar', nil]] }
|
|
123
|
+
%div{ id: false }
|
|
124
|
+
|
|
125
|
+
# Output
|
|
126
|
+
<div id='foo_bar'></span>
|
|
127
|
+
<div id='foo_bar'></span>
|
|
128
|
+
<div id='foo_bar'></span>
|
|
129
|
+
<div id=''></span>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### class attribute
|
|
133
|
+
Almost the same behavior as Haml, except no hyphenation and boolean support.
|
|
134
|
+
Arrays are flattened, falsey values are removed (but attribute itself is not removed)
|
|
135
|
+
and merging multiple classes results in unique alphabetical sort.
|
|
136
|
+
|
|
137
|
+
```rb
|
|
138
|
+
# Input
|
|
139
|
+
.d.a(class='b c'){ class: 'c a' }
|
|
140
|
+
%div{ class: 'd c b a' }
|
|
141
|
+
%div{ class: ['d', nil, 'c', [false, 'b', 'a']] }
|
|
142
|
+
%div{ class: false }
|
|
143
|
+
|
|
144
|
+
# Output
|
|
145
|
+
<div class='a b c d'></div>
|
|
146
|
+
<div class='d c b a'></div>
|
|
147
|
+
<div class='d c b a'></div>
|
|
148
|
+
<div class=''></div>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### data attribute
|
|
152
|
+
Completely compatible with Haml, hyphenation and boolean are supported.
|
|
153
|
+
|
|
154
|
+
```rb
|
|
155
|
+
# Input
|
|
156
|
+
%div{ data: { disabled: true } }
|
|
157
|
+
%div{ data: { foo: 'bar' } }
|
|
158
|
+
|
|
159
|
+
# Output
|
|
160
|
+
<div data-disabled></div>
|
|
161
|
+
<div data-foo='bar'></div>
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### boolean attributes
|
|
165
|
+
No hyphenation but complete boolean support.
|
|
166
|
+
|
|
167
|
+
```rb
|
|
168
|
+
# Input
|
|
169
|
+
%div{ disabled: 'foo' }
|
|
170
|
+
%div{ disabled: true }
|
|
171
|
+
%div{ disabled: false }
|
|
172
|
+
|
|
173
|
+
# Output
|
|
174
|
+
<div disabled='foo'></div>
|
|
175
|
+
<div disabled></div>
|
|
176
|
+
<div></div>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
List of boolean attributes is:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
disabled readonly multiple checked autobuffer autoplay controls loop selected hidden scoped async
|
|
183
|
+
defer reversed ismap seamless muted required autofocus novalidate formnovalidate open pubdate
|
|
184
|
+
itemscope allowfullscreen default inert sortable truespeed typemustmatch
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
"data-\*" is also regarded as boolean.
|
|
188
|
+
|
|
189
|
+
### other attributes
|
|
190
|
+
No hyphenation and boolean support. `false` is rendered as "false" (like Rails helpers).
|
|
191
|
+
|
|
192
|
+
```rb
|
|
193
|
+
# Input
|
|
194
|
+
%input{ value: true }
|
|
195
|
+
%input{ value: false }
|
|
196
|
+
|
|
197
|
+
# Output
|
|
198
|
+
<input value='true'>
|
|
199
|
+
<input value='false'>
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Engine options
|
|
203
|
+
|
|
204
|
+
| Option | Default | Feature |
|
|
205
|
+
|:-------|:--------|:--------|
|
|
206
|
+
| escape\_html | true | HTML-escape for Ruby script and interpolation. This is false in Haml. |
|
|
207
|
+
| escape\_attrs | true | HTML-escape for Html attributes. |
|
|
208
|
+
| format | :html | You can set :xhtml to change boolean attribute's format. |
|
|
209
|
+
| attr\_quote | `'` | You can change attribute's wrapper to `"` or something. |
|
|
210
|
+
|
|
211
|
+
### Set options for Rails
|
|
212
|
+
|
|
213
|
+
```rb
|
|
214
|
+
# config/initializers/hamlit.rb or somewhere
|
|
215
|
+
Hamlit::RailsTemplate.set_options attr_quote: '"'
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Set options for Sinatra
|
|
219
|
+
|
|
220
|
+
```rb
|
|
221
|
+
set :haml, { attr_quote: '"' }
|
|
222
|
+
```
|