haml 4.0.7 → 4.1.0.alpha.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.

@@ -69,8 +69,7 @@ module Haml
69
69
  # Processes the template and returns the result as a string.
70
70
  #
71
71
  # `scope` is the context in which the template is evaluated.
72
- # If it's a `Binding` or `Proc` object,
73
- # Haml uses it as the second argument to `Kernel#eval`;
72
+ # If it's a `Binding`, Haml uses it as the second argument to `Kernel#eval`;
74
73
  # otherwise, Haml just uses its `#instance_eval` context.
75
74
  #
76
75
  # Note that Haml modifies the evaluation context
@@ -95,14 +94,14 @@ module Haml
95
94
  # within the template.
96
95
  #
97
96
  # Due to some Ruby quirks,
98
- # if `scope` is a `Binding` or `Proc` object and a block is given,
97
+ # if `scope` is a `Binding` object and a block is given,
99
98
  # the evaluation context may not be quite what the user expects.
100
99
  # In particular, it's equivalent to passing `eval("self", scope)` as `scope`.
101
100
  # This won't have an effect in most cases,
102
101
  # but if you're relying on local variables defined in the context of `scope`,
103
102
  # they won't work.
104
103
  #
105
- # @param scope [Binding, Proc, Object] The context in which the template is evaluated
104
+ # @param scope [Binding, Object] The context in which the template is evaluated
106
105
  # @param locals [{Symbol => Object}] Local variables that will be made available
107
106
  # to the template
108
107
  # @param block [#to_proc] A block that can be yielded to within the template
@@ -111,7 +110,7 @@ module Haml
111
110
  parent = scope.instance_variable_defined?('@haml_buffer') ? scope.instance_variable_get('@haml_buffer') : nil
112
111
  buffer = Haml::Buffer.new(parent, @options.for_buffer)
113
112
 
114
- if scope.is_a?(Binding) || scope.is_a?(Proc)
113
+ if scope.is_a?(Binding)
115
114
  scope_object = eval("self", scope)
116
115
  scope = scope_object.instance_eval{binding} if block_given?
117
116
  else
@@ -121,20 +120,16 @@ module Haml
121
120
 
122
121
  set_locals(locals.merge(:_hamlout => buffer, :_erbout => buffer.buffer), scope, scope_object)
123
122
 
124
- scope_object.instance_eval do
125
- extend Haml::Helpers
126
- @haml_buffer = buffer
127
- end
123
+ scope_object.extend(Haml::Helpers)
124
+ scope_object.instance_variable_set(:'@haml_buffer', buffer)
128
125
  begin
129
- eval(@compiler.precompiled_with_return_value, scope, @options[:filename], @options[:line])
126
+ eval(@compiler.precompiled_with_return_value, scope, @options.filename, @options.line)
130
127
  rescue ::SyntaxError => e
131
128
  raise SyntaxError, e.message
132
129
  end
133
130
  ensure
134
131
  # Get rid of the current buffer
135
- scope_object.instance_eval do
136
- @haml_buffer = buffer.upper if buffer
137
- end
132
+ scope_object.instance_variable_set(:'@haml_buffer', buffer.upper) if buffer
138
133
  end
139
134
  alias_method :to_html, :render
140
135
 
@@ -159,11 +154,11 @@ module Haml
159
154
  #
160
155
  # The proc doesn't take a block; any yields in the template will fail.
161
156
  #
162
- # @param scope [Binding, Proc, Object] The context in which the template is evaluated
157
+ # @param scope [Binding, Object] The context in which the template is evaluated
163
158
  # @param local_names [Array<Symbol>] The names of the locals that can be passed to the proc
164
159
  # @return [Proc] The proc that will run the template
165
160
  def render_proc(scope = Object.new, *local_names)
166
- if scope.is_a?(Binding) || scope.is_a?(Proc)
161
+ if scope.is_a?(Binding)
167
162
  scope_object = eval("self", scope)
168
163
  else
169
164
  scope_object = scope
@@ -172,7 +167,7 @@ module Haml
172
167
 
173
168
  begin
174
169
  eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
175
- compiler.precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
170
+ compiler.precompiled_with_ambles(local_names) + "}\n", scope, @options.filename, @options.line)
176
171
  rescue ::SyntaxError => e
177
172
  raise SyntaxError, e.message
178
173
  end
@@ -220,24 +215,19 @@ module Haml
220
215
  method = object.is_a?(Module) ? :module_eval : :instance_eval
221
216
 
222
217
  object.send(method, "def #{name}(_haml_locals = {}); #{compiler.precompiled_with_ambles(local_names)}; end",
223
- @options[:filename], @options[:line])
218
+ @options.filename, @options.line)
224
219
  end
225
220
 
226
221
  private
227
222
 
228
- if RUBY_VERSION < "1.9"
229
- def initialize_encoding(given_value)
230
- end
231
- else
232
- def initialize_encoding(given_value)
233
- unless given_value
234
- @options.encoding = Encoding.default_internal || @template.encoding
235
- end
223
+ def initialize_encoding(given_value)
224
+ unless given_value
225
+ @options.encoding = Encoding.default_internal || @template.encoding
236
226
  end
237
227
  end
238
228
 
239
229
  def set_locals(locals, scope, scope_object)
240
- scope_object.send(:instance_variable_set, '@_haml_locals', locals)
230
+ scope_object.instance_variable_set '@_haml_locals', locals
241
231
  set_locals = locals.keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n")
242
232
  eval(set_locals, scope)
243
233
  end
@@ -1,5 +1,4 @@
1
1
  require 'optparse'
2
- require 'fileutils'
3
2
  require 'rbconfig'
4
3
  require 'pp'
5
4
 
@@ -237,6 +236,11 @@ END
237
236
  @options[:for_engine][:attr_wrapper] = '"'
238
237
  end
239
238
 
239
+ opts.on('--remove-whitespace',
240
+ 'Remove whitespace surrounding and within tags') do
241
+ @options[:for_engine][:remove_whitespace] = true
242
+ end
243
+
240
244
  opts.on('--cdata',
241
245
  'Always add CDATA sections to javascript and css blocks.') do
242
246
  @options[:for_engine][:cdata] = true
@@ -260,12 +264,10 @@ END
260
264
  @options[:load_paths] << path
261
265
  end
262
266
 
263
- unless RUBY_VERSION < "1.9"
264
- opts.on('-E ex[:in]', 'Specify the default external and internal character encodings.') do |encoding|
265
- external, internal = encoding.split(':')
266
- Encoding.default_external = external if external && !external.empty?
267
- Encoding.default_internal = internal if internal && !internal.empty?
268
- end
267
+ opts.on('-E ex[:in]', 'Specify the default external and internal character encodings.') do |encoding|
268
+ external, internal = encoding.split(':')
269
+ Encoding.default_external = external if external && !external.empty?
270
+ Encoding.default_internal = internal if internal && !internal.empty?
269
271
  end
270
272
 
271
273
  opts.on('-d', '--debug', "Print out the precompiled Ruby source.") do
@@ -166,7 +166,7 @@ module Haml
166
166
  text = unescape_interpolation(text).gsub(/(\\+)n/) do |s|
167
167
  escapes = $1.size
168
168
  next s if escapes % 2 == 0
169
- ("\\" * (escapes - 1)) + "\n"
169
+ "#{'\\' * (escapes - 1)}\n"
170
170
  end
171
171
  # We need to add a newline at the beginning to get the
172
172
  # filter lines to line up (since the Haml filter contains
@@ -174,7 +174,7 @@ module Haml
174
174
  # filter name). Then we need to escape the trailing
175
175
  # newline so that the whole filter block doesn't take up
176
176
  # too many.
177
- text = "\n" + text.sub(/\n"\Z/, "\\n\"")
177
+ text = %[\n#{text.sub(/\n"\Z/, "\\n\"")}]
178
178
  push_script <<RUBY.rstrip, :escape_html => false
179
179
  find_and_preserve(#{filter.inspect}.render_with_options(#{text}, _hamlout.options))
180
180
  RUBY
@@ -182,12 +182,9 @@ RUBY
182
182
  end
183
183
 
184
184
  rendered = Haml::Helpers::find_and_preserve(filter.render_with_options(text, compiler.options), compiler.options[:preserve])
185
-
186
- if options[:ugly]
187
- push_text(rendered.rstrip)
188
- else
189
- push_text(rendered.rstrip.gsub("\n", "\n#{' ' * @output_tabs}"))
190
- end
185
+ rendered.rstrip!
186
+ rendered.gsub!("\n", "\n#{' ' * @output_tabs}") unless options[:ugly]
187
+ push_text(rendered)
191
188
  end
192
189
  end
193
190
  end
@@ -216,13 +213,10 @@ RUBY
216
213
  type = " type=#{options[:attr_wrapper]}text/javascript#{options[:attr_wrapper]}"
217
214
  end
218
215
 
219
- str = "<script#{type}>\n"
220
- str << " //<![CDATA[\n" if options[:cdata]
221
- str << "#{indent}#{text.rstrip.gsub("\n", "\n#{indent}")}\n"
222
- str << " //]]>\n" if options[:cdata]
223
- str << "</script>"
216
+ text = text.rstrip
217
+ text.gsub!("\n", "\n#{indent}")
224
218
 
225
- str
219
+ %!<script#{type}>\n#{" //<![CDATA[\n" if options[:cdata]}#{indent}#{text}\n#{" //]]>\n" if options[:cdata]}</script>!
226
220
  end
227
221
  end
228
222
 
@@ -240,13 +234,10 @@ RUBY
240
234
  type = " type=#{options[:attr_wrapper]}text/css#{options[:attr_wrapper]}"
241
235
  end
242
236
 
243
- str = "<style#{type}>\n"
244
- str << " /*<![CDATA[*/\n" if options[:cdata]
245
- str << "#{indent}#{text.rstrip.gsub("\n", "\n#{indent}")}\n"
246
- str << " /*]]>*/\n" if options[:cdata]
247
- str << "</style>"
237
+ text = text.rstrip
238
+ text.gsub!("\n", "\n#{indent}")
248
239
 
249
- str
240
+ %(<style#{type}>\n#{" /*<![CDATA[*/\n" if options[:cdata]}#{indent}#{text}\n#{" /*]]>*/\n" if options[:cdata]}</style>)
250
241
  end
251
242
  end
252
243
 
@@ -256,7 +247,10 @@ RUBY
256
247
 
257
248
  # @see Base#render
258
249
  def render(text)
259
- "<![CDATA[#{("\n" + text).rstrip.gsub("\n", "\n ")}\n]]>"
250
+ text = "\n#{text}"
251
+ text.rstrip!
252
+ text.gsub!("\n", "\n ")
253
+ "<![CDATA[#{text}\n]]>"
260
254
  end
261
255
  end
262
256
 
@@ -288,7 +282,7 @@ RUBY
288
282
  def compile(compiler, text)
289
283
  return if compiler.options[:suppress_eval]
290
284
  compiler.instance_eval do
291
- push_silent <<-FIRST.gsub("\n", ';') + text + <<-LAST.gsub("\n", ';')
285
+ push_silent <<-FIRST.tr("\n", ';') + text + <<-LAST.tr("\n", ';')
292
286
  begin
293
287
  haml_io = StringIO.new(_hamlout.buffer, 'a')
294
288
  FIRST
@@ -117,17 +117,20 @@ MESSAGE
117
117
  # HTML entities so they'll render correctly in
118
118
  # whitespace-sensitive tags without screwing up the indentation.
119
119
  #
120
- # @overload perserve(input)
120
+ # @overload preserve(input)
121
121
  # Escapes newlines within a string.
122
122
  #
123
123
  # @param input [String] The string within which to escape all newlines
124
- # @overload perserve
124
+ # @overload preserve
125
125
  # Escapes newlines within a block of Haml code.
126
126
  #
127
127
  # @yield The block within which to escape newlines
128
128
  def preserve(input = nil, &block)
129
129
  return preserve(capture_haml(&block)) if block
130
- input.to_s.chomp("\n").gsub(/\n/, '&#x000A;').gsub(/\r/, '')
130
+ s = input.to_s.chomp("\n")
131
+ s.gsub!(/\n/, '&#x000A;')
132
+ s.delete!("\r")
133
+ s
131
134
  end
132
135
  alias_method :flatten, :preserve
133
136
 
@@ -195,7 +198,7 @@ MESSAGE
195
198
  result = capture_haml(i, &block)
196
199
 
197
200
  if result.count("\n") > 1
198
- result = result.gsub("\n", "\n ")
201
+ result.gsub!("\n", "\n ")
199
202
  result = "\n #{result.strip}\n"
200
203
  else
201
204
  result = result.strip
@@ -219,7 +222,11 @@ MESSAGE
219
222
  # @param lang [String] The value of `xml:lang` and `lang`
220
223
  # @return [{#to_s => String}] The attribute hash
221
224
  def html_attrs(lang = 'en-US')
222
- {:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang}
225
+ if haml_buffer.options[:format] == :xhtml
226
+ {:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang}
227
+ else
228
+ {:lang => lang}
229
+ end
223
230
  end
224
231
 
225
232
  # Increments the number of tabs the buffer automatically adds
@@ -365,17 +372,25 @@ MESSAGE
365
372
  position = haml_buffer.buffer.length
366
373
 
367
374
  haml_buffer.capture_position = position
368
- value = block.call(*args)
375
+ block.call(*args)
369
376
 
370
377
  captured = haml_buffer.buffer.slice!(position..-1)
371
-
372
- if captured == '' and value != haml_buffer.buffer
373
- captured = (value.is_a?(String) ? value : nil)
378
+ return captured if haml_buffer.options[:ugly]
379
+ # Note that the "reject" is needed for rbx 1.2.4, which includes empty
380
+ # strings in the returned array when splitting by /^/.
381
+ captured = captured.split(/^/)
382
+ captured.delete('')
383
+
384
+ min_tabs = nil
385
+ captured.each do |line|
386
+ tabs = line.index(/[^ ]/) || line.length
387
+ min_tabs ||= tabs
388
+ min_tabs = min_tabs > tabs ? tabs : min_tabs
374
389
  end
375
390
 
376
- return nil if captured.nil?
377
- return (haml_buffer.options[:ugly] ? captured : prettify(captured))
378
-
391
+ captured.map do |line|
392
+ line.slice(min_tabs, line.length)
393
+ end.join
379
394
  end
380
395
  ensure
381
396
  haml_buffer.capture_position = nil
@@ -386,10 +401,9 @@ MESSAGE
386
401
  # @param text [#to_s] The text to output
387
402
  def haml_concat(text = "")
388
403
  unless haml_buffer.options[:ugly] || haml_indent == 0
389
- haml_buffer.buffer << haml_indent <<
390
- text.to_s.gsub("\n", "\n" + haml_indent) << "\n"
404
+ haml_buffer.buffer << %[#{haml_indent}#{text.to_s.gsub("\n", "\n#{haml_indent}")}\n]
391
405
  else
392
- haml_buffer.buffer << text.to_s << "\n"
406
+ haml_buffer.buffer << "#{text}\n"
393
407
  end
394
408
  ErrorReturn.new("haml_concat")
395
409
  end
@@ -473,7 +487,7 @@ MESSAGE
473
487
  attrs)
474
488
 
475
489
  if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
476
- haml_concat "<#{name}#{attributes} />"
490
+ haml_concat "<#{name}#{attributes}#{' /' if haml_buffer.options[:format] == :xhtml}>"
477
491
  return ret
478
492
  end
479
493
 
@@ -492,7 +506,7 @@ MESSAGE
492
506
  tab_down
493
507
  haml_concat "</#{name}>"
494
508
  else
495
- tag << text << "</#{name}>"
509
+ tag << "#{text}</#{name}>"
496
510
  haml_concat tag
497
511
  end
498
512
  return ret
@@ -503,7 +517,7 @@ MESSAGE
503
517
  end
504
518
 
505
519
  if flags.include?(:<)
506
- tag << capture_haml(&block).strip << "</#{name}>"
520
+ tag << "#{capture_haml(&block).strip}</#{name}>"
507
521
  haml_concat tag
508
522
  return ret
509
523
  end
@@ -517,53 +531,78 @@ MESSAGE
517
531
  ret
518
532
  end
519
533
 
534
+ # Conditionally wrap a block in an element. If `condition` is `true` then
535
+ # this method renders the tag described by the argumants in `tag` (using
536
+ # \{#haml_tag}) with the given block inside, otherwise it just renders the block.
537
+ #
538
+ # For example,
539
+ #
540
+ # - haml_tag_if important, '.important' do
541
+ # %p
542
+ # A (possibly) important paragraph.
543
+ #
544
+ # will produce
545
+ #
546
+ # <div class='important'>
547
+ # <p>
548
+ # A (possibly) important paragraph.
549
+ # </p>
550
+ # </div>
551
+ #
552
+ # if `important` is truthy, and just
553
+ #
554
+ # <p>
555
+ # A (possibly) important paragraph.
556
+ # </p>
557
+ #
558
+ # otherwise.
559
+ #
560
+ # Like \{#haml_tag}, `haml_tag_if` outputs directly to the buffer and its
561
+ # return value should not be used. Use \{#capture_haml} if you need to use
562
+ # its results as a string.
563
+ #
564
+ # @param condition The condition to test to determine whether to render
565
+ # the enclosing tag
566
+ # @param tag Definition of the enclosing tag. See \{#haml_tag} for details
567
+ # (specifically the form that takes a block)
568
+ def haml_tag_if(condition, *tag)
569
+ if condition
570
+ haml_tag(*tag){ yield }
571
+ else
572
+ yield
573
+ end
574
+ ErrorReturn.new("haml_tag_if")
575
+ end
576
+
520
577
  # Characters that need to be escaped to HTML entities from user input
521
- HTML_ESCAPE = { '&'=>'&amp;', '<'=>'&lt;', '>'=>'&gt;', '"'=>'&quot;', "'"=>'&#039;', }
578
+ HTML_ESCAPE = { '&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;', "'" => '&#039;' }
522
579
 
523
580
  HTML_ESCAPE_REGEX = /[\"><&]/
524
581
 
525
- if RUBY_VERSION >= '1.9'
526
- # Include docs here so they are picked up by Yard
527
-
528
- # Returns a copy of `text` with ampersands, angle brackets and quotes
529
- # escaped into HTML entities.
530
- #
531
- # Note that if ActionView is loaded and XSS protection is enabled
532
- # (as is the default for Rails 3.0+, and optional for version 2.3.5+),
533
- # this won't escape text declared as "safe".
534
- #
535
- # @param text [String] The string to sanitize
536
- # @return [String] The sanitized string
537
- def html_escape(text)
538
- text = text.to_s
539
- text.gsub(HTML_ESCAPE_REGEX, HTML_ESCAPE)
540
- end
541
- else
542
- def html_escape(text)
543
- text = text.to_s
544
- text.gsub(HTML_ESCAPE_REGEX) {|s| HTML_ESCAPE[s]}
545
- end
582
+ # Returns a copy of `text` with ampersands, angle brackets and quotes
583
+ # escaped into HTML entities.
584
+ #
585
+ # Note that if ActionView is loaded and XSS protection is enabled
586
+ # (as is the default for Rails 3.0+, and optional for version 2.3.5+),
587
+ # this won't escape text declared as "safe".
588
+ #
589
+ # @param text [String] The string to sanitize
590
+ # @return [String] The sanitized string
591
+ def html_escape(text)
592
+ text = text.to_s
593
+ text.gsub(HTML_ESCAPE_REGEX, HTML_ESCAPE)
546
594
  end
547
595
 
548
- HTML_ESCAPE_ONCE_REGEX = /[\"><]|&(?!(?:[a-zA-Z]+|(#\d+));)/
549
-
550
- if RUBY_VERSION >= '1.9'
551
- # Include docs here so they are picked up by Yard
596
+ HTML_ESCAPE_ONCE_REGEX = /[\"><]|&(?!(?:[a-zA-Z]+|#(?:\d+|[xX][0-9a-fA-F]+));)/
552
597
 
553
- # Escapes HTML entities in `text`, but without escaping an ampersand
554
- # that is already part of an escaped entity.
555
- #
556
- # @param text [String] The string to sanitize
557
- # @return [String] The sanitized string
558
- def escape_once(text)
559
- text = text.to_s
560
- text.gsub(HTML_ESCAPE_ONCE_REGEX, HTML_ESCAPE)
561
- end
562
- else
563
- def escape_once(text)
564
- text = text.to_s
565
- text.gsub(HTML_ESCAPE_ONCE_REGEX){|s| HTML_ESCAPE[s]}
566
- end
598
+ # Escapes HTML entities in `text`, but without escaping an ampersand
599
+ # that is already part of an escaped entity.
600
+ #
601
+ # @param text [String] The string to sanitize
602
+ # @return [String] The sanitized string
603
+ def escape_once(text)
604
+ text = text.to_s
605
+ text.gsub(HTML_ESCAPE_ONCE_REGEX, HTML_ESCAPE)
567
606
  end
568
607
 
569
608
  # Returns whether or not the current template is a Haml template.
@@ -630,22 +669,6 @@ MESSAGE
630
669
  _erbout = _erbout = _hamlout.buffer
631
670
  proc { |*args| proc.call(*args) }
632
671
  end
633
-
634
- def prettify(text)
635
- text = text.split(/^/)
636
- text.delete('')
637
-
638
- min_tabs = nil
639
- text.each do |line|
640
- tabs = line.index(/[^ ]/) || line.length
641
- min_tabs ||= tabs
642
- min_tabs = min_tabs > tabs ? tabs : min_tabs
643
- end
644
-
645
- text.map do |line|
646
- line.slice(min_tabs, line.length)
647
- end.join
648
- end
649
672
  end
650
673
  end
651
674