haml 4.0.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|