haml 4.0.7 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -1
  3. data/CHANGELOG.md +42 -4
  4. data/FAQ.md +4 -14
  5. data/MIT-LICENSE +1 -1
  6. data/README.md +85 -42
  7. data/REFERENCE.md +108 -57
  8. data/Rakefile +46 -54
  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 +22 -132
  13. data/lib/haml/compiler.rb +87 -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 +18 -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 +36 -58
  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 +4 -1
  25. data/lib/haml/helpers/xss_mods.rb +18 -12
  26. data/lib/haml/helpers.rb +133 -90
  27. data/lib/haml/options.rb +38 -47
  28. data/lib/haml/parser.rb +278 -216
  29. data/lib/haml/{template/plugin.rb → plugin.rb} +8 -15
  30. data/lib/haml/railtie.rb +21 -12
  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 +1 -0
  39. data/test/attribute_parser_test.rb +101 -0
  40. data/test/engine_test.rb +287 -176
  41. data/test/filters_test.rb +32 -19
  42. data/test/gemfiles/Gemfile.rails-4.0.x +9 -3
  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 +224 -112
  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 +77 -76
  67. data/test/template_test.rb +24 -56
  68. data/test/template_test_helper.rb +38 -0
  69. data/test/templates/bemit.haml +3 -0
  70. data/test/templates/just_stuff.haml +1 -0
  71. data/test/templates/standard_ugly.haml +1 -0
  72. data/test/templates/with_bom.haml +1 -0
  73. data/test/temple_line_counter_test.rb +40 -0
  74. data/test/test_helper.rb +26 -8
  75. data/test/util_test.rb +6 -47
  76. metadata +53 -43
  77. data/test/gemfiles/Gemfile.rails-3.0.x +0 -5
  78. data/test/gemfiles/Gemfile.rails-3.1.x +0 -6
  79. data/test/gemfiles/Gemfile.rails-3.2.x +0 -5
  80. data/test/haml-spec/LICENSE +0 -14
  81. data/test/haml-spec/README.md +0 -106
  82. data/test/haml-spec/lua_haml_spec.lua +0 -38
  83. data/test/haml-spec/perl_haml_test.pl +0 -81
  84. data/test/haml-spec/ruby_haml_test.rb +0 -23
  85. data/test/haml-spec/tests.json +0 -660
  86. data/test/templates/_av_partial_1_ugly.haml +0 -9
  87. data/test/templates/_av_partial_2_ugly.haml +0 -5
  88. data/test/templates/action_view_ugly.haml +0 -47
  89. data/test/templates/standard_ugly.haml +0 -43
data/test/helper_test.rb CHANGED
@@ -1,32 +1,13 @@
1
1
  require 'test_helper'
2
+ require "active_model/naming"
2
3
 
3
- class ActionView::Base
4
- def nested_tag
5
- content_tag(:span) {content_tag(:div) {"something"}}
6
- end
7
-
8
- def wacky_form
9
- form_tag("/foo") {"bar"}
10
- end
4
+ class FormModel
5
+ extend ActiveModel::Naming
11
6
  end
12
7
 
13
- module Haml::Helpers
14
- def something_that_uses_haml_concat
15
- haml_concat('foo').to_s
16
- end
17
-
18
- def render_something_with_haml_concat
19
- haml_concat "<p>"
20
- end
21
-
22
- def render_something_with_haml_tag_and_concat
23
- haml_tag 'p' do
24
- haml_concat '<foo>'
25
- end
26
- end
27
- end
8
+ class HelperTest < Haml::TestCase
9
+ TEXT_AREA_CONTENT_REGEX = /<(textarea)[^>]*>\n(.*?)<\/\1>/im
28
10
 
29
- class HelperTest < MiniTest::Unit::TestCase
30
11
  Post = Struct.new('Post', :body, :error_field, :errors)
31
12
  class PostErrors
32
13
  def on(name)
@@ -41,16 +22,18 @@ class HelperTest < MiniTest::Unit::TestCase
41
22
  end
42
23
 
43
24
  def setup
44
- @base = ActionView::Base.new
25
+ @base = Class.new(ActionView::Base) {
26
+ def nested_tag
27
+ content_tag(:span) {content_tag(:div) {"something"}}
28
+ end
29
+
30
+ def wacky_form
31
+ form_tag("/foo") {"bar"}
32
+ end
33
+ }.new
45
34
  @base.controller = ActionController::Base.new
46
35
  @base.view_paths << File.expand_path("../templates", __FILE__)
47
-
48
- if defined?(ActionController::Response)
49
- # This is needed for >=3.0.0
50
- @base.controller.response = ActionController::Response.new
51
- end
52
-
53
- @base.instance_variable_set('@post', Post.new("Foo bar\nbaz", nil, PostErrors.new))
36
+ @base.instance_variable_set(:@post, Post.new("Foo bar\nbaz", nil, PostErrors.new))
54
37
  end
55
38
 
56
39
  def render(text, options = {})
@@ -59,12 +42,29 @@ class HelperTest < MiniTest::Unit::TestCase
59
42
  end
60
43
 
61
44
  def test_rendering_with_escapes
45
+ def @base.render_something_with_haml_concat
46
+ haml_concat "<p>"
47
+ end
48
+ def @base.render_something_with_haml_tag_and_concat
49
+ haml_tag 'p' do
50
+ haml_concat '<foo>'
51
+ end
52
+ end
53
+
62
54
  output = render(<<-HAML, :action_view)
63
55
  - render_something_with_haml_concat
64
56
  - render_something_with_haml_tag_and_concat
65
57
  - render_something_with_haml_concat
66
58
  HAML
67
- assert_equal("&lt;p&gt;\n<p>\n <foo>\n</p>\n&lt;p&gt;\n", output)
59
+ assert_equal("&lt;p&gt;\n<p>\n &lt;foo&gt;\n</p>\n&lt;p&gt;\n", output)
60
+ end
61
+
62
+ def test_with_raw_haml_concat
63
+ haml = <<HAML
64
+ - with_raw_haml_concat do
65
+ - haml_concat "<>&"
66
+ HAML
67
+ assert_equal("<>&\n", render(haml, :action_view))
68
68
  end
69
69
 
70
70
  def test_flatten
@@ -79,13 +79,13 @@ HAML
79
79
  end
80
80
 
81
81
  def test_list_of_should_render_correctly
82
- assert_equal("<li>1</li>\n<li>2</li>\n", render("= list_of([1, 2]) do |i|\n = i"))
83
- assert_equal("<li>[1]</li>\n", render("= list_of([[1]]) do |i|\n = i.inspect"))
84
- assert_equal("<li>\n <h1>Fee</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fi</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fo</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fum</h1>\n <p>A word!</p>\n</li>\n",
82
+ assert_equal("<li>1</li>\n<li>2</li>", render("= list_of([1, 2]) do |i|\n = i"))
83
+ assert_equal("<li>[1]</li>", render("= list_of([[1]]) do |i|\n = i.inspect"))
84
+ assert_equal("<li>\n <h1>Fee</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fi</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fo</h1>\n <p>A word!</p>\n</li>\n<li>\n <h1>Fum</h1>\n <p>A word!</p>\n</li>",
85
85
  render("= list_of(['Fee', 'Fi', 'Fo', 'Fum']) do |title|\n %h1= title\n %p A word!"))
86
- assert_equal("<li c='3'>1</li>\n<li c='3'>2</li>\n", render("= list_of([1, 2], {:c => 3}) do |i|\n = i"))
87
- assert_equal("<li c='3'>[1]</li>\n", render("= list_of([[1]], {:c => 3}) do |i|\n = i.inspect"))
88
- assert_equal("<li c='3'>\n <h1>Fee</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fi</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fo</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fum</h1>\n <p>A word!</p>\n</li>\n",
86
+ assert_equal("<li c='3'>1</li>\n<li c='3'>2</li>", render("= list_of([1, 2], {:c => 3}) do |i|\n = i"))
87
+ assert_equal("<li c='3'>[1]</li>", render("= list_of([[1]], {:c => 3}) do |i|\n = i.inspect"))
88
+ assert_equal("<li c='3'>\n <h1>Fee</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fi</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fo</h1>\n <p>A word!</p>\n</li>\n<li c='3'>\n <h1>Fum</h1>\n <p>A word!</p>\n</li>",
89
89
  render("= list_of(['Fee', 'Fi', 'Fo', 'Fum'], {:c => 3}) do |title|\n %h1= title\n %p A word!"))
90
90
  end
91
91
 
@@ -95,15 +95,15 @@ HAML
95
95
  end
96
96
 
97
97
  def test_tabs
98
- assert_equal("foo\n bar\nbaz\n", render("foo\n- tab_up\nbar\n- tab_down\nbaz"))
99
- assert_equal(" <p>tabbed</p>\n", render("- buffer.tabulation=5\n%p tabbed"))
98
+ assert_equal("foo\nbar\nbaz\n", render("foo\n- tab_up\nbar\n- tab_down\nbaz"))
99
+ assert_equal("<p>tabbed</p>\n", render("- buffer.tabulation=5\n%p tabbed"))
100
100
  end
101
101
 
102
102
  def test_with_tabs
103
103
  assert_equal(<<HTML, render(<<HAML))
104
104
  Foo
105
- Bar
106
- Baz
105
+ Bar
106
+ Baz
107
107
  Baz
108
108
  HTML
109
109
  Foo
@@ -120,7 +120,7 @@ HAML
120
120
 
121
121
  begin
122
122
  ActionView::Base.new.render(:inline => "<%= flatten('Foo\\nBar') %>")
123
- rescue NoMethodError, Haml::Util.av_template_class(:Error)
123
+ rescue NoMethodError, ActionView::Template::Error
124
124
  proper_behavior = true
125
125
  end
126
126
  assert(proper_behavior)
@@ -138,18 +138,26 @@ HAML
138
138
  end
139
139
 
140
140
  def test_form_tag
141
- # This is usually provided by ActionController::Base.
142
141
  def @base.protect_against_forgery?; false; end
143
-
144
142
  rendered = render(<<HAML, :action_view)
145
143
  = form_tag 'foo' do
146
- %p bar
147
- %strong baz
144
+ %p bar
145
+ %strong baz
148
146
  HAML
149
- fragment = Nokogiri::HTML.fragment(rendered)
150
- assert_equal 'foo', fragment.css('form').first.attributes['action'].to_s
151
- assert_equal 'bar', fragment.css('form p').first.text.strip
152
- assert_equal 'baz', fragment.css('form strong').first.text.strip
147
+ fragment = Nokogiri::HTML.fragment(rendered)
148
+ assert_equal 'foo', fragment.css('form').first.attributes['action'].to_s
149
+ assert_equal 'bar', fragment.css('form p').first.text.strip
150
+ assert_equal 'baz', fragment.css('form strong').first.text.strip
151
+ end
152
+
153
+ def test_form_for
154
+ # FIXME: current HAML doesn't do proper indentation with form_for (it's the capture { output } in #form_for).
155
+ def @base.protect_against_forgery?; false; end
156
+ rendered = render(<<HAML, :action_view)
157
+ = form_for OpenStruct.new, url: 'foo', as: :post do |f|
158
+ = f.text_field :name
159
+ HAML
160
+ assert_match(/<(form|div)[^>]+><input/, rendered)
153
161
  end
154
162
 
155
163
  def test_pre
@@ -157,56 +165,40 @@ HAML
157
165
  render('= content_tag "pre", "Foo bar\n baz"', :action_view))
158
166
  end
159
167
 
160
- # Rails >= 3.2.3 adds a newline after opening textarea tags.
161
- def self.rails_text_area_helpers_emit_a_newline?
162
- major, minor, tiny = ActionPack::VERSION::MAJOR, ActionPack::VERSION::MINOR, ActionPack::VERSION::TINY
163
- major == 4 || ((major == 3) && (minor >= 2) && (tiny >= 3))
164
- end
165
-
166
- def text_area_content_regex
167
- @text_area_content_regex ||= if self.class.rails_text_area_helpers_emit_a_newline?
168
- /<(textarea)[^>]*>\n(.*?)<\/\1>/im
169
- else
170
- /<(textarea)[^>]*>(.*?)<\/\1>/im
171
- end
172
- end
173
-
174
168
  def test_text_area_tag
175
169
  output = render('= text_area_tag "body", "Foo\nBar\n Baz\n Boom"', :action_view)
176
- match_data = output.match(text_area_content_regex)
170
+ match_data = output.match(TEXT_AREA_CONTENT_REGEX)
177
171
  assert_equal "Foo&#x000A;Bar&#x000A; Baz&#x000A; Boom", match_data[2]
178
172
  end
179
173
 
180
174
  def test_text_area
181
175
  output = render('= text_area :post, :body', :action_view)
182
- match_data = output.match(text_area_content_regex)
176
+ match_data = output.match(TEXT_AREA_CONTENT_REGEX)
183
177
  assert_equal "Foo bar&#x000A;baz", match_data[2]
184
178
  end
185
179
 
186
180
  def test_partials_should_not_cause_textareas_to_be_indented
187
181
  # non-indentation of textareas rendered inside partials
188
- @base.instance_variable_set('@post', Post.new("Foo", nil, PostErrors.new))
182
+ @base.instance_variable_set(:@post, Post.new("Foo", nil, PostErrors.new))
189
183
  output = render(".foo\n .bar\n = render '/text_area_helper'", :action_view)
190
- match_data = output.match(text_area_content_regex)
184
+ match_data = output.match(TEXT_AREA_CONTENT_REGEX)
191
185
  assert_equal 'Foo', match_data[2]
192
186
  end
193
187
 
194
- if rails_text_area_helpers_emit_a_newline?
195
- def test_textareas_should_prerve_leading_whitespace
196
- # leading whitespace preservation
197
- @base.instance_variable_set('@post', Post.new(" Foo", nil, PostErrors.new))
198
- output = render(".foo\n = text_area :post, :body", :action_view)
199
- match_data = output.match(text_area_content_regex)
200
- assert_equal '&#x0020; Foo', match_data[2]
201
- end
188
+ def test_textareas_should_preserve_leading_whitespace
189
+ # leading whitespace preservation
190
+ @base.instance_variable_set(:@post, Post.new(" Foo", nil, PostErrors.new))
191
+ output = render(".foo\n = text_area :post, :body", :action_view)
192
+ match_data = output.match(TEXT_AREA_CONTENT_REGEX)
193
+ assert_equal '&#x0020; Foo', match_data[2]
194
+ end
202
195
 
203
- def test_textareas_should_prerve_leading_whitespace_in_partials
204
- # leading whitespace in textareas rendered inside partials
205
- @base.instance_variable_set('@post', Post.new(" Foo", nil, PostErrors.new))
206
- output = render(".foo\n .bar\n = render '/text_area_helper'", :action_view)
207
- match_data = output.match(text_area_content_regex)
208
- assert_equal '&#x0020; Foo', match_data[2]
209
- end
196
+ def test_textareas_should_preserve_leading_whitespace_in_partials
197
+ # leading whitespace in textareas rendered inside partials
198
+ @base.instance_variable_set(:@post, Post.new(" Foo", nil, PostErrors.new))
199
+ output = render(".foo\n .bar\n = render '/text_area_helper'", :action_view)
200
+ match_data = output.match(TEXT_AREA_CONTENT_REGEX)
201
+ assert_equal '&#x0020; Foo', match_data[2]
210
202
  end
211
203
 
212
204
  def test_capture_haml
@@ -306,8 +298,12 @@ HAML
306
298
  assert_equal("<p id='foo&amp;bar'>baz</p>\n", render("%p{:id => 'foo&bar'} baz", :escape_html => true))
307
299
  end
308
300
 
309
- def test_haml_tag_autoclosed_tags_are_closed
310
- assert_equal("<br class='foo' />\n", render("- haml_tag :br, :class => 'foo'"))
301
+ def test_haml_tag_autoclosed_tags_are_closed_xhtml
302
+ assert_equal("<br class='foo' />\n", render("- haml_tag :br, :class => 'foo'", :format => :xhtml))
303
+ end
304
+
305
+ def test_haml_tag_autoclosed_tags_are_closed_html
306
+ assert_equal("<br class='foo'>\n", render("- haml_tag :br, :class => 'foo'", :format => :html5))
311
307
  end
312
308
 
313
309
  def test_haml_tag_with_class_array
@@ -338,7 +334,8 @@ HAML
338
334
  end
339
335
 
340
336
  def test_haml_tag_flags
341
- assert_equal("<p />\n", render("- haml_tag :p, :/"))
337
+ assert_equal("<p />\n", render("- haml_tag :p, :/", :format => :xhtml))
338
+ assert_equal("<p>\n", render("- haml_tag :p, :/", :format => :html5))
342
339
  assert_equal("<p>kumquat</p>\n", render("- haml_tag :p, :< do\n kumquat"))
343
340
 
344
341
  assert_raises(Haml::Error) { render("- haml_tag :p, 'foo', :/") }
@@ -361,12 +358,19 @@ HTML
361
358
  HAML
362
359
  end
363
360
 
361
+ def test_haml_concat_inside_haml_tag_escaped_with_xss
362
+ assert_equal("<p>\n &lt;&gt;&amp;\n</p>\n", render(<<HAML, :action_view))
363
+ - haml_tag :p do
364
+ - haml_concat "<>&"
365
+ HAML
366
+ end
367
+
364
368
  def test_haml_concat_with_multiline_string
365
369
  assert_equal(<<HTML, render(<<HAML))
366
370
  <p>
367
- foo
368
- bar
369
- baz
371
+ foo
372
+ bar
373
+ baz
370
374
  </p>
371
375
  HTML
372
376
  %p
@@ -374,10 +378,10 @@ HTML
374
378
  HAML
375
379
  end
376
380
 
377
- def test_haml_tag_with_ugly
378
- assert_equal(<<HTML, render(<<HAML, :ugly => true))
381
+ def test_haml_tag
382
+ assert_equal(<<HTML, render(<<HAML))
379
383
  <p>
380
- <strong>Hi!</strong>
384
+ <strong>Hi!</strong>
381
385
  </p>
382
386
  HTML
383
387
  - haml_tag :p do
@@ -385,6 +389,41 @@ HTML
385
389
  HAML
386
390
  end
387
391
 
392
+ def test_haml_tag_if_positive
393
+ assert_equal(<<HTML, render(<<HAML))
394
+ <div class='conditional'>
395
+ <p>A para</p>
396
+ </div>
397
+ HTML
398
+ - haml_tag_if true, '.conditional' do
399
+ %p A para
400
+ HAML
401
+ end
402
+
403
+ def test_haml_tag_if_positive_with_attributes
404
+ assert_equal(<<HTML, render(<<HAML))
405
+ <div class='conditional' foo='bar'>
406
+ <p>A para</p>
407
+ </div>
408
+ HTML
409
+ - haml_tag_if true, '.conditional', {:foo => 'bar'} do
410
+ %p A para
411
+ HAML
412
+ end
413
+
414
+ def test_haml_tag_if_negative
415
+ assert_equal(<<HTML, render(<<HAML))
416
+ <p>A para</p>
417
+ HTML
418
+ - haml_tag_if false, '.conditional' do
419
+ %p A para
420
+ HAML
421
+ end
422
+
423
+ def test_haml_tag_if_error_return
424
+ assert_raises(Haml::Error) { render("= haml_tag_if false, '.conditional' do\n %p Hello") }
425
+ end
426
+
388
427
  def test_is_haml
389
428
  assert(!ActionView::Base.new.is_haml?)
390
429
  assert_equal("true\n", render("= is_haml?"))
@@ -406,15 +445,14 @@ HAML
406
445
  end
407
446
 
408
447
  def test_capture_deals_properly_with_collections
409
- Haml::Helpers.module_eval do
410
- def trc(collection, &block)
411
- collection.each do |record|
412
- haml_concat capture_haml(record, &block)
413
- end
448
+ obj = Object.new
449
+ def obj.trc(collection, &block)
450
+ collection.each do |record|
451
+ haml_concat capture_haml(record, &block)
414
452
  end
415
453
  end
416
454
 
417
- assert_equal("1\n\n2\n\n3\n\n", render("- trc([1, 2, 3]) do |i|\n = i.inspect"))
455
+ assert_equal("1\n\n2\n\n3\n\n", render("- trc([1, 2, 3]) do |i|\n = i.inspect", scope: obj))
418
456
  end
419
457
 
420
458
  def test_capture_with_string_block
@@ -422,17 +460,57 @@ HAML
422
460
  end
423
461
 
424
462
  def test_capture_with_non_string_value_reurns_nil
425
- Haml::Helpers.module_eval do
426
- def check_capture_returns_nil(&block)
427
- contents = capture(&block)
463
+ def @base.check_capture_returns_nil(&block)
464
+ contents = capture(&block)
428
465
 
429
- contents << "ERROR" if contents
430
- end
466
+ contents << "ERROR" if contents
431
467
  end
432
468
 
433
469
  assert_equal("\n", render("= check_capture_returns_nil { 2 }", :action_view))
434
470
  end
435
471
 
472
+
473
+ class HomemadeViewContext
474
+ include ActionView::Context
475
+ include ActionView::Helpers::FormHelper
476
+
477
+ def initialize
478
+ _prepare_context
479
+ end
480
+
481
+ def url_for(*)
482
+ "/"
483
+ end
484
+
485
+ def dom_class(*)
486
+ end
487
+
488
+ def dom_id(*)
489
+ end
490
+
491
+ def m # I have to inject the model into the view using an instance method, using locals doesn't work.
492
+ FormModel.new
493
+ end
494
+
495
+ def protect_against_forgery?
496
+ end
497
+
498
+ # def capture(*args, &block)
499
+ # capture_haml(*args, &block)
500
+ # end
501
+ end
502
+
503
+ def test_form_for_with_homemade_view_context
504
+ handler = ActionView::Template.handler_for_extension("haml")
505
+ template = ActionView::Template.new(<<HAML, "inline template", handler, {})
506
+ = form_for(m, :url => "/") do
507
+ %b Bold!
508
+ HAML
509
+
510
+ # see if Bold is within form tags:
511
+ assert_match(/<form.*>.*<b>Bold!<\/b>.*<\/form>/m, template.render(HomemadeViewContext.new, {}))
512
+ end
513
+
436
514
  def test_find_and_preserve_with_block
437
515
  assert_equal("<pre>Foo&#x000A;Bar</pre>\nFoo\nBar\n",
438
516
  render("= find_and_preserve do\n %pre\n Foo\n Bar\n Foo\n Bar"))
@@ -444,7 +522,7 @@ HAML
444
522
  end
445
523
 
446
524
  def test_preserve_with_block
447
- assert_equal("<pre>Foo&#x000A;Bar</pre>&#x000A;Foo&#x000A;Bar\n",
525
+ assert_equal("<pre>Foo&#x000A;Bar</pre>&#x000A;Foo&#x000A;Bar",
448
526
  render("= preserve do\n %pre\n Foo\n Bar\n Foo\n Bar"))
449
527
  end
450
528
 
@@ -481,17 +559,22 @@ MESSAGE
481
559
  end
482
560
 
483
561
  def test_error_return_line
484
- render("%p foo\n= haml_concat 'foo'\n%p bar")
562
+ render("%p foo\n= haml_concat('foo').to_s\n%p bar")
485
563
  assert false, "Expected Haml::Error"
486
564
  rescue Haml::Error => e
487
- assert_equal 2, e.backtrace[1].scan(/:(\d+)/).first.first.to_i
565
+ assert_equal 2, e.backtrace[0].scan(/:(\d+)/).first.first.to_i
488
566
  end
489
567
 
490
568
  def test_error_return_line_in_helper
491
- render("- something_that_uses_haml_concat")
569
+ obj = Object.new
570
+ def obj.something_that_uses_haml_concat
571
+ haml_concat('foo').to_s
572
+ end
573
+
574
+ render("- something_that_uses_haml_concat", scope: obj)
492
575
  assert false, "Expected Haml::Error"
493
576
  rescue Haml::Error => e
494
- assert_equal 15, e.backtrace[0].scan(/:(\d+)/).first.first.to_i
577
+ assert_equal __LINE__ - 6, e.backtrace[0].scan(/:(\d+)/).first.first.to_i
495
578
  end
496
579
 
497
580
  class ActsLikeTag
@@ -559,7 +642,7 @@ HAML
559
642
 
560
643
  def test_escape_once_leaves_numeric_references
561
644
  assert_equal "&quot;&gt;&lt;&amp; &#160;", Haml::Helpers.escape_once('"><& &#160;') #decimal
562
- #assert_equal "&quot;&gt;&lt;&amp; &#x00a0;", Haml::Helpers.escape_once('"><& &#x00a0;') #hexadecimal
645
+ assert_equal "&quot;&gt;&lt;&amp; &#x00a0;", Haml::Helpers.escape_once('"><& &#x00a0;') #hexadecimal
563
646
  end
564
647
 
565
648
  def test_escape_once_encoding
@@ -571,6 +654,36 @@ HAML
571
654
  $stderr = old_stderr
572
655
  end
573
656
 
657
+ def test_html_attrs_xhtml
658
+ assert_equal("<html lang='en-US' xml:lang='en-US' xmlns='http://www.w3.org/1999/xhtml'></html>\n",
659
+ render("%html{html_attrs}", :format => :xhtml))
660
+ end
661
+
662
+ def test_html_attrs_html4
663
+ assert_equal("<html lang='en-US'></html>\n",
664
+ render("%html{html_attrs}", :format => :html4))
665
+ end
666
+
667
+ def test_html_attrs_html5
668
+ assert_equal("<html lang='en-US'></html>\n",
669
+ render("%html{html_attrs}", :format => :html5))
670
+ end
671
+
672
+ def test_html_attrs_xhtml_other_lang
673
+ assert_equal("<html lang='es-AR' xml:lang='es-AR' xmlns='http://www.w3.org/1999/xhtml'></html>\n",
674
+ render("%html{html_attrs('es-AR')}", :format => :xhtml))
675
+ end
676
+
677
+ def test_html_attrs_html4_other_lang
678
+ assert_equal("<html lang='es-AR'></html>\n",
679
+ render("%html{html_attrs('es-AR')}", :format => :html4))
680
+ end
681
+
682
+ def test_html_attrs_html5_other_lang
683
+ assert_equal("<html lang='es-AR'></html>\n",
684
+ render("%html{html_attrs('es-AR')}", :format => :html5))
685
+ end
686
+
574
687
  def test_escape_once_should_work_on_frozen_strings
575
688
  begin
576
689
  Haml::Helpers.escape_once('foo'.freeze)
@@ -580,4 +693,3 @@ HAML
580
693
  end
581
694
 
582
695
  end
583
-
@@ -0,0 +1,22 @@
1
+ require 'test_helper'
2
+
3
+ module Haml
4
+ class OptionsTest < Haml::TestCase
5
+ def test_buffer_defaults_have_only_buffer_option_keys
6
+ assert_equal(
7
+ Haml::Options.buffer_option_keys.sort,
8
+ Haml::Options.buffer_defaults.keys.sort,
9
+ )
10
+ end
11
+
12
+ def test_buffer_defaults_values_are_the_same_as_rails_defaults
13
+ rails_defaults = Haml::Options.defaults.merge(Haml::Template.options)
14
+ Haml::Options.buffer_option_keys.each do |key|
15
+ assert_equal(
16
+ rails_defaults[key],
17
+ Haml::Options.buffer_defaults[key], "key: #{key}"
18
+ )
19
+ end
20
+ end
21
+ end
22
+ end
data/test/parser_test.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'test_helper'
2
2
 
3
3
  module Haml
4
- class ParserTest < MiniTest::Unit::TestCase
4
+ class ParserTest < Haml::TestCase
5
5
 
6
6
  test "should raise error for 'else' at wrong indent level" do
7
7
  begin
@@ -94,12 +94,79 @@ module Haml
94
94
  end
95
95
  end
96
96
 
97
+ test "revealed conditional comments are detected" do
98
+ text = "some revealed text"
99
+ cond = "[cond]"
100
+
101
+ node = parse("/!#{cond} #{text}").children[0]
102
+
103
+ assert_equal text, node.value[:text]
104
+ assert_equal cond, node.value[:conditional]
105
+ assert node.value[:revealed]
106
+ end
107
+
108
+ test "hidden conditional comments are detected" do
109
+ text = "some revealed text"
110
+ cond = "[cond]"
111
+
112
+ node = parse("/#{cond} #{text}").children[0]
113
+
114
+ assert_equal text, node.value[:text]
115
+ assert_equal cond, node.value[:conditional]
116
+ refute node.value[:revealed]
117
+ end
118
+
119
+ test "only script lines are checked for continuation keywords" do
120
+ haml = "- if true\n setup\n- else\n else\n"
121
+ node = parse(haml).children[0]
122
+ assert_equal(3, node.children.size)
123
+ end
124
+
125
+ # see #830. Strictly speaking the pipe here is not necessary, but there
126
+ # shouldn't be an error if it is there.
127
+ test "multiline Ruby with extra trailing pipe doesn't raise error" do
128
+ haml = "%p= foo bar, |\n baz"
129
+ begin
130
+ parse haml
131
+ rescue Haml::SyntaxError
132
+ flunk "Should not have raised SyntaxError"
133
+ end
134
+ end
135
+
136
+ test "empty filter doesn't hide following lines" do
137
+ root = parse "%p\n :plain\n %p\n"
138
+ p_element = root.children[0]
139
+ assert_equal 2, p_element.children.size
140
+ assert_equal :filter, p_element.children[0].type
141
+ assert_equal :tag, p_element.children[1].type
142
+ end
143
+
144
+ # Previously blocks under a haml_comment would be rejected if any line was
145
+ # indented by a value that wasn't a multiple of the document indentation.
146
+ test "haml_comment accepts any indentation in content" do
147
+ begin
148
+ parse "-\#\n Indented two spaces\n Indented three spaces"
149
+ rescue Haml::SyntaxError
150
+ flunk "haml_comment should accept any combination of indentation"
151
+ end
152
+ end
153
+
154
+ test "block haml_comment includes text" do
155
+ root = parse "-#\n Hello\n Hello\n"
156
+ assert_equal "Hello\n Hello\n", root.children[0].value[:text]
157
+ end
158
+
159
+ test "block haml_comment includes first line if present" do
160
+ root = parse "-# First line\n Hello\n Hello\n"
161
+ assert_equal " First line\nHello\n Hello\n", root.children[0].value[:text]
162
+ end
163
+
97
164
  private
98
165
 
99
166
  def parse(haml, options = nil)
100
167
  options ||= Options.new
101
- parser = Parser.new(haml, options)
102
- parser.parse
168
+ parser = Parser.new(options)
169
+ parser.call(haml)
103
170
  end
104
171
  end
105
- end
172
+ end
@@ -0,0 +1,4 @@
1
+ <div class='o-media@md c-user c-user--premium'>
2
+ <img alt='' class='o-media__img@md c-user__photo c-avatar' src='' />
3
+ <p class='o-media__body@md c-user__bio'>...</p>
4
+ </div>
@@ -2,8 +2,8 @@
2
2
  <p></p>
3
3
  <h1>Me!</h1>
4
4
  <div id='foo'>
5
- <p id='bar'>All</p>
6
- <br />
7
- <p class='baz'>This</p>
8
- Should render
5
+ <p id='bar'>All</p>
6
+ <br />
7
+ <p class='baz'>This</p>
8
+ Should render
9
9
  </div>