haml 5.0.4 → 5.2.2
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 +36 -0
- data/.gitignore +1 -0
- data/.yardopts +1 -2
- data/CHANGELOG.md +51 -1
- data/Gemfile +2 -5
- data/MIT-LICENSE +2 -2
- data/README.md +22 -17
- data/REFERENCE.md +46 -12
- data/Rakefile +2 -13
- data/benchmark.rb +13 -9
- data/haml.gemspec +10 -3
- data/lib/haml/attribute_builder.rb +59 -3
- data/lib/haml/attribute_compiler.rb +46 -32
- data/lib/haml/attribute_parser.rb +3 -1
- data/lib/haml/buffer.rb +1 -54
- data/lib/haml/compiler.rb +23 -24
- data/lib/haml/engine.rb +12 -3
- data/lib/haml/error.rb +25 -24
- data/lib/haml/escapable.rb +39 -11
- data/lib/haml/exec.rb +5 -6
- data/lib/haml/filters.rb +12 -11
- data/lib/haml/generator.rb +2 -1
- data/lib/haml/helpers/action_view_extensions.rb +1 -0
- data/lib/haml/helpers/action_view_mods.rb +4 -1
- data/lib/haml/helpers/action_view_xss_mods.rb +1 -0
- data/lib/haml/helpers/safe_erubi_template.rb +1 -0
- data/lib/haml/helpers/safe_erubis_template.rb +1 -0
- data/lib/haml/helpers/xss_mods.rb +7 -3
- data/lib/haml/helpers.rb +15 -13
- data/lib/haml/options.rb +36 -36
- data/lib/haml/parser.rb +52 -22
- data/lib/haml/plugin.rb +25 -5
- data/lib/haml/railtie.rb +9 -4
- data/lib/haml/sass_rails_filter.rb +1 -0
- data/lib/haml/template/options.rb +1 -0
- data/lib/haml/template.rb +1 -0
- data/lib/haml/temple_engine.rb +13 -10
- data/lib/haml/temple_line_counter.rb +1 -0
- data/lib/haml/util.rb +6 -6
- data/lib/haml/version.rb +2 -1
- data/lib/haml.rb +1 -0
- metadata +29 -10
- data/.travis.yml +0 -54
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'haml/attribute_parser'
|
3
4
|
|
4
5
|
module Haml
|
@@ -6,27 +7,7 @@ module Haml
|
|
6
7
|
# @param type [Symbol] :static or :dynamic
|
7
8
|
# @param key [String]
|
8
9
|
# @param value [String] Actual string value for :static type, value's Ruby literal for :dynamic type.
|
9
|
-
|
10
|
-
# @return [String] A Ruby literal of value.
|
11
|
-
def to_literal
|
12
|
-
case type
|
13
|
-
when :static
|
14
|
-
Haml::Util.inspect_obj(value)
|
15
|
-
when :dynamic
|
16
|
-
value
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# Returns a script to render attributes on runtime.
|
22
|
-
#
|
23
|
-
# @param attributes [Hash]
|
24
|
-
# @param object_ref [String,:nil]
|
25
|
-
# @param dynamic_attributes [DynamicAttributes]
|
26
|
-
# @return [String] Attributes rendering code
|
27
|
-
def self.runtime_build(attributes, object_ref, dynamic_attributes)
|
28
|
-
"_hamlout.attributes(#{Haml::Util.inspect_obj(attributes)}, #{object_ref},#{dynamic_attributes.to_literal})"
|
29
|
-
end
|
10
|
+
AttributeValue = Struct.new(:type, :key, :value)
|
30
11
|
|
31
12
|
# @param options [Haml::Options]
|
32
13
|
def initialize(options)
|
@@ -40,16 +21,16 @@ module Haml
|
|
40
21
|
#
|
41
22
|
# @param attributes [Hash]
|
42
23
|
# @param object_ref [String,:nil]
|
43
|
-
# @param dynamic_attributes [DynamicAttributes]
|
24
|
+
# @param dynamic_attributes [Haml::Parser::DynamicAttributes]
|
44
25
|
# @return [Array] Temple expression
|
45
26
|
def compile(attributes, object_ref, dynamic_attributes)
|
46
27
|
if object_ref != :nil || !AttributeParser.available?
|
47
|
-
return [:dynamic,
|
28
|
+
return [:dynamic, compile_runtime_build(attributes, object_ref, dynamic_attributes)]
|
48
29
|
end
|
49
30
|
|
50
31
|
parsed_hashes = [dynamic_attributes.new, dynamic_attributes.old].compact.map do |attribute_hash|
|
51
32
|
unless (hash = AttributeParser.parse(attribute_hash))
|
52
|
-
return [:dynamic,
|
33
|
+
return [:dynamic, compile_runtime_build(attributes, object_ref, dynamic_attributes)]
|
53
34
|
end
|
54
35
|
hash
|
55
36
|
end
|
@@ -63,6 +44,17 @@ module Haml
|
|
63
44
|
|
64
45
|
private
|
65
46
|
|
47
|
+
# Returns a script to render attributes on runtime.
|
48
|
+
#
|
49
|
+
# @param attributes [Hash]
|
50
|
+
# @param object_ref [String,:nil]
|
51
|
+
# @param dynamic_attributes [Haml::Parser::DynamicAttributes]
|
52
|
+
# @return [String] Attributes rendering code
|
53
|
+
def compile_runtime_build(attributes, object_ref, dynamic_attributes)
|
54
|
+
arguments = [@is_html, @attr_wrapper, @escape_attrs, @hyphenate_data_attrs].map(&method(:to_literal)).join(', ')
|
55
|
+
"::Haml::AttributeBuilder.build(#{to_literal(attributes)}, #{object_ref}, #{arguments}, #{dynamic_attributes.to_literal})"
|
56
|
+
end
|
57
|
+
|
66
58
|
# Build array of grouped values whose sort order may go back and forth, which is also sorted with key name.
|
67
59
|
# This method needs to group values with the same start because it can be changed in `Haml::AttributeBuidler#build_data_keys`.
|
68
60
|
# @param values [Array<Haml::AttributeCompiler::AttributeValue>]
|
@@ -115,7 +107,8 @@ module Haml
|
|
115
107
|
hash_content = values.group_by(&:key).map do |key, values_for_key|
|
116
108
|
"#{frozen_string(key)} => #{merged_value(key, values_for_key)}"
|
117
109
|
end.join(', ')
|
118
|
-
[
|
110
|
+
arguments = [@is_html, @attr_wrapper, @escape_attrs, @hyphenate_data_attrs].map(&method(:to_literal)).join(', ')
|
111
|
+
[:dynamic, "::Haml::AttributeBuilder.build({ #{hash_content} }, nil, #{arguments})"]
|
119
112
|
end
|
120
113
|
|
121
114
|
# Renders attribute values statically.
|
@@ -129,7 +122,7 @@ module Haml
|
|
129
122
|
|
130
123
|
arguments = [@is_html, @attr_wrapper, @escape_attrs, @hyphenate_data_attrs]
|
131
124
|
code = "::Haml::AttributeBuilder.build_attributes"\
|
132
|
-
"(#{arguments.map
|
125
|
+
"(#{arguments.map(&method(:to_literal)).join(', ')}, { #{hash_content} })"
|
133
126
|
[:static, eval(code).to_s]
|
134
127
|
end
|
135
128
|
|
@@ -138,16 +131,16 @@ module Haml
|
|
138
131
|
# @return [String]
|
139
132
|
def merged_value(key, values)
|
140
133
|
if values.size == 1
|
141
|
-
values.first
|
134
|
+
attr_literal(values.first)
|
142
135
|
else
|
143
|
-
"::Haml::AttributeBuilder.merge_values(#{frozen_string(key)}, #{values.map(
|
136
|
+
"::Haml::AttributeBuilder.merge_values(#{frozen_string(key)}, #{values.map(&method(:attr_literal)).join(', ')})"
|
144
137
|
end
|
145
138
|
end
|
146
139
|
|
147
140
|
# @param str [String]
|
148
141
|
# @return [String]
|
149
142
|
def frozen_string(str)
|
150
|
-
"#{
|
143
|
+
"#{to_literal(str)}.freeze"
|
151
144
|
end
|
152
145
|
|
153
146
|
# Compiles attribute values for one key to Temple expression that generates ` key='value'`.
|
@@ -156,7 +149,7 @@ module Haml
|
|
156
149
|
# @param values [Array<AttributeValue>]
|
157
150
|
# @return [Array] Temple expression
|
158
151
|
def compile_attribute(key, values)
|
159
|
-
if values.all? { |v| Temple::StaticAnalyzer.static?(v
|
152
|
+
if values.all? { |v| Temple::StaticAnalyzer.static?(attr_literal(v)) }
|
160
153
|
return static_build(values)
|
161
154
|
end
|
162
155
|
|
@@ -180,7 +173,7 @@ module Haml
|
|
180
173
|
['false, nil', [:multi]],
|
181
174
|
[:else, [:multi,
|
182
175
|
[:static, " #{id_or_class}=#{@attr_wrapper}"],
|
183
|
-
[:escape, @escape_attrs, [:dynamic, var]],
|
176
|
+
[:escape, Escapable::EscapeSafeBuffer.new(@escape_attrs), [:dynamic, var]],
|
184
177
|
[:static, @attr_wrapper]],
|
185
178
|
]
|
186
179
|
],
|
@@ -200,7 +193,7 @@ module Haml
|
|
200
193
|
['false, nil', [:multi]],
|
201
194
|
[:else, [:multi,
|
202
195
|
[:static, " #{key}=#{@attr_wrapper}"],
|
203
|
-
[:escape, @escape_attrs, [:dynamic, var]],
|
196
|
+
[:escape, Escapable::EscapeSafeBuffer.new(@escape_attrs), [:dynamic, var]],
|
204
197
|
[:static, @attr_wrapper]],
|
205
198
|
]
|
206
199
|
],
|
@@ -219,5 +212,26 @@ module Haml
|
|
219
212
|
@unique_name ||= 0
|
220
213
|
"_haml_attribute_compiler#{@unique_name += 1}"
|
221
214
|
end
|
215
|
+
|
216
|
+
# @param [Haml::AttributeCompiler::AttributeValue] attr
|
217
|
+
def attr_literal(attr)
|
218
|
+
case attr.type
|
219
|
+
when :static
|
220
|
+
to_literal(attr.value)
|
221
|
+
when :dynamic
|
222
|
+
attr.value
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
# For haml/haml#972
|
227
|
+
# @param [Object] value
|
228
|
+
def to_literal(value)
|
229
|
+
case value
|
230
|
+
when true, false
|
231
|
+
value.to_s
|
232
|
+
else
|
233
|
+
Haml::Util.inspect_obj(value)
|
234
|
+
end
|
235
|
+
end
|
222
236
|
end
|
223
237
|
end
|
@@ -1,8 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
begin
|
3
4
|
require 'ripper'
|
4
5
|
rescue LoadError
|
5
6
|
end
|
7
|
+
require 'temple/static_analyzer'
|
6
8
|
|
7
9
|
module Haml
|
8
10
|
# Haml::AttriubuteParser parses Hash literal to { String (key name) => String (value literal) }.
|
@@ -14,7 +16,7 @@ module Haml
|
|
14
16
|
TYPE = 1
|
15
17
|
TEXT = 2
|
16
18
|
|
17
|
-
IGNORED_TYPES = %i[on_sp on_ignored_nl]
|
19
|
+
IGNORED_TYPES = %i[on_sp on_ignored_nl].freeze
|
18
20
|
|
19
21
|
class << self
|
20
22
|
# @return [Boolean] - return true if AttributeParser.parse can be used.
|
data/lib/haml/buffer.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Haml
|
3
4
|
# This class is used only internally. It holds the buffer of HTML that
|
4
5
|
# is eventually output as the resulting document.
|
@@ -129,16 +130,6 @@ module Haml
|
|
129
130
|
@real_tabs += tab_change
|
130
131
|
end
|
131
132
|
|
132
|
-
def attributes(class_id, obj_ref, *attributes_hashes)
|
133
|
-
attributes = class_id
|
134
|
-
attributes_hashes.each do |old|
|
135
|
-
AttributeBuilder.merge_attributes!(attributes, Hash[old.map {|k, v| [k.to_s, v]}])
|
136
|
-
end
|
137
|
-
AttributeBuilder.merge_attributes!(attributes, parse_object_ref(obj_ref)) if obj_ref
|
138
|
-
AttributeBuilder.build_attributes(
|
139
|
-
html?, @options[:attr_wrapper], @options[:escape_attrs], @options[:hyphenate_data_attrs], attributes)
|
140
|
-
end
|
141
|
-
|
142
133
|
# Remove the whitespace from the right side of the buffer string.
|
143
134
|
# Doesn't do anything if we're at the beginning of a capture_haml block.
|
144
135
|
def rstrip!
|
@@ -187,49 +178,5 @@ module Haml
|
|
187
178
|
tabs = [count + @tabulation, 0].max
|
188
179
|
@@tab_cache[tabs] ||= ' ' * tabs
|
189
180
|
end
|
190
|
-
|
191
|
-
# Takes an array of objects and uses the class and id of the first
|
192
|
-
# one to create an attributes hash.
|
193
|
-
# The second object, if present, is used as a prefix,
|
194
|
-
# just like you can do with `dom_id()` and `dom_class()` in Rails
|
195
|
-
def parse_object_ref(ref)
|
196
|
-
prefix = ref[1]
|
197
|
-
ref = ref[0]
|
198
|
-
# Let's make sure the value isn't nil. If it is, return the default Hash.
|
199
|
-
return {} if ref.nil?
|
200
|
-
class_name =
|
201
|
-
if ref.respond_to?(:haml_object_ref)
|
202
|
-
ref.haml_object_ref
|
203
|
-
else
|
204
|
-
underscore(ref.class)
|
205
|
-
end
|
206
|
-
ref_id =
|
207
|
-
if ref.respond_to?(:to_key)
|
208
|
-
key = ref.to_key
|
209
|
-
key.join('_') unless key.nil?
|
210
|
-
else
|
211
|
-
ref.id
|
212
|
-
end
|
213
|
-
id = "#{class_name}_#{ref_id || 'new'}"
|
214
|
-
if prefix
|
215
|
-
class_name = "#{ prefix }_#{ class_name}"
|
216
|
-
id = "#{ prefix }_#{ id }"
|
217
|
-
end
|
218
|
-
|
219
|
-
{ 'id'.freeze => id, 'class'.freeze => class_name }
|
220
|
-
end
|
221
|
-
|
222
|
-
# Changes a word from camel case to underscores.
|
223
|
-
# Based on the method of the same name in Rails' Inflector,
|
224
|
-
# but copied here so it'll run properly without Rails.
|
225
|
-
def underscore(camel_cased_word)
|
226
|
-
word = camel_cased_word.to_s.dup
|
227
|
-
word.gsub!(/::/, '_')
|
228
|
-
word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
229
|
-
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
230
|
-
word.tr!('-', '_')
|
231
|
-
word.downcase!
|
232
|
-
word
|
233
|
-
end
|
234
181
|
end
|
235
182
|
end
|
data/lib/haml/compiler.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'haml/attribute_builder'
|
3
4
|
require 'haml/attribute_compiler'
|
4
5
|
require 'haml/temple_line_counter'
|
@@ -167,7 +168,7 @@ module Haml
|
|
167
168
|
end
|
168
169
|
|
169
170
|
def compile_filter
|
170
|
-
unless filter = @filters[@node.value[:name]]
|
171
|
+
unless (filter = @filters[@node.value[:name]])
|
171
172
|
name = @node.value[:name]
|
172
173
|
if ["maruku", "textile"].include?(name)
|
173
174
|
raise Error.new(Error.message(:install_haml_contrib, name), @node.line - 1)
|
@@ -187,30 +188,28 @@ module Haml
|
|
187
188
|
|
188
189
|
if @options.html5?
|
189
190
|
'<!DOCTYPE html>'
|
190
|
-
|
191
|
-
if @
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
else
|
197
|
-
case @node.value[:type]
|
198
|
-
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
|
199
|
-
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
|
200
|
-
when "mobile"; '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
|
201
|
-
when "rdfa"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">'
|
202
|
-
when "basic"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
|
203
|
-
else '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
|
204
|
-
end
|
205
|
-
end
|
206
|
-
|
207
|
-
elsif @options.html4?
|
191
|
+
elsif @options.xhtml?
|
192
|
+
if @node.value[:version] == "1.1"
|
193
|
+
'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
|
194
|
+
elsif @node.value[:version] == "5"
|
195
|
+
'<!DOCTYPE html>'
|
196
|
+
else
|
208
197
|
case @node.value[:type]
|
209
|
-
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD
|
210
|
-
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD
|
211
|
-
|
198
|
+
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
|
199
|
+
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
|
200
|
+
when "mobile"; '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
|
201
|
+
when "rdfa"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">'
|
202
|
+
when "basic"; '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
|
203
|
+
else '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
|
212
204
|
end
|
213
205
|
end
|
206
|
+
|
207
|
+
elsif @options.html4?
|
208
|
+
case @node.value[:type]
|
209
|
+
when "strict"; '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
|
210
|
+
when "frameset"; '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">'
|
211
|
+
else '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">'
|
212
|
+
end
|
214
213
|
end
|
215
214
|
end
|
216
215
|
|
@@ -315,7 +314,7 @@ module Haml
|
|
315
314
|
|
316
315
|
case last.first
|
317
316
|
when :text
|
318
|
-
last[1].rstrip
|
317
|
+
last[1] = last[1].rstrip
|
319
318
|
if last[1].empty?
|
320
319
|
@to_merge.slice! index
|
321
320
|
rstrip_buffer! index
|
data/lib/haml/engine.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'forwardable'
|
3
4
|
|
4
5
|
require 'haml/parser'
|
@@ -51,6 +52,9 @@ module Haml
|
|
51
52
|
# see {file:REFERENCE.md#options the Haml options documentation}
|
52
53
|
# @raise [Haml::Error] if there's a Haml syntax error in the template
|
53
54
|
def initialize(template, options = {})
|
55
|
+
# Reflect changes of `Haml::Options.defaults` to `Haml::TempleEngine` options, but `#initialize_encoding`
|
56
|
+
# should be run against the arguemnt `options[:encoding]` for backward compatibility with old `Haml::Engine`.
|
57
|
+
options = Options.defaults.dup.tap { |o| o.delete(:encoding) }.merge!(options)
|
54
58
|
@options = Options.new(options)
|
55
59
|
|
56
60
|
@template = check_haml_encoding(template) do |msg, line|
|
@@ -166,8 +170,13 @@ module Haml
|
|
166
170
|
end
|
167
171
|
|
168
172
|
begin
|
169
|
-
|
170
|
-
|
173
|
+
str = @temple_engine.precompiled_with_ambles(local_names)
|
174
|
+
eval(
|
175
|
+
"Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {}; #{str}}\n",
|
176
|
+
scope,
|
177
|
+
@options.filename,
|
178
|
+
@options.line
|
179
|
+
)
|
171
180
|
rescue ::SyntaxError => e
|
172
181
|
raise SyntaxError, e.message
|
173
182
|
end
|
data/lib/haml/error.rb
CHANGED
@@ -1,32 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Haml
|
3
4
|
# An exception raised by Haml code.
|
4
5
|
class Error < StandardError
|
5
6
|
|
6
7
|
MESSAGES = {
|
7
|
-
:
|
8
|
-
:
|
9
|
-
:
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
20
|
-
:
|
21
|
-
:
|
22
|
-
:
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
26
|
-
:
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
8
|
+
bad_script_indent: '"%s" is indented at wrong level: expected %d, but was at %d.',
|
9
|
+
cant_run_filter: 'Can\'t run "%s" filter; you must require its dependencies first',
|
10
|
+
cant_use_tabs_and_spaces: "Indentation can't use both tabs and spaces.",
|
11
|
+
deeper_indenting: "The line was indented %d levels deeper than the previous line.",
|
12
|
+
filter_not_defined: 'Filter "%s" is not defined.',
|
13
|
+
gem_install_filter_deps: '"%s" filter\'s %s dependency missing: try installing it or adding it to your Gemfile',
|
14
|
+
illegal_element: "Illegal element: classes and ids must have values.",
|
15
|
+
illegal_nesting_content: "Illegal nesting: nesting within a tag that already has content is illegal.",
|
16
|
+
illegal_nesting_header: "Illegal nesting: nesting within a header command is illegal.",
|
17
|
+
illegal_nesting_line: "Illegal nesting: content can't be both given on the same line as %%%s and nested within it.",
|
18
|
+
illegal_nesting_plain: "Illegal nesting: nesting within plain text is illegal.",
|
19
|
+
illegal_nesting_self_closing: "Illegal nesting: nesting within a self-closing tag is illegal.",
|
20
|
+
inconsistent_indentation: "Inconsistent indentation: %s used for indentation, but the rest of the document was indented using %s.",
|
21
|
+
indenting_at_start: "Indenting at the beginning of the document is illegal.",
|
22
|
+
install_haml_contrib: 'To use the "%s" filter, please install the haml-contrib gem.',
|
23
|
+
invalid_attribute_list: 'Invalid attribute list: %s.',
|
24
|
+
invalid_filter_name: 'Invalid filter name ":%s".',
|
25
|
+
invalid_tag: 'Invalid tag: "%s".',
|
26
|
+
missing_if: 'Got "%s" with no preceding "if"',
|
27
|
+
no_ruby_code: "There's no Ruby code for %s to evaluate.",
|
28
|
+
self_closing_content: "Self-closing tags can't have content.",
|
29
|
+
unbalanced_brackets: 'Unbalanced brackets.',
|
30
|
+
no_end: <<-END
|
30
31
|
You don't need to use "- end" in Haml. Un-indent to close a block:
|
31
32
|
- if foo?
|
32
33
|
%strong Foo!
|
@@ -34,7 +35,7 @@ You don't need to use "- end" in Haml. Un-indent to close a block:
|
|
34
35
|
Not foo.
|
35
36
|
%p This line is un-indented, so it isn't part of the "if" block
|
36
37
|
END
|
37
|
-
}
|
38
|
+
}.freeze
|
38
39
|
|
39
40
|
def self.message(key, *args)
|
40
41
|
string = MESSAGES[key] or raise "[HAML BUG] No error messages for #{key}"
|
data/lib/haml/escapable.rb
CHANGED
@@ -1,32 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Haml
|
3
4
|
# Like Temple::Filters::Escapable, but with support for escaping by
|
4
5
|
# Haml::Herlpers.html_escape and Haml::Herlpers.escape_once.
|
5
6
|
class Escapable < Temple::Filter
|
7
|
+
# Special value of `flag` to ignore html_safe?
|
8
|
+
EscapeSafeBuffer = Struct.new(:value)
|
9
|
+
|
6
10
|
def initialize(*)
|
7
11
|
super
|
8
|
-
@escape_code = "::Haml::Helpers.html_escape((%s))"
|
9
|
-
@escaper = eval("proc {|v| #{@escape_code % 'v'} }")
|
10
|
-
@once_escape_code = "::Haml::Helpers.escape_once((%s))"
|
11
|
-
@once_escaper = eval("proc {|v| #{@once_escape_code % 'v'} }")
|
12
12
|
@escape = false
|
13
|
+
@escape_safe_buffer = false
|
13
14
|
end
|
14
15
|
|
15
16
|
def on_escape(flag, exp)
|
16
|
-
|
17
|
-
@
|
17
|
+
old_escape, old_escape_safe_buffer = @escape, @escape_safe_buffer
|
18
|
+
@escape_safe_buffer = flag.is_a?(EscapeSafeBuffer)
|
19
|
+
@escape = @escape_safe_buffer ? flag.value : flag
|
18
20
|
compile(exp)
|
19
21
|
ensure
|
20
|
-
@escape =
|
22
|
+
@escape, @escape_safe_buffer = old_escape, old_escape_safe_buffer
|
21
23
|
end
|
22
24
|
|
23
25
|
# The same as Haml::AttributeBuilder.build_attributes
|
24
26
|
def on_static(value)
|
25
27
|
[:static,
|
26
28
|
if @escape == :once
|
27
|
-
|
29
|
+
escape_once(value)
|
28
30
|
elsif @escape
|
29
|
-
|
31
|
+
escape(value)
|
30
32
|
else
|
31
33
|
value
|
32
34
|
end
|
@@ -37,13 +39,39 @@ module Haml
|
|
37
39
|
def on_dynamic(value)
|
38
40
|
[:dynamic,
|
39
41
|
if @escape == :once
|
40
|
-
|
42
|
+
escape_once_code(value)
|
41
43
|
elsif @escape
|
42
|
-
|
44
|
+
escape_code(value)
|
43
45
|
else
|
44
46
|
"(#{value}).to_s"
|
45
47
|
end
|
46
48
|
]
|
47
49
|
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def escape_once(value)
|
54
|
+
if @escape_safe_buffer
|
55
|
+
::Haml::Helpers.escape_once_without_haml_xss(value)
|
56
|
+
else
|
57
|
+
::Haml::Helpers.escape_once(value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def escape(value)
|
62
|
+
if @escape_safe_buffer
|
63
|
+
::Haml::Helpers.html_escape_without_haml_xss(value)
|
64
|
+
else
|
65
|
+
::Haml::Helpers.html_escape(value)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def escape_once_code(value)
|
70
|
+
"::Haml::Helpers.escape_once#{('_without_haml_xss' if @escape_safe_buffer)}((#{value}))"
|
71
|
+
end
|
72
|
+
|
73
|
+
def escape_code(value)
|
74
|
+
"::Haml::Helpers.html_escape#{('_without_haml_xss' if @escape_safe_buffer)}((#{value}))"
|
75
|
+
end
|
48
76
|
end
|
49
77
|
end
|
data/lib/haml/exec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'optparse'
|
3
4
|
require 'rbconfig'
|
4
5
|
require 'pp'
|
@@ -120,7 +121,7 @@ module Haml
|
|
120
121
|
@options[:input], @options[:output] = input, output
|
121
122
|
end
|
122
123
|
|
123
|
-
COLORS = {
|
124
|
+
COLORS = {red: 31, green: 32, yellow: 33}.freeze
|
124
125
|
|
125
126
|
# Prints a status message about performing the given action,
|
126
127
|
# colored using the given color (via terminal escapes) if possible.
|
@@ -337,11 +338,9 @@ END
|
|
337
338
|
end
|
338
339
|
|
339
340
|
def validate_ruby(code)
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
$!
|
344
|
-
end
|
341
|
+
eval("BEGIN {return nil}; #{code}", binding, @options[:filename] || "")
|
342
|
+
rescue ::SyntaxError # Not to be confused with Haml::SyntaxError
|
343
|
+
$!
|
345
344
|
end
|
346
345
|
end
|
347
346
|
end
|
data/lib/haml/filters.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require "tilt"
|
3
4
|
|
4
5
|
module Haml
|
@@ -119,7 +120,7 @@ module Haml
|
|
119
120
|
# @param text [String] The source text for the filter to process
|
120
121
|
# @return [String] The filtered result
|
121
122
|
# @raise [Haml::Error] if it's not overridden
|
122
|
-
def render(
|
123
|
+
def render(_text)
|
123
124
|
raise Error.new("#{self.inspect}#render not defined!")
|
124
125
|
end
|
125
126
|
|
@@ -130,7 +131,7 @@ module Haml
|
|
130
131
|
# @param text [String] The source text for the filter to process
|
131
132
|
# @return [String] The filtered result
|
132
133
|
# @raise [Haml::Error] if it or \{#render} isn't overridden
|
133
|
-
def render_with_options(text,
|
134
|
+
def render_with_options(text, _options)
|
134
135
|
render(text)
|
135
136
|
end
|
136
137
|
|
@@ -164,7 +165,11 @@ module Haml
|
|
164
165
|
if contains_interpolation?(text)
|
165
166
|
return if options[:suppress_eval]
|
166
167
|
|
167
|
-
|
168
|
+
escape = options[:escape_filter_interpolations]
|
169
|
+
# `escape_filter_interpolations` defaults to `escape_html` if unset.
|
170
|
+
escape = options[:escape_html] if escape.nil?
|
171
|
+
|
172
|
+
text = unescape_interpolation(text, escape).gsub(/(\\+)n/) do |s|
|
168
173
|
escapes = $1.size
|
169
174
|
next s if escapes % 2 == 0
|
170
175
|
"#{'\\' * (escapes - 1)}\n"
|
@@ -182,9 +187,8 @@ RUBY
|
|
182
187
|
return
|
183
188
|
end
|
184
189
|
|
185
|
-
rendered = Haml::Helpers::find_and_preserve(filter.render_with_options(text, compiler.options), compiler.options[:preserve])
|
186
|
-
rendered.rstrip
|
187
|
-
push_text("#{rendered}\n")
|
190
|
+
rendered = Haml::Helpers::find_and_preserve(filter.render_with_options(text.to_s, compiler.options), compiler.options[:preserve])
|
191
|
+
push_text("#{rendered.rstrip}\n")
|
188
192
|
end
|
189
193
|
end
|
190
194
|
end
|
@@ -247,10 +251,7 @@ RUBY
|
|
247
251
|
|
248
252
|
# @see Base#render
|
249
253
|
def render(text)
|
250
|
-
|
251
|
-
text.rstrip!
|
252
|
-
text.gsub!("\n", "\n ")
|
253
|
-
"<![CDATA[#{text}\n]]>"
|
254
|
+
"<![CDATA[#{"\n#{text.rstrip}".gsub("\n", "\n ")}\n]]>"
|
254
255
|
end
|
255
256
|
end
|
256
257
|
|
data/lib/haml/generator.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Haml
|
3
4
|
module Helpers
|
4
5
|
module ActionViewMods
|
@@ -52,10 +53,12 @@ module ActionView
|
|
52
53
|
end
|
53
54
|
|
54
55
|
module TagHelper
|
56
|
+
DEFAULT_PRESERVE_OPTIONS = %w(textarea pre code).freeze
|
57
|
+
|
55
58
|
def content_tag_with_haml(name, *args, &block)
|
56
59
|
return content_tag_without_haml(name, *args, &block) unless is_haml?
|
57
60
|
|
58
|
-
preserve = haml_buffer.options.fetch(:preserve,
|
61
|
+
preserve = haml_buffer.options.fetch(:preserve, DEFAULT_PRESERVE_OPTIONS).include?(name.to_s)
|
59
62
|
|
60
63
|
if block_given? && block_is_haml?(block) && preserve
|
61
64
|
return content_tag_without_haml(name, *args) do
|