haml 1.0.0

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 (48) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/REFERENCE +662 -0
  3. data/Rakefile +167 -0
  4. data/VERSION +1 -0
  5. data/bin/haml +18 -0
  6. data/lib/haml/buffer.rb +224 -0
  7. data/lib/haml/engine.rb +551 -0
  8. data/lib/haml/helpers.rb +220 -0
  9. data/lib/haml/helpers/action_view_mods.rb +53 -0
  10. data/lib/haml/template.rb +138 -0
  11. data/test/benchmark.rb +62 -0
  12. data/test/engine_test.rb +93 -0
  13. data/test/helper_test.rb +105 -0
  14. data/test/mocks/article.rb +6 -0
  15. data/test/profile.rb +45 -0
  16. data/test/results/content_for_layout.xhtml +16 -0
  17. data/test/results/eval_suppressed.xhtml +2 -0
  18. data/test/results/helpers.xhtml +50 -0
  19. data/test/results/helpful.xhtml +5 -0
  20. data/test/results/just_stuff.xhtml +36 -0
  21. data/test/results/list.xhtml +12 -0
  22. data/test/results/original_engine.xhtml +24 -0
  23. data/test/results/partials.xhtml +20 -0
  24. data/test/results/silent_script.xhtml +74 -0
  25. data/test/results/standard.xhtml +42 -0
  26. data/test/results/tag_parsing.xhtml +28 -0
  27. data/test/results/very_basic.xhtml +7 -0
  28. data/test/results/whitespace_handling.xhtml +51 -0
  29. data/test/rhtml/standard.rhtml +51 -0
  30. data/test/runner.rb +15 -0
  31. data/test/template_test.rb +137 -0
  32. data/test/templates/_partial.haml +7 -0
  33. data/test/templates/_text_area.haml +3 -0
  34. data/test/templates/content_for_layout.haml +10 -0
  35. data/test/templates/eval_suppressed.haml +5 -0
  36. data/test/templates/helpers.haml +39 -0
  37. data/test/templates/helpful.haml +6 -0
  38. data/test/templates/just_stuff.haml +29 -0
  39. data/test/templates/list.haml +12 -0
  40. data/test/templates/original_engine.haml +17 -0
  41. data/test/templates/partialize.haml +1 -0
  42. data/test/templates/partials.haml +12 -0
  43. data/test/templates/silent_script.haml +40 -0
  44. data/test/templates/standard.haml +40 -0
  45. data/test/templates/tag_parsing.haml +24 -0
  46. data/test/templates/very_basic.haml +4 -0
  47. data/test/templates/whitespace_handling.haml +66 -0
  48. metadata +108 -0
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require File.dirname(__FILE__) + '/../lib/haml/engine'
5
+
6
+ class EngineTest < Test::Unit::TestCase
7
+
8
+ def render(text, options = {})
9
+ Haml::Engine.new(text, options).to_html
10
+ end
11
+
12
+ def test_empty_render_should_remain_empty
13
+ assert_equal('', render(''))
14
+ end
15
+
16
+ # This is ugly because Hashes are unordered; we don't always know the order
17
+ # in which attributes will be returned.
18
+ # There is probably a better way to do this.
19
+ def test_attributes_should_render_correctly
20
+ assert_equal("<div class='atlantis' style='ugly'>\n</div>", render(".atlantis{:style => 'ugly'}").chomp)
21
+ rescue
22
+ assert_equal("<div style='ugly' class='atlantis'>\n</div>", render(".atlantis{:style => 'ugly'}").chomp)
23
+ end
24
+
25
+ def test_ruby_code_should_work_inside_attributes
26
+ author = 'hcatlin'
27
+ assert_equal("<p class='3'>foo</p>", render("%p{:class => 1+2} foo").chomp)
28
+ end
29
+
30
+ def test_nil_should_render_empty_tag
31
+ assert_equal("<div class='no_attributes'>\n</div>",
32
+ render(".no_attributes{:nil => nil}").chomp)
33
+ end
34
+
35
+ def test_strings_should_get_stripped_inside_tags
36
+ assert_equal("<div class='stripped'>This should have no spaces in front of it</div>",
37
+ render(".stripped This should have no spaces in front of it").chomp)
38
+ end
39
+
40
+ def test_one_liner_should_be_one_line
41
+ assert_equal("<p>Hello</p>", render('%p Hello').chomp)
42
+ end
43
+
44
+ def test_long_liner_should_not_print_on_one_line
45
+ assert_equal("<div>\n #{'x' * 51}\n</div>", render("%div #{'x' * 51}").chomp)
46
+ end
47
+
48
+ def test_multi_render
49
+ engine = Haml::Engine.new("%strong Hi there!")
50
+ assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
51
+ assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
52
+ assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
53
+ end
54
+
55
+ # Options tests
56
+
57
+ def test_stop_eval
58
+ assert_equal("", render("= 'Hello'", :suppress_eval => true))
59
+ end
60
+
61
+ def test_attr_wrapper
62
+ assert_equal("<p strange=*attrs*>\n</p>\n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*'))
63
+ assert_equal("<p escaped='quo\"te'>\n</p>\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"'))
64
+ assert_equal("<p escaped=\"q'uo&quot;te\">\n</p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
65
+ assert_equal("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n", render("!!! XML", :attr_wrapper => '"'))
66
+ end
67
+
68
+ def test_locals
69
+ assert_equal("<p>Paragraph!</p>\n", render("%p= text", :locals => { :text => "Paragraph!" }))
70
+ end
71
+
72
+ def test_precompiled
73
+ precompiled = <<-END
74
+ def _haml_render
75
+ _hamlout = @haml_stack[-1]
76
+ _erbout = _hamlout.buffer
77
+
78
+ _hamlout.open_tag("p", 0, nil, true, "", nil, nil, false)
79
+ @haml_lineno = 1
80
+ haml_temp = "Haml Rocks Socks"
81
+ haml_temp = _hamlout.push_script(haml_temp, 1, false)
82
+ _hamlout.close_tag("p", 0)
83
+ end
84
+ END
85
+
86
+ assert_equal("<p>Haml Rocks Socks</p>\n", render("%h1 I shall not be rendered", :precompiled => precompiled))
87
+ end
88
+
89
+ def test_comps
90
+ assert_equal(-1, "foo" <=> nil)
91
+ assert_equal(1, nil <=> "foo")
92
+ end
93
+ end
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require File.dirname(__FILE__) + '/../lib/haml/template'
5
+
6
+ class HelperTest < Test::Unit::TestCase
7
+ include Haml::Helpers
8
+
9
+ def setup
10
+ ActionView::Base.register_template_handler("haml", Haml::Template)
11
+ @base = ActionView::Base.new
12
+ @base.controller = ActionController::Base.new
13
+ end
14
+
15
+ def render(text, options = {})
16
+ if options == :action_view
17
+ @base.render :inline => text, :type => :haml
18
+ else
19
+ Haml::Engine.new(text, options).to_html
20
+ end
21
+ end
22
+
23
+ def test_flatten
24
+ assert_equal(flatten("FooBar"), "FooBar")
25
+
26
+ assert_equal(flatten("Foo\rBar"), "FooBar")
27
+
28
+ assert_equal(flatten("Foo\nBar"), "Foo&#x000A;Bar")
29
+
30
+ assert_equal(flatten("Hello\nWorld!\nYOU ARE \rFLAT?\n\rOMGZ!"),
31
+ "Hello&#x000A;World!&#x000A;YOU ARE FLAT?&#x000A;OMGZ!")
32
+ end
33
+
34
+ def test_list_of_should_render_correctly
35
+ assert_equal("<li>1</li>\n<li>2</li>\n", render("= list_of([1, 2]) do |i|\n = i"))
36
+ assert_equal("<li>1</li>\n", render("= list_of([[1]]) do |i|\n = i.first"))
37
+ 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",
38
+ render("= list_of(['Fee', 'Fi', 'Fo', 'Fum']) do |title|\n %h1= title\n %p A word!"))
39
+ end
40
+
41
+ def test_buffer_access
42
+ assert(render("= buffer") =~ /#<Haml::Buffer:0x[a-z0-9]+>/)
43
+ assert_equal(render("= (buffer == _hamlout)"), "true\n")
44
+ end
45
+
46
+ def test_tabs
47
+ assert_equal(render("foo\n- tab_up\nbar\n- tab_down\nbaz"), "foo\n bar\nbaz\n")
48
+ end
49
+
50
+ def test_helpers_dont_leak
51
+ # Haml helpers shouldn't be accessible from ERB
52
+ render("foo")
53
+ proper_behavior = false
54
+
55
+ begin
56
+ ActionView::Base.new.render(:inline => "<%= flatten('Foo\\nBar') %>")
57
+ rescue NoMethodError
58
+ proper_behavior = true
59
+ end
60
+ assert(proper_behavior)
61
+
62
+ begin
63
+ ActionView::Base.new.render(:inline => "<%= concat('foo') %>")
64
+ rescue ArgumentError
65
+ proper_behavior = true
66
+ end
67
+ assert(proper_behavior)
68
+ end
69
+
70
+ def test_action_view_included
71
+ assert(Haml::Helpers.action_view?)
72
+ end
73
+
74
+ def test_action_view_not_included
75
+ #This is for 100% rcov, rather than any real testing purposes.
76
+ Kernel.module_eval do
77
+ alias_method :old_require, :require
78
+ def require(string)
79
+ raise LoadError if string == "action_view"
80
+ old_require string
81
+ end
82
+ end
83
+
84
+ load File.dirname(__FILE__) + '/../lib/haml/helpers/action_view_mods.rb'
85
+
86
+ Kernel.module_eval do
87
+ alias_method :require, :old_require
88
+ end
89
+ end
90
+
91
+ def test_form_tag
92
+ # Until the next Rails is released, form_tag with a block can have one of
93
+ # two behaviors.
94
+
95
+ result = render("- form_tag 'foo' do\n %p bar\n %strong baz", :action_view)
96
+ new_rails = "<form action=\"foo\" method=\"post\">\n <p>foo</p>\n</form>\n"
97
+ old_rails = ""
98
+ assert(result == new_rails || result == old_rails)
99
+ end
100
+
101
+ def test_capture_haml
102
+ assert_equal("\"<p>13</p>\\n\"\n", render("- foo = capture_haml(13) do |a|\n %p= a\n= foo.dump"))
103
+ end
104
+ end
105
+
@@ -0,0 +1,6 @@
1
+ class Article
2
+ attr_accessor :id, :title, :body
3
+ def initialize
4
+ @id, @title, @body = 1, 'Hello', 'World'
5
+ end
6
+ end
@@ -0,0 +1,45 @@
1
+ require File.dirname(__FILE__) + '/../lib/haml/template'
2
+ require 'rubygems'
3
+ require 'active_support'
4
+ require 'action_view'
5
+ require 'profiler'
6
+ require 'stringio'
7
+
8
+ module Haml
9
+ # A profiler for HAML, mostly for development use. This simply implements
10
+ # the Ruby profiler for profiling HAML code.
11
+ class Profiler
12
+
13
+ # Creates a new profiler that looks for templates in the base
14
+ # directory.
15
+ def initialize(base = File.join(File.dirname(__FILE__), 'templates'))
16
+ ActionView::Base.register_template_handler("haml", Haml::Template)
17
+ unless base.class == ActionView::Base
18
+ @base = ActionView::Base.new(base)
19
+ else
20
+ @base = base
21
+ end
22
+ end
23
+
24
+ # Profiles HAML on the given template with the given number of runs.
25
+ # The template name shouldn't have a file extension; this will
26
+ # automatically look for a HAML template.
27
+ #
28
+ # Returns the results of the profiling as a string.
29
+ def profile(runs = 100, template_name = 'standard')
30
+ # Runs the profiler, collects information
31
+ Profiler__::start_profile
32
+ runs.times { @base.render template_name }
33
+ Profiler__::stop_profile
34
+
35
+ # Outputs information to a StringIO, returns result
36
+ io = StringIO.new
37
+ Profiler__::print_profile(io)
38
+ io.pos = 0
39
+ result = io.read
40
+ io.close
41
+ return result
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html>
3
+ <head>
4
+ </head>
5
+ <body>
6
+ <div id='content'>
7
+ Lorem ipsum dolor sit amet
8
+ </div>
9
+ <div id='yieldy'>
10
+ Lorem ipsum dolor sit amet
11
+ </div>
12
+ <div id='nosym'>
13
+ Lorem ipsum dolor sit amet
14
+ </div>
15
+ </body>
16
+ </html>
@@ -0,0 +1,2 @@
1
+ <p></p>
2
+ <h1>Me!</h1>
@@ -0,0 +1,50 @@
1
+ &amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;
2
+ <div>
3
+ <p class='title'>Title</p>
4
+ <p class='text'>
5
+ Woah this is really crazy
6
+ I mean wow,
7
+ man.
8
+ </p>
9
+ </div>
10
+ <div>
11
+ <p class='title'>Title</p>
12
+ <p class='text'>
13
+ Woah this is really crazy
14
+ I mean wow,
15
+ man.
16
+ </p>
17
+ </div>
18
+ <div>
19
+ <p class='title'>Title</p>
20
+ <p class='text'>
21
+ Woah this is really crazy
22
+ I mean wow,
23
+ man.
24
+ </p>
25
+ </div>
26
+ <p>foo</p>
27
+ <p>
28
+ reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally loooooooooooooooooong
29
+ </p>
30
+ <div class='woah'>
31
+ <div id='funky'>
32
+ <div>
33
+ <h1>Big!</h1>
34
+ <p>Small</p>
35
+ <!-- Invisible -->
36
+ </div>
37
+ <div class='dilly'>
38
+ <p>foo</p>
39
+ <h1>bar</h1>
40
+ </div>
41
+ </div>
42
+ (<strong>parentheses!</strong>)
43
+ </div>
44
+ *<span class='small'>Not really</span>
45
+ click
46
+ <a href='thing'>here</a>.
47
+ <p>baz</p>
48
+ <p>boom</p>
49
+ foo
50
+ <li><a href='http://www.google.com'>google</a></li>
@@ -0,0 +1,5 @@
1
+ <div class='article' id='article_1'>
2
+ <h1>Hello</h1>
3
+ <div>World</div>
4
+ </div>
5
+ <div class='article full' id='article_1'>boo</div>
@@ -0,0 +1,36 @@
1
+ <?xml version='1.0' encoding='utf-8' ?>
2
+ <?xml version='1.0' encoding='iso-8859-1' ?>
3
+ <?xml version='1.0' encoding='utf-8' ?>
4
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
6
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
7
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
8
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
9
+ <strong apos="Foo's bar!">Boo!</strong>
10
+ <div class='render'><em>wow!</em></div>
11
+ <p>
12
+ Escape
13
+ - character
14
+ %p foo
15
+ yee\ha
16
+ </p>
17
+ <!-- Short comment -->
18
+ <!--
19
+ This is a really long comment look how long it is it should be on a line of its own don't you think?
20
+ -->
21
+ <!--
22
+ This is a block comment
23
+ cool, huh?
24
+ <strong>there can even be sub-tags!</strong>
25
+ Or script!
26
+ -->
27
+ <!--[if lte IE6]> conditional comment! <![endif]-->
28
+ <!--[if gte IE7]>
29
+ <p>Block conditional comment</p>
30
+ <div>
31
+ <h1>Cool, eh?</h1>
32
+ </div>
33
+ <![endif]-->
34
+ <!--[if gte IE5.2]>
35
+ Woah a period.
36
+ <![endif]-->
@@ -0,0 +1,12 @@
1
+ ! Not a Doctype !
2
+ <ul>
3
+ <li>a</li>
4
+ <li>b</li>
5
+ <li>c</li>
6
+ <li>d</li>
7
+ <li>e</li>
8
+ <li>f</li>
9
+ <li>g</li>
10
+ <li>h</li>
11
+ <li>i</li>
12
+ </ul>
@@ -0,0 +1,24 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html>
3
+ <head>
4
+ <title>Stop. HAML time</title>
5
+ <div id='content'>
6
+ <h1>This is a title!</h1>
7
+ <p>
8
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit
9
+ </p>
10
+ <p class='foo'>Cigarettes!</p>
11
+ <h2>Man alive!</h2>
12
+ <ul class='things'>
13
+ <li>Slippers</li>
14
+ <li>Shoes</li>
15
+ <li>Bathrobe</li>
16
+ <li>Coffee</li>
17
+ </ul>
18
+ <pre>
19
+ This is some text that's in a pre block!
20
+ Let's see what happens when it's rendered! What about now, since we're on a new line?
21
+ </pre>
22
+ </div>
23
+ </head>
24
+ </html>
@@ -0,0 +1,20 @@
1
+ <p>
2
+ @foo =
3
+ value one
4
+ </p>
5
+ <p>
6
+ @foo =
7
+ value two
8
+ </p>
9
+ <p>
10
+ @foo =
11
+ value two
12
+ </p>
13
+ <p>
14
+ @foo =
15
+ value three
16
+ </p>
17
+ <p>
18
+ @foo =
19
+ value three
20
+ </p>
@@ -0,0 +1,74 @@
1
+ <div>
2
+ <h1>I can count!</h1>
3
+ 1
4
+ 2
5
+ 3
6
+ 4
7
+ 5
8
+ 6
9
+ 7
10
+ 8
11
+ 9
12
+ 10
13
+ 11
14
+ 12
15
+ 13
16
+ 14
17
+ 15
18
+ 16
19
+ 17
20
+ 18
21
+ 19
22
+ 20
23
+ <h1>I know my ABCs!</h1>
24
+ <ul>
25
+ <li>a</li>
26
+ <li>b</li>
27
+ <li>c</li>
28
+ <li>d</li>
29
+ <li>e</li>
30
+ <li>f</li>
31
+ <li>g</li>
32
+ <li>h</li>
33
+ <li>i</li>
34
+ <li>j</li>
35
+ <li>k</li>
36
+ <li>l</li>
37
+ <li>m</li>
38
+ <li>n</li>
39
+ <li>o</li>
40
+ <li>p</li>
41
+ <li>q</li>
42
+ <li>r</li>
43
+ <li>s</li>
44
+ <li>t</li>
45
+ <li>u</li>
46
+ <li>v</li>
47
+ <li>w</li>
48
+ <li>x</li>
49
+ <li>y</li>
50
+ <li>z</li>
51
+ </ul>
52
+ <h1>I can catch errors!</h1>
53
+ Oh no! "uninitialized constant Foo" happened!
54
+ <p>
55
+ "false" is:
56
+ false
57
+ </p>
58
+ Even!
59
+ Odd!
60
+ Even!
61
+ Odd!
62
+ Even!
63
+ </div>
64
+ <div class='foo'>
65
+ <strong>foobar</strong>
66
+ </div>
67
+ <strong>0</strong>
68
+ <strong>1</strong>
69
+ <strong>2</strong>
70
+ <strong>3</strong>
71
+ <strong>4</strong>
72
+ <div class='test'>
73
+ <p>boom</p>
74
+ </div>