haml 4.0.0 → 5.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 +7 -0
- data/.yardopts +1 -1
- data/CHANGELOG.md +117 -5
- data/FAQ.md +7 -17
- data/MIT-LICENSE +1 -1
- data/README.md +85 -42
- data/REFERENCE.md +181 -86
- data/Rakefile +47 -51
- data/lib/haml/attribute_builder.rb +163 -0
- data/lib/haml/attribute_compiler.rb +215 -0
- data/lib/haml/attribute_parser.rb +144 -0
- data/lib/haml/buffer.rb +38 -128
- data/lib/haml/compiler.rb +88 -295
- data/lib/haml/engine.rb +25 -41
- data/lib/haml/error.rb +3 -0
- data/lib/haml/escapable.rb +49 -0
- data/lib/haml/exec.rb +33 -19
- data/lib/haml/filters.rb +20 -24
- data/lib/haml/generator.rb +41 -0
- data/lib/haml/helpers/action_view_extensions.rb +3 -2
- data/lib/haml/helpers/action_view_mods.rb +44 -66
- data/lib/haml/helpers/action_view_xss_mods.rb +1 -0
- data/lib/haml/helpers/safe_erubi_template.rb +27 -0
- data/lib/haml/helpers/safe_erubis_template.rb +16 -4
- data/lib/haml/helpers/xss_mods.rb +18 -12
- data/lib/haml/helpers.rb +122 -58
- data/lib/haml/options.rb +39 -46
- data/lib/haml/parser.rb +278 -217
- data/lib/haml/{template/plugin.rb → plugin.rb} +8 -15
- data/lib/haml/railtie.rb +21 -11
- data/lib/haml/sass_rails_filter.rb +17 -4
- data/lib/haml/template/options.rb +12 -2
- data/lib/haml/template.rb +12 -6
- data/lib/haml/temple_engine.rb +120 -0
- data/lib/haml/temple_line_counter.rb +29 -0
- data/lib/haml/util.rb +80 -199
- data/lib/haml/version.rb +2 -1
- data/lib/haml.rb +2 -1
- data/test/attribute_parser_test.rb +101 -0
- data/test/engine_test.rb +306 -176
- data/test/filters_test.rb +32 -19
- data/test/gemfiles/Gemfile.rails-4.0.x +11 -0
- data/test/gemfiles/Gemfile.rails-4.0.x.lock +87 -0
- data/test/gemfiles/Gemfile.rails-4.1.x +5 -0
- data/test/gemfiles/Gemfile.rails-4.2.x +5 -0
- data/test/gemfiles/Gemfile.rails-5.0.x +4 -0
- data/test/helper_test.rb +282 -96
- data/test/options_test.rb +22 -0
- data/test/parser_test.rb +71 -4
- data/test/results/bemit.xhtml +4 -0
- data/test/results/eval_suppressed.xhtml +4 -4
- data/test/results/helpers.xhtml +43 -41
- data/test/results/helpful.xhtml +6 -3
- data/test/results/just_stuff.xhtml +21 -20
- data/test/results/list.xhtml +9 -9
- data/test/results/nuke_inner_whitespace.xhtml +22 -22
- data/test/results/nuke_outer_whitespace.xhtml +84 -92
- data/test/results/original_engine.xhtml +17 -17
- data/test/results/partial_layout.xhtml +4 -3
- data/test/results/partial_layout_erb.xhtml +4 -3
- data/test/results/partials.xhtml +11 -10
- data/test/results/silent_script.xhtml +63 -63
- data/test/results/standard.xhtml +156 -159
- data/test/results/tag_parsing.xhtml +19 -19
- data/test/results/very_basic.xhtml +2 -2
- data/test/results/whitespace_handling.xhtml +56 -50
- data/test/template_test.rb +44 -53
- data/test/template_test_helper.rb +38 -0
- data/test/templates/_text_area_helper.html.haml +4 -0
- data/test/templates/bemit.haml +3 -0
- data/test/templates/just_stuff.haml +1 -0
- data/test/templates/partial_layout_erb.erb +1 -1
- data/test/templates/standard_ugly.haml +1 -0
- data/test/templates/with_bom.haml +1 -0
- data/test/temple_line_counter_test.rb +40 -0
- data/test/test_helper.rb +26 -12
- data/test/util_test.rb +6 -47
- metadata +88 -106
- data/lib/haml/helpers/rails_323_textarea_fix.rb +0 -24
- data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
- data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
- data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
- data/test/gemfiles/Gemfile.rails-master +0 -4
- data/test/templates/_av_partial_1_ugly.haml +0 -9
- data/test/templates/_av_partial_2_ugly.haml +0 -5
- data/test/templates/action_view_ugly.haml +0 -47
- data/test/templates/standard_ugly.haml +0 -43
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'action_view'
|
3
|
+
|
4
|
+
module Haml
|
5
|
+
class ErubiTemplateHandler < ActionView::Template::Handlers::ERB::Erubi
|
6
|
+
|
7
|
+
def initialize(*args, &blk)
|
8
|
+
@newline_pending = 0
|
9
|
+
super
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class SafeErubiTemplate < Tilt::ErubiTemplate
|
14
|
+
def prepare
|
15
|
+
@options.merge! engine_class: Haml::ErubiTemplateHandler
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
def precompiled_preamble(locals)
|
20
|
+
[super, "@output_buffer = ActionView::OutputBuffer.new;"].join("\n")
|
21
|
+
end
|
22
|
+
|
23
|
+
def precompiled_postamble(locals)
|
24
|
+
[super, '@output_buffer.to_s'].join("\n")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,20 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'action_view'
|
3
|
+
|
1
4
|
module Haml
|
5
|
+
|
6
|
+
class ErubisTemplateHandler < ActionView::Template::Handlers::Erubis
|
7
|
+
|
8
|
+
def initialize(*args, &blk)
|
9
|
+
@newline_pending = 0
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
2
14
|
class SafeErubisTemplate < Tilt::ErubisTemplate
|
3
15
|
|
4
16
|
def initialize_engine
|
5
17
|
end
|
6
18
|
|
7
19
|
def prepare
|
8
|
-
@options.merge! :engine_class =>
|
20
|
+
@options.merge! :engine_class => Haml::ErubisTemplateHandler
|
9
21
|
super
|
10
22
|
end
|
11
23
|
|
12
24
|
def precompiled_preamble(locals)
|
13
|
-
[super, "@output_buffer =
|
25
|
+
[super, "@output_buffer = ActionView::OutputBuffer.new;"].join("\n")
|
14
26
|
end
|
15
27
|
|
16
28
|
def precompiled_postamble(locals)
|
17
|
-
[super, '@output_buffer.to_s']
|
29
|
+
[super, '@output_buffer.to_s'].join("\n")
|
18
30
|
end
|
19
31
|
end
|
20
|
-
end
|
32
|
+
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Haml
|
2
3
|
module Helpers
|
3
4
|
# This module overrides Haml helpers to work properly
|
@@ -7,8 +8,8 @@ module Haml
|
|
7
8
|
module XssMods
|
8
9
|
def self.included(base)
|
9
10
|
%w[html_escape find_and_preserve preserve list_of surround
|
10
|
-
precede succeed capture_haml haml_concat haml_indent
|
11
|
-
|
11
|
+
precede succeed capture_haml haml_concat haml_internal_concat haml_indent
|
12
|
+
escape_once].each do |name|
|
12
13
|
base.send(:alias_method, "#{name}_without_haml_xss", name)
|
13
14
|
base.send(:alias_method, name, "#{name}_with_haml_xss")
|
14
15
|
end
|
@@ -61,24 +62,29 @@ module Haml
|
|
61
62
|
Haml::Util.html_safe(capture_haml_without_haml_xss(*args, &block))
|
62
63
|
end
|
63
64
|
|
64
|
-
# Input is
|
65
|
+
# Input will be escaped unless this is in a `with_raw_haml_concat`
|
66
|
+
# block. See #Haml::Helpers::ActionViewExtensions#with_raw_haml_concat.
|
65
67
|
def haml_concat_with_haml_xss(text = "")
|
66
|
-
raw = instance_variable_defined?(
|
67
|
-
|
68
|
+
raw = instance_variable_defined?(:@_haml_concat_raw) ? @_haml_concat_raw : false
|
69
|
+
if raw
|
70
|
+
haml_internal_concat_raw text
|
71
|
+
else
|
72
|
+
haml_internal_concat text
|
73
|
+
end
|
74
|
+
ErrorReturn.new("haml_concat")
|
68
75
|
end
|
69
76
|
|
77
|
+
# Input is escaped
|
78
|
+
def haml_internal_concat_with_haml_xss(text="", newline=true, indent=true)
|
79
|
+
haml_internal_concat_without_haml_xss(haml_xss_html_escape(text), newline, indent)
|
80
|
+
end
|
81
|
+
private :haml_internal_concat_with_haml_xss
|
82
|
+
|
70
83
|
# Output is always HTML safe
|
71
84
|
def haml_indent_with_haml_xss
|
72
85
|
Haml::Util.html_safe(haml_indent_without_haml_xss)
|
73
86
|
end
|
74
87
|
|
75
|
-
# Input is escaped, haml_concat'ed output is always HTML safe
|
76
|
-
def haml_tag_with_haml_xss(name, *rest, &block)
|
77
|
-
name = haml_xss_html_escape(name.to_s)
|
78
|
-
rest.unshift(haml_xss_html_escape(rest.shift.to_s)) unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
|
79
|
-
with_raw_haml_concat {haml_tag_without_haml_xss(name, *rest, &block)}
|
80
|
-
end
|
81
|
-
|
82
88
|
# Output is always HTML safe
|
83
89
|
def escape_once_with_haml_xss(*args)
|
84
90
|
Haml::Util.html_safe(escape_once_without_haml_xss(*args))
|
data/lib/haml/helpers.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
require 'erb'
|
3
|
+
|
1
4
|
module Haml
|
2
5
|
# This module contains various helpful methods to make it easier to do various tasks.
|
3
6
|
# {Haml::Helpers} is automatically included in the context
|
@@ -106,7 +109,11 @@ MESSAGE
|
|
106
109
|
# @yield The block within which to escape newlines
|
107
110
|
def find_and_preserve(input = nil, tags = haml_buffer.options[:preserve], &block)
|
108
111
|
return find_and_preserve(capture_haml(&block), input || tags) if block
|
109
|
-
|
112
|
+
tags = tags.each_with_object('') do |t, s|
|
113
|
+
s << '|' unless s.empty?
|
114
|
+
s << Regexp.escape(t)
|
115
|
+
end
|
116
|
+
re = /<(#{tags})([^>]*)>(.*?)(<\/\1>)/im
|
110
117
|
input.to_s.gsub(re) do |s|
|
111
118
|
s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
|
112
119
|
"<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
|
@@ -117,17 +124,20 @@ MESSAGE
|
|
117
124
|
# HTML entities so they'll render correctly in
|
118
125
|
# whitespace-sensitive tags without screwing up the indentation.
|
119
126
|
#
|
120
|
-
# @overload
|
127
|
+
# @overload preserve(input)
|
121
128
|
# Escapes newlines within a string.
|
122
129
|
#
|
123
130
|
# @param input [String] The string within which to escape all newlines
|
124
|
-
# @overload
|
131
|
+
# @overload preserve
|
125
132
|
# Escapes newlines within a block of Haml code.
|
126
133
|
#
|
127
134
|
# @yield The block within which to escape newlines
|
128
135
|
def preserve(input = nil, &block)
|
129
136
|
return preserve(capture_haml(&block)) if block
|
130
|
-
input.to_s.chomp("\n")
|
137
|
+
s = input.to_s.chomp("\n")
|
138
|
+
s.gsub!(/\n/, '
')
|
139
|
+
s.delete!("\r")
|
140
|
+
s
|
131
141
|
end
|
132
142
|
alias_method :flatten, :preserve
|
133
143
|
|
@@ -190,20 +200,20 @@ MESSAGE
|
|
190
200
|
# @yield [item] A block which contains Haml code that goes within list items
|
191
201
|
# @yieldparam item An element of `enum`
|
192
202
|
def list_of(enum, opts={}, &block)
|
193
|
-
opts_attributes = opts.
|
194
|
-
|
203
|
+
opts_attributes = opts.each_with_object('') {|(k, v), s| s << " #{k}='#{v}'"}
|
204
|
+
enum.each_with_object('') do |i, ret|
|
195
205
|
result = capture_haml(i, &block)
|
196
206
|
|
197
207
|
if result.count("\n") > 1
|
198
|
-
result
|
199
|
-
result = "\n #{result.strip}\n"
|
208
|
+
result.gsub!("\n", "\n ")
|
209
|
+
result = "\n #{result.strip!}\n"
|
200
210
|
else
|
201
|
-
result
|
211
|
+
result.strip!
|
202
212
|
end
|
203
213
|
|
204
|
-
|
214
|
+
ret << "\n" unless ret.empty?
|
215
|
+
ret << %Q!<li#{opts_attributes}>#{result}</li>!
|
205
216
|
end
|
206
|
-
to_return.join("\n")
|
207
217
|
end
|
208
218
|
|
209
219
|
# Returns a hash containing default assignments for the `xmlns`, `lang`, and `xml:lang`
|
@@ -219,7 +229,11 @@ MESSAGE
|
|
219
229
|
# @param lang [String] The value of `xml:lang` and `lang`
|
220
230
|
# @return [{#to_s => String}] The attribute hash
|
221
231
|
def html_attrs(lang = 'en-US')
|
222
|
-
|
232
|
+
if haml_buffer.options[:format] == :xhtml
|
233
|
+
{:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang}
|
234
|
+
else
|
235
|
+
{:lang => lang}
|
236
|
+
end
|
223
237
|
end
|
224
238
|
|
225
239
|
# Increments the number of tabs the buffer automatically adds
|
@@ -365,24 +379,15 @@ MESSAGE
|
|
365
379
|
position = haml_buffer.buffer.length
|
366
380
|
|
367
381
|
haml_buffer.capture_position = position
|
368
|
-
block.call(*args)
|
382
|
+
value = block.call(*args)
|
369
383
|
|
370
384
|
captured = haml_buffer.buffer.slice!(position..-1)
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
captured = captured.split(/^/).reject {|x| x == ""}
|
375
|
-
|
376
|
-
min_tabs = nil
|
377
|
-
captured.each do |line|
|
378
|
-
tabs = line.index(/[^ ]/) || line.length
|
379
|
-
min_tabs ||= tabs
|
380
|
-
min_tabs = min_tabs > tabs ? tabs : min_tabs
|
385
|
+
|
386
|
+
if captured == '' and value != haml_buffer.buffer
|
387
|
+
captured = (value.is_a?(String) ? value : nil)
|
381
388
|
end
|
382
389
|
|
383
|
-
captured
|
384
|
-
line[min_tabs..-1]
|
385
|
-
end.join
|
390
|
+
captured
|
386
391
|
end
|
387
392
|
ensure
|
388
393
|
haml_buffer.capture_position = nil
|
@@ -392,14 +397,34 @@ MESSAGE
|
|
392
397
|
#
|
393
398
|
# @param text [#to_s] The text to output
|
394
399
|
def haml_concat(text = "")
|
395
|
-
|
396
|
-
|
397
|
-
|
400
|
+
haml_internal_concat text
|
401
|
+
ErrorReturn.new("haml_concat")
|
402
|
+
end
|
403
|
+
|
404
|
+
# Internal method to write directly to the buffer with control of
|
405
|
+
# whether the first line should be indented, and if there should be a
|
406
|
+
# final newline.
|
407
|
+
#
|
408
|
+
# Lines added will have the proper indentation. This can be controlled
|
409
|
+
# for the first line.
|
410
|
+
#
|
411
|
+
# Used by #haml_concat and #haml_tag.
|
412
|
+
#
|
413
|
+
# @param text [#to_s] The text to output
|
414
|
+
# @param newline [Boolean] Whether to add a newline after the text
|
415
|
+
# @param indent [Boolean] Whether to add indentation to the first line
|
416
|
+
def haml_internal_concat(text = "", newline = true, indent = true)
|
417
|
+
if haml_buffer.tabulation == 0
|
418
|
+
haml_buffer.buffer << "#{text}#{"\n" if newline}"
|
398
419
|
else
|
399
|
-
haml_buffer.buffer << text.to_s
|
420
|
+
haml_buffer.buffer << %[#{haml_indent if indent}#{text.to_s.gsub("\n", "\n#{haml_indent}")}#{"\n" if newline}]
|
400
421
|
end
|
401
|
-
ErrorReturn.new("haml_concat")
|
402
422
|
end
|
423
|
+
private :haml_internal_concat
|
424
|
+
|
425
|
+
# Allows writing raw content. `haml_internal_concat_raw` isn't
|
426
|
+
# effected by XSS mods. Used by #haml_tag to write the actual tags.
|
427
|
+
alias :haml_internal_concat_raw :haml_internal_concat
|
403
428
|
|
404
429
|
# @return [String] The indentation string for the current line
|
405
430
|
def haml_indent
|
@@ -473,14 +498,14 @@ MESSAGE
|
|
473
498
|
attrs.keys.each {|key| attrs[key.to_s] = attrs.delete(key)} unless attrs.empty?
|
474
499
|
name, attrs = merge_name_and_attributes(name.to_s, attrs)
|
475
500
|
|
476
|
-
attributes = Haml::
|
501
|
+
attributes = Haml::AttributeBuilder.build_attributes(haml_buffer.html?,
|
477
502
|
haml_buffer.options[:attr_wrapper],
|
478
503
|
haml_buffer.options[:escape_attrs],
|
479
504
|
haml_buffer.options[:hyphenate_data_attrs],
|
480
505
|
attrs)
|
481
506
|
|
482
507
|
if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
|
483
|
-
|
508
|
+
haml_internal_concat_raw "<#{name}#{attributes}#{' /' if haml_buffer.options[:format] == :xhtml}>"
|
484
509
|
return ret
|
485
510
|
end
|
486
511
|
|
@@ -490,17 +515,19 @@ MESSAGE
|
|
490
515
|
end
|
491
516
|
|
492
517
|
tag = "<#{name}#{attributes}>"
|
518
|
+
end_tag = "</#{name}>"
|
493
519
|
if block.nil?
|
494
520
|
text = text.to_s
|
495
521
|
if text.include?("\n")
|
496
|
-
|
522
|
+
haml_internal_concat_raw tag
|
497
523
|
tab_up
|
498
|
-
|
524
|
+
haml_internal_concat text
|
499
525
|
tab_down
|
500
|
-
|
526
|
+
haml_internal_concat_raw end_tag
|
501
527
|
else
|
502
|
-
tag
|
503
|
-
|
528
|
+
haml_internal_concat_raw tag, false
|
529
|
+
haml_internal_concat text, false, false
|
530
|
+
haml_internal_concat_raw end_tag, true, false
|
504
531
|
end
|
505
532
|
return ret
|
506
533
|
end
|
@@ -510,22 +537,68 @@ MESSAGE
|
|
510
537
|
end
|
511
538
|
|
512
539
|
if flags.include?(:<)
|
513
|
-
tag
|
514
|
-
|
540
|
+
haml_internal_concat_raw tag, false
|
541
|
+
haml_internal_concat "#{capture_haml(&block).strip}", false, false
|
542
|
+
haml_internal_concat_raw end_tag, true, false
|
515
543
|
return ret
|
516
544
|
end
|
517
545
|
|
518
|
-
|
546
|
+
haml_internal_concat_raw tag
|
519
547
|
tab_up
|
520
548
|
block.call
|
521
549
|
tab_down
|
522
|
-
|
550
|
+
haml_internal_concat_raw end_tag
|
523
551
|
|
524
552
|
ret
|
525
553
|
end
|
526
554
|
|
555
|
+
# Conditionally wrap a block in an element. If `condition` is `true` then
|
556
|
+
# this method renders the tag described by the arguments in `tag` (using
|
557
|
+
# \{#haml_tag}) with the given block inside, otherwise it just renders the block.
|
558
|
+
#
|
559
|
+
# For example,
|
560
|
+
#
|
561
|
+
# - haml_tag_if important, '.important' do
|
562
|
+
# %p
|
563
|
+
# A (possibly) important paragraph.
|
564
|
+
#
|
565
|
+
# will produce
|
566
|
+
#
|
567
|
+
# <div class='important'>
|
568
|
+
# <p>
|
569
|
+
# A (possibly) important paragraph.
|
570
|
+
# </p>
|
571
|
+
# </div>
|
572
|
+
#
|
573
|
+
# if `important` is truthy, and just
|
574
|
+
#
|
575
|
+
# <p>
|
576
|
+
# A (possibly) important paragraph.
|
577
|
+
# </p>
|
578
|
+
#
|
579
|
+
# otherwise.
|
580
|
+
#
|
581
|
+
# Like \{#haml_tag}, `haml_tag_if` outputs directly to the buffer and its
|
582
|
+
# return value should not be used. Use \{#capture_haml} if you need to use
|
583
|
+
# its results as a string.
|
584
|
+
#
|
585
|
+
# @param condition The condition to test to determine whether to render
|
586
|
+
# the enclosing tag
|
587
|
+
# @param tag Definition of the enclosing tag. See \{#haml_tag} for details
|
588
|
+
# (specifically the form that takes a block)
|
589
|
+
def haml_tag_if(condition, *tag)
|
590
|
+
if condition
|
591
|
+
haml_tag(*tag){ yield }
|
592
|
+
else
|
593
|
+
yield
|
594
|
+
end
|
595
|
+
ErrorReturn.new("haml_tag_if")
|
596
|
+
end
|
597
|
+
|
527
598
|
# Characters that need to be escaped to HTML entities from user input
|
528
|
-
HTML_ESCAPE = { '&'=>'&', '<'=>'<', '>'=>'>', '"'=>'"', "'"=>'&#
|
599
|
+
HTML_ESCAPE = { '&' => '&', '<' => '<', '>' => '>', '"' => '"', "'" => ''' }
|
600
|
+
|
601
|
+
HTML_ESCAPE_REGEX = /['"><&]/
|
529
602
|
|
530
603
|
# Returns a copy of `text` with ampersands, angle brackets and quotes
|
531
604
|
# escaped into HTML entities.
|
@@ -537,28 +610,19 @@ MESSAGE
|
|
537
610
|
# @param text [String] The string to sanitize
|
538
611
|
# @return [String] The sanitized string
|
539
612
|
def html_escape(text)
|
540
|
-
|
541
|
-
regex = if RUBY_VERSION >= '1.9'
|
542
|
-
Regexp.new(pattern.force_encoding(text.encoding), Regexp::FIXEDENCODING)
|
543
|
-
else
|
544
|
-
Regexp.new(pattern)
|
545
|
-
end
|
546
|
-
text.to_s.gsub(regex) {|s| HTML_ESCAPE[s]}
|
613
|
+
ERB::Util.html_escape(text)
|
547
614
|
end
|
548
615
|
|
616
|
+
HTML_ESCAPE_ONCE_REGEX = /['"><]|&(?!(?:[a-zA-Z]+|#(?:\d+|[xX][0-9a-fA-F]+));)/
|
617
|
+
|
549
618
|
# Escapes HTML entities in `text`, but without escaping an ampersand
|
550
619
|
# that is already part of an escaped entity.
|
551
620
|
#
|
552
621
|
# @param text [String] The string to sanitize
|
553
622
|
# @return [String] The sanitized string
|
554
623
|
def escape_once(text)
|
555
|
-
|
556
|
-
|
557
|
-
Regexp.new(pattern.force_encoding(text.encoding), Regexp::FIXEDENCODING)
|
558
|
-
else
|
559
|
-
Regexp.new(pattern)
|
560
|
-
end
|
561
|
-
text.to_s.gsub(regex) {|s| HTML_ESCAPE[s]}
|
624
|
+
text = text.to_s
|
625
|
+
text.gsub(HTML_ESCAPE_ONCE_REGEX, HTML_ESCAPE)
|
562
626
|
end
|
563
627
|
|
564
628
|
# Returns whether or not the current template is a Haml template.
|
@@ -588,7 +652,7 @@ MESSAGE
|
|
588
652
|
# skip merging if no ids or classes found in name
|
589
653
|
return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/
|
590
654
|
|
591
|
-
return $1 || "div",
|
655
|
+
return $1 || "div", AttributeBuilder.merge_attributes!(
|
592
656
|
Haml::Parser.parse_class_and_id($2), attributes_hash)
|
593
657
|
end
|
594
658
|
|
data/lib/haml/options.rb
CHANGED
@@ -1,38 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Haml
|
2
3
|
# This class encapsulates all of the configuration options that Haml
|
3
4
|
# understands. Please see the {file:REFERENCE.md#options Haml Reference} to
|
4
5
|
# learn how to set the options.
|
5
6
|
class Options
|
6
7
|
|
7
|
-
@defaults = {
|
8
|
-
:attr_wrapper => "'",
|
9
|
-
:autoclose => %w(meta img link br hr input area param col base),
|
10
|
-
:encoding => "UTF-8",
|
11
|
-
:escape_attrs => true,
|
12
|
-
:escape_html => false,
|
13
|
-
:filename => '(haml)',
|
14
|
-
:format => :html5,
|
15
|
-
:hyphenate_data_attrs => true,
|
16
|
-
:line => 1,
|
17
|
-
:mime_type => 'text/html',
|
18
|
-
:preserve => %w(textarea pre code),
|
19
|
-
:remove_whitespace => false,
|
20
|
-
:suppress_eval => false,
|
21
|
-
:ugly => false,
|
22
|
-
:cdata => false,
|
23
|
-
:parser_class => ::Haml::Parser,
|
24
|
-
:compiler_class => ::Haml::Compiler
|
25
|
-
}
|
26
|
-
|
27
8
|
@valid_formats = [:html4, :html5, :xhtml]
|
28
9
|
|
29
|
-
@buffer_option_keys = [:autoclose, :preserve, :attr_wrapper, :
|
10
|
+
@buffer_option_keys = [:autoclose, :preserve, :attr_wrapper, :format,
|
30
11
|
:encoding, :escape_html, :escape_attrs, :hyphenate_data_attrs, :cdata]
|
31
12
|
|
32
13
|
# The default option values.
|
33
14
|
# @return Hash
|
34
15
|
def self.defaults
|
35
|
-
@defaults
|
16
|
+
@defaults ||= Haml::TempleEngine.options.to_hash.merge(encoding: 'UTF-8')
|
36
17
|
end
|
37
18
|
|
38
19
|
# An array of valid values for the `:format` option.
|
@@ -48,6 +29,22 @@ module Haml
|
|
48
29
|
@buffer_option_keys
|
49
30
|
end
|
50
31
|
|
32
|
+
# Returns a subset of defaults: those that {Haml::Buffer} cares about.
|
33
|
+
# @return [{Symbol => Object}] The options hash
|
34
|
+
def self.buffer_defaults
|
35
|
+
@buffer_defaults ||= buffer_option_keys.inject({}) do |hash, key|
|
36
|
+
hash.merge(key => defaults[key])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.wrap(options)
|
41
|
+
if options.is_a?(Options)
|
42
|
+
options
|
43
|
+
else
|
44
|
+
Options.new(options)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
51
48
|
# The character that should wrap element attributes. This defaults to `'`
|
52
49
|
# (an apostrophe). Characters of this type within the attributes will be
|
53
50
|
# escaped (e.g. by replacing them with `'`) if the character is an
|
@@ -61,7 +58,6 @@ module Haml
|
|
61
58
|
attr_accessor :autoclose
|
62
59
|
|
63
60
|
# The encoding to use for the HTML output.
|
64
|
-
# Only available on Ruby 1.9 or higher.
|
65
61
|
# This can be a string or an `Encoding` Object. Note that Haml **does not**
|
66
62
|
# automatically re-encode Ruby values; any strings coming from outside the
|
67
63
|
# application should be converted before being passed into the Haml
|
@@ -144,13 +140,6 @@ module Haml
|
|
144
140
|
# Defaults to `false`.
|
145
141
|
attr_accessor :suppress_eval
|
146
142
|
|
147
|
-
# If set to `true`, Haml makes no attempt to properly indent or format the
|
148
|
-
# HTML output. This significantly improves rendering performance but makes
|
149
|
-
# viewing the source unpleasant.
|
150
|
-
#
|
151
|
-
# Defaults to `true` in Rails production mode, and `false` everywhere else.
|
152
|
-
attr_accessor :ugly
|
153
|
-
|
154
143
|
# Whether to include CDATA sections around javascript and css blocks when
|
155
144
|
# using the `:javascript` or `:css` filters.
|
156
145
|
#
|
@@ -167,9 +156,17 @@ module Haml
|
|
167
156
|
# The compiler class to use. Defaults to Haml::Compiler.
|
168
157
|
attr_accessor :compiler_class
|
169
158
|
|
159
|
+
# Enable template tracing. If true, it will add a 'data-trace' attribute to
|
160
|
+
# each tag generated by Haml. The value of the attribute will be the
|
161
|
+
# source template name and the line number from which the tag was generated,
|
162
|
+
# separated by a colon. On Rails applications, the path given will be a
|
163
|
+
# relative path as from the views directory. On non-Rails applications,
|
164
|
+
# the path will be the full path.
|
165
|
+
attr_accessor :trace
|
166
|
+
|
170
167
|
def initialize(values = {}, &block)
|
171
168
|
defaults.each {|k, v| instance_variable_set :"@#{k}", v}
|
172
|
-
values.
|
169
|
+
values.each {|k, v| send("#{k}=", v) if defaults.has_key?(k) && !v.nil?}
|
173
170
|
yield if block_given?
|
174
171
|
end
|
175
172
|
|
@@ -186,8 +183,7 @@ module Haml
|
|
186
183
|
send "#{key}=", value
|
187
184
|
end
|
188
185
|
|
189
|
-
[:escape_attrs, :hyphenate_data_attrs, :remove_whitespace, :suppress_eval
|
190
|
-
:ugly].each do |method|
|
186
|
+
[:escape_attrs, :hyphenate_data_attrs, :remove_whitespace, :suppress_eval].each do |method|
|
191
187
|
class_eval(<<-END)
|
192
188
|
def #{method}?
|
193
189
|
!! @#{method}
|
@@ -239,21 +235,16 @@ module Haml
|
|
239
235
|
end
|
240
236
|
|
241
237
|
def remove_whitespace=(value)
|
242
|
-
@ugly = true if value
|
243
238
|
@remove_whitespace = value
|
244
239
|
end
|
245
240
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
return unless value
|
251
|
-
@encoding = value.is_a?(Encoding) ? value.name : value.to_s
|
252
|
-
@encoding = "UTF-8" if @encoding.upcase == "US-ASCII"
|
253
|
-
end
|
241
|
+
def encoding=(value)
|
242
|
+
return unless value
|
243
|
+
@encoding = value.is_a?(Encoding) ? value.name : value.to_s
|
244
|
+
@encoding = "UTF-8" if @encoding.upcase == "US-ASCII"
|
254
245
|
end
|
255
246
|
|
256
|
-
# Returns a subset of options: those that {Haml::Buffer} cares about.
|
247
|
+
# Returns a non-default subset of options: those that {Haml::Buffer} cares about.
|
257
248
|
# All of the values here are such that when `#inspect` is called on the hash,
|
258
249
|
# it can be `Kernel#eval`ed to get the same result back.
|
259
250
|
#
|
@@ -262,7 +253,10 @@ module Haml
|
|
262
253
|
# @return [{Symbol => Object}] The options hash
|
263
254
|
def for_buffer
|
264
255
|
self.class.buffer_option_keys.inject({}) do |hash, key|
|
265
|
-
|
256
|
+
value = public_send(key)
|
257
|
+
if self.class.buffer_defaults[key] != value
|
258
|
+
hash[key] = value
|
259
|
+
end
|
266
260
|
hash
|
267
261
|
end
|
268
262
|
end
|
@@ -272,6 +266,5 @@ module Haml
|
|
272
266
|
def defaults
|
273
267
|
self.class.defaults
|
274
268
|
end
|
275
|
-
|
276
269
|
end
|
277
|
-
end
|
270
|
+
end
|