haml 4.0.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -2,48 +2,13 @@ require 'test_helper'
2
2
  require 'mocks/article'
3
3
 
4
4
  require 'action_pack/version'
5
+ require 'template_test_helper'
5
6
 
6
- module Haml::Filters::Test
7
- include Haml::Filters::Base
8
-
9
- def render(text)
10
- "TESTING HAHAHAHA!"
11
- end
12
- end
13
-
14
- module Haml::Helpers
15
- def test_partial(name, locals = {})
16
- Haml::Engine.new(File.read(File.join(TemplateTest::TEMPLATE_PATH, "_#{name}.haml"))).render(self, locals)
17
- end
18
- end
19
-
20
- class Egocentic
21
- def method_missing(*args)
22
- self
23
- end
24
- end
25
-
26
- class DummyController
27
- attr_accessor :logger
28
- def initialize
29
- @logger = Egocentic.new
30
- end
31
-
32
- def self.controller_path
33
- ''
34
- end
35
-
36
- def controller_path
37
- ''
38
- end
39
- end
40
-
41
- class TemplateTest < MiniTest::Unit::TestCase
42
- TEMPLATE_PATH = File.join(File.dirname(__FILE__), "templates")
7
+ class TemplateTest < Haml::TestCase
43
8
  TEMPLATES = %w{ very_basic standard helpers
44
9
  whitespace_handling original_engine list helpful
45
10
  silent_script tag_parsing just_stuff partials
46
- nuke_outer_whitespace nuke_inner_whitespace
11
+ nuke_outer_whitespace nuke_inner_whitespace bemit
47
12
  render_layout partial_layout partial_layout_erb}
48
13
 
49
14
  def setup
@@ -56,10 +21,10 @@ class TemplateTest < MiniTest::Unit::TestCase
56
21
  def create_base
57
22
  vars = { 'article' => Article.new, 'foo' => 'value one' }
58
23
 
59
- base = ActionView::Base.new(TEMPLATE_PATH, vars)
24
+ base = ActionView::Base.new(TemplateTestHelper::TEMPLATE_PATH, vars)
60
25
 
61
26
  # This is needed by RJS in (at least) Rails 3
62
- base.instance_variable_set('@template', base)
27
+ base.instance_variable_set(:@template, base)
63
28
 
64
29
  # This is used by form_for.
65
30
  # It's usually provided by ActionController::Base.
@@ -83,12 +48,7 @@ class TemplateTest < MiniTest::Unit::TestCase
83
48
  def assert_renders_correctly(name, &render_method)
84
49
  old_options = Haml::Template.options.dup
85
50
  Haml::Template.options[:escape_html] = false
86
- if ActionPack::VERSION::MAJOR < 2 ||
87
- (ActionPack::VERSION::MAJOR == 2 && ActionPack::VERSION::MINOR < 2)
88
- render_method ||= proc { |n| @base.render(n) }
89
- else
90
- render_method ||= proc { |n| @base.render(:file => n) }
91
- end
51
+ render_method ||= proc { |n| @base.render(:file => n) }
92
52
 
93
53
  silence_warnings do
94
54
  load_result(name).split("\n").zip(render_method[name].split("\n")).each_with_index do |pair, line|
@@ -96,7 +56,7 @@ class TemplateTest < MiniTest::Unit::TestCase
96
56
  assert_equal(pair.first, pair.last, message)
97
57
  end
98
58
  end
99
- rescue Haml::Util.av_template_class(:Error) => e
59
+ rescue ActionView::Template::Error => e
100
60
  if e.message =~ /Can't run [\w:]+ filter; required (one of|file) ((?:'\w+'(?: or )?)+)(, but none were found| not found)/
101
61
  puts "\nCouldn't require #{$2}; skipping a test."
102
62
  else
@@ -111,28 +71,51 @@ class TemplateTest < MiniTest::Unit::TestCase
111
71
  end
112
72
 
113
73
  TEMPLATES.each do |template|
114
- define_method "test_template_should_render_correctly [template: #{template}] " do
74
+ define_method "test_template_should_render_correctly [template: #{template}]" do
115
75
  assert_renders_correctly template
116
76
  end
117
77
  end
118
78
 
79
+ def test_render_method_returning_null
80
+ @base.instance_eval do
81
+ def empty
82
+ nil
83
+ end
84
+ def render_something(&block)
85
+ capture(self, &block)
86
+ end
87
+ end
88
+
89
+ content_to_render = "%h1 This is part of the broken view.\n= render_something do |thing|\n = thing.empty do\n = 'test'"
90
+ result = render(content_to_render)
91
+ expected_result = "<h1>This is part of the broken view.</h1>\n"
92
+ assert_equal(expected_result, result)
93
+ end
94
+
95
+ def test_simple_rendering
96
+ content_to_render = "%p test\n= capture { 'foo' }"
97
+ result = render(content_to_render)
98
+ expected_result = "<p>test</p>\nfoo\n"
99
+ assert_equal(expected_result, result)
100
+ end
101
+
119
102
  def test_templates_should_render_correctly_with_render_proc
120
103
  assert_renders_correctly("standard") do |name|
121
- engine = Haml::Engine.new(File.read(File.dirname(__FILE__) + "/templates/#{name}.haml"), :format => :xhtml)
104
+ engine = Haml::Engine.new(File.read(File.dirname(__FILE__) + "/templates/#{name}.haml"), format: :xhtml)
122
105
  engine.render_proc(@base).call
123
106
  end
124
107
  end
125
108
 
126
109
  def test_templates_should_render_correctly_with_def_method
127
110
  assert_renders_correctly("standard") do |name|
128
- engine = Haml::Engine.new(File.read(File.dirname(__FILE__) + "/templates/#{name}.haml"), :format => :xhtml)
111
+ engine = Haml::Engine.new(File.read(File.dirname(__FILE__) + "/templates/#{name}.haml"), format: :xhtml)
129
112
  engine.def_method(@base, "render_standard")
130
113
  @base.render_standard
131
114
  end
132
115
  end
133
116
 
134
117
  def test_instance_variables_should_work_inside_templates
135
- @base.instance_variable_set("@content_for_layout", 'something')
118
+ @base.instance_variable_set(:@content_for_layout, 'something')
136
119
  assert_equal("<p>something</p>", render("%p= @content_for_layout").chomp)
137
120
 
138
121
  @base.instance_eval("@author = 'Hampton Catlin'")
@@ -164,8 +147,8 @@ class TemplateTest < MiniTest::Unit::TestCase
164
147
  Haml::Template.options = old_options
165
148
  end
166
149
 
167
- def test_with_output_buffer_with_ugly
168
- assert_equal(<<HTML, render(<<HAML, :ugly => true))
150
+ def test_with_output_buffer
151
+ assert_equal(<<HTML, render(<<HAML))
169
152
  <p>
170
153
  foo
171
154
  baz
@@ -328,4 +311,12 @@ HTML
328
311
  Test
329
312
  HAML
330
313
  end
314
+
315
+ class ::TosUnsafeObject; def to_s; '<hr>'; end; end
316
+ class ::TosSafeObject; def to_s; '<hr>'.html_safe; end; end
317
+
318
+ def test_object_that_returns_safe_buffer
319
+ assert_equal("<hr>\n", render('= ::TosSafeObject.new', escape_html: true))
320
+ assert_equal("&lt;hr&gt;\n", render('= ::TosUnsafeObject.new', escape_html: true))
321
+ end
331
322
  end
@@ -0,0 +1,38 @@
1
+ module TemplateTestHelper
2
+ TEMPLATE_PATH = File.join(__dir__, "templates")
3
+ end
4
+
5
+ module Haml::Filters::Test
6
+ include Haml::Filters::Base
7
+
8
+ def render(text)
9
+ "TESTING HAHAHAHA!"
10
+ end
11
+ end
12
+
13
+ module Haml::Helpers
14
+ def test_partial(name, locals = {})
15
+ Haml::Engine.new(File.read(File.join(TemplateTestHelper::TEMPLATE_PATH, "_#{name}.haml")), Haml::Template.options).render(self, locals)
16
+ end
17
+ end
18
+
19
+ class Egocentic
20
+ def method_missing(*args)
21
+ self
22
+ end
23
+ end
24
+
25
+ class DummyController
26
+ attr_accessor :logger
27
+ def initialize
28
+ @logger = Egocentic.new
29
+ end
30
+
31
+ def self.controller_path
32
+ ''
33
+ end
34
+
35
+ def controller_path
36
+ ''
37
+ end
38
+ end
@@ -0,0 +1,4 @@
1
+ - defined?(text_area_helper) and nil # silence a warning
2
+ .foo
3
+ .bar
4
+ = text_area :post, :body
@@ -0,0 +1,3 @@
1
+ .o-media@md.c-user.c-user--premium
2
+ %img.o-media__img@md.c-user__photo.c-avatar{src: '', alt: ''}
3
+ %p.o-media__body@md.c-user__bio ...
@@ -29,6 +29,7 @@
29
29
  \- character
30
30
  \%p foo
31
31
  \yee\ha
32
+ \ don't lstrip me
32
33
  / Short comment
33
34
  /
34
35
  This is a block comment
@@ -1,4 +1,4 @@
1
1
  <h1>Partial layout used with for block:</h1>
2
2
  <%= render :layout => 'layout_for_partial' do -%>
3
- <p>Some content within a layout</p>
3
+ Some content within a layout
4
4
  <% end %>
@@ -0,0 +1 @@
1
+ test/templates/standard.haml
@@ -0,0 +1 @@
1
+ BOMG
@@ -0,0 +1,40 @@
1
+ require 'test_helper'
2
+
3
+ class TempleLineCounterTest < Haml::TestCase
4
+ TESTED_TEMPLES = [
5
+ [:multi,
6
+ [:code, "foo"],
7
+ [:static, "bar"],
8
+ [:dynamic, "baz"],
9
+ ],
10
+ [:multi,
11
+ [:code, "foo\nbar\nbaz"],
12
+ [:static, "foo\nbar\nbaz"],
13
+ [:dynamic, "foo\nbar\nbaz"],
14
+ ],
15
+ [:case,
16
+ ["'a\nb', false", [:static, "hello\n"]],
17
+ [:else, [:code, "raise 'error\n'"]],
18
+ ],
19
+ [:escape, true, [:dynamic, "foo\nbar"]],
20
+ [:escape, :once, [:dynamic, "foo\nbar"]],
21
+ [:escape, false, [:dynamic, "foo\nbar"]],
22
+ [:escape, true, [:static, "foo\nbar"]],
23
+ [:escape, :once, [:static, "foo\nbar"]],
24
+ [:escape, false, [:dynamic, "foo\nbar"]],
25
+ ]
26
+
27
+ def test_count_lines
28
+ TESTED_TEMPLES.each do |temple|
29
+ code = Haml::TempleEngine.chain.inject(temple) do |exp, (symbol, filter)|
30
+ case symbol
31
+ when :Parser, :Compiler
32
+ exp
33
+ else
34
+ filter.call(Haml::TempleEngine).call(exp)
35
+ end
36
+ end
37
+ assert_equal code.count("\n"), Haml::TempleLineCounter.count_lines(temple)
38
+ end
39
+ end
40
+ end
data/test/test_helper.rb CHANGED
@@ -1,19 +1,32 @@
1
+ begin
2
+ if ENV['TRAVIS'] && RUBY_VERSION == '2.1.2' && !defined?(Rubinius)
3
+ require 'coveralls'
4
+ Coveralls.wear!
5
+ end
6
+ rescue LoadError
7
+ # ignore error for other test Gemfiles
8
+ end
9
+
1
10
  if ENV["COVERAGE"]
2
11
  require "simplecov"
3
12
  SimpleCov.start
4
13
  end
5
14
 
6
- require 'rubygems'
7
- gem "minitest"
8
15
  require 'bundler/setup'
9
16
  require 'minitest/autorun'
10
17
  require 'action_pack'
11
18
  require 'action_controller'
12
19
  require 'action_view'
20
+ require 'action_view/base'
13
21
  require 'nokogiri'
14
-
15
22
  require 'rails'
23
+
24
+ if defined?(I18n.enforce_available_locales)
25
+ I18n.enforce_available_locales = true
26
+ end
27
+
16
28
  class TestApp < Rails::Application
29
+ config.eager_load = false
17
30
  config.root = ""
18
31
  end
19
32
  Rails.application = TestApp
@@ -27,17 +40,23 @@ $VERBOSE = true
27
40
  require 'haml'
28
41
  require 'haml/template'
29
42
 
30
- Haml::Template.options[:ugly] = false
43
+ TestApp.initialize!
44
+
31
45
  Haml::Template.options[:format] = :xhtml
32
46
 
47
+ BASE_TEST_CLASS = if defined?(Minitest::Test)
48
+ Minitest::Test
49
+ else
50
+ MiniTest::Unit::TestCase
51
+ end
52
+
33
53
  module Declarative
34
54
  def test(name, &block)
35
- define_method("test #{name}", &block)
55
+ define_method("test_ #{name}", &block)
36
56
  end
37
57
  end
38
58
 
39
- class MiniTest::Unit::TestCase
40
-
59
+ class Haml::TestCase < BASE_TEST_CLASS
41
60
  extend Declarative
42
61
 
43
62
  def render(text, options = {}, base = nil, &block)
@@ -65,10 +84,6 @@ class MiniTest::Unit::TestCase
65
84
  Haml::Util.silence_warnings(&block)
66
85
  end
67
86
 
68
- def rails_form_opener
69
- '<div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /></div>'
70
- end
71
-
72
87
  def assert_raises_message(klass, message)
73
88
  yield
74
89
  rescue Exception => e
@@ -81,5 +96,4 @@ class MiniTest::Unit::TestCase
81
96
  def self.error(*args)
82
97
  Haml::Error.message(*args)
83
98
  end
84
-
85
99
  end
data/test/util_test.rb CHANGED
@@ -1,21 +1,8 @@
1
1
  require 'test_helper'
2
2
 
3
- class UtilTest < MiniTest::Unit::TestCase
3
+ class UtilTest < Haml::TestCase
4
4
  include Haml::Util
5
5
 
6
- def test_powerset
7
- return unless Set[Set[]] == Set[Set[]] # There's a bug in Ruby 1.8.6 that breaks nested set equality
8
- assert_equal([[].to_set].to_set,
9
- powerset([]))
10
- assert_equal([[].to_set, [1].to_set].to_set,
11
- powerset([1]))
12
- assert_equal([[].to_set, [1].to_set, [2].to_set, [1, 2].to_set].to_set,
13
- powerset([1, 2]))
14
- assert_equal([[].to_set, [1].to_set, [2].to_set, [3].to_set,
15
- [1, 2].to_set, [2, 3].to_set, [1, 3].to_set, [1, 2, 3].to_set].to_set,
16
- powerset([1, 2, 3]))
17
- end
18
-
19
6
  def test_silence_warnings
20
7
  old_stderr, $stderr = $stderr, StringIO.new
21
8
  warn "Out"
@@ -26,38 +13,10 @@ class UtilTest < MiniTest::Unit::TestCase
26
13
  $stderr = old_stderr
27
14
  end
28
15
 
29
- def test_caller_info
30
- assert_equal(["/tmp/foo.rb", 12, "fizzle"], caller_info("/tmp/foo.rb:12: in `fizzle'"))
31
- assert_equal(["/tmp/foo.rb", 12, nil], caller_info("/tmp/foo.rb:12"))
32
- assert_equal(["(haml)", 12, "blah"], caller_info("(haml):12: in `blah'"))
33
- assert_equal(["", 12, "boop"], caller_info(":12: in `boop'"))
34
- assert_equal(["/tmp/foo.rb", -12, "fizzle"], caller_info("/tmp/foo.rb:-12: in `fizzle'"))
35
- assert_equal(["/tmp/foo.rb", 12, "fizzle"], caller_info("/tmp/foo.rb:12: in `fizzle {}'"))
36
- end
37
-
38
- def test_def_static_method
39
- klass = Class.new
40
- def_static_method(klass, :static_method, [:arg1, :arg2],
41
- :sarg1, :sarg2, <<RUBY)
42
- s = "Always " + arg1
43
- s << " <% if sarg1 %>and<% else %>but never<% end %> " << arg2
44
-
45
- <% if sarg2 %>
46
- s << "."
47
- <% end %>
48
- RUBY
49
- c = klass.new
50
- assert_equal("Always brush your teeth and comb your hair.",
51
- c.send(static_method_name(:static_method, true, true),
52
- "brush your teeth", "comb your hair"))
53
- assert_equal("Always brush your teeth and comb your hair",
54
- c.send(static_method_name(:static_method, true, false),
55
- "brush your teeth", "comb your hair"))
56
- assert_equal("Always brush your teeth but never play with fire.",
57
- c.send(static_method_name(:static_method, false, true),
58
- "brush your teeth", "play with fire"))
59
- assert_equal("Always brush your teeth but never play with fire",
60
- c.send(static_method_name(:static_method, false, false),
61
- "brush your teeth", "play with fire"))
16
+ def test_check_encoding_does_not_destoy_the_given_string
17
+ string_with_bom = File.read(File.dirname(__FILE__) + '/templates/with_bom.haml', :encoding => Encoding::UTF_8)
18
+ original = string_with_bom.dup
19
+ check_encoding(string_with_bom)
20
+ assert_equal(original, string_with_bom)
62
21
  end
63
22
  end