haml 6.1.1 → 6.2.3
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/workflows/test.yml +2 -1
- data/CHANGELOG.md +38 -1
- data/FAQ.md +1 -1
- data/Gemfile +4 -0
- data/README.md +6 -6
- data/REFERENCE.md +39 -46
- data/Rakefile +3 -37
- data/haml.gemspec +3 -7
- data/lib/haml/attribute_builder.rb +124 -136
- data/lib/haml/attribute_compiler.rb +10 -5
- data/lib/haml/compiler/doctype_compiler.rb +8 -2
- data/lib/haml/rails_template.rb +10 -0
- data/lib/haml/util.rb +5 -4
- data/lib/haml/version.rb +1 -1
- metadata +6 -24
- data/ext/haml/extconf.rb +0 -10
- data/ext/haml/haml.c +0 -537
- data/ext/haml/hescape.c +0 -108
- data/ext/haml/hescape.h +0 -20
@@ -2,173 +2,161 @@
|
|
2
2
|
require 'haml/object_ref'
|
3
3
|
|
4
4
|
module Haml::AttributeBuilder
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
buf << " class=#{quote}#{build_class(escape_attrs, *hash[key])}#{quote}"
|
27
|
-
when 'data'.freeze
|
28
|
-
buf << build_data(escape_attrs, quote, *hash[key])
|
29
|
-
when *boolean_attributes, /\Adata-/
|
30
|
-
build_boolean!(escape_attrs, quote, format, buf, key, hash[key])
|
31
|
-
else
|
32
|
-
buf << " #{key}=#{quote}#{escape_html(escape_attrs, hash[key].to_s)}#{quote}"
|
33
|
-
end
|
5
|
+
class << self
|
6
|
+
def build(escape_attrs, quote, format, object_ref, *hashes)
|
7
|
+
hashes << Haml::ObjectRef.parse(object_ref) if object_ref
|
8
|
+
buf = []
|
9
|
+
hash = merge_all_attrs(hashes)
|
10
|
+
|
11
|
+
keys = hash.keys.sort!
|
12
|
+
keys.each do |key|
|
13
|
+
case key
|
14
|
+
when 'id'
|
15
|
+
buf << " id=#{quote}#{build_id(escape_attrs, *hash[key])}#{quote}"
|
16
|
+
when 'class'
|
17
|
+
buf << " class=#{quote}#{build_class(escape_attrs, *hash[key])}#{quote}"
|
18
|
+
when 'data'
|
19
|
+
buf << build_data(escape_attrs, quote, *hash[key])
|
20
|
+
when 'aria'
|
21
|
+
buf << build_aria(escape_attrs, quote, *hash[key])
|
22
|
+
when *Haml::BOOLEAN_ATTRIBUTES, /\Adata-/, /\Aaria-/
|
23
|
+
build_boolean!(escape_attrs, quote, format, buf, key, hash[key])
|
24
|
+
else
|
25
|
+
buf << " #{key}=#{quote}#{escape_html(escape_attrs, hash[key].to_s)}#{quote}"
|
34
26
|
end
|
35
|
-
buf.join
|
36
|
-
end
|
37
|
-
|
38
|
-
def build_id(escape_attrs, *values)
|
39
|
-
escape_html(escape_attrs, values.flatten.select { |v| v }.join('_'))
|
40
27
|
end
|
28
|
+
buf.join
|
29
|
+
end
|
41
30
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
case
|
46
|
-
when value.is_a?(String)
|
47
|
-
# noop
|
48
|
-
when value.is_a?(Array)
|
49
|
-
value = value.flatten.select { |v| v }.map(&:to_s).uniq.join(' ')
|
50
|
-
when value
|
51
|
-
value = value.to_s
|
52
|
-
else
|
53
|
-
return ''
|
54
|
-
end
|
55
|
-
return escape_html(escape_attrs, value)
|
56
|
-
end
|
31
|
+
def build_id(escape_attrs, *values)
|
32
|
+
escape_html(escape_attrs, values.flatten.select { |v| v }.join('_'))
|
33
|
+
end
|
57
34
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
35
|
+
def build_class(escape_attrs, *values)
|
36
|
+
if values.size == 1
|
37
|
+
value = values.first
|
38
|
+
case
|
39
|
+
when value.is_a?(String)
|
40
|
+
# noop
|
41
|
+
when value.is_a?(Array)
|
42
|
+
value = value.flatten.select { |v| v }.map(&:to_s).uniq.join(' ')
|
43
|
+
when value
|
44
|
+
value = value.to_s
|
45
|
+
else
|
46
|
+
return ''
|
68
47
|
end
|
69
|
-
escape_html(escape_attrs,
|
48
|
+
return escape_html(escape_attrs, value)
|
70
49
|
end
|
71
50
|
|
72
|
-
|
73
|
-
|
51
|
+
classes = []
|
52
|
+
values.each do |value|
|
53
|
+
case
|
54
|
+
when value.is_a?(String)
|
55
|
+
classes += value.split(' ')
|
56
|
+
when value.is_a?(Array)
|
57
|
+
classes += value.select { |v| v }
|
58
|
+
when value
|
59
|
+
classes << value.to_s
|
60
|
+
end
|
74
61
|
end
|
62
|
+
escape_html(escape_attrs, classes.map(&:to_s).uniq.join(' '))
|
63
|
+
end
|
75
64
|
|
76
|
-
|
77
|
-
|
78
|
-
|
65
|
+
def build_data(escape_attrs, quote, *hashes)
|
66
|
+
build_data_attribute(:data, escape_attrs, quote, *hashes)
|
67
|
+
end
|
79
68
|
|
80
|
-
|
69
|
+
def build_aria(escape_attrs, quote, *hashes)
|
70
|
+
build_data_attribute(:aria, escape_attrs, quote, *hashes)
|
71
|
+
end
|
81
72
|
|
82
|
-
|
83
|
-
attrs = []
|
84
|
-
if hashes.size > 1 && hashes.all? { |h| h.is_a?(Hash) }
|
85
|
-
data_value = merge_all_attrs(hashes)
|
86
|
-
else
|
87
|
-
data_value = hashes.last
|
88
|
-
end
|
89
|
-
hash = flatten_attributes(key => data_value)
|
73
|
+
private
|
90
74
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
else
|
98
|
-
attrs << " #{key}=#{quote}#{escape_html(escape_attrs, value.to_s)}#{quote}"
|
99
|
-
end
|
100
|
-
end
|
101
|
-
attrs.join
|
75
|
+
def build_data_attribute(key, escape_attrs, quote, *hashes)
|
76
|
+
attrs = []
|
77
|
+
if hashes.size > 1 && hashes.all? { |h| h.is_a?(Hash) }
|
78
|
+
data_value = merge_all_attrs(hashes)
|
79
|
+
else
|
80
|
+
data_value = hashes.last
|
102
81
|
end
|
82
|
+
hash = flatten_attributes(key => data_value)
|
103
83
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
if k.nil?
|
113
|
-
flattened[key] = v
|
114
|
-
else
|
115
|
-
flattened["#{key}-#{k.to_s.gsub(/_/, '-')}"] = v
|
116
|
-
end
|
117
|
-
end
|
118
|
-
else
|
119
|
-
flattened[key] = value if value
|
120
|
-
end
|
84
|
+
hash.sort_by(&:first).each do |key, value|
|
85
|
+
case value
|
86
|
+
when true
|
87
|
+
attrs << " #{key}"
|
88
|
+
when nil, false
|
89
|
+
# noop
|
90
|
+
else
|
91
|
+
attrs << " #{key}=#{quote}#{escape_html(escape_attrs, value.to_s)}#{quote}"
|
121
92
|
end
|
122
|
-
flattened
|
123
93
|
end
|
94
|
+
attrs.join
|
95
|
+
end
|
96
|
+
|
97
|
+
def flatten_attributes(attributes)
|
98
|
+
flattened = {}
|
124
99
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
merged[key] ||= []
|
133
|
-
merged[key] << value
|
100
|
+
attributes.each do |key, value|
|
101
|
+
case value
|
102
|
+
when attributes
|
103
|
+
when Hash
|
104
|
+
flatten_attributes(value).each do |k, v|
|
105
|
+
if k.nil?
|
106
|
+
flattened[key] = v
|
134
107
|
else
|
135
|
-
|
108
|
+
flattened["#{key}-#{k.to_s.gsub(/_/, '-')}"] = v
|
136
109
|
end
|
137
110
|
end
|
111
|
+
else
|
112
|
+
flattened[key] = value if value
|
138
113
|
end
|
139
|
-
merged
|
140
114
|
end
|
115
|
+
flattened
|
116
|
+
end
|
141
117
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
118
|
+
def merge_all_attrs(hashes)
|
119
|
+
merged = {}
|
120
|
+
hashes.each do |hash|
|
121
|
+
unless hash.is_a?(Hash)
|
122
|
+
raise ArgumentError, "Non-hash object is given to attributes!"
|
123
|
+
end
|
124
|
+
hash.each do |key, value|
|
125
|
+
key = key.to_s
|
126
|
+
case key
|
127
|
+
when 'id', 'class', 'data', 'aria'
|
128
|
+
merged[key] ||= []
|
129
|
+
merged[key] << value
|
148
130
|
else
|
149
|
-
|
131
|
+
merged[key] = value
|
150
132
|
end
|
151
|
-
when false, nil
|
152
|
-
# omitted
|
153
|
-
else
|
154
|
-
buf << " #{key}=#{quote}#{escape_html(escape_attrs, value)}#{quote}"
|
155
133
|
end
|
156
134
|
end
|
135
|
+
merged
|
136
|
+
end
|
157
137
|
|
158
|
-
|
159
|
-
|
160
|
-
|
138
|
+
def build_boolean!(escape_attrs, quote, format, buf, key, value)
|
139
|
+
case value
|
140
|
+
when true
|
141
|
+
case format
|
142
|
+
when :xhtml
|
143
|
+
buf << " #{key}=#{quote}#{key}#{quote}"
|
161
144
|
else
|
162
|
-
|
145
|
+
buf << " #{key}"
|
163
146
|
end
|
147
|
+
when false, nil
|
148
|
+
# omitted
|
149
|
+
else
|
150
|
+
buf << " #{key}=#{quote}#{escape_html(escape_attrs, value)}#{quote}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def escape_html(escape_attrs, str)
|
155
|
+
if escape_attrs
|
156
|
+
Haml::Util.escape_html(str)
|
157
|
+
else
|
158
|
+
str
|
164
159
|
end
|
165
160
|
end
|
166
|
-
else
|
167
|
-
# Haml::AttributeBuilder.build
|
168
|
-
# Haml::AttributeBuilder.build_id
|
169
|
-
# Haml::AttributeBuilder.build_class
|
170
|
-
# Haml::AttributeBuilder.build_data
|
171
|
-
# Haml::AttributeBuilder.build_aria
|
172
|
-
require 'haml/haml'
|
173
161
|
end
|
174
162
|
end
|
@@ -4,6 +4,14 @@ require 'haml/attribute_parser'
|
|
4
4
|
require 'haml/ruby_expression'
|
5
5
|
|
6
6
|
module Haml
|
7
|
+
# The list of boolean attributes. You may add custom attributes to this constant.
|
8
|
+
BOOLEAN_ATTRIBUTES = %w[disabled readonly multiple checked autobuffer
|
9
|
+
autoplay controls loop selected hidden scoped async
|
10
|
+
defer reversed ismap seamless muted required
|
11
|
+
autofocus novalidate formnovalidate open pubdate
|
12
|
+
itemscope allowfullscreen default inert sortable
|
13
|
+
truespeed typemustmatch download]
|
14
|
+
|
7
15
|
class AttributeCompiler
|
8
16
|
def initialize(identity, options)
|
9
17
|
@identity = identity
|
@@ -31,10 +39,7 @@ module Haml
|
|
31
39
|
attrs = []
|
32
40
|
attrs.unshift(node.value[:attributes].inspect) if node.value[:attributes] != {}
|
33
41
|
|
34
|
-
args = [
|
35
|
-
@escape_attrs.inspect, "#{@quote.inspect}.freeze", @format.inspect,
|
36
|
-
'::Haml::AttributeBuilder::BOOLEAN_ATTRIBUTES', node.value[:object_ref],
|
37
|
-
] + attrs
|
42
|
+
args = [@escape_attrs.inspect, "#{@quote.inspect}.freeze", @format.inspect, node.value[:object_ref]] + attrs
|
38
43
|
[:html, :attrs, [:dynamic, "::Haml::AttributeBuilder.build(#{args.join(', ')}, #{node.value[:dynamic_attributes].to_literal})"]]
|
39
44
|
end
|
40
45
|
|
@@ -52,7 +57,7 @@ module Haml
|
|
52
57
|
compile_class!(temple, key, values)
|
53
58
|
when 'data', 'aria'
|
54
59
|
compile_data!(temple, key, values)
|
55
|
-
when *
|
60
|
+
when *BOOLEAN_ATTRIBUTES, /\Adata-/, /\Aaria-/
|
56
61
|
compile_boolean!(temple, key, values)
|
57
62
|
else
|
58
63
|
compile_common!(temple, key, values)
|
@@ -8,10 +8,12 @@ module Haml
|
|
8
8
|
|
9
9
|
def compile(node)
|
10
10
|
case node.value[:type]
|
11
|
-
when 'xml'
|
12
|
-
xml_doctype
|
13
11
|
when ''
|
14
12
|
html_doctype(node)
|
13
|
+
when 'xml'
|
14
|
+
xml_doctype
|
15
|
+
when 'rdfa'
|
16
|
+
rdfa_doctype
|
15
17
|
else
|
16
18
|
[:html, :doctype, node.value[:type]]
|
17
19
|
end
|
@@ -41,6 +43,10 @@ module Haml
|
|
41
43
|
[:multi]
|
42
44
|
end
|
43
45
|
end
|
46
|
+
|
47
|
+
def rdfa_doctype
|
48
|
+
[:static, '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">']
|
49
|
+
end
|
44
50
|
end
|
45
51
|
end
|
46
52
|
end
|
data/lib/haml/rails_template.rb
CHANGED
@@ -27,6 +27,11 @@ module Haml
|
|
27
27
|
source ||= template.source
|
28
28
|
options = RailsTemplate.options
|
29
29
|
|
30
|
+
# Make the filename available in parser etc.
|
31
|
+
if template.respond_to?(:identifier)
|
32
|
+
options = options.merge(filename: template.identifier)
|
33
|
+
end
|
34
|
+
|
30
35
|
# https://github.com/haml/haml/blob/4.0.7/lib/haml/template/plugin.rb#L19-L20
|
31
36
|
# https://github.com/haml/haml/blob/4.0.7/lib/haml/options.rb#L228
|
32
37
|
if template.respond_to?(:type) && template.type == 'text/xml'
|
@@ -43,6 +48,11 @@ module Haml
|
|
43
48
|
Engine.new(options).call(source)
|
44
49
|
end
|
45
50
|
|
51
|
+
# Rails Turbo looks for this
|
52
|
+
def default_format
|
53
|
+
:html
|
54
|
+
end
|
55
|
+
|
46
56
|
def supports_streaming?
|
47
57
|
RailsTemplate.options[:streaming]
|
48
58
|
end
|
data/lib/haml/util.rb
CHANGED
@@ -14,15 +14,16 @@ module Haml
|
|
14
14
|
module Util
|
15
15
|
extend self
|
16
16
|
|
17
|
-
#
|
18
|
-
|
17
|
+
begin # Ruby 3.2+ or ERB 4+
|
18
|
+
require 'erb/escape'
|
19
|
+
|
20
|
+
define_singleton_method(:escape_html, ERB::Escape.instance_method(:html_escape))
|
21
|
+
rescue LoadError
|
19
22
|
require 'cgi/escape'
|
20
23
|
|
21
24
|
def self.escape_html(html)
|
22
25
|
CGI.escapeHTML(html.to_s)
|
23
26
|
end
|
24
|
-
else
|
25
|
-
require 'haml/haml' # Haml::Util.escape_html
|
26
27
|
end
|
27
28
|
|
28
29
|
# TODO: Remove unescape_interpolation's workaround and get rid of `respond_to?`.
|
data/lib/haml/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: haml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.
|
4
|
+
version: 6.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Natalie Weizenbaum
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: exe
|
14
14
|
cert_chain: []
|
15
|
-
date:
|
15
|
+
date: 2023-10-04 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: temple
|
@@ -182,20 +182,6 @@ dependencies:
|
|
182
182
|
- - ">="
|
183
183
|
- !ruby/object:Gem::Version
|
184
184
|
version: '0'
|
185
|
-
- !ruby/object:Gem::Dependency
|
186
|
-
name: rake-compiler
|
187
|
-
requirement: !ruby/object:Gem::Requirement
|
188
|
-
requirements:
|
189
|
-
- - ">="
|
190
|
-
- !ruby/object:Gem::Version
|
191
|
-
version: '0'
|
192
|
-
type: :development
|
193
|
-
prerelease: false
|
194
|
-
version_requirements: !ruby/object:Gem::Requirement
|
195
|
-
requirements:
|
196
|
-
- - ">="
|
197
|
-
- !ruby/object:Gem::Version
|
198
|
-
version: '0'
|
199
185
|
- !ruby/object:Gem::Dependency
|
200
186
|
name: sass
|
201
187
|
requirement: !ruby/object:Gem::Requirement
|
@@ -258,8 +244,7 @@ email:
|
|
258
244
|
- ronnie@dio.jp
|
259
245
|
executables:
|
260
246
|
- haml
|
261
|
-
extensions:
|
262
|
-
- ext/haml/extconf.rb
|
247
|
+
extensions: []
|
263
248
|
extra_rdoc_files: []
|
264
249
|
files:
|
265
250
|
- ".github/FUNDING.yml"
|
@@ -280,10 +265,6 @@ files:
|
|
280
265
|
- bin/stackprof
|
281
266
|
- bin/test
|
282
267
|
- exe/haml
|
283
|
-
- ext/haml/extconf.rb
|
284
|
-
- ext/haml/haml.c
|
285
|
-
- ext/haml/hescape.c
|
286
|
-
- ext/haml/hescape.h
|
287
268
|
- haml.gemspec
|
288
269
|
- lib/haml.rb
|
289
270
|
- lib/haml/ambles.rb
|
@@ -339,7 +320,8 @@ files:
|
|
339
320
|
homepage: https://haml.info
|
340
321
|
licenses:
|
341
322
|
- MIT
|
342
|
-
metadata:
|
323
|
+
metadata:
|
324
|
+
rubygems_mfa_required: 'true'
|
343
325
|
post_install_message:
|
344
326
|
rdoc_options: []
|
345
327
|
require_paths:
|
@@ -355,7 +337,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
355
337
|
- !ruby/object:Gem::Version
|
356
338
|
version: '0'
|
357
339
|
requirements: []
|
358
|
-
rubygems_version: 3.
|
340
|
+
rubygems_version: 3.3.26
|
359
341
|
signing_key:
|
360
342
|
specification_version: 4
|
361
343
|
summary: An elegant, structured (X)HTML/XML templating engine.
|