haml 5.0.4 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/test.yml +40 -0
- data/.gitignore +16 -15
- data/CHANGELOG.md +62 -1
- data/Gemfile +18 -14
- data/MIT-LICENSE +2 -2
- data/README.md +4 -5
- data/REFERENCE.md +46 -12
- data/Rakefile +93 -103
- data/bin/bench +66 -0
- data/bin/console +11 -0
- data/bin/ruby +3 -0
- data/bin/setup +7 -0
- data/bin/stackprof +27 -0
- data/bin/test +24 -0
- data/exe/haml +6 -0
- data/ext/haml/extconf.rb +10 -0
- data/ext/haml/haml.c +537 -0
- data/ext/haml/hescape.c +108 -0
- data/ext/haml/hescape.h +20 -0
- data/haml.gemspec +39 -30
- data/lib/haml/ambles.rb +20 -0
- data/lib/haml/attribute_builder.rb +140 -128
- data/lib/haml/attribute_compiler.rb +86 -181
- data/lib/haml/attribute_parser.rb +86 -124
- data/lib/haml/cli.rb +154 -0
- data/lib/haml/compiler/children_compiler.rb +126 -0
- data/lib/haml/compiler/comment_compiler.rb +39 -0
- data/lib/haml/compiler/doctype_compiler.rb +46 -0
- data/lib/haml/compiler/script_compiler.rb +116 -0
- data/lib/haml/compiler/silent_script_compiler.rb +24 -0
- data/lib/haml/compiler/tag_compiler.rb +76 -0
- data/lib/haml/compiler.rb +64 -298
- data/lib/haml/dynamic_merger.rb +67 -0
- data/lib/haml/engine.rb +43 -219
- data/lib/haml/error.rb +29 -27
- data/lib/haml/escapable.rb +6 -42
- data/lib/haml/filters/base.rb +12 -0
- data/lib/haml/filters/cdata.rb +20 -0
- data/lib/haml/filters/coffee.rb +17 -0
- data/lib/haml/filters/css.rb +33 -0
- data/lib/haml/filters/erb.rb +10 -0
- data/lib/haml/filters/escaped.rb +22 -0
- data/lib/haml/filters/javascript.rb +33 -0
- data/lib/haml/filters/less.rb +20 -0
- data/lib/haml/filters/markdown.rb +11 -0
- data/lib/haml/filters/plain.rb +29 -0
- data/lib/haml/filters/preserve.rb +22 -0
- data/lib/haml/filters/ruby.rb +10 -0
- data/lib/haml/filters/sass.rb +15 -0
- data/lib/haml/filters/scss.rb +15 -0
- data/lib/haml/filters/text_base.rb +25 -0
- data/lib/haml/filters/tilt_base.rb +49 -0
- data/lib/haml/filters.rb +55 -378
- data/lib/haml/force_escapable.rb +29 -0
- data/lib/haml/helpers.rb +4 -696
- data/lib/haml/html.rb +22 -0
- data/lib/haml/identity.rb +13 -0
- data/lib/haml/object_ref.rb +30 -0
- data/lib/haml/parser.rb +208 -43
- data/lib/haml/rails_helpers.rb +51 -0
- data/lib/haml/rails_template.rb +55 -0
- data/lib/haml/railtie.rb +7 -40
- data/lib/haml/ruby_expression.rb +32 -0
- data/lib/haml/string_splitter.rb +20 -0
- data/lib/haml/template.rb +15 -33
- data/lib/haml/temple_line_counter.rb +2 -0
- data/lib/haml/util.rb +23 -21
- data/lib/haml/version.rb +1 -1
- data/lib/haml.rb +8 -19
- metadata +222 -50
- data/.gitmodules +0 -3
- data/.travis.yml +0 -54
- data/.yardopts +0 -23
- data/TODO +0 -24
- data/benchmark.rb +0 -66
- data/bin/haml +0 -9
- data/lib/haml/.gitattributes +0 -1
- data/lib/haml/buffer.rb +0 -235
- data/lib/haml/exec.rb +0 -348
- data/lib/haml/generator.rb +0 -41
- data/lib/haml/helpers/action_view_extensions.rb +0 -59
- data/lib/haml/helpers/action_view_mods.rb +0 -129
- data/lib/haml/helpers/action_view_xss_mods.rb +0 -59
- data/lib/haml/helpers/safe_erubi_template.rb +0 -19
- data/lib/haml/helpers/safe_erubis_template.rb +0 -32
- data/lib/haml/helpers/xss_mods.rb +0 -110
- data/lib/haml/options.rb +0 -273
- data/lib/haml/plugin.rb +0 -34
- data/lib/haml/sass_rails_filter.rb +0 -46
- data/lib/haml/template/options.rb +0 -26
- data/lib/haml/temple_engine.rb +0 -121
- data/yard/default/.gitignore +0 -1
- data/yard/default/fulldoc/html/css/common.sass +0 -15
- data/yard/default/layout/html/footer.erb +0 -12
data/ext/haml/hescape.h
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#ifndef HESCAPE_H
|
|
2
|
+
#define HESCAPE_H
|
|
3
|
+
|
|
4
|
+
#include <sys/types.h>
|
|
5
|
+
|
|
6
|
+
/*
|
|
7
|
+
* Replace characters according to the following rules.
|
|
8
|
+
* Note that this function can handle only ASCII-compatible string.
|
|
9
|
+
*
|
|
10
|
+
* " => "
|
|
11
|
+
* & => &
|
|
12
|
+
* ' => '
|
|
13
|
+
* < => <
|
|
14
|
+
* > => >
|
|
15
|
+
*
|
|
16
|
+
* @return size of dest. If it's larger than len, dest is required to be freed.
|
|
17
|
+
*/
|
|
18
|
+
extern size_t hesc_escape_html(char **dest, const char *src, size_t size);
|
|
19
|
+
|
|
20
|
+
#endif
|
data/haml.gemspec
CHANGED
|
@@ -1,38 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'haml/version'
|
|
3
5
|
|
|
4
6
|
Gem::Specification.new do |spec|
|
|
5
|
-
spec.name
|
|
6
|
-
spec.
|
|
7
|
-
spec.
|
|
8
|
-
spec.
|
|
9
|
-
spec.email = ['haml@googlegroups.com', 'norman@njclarke.com']
|
|
7
|
+
spec.name = 'haml'
|
|
8
|
+
spec.version = Haml::VERSION
|
|
9
|
+
spec.authors = ['Natalie Weizenbaum', 'Hampton Catlin', 'Norman Clarke', 'Akira Matsuda', 'Takashi Kokubun']
|
|
10
|
+
spec.email = ['haml@googlegroups.com', 'ronnie@dio.jp']
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
spec.
|
|
13
|
-
spec.
|
|
14
|
-
|
|
15
|
-
end
|
|
16
|
-
spec.homepage = 'http://haml.info/'
|
|
17
|
-
spec.has_rdoc = false
|
|
18
|
-
spec.license = "MIT"
|
|
19
|
-
|
|
20
|
-
spec.required_ruby_version = '>= 2.0.0'
|
|
12
|
+
spec.summary = %q{An elegant, structured (X)HTML/XML templating engine.}
|
|
13
|
+
spec.description = %q{An elegant, structured (X)HTML/XML templating engine.}
|
|
14
|
+
spec.homepage = 'https://haml.info'
|
|
15
|
+
spec.license = 'MIT'
|
|
21
16
|
|
|
22
|
-
spec.
|
|
23
|
-
spec.
|
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|sample|benchmark)/}) }
|
|
18
|
+
spec.bindir = 'exe'
|
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
20
|
+
spec.require_paths = ['lib']
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
if /java/ === RUBY_PLATFORM
|
|
23
|
+
spec.platform = 'java'
|
|
24
|
+
else
|
|
25
|
+
spec.extensions = ['ext/haml/extconf.rb']
|
|
26
|
+
spec.required_ruby_version = '>= 2.1.0'
|
|
27
|
+
end
|
|
29
28
|
|
|
30
|
-
spec.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
easy way by using indentation rather than closing tags and allowing Ruby to be
|
|
34
|
-
embedded with ease. It was originally envisioned as a plugin for Ruby on Rails,
|
|
35
|
-
but it can function as a stand-alone templating engine.
|
|
36
|
-
END
|
|
29
|
+
spec.add_dependency 'temple', '>= 0.8.2'
|
|
30
|
+
spec.add_dependency 'thor'
|
|
31
|
+
spec.add_dependency 'tilt'
|
|
37
32
|
|
|
33
|
+
spec.add_development_dependency 'benchmark_driver'
|
|
34
|
+
spec.add_development_dependency 'bundler'
|
|
35
|
+
spec.add_development_dependency 'coffee-script'
|
|
36
|
+
spec.add_development_dependency 'erubi'
|
|
37
|
+
spec.add_development_dependency 'haml', '>= 5'
|
|
38
|
+
spec.add_development_dependency 'less'
|
|
39
|
+
spec.add_development_dependency 'minitest-reporters', '~> 1.1'
|
|
40
|
+
spec.add_development_dependency 'rails', '>= 4.0'
|
|
41
|
+
spec.add_development_dependency 'rake'
|
|
42
|
+
spec.add_development_dependency 'rake-compiler'
|
|
43
|
+
spec.add_development_dependency 'sass'
|
|
44
|
+
spec.add_development_dependency 'slim'
|
|
45
|
+
spec.add_development_dependency 'string_template'
|
|
46
|
+
spec.add_development_dependency 'unindent'
|
|
38
47
|
end
|
data/lib/haml/ambles.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Haml
|
|
3
|
+
class Ambles < Temple::Filter
|
|
4
|
+
define_options :preamble, :postamble
|
|
5
|
+
|
|
6
|
+
def initialize(*)
|
|
7
|
+
super
|
|
8
|
+
@preamble = options[:preamble]
|
|
9
|
+
@postamble = options[:postamble]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call(ast)
|
|
13
|
+
ret = [:multi]
|
|
14
|
+
ret << [:static, @preamble] if @preamble
|
|
15
|
+
ret << ast
|
|
16
|
+
ret << [:static, @postamble] if @postamble
|
|
17
|
+
ret
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -1,163 +1,175 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
require 'haml/object_ref'
|
|
3
|
+
|
|
4
|
+
module Haml::AttributeBuilder
|
|
5
|
+
BOOLEAN_ATTRIBUTES = %w[disabled readonly multiple checked autobuffer
|
|
6
|
+
autoplay controls loop selected hidden scoped async
|
|
7
|
+
defer reversed ismap seamless muted required
|
|
8
|
+
autofocus novalidate formnovalidate open pubdate
|
|
9
|
+
itemscope allowfullscreen default inert sortable
|
|
10
|
+
truespeed typemustmatch download].freeze
|
|
11
|
+
|
|
12
|
+
# Java extension is not implemented for JRuby yet.
|
|
13
|
+
# TruffleRuby does not implement `rb_ary_sort_bang`, etc.
|
|
14
|
+
if /java/ === RUBY_PLATFORM || RUBY_ENGINE == 'truffleruby'
|
|
7
15
|
class << self
|
|
8
|
-
def
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
def build(escape_attrs, quote, format, boolean_attributes, object_ref, *hashes)
|
|
17
|
+
hashes << Haml::ObjectRef.parse(object_ref) if object_ref
|
|
18
|
+
buf = []
|
|
19
|
+
hash = merge_all_attrs(hashes)
|
|
20
|
+
|
|
21
|
+
keys = hash.keys.sort!
|
|
22
|
+
keys.each do |key|
|
|
23
|
+
case key
|
|
24
|
+
when 'id'.freeze
|
|
25
|
+
buf << " id=#{quote}#{build_id(escape_attrs, *hash[key])}#{quote}"
|
|
26
|
+
when 'class'.freeze
|
|
27
|
+
buf << " class=#{quote}#{build_class(escape_attrs, *hash[key])}#{quote}"
|
|
28
|
+
when 'data'.freeze
|
|
29
|
+
buf << build_data(escape_attrs, quote, *hash[key])
|
|
30
|
+
when *boolean_attributes, /\Adata-/
|
|
31
|
+
build_boolean!(escape_attrs, quote, format, buf, key, hash[key])
|
|
32
|
+
else
|
|
33
|
+
buf << " #{key}=#{quote}#{escape_html(escape_attrs, hash[key].to_s)}#{quote}"
|
|
20
34
|
end
|
|
21
35
|
end
|
|
36
|
+
buf.join
|
|
37
|
+
end
|
|
22
38
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
value = filter_and_join(value, ' ') if attr == 'class'
|
|
27
|
-
value = filter_and_join(value, '_') if attr == 'id'
|
|
39
|
+
def build_id(escape_attrs, *values)
|
|
40
|
+
escape_html(escape_attrs, values.flatten.select { |v| v }.join('_'))
|
|
41
|
+
end
|
|
28
42
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
def build_class(escape_attrs, *values)
|
|
44
|
+
if values.size == 1
|
|
45
|
+
value = values.first
|
|
46
|
+
case
|
|
47
|
+
when value.is_a?(String)
|
|
48
|
+
# noop
|
|
49
|
+
when value.is_a?(Array)
|
|
50
|
+
value = value.flatten.select { |v| v }.map(&:to_s).uniq.join(' ')
|
|
51
|
+
when value
|
|
52
|
+
value = value.to_s
|
|
53
|
+
else
|
|
54
|
+
return ''
|
|
34
55
|
end
|
|
35
|
-
|
|
36
|
-
value =
|
|
37
|
-
if escape_attrs == :once
|
|
38
|
-
Haml::Helpers.escape_once(value.to_s)
|
|
39
|
-
elsif escape_attrs
|
|
40
|
-
Haml::Helpers.html_escape(value.to_s)
|
|
41
|
-
else
|
|
42
|
-
value.to_s
|
|
43
|
-
end
|
|
44
|
-
" #{attr}=#{attr_wrapper}#{value}#{attr_wrapper}"
|
|
56
|
+
return escape_html(escape_attrs, value)
|
|
45
57
|
end
|
|
46
|
-
result.compact!
|
|
47
|
-
result.sort!
|
|
48
|
-
result.join
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# @return [String, nil]
|
|
52
|
-
def filter_and_join(value, separator)
|
|
53
|
-
return '' if (value.respond_to?(:empty?) && value.empty?)
|
|
54
58
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
value.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
classes = []
|
|
60
|
+
values.each do |value|
|
|
61
|
+
case
|
|
62
|
+
when value.is_a?(String)
|
|
63
|
+
classes += value.split(' ')
|
|
64
|
+
when value.is_a?(Array)
|
|
65
|
+
classes += value.select { |v| v }
|
|
66
|
+
when value
|
|
67
|
+
classes << value.to_s
|
|
68
|
+
end
|
|
62
69
|
end
|
|
63
|
-
|
|
70
|
+
escape_html(escape_attrs, classes.map(&:to_s).uniq.join(' '))
|
|
64
71
|
end
|
|
65
72
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
# except that it merges id, class, and data attributes.
|
|
69
|
-
#
|
|
70
|
-
# ids are concatenated with `"_"`,
|
|
71
|
-
# and classes are concatenated with `" "`.
|
|
72
|
-
# data hashes are simply merged.
|
|
73
|
-
#
|
|
74
|
-
# Destructively modifies `to`.
|
|
75
|
-
#
|
|
76
|
-
# @param to [{String => String,Hash}] The attribute hash to merge into
|
|
77
|
-
# @param from [{String => Object}] The attribute hash to merge from
|
|
78
|
-
# @return [{String => String,Hash}] `to`, after being merged
|
|
79
|
-
def merge_attributes!(to, from)
|
|
80
|
-
from.keys.each do |key|
|
|
81
|
-
to[key] = merge_value(key, to[key], from[key])
|
|
82
|
-
end
|
|
83
|
-
to
|
|
73
|
+
def build_data(escape_attrs, quote, *hashes)
|
|
74
|
+
build_data_attribute(:data, escape_attrs, quote, *hashes)
|
|
84
75
|
end
|
|
85
76
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
# @param key [String]
|
|
89
|
-
# @param values [Array<Object>]
|
|
90
|
-
# @return [String,Hash]
|
|
91
|
-
def merge_values(key, *values)
|
|
92
|
-
values.inject(nil) do |to, from|
|
|
93
|
-
merge_value(key, to, from)
|
|
94
|
-
end
|
|
77
|
+
def build_aria(escape_attrs, quote, *hashes)
|
|
78
|
+
build_data_attribute(:aria, escape_attrs, quote, *hashes)
|
|
95
79
|
end
|
|
96
80
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def build_data_attribute(key, escape_attrs, quote, *hashes)
|
|
84
|
+
attrs = []
|
|
85
|
+
if hashes.size > 1 && hashes.all? { |h| h.is_a?(Hash) }
|
|
86
|
+
data_value = merge_all_attrs(hashes)
|
|
87
|
+
else
|
|
88
|
+
data_value = hashes.last
|
|
89
|
+
end
|
|
90
|
+
hash = flatten_attributes(key => data_value)
|
|
91
|
+
|
|
92
|
+
hash.sort_by(&:first).each do |key, value|
|
|
93
|
+
case value
|
|
94
|
+
when true
|
|
95
|
+
attrs << " #{key}"
|
|
96
|
+
when nil, false
|
|
97
|
+
# noop
|
|
98
|
+
else
|
|
99
|
+
attrs << " #{key}=#{quote}#{escape_html(escape_attrs, value.to_s)}#{quote}"
|
|
101
100
|
end
|
|
102
101
|
end
|
|
102
|
+
attrs.join
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
def flatten_attributes(attributes)
|
|
106
|
+
flattened = {}
|
|
106
107
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
merged_id = "#{to}_#{merged_id}"
|
|
121
|
-
elsif to || merged_id
|
|
122
|
-
merged_id ||= to
|
|
108
|
+
attributes.each do |key, value|
|
|
109
|
+
case value
|
|
110
|
+
when attributes
|
|
111
|
+
when Hash
|
|
112
|
+
flatten_attributes(value).each do |k, v|
|
|
113
|
+
if k.nil?
|
|
114
|
+
flattened[key] = v
|
|
115
|
+
else
|
|
116
|
+
flattened["#{key}-#{k.to_s.gsub(/_/, '-')}"] = v
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
else
|
|
120
|
+
flattened[key] = value if value
|
|
123
121
|
end
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
122
|
+
end
|
|
123
|
+
flattened
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def merge_all_attrs(hashes)
|
|
127
|
+
merged = {}
|
|
128
|
+
hashes.each do |hash|
|
|
129
|
+
hash.each do |key, value|
|
|
130
|
+
key = key.to_s
|
|
131
|
+
case key
|
|
132
|
+
when 'id'.freeze, 'class'.freeze, 'data'.freeze
|
|
133
|
+
merged[key] ||= []
|
|
134
|
+
merged[key] << value
|
|
135
|
+
else
|
|
136
|
+
merged[key] = value
|
|
137
|
+
end
|
|
131
138
|
end
|
|
132
|
-
merged_class
|
|
133
|
-
else
|
|
134
|
-
from
|
|
135
139
|
end
|
|
140
|
+
merged
|
|
136
141
|
end
|
|
137
142
|
|
|
138
|
-
def
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
143
|
+
def build_boolean!(escape_attrs, quote, format, buf, key, value)
|
|
144
|
+
case value
|
|
145
|
+
when true
|
|
146
|
+
case format
|
|
147
|
+
when :xhtml
|
|
148
|
+
buf << " #{key}=#{quote}#{key}#{quote}"
|
|
144
149
|
else
|
|
145
|
-
|
|
150
|
+
buf << " #{key}"
|
|
146
151
|
end
|
|
147
|
-
|
|
152
|
+
when false, nil
|
|
153
|
+
# omitted
|
|
154
|
+
else
|
|
155
|
+
buf << " #{key}=#{quote}#{escape_html(escape_attrs, value)}#{quote}"
|
|
156
|
+
end
|
|
148
157
|
end
|
|
149
158
|
|
|
150
|
-
def
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
data.sort {|x, y| x[0].to_s <=> y[0].to_s}.inject({}) do |hash, (k, v)|
|
|
157
|
-
joined = key == '' ? k : [key, k].join(join_char)
|
|
158
|
-
hash.merge! flatten_data_attributes(v, joined, join_char, seen)
|
|
159
|
+
def escape_html(escape_attrs, str)
|
|
160
|
+
if escape_attrs
|
|
161
|
+
Haml::Util.escape_html(str)
|
|
162
|
+
else
|
|
163
|
+
str
|
|
159
164
|
end
|
|
160
165
|
end
|
|
161
166
|
end
|
|
167
|
+
else
|
|
168
|
+
# Haml::AttributeBuilder.build
|
|
169
|
+
# Haml::AttributeBuilder.build_id
|
|
170
|
+
# Haml::AttributeBuilder.build_class
|
|
171
|
+
# Haml::AttributeBuilder.build_data
|
|
172
|
+
# Haml::AttributeBuilder.build_aria
|
|
173
|
+
require 'haml/haml'
|
|
162
174
|
end
|
|
163
175
|
end
|