haml 4.0.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +117 -5
  4. data/FAQ.md +7 -17
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +85 -42
  7. data/REFERENCE.md +181 -86
  8. data/Rakefile +47 -51
  9. data/lib/haml/attribute_builder.rb +163 -0
  10. data/lib/haml/attribute_compiler.rb +215 -0
  11. data/lib/haml/attribute_parser.rb +144 -0
  12. data/lib/haml/buffer.rb +38 -128
  13. data/lib/haml/compiler.rb +88 -295
  14. data/lib/haml/engine.rb +25 -41
  15. data/lib/haml/error.rb +3 -0
  16. data/lib/haml/escapable.rb +49 -0
  17. data/lib/haml/exec.rb +33 -19
  18. data/lib/haml/filters.rb +20 -24
  19. data/lib/haml/generator.rb +41 -0
  20. data/lib/haml/helpers/action_view_extensions.rb +3 -2
  21. data/lib/haml/helpers/action_view_mods.rb +44 -66
  22. data/lib/haml/helpers/action_view_xss_mods.rb +1 -0
  23. data/lib/haml/helpers/safe_erubi_template.rb +27 -0
  24. data/lib/haml/helpers/safe_erubis_template.rb +16 -4
  25. data/lib/haml/helpers/xss_mods.rb +18 -12
  26. data/lib/haml/helpers.rb +122 -58
  27. data/lib/haml/options.rb +39 -46
  28. data/lib/haml/parser.rb +278 -217
  29. data/lib/haml/{template/plugin.rb → plugin.rb} +8 -15
  30. data/lib/haml/railtie.rb +21 -11
  31. data/lib/haml/sass_rails_filter.rb +17 -4
  32. data/lib/haml/template/options.rb +12 -2
  33. data/lib/haml/template.rb +12 -6
  34. data/lib/haml/temple_engine.rb +120 -0
  35. data/lib/haml/temple_line_counter.rb +29 -0
  36. data/lib/haml/util.rb +80 -199
  37. data/lib/haml/version.rb +2 -1
  38. data/lib/haml.rb +2 -1
  39. data/test/attribute_parser_test.rb +101 -0
  40. data/test/engine_test.rb +306 -176
  41. data/test/filters_test.rb +32 -19
  42. data/test/gemfiles/Gemfile.rails-4.0.x +11 -0
  43. data/test/gemfiles/Gemfile.rails-4.0.x.lock +87 -0
  44. data/test/gemfiles/Gemfile.rails-4.1.x +5 -0
  45. data/test/gemfiles/Gemfile.rails-4.2.x +5 -0
  46. data/test/gemfiles/Gemfile.rails-5.0.x +4 -0
  47. data/test/helper_test.rb +282 -96
  48. data/test/options_test.rb +22 -0
  49. data/test/parser_test.rb +71 -4
  50. data/test/results/bemit.xhtml +4 -0
  51. data/test/results/eval_suppressed.xhtml +4 -4
  52. data/test/results/helpers.xhtml +43 -41
  53. data/test/results/helpful.xhtml +6 -3
  54. data/test/results/just_stuff.xhtml +21 -20
  55. data/test/results/list.xhtml +9 -9
  56. data/test/results/nuke_inner_whitespace.xhtml +22 -22
  57. data/test/results/nuke_outer_whitespace.xhtml +84 -92
  58. data/test/results/original_engine.xhtml +17 -17
  59. data/test/results/partial_layout.xhtml +4 -3
  60. data/test/results/partial_layout_erb.xhtml +4 -3
  61. data/test/results/partials.xhtml +11 -10
  62. data/test/results/silent_script.xhtml +63 -63
  63. data/test/results/standard.xhtml +156 -159
  64. data/test/results/tag_parsing.xhtml +19 -19
  65. data/test/results/very_basic.xhtml +2 -2
  66. data/test/results/whitespace_handling.xhtml +56 -50
  67. data/test/template_test.rb +44 -53
  68. data/test/template_test_helper.rb +38 -0
  69. data/test/templates/_text_area_helper.html.haml +4 -0
  70. data/test/templates/bemit.haml +3 -0
  71. data/test/templates/just_stuff.haml +1 -0
  72. data/test/templates/partial_layout_erb.erb +1 -1
  73. data/test/templates/standard_ugly.haml +1 -0
  74. data/test/templates/with_bom.haml +1 -0
  75. data/test/temple_line_counter_test.rb +40 -0
  76. data/test/test_helper.rb +26 -12
  77. data/test/util_test.rb +6 -47
  78. metadata +88 -106
  79. data/lib/haml/helpers/rails_323_textarea_fix.rb +0 -24
  80. data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
  81. data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
  82. data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
  83. data/test/gemfiles/Gemfile.rails-master +0 -4
  84. data/test/templates/_av_partial_1_ugly.haml +0 -9
  85. data/test/templates/_av_partial_2_ugly.haml +0 -5
  86. data/test/templates/action_view_ugly.haml +0 -47
  87. data/test/templates/standard_ugly.haml +0 -43
data/test/engine_test.rb CHANGED
@@ -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.
@@ -113,13 +113,11 @@ class EngineTest < MiniTest::Unit::TestCase
113
113
  end
114
114
 
115
115
  def setup
116
- return if RUBY_VERSION < "1.9"
117
116
  @old_default_internal = Encoding.default_internal
118
117
  silence_warnings{Encoding.default_internal = nil}
119
118
  end
120
119
 
121
120
  def teardown
122
- return if RUBY_VERSION < "1.9"
123
121
  silence_warnings{Encoding.default_internal = @old_default_internal}
124
122
  end
125
123
 
@@ -128,11 +126,11 @@ class EngineTest < MiniTest::Unit::TestCase
128
126
  end
129
127
 
130
128
  def test_flexible_tabulation
131
- 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",
132
130
  render("%p\n foo\n%q\n bar\n %a\n baz"))
133
- 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",
134
132
  render("%p\n\tfoo\n%q\n\tbar\n\t%a\n\t\tbaz"))
135
- 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",
136
134
  render("%p\n :plain\n \t \t bar\n baz"))
137
135
  end
138
136
 
@@ -187,7 +185,7 @@ class EngineTest < MiniTest::Unit::TestCase
187
185
  def test_dynamic_attributes_with_no_content
188
186
  assert_equal(<<HTML, render(<<HAML))
189
187
  <p>
190
- <a href='http://haml.info'></a>
188
+ <a href='http://haml.info'></a>
191
189
  </p>
192
190
  HTML
193
191
  %p
@@ -224,7 +222,7 @@ HAML
224
222
  end
225
223
 
226
224
  def test_one_liner_with_newline_shouldnt_be_one_line
227
- 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)
228
226
  end
229
227
 
230
228
  def test_multi_render
@@ -235,8 +233,31 @@ HAML
235
233
  end
236
234
 
237
235
  def test_interpolation
238
- assert_equal("<p>Hello World</p>\n", render('%p Hello #{who}', :locals => {:who => 'World'}))
239
- 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
240
261
  end
241
262
 
242
263
  def test_interpolation_in_the_middle_of_a_string
@@ -244,9 +265,43 @@ HAML
244
265
  render("\"title '\#{\"Title\"}'. \""))
245
266
  end
246
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
+
247
285
  def test_interpolation_at_the_beginning_of_a_line
248
286
  assert_equal("<p>2</p>\n", render('%p #{1 + 1}'))
249
- 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
250
305
  end
251
306
 
252
307
  def test_escaped_interpolation
@@ -271,7 +326,7 @@ HAML
271
326
 
272
327
  def test_attribute_hash_with_newlines
273
328
  assert_equal("<p a='b' c='d'>foop</p>\n", render("%p{:a => 'b',\n :c => 'd'} foop"))
274
- 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"))
275
330
  assert_equal("<p a='b' c='d'>\n", render("%p{:a => 'b',\n :c => 'd'}/"))
276
331
  assert_equal("<p a='b' c='d' e='f'></p>\n", render("%p{:a => 'b',\n :c => 'd',\n :e => 'f'}"))
277
332
  end
@@ -290,8 +345,8 @@ HAML
290
345
  assert_equal(hash, {:color => 'red'})
291
346
  end
292
347
 
293
- def test_ugly_semi_prerendered_tags
294
- assert_equal(<<HTML, render(<<HAML, :ugly => true))
348
+ def test_semi_prerendered_tags
349
+ assert_equal(<<HTML, render(<<HAML))
295
350
  <p a='2'></p>
296
351
  <p a='2'>foo</p>
297
352
  <p a='2'>
@@ -333,7 +388,7 @@ HAML
333
388
  assert_equal("<textarea>#{'a' * 100}</textarea>\n",
334
389
  render("%textarea #{'a' * 100}"))
335
390
 
336
- 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))
337
392
  %p
338
393
  %textarea
339
394
  Foo
@@ -380,7 +435,7 @@ HAML
380
435
  def test_both_whitespace_nukes_work_together
381
436
  assert_equal(<<RESULT, render(<<SOURCE))
382
437
  <p><q>Foo
383
- Bar</q></p>
438
+ Bar</q></p>
384
439
  RESULT
385
440
  %p
386
441
  %q><= "Foo\\nBar"
@@ -389,6 +444,7 @@ SOURCE
389
444
 
390
445
  def test_nil_option
391
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))
392
448
  end
393
449
 
394
450
  def test_comment_with_crazy_nesting
@@ -407,15 +463,14 @@ HAML
407
463
 
408
464
  # Regression tests
409
465
 
410
- unless RUBY_VERSION < "1.9"
411
- def test_indentation_after_dynamic_attr_hash
412
- assert_equal(<<HTML, render(<<HAML))
466
+ def test_indentation_after_dynamic_attr_hash
467
+ assert_equal(<<HTML, render(<<HAML))
413
468
  <html>
414
- <body>
415
- <img src='test'>
416
- foo
417
- bar
418
- </body>
469
+ <body>
470
+ <img src='test'>
471
+ foo
472
+ bar
473
+ </body>
419
474
  </html>
420
475
  HTML
421
476
  %html
@@ -423,14 +478,15 @@ HTML
423
478
  %img{:src => 'te'+'st'}
424
479
  = "foo\\nbar"
425
480
  HAML
426
- end
427
481
  end
428
482
 
429
483
  def test_whitespace_nuke_with_both_newlines
430
- assert_equal("<p>foo</p>\n", render('%p<= "\nfoo\n"'))
484
+ assert_equal("<p>\nfoo\n</p>\n", render('%p<= "\nfoo\n"'))
431
485
  assert_equal(<<HTML, render(<<HAML))
432
486
  <p>
433
- <p>foo</p>
487
+ <p>
488
+ foo
489
+ </p>
434
490
  </p>
435
491
  HTML
436
492
  %p
@@ -441,7 +497,7 @@ HAML
441
497
  def test_whitespace_nuke_with_tags_and_else
442
498
  assert_equal(<<HTML, render(<<HAML))
443
499
  <a>
444
- <b>foo</b>
500
+ <b>foo</b>
445
501
  </a>
446
502
  HTML
447
503
  %a
@@ -454,9 +510,9 @@ HAML
454
510
 
455
511
  assert_equal(<<HTML, render(<<HAML))
456
512
  <a>
457
- <b>
458
- foo
459
- </b>
513
+ <b>
514
+ foo
515
+ </b>
460
516
  </a>
461
517
  HTML
462
518
  %a
@@ -471,7 +527,7 @@ HAML
471
527
  def test_outer_whitespace_nuke_with_empty_script
472
528
  assert_equal(<<HTML, render(<<HAML))
473
529
  <p>
474
- foo<a></a></p>
530
+ foo <a></a></p>
475
531
  HTML
476
532
  %p
477
533
  foo
@@ -483,7 +539,7 @@ HAML
483
539
  def test_both_case_indentation_work_with_deeply_nested_code
484
540
  result = <<RESULT
485
541
  <h2>
486
- other
542
+ other
487
543
  </h2>
488
544
  RESULT
489
545
  assert_equal(result, render(<<HAML))
@@ -506,15 +562,15 @@ HAML
506
562
  HAML
507
563
  end
508
564
 
509
- def test_equals_block_with_ugly
510
- assert_equal("foo\n", render(<<HAML, :ugly => true))
565
+ def test_equals_block
566
+ assert_equal("foo\n", render(<<HAML))
511
567
  = capture_haml do
512
568
  foo
513
569
  HAML
514
570
  end
515
571
 
516
- def test_plain_equals_with_ugly
517
- assert_equal("foo\nbar\n", render(<<HAML, :ugly => true))
572
+ def test_plain_equals
573
+ assert_equal("foo\nbar\n", render(<<HAML))
518
574
  = "foo"
519
575
  bar
520
576
  HAML
@@ -532,10 +588,7 @@ HAML
532
588
  end
533
589
 
534
590
  def test_end_with_method_call
535
- assert_equal(<<HTML, render(<<HAML))
536
- 2|3|4
537
- b-a-r
538
- HTML
591
+ assert_equal("2|3|4b-a-r", render(<<HAML))
539
592
  = [1, 2, 3].map do |i|
540
593
  - i + 1
541
594
  - end.join("|")
@@ -549,9 +602,7 @@ HAML
549
602
  def test_nested_end_with_method_call
550
603
  assert_equal(<<HTML, render(<<HAML))
551
604
  <p>
552
- 2|3|4
553
- b-a-r
554
- </p>
605
+ 2|3|4b-a-r</p>
555
606
  HTML
556
607
  %p
557
608
  = [1, 2, 3].map do |i|
@@ -633,7 +684,7 @@ HAML
633
684
  def test_escape_attrs_false
634
685
  assert_equal(<<HTML, render(<<HAML, :escape_attrs => false))
635
686
  <div class='<?php echo "&quot;" ?>' id='foo'>
636
- bar
687
+ bar
637
688
  </div>
638
689
  HTML
639
690
  #foo{:class => '<?php echo "&quot;" ?>'}
@@ -642,9 +693,9 @@ HAML
642
693
  end
643
694
 
644
695
  def test_escape_attrs_always
645
- assert_equal(<<HTML, render(<<HAML, :escape_attrs => :always))
646
- <div class='"&amp;lt;&amp;gt;&amp;amp;"' id='foo'>
647
- 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
648
699
  </div>
649
700
  HTML
650
701
  #foo{:class => '"&lt;&gt;&amp;"'}
@@ -764,7 +815,7 @@ HAML
764
815
  assert_equal("<a href='#'>Foo</a>\n",
765
816
  render('%a(href="#") #{"Foo"}'))
766
817
 
767
- assert_equal("<a href='#\"'></a>\n", render('%a(href="#\\"")'))
818
+ assert_equal("<a href='#&quot;'></a>\n", render('%a(href="#\\"")'))
768
819
  end
769
820
 
770
821
  def test_case_assigned_to_var
@@ -893,7 +944,7 @@ HAML
893
944
  # HTML escaping tests
894
945
 
895
946
  def test_ampersand_equals_should_escape
896
- 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))
897
948
  end
898
949
 
899
950
  def test_ampersand_equals_inline_should_escape
@@ -905,7 +956,7 @@ HAML
905
956
  end
906
957
 
907
958
  def test_bang_equals_should_not_escape
908
- 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))
909
960
  end
910
961
 
911
962
  def test_bang_equals_inline_should_not_escape
@@ -919,8 +970,6 @@ HAML
919
970
  render(".atlantis{:style => 'ugly&stupid'} foo"))
920
971
  assert_equal("<p class='atlantis' style='ugly&amp;stupid'>foo</p>\n",
921
972
  render("%p.atlantis{:style => 'ugly&stupid'}= 'foo'"))
922
- assert_equal("<p class='atlantis' style='ugly&#x000A;stupid'></p>\n",
923
- render("%p.atlantis{:style => \"ugly\\nstupid\"}"))
924
973
  end
925
974
 
926
975
  def test_dynamic_attributes_should_be_escaped
@@ -930,8 +979,6 @@ HAML
930
979
  render("%p{:width => nil, :src => '&foo.png', :alt => String.new} foo"))
931
980
  assert_equal("<div alt='' src='&amp;foo.png'>foo</div>\n",
932
981
  render("%div{:width => nil, :src => '&foo.png', :alt => String.new}= 'foo'"))
933
- assert_equal("<img alt='' src='foo&#x000A;.png'>\n",
934
- render("%img{:width => nil, :src => \"foo\\n.png\", :alt => String.new}"))
935
982
  end
936
983
 
937
984
  def test_string_double_equals_should_be_esaped
@@ -950,13 +997,13 @@ HAML
950
997
  end
951
998
 
952
999
  def test_escaped_string_double_equals
953
- assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n &== \#{2+2}&\#{'<'}", :escape_html => true))
954
- 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))
955
1002
  end
956
1003
 
957
1004
  def test_unescaped_string_double_equals
958
- assert_equal("<p>\n 4&<\n</p>\n", render("%p\n !== \#{2+2}&\#{'<'}", :escape_html => true))
959
- 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))
960
1007
  end
961
1008
 
962
1009
  def test_string_interpolation_should_be_esaped
@@ -975,18 +1022,28 @@ HAML
975
1022
  end
976
1023
 
977
1024
  def test_escaped_string_interpolation
978
- assert_equal("<p>\n 4&&lt;\n</p>\n", render("%p\n & \#{2+2}&\#{'<'}", :escape_html => true))
979
- 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>"}'))
980
1032
  end
981
1033
 
982
1034
  def test_unescaped_string_interpolation
983
- assert_equal("<p>\n 4&<\n</p>\n", render("%p\n ! \#{2+2}&\#{'<'}", :escape_html => true))
984
- 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>"}'))
985
1042
  end
986
1043
 
987
1044
  def test_scripts_should_respect_escape_html_option
988
- assert_equal("<p>\n foo &amp; bar\n</p>\n", render("%p\n = 'foo & bar'", :escape_html => true))
989
- 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))
990
1047
  end
991
1048
 
992
1049
  def test_inline_scripts_should_respect_escape_html_option
@@ -1065,9 +1122,9 @@ HAML
1065
1122
 
1066
1123
  def test_attr_wrapper
1067
1124
  assert_equal("<p strange=*attrs*></p>\n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*'))
1068
- assert_equal("<p escaped='quo\"te'></p>\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"'))
1069
- assert_equal("<p escaped=\"quo'te\"></p>\n", render("%p{ :escaped => 'quo\\'te'}", :attr_wrapper => '"'))
1070
- 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 => '"'))
1071
1128
  assert_equal("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n", render("!!! XML", :attr_wrapper => '"', :format => :xhtml))
1072
1129
  end
1073
1130
 
@@ -1085,9 +1142,7 @@ HAML
1085
1142
  end
1086
1143
 
1087
1144
  def test_attrs_parsed_correctly
1088
- assert_equal("<p boom=>biddly='bar =&gt; baz'></p>\n", render("%p{'boom=>biddly' => 'bar => baz'}"))
1089
1145
  assert_equal("<p foo,bar='baz, qux'></p>\n", render("%p{'foo,bar' => 'baz, qux'}"))
1090
- assert_equal("<p escaped='quo&#x000A;te'></p>\n", render("%p{ :escaped => \"quo\\nte\"}"))
1091
1146
  assert_equal("<p escaped='quo4te'></p>\n", render("%p{ :escaped => \"quo\#{2 + 2}te\"}"))
1092
1147
  end
1093
1148
 
@@ -1193,10 +1248,10 @@ HAML
1193
1248
  def test_compile_error
1194
1249
  render("a\nb\n- fee)\nc")
1195
1250
  rescue Exception => e
1196
- 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)
1197
1253
  else
1198
- assert(false,
1199
- '"a\nb\n- fee)\nc" doesn\'t produce an exception!')
1254
+ assert(false, '"a\nb\n- fee)\nc" doesn\'t produce an exception!')
1200
1255
  end
1201
1256
 
1202
1257
  def test_unbalanced_brackets
@@ -1205,14 +1260,39 @@ HAML
1205
1260
  assert_equal(Haml::Error.message(:unbalanced_brackets), e.message)
1206
1261
  end
1207
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
+
1208
1278
  def test_balanced_conditional_comments
1209
1279
  assert_equal("<!--[if !(IE 6)|(IE 7)]> Bracket: ] <![endif]-->\n",
1210
1280
  render("/[if !(IE 6)|(IE 7)] Bracket: ]"))
1211
1281
  end
1212
1282
 
1283
+ def test_downlevel_revealed_conditional_comments
1284
+ assert_equal("<!--[if !IE]><!--> A comment <!--<![endif]-->\n",
1285
+ render("/![if !IE] A comment"))
1286
+ end
1287
+
1288
+ def test_downlevel_revealed_conditional_comments_block
1289
+ assert_equal("<!--[if !IE]><!-->\nA comment\n<!--<![endif]-->\n",
1290
+ render("/![if !IE]\n A comment"))
1291
+ end
1292
+
1213
1293
  def test_local_assigns_dont_modify_class
1214
1294
  assert_equal("bar\n", render("= foo", :locals => {:foo => 'bar'}))
1215
- assert_equal(nil, defined?(foo))
1295
+ assert_nil(defined?(foo))
1216
1296
  end
1217
1297
 
1218
1298
  def test_object_ref_with_nil_id
@@ -1247,7 +1327,7 @@ HAML
1247
1327
 
1248
1328
  def test_render_should_accept_a_binding_as_scope
1249
1329
  string = "This is a string!"
1250
- string.instance_variable_set("@var", "Instance variable")
1330
+ string.instance_variable_set(:@var, "Instance variable")
1251
1331
  b = string.instance_eval do
1252
1332
  var = "Local variable"
1253
1333
  # Silence unavoidable warning; Ruby doesn't know we're going to use this
@@ -1328,15 +1408,15 @@ HAML
1328
1408
  end
1329
1409
  end
1330
1410
 
1331
- def test_ugly_true
1411
+ def test_spacing_inside_tag
1332
1412
  assert_equal("<div id='outer'>\n<div id='inner'>\n<p>hello world</p>\n</div>\n</div>\n",
1333
- render("#outer\n #inner\n %p hello world", :ugly => true))
1413
+ render("#outer\n #inner\n %p hello world"))
1334
1414
 
1335
1415
  assert_equal("<p>#{'s' * 75}</p>\n",
1336
- render("%p #{'s' * 75}", :ugly => true))
1416
+ render("%p #{'s' * 75}"))
1337
1417
 
1338
1418
  assert_equal("<p>#{'s' * 75}</p>\n",
1339
- render("%p= 's' * 75", :ugly => true))
1419
+ render("%p= 's' * 75"))
1340
1420
  end
1341
1421
 
1342
1422
  def test_remove_whitespace_true
@@ -1353,15 +1433,13 @@ HAML
1353
1433
  render('%div <span>foo</span> <span>bar</span>', :remove_whitespace => true))
1354
1434
  end
1355
1435
 
1356
- def test_auto_preserve_unless_ugly
1436
+ def test_auto_preserve
1357
1437
  assert_equal("<pre>foo&#x000A;bar</pre>\n", render('%pre="foo\nbar"'))
1358
1438
  assert_equal("<pre>foo\nbar</pre>\n", render("%pre\n foo\n bar"))
1359
- assert_equal("<pre>foo\nbar</pre>\n", render('%pre="foo\nbar"', :ugly => true))
1360
- assert_equal("<pre>foo\nbar</pre>\n", render("%pre\n foo\n bar", :ugly => true))
1361
1439
  end
1362
1440
 
1363
1441
  def test_xhtml_output_option
1364
- 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)
1365
1443
  assert_equal "<a />\n", render("%a/", :format => :xhtml)
1366
1444
  end
1367
1445
 
@@ -1376,12 +1454,28 @@ HAML
1376
1454
  assert_equal("<a b='a, b'></a>\n", render("%a{:b => 'a, b'}", :suppress_eval => true))
1377
1455
  assert_equal("<a b='a\tb'></a>\n", render('%a{:b => "a\tb"}', :suppress_eval => true))
1378
1456
  assert_equal("<a b='a\#{foo}b'></a>\n", render('%a{:b => "a\\#{foo}b"}', :suppress_eval => true))
1457
+ assert_equal("<a b='#f00'></a>\n", render("%a{:b => '#f00'}", :suppress_eval => true))
1379
1458
  end
1380
1459
 
1381
1460
  def test_dynamic_hashes_with_suppress_eval
1382
1461
  assert_equal("<a></a>\n", render('%a{:b => "a #{1 + 1} b", :c => "d"}', :suppress_eval => true))
1383
1462
  end
1384
1463
 
1464
+ def test_interpolates_instance_vars_in_attribute_values
1465
+ scope = Object.new
1466
+ scope.instance_variable_set :@foo, 'bar'
1467
+ assert_equal("<a b='a bar b'></a>\n", render('%a{:b => "a #@foo b"}', :scope => scope))
1468
+ end
1469
+
1470
+ def test_interpolates_global_vars_in_attribute_values
1471
+ # make sure the value isn't just interpolated in during template compilation
1472
+ engine = Haml::Engine.new('%a{:b => "a #$global_var_for_testing b"}')
1473
+ $global_var_for_testing = 'bar'
1474
+ assert_equal("<a b='a bar b'></a>\n", engine.to_html)
1475
+ ensure
1476
+ $global_var_for_testing = nil
1477
+ end
1478
+
1385
1479
  def test_utf8_attrs
1386
1480
  assert_equal("<a href='héllo'></a>\n", render("%a{:href => 'héllo'}"))
1387
1481
  assert_equal("<a href='héllo'></a>\n", render("%a(href='héllo')"))
@@ -1390,7 +1484,7 @@ HAML
1390
1484
  # HTML 4.0
1391
1485
 
1392
1486
  def test_html_has_no_self_closing_tags
1393
- 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)
1394
1488
  assert_equal "<br>\n", render("%br/", :format => :html4)
1395
1489
  end
1396
1490
 
@@ -1434,7 +1528,7 @@ HAML
1434
1528
  render("%div{:data => {:one_plus_one => 1+1}}",
1435
1529
  :hyphenate_data_attrs => false))
1436
1530
 
1437
- 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",
1438
1532
  render(%{%div{:data => {:foo => %{Here's a "quoteful" string.}}}},
1439
1533
  :hyphenate_data_attrs => false)) #'
1440
1534
  end
@@ -1453,6 +1547,21 @@ HAML
1453
1547
  render("%div{:foo => {:baz => 'bang'}}"))
1454
1548
  end
1455
1549
 
1550
+ def test_arbitrary_attribute_hash_merging
1551
+ assert_equal(%Q{<a aria-baz='qux' aria-foo='bar'></a>\n}, render(<<-HAML))
1552
+ - h1 = {:aria => {:foo => :bar}}
1553
+ - h2 = {:baz => :qux}
1554
+ %a{h1, :aria => h2}
1555
+ HAML
1556
+ end
1557
+
1558
+ def test_hash_method_call_in_attributes
1559
+ assert_equal(%Q{<a foo='bar' hoge='fuga'></a>\n}, render(<<-HAML))
1560
+ - hash = {:hoge => :fuga}
1561
+ %a{{foo: 'bar'}.merge(hash)}
1562
+ HAML
1563
+ end
1564
+
1456
1565
  def test_html5_data_attributes_with_nested_hash
1457
1566
  assert_equal("<div data-a-b='c'></div>\n", render(<<-HAML))
1458
1567
  - hash = {:a => {:b => 'c'}}
@@ -1478,32 +1587,36 @@ HAML
1478
1587
  end
1479
1588
 
1480
1589
  def test_html5_data_attributes_with_attr_method
1481
- Haml::Helpers.module_eval do
1482
- def data_hash
1483
- {:data => {:foo => "bar", :baz => "bang"}}
1484
- end
1590
+ obj = Object.new
1591
+ def obj.data_hash
1592
+ {:data => {:foo => "bar", :baz => "bang"}}
1593
+ end
1485
1594
 
1486
- def data_val
1487
- {:data => "dat"}
1488
- end
1595
+ def obj.data_val
1596
+ {:data => "dat"}
1489
1597
  end
1490
1598
 
1491
1599
  assert_equal("<div data-baz='bang' data-brat='wurst' data-foo='blip'></div>\n",
1492
- render("%div{data_hash, :data => {:foo => 'blip', :brat => 'wurst'}}"))
1600
+ render("%div{data_hash, :data => {:foo => 'blip', :brat => 'wurst'}}", scope: obj))
1493
1601
  assert_equal("<div data-baz='bang' data-foo='blip'></div>\n",
1494
- render("%div{data_hash, 'data-foo' => 'blip'}"))
1602
+ render("%div{data_hash, 'data-foo' => 'blip'}", scope: obj))
1495
1603
  assert_equal("<div data-baz='bang' data-foo='bar' data='dat'></div>\n",
1496
- render("%div{data_hash, :data => 'dat'}"))
1604
+ render("%div{data_hash, :data => 'dat'}", scope: obj))
1497
1605
  assert_equal("<div data-brat='wurst' data-foo='blip' data='dat'></div>\n",
1498
- render("%div{data_val, :data => {:foo => 'blip', :brat => 'wurst'}}"))
1606
+ render("%div{data_val, :data => {:foo => 'blip', :brat => 'wurst'}}", scope: obj))
1607
+ end
1608
+
1609
+ def test_html5_data_attributes_with_identical_attribute_values
1610
+ assert_equal("<div data-x='50' data-y='50'></div>\n",
1611
+ render("%div{:data => {:x => 50, :y => 50}}"))
1499
1612
  end
1500
1613
 
1501
1614
  def test_xml_doc_using_html5_format_and_mime_type
1502
1615
  assert_equal(<<XML, render(<<HAML, { :format => :html5, :mime_type => 'text/xml' }))
1503
1616
  <?xml version='1.0' encoding='utf-8' ?>
1504
1617
  <root>
1505
- <element />
1506
- <hr />
1618
+ <element />
1619
+ <hr />
1507
1620
  </root>
1508
1621
  XML
1509
1622
  !!! XML
@@ -1517,8 +1630,8 @@ HAML
1517
1630
  assert_equal(<<XML, render(<<HAML, { :format => :html4, :mime_type => 'text/xml' }))
1518
1631
  <?xml version='1.0' encoding='utf-8' ?>
1519
1632
  <root>
1520
- <element />
1521
- <hr />
1633
+ <element />
1634
+ <hr />
1522
1635
  </root>
1523
1636
  XML
1524
1637
  !!! XML
@@ -1584,10 +1697,10 @@ HAML
1584
1697
 
1585
1698
  def test_new_attribute_parsing
1586
1699
  assert_equal("<a a2='b2'>bar</a>\n", render("%a(a2=b2) bar", :locals => {:b2 => 'b2'}))
1587
- assert_equal(%Q{<a a='foo"bar'>bar</a>\n}, render(%q{%a(a="#{'foo"bar'}") bar})) #'
1588
- assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #'
1589
- assert_equal(%Q{<a a='foo"bar'>bar</a>\n}, render(%q{%a(a='foo"bar') bar}))
1590
- assert_equal(%Q{<a a="foo'bar">bar</a>\n}, render(%q{%a(a="foo'bar") bar}))
1700
+ assert_equal(%Q{<a a='foo&quot;bar'>bar</a>\n}, render(%q{%a(a="#{'foo"bar'}") bar})) #'
1701
+ assert_equal(%Q{<a a='foo&#39;bar'>bar</a>\n}, render(%q{%a(a="#{"foo'bar"}") bar})) #'
1702
+ assert_equal(%Q{<a a='foo&quot;bar'>bar</a>\n}, render(%q{%a(a='foo"bar') bar}))
1703
+ assert_equal(%Q{<a a='foo&#39;bar'>bar</a>\n}, render(%q{%a(a="foo'bar") bar}))
1591
1704
  assert_equal("<a a:b='foo'>bar</a>\n", render("%a(a:b='foo') bar"))
1592
1705
  assert_equal("<a a='foo' b='bar'>bar</a>\n", render("%a(a = 'foo' b = 'bar') bar"))
1593
1706
  assert_equal("<a a='foo' b='bar'>bar</a>\n", render("%a(a = foo b = bar) bar", :locals => {:foo => 'foo', :bar => 'bar'}))
@@ -1597,11 +1710,11 @@ HAML
1597
1710
  end
1598
1711
 
1599
1712
  def test_new_attribute_escaping
1600
- assert_equal(%Q{<a a='foo " bar'>bar</a>\n}, render(%q{%a(a="foo \" bar") bar}))
1601
- assert_equal(%Q{<a a='foo \\" bar'>bar</a>\n}, render(%q{%a(a="foo \\\\\" bar") bar}))
1713
+ assert_equal(%Q{<a a='foo &quot; bar'>bar</a>\n}, render(%q{%a(a="foo \" bar") bar}))
1714
+ assert_equal(%Q{<a a='foo \\&quot; bar'>bar</a>\n}, render(%q{%a(a="foo \\\\\" bar") bar}))
1602
1715
 
1603
- assert_equal(%Q{<a a="foo ' bar">bar</a>\n}, render(%q{%a(a='foo \' bar') bar}))
1604
- assert_equal(%Q{<a a="foo \\' bar">bar</a>\n}, render(%q{%a(a='foo \\\\\' bar') bar}))
1716
+ assert_equal(%Q{<a a='foo &#39; bar'>bar</a>\n}, render(%q{%a(a='foo \' bar') bar}))
1717
+ assert_equal(%Q{<a a='foo \\&#39; bar'>bar</a>\n}, render(%q{%a(a='foo \\\\\' bar') bar}))
1605
1718
 
1606
1719
  assert_equal(%Q{<a a='foo \\ bar'>bar</a>\n}, render(%q{%a(a="foo \\\\ bar") bar}))
1607
1720
  assert_equal(%Q{<a a='foo \#{1 + 1} bar'>bar</a>\n}, render(%q{%a(a="foo \#{1 + 1} bar") bar}))
@@ -1630,6 +1743,8 @@ HAML
1630
1743
  locals = {:b => 'b', :d => 'd'}
1631
1744
  assert_equal("<p a='b' c='d'></p>\n", render("%p{:a => b}(c=d)", :locals => locals))
1632
1745
  assert_equal("<p a='b' c='d'></p>\n", render("%p(a=b){:c => d}", :locals => locals))
1746
+
1747
+ 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))
1633
1748
  end
1634
1749
 
1635
1750
  # Ruby Multiline
@@ -1677,11 +1792,7 @@ HAML
1677
1792
  end
1678
1793
 
1679
1794
  def test_ruby_character_literals_are_not_continuation
1680
- html = if RUBY_VERSION < "1.9"
1681
- "44\n44\n<p>foo</p>\n"
1682
- else
1683
- ",\n,\n<p>foo</p>\n"
1684
- end
1795
+ html = ",\n,\n<p>foo</p>\n"
1685
1796
  assert_equal(html, render(<<HAML))
1686
1797
  = ?,
1687
1798
  = ?\,
@@ -1733,8 +1844,7 @@ HAML
1733
1844
 
1734
1845
  def test_loud_ruby_multiline_with_block
1735
1846
  assert_equal(<<HTML, render(<<HAML))
1736
- #{%w[far faz fang]}
1737
- <p>foo</p>
1847
+ #{%w[far faz fang]}<p>foo</p>
1738
1848
  <p>bar</p>
1739
1849
  HTML
1740
1850
  = ["bar",
@@ -1847,7 +1957,7 @@ HAML
1847
1957
  def test_utf_8_bom
1848
1958
  assert_equal <<HTML, render(<<HAML)
1849
1959
  <div class='foo'>
1850
- <p>baz</p>
1960
+ <p>baz</p>
1851
1961
  </div>
1852
1962
  HTML
1853
1963
  \xEF\xBB\xBF.foo
@@ -1855,60 +1965,59 @@ HTML
1855
1965
  HAML
1856
1966
  end
1857
1967
 
1858
- unless RUBY_VERSION < "1.9"
1859
- def test_default_encoding
1860
- assert_equal(Encoding.find("utf-8"), render(<<HAML.encode("us-ascii")).encoding)
1968
+ def test_default_encoding
1969
+ assert_equal(Encoding.find("utf-8"), render(<<HAML.encode("us-ascii")).encoding)
1861
1970
  %p bar
1862
1971
  %p foo
1863
1972
  HAML
1864
- end
1973
+ end
1865
1974
 
1866
- def test_fake_ascii_encoding
1867
- assert_encoded_equal(<<HTML.force_encoding("ascii-8bit"), render(<<HAML, :encoding => "ascii-8bit"))
1975
+ def test_fake_ascii_encoding
1976
+ assert_encoded_equal(<<HTML.force_encoding("ascii-8bit"), render(<<HAML, :encoding => "ascii-8bit"))
1868
1977
  <p>bâr</p>
1869
1978
  <p>föö</p>
1870
1979
  HTML
1871
1980
  %p bâr
1872
1981
  %p föö
1873
1982
  HAML
1874
- end
1983
+ end
1875
1984
 
1876
- def test_convert_template_render_proc
1877
- assert_converts_template_properly {|e| e.render_proc.call}
1878
- end
1985
+ def test_convert_template_render_proc
1986
+ assert_converts_template_properly {|e| e.render_proc.call}
1987
+ end
1879
1988
 
1880
- def test_convert_template_render
1881
- assert_converts_template_properly {|e| e.render}
1882
- end
1989
+ def test_convert_template_render
1990
+ assert_converts_template_properly {|e| e.render}
1991
+ end
1883
1992
 
1884
- def test_convert_template_def_method
1885
- assert_converts_template_properly do |e|
1886
- o = Object.new
1887
- e.def_method(o, :render)
1888
- o.render
1889
- end
1993
+ def test_convert_template_def_method
1994
+ assert_converts_template_properly do |e|
1995
+ o = Object.new
1996
+ e.def_method(o, :render)
1997
+ o.render
1890
1998
  end
1999
+ end
1891
2000
 
1892
- def test_encoding_error
1893
- render("foo\nbar\nb\xFEaz".force_encoding("utf-8"))
1894
- assert(false, "Expected exception")
1895
- rescue Haml::Error => e
1896
- assert_equal(3, e.line)
1897
- assert_match(/Invalid .* character/, e.message)
1898
- end
2001
+ def test_encoding_error
2002
+ render("foo\nbar\nb\xFEaz".force_encoding("utf-8"))
2003
+ assert(false, "Expected exception")
2004
+ rescue Haml::Error => e
2005
+ assert_equal(3, e.line)
2006
+ assert_match(/Invalid .* character/, e.message)
2007
+ end
1899
2008
 
1900
- def test_ascii_incompatible_encoding_error
1901
- template = "foo\nbar\nb_z".encode("utf-16le")
1902
- template[9] = "\xFE".force_encoding("utf-16le")
1903
- render(template)
1904
- assert(false, "Expected exception")
1905
- rescue Haml::Error => e
1906
- assert_equal(3, e.line)
1907
- assert_match(/Invalid .* character/, e.message)
1908
- end
2009
+ def test_ascii_incompatible_encoding_error
2010
+ template = "foo\nbar\nb_z".encode("utf-16le")
2011
+ template[9] = "\xFE".force_encoding("utf-16le")
2012
+ render(template)
2013
+ assert(false, "Expected exception")
2014
+ rescue Haml::Error => e
2015
+ assert_equal(3, e.line)
2016
+ assert_match(/Invalid .* character/, e.message)
2017
+ end
1909
2018
 
1910
- def test_same_coding_comment_as_encoding
1911
- assert_renders_encoded(<<HTML, <<HAML)
2019
+ def test_same_coding_comment_as_encoding
2020
+ assert_renders_encoded(<<HTML, <<HAML)
1912
2021
  <p>bâr</p>
1913
2022
  <p>föö</p>
1914
2023
  HTML
@@ -1916,34 +2025,33 @@ HTML
1916
2025
  %p bâr
1917
2026
  %p föö
1918
2027
  HAML
1919
- end
1920
-
1921
- def test_coding_comments
1922
- assert_valid_encoding_comment("-# coding: ibm866")
1923
- assert_valid_encoding_comment("-# CodINg: IbM866")
1924
- assert_valid_encoding_comment("-#coding:ibm866")
1925
- assert_valid_encoding_comment("-# CodINg= ibm866")
1926
- assert_valid_encoding_comment("-# foo BAR FAOJcoding: ibm866")
1927
- assert_valid_encoding_comment("-# coding: ibm866 ASFJ (&(&#!$")
1928
- assert_valid_encoding_comment("-# -*- coding: ibm866")
1929
- assert_valid_encoding_comment("-# coding: ibm866 -*- coding: blah")
1930
- assert_valid_encoding_comment("-# -*- coding: ibm866 -*-")
1931
- assert_valid_encoding_comment("-# -*- encoding: ibm866 -*-")
1932
- assert_valid_encoding_comment('-# -*- coding: "ibm866" -*-')
1933
- assert_valid_encoding_comment("-#-*-coding:ibm866-*-")
1934
- assert_valid_encoding_comment("-#-*-coding:ibm866-*-")
1935
- assert_valid_encoding_comment("-# -*- foo: bar; coding: ibm866; baz: bang -*-")
1936
- assert_valid_encoding_comment("-# foo bar coding: baz -*- coding: ibm866 -*-")
1937
- assert_valid_encoding_comment("-# -*- coding: ibm866 -*- foo bar coding: baz")
1938
- end
2028
+ end
1939
2029
 
1940
- def test_different_coding_than_system
1941
- assert_renders_encoded(<<HTML.encode("IBM866"), <<HAML.encode("IBM866"))
2030
+ def test_coding_comments
2031
+ assert_valid_encoding_comment("-# coding: ibm866")
2032
+ assert_valid_encoding_comment("-# CodINg: IbM866")
2033
+ assert_valid_encoding_comment("-#coding:ibm866")
2034
+ assert_valid_encoding_comment("-# CodINg= ibm866")
2035
+ assert_valid_encoding_comment("-# foo BAR FAOJcoding: ibm866")
2036
+ assert_valid_encoding_comment("-# coding: ibm866 ASFJ (&(&#!$")
2037
+ assert_valid_encoding_comment("-# -*- coding: ibm866")
2038
+ assert_valid_encoding_comment("-# coding: ibm866 -*- coding: blah")
2039
+ assert_valid_encoding_comment("-# -*- coding: ibm866 -*-")
2040
+ assert_valid_encoding_comment("-# -*- encoding: ibm866 -*-")
2041
+ assert_valid_encoding_comment('-# -*- coding: "ibm866" -*-')
2042
+ assert_valid_encoding_comment("-#-*-coding:ibm866-*-")
2043
+ assert_valid_encoding_comment("-#-*-coding:ibm866-*-")
2044
+ assert_valid_encoding_comment("-# -*- foo: bar; coding: ibm866; baz: bang -*-")
2045
+ assert_valid_encoding_comment("-# foo bar coding: baz -*- coding: ibm866 -*-")
2046
+ assert_valid_encoding_comment("-# -*- coding: ibm866 -*- foo bar coding: baz")
2047
+ end
2048
+
2049
+ def test_different_coding_than_system
2050
+ assert_renders_encoded(<<HTML.encode("IBM866"), <<HAML.encode("IBM866"))
1942
2051
  <p>тАЬ</p>
1943
2052
  HTML
1944
2053
  %p тАЬ
1945
2054
  HAML
1946
- end
1947
2055
  end
1948
2056
 
1949
2057
  def test_block_spacing
@@ -1958,6 +2066,28 @@ HAML
1958
2066
  end
1959
2067
  end
1960
2068
 
2069
+ def test_tracing
2070
+ result = render('%p{:class => "hello"}', :trace => true, :filename => 'foo').strip
2071
+ assert_equal "<p class='hello' data-trace='foo:1'></p>", result
2072
+ end
2073
+
2074
+ def test_unsafe_dynamic_attribute_name_raises_invalid_attribute_name_error
2075
+ assert_raises(Haml::InvalidAttributeNameError) do
2076
+ render(<<-HAML)
2077
+ - params = { 'x /><script>alert(1);</script><div x' => 'hello' }
2078
+ %div{ data: params }
2079
+ HAML
2080
+ end
2081
+ end
2082
+
2083
+ def test_unsafe_static_attribute_name_raises_invalid_attribute_name_error
2084
+ assert_raises(Haml::InvalidAttributeNameError) do
2085
+ render(<<-HAML)
2086
+ %div{ 'x /><script>alert(1);</script><div x' => 'hello' }
2087
+ HAML
2088
+ end
2089
+ end
2090
+
1961
2091
  private
1962
2092
 
1963
2093
  def assert_valid_encoding_comment(comment)