haml 4.1.0.beta.1 → 5.0.0.beta.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of haml might be problematic. Click here for more details.

Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +36 -6
  4. data/FAQ.md +4 -14
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +81 -48
  7. data/REFERENCE.md +86 -50
  8. data/Rakefile +28 -41
  9. data/lib/haml/attribute_builder.rb +163 -0
  10. data/lib/haml/attribute_compiler.rb +214 -0
  11. data/lib/haml/attribute_parser.rb +112 -0
  12. data/lib/haml/buffer.rb +24 -126
  13. data/lib/haml/compiler.rb +62 -281
  14. data/lib/haml/engine.rb +16 -23
  15. data/lib/haml/error.rb +2 -0
  16. data/lib/haml/escapable.rb +48 -0
  17. data/lib/haml/exec.rb +23 -12
  18. data/lib/haml/filters.rb +3 -4
  19. data/lib/haml/generator.rb +36 -0
  20. data/lib/haml/helpers.rb +61 -48
  21. data/lib/haml/helpers/action_view_extensions.rb +1 -1
  22. data/lib/haml/helpers/action_view_mods.rb +32 -50
  23. data/lib/haml/helpers/safe_erubi_template.rb +26 -0
  24. data/lib/haml/helpers/safe_erubis_template.rb +2 -0
  25. data/lib/haml/helpers/xss_mods.rb +17 -12
  26. data/lib/haml/options.rb +32 -36
  27. data/lib/haml/parser.rb +61 -38
  28. data/lib/haml/{template/plugin.rb → plugin.rb} +5 -2
  29. data/lib/haml/railtie.rb +14 -6
  30. data/lib/haml/template.rb +11 -6
  31. data/lib/haml/temple_engine.rb +119 -0
  32. data/lib/haml/temple_line_counter.rb +28 -0
  33. data/lib/haml/util.rb +17 -112
  34. data/lib/haml/version.rb +1 -1
  35. data/test/attribute_parser_test.rb +105 -0
  36. data/test/engine_test.rb +202 -106
  37. data/test/filters_test.rb +32 -19
  38. data/test/gemfiles/Gemfile.rails-4.0.x +7 -1
  39. data/test/gemfiles/Gemfile.rails-4.0.x.lock +57 -71
  40. data/test/gemfiles/Gemfile.rails-4.1.x +5 -0
  41. data/test/gemfiles/Gemfile.rails-4.2.x +5 -0
  42. data/test/gemfiles/Gemfile.rails-5.0.x +4 -0
  43. data/test/helper_test.rb +156 -109
  44. data/test/options_test.rb +21 -0
  45. data/test/parser_test.rb +49 -4
  46. data/test/results/eval_suppressed.xhtml +4 -4
  47. data/test/results/helpers.xhtml +43 -41
  48. data/test/results/helpful.xhtml +6 -3
  49. data/test/results/just_stuff.xhtml +21 -20
  50. data/test/results/list.xhtml +9 -9
  51. data/test/results/nuke_inner_whitespace.xhtml +22 -22
  52. data/test/results/nuke_outer_whitespace.xhtml +84 -92
  53. data/test/results/original_engine.xhtml +17 -17
  54. data/test/results/partial_layout.xhtml +4 -3
  55. data/test/results/partial_layout_erb.xhtml +4 -3
  56. data/test/results/partials.xhtml +11 -10
  57. data/test/results/silent_script.xhtml +63 -63
  58. data/test/results/standard.xhtml +156 -159
  59. data/test/results/tag_parsing.xhtml +19 -19
  60. data/test/results/very_basic.xhtml +2 -2
  61. data/test/results/whitespace_handling.xhtml +77 -76
  62. data/test/template_test.rb +21 -48
  63. data/test/template_test_helper.rb +38 -0
  64. data/test/templates/just_stuff.haml +1 -0
  65. data/test/templates/standard_ugly.haml +1 -0
  66. data/test/temple_line_counter_test.rb +40 -0
  67. data/test/test_helper.rb +10 -10
  68. data/test/util_test.rb +1 -48
  69. metadata +49 -35
  70. data/lib/haml/temple.rb +0 -85
  71. data/test/gemfiles/Gemfile.rails-3.2.x +0 -4
  72. data/test/templates/_av_partial_1_ugly.haml +0 -9
  73. data/test/templates/_av_partial_2_ugly.haml +0 -5
  74. data/test/templates/action_view_ugly.haml +0 -47
  75. data/test/templates/standard_ugly.haml +0 -43
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  require 'test_helper'
3
3
 
4
- class EngineTest < MiniTest::Unit::TestCase
4
+ class EngineTest < Haml::TestCase
5
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.
@@ -126,11 +126,11 @@ class EngineTest < MiniTest::Unit::TestCase
126
126
  end
127
127
 
128
128
  def test_flexible_tabulation
129
- assert_equal("<p>\n foo\n</p>\n<q>\n bar\n <a>\n baz\n </a>\n</q>\n",
129
+ assert_equal("<p>\nfoo\n</p>\n<q>\nbar\n<a>\nbaz\n</a>\n</q>\n",
130
130
  render("%p\n foo\n%q\n bar\n %a\n baz"))
131
- assert_equal("<p>\n foo\n</p>\n<q>\n bar\n <a>\n baz\n </a>\n</q>\n",
131
+ assert_equal("<p>\nfoo\n</p>\n<q>\nbar\n<a>\nbaz\n</a>\n</q>\n",
132
132
  render("%p\n\tfoo\n%q\n\tbar\n\t%a\n\t\tbaz"))
133
- assert_equal("<p>\n \t \t bar\n baz\n</p>\n",
133
+ assert_equal("<p>\n \t \t bar\n baz\n</p>\n",
134
134
  render("%p\n :plain\n \t \t bar\n baz"))
135
135
  end
136
136
 
@@ -185,7 +185,7 @@ class EngineTest < MiniTest::Unit::TestCase
185
185
  def test_dynamic_attributes_with_no_content
186
186
  assert_equal(<<HTML, render(<<HAML))
187
187
  <p>
188
- <a href='http://haml.info'></a>
188
+ <a href='http://haml.info'></a>
189
189
  </p>
190
190
  HTML
191
191
  %p
@@ -222,7 +222,7 @@ HAML
222
222
  end
223
223
 
224
224
  def test_one_liner_with_newline_shouldnt_be_one_line
225
- assert_equal("<p>\n foo\n bar\n</p>", render('%p= "foo\nbar"').chomp)
225
+ assert_equal("<p>foo\nbar</p>", render('%p= "foo\nbar"').chomp)
226
226
  end
227
227
 
228
228
  def test_multi_render
@@ -233,8 +233,31 @@ HAML
233
233
  end
234
234
 
235
235
  def test_interpolation
236
- assert_equal("<p>Hello World</p>\n", render('%p Hello #{who}', :locals => {:who => 'World'}))
237
- assert_equal("<p>\n Hello World\n</p>\n", render("%p\n Hello \#{who}", :locals => {:who => 'World'}))
236
+ assert_equal("<p>Hello World</p>\n", render('%p Hello #{who}', locals: {who: 'World'}, escape_html: false))
237
+ assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#{who}", locals: {who: 'World'}, escape_html: false))
238
+ assert_equal("<p>Hello World</p>\n", render('%p Hello #{who}', locals: {who: 'World'}, escape_html: true))
239
+ assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#{who}", locals: {who: 'World'}, escape_html: true))
240
+ end
241
+
242
+ def test_interpolation_with_instance_var
243
+ scope = Object.new
244
+ scope.instance_variable_set(:@who, 'World')
245
+
246
+ assert_equal("<p>Hello World</p>\n", render('%p Hello #@who', scope: scope, escape_html: false))
247
+ assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#@who", scope: scope, escape_html: false))
248
+ assert_equal("<p>Hello World</p>\n", render('%p Hello #@who', scope: scope, escape_html: true))
249
+ assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#@who", scope: scope, escape_html: true))
250
+ end
251
+
252
+ def test_interpolation_with_global
253
+ $global_var_for_testing = 'World'
254
+
255
+ assert_equal("<p>Hello World</p>\n", render('%p Hello #$global_var_for_testing', escape_html: false))
256
+ assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#$global_var_for_testing", escape_html: false))
257
+ assert_equal("<p>Hello World</p>\n", render('%p Hello #$global_var_for_testing', escape_html: true))
258
+ assert_equal("<p>\nHello World\n</p>\n", render("%p\n Hello \#$global_var_for_testing", escape_html: true))
259
+ ensure
260
+ $global_var_for_testing = nil
238
261
  end
239
262
 
240
263
  def test_interpolation_in_the_middle_of_a_string
@@ -242,9 +265,43 @@ HAML
242
265
  render("\"title '\#{\"Title\"}'. \""))
243
266
  end
244
267
 
268
+ def test_interpolation_with_instance_var_in_the_middle_of_a_string
269
+ scope = Object.new
270
+ scope.instance_variable_set(:@title, 'Title')
271
+
272
+ assert_equal("\"title 'Title'. \"\n",
273
+ render("\"title '\#@title'. \"", :scope => scope))
274
+ end
275
+
276
+ def test_interpolation_with_global_in_the_middle_of_a_string
277
+ $global_var_for_testing = 'Title'
278
+
279
+ assert_equal("\"title 'Title'. \"\n",
280
+ render("\"title '\#$global_var_for_testing'. \""))
281
+ ensure
282
+ $global_var_for_testing = nil
283
+ end
284
+
245
285
  def test_interpolation_at_the_beginning_of_a_line
246
286
  assert_equal("<p>2</p>\n", render('%p #{1 + 1}'))
247
- assert_equal("<p>\n 2\n</p>\n", render("%p\n \#{1 + 1}"))
287
+ assert_equal("<p>\n2\n</p>\n", render("%p\n \#{1 + 1}"))
288
+ end
289
+
290
+ def test_interpolation_with_instance_var_at_the_beginning_of_a_line
291
+ scope = Object.new
292
+ scope.instance_variable_set(:@foo, 2)
293
+
294
+ assert_equal("<p>2</p>\n", render('%p #@foo', :scope => scope))
295
+ assert_equal("<p>\n2\n</p>\n", render("%p\n \#@foo", :scope => scope))
296
+ end
297
+
298
+ def test_interpolation_with_global_at_the_beginning_of_a_line
299
+ $global_var_for_testing = 2
300
+
301
+ assert_equal("<p>2</p>\n", render('%p #$global_var_for_testing'))
302
+ assert_equal("<p>\n2\n</p>\n", render("%p\n \#$global_var_for_testing"))
303
+ ensure
304
+ $global_var_for_testing = nil
248
305
  end
249
306
 
250
307
  def test_escaped_interpolation
@@ -269,7 +326,7 @@ HAML
269
326
 
270
327
  def test_attribute_hash_with_newlines
271
328
  assert_equal("<p a='b' c='d'>foop</p>\n", render("%p{:a => 'b',\n :c => 'd'} foop"))
272
- assert_equal("<p a='b' c='d'>\n foop\n</p>\n", render("%p{:a => 'b',\n :c => 'd'}\n foop"))
329
+ assert_equal("<p a='b' c='d'>\nfoop\n</p>\n", render("%p{:a => 'b',\n :c => 'd'}\n foop"))
273
330
  assert_equal("<p a='b' c='d'>\n", render("%p{:a => 'b',\n :c => 'd'}/"))
274
331
  assert_equal("<p a='b' c='d' e='f'></p>\n", render("%p{:a => 'b',\n :c => 'd',\n :e => 'f'}"))
275
332
  end
@@ -288,8 +345,8 @@ HAML
288
345
  assert_equal(hash, {:color => 'red'})
289
346
  end
290
347
 
291
- def test_ugly_semi_prerendered_tags
292
- assert_equal(<<HTML, render(<<HAML, :ugly => true))
348
+ def test_semi_prerendered_tags
349
+ assert_equal(<<HTML, render(<<HAML))
293
350
  <p a='2'></p>
294
351
  <p a='2'>foo</p>
295
352
  <p a='2'>
@@ -331,7 +388,7 @@ HAML
331
388
  assert_equal("<textarea>#{'a' * 100}</textarea>\n",
332
389
  render("%textarea #{'a' * 100}"))
333
390
 
334
- assert_equal("<p>\n <textarea>Foo\n Bar\n Baz</textarea>\n</p>\n", render(<<SOURCE))
391
+ assert_equal("<p>\n<textarea>Foo\nBar\nBaz</textarea>\n</p>\n", render(<<SOURCE))
335
392
  %p
336
393
  %textarea
337
394
  Foo
@@ -378,7 +435,7 @@ HAML
378
435
  def test_both_whitespace_nukes_work_together
379
436
  assert_equal(<<RESULT, render(<<SOURCE))
380
437
  <p><q>Foo
381
- Bar</q></p>
438
+ Bar</q></p>
382
439
  RESULT
383
440
  %p
384
441
  %q><= "Foo\\nBar"
@@ -387,6 +444,7 @@ SOURCE
387
444
 
388
445
  def test_nil_option
389
446
  assert_equal("<p foo='bar'></p>\n", render('%p{:foo => "bar"}', :attr_wrapper => nil))
447
+ assert_equal("<p foo='bar'></p>\n", render('%p{foo: "bar"}', :attr_wrapper => nil))
390
448
  end
391
449
 
392
450
  def test_comment_with_crazy_nesting
@@ -408,11 +466,11 @@ HAML
408
466
  def test_indentation_after_dynamic_attr_hash
409
467
  assert_equal(<<HTML, render(<<HAML))
410
468
  <html>
411
- <body>
412
- <img src='test'>
413
- foo
414
- bar
415
- </body>
469
+ <body>
470
+ <img src='test'>
471
+ foo
472
+ bar
473
+ </body>
416
474
  </html>
417
475
  HTML
418
476
  %html
@@ -423,10 +481,12 @@ HAML
423
481
  end
424
482
 
425
483
  def test_whitespace_nuke_with_both_newlines
426
- assert_equal("<p>foo</p>\n", render('%p<= "\nfoo\n"'))
484
+ assert_equal("<p>\nfoo\n</p>\n", render('%p<= "\nfoo\n"'))
427
485
  assert_equal(<<HTML, render(<<HAML))
428
486
  <p>
429
- <p>foo</p>
487
+ <p>
488
+ foo
489
+ </p>
430
490
  </p>
431
491
  HTML
432
492
  %p
@@ -437,7 +497,7 @@ HAML
437
497
  def test_whitespace_nuke_with_tags_and_else
438
498
  assert_equal(<<HTML, render(<<HAML))
439
499
  <a>
440
- <b>foo</b>
500
+ <b>foo</b>
441
501
  </a>
442
502
  HTML
443
503
  %a
@@ -450,9 +510,9 @@ HAML
450
510
 
451
511
  assert_equal(<<HTML, render(<<HAML))
452
512
  <a>
453
- <b>
454
- foo
455
- </b>
513
+ <b>
514
+ foo
515
+ </b>
456
516
  </a>
457
517
  HTML
458
518
  %a
@@ -467,7 +527,7 @@ HAML
467
527
  def test_outer_whitespace_nuke_with_empty_script
468
528
  assert_equal(<<HTML, render(<<HAML))
469
529
  <p>
470
- foo<a></a></p>
530
+ foo <a></a></p>
471
531
  HTML
472
532
  %p
473
533
  foo
@@ -479,7 +539,7 @@ HAML
479
539
  def test_both_case_indentation_work_with_deeply_nested_code
480
540
  result = <<RESULT
481
541
  <h2>
482
- other
542
+ other
483
543
  </h2>
484
544
  RESULT
485
545
  assert_equal(result, render(<<HAML))
@@ -502,15 +562,15 @@ HAML
502
562
  HAML
503
563
  end
504
564
 
505
- def test_equals_block_with_ugly
506
- assert_equal("foo\n", render(<<HAML, :ugly => true))
565
+ def test_equals_block
566
+ assert_equal("foo\n", render(<<HAML))
507
567
  = capture_haml do
508
568
  foo
509
569
  HAML
510
570
  end
511
571
 
512
- def test_plain_equals_with_ugly
513
- assert_equal("foo\nbar\n", render(<<HAML, :ugly => true))
572
+ def test_plain_equals
573
+ assert_equal("foo\nbar\n", render(<<HAML))
514
574
  = "foo"
515
575
  bar
516
576
  HAML
@@ -528,10 +588,7 @@ HAML
528
588
  end
529
589
 
530
590
  def test_end_with_method_call
531
- assert_equal(<<HTML, render(<<HAML))
532
- 2|3|4
533
- b-a-r
534
- HTML
591
+ assert_equal("2|3|4b-a-r", render(<<HAML))
535
592
  = [1, 2, 3].map do |i|
536
593
  - i + 1
537
594
  - end.join("|")
@@ -545,9 +602,7 @@ HAML
545
602
  def test_nested_end_with_method_call
546
603
  assert_equal(<<HTML, render(<<HAML))
547
604
  <p>
548
- 2|3|4
549
- b-a-r
550
- </p>
605
+ 2|3|4b-a-r</p>
551
606
  HTML
552
607
  %p
553
608
  = [1, 2, 3].map do |i|
@@ -629,7 +684,7 @@ HAML
629
684
  def test_escape_attrs_false
630
685
  assert_equal(<<HTML, render(<<HAML, :escape_attrs => false))
631
686
  <div class='<?php echo "&quot;" ?>' id='foo'>
632
- bar
687
+ bar
633
688
  </div>
634
689
  HTML
635
690
  #foo{:class => '<?php echo "&quot;" ?>'}
@@ -638,9 +693,9 @@ HAML
638
693
  end
639
694
 
640
695
  def test_escape_attrs_always
641
- assert_equal(<<HTML, render(<<HAML, :escape_attrs => :always))
642
- <div class='"&amp;lt;&amp;gt;&amp;amp;"' id='foo'>
643
- bar
696
+ assert_equal(<<HTML, render(<<HAML, :escape_attrs => true))
697
+ <div class='&quot;&amp;lt;&amp;gt;&amp;amp;&quot;' id='foo'>
698
+ bar
644
699
  </div>
645
700
  HTML
646
701
  #foo{:class => '"&lt;&gt;&amp;"'}
@@ -760,7 +815,7 @@ HAML
760
815
  assert_equal("<a href='#'>Foo</a>\n",
761
816
  render('%a(href="#") #{"Foo"}'))
762
817
 
763
- assert_equal("<a href='#\"'></a>\n", render('%a(href="#\\"")'))
818
+ assert_equal("<a href='#&quot;'></a>\n", render('%a(href="#\\"")'))
764
819
  end
765
820
 
766
821
  def test_case_assigned_to_var
@@ -889,7 +944,7 @@ HAML
889
944
  # HTML escaping tests
890
945
 
891
946
  def test_ampersand_equals_should_escape
892
- assert_equal("<p>\n foo &amp; bar\n</p>\n", render("%p\n &= 'foo & bar'", :escape_html => false))
947
+ assert_equal("<p>\nfoo &amp; bar\n</p>\n", render("%p\n &= 'foo & bar'", :escape_html => false))
893
948
  end
894
949
 
895
950
  def test_ampersand_equals_inline_should_escape
@@ -901,7 +956,7 @@ HAML
901
956
  end
902
957
 
903
958
  def test_bang_equals_should_not_escape
904
- assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n != 'foo & bar'", :escape_html => true))
959
+ assert_equal("<p>\nfoo & bar\n</p>\n", render("%p\n != 'foo & bar'", :escape_html => true))
905
960
  end
906
961
 
907
962
  def test_bang_equals_inline_should_not_escape
@@ -915,8 +970,6 @@ HAML
915
970
  render(".atlantis{:style => 'ugly&stupid'} foo"))
916
971
  assert_equal("<p class='atlantis' style='ugly&amp;stupid'>foo</p>\n",
917
972
  render("%p.atlantis{:style => 'ugly&stupid'}= 'foo'"))
918
- assert_equal("<p class='atlantis' style='ugly&#x000A;stupid'></p>\n",
919
- render("%p.atlantis{:style => \"ugly\\nstupid\"}"))
920
973
  end
921
974
 
922
975
  def test_dynamic_attributes_should_be_escaped
@@ -926,8 +979,6 @@ HAML
926
979
  render("%p{:width => nil, :src => '&foo.png', :alt => String.new} foo"))
927
980
  assert_equal("<div alt='' src='&amp;foo.png'>foo</div>\n",
928
981
  render("%div{:width => nil, :src => '&foo.png', :alt => String.new}= 'foo'"))
929
- assert_equal("<img alt='' src='foo&#x000A;.png'>\n",
930
- render("%img{:width => nil, :src => \"foo\\n.png\", :alt => String.new}"))
931
982
  end
932
983
 
933
984
  def test_string_double_equals_should_be_esaped
@@ -946,13 +997,13 @@ HAML
946
997
  end
947
998
 
948
999
  def test_escaped_string_double_equals
949
- assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => true))
950
- assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => false))
1000
+ assert_equal("<p>\n4&&lt;\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => true))
1001
+ assert_equal("<p>\n4&&lt;\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => false))
951
1002
  end
952
1003
 
953
1004
  def test_unescaped_string_double_equals
954
- assert_equal("<p>\n 4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => true))
955
- assert_equal("<p>\n 4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => false))
1005
+ assert_equal("<p>\n4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => true))
1006
+ assert_equal("<p>\n4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => false))
956
1007
  end
957
1008
 
958
1009
  def test_string_interpolation_should_be_esaped
@@ -971,18 +1022,28 @@ HAML
971
1022
  end
972
1023
 
973
1024
  def test_escaped_string_interpolation
974
- assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => true))
975
- assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => false))
1025
+ assert_equal("<p>\n4&&lt;\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => true))
1026
+ assert_equal("<p>\n4&&lt;\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => false))
1027
+ end
1028
+
1029
+ def test_escaped_string_interpolation_with_no_space
1030
+ assert_equal("&lt;br&gt;\n", render('&#{"<br>"}'))
1031
+ assert_equal("<span>&lt;br&gt;</span>\n", render('%span&#{"<br>"}'))
976
1032
  end
977
1033
 
978
1034
  def test_unescaped_string_interpolation
979
- assert_equal("<p>\n 4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => true))
980
- assert_equal("<p>\n 4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => false))
1035
+ assert_equal("<p>\n4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => true))
1036
+ assert_equal("<p>\n4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => false))
1037
+ end
1038
+
1039
+ def test_unescaped_string_interpolation_with_no_space
1040
+ assert_equal("<br>\n", render('!#{"<br>"}'))
1041
+ assert_equal("<span><br></span>\n", render('%span!#{"<br>"}'))
981
1042
  end
982
1043
 
983
1044
  def test_scripts_should_respect_escape_html_option
984
- assert_equal("<p>\n foo &amp; bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => true))
985
- assert_equal("<p>\n foo & bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => false))
1045
+ assert_equal("<p>\nfoo &amp; bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => true))
1046
+ assert_equal("<p>\nfoo & bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => false))
986
1047
  end
987
1048
 
988
1049
  def test_inline_scripts_should_respect_escape_html_option
@@ -1061,9 +1122,9 @@ HAML
1061
1122
 
1062
1123
  def test_attr_wrapper
1063
1124
  assert_equal("<p strange=*attrs*></p>\n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*'))
1064
- assert_equal("<p escaped='quo\"te'></p>\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"'))
1065
- assert_equal("<p escaped=\"quo'te\"></p>\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"'))
1066
- assert_equal("<p escaped=\"q'uo&#x0022;te\"></p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
1125
+ assert_equal("<p escaped=\"quo&quot;te\"></p>\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"'))
1126
+ assert_equal("<p escaped=\"quo&#39;te\"></p>\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"'))
1127
+ assert_equal("<p escaped=\"q&#39;uo&quot;te\"></p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
1067
1128
  assert_equal("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n", render("!!! XML", :attr_wrapper => '"', :format => :xhtml))
1068
1129
  end
1069
1130
 
@@ -1081,9 +1142,7 @@ HAML
1081
1142
  end
1082
1143
 
1083
1144
  def test_attrs_parsed_correctly
1084
- assert_equal("<p boom=>biddly='bar =&gt; baz'></p>\n", render("%p{'boom=>biddly' => 'bar => baz'}"))
1085
1145
  assert_equal("<p foo,bar='baz, qux'></p>\n", render("%p{'foo,bar' => 'baz, qux'}"))
1086
- assert_equal("<p escaped='quo&#x000A;te'></p>\n", render("%p{ :escaped => \"quo\\nte\"}"))
1087
1146
  assert_equal("<p escaped='quo4te'></p>\n", render("%p{ :escaped => \"quo\#{2 + 2}te\"}"))
1088
1147
  end
1089
1148
 
@@ -1189,10 +1248,10 @@ HAML
1189
1248
  def test_compile_error
1190
1249
  render("a\nb\n- fee)\nc")
1191
1250
  rescue Exception => e
1192
- assert_match(/\(test_compile_error\):3: (syntax error|expecting \$end)/i, e.message)
1251
+ assert_match(/\(test_compile_error\):3:/i, e.message)
1252
+ assert_match(/(syntax error|expecting \$end)/i, e.message)
1193
1253
  else
1194
- assert(false,
1195
- '"a\nb\n- fee)\nc" doesn\'t produce an exception!')
1254
+ assert(false, '"a\nb\n- fee)\nc" doesn\'t produce an exception!')
1196
1255
  end
1197
1256
 
1198
1257
  def test_unbalanced_brackets
@@ -1201,6 +1260,21 @@ HAML
1201
1260
  assert_equal(Haml::Error.message(:unbalanced_brackets), e.message)
1202
1261
  end
1203
1262
 
1263
+ def test_single_line_comments_are_interpolated
1264
+ assert_equal("<!-- Hello 2 -->\n",
1265
+ render('/ Hello #{1 + 1}'))
1266
+ end
1267
+
1268
+ def test_single_line_comments_are_not_interpolated_with_suppress_eval
1269
+ assert_equal("<!-- -->\n",
1270
+ render('/ Hello #{1 + 1}', :suppress_eval => true))
1271
+ end
1272
+
1273
+ def test_single_line_comments_with_interpolation_dont_break_tabulation
1274
+ assert_equal("<!-- Hello 2 -->\nconcatted\n",
1275
+ render("/ Hello \#{1 + 1}\n- haml_concat 'concatted'"))
1276
+ end
1277
+
1204
1278
  def test_balanced_conditional_comments
1205
1279
  assert_equal("<!--[if !(IE 6)|(IE 7)]> Bracket: ] <![endif]-->\n",
1206
1280
  render("/[if !(IE 6)|(IE 7)] Bracket: ]"))
@@ -1212,13 +1286,13 @@ HAML
1212
1286
  end
1213
1287
 
1214
1288
  def test_downlevel_revealed_conditional_comments_block
1215
- assert_equal("<!--[if !IE]><!-->\n A comment\n<!--<![endif]-->\n",
1289
+ assert_equal("<!--[if !IE]><!-->\nA comment\n<!--<![endif]-->\n",
1216
1290
  render("/![if !IE]\n A comment"))
1217
1291
  end
1218
1292
 
1219
1293
  def test_local_assigns_dont_modify_class
1220
1294
  assert_equal("bar\n", render("= foo", :locals => {:foo => 'bar'}))
1221
- assert_equal(nil, defined?(foo))
1295
+ assert_nil(defined?(foo))
1222
1296
  end
1223
1297
 
1224
1298
  def test_object_ref_with_nil_id
@@ -1253,7 +1327,7 @@ HAML
1253
1327
 
1254
1328
  def test_render_should_accept_a_binding_as_scope
1255
1329
  string = "This is a string!"
1256
- string.instance_variable_set("@var", "Instance variable")
1330
+ string.instance_variable_set(:@var, "Instance variable")
1257
1331
  b = string.instance_eval do
1258
1332
  var = "Local variable"
1259
1333
  # Silence unavoidable warning; Ruby doesn't know we're going to use this
@@ -1334,15 +1408,15 @@ HAML
1334
1408
  end
1335
1409
  end
1336
1410
 
1337
- def test_ugly_true
1411
+ def test_spacing_inside_tag
1338
1412
  assert_equal("<div id='outer'>\n<div id='inner'>\n<p>hello world</p>\n</div>\n</div>\n",
1339
- render("#outer\n #inner\n %p hello world", :ugly => true))
1413
+ render("#outer\n #inner\n %p hello world"))
1340
1414
 
1341
1415
  assert_equal("<p>#{'s' * 75}</p>\n",
1342
- render("%p #{'s' * 75}", :ugly => true))
1416
+ render("%p #{'s' * 75}"))
1343
1417
 
1344
1418
  assert_equal("<p>#{'s' * 75}</p>\n",
1345
- render("%p= 's' * 75", :ugly => true))
1419
+ render("%p= 's' * 75"))
1346
1420
  end
1347
1421
 
1348
1422
  def test_remove_whitespace_true
@@ -1359,15 +1433,13 @@ HAML
1359
1433
  render('%div <span>foo</span> <span>bar</span>', :remove_whitespace => true))
1360
1434
  end
1361
1435
 
1362
- def test_auto_preserve_unless_ugly
1436
+ def test_auto_preserve
1363
1437
  assert_equal("<pre>foo&#x000A;bar</pre>\n", render('%pre="foo\nbar"'))
1364
1438
  assert_equal("<pre>foo\nbar</pre>\n", render("%pre\n foo\n bar"))
1365
- assert_equal("<pre>foo\nbar</pre>\n", render('%pre="foo\nbar"', :ugly => true))
1366
- assert_equal("<pre>foo\nbar</pre>\n", render("%pre\n foo\n bar", :ugly => true))
1367
1439
  end
1368
1440
 
1369
1441
  def test_xhtml_output_option
1370
- assert_equal "<p>\n <br />\n</p>\n", render("%p\n %br", :format => :xhtml)
1442
+ assert_equal "<p>\n<br />\n</p>\n", render("%p\n %br", :format => :xhtml)
1371
1443
  assert_equal "<a />\n", render("%a/", :format => :xhtml)
1372
1444
  end
1373
1445
 
@@ -1400,6 +1472,8 @@ HAML
1400
1472
  engine = Haml::Engine.new('%a{:b => "a #$global_var_for_testing b"}')
1401
1473
  $global_var_for_testing = 'bar'
1402
1474
  assert_equal("<a b='a bar b'></a>\n", engine.to_html)
1475
+ ensure
1476
+ $global_var_for_testing = nil
1403
1477
  end
1404
1478
 
1405
1479
  def test_utf8_attrs
@@ -1410,7 +1484,7 @@ HAML
1410
1484
  # HTML 4.0
1411
1485
 
1412
1486
  def test_html_has_no_self_closing_tags
1413
- assert_equal "<p>\n <br>\n</p>\n", render("%p\n %br", :format => :html4)
1487
+ assert_equal "<p>\n<br>\n</p>\n", render("%p\n %br", :format => :html4)
1414
1488
  assert_equal "<br>\n", render("%br/", :format => :html4)
1415
1489
  end
1416
1490
 
@@ -1454,7 +1528,7 @@ HAML
1454
1528
  render("%div{:data => {:one_plus_one => 1+1}}",
1455
1529
  :hyphenate_data_attrs => false))
1456
1530
 
1457
- assert_equal("<div data-foo='Here&#x0027;s a \"quoteful\" string.'></div>\n",
1531
+ assert_equal("<div data-foo='Here&#39;s a &quot;quoteful&quot; string.'></div>\n",
1458
1532
  render(%{%div{:data => {:foo => %{Here's a "quoteful" string.}}}},
1459
1533
  :hyphenate_data_attrs => false)) #'
1460
1534
  end
@@ -1507,24 +1581,23 @@ HAML
1507
1581
  end
1508
1582
 
1509
1583
  def test_html5_data_attributes_with_attr_method
1510
- Haml::Helpers.module_eval do
1511
- def data_hash
1512
- {:data => {:foo => "bar", :baz => "bang"}}
1513
- end
1584
+ obj = Object.new
1585
+ def obj.data_hash
1586
+ {:data => {:foo => "bar", :baz => "bang"}}
1587
+ end
1514
1588
 
1515
- def data_val
1516
- {:data => "dat"}
1517
- end
1589
+ def obj.data_val
1590
+ {:data => "dat"}
1518
1591
  end
1519
1592
 
1520
1593
  assert_equal("<div data-baz='bang' data-brat='wurst' data-foo='blip'></div>\n",
1521
- render("%div{data_hash, :data => {:foo => 'blip', :brat => 'wurst'}}"))
1594
+ render("%div{data_hash, :data => {:foo => 'blip', :brat => 'wurst'}}", scope: obj))
1522
1595
  assert_equal("<div data-baz='bang' data-foo='blip'></div>\n",
1523
- render("%div{data_hash, 'data-foo' => 'blip'}"))
1596
+ render("%div{data_hash, 'data-foo' => 'blip'}", scope: obj))
1524
1597
  assert_equal("<div data-baz='bang' data-foo='bar' data='dat'></div>\n",
1525
- render("%div{data_hash, :data => 'dat'}"))
1598
+ render("%div{data_hash, :data => 'dat'}", scope: obj))
1526
1599
  assert_equal("<div data-brat='wurst' data-foo='blip' data='dat'></div>\n",
1527
- render("%div{data_val, :data => {:foo => 'blip', :brat => 'wurst'}}"))
1600
+ render("%div{data_val, :data => {:foo => 'blip', :brat => 'wurst'}}", scope: obj))
1528
1601
  end
1529
1602
 
1530
1603
  def test_html5_data_attributes_with_identical_attribute_values
@@ -1536,8 +1609,8 @@ HAML
1536
1609
  assert_equal(<<XML, render(<<HAML, { :format => :html5, :mime_type => 'text/xml' }))
1537
1610
  <?xml version='1.0' encoding='utf-8' ?>
1538
1611
  <root>
1539
- <element />
1540
- <hr />
1612
+ <element />
1613
+ <hr />
1541
1614
  </root>
1542
1615
  XML
1543
1616
  !!! XML
@@ -1551,8 +1624,8 @@ HAML
1551
1624
  assert_equal(<<XML, render(<<HAML, { :format => :html4, :mime_type => 'text/xml' }))
1552
1625
  <?xml version='1.0' encoding='utf-8' ?>
1553
1626
  <root>
1554
- <element />
1555
- <hr />
1627
+ <element />
1628
+ <hr />
1556
1629
  </root>
1557
1630
  XML
1558
1631
  !!! XML
@@ -1618,10 +1691,10 @@ HAML
1618
1691
 
1619
1692
  def test_new_attribute_parsing
1620
1693
  assert_equal("<a a2='b2'>bar</a>\n", render("%a(a2=b2) bar", :locals => {:b2 => 'b2'}))
1621
- assert_equal(%Q{<a a='foo"bar'>bar</a>\n}, render(%q{%a(a="#{'foo"bar'}") bar})) #'
1622
- assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #'
1623
- assert_equal(%Q{<a a='foo"bar'>bar</a>\n}, render(%q{%a(a='foo"bar') bar}))
1624
- assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="foo'bar") bar}))
1694
+ assert_equal(%Q{<a a='foo&quot;bar'>bar</a>\n}, render(%q{%a(a="#{'foo"bar'}") bar})) #'
1695
+ assert_equal(%Q{<a a='foo&#39;bar'>bar</a>\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #'
1696
+ assert_equal(%Q{<a a='foo&quot;bar'>bar</a>\n}, render(%q{%a(a='foo"bar') bar}))
1697
+ assert_equal(%Q{<a a='foo&#39;bar'>bar</a>\n}, render(%q{%a(a="foo'bar") bar}))
1625
1698
  assert_equal("<a a:b='foo'>bar</a>\n", render("%a(a:b='foo') bar"))
1626
1699
  assert_equal("<a a='foo' b='bar'>bar</a>\n", render("%a(a = 'foo' b = 'bar') bar"))
1627
1700
  assert_equal("<a a='foo' b='bar'>bar</a>\n", render("%a(a = foo b = bar) bar", :locals => {:foo => 'foo', :bar => 'bar'}))
@@ -1631,11 +1704,11 @@ HAML
1631
1704
  end
1632
1705
 
1633
1706
  def test_new_attribute_escaping
1634
- assert_equal(%Q{<a a='foo " bar'>bar</a>\n}, render(%q{%a(a="foo \" bar") bar}))
1635
- assert_equal(%Q{<a a='foo \\" bar'>bar</a>\n}, render(%q{%a(a="foo \\\\\" bar") bar}))
1707
+ assert_equal(%Q{<a a='foo &quot; bar'>bar</a>\n}, render(%q{%a(a="foo \" bar") bar}))
1708
+ assert_equal(%Q{<a a='foo \\&quot; bar'>bar</a>\n}, render(%q{%a(a="foo \\\\\" bar") bar}))
1636
1709
 
1637
- assert_equal(%Q{<a a="foo ' bar">bar</a>\n}, render(%q{%a(a='foo \' bar') bar}))
1638
- assert_equal(%Q{<a a="foo \\' bar">bar</a>\n}, render(%q{%a(a='foo \\\\\' bar') bar}))
1710
+ assert_equal(%Q{<a a='foo &#39; bar'>bar</a>\n}, render(%q{%a(a='foo \' bar') bar}))
1711
+ assert_equal(%Q{<a a='foo \\&#39; bar'>bar</a>\n}, render(%q{%a(a='foo \\\\\' bar') bar}))
1639
1712
 
1640
1713
  assert_equal(%Q{<a a='foo \\ bar'>bar</a>\n}, render(%q{%a(a="foo \\\\ bar") bar}))
1641
1714
  assert_equal(%Q{<a a='foo \#{1 + 1} bar'>bar</a>\n}, render(%q{%a(a="foo \#{1 + 1} bar") bar}))
@@ -1664,6 +1737,8 @@ HAML
1664
1737
  locals = {:b => 'b', :d => 'd'}
1665
1738
  assert_equal("<p a='b' c='d'></p>\n", render("%p{:a => b}(c=d)", :locals => locals))
1666
1739
  assert_equal("<p a='b' c='d'></p>\n", render("%p(a=b){:c => d}", :locals => locals))
1740
+
1741
+ assert_equal("<p id='b_d'></p>\n<p id='b_d'></p>\n", render("%p(id=b){id:d}\n%p(id=b){id:d}", locals: locals))
1667
1742
  end
1668
1743
 
1669
1744
  # Ruby Multiline
@@ -1763,8 +1838,7 @@ HAML
1763
1838
 
1764
1839
  def test_loud_ruby_multiline_with_block
1765
1840
  assert_equal(<<HTML, render(<<HAML))
1766
- #{%w[far faz fang]}
1767
- <p>foo</p>
1841
+ #{%w[far faz fang]}<p>foo</p>
1768
1842
  <p>bar</p>
1769
1843
  HTML
1770
1844
  = ["bar",
@@ -1877,7 +1951,7 @@ HAML
1877
1951
  def test_utf_8_bom
1878
1952
  assert_equal <<HTML, render(<<HAML)
1879
1953
  <div class='foo'>
1880
- <p>baz</p>
1954
+ <p>baz</p>
1881
1955
  </div>
1882
1956
  HTML
1883
1957
  \xEF\xBB\xBF.foo
@@ -1986,6 +2060,28 @@ HAML
1986
2060
  end
1987
2061
  end
1988
2062
 
2063
+ def test_tracing
2064
+ result = render('%p{:class => "hello"}', :trace => true, :filename => 'foo').strip
2065
+ assert_equal "<p class='hello' data-trace='foo:1'></p>", result
2066
+ end
2067
+
2068
+ def test_unsafe_dynamic_attribute_name_raises_invalid_attribute_name_error
2069
+ assert_raises(Haml::InvalidAttributeNameError) do
2070
+ render(<<-HAML)
2071
+ - params = { 'x /><script>alert(1);</script><div x' => 'hello' }
2072
+ %div{ data: params }
2073
+ HAML
2074
+ end
2075
+ end
2076
+
2077
+ def test_unsafe_static_attribute_name_raises_invalid_attribute_name_error
2078
+ assert_raises(Haml::InvalidAttributeNameError) do
2079
+ render(<<-HAML)
2080
+ %div{ 'x /><script>alert(1);</script><div x' => 'hello' }
2081
+ HAML
2082
+ end
2083
+ end
2084
+
1989
2085
  private
1990
2086
 
1991
2087
  def assert_valid_encoding_comment(comment)