haml 5.0.3 → 5.2.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 +5 -5
- data/.gitignore +1 -0
- data/.travis.yml +50 -25
- data/.yardopts +1 -2
- data/CHANGELOG.md +44 -1
- data/Gemfile +2 -5
- data/MIT-LICENSE +2 -2
- data/README.md +4 -5
- data/REFERENCE.md +27 -4
- data/Rakefile +2 -13
- data/benchmark.rb +13 -9
- data/haml.gemspec +10 -3
- data/lib/haml.rb +1 -0
- data/lib/haml/attribute_builder.rb +4 -3
- data/lib/haml/attribute_compiler.rb +43 -31
- data/lib/haml/attribute_parser.rb +6 -4
- data/lib/haml/buffer.rb +4 -1
- 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.rb +15 -13
- 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/options.rb +36 -36
- data/lib/haml/parser.rb +21 -19
- data/lib/haml/plugin.rb +7 -4
- data/lib/haml/railtie.rb +4 -4
- data/lib/haml/sass_rails_filter.rb +1 -0
- data/lib/haml/template.rb +1 -0
- data/lib/haml/template/options.rb +1 -0
- data/lib/haml/temple_engine.rb +11 -9
- data/lib/haml/temple_line_counter.rb +1 -0
- data/lib/haml/util.rb +5 -5
- data/lib/haml/version.rb +2 -1
- metadata +28 -10
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
data/lib/haml/helpers.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'erb'
|
3
4
|
|
4
5
|
module Haml
|
@@ -109,10 +110,7 @@ MESSAGE
|
|
109
110
|
# @yield The block within which to escape newlines
|
110
111
|
def find_and_preserve(input = nil, tags = haml_buffer.options[:preserve], &block)
|
111
112
|
return find_and_preserve(capture_haml(&block), input || tags) if block
|
112
|
-
tags = tags.
|
113
|
-
s << '|' unless s.empty?
|
114
|
-
s << Regexp.escape(t)
|
115
|
-
end
|
113
|
+
tags = tags.map { |tag| Regexp.escape(tag) }.join('|')
|
116
114
|
re = /<(#{tags})([^>]*)>(.*?)(<\/\1>)/im
|
117
115
|
input.to_s.gsub(re) do |s|
|
118
116
|
s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
|
@@ -200,8 +198,8 @@ MESSAGE
|
|
200
198
|
# @yield [item] A block which contains Haml code that goes within list items
|
201
199
|
# @yieldparam item An element of `enum`
|
202
200
|
def list_of(enum, opts={}, &block)
|
203
|
-
opts_attributes = opts.
|
204
|
-
enum.
|
201
|
+
opts_attributes = opts.map { |k, v| " #{k}='#{v}'" }.join
|
202
|
+
enum.map do |i|
|
205
203
|
result = capture_haml(i, &block)
|
206
204
|
|
207
205
|
if result.count("\n") > 1
|
@@ -211,9 +209,8 @@ MESSAGE
|
|
211
209
|
result.strip!
|
212
210
|
end
|
213
211
|
|
214
|
-
|
215
|
-
|
216
|
-
end
|
212
|
+
%Q!<li#{opts_attributes}>#{result}</li>!
|
213
|
+
end.join("\n")
|
217
214
|
end
|
218
215
|
|
219
216
|
# Returns a hash containing default assignments for the `xmlns`, `lang`, and `xml:lang`
|
@@ -596,7 +593,7 @@ MESSAGE
|
|
596
593
|
end
|
597
594
|
|
598
595
|
# Characters that need to be escaped to HTML entities from user input
|
599
|
-
HTML_ESCAPE = {
|
596
|
+
HTML_ESCAPE = {'&' => '&', '<' => '<', '>' => '>', '"' => '"', "'" => '''}.freeze
|
600
597
|
|
601
598
|
HTML_ESCAPE_REGEX = /['"><&]/
|
602
599
|
|
@@ -610,9 +607,12 @@ MESSAGE
|
|
610
607
|
# @param text [String] The string to sanitize
|
611
608
|
# @return [String] The sanitized string
|
612
609
|
def html_escape(text)
|
613
|
-
|
610
|
+
CGI.escapeHTML(text.to_s)
|
614
611
|
end
|
615
612
|
|
613
|
+
# Always escape text regardless of html_safe?
|
614
|
+
alias_method :html_escape_without_haml_xss, :html_escape
|
615
|
+
|
616
616
|
HTML_ESCAPE_ONCE_REGEX = /['"><]|&(?!(?:[a-zA-Z]+|#(?:\d+|[xX][0-9a-fA-F]+));)/
|
617
617
|
|
618
618
|
# Escapes HTML entities in `text`, but without escaping an ampersand
|
@@ -625,6 +625,9 @@ MESSAGE
|
|
625
625
|
text.gsub(HTML_ESCAPE_ONCE_REGEX, HTML_ESCAPE)
|
626
626
|
end
|
627
627
|
|
628
|
+
# Always escape text once regardless of html_safe?
|
629
|
+
alias_method :escape_once_without_haml_xss, :escape_once
|
630
|
+
|
628
631
|
# Returns whether or not the current template is a Haml template.
|
629
632
|
#
|
630
633
|
# This function, unlike other {Haml::Helpers} functions,
|
@@ -704,4 +707,3 @@ class Object
|
|
704
707
|
false
|
705
708
|
end
|
706
709
|
end
|
707
|
-
|
@@ -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
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Haml
|
3
4
|
module Helpers
|
4
5
|
# This module overrides Haml helpers to work properly
|
@@ -7,12 +8,15 @@ module Haml
|
|
7
8
|
# to work with Rails' XSS protection methods.
|
8
9
|
module XssMods
|
9
10
|
def self.included(base)
|
10
|
-
%w[
|
11
|
-
precede succeed capture_haml haml_concat haml_internal_concat haml_indent
|
12
|
-
escape_once].each do |name|
|
11
|
+
%w[find_and_preserve preserve list_of surround
|
12
|
+
precede succeed capture_haml haml_concat haml_internal_concat haml_indent].each do |name|
|
13
13
|
base.send(:alias_method, "#{name}_without_haml_xss", name)
|
14
14
|
base.send(:alias_method, name, "#{name}_with_haml_xss")
|
15
15
|
end
|
16
|
+
# Those two always have _without_haml_xss
|
17
|
+
%w[html_escape escape_once].each do |name|
|
18
|
+
base.send(:alias_method, name, "#{name}_with_haml_xss")
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
22
|
# Don't escape text that's already safe,
|
data/lib/haml/options.rb
CHANGED
@@ -1,47 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
module Haml
|
3
4
|
# This class encapsulates all of the configuration options that Haml
|
4
5
|
# understands. Please see the {file:REFERENCE.md#options Haml Reference} to
|
5
6
|
# learn how to set the options.
|
6
7
|
class Options
|
7
|
-
|
8
8
|
@valid_formats = [:html4, :html5, :xhtml]
|
9
|
-
|
10
9
|
@buffer_option_keys = [:autoclose, :preserve, :attr_wrapper, :format,
|
11
|
-
:encoding, :escape_html, :escape_attrs, :hyphenate_data_attrs, :cdata]
|
10
|
+
:encoding, :escape_html, :escape_filter_interpolations, :escape_attrs, :hyphenate_data_attrs, :cdata]
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
class << self
|
13
|
+
# The default option values.
|
14
|
+
# @return Hash
|
15
|
+
def defaults
|
16
|
+
@defaults ||= Haml::TempleEngine.options.to_hash.merge(encoding: 'UTF-8')
|
17
|
+
end
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
@valid_formats
|
23
|
-
end
|
19
|
+
# An array of valid values for the `:format` option.
|
20
|
+
# @return Array
|
21
|
+
attr_reader :valid_formats
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@buffer_option_keys
|
30
|
-
end
|
23
|
+
# An array of keys that will be used to provide a hash of options to
|
24
|
+
# {Haml::Buffer}.
|
25
|
+
# @return Hash
|
26
|
+
attr_reader :buffer_option_keys
|
31
27
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
# Returns a subset of defaults: those that {Haml::Buffer} cares about.
|
29
|
+
# @return [{Symbol => Object}] The options hash
|
30
|
+
def buffer_defaults
|
31
|
+
@buffer_defaults ||= buffer_option_keys.inject({}) do |hash, key|
|
32
|
+
hash.merge(key => defaults[key])
|
33
|
+
end
|
37
34
|
end
|
38
|
-
end
|
39
35
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
36
|
+
def wrap(options)
|
37
|
+
if options.is_a?(Options)
|
38
|
+
options
|
39
|
+
else
|
40
|
+
Options.new(options)
|
41
|
+
end
|
45
42
|
end
|
46
43
|
end
|
47
44
|
|
@@ -85,6 +82,13 @@ module Haml
|
|
85
82
|
# Defaults to false.
|
86
83
|
attr_accessor :escape_html
|
87
84
|
|
85
|
+
# Sets whether or not to escape HTML-sensitive characters in interpolated strings.
|
86
|
+
# See also {file:REFERENCE.md#escaping_html Escaping HTML} and
|
87
|
+
# {file:REFERENCE.md#unescaping_html Unescaping HTML}.
|
88
|
+
#
|
89
|
+
# Defaults to the current value of `escape_html`.
|
90
|
+
attr_accessor :escape_filter_interpolations
|
91
|
+
|
88
92
|
# The name of the Haml file being parsed.
|
89
93
|
# This is only used as information when exceptions are raised. This is
|
90
94
|
# automatically assigned when working through ActionView, so it's really
|
@@ -131,7 +135,7 @@ module Haml
|
|
131
135
|
# formatting errors.
|
132
136
|
#
|
133
137
|
# Defaults to `false`.
|
134
|
-
|
138
|
+
attr_accessor :remove_whitespace
|
135
139
|
|
136
140
|
# Whether or not attribute hashes and Ruby scripts designated by `=` or `~`
|
137
141
|
# should be evaluated. If this is `true`, said scripts are rendered as empty
|
@@ -167,7 +171,7 @@ module Haml
|
|
167
171
|
# Key is filter name in String and value is Class to use. Defaults to {}.
|
168
172
|
attr_accessor :filters
|
169
173
|
|
170
|
-
def initialize(values = {}
|
174
|
+
def initialize(values = {})
|
171
175
|
defaults.each {|k, v| instance_variable_set :"@#{k}", v}
|
172
176
|
values.each {|k, v| send("#{k}=", v) if defaults.has_key?(k) && !v.nil?}
|
173
177
|
yield if block_given?
|
@@ -237,10 +241,6 @@ module Haml
|
|
237
241
|
xhtml? || @cdata
|
238
242
|
end
|
239
243
|
|
240
|
-
def remove_whitespace=(value)
|
241
|
-
@remove_whitespace = value
|
242
|
-
end
|
243
|
-
|
244
244
|
def encoding=(value)
|
245
245
|
return unless value
|
246
246
|
@encoding = value.is_a?(Encoding) ? value.name : value.to_s
|
data/lib/haml/parser.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# frozen_string_literal:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'strscan'
|
3
4
|
|
4
5
|
module Haml
|
@@ -60,7 +61,7 @@ module Haml
|
|
60
61
|
SILENT_SCRIPT,
|
61
62
|
ESCAPE,
|
62
63
|
FILTER
|
63
|
-
]
|
64
|
+
].freeze
|
64
65
|
|
65
66
|
# The value of the character that designates that a line is part
|
66
67
|
# of a multiline string.
|
@@ -74,8 +75,8 @@ module Haml
|
|
74
75
|
#
|
75
76
|
BLOCK_WITH_SPACES = /do\s*\|\s*[^\|]*\s+\|\z/
|
76
77
|
|
77
|
-
MID_BLOCK_KEYWORDS = %w[else elsif rescue ensure end when]
|
78
|
-
START_BLOCK_KEYWORDS = %w[if begin case unless]
|
78
|
+
MID_BLOCK_KEYWORDS = %w[else elsif rescue ensure end when].freeze
|
79
|
+
START_BLOCK_KEYWORDS = %w[if begin case unless].freeze
|
79
80
|
# Try to parse assignments to block starters as best as possible
|
80
81
|
START_BLOCK_KEYWORD_REGEX = /(?:\w+(?:,\s*\w+)*\s*=\s*)?(#{START_BLOCK_KEYWORDS.join('|')})/
|
81
82
|
BLOCK_KEYWORD_REGEX = /^-?\s*(?:(#{MID_BLOCK_KEYWORDS.join('|')})|#{START_BLOCK_KEYWORD_REGEX.source})\b/
|
@@ -178,7 +179,7 @@ module Haml
|
|
178
179
|
private
|
179
180
|
|
180
181
|
# @private
|
181
|
-
|
182
|
+
Line = Struct.new(:whitespace, :text, :full, :index, :parser, :eod) do
|
182
183
|
alias_method :eod?, :eod
|
183
184
|
|
184
185
|
# @private
|
@@ -194,25 +195,26 @@ module Haml
|
|
194
195
|
end
|
195
196
|
|
196
197
|
# @private
|
197
|
-
|
198
|
+
ParseNode = Struct.new(:type, :line, :value, :parent, :children) do
|
198
199
|
def initialize(*args)
|
199
200
|
super
|
200
201
|
self.children ||= []
|
201
202
|
end
|
202
203
|
|
203
204
|
def inspect
|
204
|
-
%Q[(#{type} #{value.inspect}#{children.each_with_object('') {|c, s| s << "\n#{c.inspect.gsub!(/^/, ' ')}"}})]
|
205
|
+
%Q[(#{type} #{value.inspect}#{children.each_with_object(''.dup) {|c, s| s << "\n#{c.inspect.gsub!(/^/, ' ')}"}})].dup
|
205
206
|
end
|
206
207
|
end
|
207
208
|
|
208
209
|
# @param [String] new - Hash literal including dynamic values.
|
209
210
|
# @param [String] old - Hash literal including dynamic values or Ruby literal of multiple Hashes which MUST be interpreted as method's last arguments.
|
210
|
-
|
211
|
+
DynamicAttributes = Struct.new(:new, :old) do
|
212
|
+
undef :old=
|
211
213
|
def old=(value)
|
212
214
|
unless value =~ /\A{.*}\z/m
|
213
215
|
raise ArgumentError.new('Old attributes must start with "{" and end with "}"')
|
214
216
|
end
|
215
|
-
|
217
|
+
self[:old] = value
|
216
218
|
end
|
217
219
|
|
218
220
|
# This will be a literal for Haml::Buffer#attributes's last argument, `attributes_hashes`.
|
@@ -287,7 +289,7 @@ module Haml
|
|
287
289
|
end
|
288
290
|
|
289
291
|
def block_keyword(text)
|
290
|
-
return unless keyword = text.scan(BLOCK_KEYWORD_REGEX)[0]
|
292
|
+
return unless (keyword = text.scan(BLOCK_KEYWORD_REGEX)[0])
|
291
293
|
keyword[0] || keyword[1]
|
292
294
|
end
|
293
295
|
|
@@ -305,7 +307,7 @@ module Haml
|
|
305
307
|
return ParseNode.new(:plain, line.index + 1, :text => line.text)
|
306
308
|
end
|
307
309
|
|
308
|
-
escape_html = @options.escape_html if escape_html.nil?
|
310
|
+
escape_html = @options.escape_html && @options.mime_type != 'text/plain' if escape_html.nil?
|
309
311
|
line.text = unescape_interpolation(line.text, escape_html)
|
310
312
|
script(line, false)
|
311
313
|
end
|
@@ -534,7 +536,7 @@ module Haml
|
|
534
536
|
|
535
537
|
# Post-process case statements to normalize the nesting of "when" clauses
|
536
538
|
return unless node.value[:keyword] == "case"
|
537
|
-
return unless first = node.children.first
|
539
|
+
return unless (first = node.children.first)
|
538
540
|
return unless first.type == :silent_script && first.value[:keyword] == "when"
|
539
541
|
return if first.children.empty?
|
540
542
|
# If the case node has a "when" child with children, it's the
|
@@ -583,9 +585,9 @@ module Haml
|
|
583
585
|
scanner = StringScanner.new(text)
|
584
586
|
scanner.scan(/\s+/)
|
585
587
|
until scanner.eos?
|
586
|
-
return unless key = scanner.scan(LITERAL_VALUE_REGEX)
|
588
|
+
return unless (key = scanner.scan(LITERAL_VALUE_REGEX))
|
587
589
|
return unless scanner.scan(/\s*=>\s*/)
|
588
|
-
return unless value = scanner.scan(LITERAL_VALUE_REGEX)
|
590
|
+
return unless (value = scanner.scan(LITERAL_VALUE_REGEX))
|
589
591
|
return unless scanner.scan(/\s*(?:,|$)\s*/)
|
590
592
|
attributes[eval(key).to_s] = eval(value).to_s
|
591
593
|
end
|
@@ -698,7 +700,7 @@ module Haml
|
|
698
700
|
end
|
699
701
|
|
700
702
|
static_attributes = {}
|
701
|
-
dynamic_attributes = "{"
|
703
|
+
dynamic_attributes = "{".dup
|
702
704
|
attributes.each do |name, (type, val)|
|
703
705
|
if type == :static
|
704
706
|
static_attributes[name] = val
|
@@ -713,7 +715,7 @@ module Haml
|
|
713
715
|
end
|
714
716
|
|
715
717
|
def parse_new_attribute(scanner)
|
716
|
-
unless name = scanner.scan(/[-:\w]+/)
|
718
|
+
unless (name = scanner.scan(/[-:\w]+/))
|
717
719
|
return if scanner.scan(/\)/)
|
718
720
|
return false
|
719
721
|
end
|
@@ -722,8 +724,8 @@ module Haml
|
|
722
724
|
return name, [:static, true] unless scanner.scan(/=/) #/end
|
723
725
|
|
724
726
|
scanner.scan(/\s*/)
|
725
|
-
unless quote = scanner.scan(/["']/)
|
726
|
-
return false unless var = scanner.scan(/(@@?|\$)?\w+/)
|
727
|
+
unless (quote = scanner.scan(/["']/))
|
728
|
+
return false unless (var = scanner.scan(/(@@?|\$)?\w+/))
|
727
729
|
return name, [:dynamic, var]
|
728
730
|
end
|
729
731
|
|
@@ -738,7 +740,7 @@ module Haml
|
|
738
740
|
|
739
741
|
return name, [:static, content.first[1]] if content.size == 1
|
740
742
|
return name, [:dynamic,
|
741
|
-
%!"#{content.each_with_object('') {|(t, v), s| s << (t == :str ? inspect_obj(v)[1...-1] : "\#{#{v}}")}}"!]
|
743
|
+
%!"#{content.each_with_object(''.dup) {|(t, v), s| s << (t == :str ? inspect_obj(v)[1...-1] : "\#{#{v}}")}}"!]
|
742
744
|
end
|
743
745
|
|
744
746
|
def next_line
|