haml 2.0.3 → 2.0.4

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.

@@ -12,7 +12,7 @@ and providing elegant, easily understandable, and powerful syntax.
12
12
  == Using
13
13
 
14
14
  There are several ways to use Haml and Sass.
15
- They can be used as a plugins for Rails or Merb,
15
+ They can be used as a plugin for Rails or Merb,
16
16
  or embedded on their own in other applications.
17
17
  The first step of all of these is to install the Haml gem:
18
18
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.3
1
+ 2.0.4
data/init.rb CHANGED
@@ -4,4 +4,5 @@ rescue LoadError
4
4
  require 'haml' # From gem
5
5
  end
6
6
 
7
+ # Load Haml and Sass
7
8
  Haml.init_rails(binding)
@@ -1,5 +1,5 @@
1
1
  dir = File.dirname(__FILE__)
2
- $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
2
+ $LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
3
3
 
4
4
  # = Haml (XHTML Abstraction Markup Language)
5
5
  #
@@ -138,7 +138,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
138
138
  #
139
139
  # is compiled to:
140
140
  #
141
- # <head name="doc_head">
141
+ # <head name='doc_head'>
142
142
  # <script src='javascripts/script_9' type='text/javascript'>
143
143
  # </script>
144
144
  # </head>
@@ -159,7 +159,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
159
159
  #
160
160
  # This is compiled to:
161
161
  #
162
- # <html lang='fr-fr' xml:lang='fr=fr' xmlns='http://www.w3.org/1999/xhtml'>
162
+ # <html lang='fr-fr' xml:lang='fr-fr' xmlns='http://www.w3.org/1999/xhtml'>
163
163
  # </html>
164
164
  #
165
165
  # You can use as many such attribute methods as you want
@@ -184,6 +184,9 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
184
184
  #
185
185
  # <sandwich bread='whole wheat' delicious='true' filling='peanut butter and jelly' />
186
186
  #
187
+ # Note that the Haml attributes list has the same syntax as a Ruby method call.
188
+ # This means that any attribute methods must come before the hash literal.
189
+ #
187
190
  # ===== Boolean Attributes
188
191
  #
189
192
  # Some attributes, such as "checked" for <tt>input</tt> tags or "selected" for <tt>option</tt> tags,
@@ -200,7 +203,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
200
203
  # In XHTML, the only valid value for these attributes is the name of the attribute.
201
204
  # Thus this will render in XHTML as
202
205
  #
203
- # <input selected="selected">
206
+ # <input selected='selected'>
204
207
  #
205
208
  # To set these attributes to false, simply assign them to a Ruby false value.
206
209
  # In both XHTML and HTML
@@ -238,8 +241,8 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
238
241
  #
239
242
  # is compiled to:
240
243
  #
241
- # <div class="greeting_crazy_user" id="greeting_crazy_user_15">
242
- # <bar class="fixnum" id="fixnum_581" />
244
+ # <div class='greeting_crazy_user' id='greeting_crazy_user_15'>
245
+ # <bar class='fixnum' id='fixnum_581' />
243
246
  # Hello!
244
247
  # </div>
245
248
  #
@@ -306,11 +309,11 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
306
309
  #
307
310
  # is compiled to:
308
311
  #
309
- # <div id="content">
310
- # <div class="articles">
311
- # <div class="article title">Doogie Howser Comes Out</div>
312
- # <div class="article date">2006-11-05</div>
313
- # <div class="article entry">
312
+ # <div id='content'>
313
+ # <div class='articles'>
314
+ # <div class='article title'>Doogie Howser Comes Out</div>
315
+ # <div class='article date'>2006-11-05</div>
316
+ # <div class='article entry'>
314
317
  # Neil Patrick Harris would like to dispel any rumors that he is straight
315
318
  # </div>
316
319
  # </div>
@@ -474,7 +477,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
474
477
  #
475
478
  # is compiled to:
476
479
  #
477
- # <?xml version="1.0" encoding="utf-8" ?>
480
+ # <?xml version='1.0' encoding='utf-8' ?>
478
481
  # <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
479
482
  # <html>
480
483
  # <head>
@@ -514,7 +517,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
514
517
  #
515
518
  # is compiled to:
516
519
  #
517
- # <?xml version="1.0" encoding="iso-8859-1" ?>
520
+ # <?xml version='1.0' encoding='iso-8859-1' ?>
518
521
  #
519
522
  # ==== /
520
523
  #
@@ -566,7 +569,7 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
566
569
  # </a>
567
570
  # <![endif]-->
568
571
  #
569
- # ==== \
572
+ # ==== \
570
573
  #
571
574
  # The backslash character escapes the first character of a line,
572
575
  # allowing use of otherwise interpreted characters as plain text.
@@ -915,9 +918,9 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
915
918
  #
916
919
  # Haml::Template.options[:format] = :html5
917
920
  #
918
- # ...or by setting the <tt>Merb::Config[:haml]</tt> hash in <tt>init.rb</tt> in Merb...
921
+ # ...or by setting the <tt>Merb::Plugin.config[:haml]</tt> hash in <tt>init.rb</tt> in Merb...
919
922
  #
920
- # Merb::Config[:haml][:format] = :html5
923
+ # Merb::Plugin.config[:haml][:format] = :html5
921
924
  #
922
925
  # ...or by passing an options hash to Haml::Engine.new.
923
926
  # Available options are:
@@ -993,7 +996,7 @@ module Haml
993
996
 
994
997
  if File.exists?(scope('REVISION'))
995
998
  rev = File.read(scope('REVISION')).strip
996
- rev = nil if rev !~ /[a-f0-9]+/
999
+ rev = nil if rev !~ /^([a-f0-9]+|\(.*\))$/
997
1000
  end
998
1001
 
999
1002
  if rev.nil? && File.exists?(scope('.git/HEAD'))
@@ -1005,8 +1008,10 @@ module Haml
1005
1008
 
1006
1009
  if rev
1007
1010
  @@version[:rev] = rev
1008
- @@version[:string] << "."
1009
- @@version[:string] << rev[0...7] unless rev[0] == ?(
1011
+ unless rev[0] == ?(
1012
+ @@version[:string] << "."
1013
+ @@version[:string] << rev[0...7]
1014
+ end
1010
1015
  end
1011
1016
 
1012
1017
  @@version
@@ -151,16 +151,19 @@ module Haml
151
151
  tabulation = @real_tabs
152
152
 
153
153
  attributes = class_id
154
- attributes_hashes.each do |attributes_hash|
155
- attributes_hash.keys.each { |key| attributes_hash[key.to_s] = attributes_hash.delete(key) }
156
- self.class.merge_attrs(attributes, attributes_hash)
154
+ attributes_hashes.each do |old|
155
+ self.class.merge_attrs(attributes, old.inject({}) {|h, (key, val)| h[key.to_s] = val; h})
157
156
  end
158
157
  self.class.merge_attrs(attributes, parse_object_ref(obj_ref)) if obj_ref
159
158
 
160
- if self_closing
159
+ if self_closing && xhtml?
161
160
  str = " />" + (nuke_outer_whitespace ? "" : "\n")
162
161
  else
163
- str = ">" + (try_one_line || preserve_tag || nuke_inner_whitespace ? "" : "\n")
162
+ str = ">" + ((if self_closing && html?
163
+ nuke_outer_whitespace
164
+ else
165
+ try_one_line || preserve_tag || nuke_inner_whitespace
166
+ end) ? "" : "\n")
164
167
  end
165
168
 
166
169
  attributes = Precompiler.build_attributes(html?, @options[:attr_wrapper], attributes)
@@ -92,7 +92,7 @@ module Haml
92
92
  if @options[:filters]
93
93
  warn <<END
94
94
  DEPRECATION WARNING:
95
- The Haml :filters option is deprecated and will be removed in version 2.1.
95
+ The Haml :filters option is deprecated and will be removed in version 2.2.
96
96
  Filters are now automatically registered.
97
97
  END
98
98
  end
@@ -24,13 +24,9 @@ module Haml
24
24
 
25
25
  @options
26
26
  rescue Exception => e
27
- raise e if e.is_a? SystemExit
27
+ raise e if @options[:trace] || e.is_a?(SystemExit)
28
28
 
29
- $stderr.print "#{e.class} on line #{get_line e}: " if @options[:trace]
30
29
  $stderr.puts e.message
31
-
32
- e.backtrace[1..-1].each { |t| $stderr.puts " #{t}" } if @options[:trace]
33
-
34
30
  exit 1
35
31
  end
36
32
  exit 0
@@ -212,10 +212,10 @@ END
212
212
 
213
213
  module Sass
214
214
  include Base
215
- lazy_require 'sass/engine'
215
+ lazy_require 'sass/plugin'
216
216
 
217
217
  def render(text)
218
- ::Sass::Engine.new(text,::Sass::Plugin.engine_options).render
218
+ ::Sass::Engine.new(text, ::Sass::Plugin.engine_options).render
219
219
  end
220
220
  end
221
221
 
@@ -239,6 +239,7 @@ END
239
239
  end
240
240
  end
241
241
  RedCloth = Textile
242
+ Filters.defined['redcloth'] = RedCloth
242
243
 
243
244
  # Uses BlueCloth or RedCloth to provide only Markdown (not Textile) parsing
244
245
  module Markdown
@@ -254,11 +254,39 @@ module Haml
254
254
  # the local variable <tt>foo</tt> would be assigned to "<p>13</p>\n".
255
255
  #
256
256
  def capture_haml(*args, &block)
257
- capture_haml_with_buffer(haml_buffer.buffer, *args, &block)
257
+ buffer = eval('_hamlout', block) rescue haml_buffer
258
+ with_haml_buffer(buffer) do
259
+ position = haml_buffer.buffer.length
260
+
261
+ block.call(*args)
262
+
263
+ captured = haml_buffer.buffer.slice!(position..-1)
264
+
265
+ min_tabs = nil
266
+ captured.each do |line|
267
+ tabs = line.index(/[^ ]/)
268
+ min_tabs ||= tabs
269
+ min_tabs = min_tabs > tabs ? tabs : min_tabs
270
+ end
271
+
272
+ result = captured.map do |line|
273
+ line[min_tabs..-1]
274
+ end
275
+ result.to_s
276
+ end
277
+ end
278
+
279
+ def puts(*args) # :nodoc:
280
+ warn <<END
281
+ DEPRECATION WARNING:
282
+ The Haml #puts helper is deprecated and will be removed in version 2.4.
283
+ Use the #haml_concat helper instead.
284
+ END
285
+ haml_concat *args
258
286
  end
259
287
 
260
288
  # Outputs text directly to the Haml buffer, with the proper tabulation
261
- def puts(text = "")
289
+ def haml_concat(text = "")
262
290
  haml_buffer.buffer << (' ' * haml_buffer.tabulation) << text.to_s << "\n"
263
291
  nil
264
292
  end
@@ -271,7 +299,7 @@ module Haml
271
299
  # Creates an HTML tag with the given name and optionally text and attributes.
272
300
  # Can take a block that will be executed
273
301
  # between when the opening and closing tags are output.
274
- # If the block is a Haml block or outputs text using puts,
302
+ # If the block is a Haml block or outputs text using haml_concat,
275
303
  # the text will be properly indented.
276
304
  #
277
305
  # <tt>flags</tt> is a list of symbol flags
@@ -285,10 +313,10 @@ module Haml
285
313
  # haml_tag :tr do
286
314
  # haml_tag :td, {:class => 'cell'} do
287
315
  # haml_tag :strong, "strong!"
288
- # puts "data"
316
+ # haml_concat "data"
289
317
  # end
290
318
  # haml_tag :td do
291
- # puts "more_data"
319
+ # haml_concat "more_data"
292
320
  # end
293
321
  # end
294
322
  # end
@@ -319,7 +347,7 @@ module Haml
319
347
  rest.shift || {})
320
348
 
321
349
  if text.nil? && block.nil? && (haml_buffer.options[:autoclose].include?(name) || flags.include?(:/))
322
- puts "<#{name}#{attributes} />"
350
+ haml_concat "<#{name}#{attributes} />"
323
351
  return nil
324
352
  end
325
353
 
@@ -331,7 +359,7 @@ module Haml
331
359
  tag = "<#{name}#{attributes}>"
332
360
  if block.nil?
333
361
  tag << text.to_s << "</#{name}>"
334
- puts tag
362
+ haml_concat tag
335
363
  return
336
364
  end
337
365
 
@@ -341,15 +369,15 @@ module Haml
341
369
 
342
370
  if flags.include?(:<)
343
371
  tag << capture_haml(&block).strip << "</#{name}>"
344
- puts tag
372
+ haml_concat tag
345
373
  return
346
374
  end
347
375
 
348
- puts tag
376
+ haml_concat tag
349
377
  tab_up
350
378
  block.call
351
379
  tab_down
352
- puts "</#{name}>"
380
+ haml_concat "</#{name}>"
353
381
  nil
354
382
  end
355
383
 
@@ -379,6 +407,21 @@ module Haml
379
407
 
380
408
  private
381
409
 
410
+ # call-seq:
411
+ # with_haml_buffer(buffer) {...}
412
+ #
413
+ # Runs the block with the given buffer as the currently active buffer.
414
+ def with_haml_buffer(buffer)
415
+ @haml_buffer, old_buffer = buffer, @haml_buffer
416
+ old_buffer.active, was_active = false, old_buffer.active? if old_buffer
417
+ @haml_buffer.active = true
418
+ yield
419
+ ensure
420
+ @haml_buffer.active = false
421
+ old_buffer.active = was_active if old_buffer
422
+ @haml_buffer = old_buffer
423
+ end
424
+
382
425
  # Gets a reference to the current Haml::Buffer object.
383
426
  def haml_buffer
384
427
  @haml_buffer
@@ -392,28 +435,6 @@ module Haml
392
435
  proc { |*args| proc.call(*args) }
393
436
  end
394
437
 
395
- # Performs the function of capture_haml, assuming <tt>local_buffer</tt>
396
- # is where the output of block goes.
397
- def capture_haml_with_buffer(local_buffer, *args, &block)
398
- position = local_buffer.length
399
-
400
- block.call(*args)
401
-
402
- captured = local_buffer.slice!(position..-1)
403
-
404
- min_tabs = nil
405
- captured.each do |line|
406
- tabs = line.index(/[^ ]/)
407
- min_tabs ||= tabs
408
- min_tabs = min_tabs > tabs ? tabs : min_tabs
409
- end
410
-
411
- result = captured.map do |line|
412
- line[min_tabs..-1]
413
- end
414
- result.to_s
415
- end
416
-
417
438
  include ActionViewExtensions if self.const_defined? "ActionViewExtensions"
418
439
  end
419
440
  end
@@ -2,7 +2,15 @@ if defined?(ActionView) and not defined?(Merb::Plugins)
2
2
  module ActionView
3
3
  class Base # :nodoc:
4
4
  def render_with_haml(*args, &block)
5
- return non_haml { render_without_haml(*args, &block) } if is_haml?
5
+ options = args.first
6
+
7
+ # If render :layout is used with a block,
8
+ # it concats rather than returning a string
9
+ # so we need it to keep thinking it's Haml
10
+ # until it hits the sub-render
11
+ if is_haml? && !(options.is_a?(Hash) && options[:layout] && block_given?)
12
+ return non_haml { render_without_haml(*args, &block) }
13
+ end
6
14
  render_without_haml(*args, &block)
7
15
  end
8
16
  alias_method :render_without_haml, :render
@@ -60,11 +68,11 @@ if defined?(ActionView) and not defined?(Merb::Plugins)
60
68
  alias_method :capture_without_haml, :capture
61
69
  alias_method :capture, :capture_with_haml
62
70
 
63
- def capture_erb_with_buffer_with_haml(*args, &block)
71
+ def capture_erb_with_buffer_with_haml(buffer, *args, &block)
64
72
  if is_haml?
65
- capture_haml_with_buffer(*args, &block)
73
+ capture_haml(*args, &block)
66
74
  else
67
- capture_erb_with_buffer_without_haml(*args, &block)
75
+ capture_erb_with_buffer_without_haml(buffer, *args, &block)
68
76
  end
69
77
  end
70
78
  alias_method :capture_erb_with_buffer_without_haml, :capture_erb_with_buffer
@@ -25,7 +25,7 @@ module Haml
25
25
 
26
26
  if @@options[:rhtml]
27
27
  match_to_html(template, /<%=(.*?)-?%>/m, 'loud')
28
- match_to_html(template, /<%(.*?)-?%>/m, 'silent')
28
+ match_to_html(template, /<%-?(.*?)-?%>/m, 'silent')
29
29
  end
30
30
 
31
31
  method = @@options[:xhtml] ? Hpricot.method(:XML) : method(:Hpricot)
@@ -131,17 +131,20 @@ module Haml
131
131
  def to_haml(tabs = 0)
132
132
  output = "#{tabulate(tabs)}"
133
133
  if HTML.options[:rhtml] && name[0...5] == 'haml:'
134
- return output + HTML.send("haml_tag_#{name[5..-1]}",
135
- CGI.unescapeHTML(self.innerHTML))
134
+ return output + HTML.send("haml_tag_#{name[5..-1]}", CGI.unescapeHTML(self.inner_text))
136
135
  end
137
136
 
138
- output += "%#{name}" unless name == 'div' && (attributes.include?('id') || attributes.include?('class'))
137
+ output += "%#{name}" unless name == 'div' && (static_id? || static_classname?)
139
138
 
140
139
  if attributes
141
- output += "##{attributes['id']}" if attributes['id']
142
- attributes['class'].split(' ').each { |c| output += ".#{c}" } if attributes['class']
143
- remove_attribute('id')
144
- remove_attribute('class')
140
+ if static_id?
141
+ output += "##{attributes['id']}"
142
+ remove_attribute('id')
143
+ end
144
+ if static_classname?
145
+ attributes['class'].split(' ').each { |c| output += ".#{c}" }
146
+ remove_attribute('class')
147
+ end
145
148
  output += haml_attributes if attributes.length > 0
146
149
  end
147
150
 
@@ -156,13 +159,49 @@ module Haml
156
159
  end
157
160
 
158
161
  private
162
+
163
+ def dynamic_attributes
164
+ @dynamic_attributes ||= begin
165
+ attributes.inject({}) do |dynamic, pair|
166
+ name, value = pair
167
+ unless value.empty?
168
+ full_match = nil
169
+ ruby_value = value.gsub(%r{<haml:loud>\s*(.+?)\s*</haml:loud>}) do
170
+ full_match = $`.empty? && $'.empty?
171
+ full_match ? $1: "\#{#{$1}}"
172
+ end
173
+ unless ruby_value == value
174
+ dynamic[name] = full_match ? ruby_value : %("#{ruby_value}")
175
+ end
176
+ end
177
+ dynamic
178
+ end
179
+ end
180
+ end
181
+
182
+ def static_attribute?(name)
183
+ attributes[name] and !dynamic_attribute?(name)
184
+ end
185
+
186
+ def dynamic_attribute?(name)
187
+ HTML.options[:rhtml] and dynamic_attributes.key?(name)
188
+ end
189
+
190
+ def static_id?
191
+ static_attribute? 'id'
192
+ end
193
+
194
+ def static_classname?
195
+ static_attribute? 'class'
196
+ end
159
197
 
160
198
  # Returns a string representation of an attributes hash
161
199
  # that's prettier than that produced by Hash#inspect
162
200
  def haml_attributes
163
201
  attrs = attributes.map do |name, value|
202
+ value = dynamic_attribute?(name) ? dynamic_attributes[name] : value.inspect
164
203
  name = name.index(/\W/) ? name.inspect : ":#{name}"
165
- "#{name} => #{value.inspect}"
204
+ "#{name} => #{value}"
166
205
  end
167
206
  "{ #{attrs.join(', ')} }"
168
207
  end
@@ -209,9 +209,11 @@ END
209
209
 
210
210
  push_silent(text[1..-1], true)
211
211
  newline_now
212
- if (@block_opened && !mid_block_keyword?(text)) || text[1..-1].split(' ', 2)[0] == "case"
213
- push_and_tabulate([:script])
214
- end
212
+
213
+ case_stmt = text[1..-1].split(' ', 2)[0] == "case"
214
+ block = @block_opened && !mid_block_keyword?(text)
215
+ push_and_tabulate([:script]) if block || case_stmt
216
+ push_and_tabulate(nil) if block && case_stmt
215
217
  when FILTER; start_filtered(text[1..-1].downcase)
216
218
  when DOCTYPE
217
219
  return render_doctype(text) if text[0...3] == '!!!'
@@ -371,6 +373,7 @@ END
371
373
  when :loud; close_loud value
372
374
  when :filtered; close_filtered value
373
375
  when :haml_comment; close_haml_comment
376
+ when nil; close_nil
374
377
  end
375
378
  end
376
379
 
@@ -420,6 +423,10 @@ END
420
423
  @template_tabs -= 1
421
424
  end
422
425
 
426
+ def close_nil
427
+ @template_tabs -= 1
428
+ end
429
+
423
430
  # Iterates through the classes and ids supplied through <tt>.</tt>
424
431
  # and <tt>#</tt> syntax, and returns a hash with them as attributes,
425
432
  # that can then be merged with another attributes hash.
@@ -544,7 +551,7 @@ END
544
551
  preserve_tag &&= !options[:ugly]
545
552
 
546
553
  case action
547
- when '/'; self_closing = xhtml?
554
+ when '/'; self_closing = true
548
555
  when '~'; parse = preserve_script = true
549
556
  when '='
550
557
  parse = true
@@ -1,5 +1,5 @@
1
1
  dir = File.dirname(__FILE__)
2
- $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
2
+ $LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
3
3
 
4
4
  # = Sass (Syntactically Awesome StyleSheets)
5
5
  #
@@ -788,9 +788,9 @@ $LOAD_PATH << dir unless $LOAD_PATH.include?(dir)
788
788
  #
789
789
  # Sass::Plugin.options[:style] = :compact
790
790
  #
791
- # ...or by setting the <tt>Merb::Config[:sass]</tt> hash in <tt>init.rb</tt> in Merb...
791
+ # ...or by setting the <tt>Merb::Plugin.config[:sass]</tt> hash in <tt>init.rb</tt> in Merb...
792
792
  #
793
- # Merb::Config[:sass][:style] = :compact
793
+ # Merb::Plugin.config[:sass][:style] = :compact
794
794
  #
795
795
  # ...or by passing an options hash to Sass::Engine.new.
796
796
  # Available options are:
@@ -237,7 +237,7 @@ module Sass
237
237
  root.children.map! do |child|
238
238
  next child unless Tree::RuleNode === child && child.rule.include?(',')
239
239
  child.rule.split(',').map do |rule|
240
- node = Tree::RuleNode.new(rule, nil)
240
+ node = Tree::RuleNode.new(rule.strip, nil)
241
241
  node.children = child.children
242
242
  node
243
243
  end
@@ -278,7 +278,13 @@ END
278
278
  def parse_line(line)
279
279
  case line[0]
280
280
  when ATTRIBUTE_CHAR
281
- parse_attribute(line, ATTRIBUTE)
281
+ if line[1] != ATTRIBUTE_CHAR
282
+ parse_attribute(line, ATTRIBUTE)
283
+ else
284
+ # Support CSS3-style pseudo-elements,
285
+ # which begin with ::
286
+ Tree::RuleNode.new(line, @options[:style])
287
+ end
282
288
  when Constant::CONSTANT_CHAR
283
289
  parse_constant(line)
284
290
  when COMMENT_CHAR
@@ -365,7 +371,7 @@ END
365
371
  end
366
372
 
367
373
  def parse_mixin_definition(line)
368
- mixin_name = line[1..-1]
374
+ mixin_name = line[1..-1].strip
369
375
  @mixins[mixin_name] = []
370
376
  index = @line
371
377
  line, tabs = @lines[index]
@@ -440,15 +446,9 @@ END
440
446
 
441
447
  new_filename = find_full_path("#{filename}.sass", load_paths)
442
448
 
443
- if new_filename.nil?
444
- if was_sass
445
- raise Exception.new("File to import not found or unreadable: #{original_filename}.")
446
- else
447
- return filename + '.css'
448
- end
449
- else
450
- new_filename
451
- end
449
+ return new_filename if new_filename
450
+ return filename + '.css' unless was_sass
451
+ raise SyntaxError.new("File to import not found or unreadable: #{original_filename}.", @line)
452
452
  end
453
453
 
454
454
  def self.find_full_path(filename, load_paths)
@@ -12,6 +12,7 @@ END
12
12
  end
13
13
 
14
14
  require File.dirname(__FILE__) + '/../lib/haml'
15
+ require File.dirname(__FILE__) + '/linked_rails'
15
16
  %w[sass rubygems erb erubis markaby active_support action_controller
16
17
  action_view haml/template].each(&method(:require))
17
18
 
@@ -23,6 +24,17 @@ rescue LoadError
23
24
  raise "The Haml benchmarks require the benchwarmer gem, available from http://github.com/wycats/benchwarmer"
24
25
  end
25
26
 
27
+ def view
28
+ unless ActionView::Base.instance_methods.include? 'finder'
29
+ return ActionView::Base.new(File.dirname(__FILE__), vars)
30
+ end
31
+
32
+ # Rails >=2.1.0
33
+ base = ActionView::Base.new
34
+ base.finder.append_view_path(File.dirname(__FILE__))
35
+ base
36
+ end
37
+
26
38
  Benchmark.warmer(times) do
27
39
  columns :haml, :erb, :erubis, :mab
28
40
  titles :haml => "Haml", :erb => "ERB", :erubis => "Erubis", :mab => "Markaby"
@@ -53,7 +65,7 @@ Benchmark.warmer(times) do
53
65
  end
54
66
 
55
67
  report "ActionView" do
56
- @base = ActionView::Base.new(File.dirname(__FILE__))
68
+ @base = view
57
69
 
58
70
  # To cache the template
59
71
  @base.render 'haml/templates/standard'
@@ -64,7 +76,7 @@ Benchmark.warmer(times) do
64
76
  end
65
77
 
66
78
  report "ActionView with deep partials" do
67
- @base = ActionView::Base.new(File.dirname(__FILE__))
79
+ @base = view
68
80
 
69
81
  # To cache the template
70
82
  @base.render 'haml/templates/action_view'
@@ -135,6 +135,20 @@ END
135
135
  assert_equal("<img alt='' src='/foo.png' />\n", render("%img{:width => nil, :src => '/foo.png', :alt => String.new}"))
136
136
  end
137
137
 
138
+ def test_attr_hashes_not_modified
139
+ hash = {:color => 'red'}
140
+ assert_equal(<<HTML, render(<<HAML, :locals => {:hash => hash}))
141
+ <div color='red'></div>
142
+ <div class='special' color='red'></div>
143
+ <div color='red'></div>
144
+ HTML
145
+ %div{hash}
146
+ .special{hash}
147
+ %div{hash}
148
+ HAML
149
+ assert_equal(hash, {:color => 'red'})
150
+ end
151
+
138
152
  def test_end_of_file_multiline
139
153
  assert_equal("<p>0</p>\n<p>1</p>\n<p>2</p>\n", render("- for i in (0...3)\n %p= |\n i |"))
140
154
  end
@@ -184,6 +198,33 @@ RESULT
184
198
  SOURCE
185
199
  end
186
200
 
201
+ # Mostly a regression test
202
+ def test_both_case_indentation_work_with_deeply_nested_code
203
+ result = <<RESULT
204
+ <h2>
205
+ other
206
+ </h2>
207
+ RESULT
208
+ assert_equal(result, render(<<HAML))
209
+ - case 'other'
210
+ - when 'test'
211
+ %h2
212
+ hi
213
+ - when 'other'
214
+ %h2
215
+ other
216
+ HAML
217
+ assert_equal(result, render(<<HAML))
218
+ - case 'other'
219
+ - when 'test'
220
+ %h2
221
+ hi
222
+ - when 'other'
223
+ %h2
224
+ other
225
+ HAML
226
+ end
227
+
187
228
  # HTML escaping tests
188
229
 
189
230
  def test_ampersand_equals_should_escape
@@ -287,11 +328,11 @@ SOURCE
287
328
 
288
329
  def test_stop_eval
289
330
  assert_equal("", render("= 'Hello'", :suppress_eval => true))
290
- assert_equal("", render("- puts 'foo'", :suppress_eval => true))
331
+ assert_equal("", render("- haml_concat 'foo'", :suppress_eval => true))
291
332
  assert_equal("<div id='foo' yes='no' />\n", render("#foo{:yes => 'no'}/", :suppress_eval => true))
292
333
  assert_equal("<div id='foo' />\n", render("#foo{:yes => 'no', :call => a_function() }/", :suppress_eval => true))
293
334
  assert_equal("<div />\n", render("%div[1]/", :suppress_eval => true))
294
- assert_equal("", render(":ruby\n puts 'hello'", :suppress_eval => true))
335
+ assert_equal("", render(":ruby\n Kernel.puts 'hello'", :suppress_eval => true))
295
336
  end
296
337
 
297
338
  def test_attr_wrapper
@@ -540,8 +581,11 @@ END
540
581
  assert_equal "<div class='foo'></div>\n", render(".foo", :format => :html4)
541
582
  end
542
583
 
543
- def test_html_ignores_explicit_self_closing_declaration
544
- assert_equal "<a></a>\n", render("%a/", :format => :html4)
584
+ def test_html_doesnt_add_slash_to_self_closing_tags
585
+ assert_equal "<a>\n", render("%a/", :format => :html4)
586
+ assert_equal "<a foo='2'>\n", render("%a{:foo => 1 + 1}/", :format => :html4)
587
+ assert_equal "<meta>\n", render("%meta", :format => :html4)
588
+ assert_equal "<meta foo='2'>\n", render("%meta{:foo => 1 + 1}", :format => :html4)
545
589
  end
546
590
 
547
591
  def test_html_ignores_xml_prolog_declaration
@@ -148,7 +148,7 @@ class HelperTest < Test::Unit::TestCase
148
148
  Haml::Helpers.module_eval do
149
149
  def trc(collection, &block)
150
150
  collection.each do |record|
151
- puts capture_haml(record, &block)
151
+ haml_concat capture_haml(record, &block)
152
152
  end
153
153
  end
154
154
  end
@@ -175,7 +175,7 @@ class HelperTest < Test::Unit::TestCase
175
175
 
176
176
  result = context.capture_haml do
177
177
  context.haml_tag :p, :attr => "val" do
178
- context.puts "Blah"
178
+ context.haml_concat "Blah"
179
179
  end
180
180
  end
181
181
 
@@ -40,6 +40,41 @@ class Html2HamlTest < Test::Unit::TestCase
40
40
  assert_equal '= h @item.title', render_rhtml('<%=h @item.title %>')
41
41
  assert_equal '= h @item.title', render_rhtml('<%=h @item.title -%>')
42
42
  end
43
+
44
+ def test_rhtml_with_html_special_chars
45
+ assert_equal '= 3 < 5 ? "OK" : "Your computer is b0rken"',
46
+ render_rhtml(%Q{<%= 3 < 5 ? "OK" : "Your computer is b0rken" %>})
47
+ end
48
+
49
+ def test_rhtml_in_class_attribute
50
+ assert_equal "%div{ :class => dyna_class }\n I have a dynamic attribute",
51
+ render_rhtml(%Q{<div class="<%= dyna_class %>">I have a dynamic attribute</div>})
52
+ end
53
+
54
+ def test_rhtml_in_id_attribute
55
+ assert_equal "%div{ :id => dyna_id }\n I have a dynamic attribute",
56
+ render_rhtml(%Q{<div id="<%= dyna_id %>">I have a dynamic attribute</div>})
57
+ end
58
+
59
+ def test_rhtml_in_attribute_results_in_string_interpolation
60
+ assert_equal %(%div{ :id => "item_\#{i}" }\n Ruby string interpolation FTW),
61
+ render_rhtml(%Q{<div id="item_<%= i %>">Ruby string interpolation FTW</div>})
62
+ end
63
+
64
+ def test_rhtml_in_attribute_with_trailing_content
65
+ assert_equal %(%div{ :class => "\#{12}!" }\n Bang!),
66
+ render_rhtml(%Q{<div class="<%= 12 %>!">Bang!</div>})
67
+ end
68
+
69
+ def test_rhtml_in_attribute_to_multiple_interpolations
70
+ assert_equal %(%div{ :class => "\#{12} + \#{13}" }\n Math is super),
71
+ render_rhtml(%Q{<div class="<%= 12 %> + <%= 13 %>">Math is super</div>})
72
+ end
73
+
74
+ def test_whitespace_eating_erb_tags
75
+ assert_equal %(- form_for),
76
+ render_rhtml(%Q{<%- form_for -%>})
77
+ end
43
78
 
44
79
  protected
45
80
 
@@ -0,0 +1,5 @@
1
+ <h1>Partial layout used with for block:</h1>
2
+ <div class='partial-layout'>
3
+ <h2>This is inside a partial layout</h2>
4
+ <p>Some content within a layout</p>
5
+ </div>
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  require File.dirname(__FILE__) + '/../test_helper'
3
3
  require 'haml/template'
4
+ require 'sass/plugin'
4
5
  require File.dirname(__FILE__) + '/mocks/article'
5
6
 
6
7
  module Haml::Filters::Test
@@ -17,11 +18,17 @@ module Haml::Helpers
17
18
  end
18
19
  end
19
20
 
21
+ class DummyController
22
+ def self.controller_path
23
+ ''
24
+ end
25
+ end
26
+
20
27
  class TemplateTest < Test::Unit::TestCase
21
28
  TEMPLATE_PATH = File.join(File.dirname(__FILE__), "templates")
22
29
  TEMPLATES = %w{ very_basic standard helpers
23
30
  whitespace_handling original_engine list helpful
24
- silent_script tag_parsing just_stuff partials
31
+ silent_script tag_parsing just_stuff partials partial_layout
25
32
  filters nuke_outer_whitespace nuke_inner_whitespace }
26
33
 
27
34
  def setup
@@ -35,11 +42,21 @@ class TemplateTest < Test::Unit::TestCase
35
42
  @base.finder.append_view_path(TEMPLATE_PATH)
36
43
  end
37
44
 
38
- @base.send(:evaluate_assigns)
45
+ if @base.private_methods.include?('evaluate_assigns')
46
+ @base.send(:evaluate_assigns)
47
+ else
48
+ # Rails 2.2
49
+ @base.send(:_evaluate_assigns_and_ivars)
50
+ end
39
51
 
40
52
  # This is used by form_for.
41
53
  # It's usually provided by ActionController::Base.
42
54
  def @base.protect_against_forgery?; false; end
55
+
56
+ # filters template uses :sass
57
+ Sass::Plugin.options.update(:line_comments => true, :style => :compact)
58
+
59
+ @base.controller = DummyController.new
43
60
  end
44
61
 
45
62
  def render(text)
@@ -0,0 +1,3 @@
1
+ .partial-layout
2
+ %h2 This is inside a partial layout
3
+ = yield
@@ -1,6 +1,6 @@
1
1
  = "not me!"
2
2
  = "nor me!"
3
- - puts "not even me!"
3
+ - haml_concat "not even me!"
4
4
  %p= "NO!"
5
5
  %p~ "UH-UH!"
6
6
  %h1 Me!
@@ -52,18 +52,18 @@ click
52
52
  = list_of({:google => 'http://www.google.com'}) do |name, link|
53
53
  %a{ :href => link }= name
54
54
  %p
55
- - puts "foo"
55
+ - haml_concat "foo"
56
56
  %div
57
- - puts "bar"
58
- - puts "boom"
57
+ - haml_concat "bar"
58
+ - haml_concat "boom"
59
59
  baz
60
- - puts "boom, again"
60
+ - haml_concat "boom, again"
61
61
  - haml_tag :table do
62
62
  - haml_tag :tr do
63
63
  - haml_tag :td, {:class => 'cell'} do
64
64
  - haml_tag :strong, "strong!"
65
- - puts "data"
65
+ - haml_concat "data"
66
66
  - haml_tag :td do
67
- - puts "more_data"
67
+ - haml_concat "more_data"
68
68
  - haml_tag :hr
69
69
  - haml_tag :div, ''
@@ -0,0 +1,3 @@
1
+ %h1 Partial layout used with for block:
2
+ - render :layout => 'layout_for_partial.haml' do
3
+ %p Some content within a layout
@@ -0,0 +1,12 @@
1
+ # allows testing with edge Rails by creating a test/rails symlink
2
+ linked_rails = File.dirname(__FILE__) + '/rails'
3
+
4
+ if File.exists?(linked_rails) && !$:.include?(linked_rails + '/activesupport/lib')
5
+ puts "[ using linked Rails ]"
6
+ $:.unshift linked_rails + '/activesupport/lib'
7
+ $:.unshift linked_rails + '/actionpack/lib'
8
+ else
9
+ require 'rubygems'
10
+ end
11
+ require 'action_controller'
12
+ require 'action_view'
@@ -174,6 +174,16 @@ END
174
174
  end
175
175
  end
176
176
 
177
+ def test_pseudo_elements
178
+ assert_equal(<<CSS, render(<<SASS))
179
+ ::first-line {
180
+ size: 10em; }
181
+ CSS
182
+ ::first-line
183
+ size: 10em
184
+ SASS
185
+ end
186
+
177
187
  def test_directive
178
188
  assert_equal("@a b;", render("@a b"))
179
189
 
@@ -1,8 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
-
3
- MERB_ENV = RAILS_ENV = 'testing'
4
- RAILS_ROOT = '.'
5
-
6
2
  require File.dirname(__FILE__) + '/../test_helper'
7
3
  require 'sass/plugin'
8
4
  require 'fileutils'
@@ -1,18 +1,13 @@
1
1
  lib_dir = File.dirname(__FILE__) + '/../lib'
2
- # allows testing with edge Rails by creating a test/rails symlink
3
- linked_rails = File.dirname(__FILE__) + '/rails'
4
-
5
- if File.exists?(linked_rails) && !$:.include?(linked_rails + '/activesupport/lib')
6
- puts "[ using linked Rails ]"
7
- $:.unshift linked_rails + '/activesupport/lib'
8
- $:.unshift linked_rails + '/actionpack/lib'
9
- else
10
- require 'rubygems'
11
- end
12
- require 'action_controller'
13
- require 'action_view'
2
+ require File.dirname(__FILE__) + '/linked_rails'
14
3
 
15
4
  require 'test/unit'
16
5
  $:.unshift lib_dir unless $:.include?(lib_dir)
17
6
  require 'haml'
18
7
  require 'sass'
8
+
9
+ # required because of Sass::Plugin
10
+ unless defined? RAILS_ROOT
11
+ RAILS_ROOT = '.'
12
+ MERB_ENV = RAILS_ENV = 'testing'
13
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haml
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Weizenbaum
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2008-09-07 00:00:00 -07:00
13
+ date: 2008-10-30 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -134,6 +134,7 @@ files:
134
134
  - test/haml/templates/_partial.haml
135
135
  - test/haml/templates/nuke_outer_whitespace.haml
136
136
  - test/haml/templates/_av_partial_2.haml
137
+ - test/haml/templates/partial_layout.haml
137
138
  - test/haml/templates/helpful.haml
138
139
  - test/haml/templates/just_stuff.haml
139
140
  - test/haml/templates/silent_script.haml
@@ -145,6 +146,7 @@ files:
145
146
  - test/haml/templates/partials.haml
146
147
  - test/haml/templates/standard.haml
147
148
  - test/haml/templates/partialize.haml
149
+ - test/haml/templates/_layout_for_partial.haml
148
150
  - test/haml/templates/_av_partial_1.haml
149
151
  - test/haml/templates/filters.haml
150
152
  - test/haml/templates/content_for_layout.haml
@@ -168,10 +170,12 @@ files:
168
170
  - test/haml/results/original_engine.xhtml
169
171
  - test/haml/results/helpers.xhtml
170
172
  - test/haml/results/list.xhtml
173
+ - test/haml/results/partial_layout.xhtml
171
174
  - test/haml/results/tag_parsing.xhtml
172
175
  - test/haml/markaby
173
176
  - test/haml/markaby/standard.mab
174
177
  - test/haml/engine_test.rb
178
+ - test/linked_rails.rb
175
179
  - test/rails
176
180
  - test/benchmark.rb
177
181
  - test/test_helper.rb
@@ -211,7 +215,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
211
215
  requirements: []
212
216
 
213
217
  rubyforge_project: haml
214
- rubygems_version: 1.1.1
218
+ rubygems_version: 1.3.0
215
219
  signing_key:
216
220
  specification_version: 2
217
221
  summary: An elegant, structured XHTML/XML templating engine. Comes with Sass, a similar CSS templating engine.