haml 5.2.2 → 6.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/workflows/test.yml +13 -14
- data/.gitignore +16 -16
- data/.yardopts +0 -3
- data/CHANGELOG.md +116 -3
- data/Gemfile +18 -11
- data/MIT-LICENSE +1 -1
- data/README.md +17 -23
- data/REFERENCE.md +69 -145
- data/Rakefile +48 -81
- data/bin/bench +66 -0
- data/bin/console +11 -0
- data/bin/ruby +3 -0
- data/bin/setup +7 -0
- data/bin/stackprof +27 -0
- data/bin/test +24 -0
- data/exe/haml +6 -0
- data/ext/haml/extconf.rb +10 -0
- data/ext/haml/haml.c +537 -0
- data/ext/haml/hescape.c +108 -0
- data/ext/haml/hescape.h +20 -0
- data/haml.gemspec +39 -37
- data/lib/haml/ambles.rb +20 -0
- data/lib/haml/attribute_builder.rb +134 -179
- data/lib/haml/attribute_compiler.rb +85 -194
- data/lib/haml/attribute_parser.rb +92 -126
- data/lib/haml/cli.rb +154 -0
- data/lib/haml/compiler/children_compiler.rb +155 -0
- data/lib/haml/compiler/comment_compiler.rb +51 -0
- data/lib/haml/compiler/doctype_compiler.rb +46 -0
- data/lib/haml/compiler/script_compiler.rb +114 -0
- data/lib/haml/compiler/silent_script_compiler.rb +24 -0
- data/lib/haml/compiler/tag_compiler.rb +76 -0
- data/lib/haml/compiler.rb +63 -296
- data/lib/haml/dynamic_merger.rb +67 -0
- data/lib/haml/engine.rb +48 -227
- data/lib/haml/error.rb +5 -4
- data/lib/haml/escape.rb +13 -0
- data/lib/haml/escape_any.rb +21 -0
- data/lib/haml/filters/base.rb +12 -0
- data/lib/haml/filters/cdata.rb +20 -0
- data/lib/haml/filters/coffee.rb +17 -0
- data/lib/haml/filters/css.rb +33 -0
- data/lib/haml/filters/erb.rb +10 -0
- data/lib/haml/filters/escaped.rb +22 -0
- data/lib/haml/filters/javascript.rb +33 -0
- data/lib/haml/filters/less.rb +20 -0
- data/lib/haml/filters/markdown.rb +11 -0
- data/lib/haml/filters/plain.rb +29 -0
- data/lib/haml/filters/preserve.rb +22 -0
- data/lib/haml/filters/ruby.rb +10 -0
- data/lib/haml/filters/sass.rb +15 -0
- data/lib/haml/filters/scss.rb +15 -0
- data/lib/haml/filters/text_base.rb +25 -0
- data/lib/haml/filters/tilt_base.rb +59 -0
- data/lib/haml/filters.rb +54 -378
- data/lib/haml/force_escape.rb +29 -0
- data/lib/haml/helpers.rb +3 -697
- data/lib/haml/html.rb +22 -0
- data/lib/haml/identity.rb +13 -0
- data/lib/haml/object_ref.rb +35 -0
- data/lib/haml/parser.rb +157 -22
- data/lib/haml/rails_helpers.rb +53 -0
- data/lib/haml/rails_template.rb +57 -0
- data/lib/haml/railtie.rb +3 -46
- data/lib/haml/ruby_expression.rb +32 -0
- data/lib/haml/string_splitter.rb +140 -0
- data/lib/haml/template.rb +15 -34
- data/lib/haml/temple_line_counter.rb +2 -1
- data/lib/haml/util.rb +18 -15
- data/lib/haml/version.rb +1 -2
- data/lib/haml/whitespace.rb +8 -0
- data/lib/haml.rb +8 -20
- metadata +211 -55
- data/.gitmodules +0 -3
- data/TODO +0 -24
- data/benchmark.rb +0 -70
- data/bin/haml +0 -9
- data/lib/haml/.gitattributes +0 -1
- data/lib/haml/buffer.rb +0 -182
- data/lib/haml/escapable.rb +0 -77
- data/lib/haml/exec.rb +0 -347
- data/lib/haml/generator.rb +0 -42
- data/lib/haml/helpers/action_view_extensions.rb +0 -60
- data/lib/haml/helpers/action_view_mods.rb +0 -132
- data/lib/haml/helpers/action_view_xss_mods.rb +0 -60
- data/lib/haml/helpers/safe_erubi_template.rb +0 -20
- data/lib/haml/helpers/safe_erubis_template.rb +0 -33
- data/lib/haml/helpers/xss_mods.rb +0 -114
- data/lib/haml/options.rb +0 -273
- data/lib/haml/plugin.rb +0 -54
- data/lib/haml/sass_rails_filter.rb +0 -47
- data/lib/haml/template/options.rb +0 -27
- data/lib/haml/temple_engine.rb +0 -124
- data/yard/default/.gitignore +0 -1
- data/yard/default/fulldoc/html/css/common.sass +0 -15
- data/yard/default/layout/html/footer.erb +0 -12
data/lib/haml/helpers.rb
CHANGED
@@ -1,709 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'erb'
|
4
|
-
|
5
2
|
module Haml
|
6
|
-
# This module contains various helpful methods to make it easier to do various tasks.
|
7
|
-
# {Haml::Helpers} is automatically included in the context
|
8
|
-
# that a Haml template is parsed in, so all these methods are at your
|
9
|
-
# disposal from within the template.
|
10
3
|
module Helpers
|
11
|
-
|
12
|
-
# It's used to raise an error when the return value of a helper is used
|
13
|
-
# when it shouldn't be.
|
14
|
-
class ErrorReturn
|
15
|
-
def initialize(method)
|
16
|
-
@message = <<MESSAGE
|
17
|
-
#{method} outputs directly to the Haml template.
|
18
|
-
Disregard its return value and use the - operator,
|
19
|
-
or use capture_haml to get the value as a String.
|
20
|
-
MESSAGE
|
21
|
-
end
|
22
|
-
|
23
|
-
# Raises an error.
|
24
|
-
#
|
25
|
-
# @raise [Haml::Error] The error
|
26
|
-
def to_s
|
27
|
-
raise Haml::Error.new(@message)
|
28
|
-
rescue Haml::Error => e
|
29
|
-
e.backtrace.shift
|
30
|
-
|
31
|
-
# If the ErrorReturn is used directly in the template,
|
32
|
-
# we don't want Haml's stuff to get into the backtrace,
|
33
|
-
# so we get rid of the format_script line.
|
34
|
-
#
|
35
|
-
# We also have to subtract one from the Haml line number
|
36
|
-
# since the value is passed to format_script the line after
|
37
|
-
# it's actually used.
|
38
|
-
if e.backtrace.first =~ /^\(eval\):\d+:in `format_script/
|
39
|
-
e.backtrace.shift
|
40
|
-
e.backtrace.first.gsub!(/^\(haml\):(\d+)/) {|s| "(haml):#{$1.to_i - 1}"}
|
41
|
-
end
|
42
|
-
raise e
|
43
|
-
end
|
44
|
-
|
45
|
-
# @return [String] A human-readable string representation
|
46
|
-
def inspect
|
47
|
-
"Haml::Helpers::ErrorReturn(#{@message.inspect})"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
self.extend self
|
52
|
-
|
53
|
-
@@action_view_defined = false
|
54
|
-
|
55
|
-
# @return [Boolean] Whether or not ActionView is loaded
|
56
|
-
def self.action_view?
|
57
|
-
@@action_view_defined
|
58
|
-
end
|
59
|
-
|
60
|
-
# Note: this does **not** need to be called when using Haml helpers
|
61
|
-
# normally in Rails.
|
62
|
-
#
|
63
|
-
# Initializes the current object as though it were in the same context
|
64
|
-
# as a normal ActionView instance using Haml.
|
65
|
-
# This is useful if you want to use the helpers in a context
|
66
|
-
# other than the normal setup with ActionView.
|
67
|
-
# For example:
|
68
|
-
#
|
69
|
-
# context = Object.new
|
70
|
-
# class << context
|
71
|
-
# include Haml::Helpers
|
72
|
-
# end
|
73
|
-
# context.init_haml_helpers
|
74
|
-
# context.haml_tag :p, "Stuff"
|
75
|
-
#
|
76
|
-
def init_haml_helpers
|
77
|
-
@haml_buffer = Haml::Buffer.new(haml_buffer, Options.new.for_buffer)
|
78
|
-
nil
|
79
|
-
end
|
80
|
-
|
81
|
-
# Runs a block of code in a non-Haml context
|
82
|
-
# (i.e. \{#is\_haml?} will return false).
|
83
|
-
#
|
84
|
-
# This is mainly useful for rendering sub-templates such as partials in a non-Haml language,
|
85
|
-
# particularly where helpers may behave differently when run from Haml.
|
86
|
-
#
|
87
|
-
# Note that this is automatically applied to Rails partials.
|
88
|
-
#
|
89
|
-
# @yield A block which won't register as Haml
|
90
|
-
def non_haml
|
91
|
-
was_active = @haml_buffer.active?
|
92
|
-
@haml_buffer.active = false
|
93
|
-
yield
|
94
|
-
ensure
|
95
|
-
@haml_buffer.active = was_active
|
96
|
-
end
|
97
|
-
|
98
|
-
# Uses \{#preserve} to convert any newlines inside whitespace-sensitive tags
|
99
|
-
# into the HTML entities for endlines.
|
100
|
-
#
|
101
|
-
# @param tags [Array<String>] Tags that should have newlines escaped
|
102
|
-
#
|
103
|
-
# @overload find_and_preserve(input, tags = haml_buffer.options[:preserve])
|
104
|
-
# Escapes newlines within a string.
|
105
|
-
#
|
106
|
-
# @param input [String] The string within which to escape newlines
|
107
|
-
# @overload find_and_preserve(tags = haml_buffer.options[:preserve])
|
108
|
-
# Escapes newlines within a block of Haml code.
|
109
|
-
#
|
110
|
-
# @yield The block within which to escape newlines
|
111
|
-
def find_and_preserve(input = nil, tags = haml_buffer.options[:preserve], &block)
|
112
|
-
return find_and_preserve(capture_haml(&block), input || tags) if block
|
113
|
-
tags = tags.map { |tag| Regexp.escape(tag) }.join('|')
|
114
|
-
re = /<(#{tags})([^>]*)>(.*?)(<\/\1>)/im
|
115
|
-
input.to_s.gsub(re) do |s|
|
116
|
-
s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
|
117
|
-
"<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
# Takes any string, finds all the newlines, and converts them to
|
122
|
-
# HTML entities so they'll render correctly in
|
123
|
-
# whitespace-sensitive tags without screwing up the indentation.
|
124
|
-
#
|
125
|
-
# @overload preserve(input)
|
126
|
-
# Escapes newlines within a string.
|
127
|
-
#
|
128
|
-
# @param input [String] The string within which to escape all newlines
|
129
|
-
# @overload preserve
|
130
|
-
# Escapes newlines within a block of Haml code.
|
131
|
-
#
|
132
|
-
# @yield The block within which to escape newlines
|
133
|
-
def preserve(input = nil, &block)
|
134
|
-
return preserve(capture_haml(&block)) if block
|
4
|
+
def self.preserve(input)
|
135
5
|
s = input.to_s.chomp("\n")
|
136
6
|
s.gsub!(/\n/, '
')
|
137
7
|
s.delete!("\r")
|
138
8
|
s
|
139
9
|
end
|
140
|
-
alias_method :flatten, :preserve
|
141
|
-
|
142
|
-
# Takes an `Enumerable` object and a block
|
143
|
-
# and iterates over the enum,
|
144
|
-
# yielding each element to a Haml block
|
145
|
-
# and putting the result into `<li>` elements.
|
146
|
-
# This creates a list of the results of the block.
|
147
|
-
# For example:
|
148
|
-
#
|
149
|
-
# = list_of([['hello'], ['yall']]) do |i|
|
150
|
-
# = i[0]
|
151
|
-
#
|
152
|
-
# Produces:
|
153
|
-
#
|
154
|
-
# <li>hello</li>
|
155
|
-
# <li>yall</li>
|
156
|
-
#
|
157
|
-
# And:
|
158
|
-
#
|
159
|
-
# = list_of({:title => 'All the stuff', :description => 'A book about all the stuff.'}) do |key, val|
|
160
|
-
# %h3= key.humanize
|
161
|
-
# %p= val
|
162
|
-
#
|
163
|
-
# Produces:
|
164
|
-
#
|
165
|
-
# <li>
|
166
|
-
# <h3>Title</h3>
|
167
|
-
# <p>All the stuff</p>
|
168
|
-
# </li>
|
169
|
-
# <li>
|
170
|
-
# <h3>Description</h3>
|
171
|
-
# <p>A book about all the stuff.</p>
|
172
|
-
# </li>
|
173
|
-
#
|
174
|
-
# While:
|
175
|
-
#
|
176
|
-
# = list_of(["Home", "About", "Contact", "FAQ"], {class: "nav", role: "nav"}) do |item|
|
177
|
-
# %a{ href="#" }= item
|
178
|
-
#
|
179
|
-
# Produces:
|
180
|
-
#
|
181
|
-
# <li class='nav' role='nav'>
|
182
|
-
# <a href='#'>Home</a>
|
183
|
-
# </li>
|
184
|
-
# <li class='nav' role='nav'>
|
185
|
-
# <a href='#'>About</a>
|
186
|
-
# </li>
|
187
|
-
# <li class='nav' role='nav'>
|
188
|
-
# <a href='#'>Contact</a>
|
189
|
-
# </li>
|
190
|
-
# <li class='nav' role='nav'>
|
191
|
-
# <a href='#'>FAQ</a>
|
192
|
-
# </li>
|
193
|
-
#
|
194
|
-
# `[[class", "nav"], [role", "nav"]]` could have been used instead of `{class: "nav", role: "nav"}` (or any enumerable collection where each pair of items responds to #to_s)
|
195
|
-
#
|
196
|
-
# @param enum [Enumerable] The list of objects to iterate over
|
197
|
-
# @param [Enumerable<#to_s,#to_s>] opts Each key/value pair will become an attribute pair for each list item element.
|
198
|
-
# @yield [item] A block which contains Haml code that goes within list items
|
199
|
-
# @yieldparam item An element of `enum`
|
200
|
-
def list_of(enum, opts={}, &block)
|
201
|
-
opts_attributes = opts.map { |k, v| " #{k}='#{v}'" }.join
|
202
|
-
enum.map do |i|
|
203
|
-
result = capture_haml(i, &block)
|
204
|
-
|
205
|
-
if result.count("\n") > 1
|
206
|
-
result.gsub!("\n", "\n ")
|
207
|
-
result = "\n #{result.strip}\n"
|
208
|
-
else
|
209
|
-
result.strip!
|
210
|
-
end
|
211
|
-
|
212
|
-
%Q!<li#{opts_attributes}>#{result}</li>!
|
213
|
-
end.join("\n")
|
214
|
-
end
|
215
|
-
|
216
|
-
# Returns a hash containing default assignments for the `xmlns`, `lang`, and `xml:lang`
|
217
|
-
# attributes of the `html` HTML element.
|
218
|
-
# For example,
|
219
|
-
#
|
220
|
-
# %html{html_attrs}
|
221
|
-
#
|
222
|
-
# becomes
|
223
|
-
#
|
224
|
-
# <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en-US' lang='en-US'>
|
225
|
-
#
|
226
|
-
# @param lang [String] The value of `xml:lang` and `lang`
|
227
|
-
# @return [{#to_s => String}] The attribute hash
|
228
|
-
def html_attrs(lang = 'en-US')
|
229
|
-
if haml_buffer.options[:format] == :xhtml
|
230
|
-
{:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang}
|
231
|
-
else
|
232
|
-
{:lang => lang}
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
# Increments the number of tabs the buffer automatically adds
|
237
|
-
# to the lines of the template.
|
238
|
-
# For example:
|
239
|
-
#
|
240
|
-
# %h1 foo
|
241
|
-
# - tab_up
|
242
|
-
# %p bar
|
243
|
-
# - tab_down
|
244
|
-
# %strong baz
|
245
|
-
#
|
246
|
-
# Produces:
|
247
|
-
#
|
248
|
-
# <h1>foo</h1>
|
249
|
-
# <p>bar</p>
|
250
|
-
# <strong>baz</strong>
|
251
|
-
#
|
252
|
-
# @param i [Fixnum] The number of tabs by which to increase the indentation
|
253
|
-
# @see #tab_down
|
254
|
-
def tab_up(i = 1)
|
255
|
-
haml_buffer.tabulation += i
|
256
|
-
end
|
257
|
-
|
258
|
-
# Decrements the number of tabs the buffer automatically adds
|
259
|
-
# to the lines of the template.
|
260
|
-
#
|
261
|
-
# @param i [Fixnum] The number of tabs by which to decrease the indentation
|
262
|
-
# @see #tab_up
|
263
|
-
def tab_down(i = 1)
|
264
|
-
haml_buffer.tabulation -= i
|
265
|
-
end
|
266
|
-
|
267
|
-
# Sets the number of tabs the buffer automatically adds
|
268
|
-
# to the lines of the template,
|
269
|
-
# but only for the duration of the block.
|
270
|
-
# For example:
|
271
|
-
#
|
272
|
-
# %h1 foo
|
273
|
-
# - with_tabs(2) do
|
274
|
-
# %p bar
|
275
|
-
# %strong baz
|
276
|
-
#
|
277
|
-
# Produces:
|
278
|
-
#
|
279
|
-
# <h1>foo</h1>
|
280
|
-
# <p>bar</p>
|
281
|
-
# <strong>baz</strong>
|
282
|
-
#
|
283
|
-
#
|
284
|
-
# @param i [Fixnum] The number of tabs to use
|
285
|
-
# @yield A block in which the indentation will be `i` spaces
|
286
|
-
def with_tabs(i)
|
287
|
-
old_tabs = haml_buffer.tabulation
|
288
|
-
haml_buffer.tabulation = i
|
289
|
-
yield
|
290
|
-
ensure
|
291
|
-
haml_buffer.tabulation = old_tabs
|
292
|
-
end
|
293
|
-
|
294
|
-
# Surrounds a block of Haml code with strings,
|
295
|
-
# with no whitespace in between.
|
296
|
-
# For example:
|
297
|
-
#
|
298
|
-
# = surround '(', ')' do
|
299
|
-
# %a{:href => "food"} chicken
|
300
|
-
#
|
301
|
-
# Produces:
|
302
|
-
#
|
303
|
-
# (<a href='food'>chicken</a>)
|
304
|
-
#
|
305
|
-
# and
|
306
|
-
#
|
307
|
-
# = surround '*' do
|
308
|
-
# %strong angry
|
309
|
-
#
|
310
|
-
# Produces:
|
311
|
-
#
|
312
|
-
# *<strong>angry</strong>*
|
313
|
-
#
|
314
|
-
# @param front [String] The string to add before the Haml
|
315
|
-
# @param back [String] The string to add after the Haml
|
316
|
-
# @yield A block of Haml to surround
|
317
|
-
def surround(front, back = front, &block)
|
318
|
-
output = capture_haml(&block)
|
319
|
-
|
320
|
-
"#{front}#{output.chomp}#{back}\n"
|
321
|
-
end
|
322
|
-
|
323
|
-
# Prepends a string to the beginning of a Haml block,
|
324
|
-
# with no whitespace between.
|
325
|
-
# For example:
|
326
|
-
#
|
327
|
-
# = precede '*' do
|
328
|
-
# %span.small Not really
|
329
|
-
#
|
330
|
-
# Produces:
|
331
|
-
#
|
332
|
-
# *<span class='small'>Not really</span>
|
333
|
-
#
|
334
|
-
# @param str [String] The string to add before the Haml
|
335
|
-
# @yield A block of Haml to prepend to
|
336
|
-
def precede(str, &block)
|
337
|
-
"#{str}#{capture_haml(&block).chomp}\n"
|
338
|
-
end
|
339
|
-
|
340
|
-
# Appends a string to the end of a Haml block,
|
341
|
-
# with no whitespace between.
|
342
|
-
# For example:
|
343
|
-
#
|
344
|
-
# click
|
345
|
-
# = succeed '.' do
|
346
|
-
# %a{:href=>"thing"} here
|
347
|
-
#
|
348
|
-
# Produces:
|
349
|
-
#
|
350
|
-
# click
|
351
|
-
# <a href='thing'>here</a>.
|
352
|
-
#
|
353
|
-
# @param str [String] The string to add after the Haml
|
354
|
-
# @yield A block of Haml to append to
|
355
|
-
def succeed(str, &block)
|
356
|
-
"#{capture_haml(&block).chomp}#{str}\n"
|
357
|
-
end
|
358
|
-
|
359
|
-
# Captures the result of a block of Haml code,
|
360
|
-
# gets rid of the excess indentation,
|
361
|
-
# and returns it as a string.
|
362
|
-
# For example, after the following,
|
363
|
-
#
|
364
|
-
# .foo
|
365
|
-
# - foo = capture_haml(13) do |a|
|
366
|
-
# %p= a
|
367
|
-
#
|
368
|
-
# the local variable `foo` would be assigned to `"<p>13</p>\n"`.
|
369
|
-
#
|
370
|
-
# @param args [Array] Arguments to pass into the block
|
371
|
-
# @yield [args] A block of Haml code that will be converted to a string
|
372
|
-
# @yieldparam args [Array] `args`
|
373
|
-
def capture_haml(*args, &block)
|
374
|
-
buffer = eval('if defined? _hamlout then _hamlout else nil end', block.binding) || haml_buffer
|
375
|
-
with_haml_buffer(buffer) do
|
376
|
-
position = haml_buffer.buffer.length
|
377
|
-
|
378
|
-
haml_buffer.capture_position = position
|
379
|
-
value = block.call(*args)
|
380
|
-
|
381
|
-
captured = haml_buffer.buffer.slice!(position..-1)
|
382
|
-
|
383
|
-
if captured == '' and value != haml_buffer.buffer
|
384
|
-
captured = (value.is_a?(String) ? value : nil)
|
385
|
-
end
|
386
|
-
|
387
|
-
captured
|
388
|
-
end
|
389
|
-
ensure
|
390
|
-
haml_buffer.capture_position = nil
|
391
|
-
end
|
392
|
-
|
393
|
-
# Outputs text directly to the Haml buffer, with the proper indentation.
|
394
|
-
#
|
395
|
-
# @param text [#to_s] The text to output
|
396
|
-
def haml_concat(text = "")
|
397
|
-
haml_internal_concat text
|
398
|
-
ErrorReturn.new("haml_concat")
|
399
|
-
end
|
400
|
-
|
401
|
-
# Internal method to write directly to the buffer with control of
|
402
|
-
# whether the first line should be indented, and if there should be a
|
403
|
-
# final newline.
|
404
|
-
#
|
405
|
-
# Lines added will have the proper indentation. This can be controlled
|
406
|
-
# for the first line.
|
407
|
-
#
|
408
|
-
# Used by #haml_concat and #haml_tag.
|
409
|
-
#
|
410
|
-
# @param text [#to_s] The text to output
|
411
|
-
# @param newline [Boolean] Whether to add a newline after the text
|
412
|
-
# @param indent [Boolean] Whether to add indentation to the first line
|
413
|
-
def haml_internal_concat(text = "", newline = true, indent = true)
|
414
|
-
if haml_buffer.tabulation == 0
|
415
|
-
haml_buffer.buffer << "#{text}#{"\n" if newline}"
|
416
|
-
else
|
417
|
-
haml_buffer.buffer << %[#{haml_indent if indent}#{text.to_s.gsub("\n", "\n#{haml_indent}")}#{"\n" if newline}]
|
418
|
-
end
|
419
|
-
end
|
420
|
-
private :haml_internal_concat
|
421
|
-
|
422
|
-
# Allows writing raw content. `haml_internal_concat_raw` isn't
|
423
|
-
# effected by XSS mods. Used by #haml_tag to write the actual tags.
|
424
|
-
alias :haml_internal_concat_raw :haml_internal_concat
|
425
|
-
|
426
|
-
# @return [String] The indentation string for the current line
|
427
|
-
def haml_indent
|
428
|
-
' ' * haml_buffer.tabulation
|
429
|
-
end
|
430
|
-
|
431
|
-
# Creates an HTML tag with the given name and optionally text and attributes.
|
432
|
-
# Can take a block that will run between the opening and closing tags.
|
433
|
-
# If the block is a Haml block or outputs text using \{#haml\_concat},
|
434
|
-
# the text will be properly indented.
|
435
|
-
#
|
436
|
-
# `name` can be a string using the standard Haml class/id shorthand
|
437
|
-
# (e.g. "span#foo.bar", "#foo").
|
438
|
-
# Just like standard Haml tags, these class and id values
|
439
|
-
# will be merged with manually-specified attributes.
|
440
|
-
#
|
441
|
-
# `flags` is a list of symbol flags
|
442
|
-
# like those that can be put at the end of a Haml tag
|
443
|
-
# (`:/`, `:<`, and `:>`).
|
444
|
-
# Currently, only `:/` and `:<` are supported.
|
445
|
-
#
|
446
|
-
# `haml_tag` outputs directly to the buffer;
|
447
|
-
# its return value should not be used.
|
448
|
-
# If you need to get the results as a string,
|
449
|
-
# use \{#capture\_haml\}.
|
450
|
-
#
|
451
|
-
# For example,
|
452
|
-
#
|
453
|
-
# haml_tag :table do
|
454
|
-
# haml_tag :tr do
|
455
|
-
# haml_tag 'td.cell' do
|
456
|
-
# haml_tag :strong, "strong!"
|
457
|
-
# haml_concat "data"
|
458
|
-
# end
|
459
|
-
# haml_tag :td do
|
460
|
-
# haml_concat "more_data"
|
461
|
-
# end
|
462
|
-
# end
|
463
|
-
# end
|
464
|
-
#
|
465
|
-
# outputs
|
466
|
-
#
|
467
|
-
# <table>
|
468
|
-
# <tr>
|
469
|
-
# <td class='cell'>
|
470
|
-
# <strong>
|
471
|
-
# strong!
|
472
|
-
# </strong>
|
473
|
-
# data
|
474
|
-
# </td>
|
475
|
-
# <td>
|
476
|
-
# more_data
|
477
|
-
# </td>
|
478
|
-
# </tr>
|
479
|
-
# </table>
|
480
|
-
#
|
481
|
-
# @param name [#to_s] The name of the tag
|
482
|
-
#
|
483
|
-
# @overload haml_tag(name, *rest, attributes = {})
|
484
|
-
# @yield The block of Haml code within the tag
|
485
|
-
# @overload haml_tag(name, text, *flags, attributes = {})
|
486
|
-
# @param text [#to_s] The text within the tag
|
487
|
-
# @param flags [Array<Symbol>] Haml end-of-tag flags
|
488
|
-
def haml_tag(name, *rest, &block)
|
489
|
-
ret = ErrorReturn.new("haml_tag")
|
490
|
-
|
491
|
-
text = rest.shift.to_s unless [Symbol, Hash, NilClass].any? {|t| rest.first.is_a? t}
|
492
|
-
flags = []
|
493
|
-
flags << rest.shift while rest.first.is_a? Symbol
|
494
|
-
attrs = (rest.shift || {})
|
495
|
-
attrs.keys.each {|key| attrs[key.to_s] = attrs.delete(key)} unless attrs.empty?
|
496
|
-
name, attrs = merge_name_and_attributes(name.to_s, attrs)
|
497
|
-
|
498
|
-
attributes = Haml::AttributeBuilder.build_attributes(haml_buffer.html?,
|
499
|
-
haml_buffer.options[:attr_wrapper],
|
500
|
-
haml_buffer.options[:escape_attrs],
|
501
|
-
haml_buffer.options[:hyphenate_data_attrs],
|
502
|
-
attrs)
|
503
|
-
|
504
|
-
if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
|
505
|
-
haml_internal_concat_raw "<#{name}#{attributes}#{' /' if haml_buffer.options[:format] == :xhtml}>"
|
506
|
-
return ret
|
507
|
-
end
|
508
|
-
|
509
|
-
if flags.include?(:/)
|
510
|
-
raise Error.new(Error.message(:self_closing_content)) if text
|
511
|
-
raise Error.new(Error.message(:illegal_nesting_self_closing)) if block
|
512
|
-
end
|
513
|
-
|
514
|
-
tag = "<#{name}#{attributes}>"
|
515
|
-
end_tag = "</#{name}>"
|
516
|
-
if block.nil?
|
517
|
-
text = text.to_s
|
518
|
-
if text.include?("\n")
|
519
|
-
haml_internal_concat_raw tag
|
520
|
-
tab_up
|
521
|
-
haml_internal_concat text
|
522
|
-
tab_down
|
523
|
-
haml_internal_concat_raw end_tag
|
524
|
-
else
|
525
|
-
haml_internal_concat_raw tag, false
|
526
|
-
haml_internal_concat text, false, false
|
527
|
-
haml_internal_concat_raw end_tag, true, false
|
528
|
-
end
|
529
|
-
return ret
|
530
|
-
end
|
531
|
-
|
532
|
-
if text
|
533
|
-
raise Error.new(Error.message(:illegal_nesting_line, name))
|
534
|
-
end
|
535
|
-
|
536
|
-
if flags.include?(:<)
|
537
|
-
haml_internal_concat_raw tag, false
|
538
|
-
haml_internal_concat "#{capture_haml(&block).strip}", false, false
|
539
|
-
haml_internal_concat_raw end_tag, true, false
|
540
|
-
return ret
|
541
|
-
end
|
542
|
-
|
543
|
-
haml_internal_concat_raw tag
|
544
|
-
tab_up
|
545
|
-
block.call
|
546
|
-
tab_down
|
547
|
-
haml_internal_concat_raw end_tag
|
548
|
-
|
549
|
-
ret
|
550
|
-
end
|
551
10
|
|
552
|
-
|
553
|
-
|
554
|
-
# \{#haml_tag}) with the given block inside, otherwise it just renders the block.
|
555
|
-
#
|
556
|
-
# For example,
|
557
|
-
#
|
558
|
-
# - haml_tag_if important, '.important' do
|
559
|
-
# %p
|
560
|
-
# A (possibly) important paragraph.
|
561
|
-
#
|
562
|
-
# will produce
|
563
|
-
#
|
564
|
-
# <div class='important'>
|
565
|
-
# <p>
|
566
|
-
# A (possibly) important paragraph.
|
567
|
-
# </p>
|
568
|
-
# </div>
|
569
|
-
#
|
570
|
-
# if `important` is truthy, and just
|
571
|
-
#
|
572
|
-
# <p>
|
573
|
-
# A (possibly) important paragraph.
|
574
|
-
# </p>
|
575
|
-
#
|
576
|
-
# otherwise.
|
577
|
-
#
|
578
|
-
# Like \{#haml_tag}, `haml_tag_if` outputs directly to the buffer and its
|
579
|
-
# return value should not be used. Use \{#capture_haml} if you need to use
|
580
|
-
# its results as a string.
|
581
|
-
#
|
582
|
-
# @param condition The condition to test to determine whether to render
|
583
|
-
# the enclosing tag
|
584
|
-
# @param tag Definition of the enclosing tag. See \{#haml_tag} for details
|
585
|
-
# (specifically the form that takes a block)
|
586
|
-
def haml_tag_if(condition, *tag)
|
587
|
-
if condition
|
588
|
-
haml_tag(*tag){ yield }
|
589
|
-
else
|
590
|
-
yield
|
591
|
-
end
|
592
|
-
ErrorReturn.new("haml_tag_if")
|
11
|
+
def preserve(input)
|
12
|
+
Helpers.preserve(input)
|
593
13
|
end
|
594
|
-
|
595
|
-
# Characters that need to be escaped to HTML entities from user input
|
596
|
-
HTML_ESCAPE = {'&' => '&', '<' => '<', '>' => '>', '"' => '"', "'" => '''}.freeze
|
597
|
-
|
598
|
-
HTML_ESCAPE_REGEX = /['"><&]/
|
599
|
-
|
600
|
-
# Returns a copy of `text` with ampersands, angle brackets and quotes
|
601
|
-
# escaped into HTML entities.
|
602
|
-
#
|
603
|
-
# Note that if ActionView is loaded and XSS protection is enabled
|
604
|
-
# (as is the default for Rails 3.0+, and optional for version 2.3.5+),
|
605
|
-
# this won't escape text declared as "safe".
|
606
|
-
#
|
607
|
-
# @param text [String] The string to sanitize
|
608
|
-
# @return [String] The sanitized string
|
609
|
-
def html_escape(text)
|
610
|
-
CGI.escapeHTML(text.to_s)
|
611
|
-
end
|
612
|
-
|
613
|
-
# Always escape text regardless of html_safe?
|
614
|
-
alias_method :html_escape_without_haml_xss, :html_escape
|
615
|
-
|
616
|
-
HTML_ESCAPE_ONCE_REGEX = /['"><]|&(?!(?:[a-zA-Z]+|#(?:\d+|[xX][0-9a-fA-F]+));)/
|
617
|
-
|
618
|
-
# Escapes HTML entities in `text`, but without escaping an ampersand
|
619
|
-
# that is already part of an escaped entity.
|
620
|
-
#
|
621
|
-
# @param text [String] The string to sanitize
|
622
|
-
# @return [String] The sanitized string
|
623
|
-
def escape_once(text)
|
624
|
-
text = text.to_s
|
625
|
-
text.gsub(HTML_ESCAPE_ONCE_REGEX, HTML_ESCAPE)
|
626
|
-
end
|
627
|
-
|
628
|
-
# Always escape text once regardless of html_safe?
|
629
|
-
alias_method :escape_once_without_haml_xss, :escape_once
|
630
|
-
|
631
|
-
# Returns whether or not the current template is a Haml template.
|
632
|
-
#
|
633
|
-
# This function, unlike other {Haml::Helpers} functions,
|
634
|
-
# also works in other `ActionView` templates,
|
635
|
-
# where it will always return false.
|
636
|
-
#
|
637
|
-
# @return [Boolean] Whether or not the current template is a Haml template
|
638
|
-
def is_haml?
|
639
|
-
!@haml_buffer.nil? && @haml_buffer.active?
|
640
|
-
end
|
641
|
-
|
642
|
-
# Returns whether or not `block` is defined directly in a Haml template.
|
643
|
-
#
|
644
|
-
# @param block [Proc] A Ruby block
|
645
|
-
# @return [Boolean] Whether or not `block` is defined directly in a Haml template
|
646
|
-
def block_is_haml?(block)
|
647
|
-
eval('!!defined?(_hamlout)', block.binding)
|
648
|
-
end
|
649
|
-
|
650
|
-
private
|
651
|
-
|
652
|
-
# Parses the tag name used for \{#haml\_tag}
|
653
|
-
# and merges it with the Ruby attributes hash.
|
654
|
-
def merge_name_and_attributes(name, attributes_hash = {})
|
655
|
-
# skip merging if no ids or classes found in name
|
656
|
-
return name, attributes_hash unless name =~ /^(.+?)?([\.#].*)$/
|
657
|
-
|
658
|
-
return $1 || "div", AttributeBuilder.merge_attributes!(
|
659
|
-
Haml::Parser.parse_class_and_id($2), attributes_hash)
|
660
|
-
end
|
661
|
-
|
662
|
-
# Runs a block of code with the given buffer as the currently active buffer.
|
663
|
-
#
|
664
|
-
# @param buffer [Haml::Buffer] The Haml buffer to use temporarily
|
665
|
-
# @yield A block in which the given buffer should be used
|
666
|
-
def with_haml_buffer(buffer)
|
667
|
-
@haml_buffer, old_buffer = buffer, @haml_buffer
|
668
|
-
old_buffer.active, old_was_active = false, old_buffer.active? if old_buffer
|
669
|
-
@haml_buffer.active, was_active = true, @haml_buffer.active?
|
670
|
-
yield
|
671
|
-
ensure
|
672
|
-
@haml_buffer.active = was_active
|
673
|
-
old_buffer.active = old_was_active if old_buffer
|
674
|
-
@haml_buffer = old_buffer
|
675
|
-
end
|
676
|
-
|
677
|
-
# The current {Haml::Buffer} object.
|
678
|
-
#
|
679
|
-
# @return [Haml::Buffer]
|
680
|
-
def haml_buffer
|
681
|
-
@haml_buffer if defined? @haml_buffer
|
682
|
-
end
|
683
|
-
|
684
|
-
# Gives a proc the same local `_hamlout` and `_erbout` variables
|
685
|
-
# that the current template has.
|
686
|
-
#
|
687
|
-
# @param proc [#call] The proc to bind
|
688
|
-
# @return [Proc] A new proc with the new variables bound
|
689
|
-
def haml_bind_proc(&proc)
|
690
|
-
_hamlout = haml_buffer
|
691
|
-
#double assignment is to avoid warnings
|
692
|
-
_erbout = _erbout = _hamlout.buffer
|
693
|
-
proc { |*args| proc.call(*args) }
|
694
|
-
end
|
695
|
-
end
|
696
|
-
end
|
697
|
-
|
698
|
-
# @private
|
699
|
-
class Object
|
700
|
-
# Haml overrides various `ActionView` helpers,
|
701
|
-
# which call an \{#is\_haml?} method
|
702
|
-
# to determine whether or not the current context object
|
703
|
-
# is a proper Haml context.
|
704
|
-
# Because `ActionView` helpers may be included in non-`ActionView::Base` classes,
|
705
|
-
# it's a good idea to define \{#is\_haml?} for all objects.
|
706
|
-
def is_haml?
|
707
|
-
false
|
708
14
|
end
|
709
15
|
end
|