Gem: haml

This commit is contained in:
2008-03-02 19:19:02 -03:00
parent c5cb69f277
commit 3f8c9f0ae6
107 changed files with 8275 additions and 0 deletions

View File

@@ -0,0 +1,261 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'active_support'
require 'action_controller'
require 'action_view'
require 'test/unit'
require File.dirname(__FILE__) + '/../../lib/haml'
require 'haml/engine'
class EngineTest < Test::Unit::TestCase
def render(text, options = {})
Haml::Engine.new(text, options).to_html
end
def test_empty_render_should_remain_empty
assert_equal('', render(''))
end
# This is ugly because Hashes are unordered; we don't always know the order
# in which attributes will be returned.
# There is probably a better way to do this.
def test_attributes_should_render_correctly
assert_equal("<div class='atlantis' style='ugly'>\n</div>", render(".atlantis{:style => 'ugly'}").chomp)
rescue
assert_equal("<div style='ugly' class='atlantis'>\n</div>", render(".atlantis{:style => 'ugly'}").chomp)
end
def test_ruby_code_should_work_inside_attributes
author = 'hcatlin'
assert_equal("<p class='3'>foo</p>", render("%p{:class => 1+2} foo").chomp)
end
def test_nil_should_render_empty_tag
assert_equal("<div class='no_attributes'>\n</div>",
render(".no_attributes{:nil => nil}").chomp)
end
def test_strings_should_get_stripped_inside_tags
assert_equal("<div class='stripped'>This should have no spaces in front of it</div>",
render(".stripped This should have no spaces in front of it").chomp)
end
def test_one_liner_should_be_one_line
assert_equal("<p>Hello</p>", render('%p Hello').chomp)
end
def test_long_liner_should_not_print_on_one_line
assert_equal("<div>\n #{'x' * 51}\n</div>", render("%div #{'x' * 51}").chomp)
end
def test_multi_render
engine = Haml::Engine.new("%strong Hi there!")
assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
assert_equal("<strong>Hi there!</strong>\n", engine.to_html)
end
def test_double_equals
assert_equal("<p>Hello World</p>\n", render('%p== Hello #{who}', :locals => {:who => 'World'}))
assert_equal("<p>\n Hello World\n</p>\n", render("%p\n == Hello \#{who}", :locals => {:who => 'World'}))
end
def test_nil_tag_value_should_render_as_empty
assert_equal("<p></p>\n", render("%p= nil"))
end
def test_tag_with_failed_if_should_render_as_empty
assert_equal("<p></p>\n", render("%p= 'Hello' if false"))
end
# Options tests
def test_stop_eval
assert_equal("", render("= 'Hello'", :suppress_eval => true))
assert_equal("", render("- puts 'foo'", :suppress_eval => true))
assert_equal("<div id='foo' yes='no' />\n", render("#foo{:yes => 'no'}/", :suppress_eval => true))
assert_equal("<div id='foo' />\n", render("#foo{:yes => 'no', :call => a_function() }/", :suppress_eval => true))
assert_equal("<div />\n", render("%div[1]/", :suppress_eval => true))
begin
assert_equal("", render(":ruby\n puts 'hello'", :suppress_eval => true))
rescue Haml::HamlError => err
caught = true
assert_equal('Filter "ruby" is not defined!', err.message)
end
assert(caught, "Rendering a ruby filter without evaluating didn't throw an error!")
end
def test_attr_wrapper
assert_equal("<p strange=*attrs*>\n</p>\n", render("%p{ :strange => 'attrs'}", :attr_wrapper => '*'))
assert_equal("<p escaped='quo\"te'>\n</p>\n", render("%p{ :escaped => 'quo\"te'}", :attr_wrapper => '"'))
assert_equal("<p escaped=\"q'uo&quot;te\">\n</p>\n", render("%p{ :escaped => 'q\\'uo\"te'}", :attr_wrapper => '"'))
assert_equal("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n", render("!!! XML", :attr_wrapper => '"'))
end
def test_attrs_parsed_correctly
assert_equal("<p boom=>biddly='bar => baz'>\n</p>\n", render("%p{'boom=>biddly' => 'bar => baz'}"))
assert_equal("<p foo,bar='baz, qux'>\n</p>\n", render("%p{'foo,bar' => 'baz, qux'}"))
assert_equal("<p escaped='quo\nte'>\n</p>\n", render("%p{ :escaped => \"quo\\nte\"}"))
assert_equal("<p escaped='quo4te'>\n</p>\n", render("%p{ :escaped => \"quo\#{2 + 2}te\"}"))
end
def test_locals
assert_equal("<p>Paragraph!</p>\n", render("%p= text", :locals => { :text => "Paragraph!" }))
end
def test_recompile_with_new_locals
template = "%p= (text == 'first time') ? text : new_text"
assert_equal("<p>first time</p>\n", render(template, :locals => { :text => "first time" }))
assert_equal("<p>second time</p>\n", render(template, :locals => { :text => "recompile", :new_text => "second time" }))
# Make sure the method called will return junk unless recompiled
method_name = Haml::Engine.send(:class_variable_get, '@@method_names')[template]
Haml::Engine::CompiledTemplates.module_eval "def #{method_name}(stuff); @haml_stack[-1].push_text 'NOT RECOMPILED', 0; end"
assert_equal("NOT RECOMPILED\n", render(template, :locals => { :text => "first time" }))
assert_equal("<p>first time</p>\n", render(template, :locals => { :text => "first time", :foo => 'bar' }))
end
def test_dynamc_attrs_shouldnt_register_as_literal_values
assert_equal("<p a='b2c'>\n</p>\n", render('%p{:a => "b#{1 + 1}c"}'))
assert_equal("<p a='b2c'>\n</p>\n", render("%p{:a => 'b' + (1 + 1).to_s + 'c'}"))
end
def test_rec_merge
hash1 = {1=>2, 3=>{5=>7, 8=>9}}
hash2 = {4=>5, 3=>{5=>2, 16=>12}}
hash3 = {1=>2, 4=>5, 3=>{5=>2, 8=>9, 16=>12}}
hash1.rec_merge!(hash2)
assert_equal(hash3, hash1)
end
def test_exception_type
begin
render("%p hi\n= undefined")
rescue Exception => e
assert(e.is_a?(Haml::Error))
assert_equal(2, e.haml_line)
assert_equal(nil, e.haml_filename)
assert_equal('(haml):2', e.backtrace[0])
else
# Test failed... should have raised an exception
assert(false)
end
end
def test_syntax_errors
errs = [ "!!!\n a", "a\n b", "a\n:foo\nb", "/ a\n b",
"% a", "%p a\n b", "a\n%p=\nb", "%p=\n a",
"a\n%p~\nb", "a\n~\nb", "a\n~\n b", "%p~\n b", "%p/\n a",
"%p\n \t%a b", "%a\n b\nc", "%a\n b\nc",
":notafilter\n This isn't\n a filter!",
".{} a", "\#{} a", ".= 'foo'", "%a/ b", "%p..class", "%p..#." ]
errs.each do |err|
begin
render(err)
rescue Exception => e
assert(e.is_a?(Haml::Error),
"#{err.dump} doesn't produce Haml::SyntaxError!")
else
assert(false,
"#{err.dump} doesn't produce an exception!")
end
end
end
def test_compile_error
begin
render("a\nb\n- fee do\nc")
rescue Exception => e
assert_equal(3, e.haml_line)
else
assert(false,
'"a\nb\n- fee do\nc" doesn\'t produce an exception!')
end
end
def test_no_bluecloth
old_markdown = false
if defined?(Haml::Filters::Markdown)
old_markdown = Haml::Filters::Markdown
end
Kernel.module_eval do
alias_method :haml_old_require, :gem_original_require
def gem_original_require(file)
raise LoadError if file == 'bluecloth'
haml_old_require(file)
end
end
if old_markdown
Haml::Filters.instance_eval do
remove_const 'Markdown'
end
end
# This is purposefully redundant, so it doesn't stop
# haml/filters from being required later on.
require 'haml/../haml/filters'
assert_equal("<h1>Foo</h1>\t<p>- a\n- b</p>\n",
Haml::Engine.new(":markdown\n Foo\n ===\n - a\n - b").to_html)
Haml::Filters.instance_eval do
remove_const 'Markdown'
end
Haml::Filters.const_set('Markdown', old_markdown) if old_markdown
Kernel.module_eval do
alias_method :gem_original_require, :haml_old_require
end
NOT_LOADED.delete 'bluecloth'
end
def test_no_redcloth
Kernel.module_eval do
alias_method :haml_old_require2, :gem_original_require
def gem_original_require(file)
raise LoadError if file == 'redcloth'
haml_old_require2(file)
end
end
# This is purposefully redundant, so it doesn't stop
# haml/filters from being required later on.
require 'haml/../haml/../haml/filters'
begin
Haml::Engine.new(":redcloth\n _foo_").to_html
rescue Haml::HamlError
else
assert(false, "No exception raised!")
end
Kernel.module_eval do
alias_method :gem_original_require2, :haml_old_require
end
NOT_LOADED.delete 'redcloth'
end
def test_local_assigns_dont_modify_class
assert_equal("bar\n", render("= foo", :locals => {:foo => 'bar'}))
assert_equal(nil, defined?(foo))
end
def test_object_ref_with_nil_id
user = Struct.new('User', :id).new
assert_equal("<p class='struct_user' id='struct_user_new'>New User</p>\n",
render("%p[user] New User", :locals => {:user => user}))
end
end

View File

@@ -0,0 +1,123 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'active_support'
require 'action_controller'
require 'action_view'
require 'test/unit'
require File.dirname(__FILE__) + '/../../lib/haml'
require 'haml/template'
class HelperTest < Test::Unit::TestCase
include Haml::Helpers
def setup
ActionView::Base.register_template_handler("haml", Haml::Template)
@base = ActionView::Base.new
@base.controller = ActionController::Base.new
end
def render(text, options = {})
if options == :action_view
@base.render :inline => text, :type => :haml
else
scope = options.delete :scope_object
Haml::Engine.new(text, options).to_html(scope ? scope : Object.new)
end
end
def test_flatten
assert_equal(flatten("FooBar"), "FooBar")
assert_equal(flatten("Foo\rBar"), "FooBar")
assert_equal(flatten("Foo\nBar"), "Foo&#x000A;Bar")
assert_equal(flatten("Hello\nWorld!\nYOU ARE \rFLAT?\n\rOMGZ!"),
"Hello&#x000A;World!&#x000A;YOU ARE FLAT?&#x000A;OMGZ!")
end
def test_list_of_should_render_correctly
assert_equal("<li>1</li>\n<li>2</li>\n", render("= list_of([1, 2]) do |i|\n = i"))
assert_equal("<li>[1]</li>\n", render("= list_of([[1]]) do |i|\n = i.inspect"))
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",
render("= list_of(['Fee', 'Fi', 'Fo', 'Fum']) do |title|\n %h1= title\n %p A word!"))
end
def test_buffer_access
assert(render("= buffer") =~ /#<Haml::Buffer:0x[a-z0-9]+>/)
assert_equal(render("= (buffer == _hamlout)"), "true\n")
end
def test_tabs
assert_equal(render("foo\n- tab_up\nbar\n- tab_down\nbaz"), "foo\n bar\nbaz\n")
end
def test_helpers_dont_leak
# Haml helpers shouldn't be accessible from ERB
render("foo")
proper_behavior = false
begin
ActionView::Base.new.render(:inline => "<%= flatten('Foo\\nBar') %>")
rescue NoMethodError
proper_behavior = true
end
assert(proper_behavior)
begin
ActionView::Base.new.render(:inline => "<%= concat('foo') %>")
rescue ArgumentError, NameError
proper_behavior = true
end
assert(proper_behavior)
end
def test_action_view_included
assert(Haml::Helpers.action_view?)
end
def test_form_tag
result = render("- form_tag 'foo' do\n %p bar\n %strong baz", :action_view)
should_be = "<form action=\"foo\" method=\"post\">\n <p>bar</p>\n <strong>baz</strong>\n</form>\n"
assert_equal(should_be, result)
end
def test_capture_haml
assert_equal("\"<p>13</p>\\n\"\n", render("- foo = capture_haml(13) do |a|\n %p= a\n= foo.dump"))
end
def test_is_haml
assert(!ActionView::Base.new.is_haml?)
assert_equal("true\n", render("= is_haml?"))
assert_equal("true\n", render("= is_haml?", :action_view))
assert_equal("false", @base.render(:inline => '<%= is_haml? %>'))
assert_equal("false\n", render("= render :inline => '<%= is_haml? %>'", :action_view))
end
def test_page_class
controller = Struct.new(:controller_name, :action_name).new('troller', 'tion')
scope = Struct.new(:controller).new(controller)
result = render("%div{:class => page_class} MyDiv", :scope_object => scope)
expected = "<div class='troller tion'>MyDiv</div>\n"
assert_equal expected, result
end
def test_indented_capture
assert_equal(" \n Foo\n ", @base.render(:inline => " <% res = capture do %>\n Foo\n <% end %><%= res %>"))
end
def test_capture_deals_properly_with_collections
Haml::Helpers.module_eval do
def trc(collection, &block)
collection.each do |record|
puts capture_haml(record, &block)
end
end
end
assert_equal("1\n\n2\n\n3\n\n", render("- trc([1, 2, 3]) do |i|\n = i.inspect"))
end
end

View File

@@ -0,0 +1,6 @@
class Article
attr_accessor :id, :title, :body
def initialize
@id, @title, @body = 1, 'Hello', 'World'
end
end

View File

@@ -0,0 +1,16 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
</head>
<body>
<div id='content'>
Lorem ipsum dolor sit amet
</div>
<div id='yieldy'>
Lorem ipsum dolor sit amet
</div>
<div id='nosym'>
Lorem ipsum dolor sit amet
</div>
</body>
</html>

View File

@@ -0,0 +1,8 @@
<p></p>
<h1>Me!</h1>
<div id='foo'>
<p id='bar'>All</p>
<br />
<p class='baz'>This</p>
Should render
</div>

View File

@@ -0,0 +1,57 @@
<style>
p {
border-style: dotted;
border-width: 10px;
border-color: #ff00ff; }
h1 {
font-weight: normal; }
</style>
TESTING HAHAHAHA!
<h1>Foo</h1>
<pre><code>This is preformatted!
Look at that!
Wowie-zowie!</code></pre>
<p><strong>boldilicious!</strong></p>
<h1>Yeah</h1>
<p><em>pretty much the same as above</em></p>
This
Is
Plain
Text
%strong right?
a
b
c
d
e
f
g
h
i
j
<ul>
<li>Foo</li>
<li>Bar</li>
<li>BAZ!</li>
</ul>
Text!
Hello, World!
How are you doing today?

View File

@@ -0,0 +1,84 @@
&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;
<div>
<p class='title'>Title</p>
<p class='text'>
Woah this is really crazy
I mean wow,
man.
</p>
</div>
<div>
<p class='title'>Title</p>
<p class='text'>
Woah this is really crazy
I mean wow,
man.
</p>
</div>
<div>
<p class='title'>Title</p>
<p class='text'>
Woah this is really crazy
I mean wow,
man.
</p>
</div>
<p>foo</p>
<p>
reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally loooooooooooooooooong
</p>
<div class='woah'>
<div id='funky'>
<div>
<h1>Big!</h1>
<p>Small</p>
<!-- Invisible -->
</div>
<div class='dilly'>
<p>foo</p>
<h1>bar</h1>
</div>
</div>
(<strong>parentheses!</strong>)
</div>
*<span class='small'>Not really</span>
click
<a href='thing'>here</a>.
<p>baz</p>
<p>boom</p>
foo
<p>
<form action="hello/world" method="post">
</p>
<form action="heeheeaform" method="post">
<div><input name="commit" type="submit" value="save" /></div>
</form>
<form action="article_url" method="post">
Title:
<input id="article_title" name="article[title]" size="30" type="text" value="Hello" />
Body:
<input id="article_body" name="article[body]" size="30" type="text" value="World" />
</form>
<li><a href='http://www.google.com'>google</a></li>
<p>
foo
<div>
bar
</div>
boom
baz
boom, again
</p>
<table>
<tr>
<td class='cell'>
<strong>
strong!
</strong>
data
</td>
<td>
more_data
</td>
</tr>
</table>

View File

@@ -0,0 +1,10 @@
<div class='article' id='article_1'>
<h1>Hello</h1>
<div>World</div>
</div>
<div class='article' id='id_article_1'>id</div>
<div class='article class' id='article_1'>class</div>
<div class='article class' id='id_article_1'>id class</div>
<div class='article full' id='article_1'>boo</div>
<div class='article full' id='article_1'>moo</div>
<div class='article articleFull' id='article_1'>foo</div>

View File

@@ -0,0 +1,59 @@
<?xml version='1.0' encoding='utf-8' ?>
<?xml version='1.0' encoding='iso-8859-1' ?>
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<strong apos="Foo's bar!">Boo!</strong>
Embedded? false!
Embedded? true!
Embedded? true!
<div class='render'><em>wow!</em></div>
stuff followed by whitespace
<strong>block with whitespace</strong>
<p>
Escape
- character
%p foo
yee\ha
</p>
<!-- Short comment -->
<!--
This is a really long comment look how long it is it should be on a line of its own don't you think?
-->
<!--
This is a block comment
cool, huh?
<strong>there can even be sub-tags!</strong>
Or script!
-->
<p>class attribute shouldn't appear!</p>
<!--[if lte IE6]> conditional comment! <![endif]-->
<!--[if gte IE7]>
<p>Block conditional comment</p>
<div>
<h1>Cool, eh?</h1>
</div>
<![endif]-->
<!--[if gte IE5.2]>
Woah a period.
<![endif]-->
testtest
<br />
<meta foo='bar' />
<img />
<hr />
<link />
<script>Inline content</script>
<br>
Nested content
</br>
<p class='article bar foo' id='article_1'>Blah</p>
<p class='article foo' id='article_1'>Blah</p>
<p class='article quux qux' id='article_1'>Blump</p>
Woah inner quotes
<p class='dynamic_quote' dyn='3' quotes="single '">
</p>
<p class='dynamic_atomic' dyn='3' />

View File

@@ -0,0 +1,12 @@
! Not a Doctype !
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
<li>g</li>
<li>h</li>
<li>i</li>
</ul>

View File

@@ -0,0 +1,24 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>Stop. haml time</title>
<div id='content'>
<h1>This is a title!</h1>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit
</p>
<p class='foo'>Cigarettes!</p>
<h2>Man alive!</h2>
<ul class='things'>
<li>Slippers</li>
<li>Shoes</li>
<li>Bathrobe</li>
<li>Coffee</li>
</ul>
<pre>
This is some text that's in a pre block!
Let's see what happens when it's rendered! What about now, since we're on a new line?
</pre>
</div>
</head>
</html>

View File

@@ -0,0 +1,20 @@
<p>
@foo =
value one
</p>
<p>
@foo =
value two
</p>
<p>
@foo =
value two
</p>
<p>
@foo =
value three
</p>
<p>
@foo =
value three
</p>

View File

@@ -0,0 +1,74 @@
<div>
<h1>I can count!</h1>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<h1>I know my ABCs!</h1>
<ul>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
<li>g</li>
<li>h</li>
<li>i</li>
<li>j</li>
<li>k</li>
<li>l</li>
<li>m</li>
<li>n</li>
<li>o</li>
<li>p</li>
<li>q</li>
<li>r</li>
<li>s</li>
<li>t</li>
<li>u</li>
<li>v</li>
<li>w</li>
<li>x</li>
<li>y</li>
<li>z</li>
</ul>
<h1>I can catch errors!</h1>
Oh no! "undefined method `silly' for String:Class" happened!
<p>
"false" is:
false
</p>
Even!
Odd!
Even!
Odd!
Even!
</div>
<div class='foo'>
<strong>foobar</strong>
</div>
<strong>0</strong>
<strong>1</strong>
<strong>2</strong>
<strong>3</strong>
<strong>4</strong>
<div class='test'>
<p>boom</p>
</div>

View File

@@ -0,0 +1,43 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang='en-US' xml:lang='en-US' xmlns='http://www.w3.org/1999/xhtml'>
<head>
<title>Hampton Catlin Is Totally Awesome</title>
<meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
</head>
<body>
<!-- You're In my house now! -->
foo
<div class='header'>
Yes, ladies and gentileman. He is just that egotistical.
Fantastic! This should be multi-line output
The question is if this would translate! Ahah!
20
</div>
<div id='body'> Quotes should be loved! Just like people!</div>
Wow.|
<p>
Holy cow multiline tags! A pipe (|) even!
PipesIgnored|PipesIgnored|PipesIgnored|
1|2|3
</p>
<div class='silent'>
this shouldn't evaluate but now it should!
</div>
<ul class='really cool'>
<li>a</li>
<li>b</li>
<li>c</li>
<li>d</li>
<li>e</li>
<li>f</li>
</ul>
<div class='of_divs_with_underscore' id='combo'>with this text</div>
hello
<div class='footer'>
<strong class='shout'>
This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid.
So, I'm just making it *really* long. God, I hope this works
</strong>
</div>
</body>
</html>

View File

@@ -0,0 +1,28 @@
<div class='tags'>
<foo>1</foo>
<FOO>2</FOO>
<fooBAR>3</fooBAR>
<fooBar>4</fooBar>
<foo_bar>5</foo_bar>
<foo-bar>6</foo-bar>
<foo:bar>7</foo:bar>
<foo class='bar'>8</foo>
<fooBAr_baz:boom_bar>9</fooBAr_baz:boom_bar>
<foo13>10</foo13>
<foo2u>11</foo2u>
</div>
<div class='classes'>
<p class='foo bar' id='boom'>
</p>
<div class='fooBar'>a</div>
<div class='foo-bar'>b</div>
<div class='foo_bar'>c</div>
<div class='FOOBAR'>d</div>
<div class='foo16'>e</div>
<div class='123'>f</div>
<div class='foo2u'>g</div>
</div>
<div class='broken'>
<foo><{ :a => :b }</foo>
<div class='foo'>>{ :c => :d }</div>
</div>

View File

@@ -0,0 +1,7 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,94 @@
<div id='whitespace_test'>
<div class='text_area_test_area'>
<textarea>Oneline</textarea>
</div>
<textarea>BLAH
</textarea>
<div class='text_area_test_area'>
<textarea>Two&#x000A;lines</textarea>
</div>
<textarea>BLAH
</textarea>
<div class='text_area_test_area'>
<textarea>Oneline</textarea>
</div>
<textarea>BLAH&#x000A;</textarea>
<div class='text_area_test_area'>
<textarea>Two&#x000A;lines</textarea>
</div>
<textarea>BLAH&#x000A;</textarea>
<div id='flattened'>
<div class='text_area_test_area'>
<textarea>Two&#x000A;lines</textarea>
</div>
<textarea>BLAH&#x000A;</textarea>
</div>
</div>
<div class='hithere'>
Foo bar
<pre>foo bar</pre>
<pre>foo&#x000A;bar</pre>
<p><pre>foo&#x000A;bar</pre></p>
<p>
foo
bar
</p>
</div>
<div class='foo'>
13
<textarea>&#x000A;a&#x000A;</textarea><textarea>&#x000A;b&#x000A;</textarea><textarea>&#x000A;c&#x000A;</textarea>
</div>
<div id='whitespace_test'>
<div class='text_area_test_area'>
<textarea>Oneline</textarea>
</div>
<textarea>BLAH
</textarea>
<div class='text_area_test_area'>
<textarea>Two&#x000A;lines</textarea>
</div>
<textarea>BLAH
</textarea>
<div class='text_area_test_area'>
<textarea>Oneline</textarea>
</div>
<textarea>BLAH&#x000A;</textarea>
<div class='text_area_test_area'>
<textarea>Two&#x000A;lines</textarea>
</div>
<textarea>BLAH&#x000A;</textarea>
<div id='flattened'>
<div class='text_area_test_area'>
<textarea>Two&#x000A;lines</textarea>
</div>
<textarea>BLAH&#x000A;</textarea>
</div>
</div>
<div class='hithere'>
Foo bar
<pre>foo bar</pre>
<pre>foo&#x000A;bar</pre>
<p><pre>foo&#x000A;bar</pre></p>
<p>
foo
bar
</p>
<pre>
___&#x000A; ,o88888&#x000A; ,o8888888'&#x000A; ,:o:o:oooo. ,8O88Pd8888"&#x000A; ,.::.::o:ooooOoOoO. ,oO8O8Pd888'"&#x000A; ,.:.::o:ooOoOoOO8O8OOo.8OOPd8O8O"&#x000A; , ..:.::o:ooOoOOOO8OOOOo.FdO8O8"&#x000A; , ..:.::o:ooOoOO8O888O8O,COCOO"&#x000A; , . ..:.::o:ooOoOOOO8OOOOCOCO"&#x000A; . ..:.::o:ooOoOoOO8O8OCCCC"o&#x000A; . ..:.::o:ooooOoCoCCC"o:o&#x000A; . ..:.::o:o:,cooooCo"oo:o:&#x000A; ` . . ..:.:cocoooo"'o:o:::'&#x000A; .` . ..::ccccoc"'o:o:o:::'&#x000A; :.:. ,c:cccc"':.:.:.:.:.'&#x000A; ..:.:"'`::::c:"'..:.:.:.:.:.' http://www.chris.com/ASCII/&#x000A; ...:.'.:.::::"' . . . . .'&#x000A; .. . ....:."' ` . . . ''&#x000A; . . . ...."'&#x000A; .. . ."' -hrr-&#x000A; .&#x000A;&#x000A;&#x000A; It's a planet!&#x000A;%strong This shouldn't be bold!&#x000A;
</pre>
<strong>This should!</strong>
<textarea>
___ ___ ___ ___ &#x000A; /\__\ /\ \ /\__\ /\__\&#x000A; /:/ / /::\ \ /::| | /:/ /&#x000A; /:/__/ /:/\:\ \ /:|:| | /:/ / &#x000A; /::\ \ ___ /::\~\:\ \ /:/|:|__|__ /:/ / &#x000A; /:/\:\ /\__\ /:/\:\ \:\__\ /:/ |::::\__\ /:/__/ &#x000A; \/__\:\/:/ / \/__\:\/:/ / \/__/~~/:/ / \:\ \ &#x000A; \::/ / \::/ / /:/ / \:\ \ &#x000A; /:/ / /:/ / /:/ / \:\ \ &#x000A; /:/ / /:/ / /:/ / \:\__\&#x000A; \/__/ \/__/ \/__/ \/__/&#x000A;&#x000A; Many&#x000A; thanks&#x000A; to&#x000A; http://www.network-science.de/ascii/&#x000A;
<strong>indeed!</strong>
</textarea>
</div>
<div class='foo'>
13
</div>
<pre>
__ ______ __ ______&#x000A;.----.| |--.|__ |.----.| |--..--------.| __ |&#x000A;| __|| ||__ || __|| < | || __ |&#x000A;|____||__|__||______||____||__|__||__|__|__||______|&#x000A;
</pre>
<pre>
foo&#x000A;
bar
</pre>

View File

@@ -0,0 +1,55 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en-US'>
<head>
<title>Hampton Catlin Is Totally Awesome</title>
<meta content='text/html; charset=utf-8' http-equiv='Content-Type' />
</head>
<body>
<!-- You're In my house now! -->
<% concat("Foo", Proc.new {}) %>
<div class='header'>
Yes, ladies and gentileman. He is just that egotistical.
Fantastic! This should be multi-line output
The question is if this would translate! Ahah!
<%= 1 + 9 + 8 + 2 %>
<%# numbers should work and this should be ignored %>
</div>
<% 120.times do |number| -%>
<%= number %>
<% end -%>
<div id='body'><%= " Quotes should be loved! Just like people!" %></div>
Wow.
<p>
<%= "Holy cow " +
"multiline " +
"tags! " +
"A pipe (|) even!" %>
<%= [1, 2, 3].collect { |n| "PipesIgnored|" } %>
<%= [1, 2, 3].collect { |n|
n.to_s
}.join("|") %>
</p>
<div class='silent'>
<% foo = String.new
foo << "this"
foo << " shouldn't"
foo << " evaluate" %>
<%= foo + "but now it should!" %>
<%# Woah crap a comment! %>
</div>
<ul class='really cool'>
<% ('a'..'f').each do |a|%>
<li><%= a %>
<% end %>
<div class='of_divs_with_underscore' id='combo'><%= @should_eval = "with this text" %></div>
<%= [ 104, 101, 108, 108, 111 ].map do |byte|
byte.chr
end %>
<div class='footer'>
<strong class='shout'>
<%= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid.\n" +
" So, I'm just making it *really* long. God, I hope this works" %>
</strong>
</div>
</body>
</html>

View File

@@ -0,0 +1,16 @@
require 'rubygems'
require 'active_support'
require 'action_controller'
require 'action_view'
require '../../lib/haml/template'
require 'fileutils'
haml_template_engine = Haml::Template.new(ActionView::Base.new)
haml_template_engine.render(File.dirname(__FILE__) + '/templates/standard.haml')
begin
eval(File.read("template_test.rb"))
rescue StandardError => e
puts e.backtrace
puts e.inspect
end

View File

@@ -0,0 +1,155 @@
#!/usr/bin/env ruby
require 'test/unit'
require 'rubygems'
require 'active_support'
require 'action_controller'
require 'action_view'
require File.dirname(__FILE__) + '/../../lib/haml'
require 'haml/template'
require File.dirname(__FILE__) + '/mocks/article'
class TestFilter
def initialize(text)
@text = text
end
def render
"TESTING HAHAHAHA!"
end
end
class TemplateTest < Test::Unit::TestCase
@@templates = %w{ very_basic standard helpers
whitespace_handling original_engine list helpful
silent_script tag_parsing just_stuff partials
filters }
def setup
ActionView::Base.register_template_handler("haml", Haml::Template)
Haml::Template.options = { :filters => { 'test'=>TestFilter } }
@base = ActionView::Base.new(File.dirname(__FILE__) + "/templates/", {'article' => Article.new, 'foo' => 'value one'})
end
def render(text)
Haml::Engine.new(text).to_html(@base)
end
def load_result(name)
@result = ''
File.new(File.dirname(__FILE__) + "/results/#{name}.xhtml").each_line { |l| @result += l }
@result
end
def assert_renders_correctly(name)
test = Proc.new do |rendered|
load_result(name).split("\n").zip(rendered.split("\n")).each_with_index do |pair, line|
message = "template: #{name}\nline: #{line}"
assert_equal(pair.first, pair.last, message)
end
end
test.call(@base.render(name))
# If eval's suppressed, the partial won't render anyway :p.
unless Haml::Template.options[:suppress_eval]
test.call(@base.render(:file => "partialize", :locals => { :name => name }))
end
end
def test_empty_render_should_remain_empty
assert_equal('', render(''))
end
def test_templates_should_render_correctly
@@templates.each do |template|
assert_renders_correctly template
end
end
def test_action_view_templates_render_correctly
@base.instance_variable_set("@content_for_layout", 'Lorem ipsum dolor sit amet')
assert_renders_correctly 'content_for_layout'
end
def test_instance_variables_should_work_inside_templates
@base.instance_variable_set("@content_for_layout", 'something')
assert_equal("<p>something</p>", render("%p= @content_for_layout").chomp)
@base.instance_eval("@author = 'Hampton Catlin'")
assert_equal("<div class='author'>Hampton Catlin</div>", render(".author= @author").chomp)
@base.instance_eval("@author = 'Hampton'")
assert_equal("Hampton", render("= @author").chomp)
@base.instance_eval("@author = 'Catlin'")
assert_equal("Catlin", render("= @author").chomp)
end
def test_instance_variables_should_work_inside_attributes
@base.instance_eval("@author = 'hcatlin'")
assert_equal("<p class='hcatlin'>foo</p>", render("%p{:class => @author} foo").chomp)
end
def test_template_renders_should_eval
assert_equal("2\n", render("= 1+1"))
end
def test_rhtml_still_renders
# Make sure it renders normally
res = @base.render("../rhtml/standard")
assert !(res.nil? || res.empty?)
# Register Haml stuff in @base...
@base.render("standard")
# Does it still render?
res = @base.render("../rhtml/standard")
assert !(res.nil? || res.empty?)
end
def test_haml_options
Haml::Template.options = { :suppress_eval => true }
assert_equal({ :suppress_eval => true }, Haml::Template.options)
assert_renders_correctly("eval_suppressed")
Haml::Template.options = {}
end
def test_exceptions_should_work_correctly
begin
Haml::Template.new(@base).render(File.dirname(__FILE__) + '/templates/breakage.haml')
rescue Exception => e
assert_equal("./test/haml/templates/breakage.haml:4", e.backtrace[0])
else
assert false
end
begin
render("- raise 'oops!'")
rescue Exception => e
assert_equal("(haml):1", e.backtrace[0])
else
assert false
end
template = <<END
%p
%h1 Hello!
= "lots of lines"
= "even more!"
- raise 'oh no!'
%p
this is after the exception
%strong yes it is!
ho ho ho.
END
begin
render(template.chomp)
rescue Exception => e
assert_equal("(haml):5", e.backtrace[0])
else
assert false
end
end
end

View File

@@ -0,0 +1,7 @@
%p
@foo =
= @foo
- @foo = 'value three'
%p
@foo =
= @foo

View File

@@ -0,0 +1,3 @@
.text_area_test_area
~ "<textarea>" + value + "</textarea>"
= "<textarea>BLAH\n</textarea>"

View File

@@ -0,0 +1,8 @@
%p
%h1 Hello!
= "lots of lines"
- raise "Oh no!"
%p
this is after the exception
%strong yes it is!
ho ho ho.

View File

@@ -0,0 +1,10 @@
!!!
%html
%head
%body
#content
= @content_for_layout
#yieldy
= yield :layout
#nosym
= yield

View File

@@ -0,0 +1,10 @@
= "not me!"
= "nor me!"
- puts "not even me!"
%p= "NO!"
%h1 Me!
#foo
%p#bar All
%br/
%p.baz This
Should render

View File

@@ -0,0 +1,53 @@
%style
:sass
p
:border
:style dotted
:width 10px
:color #ff00ff
h1
:font-weight normal
:test
This
Should
Not
Print
:redcloth
Foo
===
This is preformatted!
Look at that!
Wowie-zowie!
*boldilicious!*
:textile
h1. Yeah
_pretty much the same as above_
:plain
This
Is
Plain
Text
%strong right?
:erb
<% 10.times do |c| %>
<%= (c+97).chr %>
<% end %>
:markdown
* Foo
* Bar
* BAZ!
= "Text!"
:ruby
puts "Hello, World!"
puts "How are you doing today?"

View File

@@ -0,0 +1,63 @@
= h("&&&&&&&&&&&") # This is an ActionView Helper... should load
- foo = capture do # This ActionView Helper is designed for ERB, but should work with haml
%div
%p.title Title
%p.text
Woah this is really crazy
I mean wow,
man.
- 3.times do
= foo
%p foo
- tab_up
%p reeeeeeeeeeeeeeeeeeeeeeeeeeeeeeally loooooooooooooooooong
- tab_down
.woah
#funky
= capture_haml do
%div
%h1 Big!
%p Small
/ Invisible
= capture do
.dilly
%p foo
%h1 bar
= surround '(', ')' do
%strong parentheses!
= precede '*' do
%span.small Not really
click
= succeed '.' do
%a{:href=>"thing"} here
%p baz
- buffer.tabulation = 10
%p boom
- concat "foo\n"
- buffer.tabulation = 0
- def url_for(*stuff); stuff.join(' '); end
%p
= form_tag 'hello/world'
- form_tag 'heeheeaform' do
%div= submit_tag 'save'
- form_for :article, @article, :url => 'article_url' do |f|
Title:
= f.text_field :title
Body:
= f.text_field :body
= list_of({:google => 'http://www.google.com'}) do |name, link|
%a{ :href => link }= name
%p
- puts "foo"
%div
- puts "bar"
- puts "boom"
baz
- puts "boom, again"
- open :table do
- open :tr do
- open :td, {:class => 'cell'} do
- open :strong, "strong!"
- puts "data"
- open :td do
- puts "more_data"

View File

@@ -0,0 +1,11 @@
%div[@article]
%h1= @article.title
%div= @article.body
#id[@article] id
.class[@article] class
#id.class[@article] id class
%div{:class => "article full"}[@article]= "boo"
%div{'class' => "article full"}[@article]= "moo"
%div.articleFull[@article]= "foo"
%span[@not_a_real_variable_and_will_be_nil]
Boo

View File

@@ -0,0 +1,69 @@
!!! XML
!!! XML ISO-8859-1
!!! XML UtF-8 Foo bar
!!!
!!! 1.1
!!! 1.1 Strict
!!! Strict foo bar
!!! FRAMESET
%strong{:apos => "Foo's bar!"} Boo!
== Embedded? false!
== Embedded? #{true}!
- embedded = true
== Embedded? #{embedded}!
.render= render :inline => "%em= 'wow!'", :type => :haml
= "stuff followed by whitespace"
- if true
%strong block with whitespace
%p
\Escape
\- character
\%p foo
\yee\ha
/ Short comment
/ This is a really long comment look how long it is it should be on a line of its own don't you think?
/
This is a block comment
cool, huh?
%strong there can even be sub-tags!
= "Or script!"
-# Haml comment
-#
Nested Haml comment
- raise 'dead'
%p{ :class => "" } class attribute shouldn't appear!
/[if lte IE6] conditional comment!
/[if gte IE7]
%p Block conditional comment
%div
%h1 Cool, eh?
/[if gte IE5.2]
Woah a period.
= "test" |
"test" |
-# Hard tabs shouldn't throw errors.
- case :foo
- when :bar
%br Blah
- when :foo
%br
- case :foo
- when :bar
%meta{ :foo => 'blah'}
- when :foo
%meta{ :foo => 'bar'}
%img
%hr
%link
%script Inline content
%br
Nested content
%p.foo{:class => true ? 'bar' : 'baz'}[@article] Blah
%p.foo{:class => false ? 'bar' : ''}[@article] Blah
%p.qux{:class => 'quux'}[@article] Blump
== #{"Woah inner quotes"}
%p.dynamic_quote{:quotes => "single '", :dyn => 1 + 2}
%p.dynamic_atomic{:dyn => 1 + 2}/

View File

@@ -0,0 +1,12 @@
! Not a Doctype !
%ul
%li a
%li b
%li c
%li d
%li e
%li f
%li g
%li h
%li i

View File

@@ -0,0 +1,17 @@
!!!
%html
%head
%title Stop. haml time
#content
%h1 This is a title!
%p Lorem ipsum dolor sit amet, consectetur adipisicing elit
%p{:class => 'foo'} Cigarettes!
%h2 Man alive!
%ul.things
%li Slippers
%li Shoes
%li Bathrobe
%li Coffee
%pre
This is some text that's in a pre block!
Let's see what happens when it's rendered! What about now, since we're on a new line?

View File

@@ -0,0 +1 @@
= render :file => "#{name}.haml"

View File

@@ -0,0 +1,12 @@
%p
@foo =
= @foo
- @foo = 'value two'
%p
@foo =
= @foo
= render :file => "_partial.haml"
%p
@foo =
= @foo
- @foo = 'value one'

View File

@@ -0,0 +1,40 @@
%div
%h1 I can count!
- (1..20).each do |i|
= i
%h1 I know my ABCs!
%ul
- ('a'..'z').each do |i|
%li= i
%h1 I can catch errors!
- begin
- String.silly
- rescue NameError => e
= "Oh no! \"#{e}\" happened!"
%p
"false" is:
- if false
= "true"
- else
= "false"
- if true
- 5.times do |i|
- if i % 2 == 1
Odd!
- else
Even!
- else
= "This can't happen!"
- 13 |
.foo
%strong foobar
- 5.times |
do |
|a| |
%strong= a
.test
- "foo |
bar |
baz" |
%p boom

View File

@@ -0,0 +1,43 @@
!!!
%html{html_attrs}
%head
%title Hampton Catlin Is Totally Awesome
%meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"}
%body
/ You're In my house now!
- concat("foo\n")
.header
Yes, ladies and gentileman. He is just that egotistical.
Fantastic! This should be multi-line output
The question is if this would translate! Ahah!
= 1 + 9 + 8 + 2 #numbers should work and this should be ignored
#body= " Quotes should be loved! Just like people!"
- 120.times do |number|
- number
Wow.|
%p
= "Holy cow " + |
"multiline " + |
"tags! " + |
"A pipe (|) even!" |
= [1, 2, 3].collect { |n| "PipesIgnored|" }
= [1, 2, 3].collect { |n| |
n.to_s |
}.join("|") |
%div.silent
- foo = String.new
- foo << "this"
- foo << " shouldn't"
- foo << " evaluate"
= foo + " but now it should!"
-# Woah crap a comment!
-# That was a line that shouldn't close everything.
%ul.really.cool
- ('a'..'f').each do |a|
%li= a
#combo.of_divs_with_underscore= @should_eval = "with this text"
= [ 104, 101, 108, 108, 111 ].map do |byte|
- byte.chr
.footer
%strong.shout= "This is a really long ruby quote. It should be loved and wrapped because its more than 50 characters. This value may change in the future and this test may look stupid. \nSo, I'm just making it *really* long. God, I hope this works"

View File

@@ -0,0 +1,24 @@
%div.tags
%foo 1
%FOO 2
%fooBAR 3
%fooBar 4
%foo_bar 5
%foo-bar 6
%foo:bar 7
%foo.bar 8
%fooBAr_baz:boom_bar 9
%foo13 10
%foo2u 11
%div.classes
%p.foo.bar#baz#boom
.fooBar a
.foo-bar b
.foo_bar c
.FOOBAR d
.foo16 e
.123 f
.foo2u g
%div.broken
%foo<{ :a => :b }
.foo>{ :c => :d }

View File

@@ -0,0 +1,4 @@
!!!
%html
%head
%body

View File

@@ -0,0 +1,87 @@
#whitespace_test
= render :file => "_text_area.haml", :locals => { :value => "Oneline" }
= render :file => "_text_area.haml", :locals => { :value => "Two\nlines" }
~ render :file => "_text_area.haml", :locals => { :value => "Oneline" }
~ render :file => "_text_area.haml", :locals => { :value => "Two\nlines" }
#flattened~ render :file => "_text_area.haml", :locals => { :value => "Two\nlines" }
.hithere
~ "Foo bar"
~ "<pre>foo bar</pre>"
~ "<pre>foo\nbar</pre>"
%p~ "<pre>foo\nbar</pre>"
%p~ "foo\nbar"
.foo
~ 13
~ ['a', 'b', 'c'].map do |a|
- "<textarea>\n#{a}\n</textarea>"
#whitespace_test
= render :file => "_text_area.haml", :locals => { :value => "Oneline" }
= render :file => "_text_area.haml", :locals => { :value => "Two\nlines" }
= find_and_preserve render(:file => "_text_area.haml", :locals => { :value => "Oneline" })
= find_and_preserve render(:file => "_text_area.haml", :locals => { :value => "Two\nlines" })
#flattened= find_and_preserve render(:file => "_text_area.haml", :locals => { :value => "Two\nlines" })
.hithere
= find_and_preserve("Foo bar")
= find_and_preserve("<pre>foo bar</pre>")
= find_and_preserve("<pre>foo\nbar</pre>")
%p= find_and_preserve("<pre>foo\nbar</pre>")
%p= find_and_preserve("foo\nbar")
%pre
:preserve
___
,o88888
,o8888888'
,:o:o:oooo. ,8O88Pd8888"
,.::.::o:ooooOoOoO. ,oO8O8Pd888'"
,.:.::o:ooOoOoOO8O8OOo.8OOPd8O8O"
, ..:.::o:ooOoOOOO8OOOOo.FdO8O8"
, ..:.::o:ooOoOO8O888O8O,COCOO"
, . ..:.::o:ooOoOOOO8OOOOCOCO"
. ..:.::o:ooOoOoOO8O8OCCCC"o
. ..:.::o:ooooOoCoCCC"o:o
. ..:.::o:o:,cooooCo"oo:o:
` . . ..:.:cocoooo"'o:o:::'
.` . ..::ccccoc"'o:o:o:::'
:.:. ,c:cccc"':.:.:.:.:.'
..:.:"'`::::c:"'..:.:.:.:.:.' http://www.chris.com/ASCII/
...:.'.:.::::"' . . . . .'
.. . ....:."' ` . . . ''
. . . ...."'
.. . ."' -hrr-
.
It's a planet!
%strong This shouldn't be bold!
%strong This should!
%textarea
:preserve
___ ___ ___ ___
/\__\ /\ \ /\__\ /\__\
/:/ / /::\ \ /::| | /:/ /
/:/__/ /:/\:\ \ /:|:| | /:/ /
/::\ \ ___ /::\~\:\ \ /:/|:|__|__ /:/ /
/:/\:\ /\__\ /:/\:\ \:\__\ /:/ |::::\__\ /:/__/
\/__\:\/:/ / \/__\:\/:/ / \/__/~~/:/ / \:\ \
\::/ / \::/ / /:/ / \:\ \
/:/ / /:/ / /:/ / \:\ \
/:/ / /:/ / /:/ / \:\__\
\/__/ \/__/ \/__/ \/__/
Many
thanks
to
http://www.network-science.de/ascii/
%strong indeed!
.foo
= find_and_preserve(13)
%pre
:preserve
__ ______ __ ______
.----.| |--.|__ |.----.| |--..--------.| __ |
| __|| ||__ || __|| < | || __ |
|____||__|__||______||____||__|__||__|__|__||______|
%pre
:preserve
foo
bar