haml 2.0.2 → 2.0.3

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.

@@ -8,7 +8,7 @@ module Sass::Constant # :nodoc:
8
8
  def parse(value)
9
9
  first, second, unit = value.scan(Literal::NUMBER)[0]
10
10
  @value = first.empty? ? second.to_i : "#{first}#{second}".to_f
11
- @unit = unit unless unit.empty?
11
+ @unit = unit.empty? ? nil : unit
12
12
  end
13
13
 
14
14
  def plus(other)
@@ -18,7 +18,7 @@ module Sass
18
18
  end
19
19
 
20
20
  class ValueNode
21
- def to_sass(tabs)
21
+ def to_sass(tabs, opts = {})
22
22
  "#{value}\n"
23
23
  end
24
24
  end
@@ -40,6 +40,12 @@ module Sass
40
40
  "#{' ' * tabs}#{opts[:alternate] ? '' : ':'}#{name}#{opts[:alternate] ? ':' : ''} #{value}\n"
41
41
  end
42
42
  end
43
+
44
+ class DirectiveNode
45
+ def to_sass(tabs, opts = {})
46
+ "#{' ' * tabs}#{value}#{children.map {|c| c.to_sass(tabs + 1, opts)}}\n"
47
+ end
48
+ end
43
49
  end
44
50
 
45
51
  # This class is based on the Ruby 1.9 ordered hashes.
@@ -118,7 +124,7 @@ module Sass
118
124
  # containing the CSS template.
119
125
  def render
120
126
  begin
121
- build_tree.to_sass(@options).lstrip
127
+ build_tree.to_sass(@options).strip + "\n"
122
128
  rescue Exception => err
123
129
  line = @template.string[0...@template.pos].split("\n").size
124
130
 
@@ -132,7 +138,6 @@ module Sass
132
138
  def build_tree
133
139
  root = Tree::Node.new(nil)
134
140
  whitespace
135
- directives root
136
141
  rules root
137
142
  expand_commas root
138
143
  parent_ref_rules root
@@ -142,37 +147,33 @@ module Sass
142
147
  root
143
148
  end
144
149
 
145
- def directives(root)
146
- while @template.scan(/@/)
147
- name = @template.scan /[^\s;]+/
148
- whitespace
149
- value = @template.scan /[^;]+/
150
- assert_match /;/
150
+ def rules(root)
151
+ while r = rule
152
+ root << r
151
153
  whitespace
152
-
153
- if name == "import" && value =~ /^(url\()?"?([^\s\(\)\"]+)\.css"?\)?$/
154
- value = $2
155
- end
156
-
157
- root << Tree::ValueNode.new("@#{name} #{value};", nil)
158
154
  end
159
155
  end
160
156
 
161
- def rules(root)
162
- rules = []
163
- while @template.scan(/[^\{\s]+/)
164
- rules << @template[0]
165
- whitespace
157
+ def rule
158
+ return unless rule = @template.scan(/[^\{\};]+/)
159
+ rule.strip!
160
+ directive = rule[0] == ?@
166
161
 
167
- if @template.scan(/\{/)
168
- result = Tree::RuleNode.new(rules.join(' '), nil)
169
- root << result
170
- rules = []
162
+ if directive
163
+ node = Tree::DirectiveNode.new(rule, nil)
164
+ return node if @template.scan(/;/)
171
165
 
172
- whitespace
173
- attributes(result)
174
- end
166
+ assert_match /\{/
167
+ whitespace
168
+
169
+ rules(node)
170
+ return node
175
171
  end
172
+
173
+ assert_match /\{/
174
+ node = Tree::RuleNode.new(rule, nil)
175
+ attributes(node)
176
+ return node
176
177
  end
177
178
 
178
179
  def attributes(rule)
@@ -4,7 +4,7 @@ module Sass
4
4
  # and the Sass file that was being parsed (if applicable).
5
5
  # It also provides a handy way to rescue only exceptions raised
6
6
  # because of a faulty template.
7
- class SyntaxError < Exception
7
+ class SyntaxError < StandardError
8
8
  # The line of the Sass template on which the exception was thrown.
9
9
  attr_accessor :sass_line
10
10
 
@@ -34,6 +34,13 @@ module Sass
34
34
  @@options.merge!(value)
35
35
  end
36
36
 
37
+ # Get the options ready to be passed to the Sass::Engine
38
+ def engine_options(additional_options = {})
39
+ opts = options.dup.merge(additional_options)
40
+ opts[:load_paths] = load_paths(opts)
41
+ opts
42
+ end
43
+
37
44
  # Checks each stylesheet in <tt>options[:css_location]</tt>
38
45
  # to see if it needs updating,
39
46
  # and updates it using the corresponding template
@@ -53,10 +60,7 @@ module Sass
53
60
  File.delete(css) if File.exists?(css)
54
61
 
55
62
  filename = template_filename(name)
56
- l_options = @@options.dup
57
- l_options[:filename] = filename
58
- l_options[:load_paths] = load_paths
59
- engine = Engine.new(File.read(filename), l_options)
63
+ engine = Engine.new(File.read(filename), engine_options(:filename => filename))
60
64
  result = begin
61
65
  engine.render
62
66
  rescue Exception => e
@@ -64,7 +68,7 @@ module Sass
64
68
  end
65
69
 
66
70
  # Create any directories that might be necessary
67
- dirs = [l_options[:css_location]]
71
+ dirs = [options[:css_location]]
68
72
  name.split("/")[0...-1].each { |dir| dirs << "#{dirs[-1]}/#{dir}" }
69
73
  dirs.each { |dir| Dir.mkdir(dir) unless File.exist?(dir) }
70
74
 
@@ -78,8 +82,8 @@ module Sass
78
82
 
79
83
  private
80
84
 
81
- def load_paths
82
- (options[:load_paths] || []) + [options[:template_location]]
85
+ def load_paths(opts = options)
86
+ (opts[:load_paths] || []) + [options[:template_location]]
83
87
  end
84
88
 
85
89
  def exception_string(e)
@@ -6,7 +6,7 @@ unless defined?(Sass::MERB_LOADED)
6
6
  root = MERB_ROOT
7
7
  env = MERB_ENV
8
8
  else
9
- root = Merb.root
9
+ root = Merb.root.to_s
10
10
  env = Merb.environment
11
11
  end
12
12
 
@@ -0,0 +1 @@
1
+ Kernel.load File.join(File.dirname(__FILE__), '..', 'init.rb')
@@ -2,7 +2,7 @@
2
2
  require File.dirname(__FILE__) + '/../test_helper'
3
3
 
4
4
  class EngineTest < Test::Unit::TestCase
5
- # A map of erroneous Sass documents to the error messages they should produce.
5
+ # A map of erroneous Haml documents to the error messages they should produce.
6
6
  # The error messages may be arrays;
7
7
  # if so, the second element should be the line number that should be reported for the error.
8
8
  # If this isn't provided, the tests will assume the line number should be the last line of the document.
@@ -34,13 +34,7 @@ END
34
34
  "%a/ b" => "Self-closing tags can't have content.",
35
35
  " %p foo" => "Indenting at the beginning of the document is illegal.",
36
36
  " %p foo" => "Indenting at the beginning of the document is illegal.",
37
- "- end" => <<END.rstrip,
38
- You don't need to use "- end" in Haml. Use indentation instead:
39
- - if foo?
40
- %strong Foo!
41
- - else
42
- Not foo.
43
- END
37
+ "- end" => "You don't need to use \"- end\" in Haml. Use indentation instead:\n- if foo?\n %strong Foo!\n- else\n Not foo.",
44
38
  " \n\t\n %p foo" => ["Indenting at the beginning of the document is illegal.", 3],
45
39
 
46
40
  # Regression tests
@@ -64,9 +58,19 @@ END
64
58
  def render(text, options = {}, &block)
65
59
  scope = options.delete(:scope) || Object.new
66
60
  locals = options.delete(:locals) || {}
67
- Haml::Engine.new(text, options).to_html(scope, locals, &block)
61
+ engine(text, options).to_html(scope, locals, &block)
68
62
  end
69
-
63
+
64
+ def engine(text, options = {})
65
+ unless options[:filename]
66
+ # use caller method name as fake filename. useful for debugging
67
+ i = -1
68
+ caller[i+=1] =~ /`(.+?)'/ until $1 and $1.index('test_') == 0
69
+ options[:filename] = "(#{$1})"
70
+ end
71
+ Haml::Engine.new(text, options)
72
+ end
73
+
70
74
  def test_empty_render_should_remain_empty
71
75
  assert_equal('', render(''))
72
76
  end
@@ -99,7 +103,7 @@ END
99
103
  end
100
104
 
101
105
  def test_multi_render
102
- engine = Haml::Engine.new("%strong Hi there!")
106
+ engine = engine("%strong Hi there!")
103
107
  assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
104
108
  assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
105
109
  assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
@@ -190,6 +194,10 @@ SOURCE
190
194
  assert_equal("<p>foo &amp; bar</p>\n", render("%p&= 'foo & bar'", :escape_html => false))
191
195
  end
192
196
 
197
+ def test_ampersand_equals_should_escape_before_preserve
198
+ assert_equal("<textarea>foo&#x000A;bar</textarea>\n", render('%textarea&= "foo\nbar"', :escape_html => false))
199
+ end
200
+
193
201
  def test_bang_equals_should_not_escape
194
202
  assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n != 'foo & bar'", :escape_html => true))
195
203
  end
@@ -266,14 +274,14 @@ SOURCE
266
274
  render("\n\n = abc", :filename => 'test', :line => 2)
267
275
  rescue Exception => e
268
276
  assert_kind_of Haml::SyntaxError, e
269
- assert_match /test:4/, e.backtrace.first
277
+ assert_match(/test:4/, e.backtrace.first)
270
278
  end
271
279
 
272
280
  begin
273
281
  render("\n\n= 123\n\n= nil[]", :filename => 'test', :line => 2)
274
282
  rescue Exception => e
275
283
  assert_kind_of NoMethodError, e
276
- assert_match /test:6/, e.backtrace.first
284
+ assert_match(/test:6/, e.backtrace.first)
277
285
  end
278
286
  end
279
287
 
@@ -360,12 +368,15 @@ SOURCE
360
368
  def test_exceptions
361
369
  EXCEPTION_MAP.each do |key, value|
362
370
  begin
363
- render(key)
371
+ render(key, :filename => "(exception test for #{key.inspect})")
364
372
  rescue Exception => err
365
373
  value = [value] unless value.is_a?(Array)
374
+ expected_message, line_no = value
375
+ line_no ||= key.split("\n").length
376
+ line_reported = err.backtrace[0].gsub(/\(.+\):/, '').to_i
366
377
 
367
- assert_equal(value.first, err.message, "Line: #{key}")
368
- assert_equal(value[1] || key.split("\n").length, err.backtrace[0].gsub('(haml):', '').to_i, "Line: #{key}")
378
+ assert_equal(expected_message, err.message, "Line: #{key}")
379
+ assert_equal(line_no, line_reported, "Line: #{key}")
369
380
  else
370
381
  assert(false, "Exception not raised for\n#{key}")
371
382
  end
@@ -375,7 +386,7 @@ SOURCE
375
386
  def test_exception_line
376
387
  render("a\nb\n!!!\n c\nd")
377
388
  rescue Haml::SyntaxError => e
378
- assert_equal("(haml):4", e.backtrace[0])
389
+ assert_equal("(test_exception_line):4", e.backtrace[0])
379
390
  else
380
391
  assert(false, '"a\nb\n!!!\n c\nd" doesn\'t produce an exception')
381
392
  end
@@ -383,7 +394,7 @@ SOURCE
383
394
  def test_exception
384
395
  render("%p\n hi\n %a= undefined\n= 12")
385
396
  rescue Exception => e
386
- assert_match("(haml):3", e.backtrace[0])
397
+ assert_match("(test_exception):3", e.backtrace[0])
387
398
  else
388
399
  # Test failed... should have raised an exception
389
400
  assert(false)
@@ -392,7 +403,7 @@ SOURCE
392
403
  def test_compile_error
393
404
  render("a\nb\n- fee)\nc")
394
405
  rescue Exception => e
395
- assert_match(/^compile error\n\(haml\):3: syntax error/i, e.message)
406
+ assert_match(/^compile error\n\(test_compile_error\):3: syntax error/i, e.message)
396
407
  else
397
408
  assert(false,
398
409
  '"a\nb\n- fee)\nc" doesn\'t produce an exception!')
@@ -409,76 +420,6 @@ SOURCE
409
420
  render("/[if !(IE 6)|(IE 7)] Bracket: ]"))
410
421
  end
411
422
 
412
- def test_no_bluecloth
413
- Kernel.module_eval do
414
- def gem_original_require_with_bluecloth(file)
415
- raise LoadError if file == 'bluecloth'
416
- gem_original_require_without_bluecloth(file)
417
- end
418
- alias_method :gem_original_require_without_bluecloth, :gem_original_require
419
- alias_method :gem_original_require, :gem_original_require_with_bluecloth
420
- end
421
-
422
- begin
423
- assert_equal("<h1>Foo</h1>\t<p>- a\n- b</p>\n",
424
- Haml::Engine.new(":markdown\n Foo\n ===\n - a\n - b").to_html)
425
- rescue Haml::Error => e
426
- if e.message == "Can't run Markdown filter; required 'bluecloth' or 'redcloth', but none were found"
427
- puts "\nCouldn't require 'bluecloth' or 'redcloth'; skipping a test."
428
- else
429
- raise e
430
- end
431
- end
432
-
433
- Kernel.module_eval do
434
- alias_method :gem_original_require, :gem_original_require_without_bluecloth
435
- end
436
- end
437
-
438
- def test_no_redcloth
439
- Kernel.module_eval do
440
- def gem_original_require_with_redcloth(file)
441
- raise LoadError if file == 'redcloth'
442
- gem_original_require_without_redcloth(file)
443
- end
444
- alias_method :gem_original_require_without_redcloth, :gem_original_require
445
- alias_method :gem_original_require, :gem_original_require_with_redcloth
446
- end
447
-
448
- begin
449
- Haml::Engine.new(":redcloth\n _foo_").to_html
450
- rescue Haml::Error
451
- else
452
- assert(false, "No exception raised!")
453
- end
454
-
455
- Kernel.module_eval do
456
- alias_method :gem_original_require, :gem_original_require_without_redcloth
457
- end
458
- end
459
-
460
- def test_no_redcloth_or_bluecloth
461
- Kernel.module_eval do
462
- def gem_original_require_with_redcloth_and_bluecloth(file)
463
- raise LoadError if file == 'redcloth' || file == 'bluecloth'
464
- gem_original_require_without_redcloth_and_bluecloth(file)
465
- end
466
- alias_method :gem_original_require_without_redcloth_and_bluecloth, :gem_original_require
467
- alias_method :gem_original_require, :gem_original_require_with_redcloth_and_bluecloth
468
- end
469
-
470
- begin
471
- Haml::Engine.new(":markdown\n _foo_").to_html
472
- rescue Haml::Error
473
- else
474
- assert(false, "No exception raised!")
475
- end
476
-
477
- Kernel.module_eval do
478
- alias_method :gem_original_require, :gem_original_require_without_redcloth_and_bluecloth
479
- end
480
- end
481
-
482
423
  def test_empty_filter
483
424
  assert_equal(<<END, render(':javascript'))
484
425
  <script type='text/javascript'>
@@ -537,28 +478,28 @@ END
537
478
 
538
479
  def test_yield_should_work_with_def_method
539
480
  s = "foo"
540
- Haml::Engine.new("= yield\n= upcase").def_method(s, :render)
481
+ engine("= yield\n= upcase").def_method(s, :render)
541
482
  assert_equal("12\nFOO\n", s.render { 12 })
542
483
  end
543
484
 
544
485
  def test_def_method_with_module
545
- Haml::Engine.new("= yield\n= upcase").def_method(String, :render_haml)
486
+ engine("= yield\n= upcase").def_method(String, :render_haml)
546
487
  assert_equal("12\nFOO\n", "foo".render_haml { 12 })
547
488
  end
548
489
 
549
490
  def test_def_method_locals
550
491
  obj = Object.new
551
- Haml::Engine.new("%p= foo\n.bar{:baz => baz}= boom").def_method(obj, :render, :foo, :baz, :boom)
492
+ engine("%p= foo\n.bar{:baz => baz}= boom").def_method(obj, :render, :foo, :baz, :boom)
552
493
  assert_equal("<p>1</p>\n<div baz='2' class='bar'>3</div>\n", obj.render(:foo => 1, :baz => 2, :boom => 3))
553
494
  end
554
495
 
555
496
  def test_render_proc_locals
556
- proc = Haml::Engine.new("%p= foo\n.bar{:baz => baz}= boom").render_proc(Object.new, :foo, :baz, :boom)
497
+ proc = engine("%p= foo\n.bar{:baz => baz}= boom").render_proc(Object.new, :foo, :baz, :boom)
557
498
  assert_equal("<p>1</p>\n<div baz='2' class='bar'>3</div>\n", proc[:foo => 1, :baz => 2, :boom => 3])
558
499
  end
559
500
 
560
501
  def test_render_proc_with_binding
561
- assert_equal("FOO\n", Haml::Engine.new("= upcase").render_proc("foo".instance_eval{binding}).call)
502
+ assert_equal("FOO\n", engine("= upcase").render_proc("foo".instance_eval{binding}).call)
562
503
  end
563
504
 
564
505
  def test_ugly_true
@@ -585,7 +526,7 @@ END
585
526
  end
586
527
 
587
528
  def test_arbitrary_output_option
588
- assert_raise(Haml::Error, "Invalid output format :html1") { Haml::Engine.new("%br", :format => :html1) }
529
+ assert_raise(Haml::Error, "Invalid output format :html1") { engine("%br", :format => :html1) }
589
530
  end
590
531
 
591
532
  # HTML 4.0
@@ -614,7 +555,7 @@ END
614
555
 
615
556
  # because anything before the doctype triggers quirks mode in IE
616
557
  def test_xml_prolog_and_doctype_dont_result_in_a_leading_whitespace_in_html
617
- assert_no_match /^\s+/, render("!!! xml\n!!!", :format => :html4)
558
+ assert_no_match(/^\s+/, render("!!! xml\n!!!", :format => :html4))
618
559
  end
619
560
 
620
561
  # HTML5
@@ -52,7 +52,8 @@ class Html2HamlTest < Test::Unit::TestCase
52
52
  end
53
53
 
54
54
  def assert_equal_attributes(expected, result)
55
- assert_equal *[expected, result].map { |s| s.gsub!(/\{ (.+) \}/, ''); $1.split(', ').sort }
55
+ expected_attr, result_attr = [expected, result].map { |s| s.gsub!(/\{ (.+) \}/, ''); $1.split(', ').sort }
56
+ assert_equal expected_attr, result_attr
56
57
  assert_equal expected, result
57
58
  end
58
59
  end
@@ -1,24 +1,9 @@
1
1
  <style>
2
- p {
3
- border-style: dotted;
4
- border-width: 22px;
5
- border-color: #ff00ff; }
2
+ p { border-style: dotted; border-width: 22px; border-color: #ff00ff; }
6
3
 
7
- h1 {
8
- font-weight: normal; }
4
+ h1 { font-weight: normal; }
9
5
  </style>
10
6
  TESTING HAHAHAHA!
11
- <h1>Foo</h1>
12
-
13
-
14
- <pre><code>This is preformatted!&#x000A;Look at that!&#x000A;Wowie-zowie!</code></pre>
15
-
16
-
17
- <p><strong>boldilicious!</strong></p>
18
- <h1>Yeah</h1>
19
-
20
-
21
- <p><em>pretty much the same as above</em></p>
22
7
  <p>
23
8
  <script type='text/javascript'>
24
9
  //<![CDATA[
@@ -67,12 +52,6 @@ This
67
52
 
68
53
  </ul>
69
54
  <div class='res'>178</div>
70
- <p>
71
- <p>I like preserved text:</p>
72
-
73
-
74
- <pre><code>Foo&#x000A; Bar!&#x000A;Baz</code></pre>
75
- </p>
76
55
  <ul>
77
56
  <li>Foo</li>
78
57
  <li>Bar</li>