haml 4.1.0.beta.1 → 5.0.0.beta.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of haml might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/CHANGELOG.md +36 -6
- data/FAQ.md +4 -14
- data/MIT-LICENSE +1 -1
- data/README.md +81 -48
- data/REFERENCE.md +86 -50
- data/Rakefile +28 -41
- data/lib/haml/attribute_builder.rb +163 -0
- data/lib/haml/attribute_compiler.rb +214 -0
- data/lib/haml/attribute_parser.rb +112 -0
- data/lib/haml/buffer.rb +24 -126
- data/lib/haml/compiler.rb +62 -281
- data/lib/haml/engine.rb +16 -23
- data/lib/haml/error.rb +2 -0
- data/lib/haml/escapable.rb +48 -0
- data/lib/haml/exec.rb +23 -12
- data/lib/haml/filters.rb +3 -4
- data/lib/haml/generator.rb +36 -0
- data/lib/haml/helpers.rb +61 -48
- data/lib/haml/helpers/action_view_extensions.rb +1 -1
- data/lib/haml/helpers/action_view_mods.rb +32 -50
- data/lib/haml/helpers/safe_erubi_template.rb +26 -0
- data/lib/haml/helpers/safe_erubis_template.rb +2 -0
- data/lib/haml/helpers/xss_mods.rb +17 -12
- data/lib/haml/options.rb +32 -36
- data/lib/haml/parser.rb +61 -38
- data/lib/haml/{template/plugin.rb → plugin.rb} +5 -2
- data/lib/haml/railtie.rb +14 -6
- data/lib/haml/template.rb +11 -6
- data/lib/haml/temple_engine.rb +119 -0
- data/lib/haml/temple_line_counter.rb +28 -0
- data/lib/haml/util.rb +17 -112
- data/lib/haml/version.rb +1 -1
- data/test/attribute_parser_test.rb +105 -0
- data/test/engine_test.rb +202 -106
- data/test/filters_test.rb +32 -19
- data/test/gemfiles/Gemfile.rails-4.0.x +7 -1
- data/test/gemfiles/Gemfile.rails-4.0.x.lock +57 -71
- 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 +156 -109
- data/test/options_test.rb +21 -0
- data/test/parser_test.rb +49 -4
- 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 +77 -76
- data/test/template_test.rb +21 -48
- data/test/template_test_helper.rb +38 -0
- data/test/templates/just_stuff.haml +1 -0
- data/test/templates/standard_ugly.haml +1 -0
- data/test/temple_line_counter_test.rb +40 -0
- data/test/test_helper.rb +10 -10
- data/test/util_test.rb +1 -48
- metadata +49 -35
- data/lib/haml/temple.rb +0 -85
- data/test/gemfiles/Gemfile.rails-3.2.x +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
@@ -45,7 +45,7 @@ module Haml
|
|
45
45
|
# @yield A block in which all input to `#haml_concat` is treated as raw.
|
46
46
|
# @see Haml::Util#rails_xss_safe?
|
47
47
|
def with_raw_haml_concat
|
48
|
-
old = instance_variable_defined?(
|
48
|
+
old = instance_variable_defined?(:@_haml_concat_raw) ? @_haml_concat_raw : false
|
49
49
|
@_haml_concat_raw = true
|
50
50
|
yield
|
51
51
|
ensure
|
@@ -1,40 +1,39 @@
|
|
1
|
-
module
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
1
|
+
module Haml
|
2
|
+
module Helpers
|
3
|
+
module ActionViewMods
|
4
|
+
def render(*args, &block)
|
5
|
+
options = args.first
|
6
|
+
|
7
|
+
# If render :layout is used with a block, it concats rather than returning
|
8
|
+
# a string so we need it to keep thinking it's Haml until it hits the
|
9
|
+
# sub-render.
|
10
|
+
if is_haml? && !(options.is_a?(Hash) && options[:layout] && block_given?)
|
11
|
+
return non_haml { super }
|
12
|
+
end
|
13
|
+
super
|
11
14
|
end
|
12
|
-
render_without_haml(*args, &block)
|
13
|
-
end
|
14
|
-
alias_method :render_without_haml, :render
|
15
|
-
alias_method :render, :render_with_haml
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
alias_method :output_buffer_without_haml, :output_buffer
|
22
|
-
alias_method :output_buffer, :output_buffer_with_haml
|
16
|
+
def output_buffer
|
17
|
+
return haml_buffer.buffer if is_haml?
|
18
|
+
super
|
19
|
+
end
|
23
20
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
def output_buffer=(new_buffer)
|
22
|
+
if is_haml?
|
23
|
+
if Haml::Util.rails_xss_safe? && new_buffer.is_a?(ActiveSupport::SafeBuffer)
|
24
|
+
new_buffer = String.new(new_buffer)
|
25
|
+
end
|
26
|
+
haml_buffer.buffer = new_buffer
|
27
|
+
else
|
28
|
+
super
|
28
29
|
end
|
29
|
-
haml_buffer.buffer = new_buffer
|
30
|
-
else
|
31
|
-
set_output_buffer_without_haml new_buffer
|
32
30
|
end
|
33
31
|
end
|
34
|
-
|
35
|
-
alias_method :output_buffer=, :set_output_buffer_with_haml
|
32
|
+
ActionView::Base.send(:prepend, ActionViewMods)
|
36
33
|
end
|
34
|
+
end
|
37
35
|
|
36
|
+
module ActionView
|
38
37
|
module Helpers
|
39
38
|
module CaptureHelper
|
40
39
|
def capture_with_haml(*args, &block)
|
@@ -82,11 +81,9 @@ module ActionView
|
|
82
81
|
end
|
83
82
|
end
|
84
83
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
include HamlSupport
|
89
|
-
end
|
84
|
+
module Tags
|
85
|
+
class TextArea
|
86
|
+
include HamlSupport
|
90
87
|
end
|
91
88
|
end
|
92
89
|
|
@@ -113,7 +110,7 @@ module ActionView
|
|
113
110
|
with_tabs(1) {oldproc.call(*args)}
|
114
111
|
end
|
115
112
|
end
|
116
|
-
res = form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc)
|
113
|
+
res = form_tag_without_haml(url_for_options, options, *parameters_for_url, &proc) << "\n"
|
117
114
|
res << "\n" if wrap_block
|
118
115
|
res
|
119
116
|
else
|
@@ -123,20 +120,5 @@ module ActionView
|
|
123
120
|
alias_method :form_tag_without_haml, :form_tag
|
124
121
|
alias_method :form_tag, :form_tag_with_haml
|
125
122
|
end
|
126
|
-
|
127
|
-
module FormHelper
|
128
|
-
def form_for_with_haml(object_name, *args, &proc)
|
129
|
-
wrap_block = block_given? && is_haml? && block_is_haml?(proc)
|
130
|
-
if wrap_block
|
131
|
-
oldproc = proc
|
132
|
-
proc = proc {|*subargs| with_tabs(1) {oldproc.call(*subargs)}}
|
133
|
-
end
|
134
|
-
res = form_for_without_haml(object_name, *args, &proc)
|
135
|
-
res << "\n" if wrap_block
|
136
|
-
res
|
137
|
-
end
|
138
|
-
alias_method :form_for_without_haml, :form_for
|
139
|
-
alias_method :form_for, :form_for_with_haml
|
140
|
-
end
|
141
123
|
end
|
142
124
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'action_view'
|
2
|
+
|
3
|
+
module Haml
|
4
|
+
class ErubiTemplateHandler < ActionView::Template::Handlers::ERB::Erubi
|
5
|
+
|
6
|
+
def initialize(*args, &blk)
|
7
|
+
@newline_pending = 0
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class SafeErubiTemplate < Tilt::ErubiTemplate
|
13
|
+
def prepare
|
14
|
+
@options.merge! engine_class: Haml::ErubiTemplateHandler
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def precompiled_preamble(locals)
|
19
|
+
[super, "@output_buffer = ActionView::OutputBuffer.new;"].join("\n")
|
20
|
+
end
|
21
|
+
|
22
|
+
def precompiled_postamble(locals)
|
23
|
+
[super, '@output_buffer.to_s'].join("\n")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -7,8 +7,8 @@ module Haml
|
|
7
7
|
module XssMods
|
8
8
|
def self.included(base)
|
9
9
|
%w[html_escape find_and_preserve preserve list_of surround
|
10
|
-
precede succeed capture_haml haml_concat haml_indent
|
11
|
-
|
10
|
+
precede succeed capture_haml haml_concat haml_internal_concat haml_indent
|
11
|
+
escape_once].each do |name|
|
12
12
|
base.send(:alias_method, "#{name}_without_haml_xss", name)
|
13
13
|
base.send(:alias_method, name, "#{name}_with_haml_xss")
|
14
14
|
end
|
@@ -61,24 +61,29 @@ module Haml
|
|
61
61
|
Haml::Util.html_safe(capture_haml_without_haml_xss(*args, &block))
|
62
62
|
end
|
63
63
|
|
64
|
-
# Input is
|
64
|
+
# Input will be escaped unless this is in a `with_raw_haml_concat`
|
65
|
+
# block. See #Haml::Helpers::ActionViewExtensions#with_raw_haml_concat.
|
65
66
|
def haml_concat_with_haml_xss(text = "")
|
66
|
-
raw = instance_variable_defined?(
|
67
|
-
|
67
|
+
raw = instance_variable_defined?(:@_haml_concat_raw) ? @_haml_concat_raw : false
|
68
|
+
if raw
|
69
|
+
haml_internal_concat_raw text
|
70
|
+
else
|
71
|
+
haml_internal_concat text
|
72
|
+
end
|
73
|
+
ErrorReturn.new("haml_concat")
|
68
74
|
end
|
69
75
|
|
76
|
+
# Input is escaped
|
77
|
+
def haml_internal_concat_with_haml_xss(text="", newline=true, indent=true)
|
78
|
+
haml_internal_concat_without_haml_xss(haml_xss_html_escape(text), newline, indent)
|
79
|
+
end
|
80
|
+
private :haml_internal_concat_with_haml_xss
|
81
|
+
|
70
82
|
# Output is always HTML safe
|
71
83
|
def haml_indent_with_haml_xss
|
72
84
|
Haml::Util.html_safe(haml_indent_without_haml_xss)
|
73
85
|
end
|
74
86
|
|
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
87
|
# Output is always HTML safe
|
83
88
|
def escape_once_with_haml_xss(*args)
|
84
89
|
Haml::Util.html_safe(escape_once_without_haml_xss(*args))
|
data/lib/haml/options.rb
CHANGED
@@ -4,37 +4,15 @@ module Haml
|
|
4
4
|
# learn how to set the options.
|
5
5
|
class Options
|
6
6
|
|
7
|
-
@defaults = {
|
8
|
-
:attr_wrapper => "'",
|
9
|
-
:autoclose => %w(area base basefont br col command embed frame
|
10
|
-
hr img input isindex keygen link menuitem meta
|
11
|
-
param source track wbr),
|
12
|
-
:encoding => "UTF-8",
|
13
|
-
:escape_attrs => true,
|
14
|
-
:escape_html => false,
|
15
|
-
:filename => '(haml)',
|
16
|
-
:format => :html5,
|
17
|
-
:hyphenate_data_attrs => true,
|
18
|
-
:line => 1,
|
19
|
-
:mime_type => 'text/html',
|
20
|
-
:preserve => %w(textarea pre code),
|
21
|
-
:remove_whitespace => false,
|
22
|
-
:suppress_eval => false,
|
23
|
-
:ugly => false,
|
24
|
-
:cdata => false,
|
25
|
-
:parser_class => ::Haml::Parser,
|
26
|
-
:compiler_class => ::Haml::Compiler
|
27
|
-
}
|
28
|
-
|
29
7
|
@valid_formats = [:html4, :html5, :xhtml]
|
30
8
|
|
31
|
-
@buffer_option_keys = [:autoclose, :preserve, :attr_wrapper, :
|
9
|
+
@buffer_option_keys = [:autoclose, :preserve, :attr_wrapper, :format,
|
32
10
|
:encoding, :escape_html, :escape_attrs, :hyphenate_data_attrs, :cdata]
|
33
11
|
|
34
12
|
# The default option values.
|
35
13
|
# @return Hash
|
36
14
|
def self.defaults
|
37
|
-
@defaults
|
15
|
+
@defaults ||= Haml::TempleEngine.options.to_hash.merge(encoding: 'UTF-8')
|
38
16
|
end
|
39
17
|
|
40
18
|
# An array of valid values for the `:format` option.
|
@@ -50,6 +28,22 @@ module Haml
|
|
50
28
|
@buffer_option_keys
|
51
29
|
end
|
52
30
|
|
31
|
+
# Returns a subset of defaults: those that {Haml::Buffer} cares about.
|
32
|
+
# @return [{Symbol => Object}] The options hash
|
33
|
+
def self.buffer_defaults
|
34
|
+
@buffer_defaults ||= buffer_option_keys.inject({}) do |hash, key|
|
35
|
+
hash.merge(key => defaults[key])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.wrap(options)
|
40
|
+
if options.is_a?(Options)
|
41
|
+
options
|
42
|
+
else
|
43
|
+
Options.new(options)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
53
47
|
# The character that should wrap element attributes. This defaults to `'`
|
54
48
|
# (an apostrophe). Characters of this type within the attributes will be
|
55
49
|
# escaped (e.g. by replacing them with `'`) if the character is an
|
@@ -145,13 +139,6 @@ module Haml
|
|
145
139
|
# Defaults to `false`.
|
146
140
|
attr_accessor :suppress_eval
|
147
141
|
|
148
|
-
# If set to `true`, Haml makes no attempt to properly indent or format the
|
149
|
-
# HTML output. This significantly improves rendering performance but makes
|
150
|
-
# viewing the source unpleasant.
|
151
|
-
#
|
152
|
-
# Defaults to `true` in Rails production mode, and `false` everywhere else.
|
153
|
-
attr_accessor :ugly
|
154
|
-
|
155
142
|
# Whether to include CDATA sections around javascript and css blocks when
|
156
143
|
# using the `:javascript` or `:css` filters.
|
157
144
|
#
|
@@ -168,6 +155,14 @@ module Haml
|
|
168
155
|
# The compiler class to use. Defaults to Haml::Compiler.
|
169
156
|
attr_accessor :compiler_class
|
170
157
|
|
158
|
+
# Enable template tracing. If true, it will add a 'data-trace' attribute to
|
159
|
+
# each tag generated by Haml. The value of the attribute will be the
|
160
|
+
# source template name and the line number from which the tag was generated,
|
161
|
+
# separated by a colon. On Rails applications, the path given will be a
|
162
|
+
# relative path as from the views directory. On non-Rails applications,
|
163
|
+
# the path will be the full path.
|
164
|
+
attr_accessor :trace
|
165
|
+
|
171
166
|
def initialize(values = {}, &block)
|
172
167
|
defaults.each {|k, v| instance_variable_set :"@#{k}", v}
|
173
168
|
values.each {|k, v| send("#{k}=", v) if defaults.has_key?(k) && !v.nil?}
|
@@ -187,8 +182,7 @@ module Haml
|
|
187
182
|
send "#{key}=", value
|
188
183
|
end
|
189
184
|
|
190
|
-
[:escape_attrs, :hyphenate_data_attrs, :remove_whitespace, :suppress_eval
|
191
|
-
:ugly].each do |method|
|
185
|
+
[:escape_attrs, :hyphenate_data_attrs, :remove_whitespace, :suppress_eval].each do |method|
|
192
186
|
class_eval(<<-END)
|
193
187
|
def #{method}?
|
194
188
|
!! @#{method}
|
@@ -240,7 +234,6 @@ module Haml
|
|
240
234
|
end
|
241
235
|
|
242
236
|
def remove_whitespace=(value)
|
243
|
-
@ugly = true if value
|
244
237
|
@remove_whitespace = value
|
245
238
|
end
|
246
239
|
|
@@ -250,7 +243,7 @@ module Haml
|
|
250
243
|
@encoding = "UTF-8" if @encoding.upcase == "US-ASCII"
|
251
244
|
end
|
252
245
|
|
253
|
-
# Returns a subset of options: those that {Haml::Buffer} cares about.
|
246
|
+
# Returns a non-default subset of options: those that {Haml::Buffer} cares about.
|
254
247
|
# All of the values here are such that when `#inspect` is called on the hash,
|
255
248
|
# it can be `Kernel#eval`ed to get the same result back.
|
256
249
|
#
|
@@ -259,7 +252,10 @@ module Haml
|
|
259
252
|
# @return [{Symbol => Object}] The options hash
|
260
253
|
def for_buffer
|
261
254
|
self.class.buffer_option_keys.inject({}) do |hash, key|
|
262
|
-
|
255
|
+
value = public_send(key)
|
256
|
+
if self.class.buffer_defaults[key] != value
|
257
|
+
hash[key] = value
|
258
|
+
end
|
263
259
|
hash
|
264
260
|
end
|
265
261
|
end
|
data/lib/haml/parser.rb
CHANGED
@@ -83,20 +83,21 @@ module Haml
|
|
83
83
|
DOCTYPE_REGEX = /(\d(?:\.\d)?)?\s*([a-z]*)\s*([^ ]+)?/i
|
84
84
|
|
85
85
|
# The Regex that matches a literal string or symbol value
|
86
|
-
LITERAL_VALUE_REGEX = /:(\w*)|(["'])((
|
86
|
+
LITERAL_VALUE_REGEX = /:(\w*)|(["'])((?!\\|\#\{|\#@|\#\$|\2).|\\.)*\2/
|
87
87
|
|
88
88
|
ID_KEY = 'id'.freeze
|
89
89
|
CLASS_KEY = 'class'.freeze
|
90
90
|
|
91
|
-
def initialize(
|
92
|
-
@options
|
93
|
-
@flat = false
|
91
|
+
def initialize(options)
|
92
|
+
@options = Options.wrap(options)
|
94
93
|
# Record the indent levels of "if" statements to validate the subsequent
|
95
94
|
# elsif and else statements are indented at the appropriate level.
|
96
95
|
@script_level_stack = []
|
97
96
|
@template_index = 0
|
98
97
|
@template_tabs = 0
|
98
|
+
end
|
99
99
|
|
100
|
+
def call(template)
|
100
101
|
match = template.rstrip.scan(/(([ \t]+)?(.*?))(?:\Z|\r\n|\r|\n)/m)
|
101
102
|
# discard the last match which is always blank
|
102
103
|
match.pop
|
@@ -105,11 +106,10 @@ module Haml
|
|
105
106
|
end
|
106
107
|
# Append special end-of-document marker
|
107
108
|
@template << Line.new(nil, '-#', '-#', @template.size, self, true)
|
108
|
-
end
|
109
109
|
|
110
|
-
def parse
|
111
110
|
@root = @parent = ParseNode.new(:root)
|
112
|
-
@
|
111
|
+
@flat = false
|
112
|
+
@filter_buffer = nil
|
113
113
|
@indentation = nil
|
114
114
|
@line = next_line
|
115
115
|
|
@@ -129,13 +129,13 @@ module Haml
|
|
129
129
|
end
|
130
130
|
|
131
131
|
@tab_up = nil
|
132
|
-
process_line(@line) unless @line.text.empty?
|
133
|
-
if
|
132
|
+
process_line(@line) unless @line.text.empty?
|
133
|
+
if block_opened? || @tab_up
|
134
134
|
@template_tabs += 1
|
135
135
|
@parent = @parent.children.last
|
136
136
|
end
|
137
137
|
|
138
|
-
if
|
138
|
+
if !flat? && @next_line.tabs - @line.tabs > 1
|
139
139
|
raise SyntaxError.new(Error.message(:deeper_indenting, @next_line.tabs - @line.tabs), @next_line.index)
|
140
140
|
end
|
141
141
|
|
@@ -200,7 +200,7 @@ module Haml
|
|
200
200
|
end
|
201
201
|
|
202
202
|
def inspect
|
203
|
-
%Q[(#{type} #{value.inspect}#{children.
|
203
|
+
%Q[(#{type} #{value.inspect}#{children.each_with_object('') {|c, s| s << "\n#{c.inspect.gsub!(/^/, ' ')}"}})]
|
204
204
|
end
|
205
205
|
end
|
206
206
|
|
@@ -209,7 +209,15 @@ module Haml
|
|
209
209
|
return unless line.tabs <= @template_tabs && @template_tabs > 0
|
210
210
|
|
211
211
|
to_close = @template_tabs - line.tabs
|
212
|
-
to_close.times {|i| close unless to_close - 1 - i == 0 &&
|
212
|
+
to_close.times {|i| close unless to_close - 1 - i == 0 && continuation_script?(line.text)}
|
213
|
+
end
|
214
|
+
|
215
|
+
def continuation_script?(text)
|
216
|
+
text[0] == SILENT_SCRIPT && mid_block_keyword?(text)
|
217
|
+
end
|
218
|
+
|
219
|
+
def mid_block_keyword?(text)
|
220
|
+
MID_BLOCK_KEYWORDS.include?(block_keyword(text))
|
213
221
|
end
|
214
222
|
|
215
223
|
# Processes a single line of Haml.
|
@@ -220,7 +228,7 @@ module Haml
|
|
220
228
|
case line.text[0]
|
221
229
|
when DIV_CLASS; push div(line)
|
222
230
|
when DIV_ID
|
223
|
-
return push plain(line) if line.text[1]
|
231
|
+
return push plain(line) if %w[{ @ $].include?(line.text[1])
|
224
232
|
push div(line)
|
225
233
|
when ELEMENT; push tag(line)
|
226
234
|
when COMMENT; push comment(line.text[1..-1].lstrip)
|
@@ -228,23 +236,27 @@ module Haml
|
|
228
236
|
return push plain(line.strip!(3), :escape_html) if line.text[1, 2] == '=='
|
229
237
|
return push script(line.strip!(2), :escape_html) if line.text[1] == SCRIPT
|
230
238
|
return push flat_script(line.strip!(2), :escape_html) if line.text[1] == FLAT_SCRIPT
|
231
|
-
return push plain(line.strip!(1), :escape_html) if line.text[1] == ?\s
|
239
|
+
return push plain(line.strip!(1), :escape_html) if line.text[1] == ?\s || line.text[1..2] == '#{'
|
232
240
|
push plain(line)
|
233
241
|
when SCRIPT
|
234
242
|
return push plain(line.strip!(2)) if line.text[1] == SCRIPT
|
235
243
|
line.text = line.text[1..-1]
|
236
244
|
push script(line)
|
237
245
|
when FLAT_SCRIPT; push flat_script(line.strip!(1))
|
238
|
-
when SILENT_SCRIPT
|
246
|
+
when SILENT_SCRIPT
|
247
|
+
return push haml_comment(line.text[2..-1]) if line.text[1] == SILENT_COMMENT
|
248
|
+
push silent_script(line)
|
239
249
|
when FILTER; push filter(line.text[1..-1].downcase)
|
240
250
|
when DOCTYPE
|
241
251
|
return push doctype(line.text) if line.text[0, 3] == '!!!'
|
242
252
|
return push plain(line.strip!(3), false) if line.text[1, 2] == '=='
|
243
253
|
return push script(line.strip!(2), false) if line.text[1] == SCRIPT
|
244
254
|
return push flat_script(line.strip!(2), false) if line.text[1] == FLAT_SCRIPT
|
245
|
-
return push plain(line.strip!(1), false) if line.text[1] == ?\s
|
255
|
+
return push plain(line.strip!(1), false) if line.text[1] == ?\s || line.text[1..2] == '#{'
|
256
|
+
push plain(line)
|
257
|
+
when ESCAPE
|
258
|
+
line.text = line.text[1..-1]
|
246
259
|
push plain(line)
|
247
|
-
when ESCAPE; push plain(line.strip!(1))
|
248
260
|
else; push plain(line)
|
249
261
|
end
|
250
262
|
end
|
@@ -254,10 +266,6 @@ module Haml
|
|
254
266
|
keyword[0] || keyword[1]
|
255
267
|
end
|
256
268
|
|
257
|
-
def mid_block_keyword?(text)
|
258
|
-
MID_BLOCK_KEYWORDS.include?(block_keyword(text))
|
259
|
-
end
|
260
|
-
|
261
269
|
def push(node)
|
262
270
|
@parent.children << node
|
263
271
|
node.parent = @parent
|
@@ -295,8 +303,6 @@ module Haml
|
|
295
303
|
end
|
296
304
|
|
297
305
|
def silent_script(line)
|
298
|
-
return haml_comment(line.text[2..-1]) if line.text[1] == SILENT_COMMENT
|
299
|
-
|
300
306
|
raise SyntaxError.new(Error.message(:no_end), line.index) if line.text[1..-1].strip == 'end'
|
301
307
|
|
302
308
|
line = handle_ruby_multiline(line)
|
@@ -337,7 +343,15 @@ module Haml
|
|
337
343
|
end
|
338
344
|
|
339
345
|
def haml_comment(text)
|
340
|
-
|
346
|
+
if filter_opened?
|
347
|
+
@flat = true
|
348
|
+
@filter_buffer = String.new
|
349
|
+
@filter_buffer << "#{text}\n" unless text.empty?
|
350
|
+
text = @filter_buffer
|
351
|
+
# If we don't know the indentation by now, it'll be set in Line#tabs
|
352
|
+
@flat_spaces = @indentation * (@template_tabs+1) if @indentation
|
353
|
+
end
|
354
|
+
|
341
355
|
ParseNode.new(:haml_comment, @line.index + 1, :text => text)
|
342
356
|
end
|
343
357
|
|
@@ -347,7 +361,6 @@ module Haml
|
|
347
361
|
|
348
362
|
preserve_tag = @options.preserve.include?(tag_name)
|
349
363
|
nuke_inner_whitespace ||= preserve_tag
|
350
|
-
preserve_tag = false if @options.ugly
|
351
364
|
escape_html = (action == '&' || (action != '!' && @options.escape_html))
|
352
365
|
|
353
366
|
case action
|
@@ -387,13 +400,13 @@ module Haml
|
|
387
400
|
|
388
401
|
if attributes_hashes[:new]
|
389
402
|
static_attributes, attributes_hash = attributes_hashes[:new]
|
390
|
-
|
403
|
+
AttributeBuilder.merge_attributes!(attributes, static_attributes) if static_attributes
|
391
404
|
attributes_list << attributes_hash
|
392
405
|
end
|
393
406
|
|
394
407
|
if attributes_hashes[:old]
|
395
408
|
static_attributes = parse_static_hash(attributes_hashes[:old])
|
396
|
-
|
409
|
+
AttributeBuilder.merge_attributes!(attributes, static_attributes) if static_attributes
|
397
410
|
attributes_list << attributes_hashes[:old] unless static_attributes || @options.suppress_eval
|
398
411
|
end
|
399
412
|
|
@@ -403,7 +416,7 @@ module Haml
|
|
403
416
|
raise SyntaxError.new(Error.message(:no_ruby_code, action), last_line - 1) if parse && value.empty?
|
404
417
|
raise SyntaxError.new(Error.message(:self_closing_content), last_line - 1) if self_closing && !value.empty?
|
405
418
|
|
406
|
-
if block_opened? && !value.empty? && !is_ruby_multiline?(
|
419
|
+
if block_opened? && !value.empty? && !is_ruby_multiline?(value)
|
407
420
|
raise SyntaxError.new(Error.message(:illegal_nesting_line, tag_name), @next_line.index)
|
408
421
|
end
|
409
422
|
|
@@ -439,11 +452,18 @@ module Haml
|
|
439
452
|
conditional, text = balance(text, ?[, ?]) if text[0] == ?[
|
440
453
|
text.strip!
|
441
454
|
|
455
|
+
if contains_interpolation?(text)
|
456
|
+
parse = true
|
457
|
+
text = unescape_interpolation(text)
|
458
|
+
else
|
459
|
+
parse = false
|
460
|
+
end
|
461
|
+
|
442
462
|
if block_opened? && !text.empty?
|
443
463
|
raise SyntaxError.new(Haml::Error.message(:illegal_nesting_content), @next_line.index)
|
444
464
|
end
|
445
465
|
|
446
|
-
ParseNode.new(:comment, @line.index + 1, :conditional => conditional, :text => text, :revealed => revealed)
|
466
|
+
ParseNode.new(:comment, @line.index + 1, :conditional => conditional, :text => text, :revealed => revealed, :parse => parse)
|
447
467
|
end
|
448
468
|
|
449
469
|
# Renders an XHTML doctype or XML shebang.
|
@@ -456,10 +476,9 @@ module Haml
|
|
456
476
|
def filter(name)
|
457
477
|
raise Error.new(Error.message(:invalid_filter_name, name)) unless name =~ /^\w+$/
|
458
478
|
|
459
|
-
@filter_buffer = String.new
|
460
|
-
|
461
479
|
if filter_opened?
|
462
480
|
@flat = true
|
481
|
+
@filter_buffer = String.new
|
463
482
|
# If we don't know the indentation by now, it'll be set in Line#tabs
|
464
483
|
@flat_spaces = @indentation * (@template_tabs+1) if @indentation
|
465
484
|
end
|
@@ -474,13 +493,17 @@ module Haml
|
|
474
493
|
end
|
475
494
|
|
476
495
|
def close_filter(_)
|
477
|
-
|
478
|
-
@flat_spaces = nil
|
479
|
-
@filter_buffer = nil
|
496
|
+
close_flat_section
|
480
497
|
end
|
481
498
|
|
482
499
|
def close_haml_comment(_)
|
483
|
-
|
500
|
+
close_flat_section
|
501
|
+
end
|
502
|
+
|
503
|
+
def close_flat_section
|
504
|
+
@flat = false
|
505
|
+
@flat_spaces = nil
|
506
|
+
@filter_buffer = nil
|
484
507
|
end
|
485
508
|
|
486
509
|
def close_silent_script(node)
|
@@ -681,7 +704,7 @@ module Haml
|
|
681
704
|
|
682
705
|
return name, [:static, content.first[1]] if content.size == 1
|
683
706
|
return name, [:dynamic,
|
684
|
-
%!"#{content.
|
707
|
+
%!"#{content.each_with_object('') {|(t, v), s| s << (t == :str ? inspect_obj(v)[1...-1] : "\#{#{v}}")}}"!]
|
685
708
|
end
|
686
709
|
|
687
710
|
def next_line
|
@@ -690,7 +713,7 @@ module Haml
|
|
690
713
|
# `flat?' here is a little outdated,
|
691
714
|
# so we have to manually check if either the previous or current line
|
692
715
|
# closes the flat block, as well as whether a new block is opened.
|
693
|
-
line_defined = instance_variable_defined?(
|
716
|
+
line_defined = instance_variable_defined?(:@line)
|
694
717
|
@line.tabs if line_defined
|
695
718
|
unless (flat? && !closes_flat?(line) && !closes_flat?(@line)) ||
|
696
719
|
(line_defined && @line.text[0] == ?: && line.full =~ %r[^#{@line.full[/^\s+/]}\s])
|
@@ -759,7 +782,7 @@ module Haml
|
|
759
782
|
# Same semantics as block_opened?, except that block_opened? uses Line#tabs,
|
760
783
|
# which doesn't interact well with filter lines
|
761
784
|
def filter_opened?
|
762
|
-
@next_line.full =~ (@indentation ? /^#{@indentation * @template_tabs}/ : /^\s/)
|
785
|
+
@next_line.full =~ (@indentation ? /^#{@indentation * (@template_tabs + 1)}/ : /^\s/)
|
763
786
|
end
|
764
787
|
|
765
788
|
def flat?
|