mirror of
https://github.com/haml/haml.git
synced 2022-11-09 12:33:31 -05:00
Better facilities for whitespace-sensitive elements. See REFERENCE entry on ~.
git-svn-id: svn://hamptoncatlin.com/haml/branches/edge@113 7063305b-7217-0410-af8c-cdc13e5119b9
This commit is contained in:
parent
fcc7b01ba7
commit
00ef3f9983
7 changed files with 249 additions and 162 deletions
112
REFERENCE
112
REFERENCE
|
@ -1,10 +1,10 @@
|
|||
= Haml (XHTML Abstraction Markup Language)
|
||||
|
||||
HAML is a markup language that's used to cleanly and simply describe the XHTML
|
||||
of any web document without the use of inline code. Haml functions as a
|
||||
replacement for inline page templating systems such PHP, RHTML, and ASP.
|
||||
However, Haml avoids the need for explicitly coding XHTML into the template,
|
||||
because it iself is a description of the XHTML, with some code to generate
|
||||
HAML is a markup language that's used to cleanly and simply describe the XHTML
|
||||
of any web document without the use of inline code. Haml functions as a
|
||||
replacement for inline page templating systems such PHP, RHTML, and ASP.
|
||||
However, Haml avoids the need for explicitly coding XHTML into the template,
|
||||
because it iself is a description of the XHTML, with some code to generate
|
||||
dynamic content.
|
||||
|
||||
== Features
|
||||
|
@ -19,7 +19,7 @@ dynamic content.
|
|||
== Authors
|
||||
|
||||
HAML was originally created by Hampton Catlin (hcatlin). Help with the
|
||||
Ruby On Rails implementation and much of the documentation by
|
||||
Ruby On Rails implementation and much of the documentation by
|
||||
Jeff Hardy (packagethief).
|
||||
|
||||
Nathan Weizenbaum (Nex3) contribued the buffered-engine code along with many
|
||||
|
@ -50,7 +50,7 @@ is compiled to:
|
|||
<li class='email'>eugene@example.com</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
== Characters with meaning to Haml
|
||||
|
||||
Various characters, when placed at a certain point in a line, instruct HAML
|
||||
|
@ -70,7 +70,7 @@ and text to be rendered inside the element. It creates an element in the form of
|
|||
%one
|
||||
%two
|
||||
%three Hey there
|
||||
|
||||
|
||||
is compiled to:
|
||||
|
||||
<one>
|
||||
|
@ -99,7 +99,7 @@ is compiled to:
|
|||
<script src='javascripts/script_9' type='text/javascript'>
|
||||
</script>
|
||||
</head>
|
||||
|
||||
|
||||
==== []
|
||||
|
||||
Square brackets follow a tag definiton and contain a Ruby object that is used to
|
||||
|
@ -110,11 +110,11 @@ obscure implementation detail, this is most useful for elements that represent
|
|||
instances of Models. For example:
|
||||
|
||||
# file: app/controllers/users_controller.rb
|
||||
|
||||
|
||||
def show
|
||||
@user = CrazyUser.find(15)
|
||||
end
|
||||
|
||||
|
||||
# file: app/views/users/show.haml
|
||||
|
||||
%div[@user]
|
||||
|
@ -142,7 +142,7 @@ is compiled to:
|
|||
|
||||
<br />
|
||||
<meta http-equiv='Content-Type' content='text/html' />
|
||||
|
||||
|
||||
==== . and #
|
||||
|
||||
The period and pound sign are borrowed from CSS and used as shortcuts to specify the
|
||||
|
@ -161,7 +161,7 @@ is compiled to:
|
|||
<p class='beans' food='true'>The magical fruit</p>
|
||||
<h1 class='class' id='id'>La La La</h1>
|
||||
</div>
|
||||
|
||||
|
||||
==== Assumed Divs
|
||||
|
||||
Because the div element is used so often, it is the default element. If you only
|
||||
|
@ -184,33 +184,47 @@ and is compiled to:
|
|||
<div class='item'>Broken record album</div>
|
||||
<div class='description'>What a cool item!</div>
|
||||
</div>
|
||||
|
||||
|
||||
==== = and ~
|
||||
|
||||
<tt>=</tt> and <tt>~</tt> are placed at the end of a tag definition, after class,
|
||||
id, and attribute declarations. They're just shortcuts for inserting Ruby code
|
||||
into an element. They work the same as <tt>=</tt> and <tt>~</tt> without a tag;
|
||||
see below for documentation of those. For example:
|
||||
see below for documentation of those. However, if the result is short enough, it
|
||||
is displayed entirely on one line. For example:
|
||||
|
||||
%p= "hello"
|
||||
%h1~ 1 + 2
|
||||
|
||||
is the same as:
|
||||
|
||||
is not quite the same as:
|
||||
|
||||
%p
|
||||
= "hello"
|
||||
%h1
|
||||
~ 1 + 2
|
||||
|
||||
and is compiled to:
|
||||
|
||||
<p>
|
||||
hello
|
||||
</p>
|
||||
<h1>
|
||||
3
|
||||
</h1>
|
||||
|
||||
It's compiled to:
|
||||
|
||||
<p>hello</p>
|
||||
<h1>3</h1>
|
||||
|
||||
In addition, if the tilde character is followed by an indented section of text,
|
||||
the text is rendered on one line using the XHTML newline escape character.
|
||||
For example,
|
||||
|
||||
.house
|
||||
%pre~
|
||||
/^^^\
|
||||
|[] []|
|
||||
|_____|
|
||||
|
||||
is compiled to:
|
||||
|
||||
<div class="house">
|
||||
<pre>
 /^^^\
|[] []|
|_____|
</pre>
|
||||
</div>
|
||||
|
||||
|
||||
=== XHTML Helpers
|
||||
|
||||
==== No Special Character
|
||||
|
@ -229,7 +243,7 @@ is compiled to:
|
|||
Wow this is cool!
|
||||
</whiz>
|
||||
</gee>
|
||||
|
||||
|
||||
==== !!!
|
||||
|
||||
When describing XHTML documents with Haml, you can have a document type
|
||||
|
@ -256,25 +270,25 @@ is compiled to:
|
|||
<p>Sign my guestbook</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
You can also specify the version and type of XHTML after the <tt>!!!</tt>.
|
||||
XHTML 1.0 Strict, Transitional, and Frameset and XHTML 1.1 are supported.
|
||||
The default version is 1.0 and the default type is Transitional. For example,
|
||||
|
||||
!!! 1.1
|
||||
|
||||
|
||||
is compiled to:
|
||||
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
|
||||
|
||||
and
|
||||
|
||||
!!! Strict
|
||||
|
||||
|
||||
is compiled to:
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
|
||||
|
||||
==== /
|
||||
|
||||
The forward slash character, when placed at the beginning of a line, wraps all
|
||||
|
@ -300,7 +314,7 @@ The forward slash can also wrap indented sections of code. For example:
|
|||
|
||||
is compiled to:
|
||||
|
||||
<!--
|
||||
<!--
|
||||
<p>This doesn't render...</p>
|
||||
<div>
|
||||
<h1>Because it's commented out!</h1>
|
||||
|
@ -316,12 +330,12 @@ by enclosing the condition in square brackets after the <tt>/</tt>. For example:
|
|||
|
||||
is compiled to:
|
||||
|
||||
<!--[if IE]>
|
||||
<!--[if IE]>
|
||||
<a href='http://www.mozilla.com/en-US/firefox/'>
|
||||
<h1>Get Firefox</h1>
|
||||
</a>
|
||||
<![endif]-->
|
||||
|
||||
|
||||
==== |
|
||||
|
||||
The pipe character designates a multiline string. It's placed at the end of a line,
|
||||
|
@ -343,7 +357,7 @@ is compiled to:
|
|||
probably make it |
|
||||
multiline so it doesn't |
|
||||
look awful. |
|
||||
|
||||
|
||||
=== Ruby evaluators
|
||||
|
||||
==== =
|
||||
|
@ -361,7 +375,7 @@ is compiled to:
|
|||
hi there reader!
|
||||
yo
|
||||
</p>
|
||||
|
||||
|
||||
==== ~
|
||||
|
||||
The tilde character works the same as the equals character, but the output is
|
||||
|
@ -372,17 +386,17 @@ properly. For example:
|
|||
= "Woah <pre> this is \n</pre> crazy"
|
||||
%foo2
|
||||
~ "Woah <pre> this is \n</pre> crazy"
|
||||
|
||||
|
||||
is compiled to:
|
||||
|
||||
<foo>
|
||||
Woah <pre> this is
|
||||
Woah <pre> this is
|
||||
</pre> crazy
|
||||
</foo>
|
||||
<foo2>
|
||||
Woah <pre> this is 
</pre> crazy
|
||||
</foo2>
|
||||
|
||||
|
||||
==== -
|
||||
|
||||
The hyphen character makes the text following it into "silent script", or
|
||||
|
@ -397,13 +411,13 @@ For example:
|
|||
- foo << " there"
|
||||
- foo << " you!"
|
||||
%p= foo
|
||||
|
||||
|
||||
is compiled to:
|
||||
|
||||
<p>
|
||||
hello there you!
|
||||
</p>
|
||||
|
||||
|
||||
===== Blocks
|
||||
|
||||
Like XHTML tags, you don't need to explicity close your Ruby blocks in
|
||||
|
@ -415,7 +429,7 @@ or something similar). For example:
|
|||
- (42...47).each do |i|
|
||||
%p= i
|
||||
%p See, I can count!
|
||||
|
||||
|
||||
is compiled to:
|
||||
|
||||
<p>
|
||||
|
@ -433,7 +447,7 @@ is compiled to:
|
|||
<p>
|
||||
46
|
||||
</p>
|
||||
|
||||
|
||||
Another example:
|
||||
|
||||
%p
|
||||
|
@ -444,7 +458,7 @@ Another example:
|
|||
= "2?"
|
||||
- when 3
|
||||
= "3."
|
||||
|
||||
|
||||
is compiled to:
|
||||
|
||||
<p>
|
||||
|
@ -456,7 +470,7 @@ is compiled to:
|
|||
Write Rails templates with the .haml extension. Example:
|
||||
|
||||
# file: app/views/movies/teen_wolf.haml
|
||||
|
||||
|
||||
%html
|
||||
%head
|
||||
%title= "Teen Wolf (1985)"
|
||||
|
@ -505,7 +519,7 @@ templates. Helper methods are also available in Haml templates. Example:
|
|||
.title
|
||||
%h1= @title
|
||||
= link_to 'Home', home_url
|
||||
|
||||
|
||||
may be compiled to:
|
||||
|
||||
<div id='content'>
|
||||
|
@ -514,7 +528,7 @@ may be compiled to:
|
|||
<a href='/'>Home</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
=== Setting Options
|
||||
|
||||
Options can be set by setting the hash <tt>Haml::Template.options</tt>
|
||||
|
|
|
@ -5,16 +5,16 @@ module Haml
|
|||
# processing done within instance_eval'd code.
|
||||
class Buffer
|
||||
include Haml::Helpers
|
||||
|
||||
|
||||
# Set the maximum length for a line to be considered a one-liner.
|
||||
# Lines <= the maximum will be rendered on one line,
|
||||
# i.e. <tt><p>Hello world</p></tt>
|
||||
ONE_LINER_LENGTH = 50
|
||||
|
||||
|
||||
# The string that holds the compiled XHTML. This is aliased as
|
||||
# _erbout for compatibility with ERB-specific code.
|
||||
attr_accessor :buffer
|
||||
|
||||
|
||||
# Creates a new buffer.
|
||||
def initialize(options = {})
|
||||
@options = options
|
||||
|
@ -22,11 +22,16 @@ module Haml
|
|||
@buffer = ""
|
||||
@one_liner_pending = false
|
||||
end
|
||||
|
||||
|
||||
# Renders +text+ with the proper tabulation. This also deals with
|
||||
# making a possible one-line tag one line or not.
|
||||
def push_text(text, tabulation)
|
||||
if @one_liner_pending && one_liner?(text)
|
||||
def push_text(text, tabulation, flattened = false)
|
||||
if flattened
|
||||
# In this case, tabulation is the number of spaces, rather
|
||||
# than the number of tabs.
|
||||
@buffer << "#{' ' * tabulation}#{flatten(text + "\n")}"
|
||||
@one_liner_pending = true
|
||||
elsif @one_liner_pending && one_liner?(text)
|
||||
@buffer << text
|
||||
else
|
||||
if @one_liner_pending
|
||||
|
@ -36,7 +41,7 @@ module Haml
|
|||
@buffer << "#{tabs(tabulation)}#{text}\n"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Properly formats the output of a script that was run in the
|
||||
# instance_eval.
|
||||
def push_script(result, tabulation, flattened)
|
||||
|
@ -49,29 +54,29 @@ module Haml
|
|||
end
|
||||
nil
|
||||
end
|
||||
|
||||
|
||||
# Takes the various information about the opening tag for an
|
||||
# element, formats it, and adds it to the buffer.
|
||||
def open_tag(name, tabulation, atomic, try_one_line, class_id, attributes_hash, obj_ref)
|
||||
def open_tag(name, tabulation, atomic, try_one_line, class_id, attributes_hash, obj_ref, flattened)
|
||||
attributes = {}
|
||||
attributes.merge!(parse_object_ref(obj_ref)) if obj_ref
|
||||
attributes.merge!(parse_class_and_id(class_id)) if class_id
|
||||
attributes.merge!(attributes_hash) unless attributes_hash.nil? || attributes_hash.empty?
|
||||
|
||||
|
||||
@buffer << "#{tabs(tabulation)}<#{name}#{build_attributes(attributes)}"
|
||||
@one_liner_pending = false
|
||||
if atomic
|
||||
@buffer << " />\n"
|
||||
elsif try_one_line
|
||||
@one_liner_pending = true
|
||||
@buffer << ">"
|
||||
elsif flattened
|
||||
@buffer << ">
"
|
||||
else
|
||||
if try_one_line
|
||||
@one_liner_pending = true
|
||||
@buffer << ">"
|
||||
else
|
||||
@buffer << ">\n"
|
||||
end
|
||||
@buffer << ">\n"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Creates a closing tag with the given name.
|
||||
def close_tag(name, tabulation)
|
||||
if @one_liner_pending
|
||||
|
@ -81,7 +86,7 @@ module Haml
|
|||
push_text("</#{name}>", tabulation)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Opens an XHTML comment.
|
||||
def open_comment(try_one_line, conditional, tabulation)
|
||||
conditional << ">" if conditional
|
||||
|
@ -92,7 +97,7 @@ module Haml
|
|||
@buffer << "\n"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Closes an XHTML comment.
|
||||
def close_comment(has_conditional, tabulation)
|
||||
close_tag = has_conditional ? "<![endif]-->" : "-->"
|
||||
|
@ -103,14 +108,14 @@ module Haml
|
|||
push_text(close_tag, tabulation)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
# Gets <tt>count</tt> tabs. Mostly for internal use.
|
||||
def tabs(count)
|
||||
' ' * count
|
||||
end
|
||||
|
||||
|
||||
# Iterates through the classes and ids supplied through <tt>.</tt>
|
||||
# and <tt>#</tt> syntax, and returns a hash with them as attributes,
|
||||
# that can then be merged with another attributes hash.
|
||||
|
@ -131,7 +136,7 @@ module Haml
|
|||
end
|
||||
attributes
|
||||
end
|
||||
|
||||
|
||||
# Takes an array of objects and uses the class and id of the first
|
||||
# one to create an attributes hash.
|
||||
def parse_object_ref(ref)
|
||||
|
@ -139,7 +144,7 @@ module Haml
|
|||
class_name = ref.class.to_s.underscore
|
||||
{:id => "#{class_name}_#{ref.id}", :class => class_name}
|
||||
end
|
||||
|
||||
|
||||
# Takes a hash and builds a list of XHTML attributes from it, returning
|
||||
# the result.
|
||||
def build_attributes(attributes = {})
|
||||
|
@ -162,7 +167,7 @@ module Haml
|
|||
result = result.compact.join(' ')
|
||||
(attributes.empty? ? String.new : String.new(' ')) + result
|
||||
end
|
||||
|
||||
|
||||
# Returns whether or not the given value is short enough to be rendered
|
||||
# on one line.
|
||||
def one_liner?(value)
|
||||
|
|
|
@ -5,7 +5,7 @@ module Haml
|
|||
# This is the class where all the parsing and processing of the HAML
|
||||
# template is done. It can be directly used by the user by creating a
|
||||
# new instance and calling to_html to render the template. For example:
|
||||
#
|
||||
#
|
||||
# template = File.load('templates/really_cool_template.haml')
|
||||
# haml_engine = Haml::Engine.new(template)
|
||||
# output = haml_engine.to_html
|
||||
|
@ -15,41 +15,41 @@ module Haml
|
|||
|
||||
# Allow access to the precompiled template
|
||||
attr_reader :precompiled
|
||||
|
||||
|
||||
# Allow reading and writing of the options hash
|
||||
attr :options, true
|
||||
|
||||
|
||||
# Designates an XHTML/XML element.
|
||||
ELEMENT = '%'[0]
|
||||
|
||||
|
||||
# Designates a <tt><div></tt> element with the given class.
|
||||
DIV_CLASS = '.'[0]
|
||||
|
||||
|
||||
# Designates a <tt><div></tt> element with the given id.
|
||||
DIV_ID = '#'[0]
|
||||
|
||||
|
||||
# Designates an XHTML/XML comment.
|
||||
COMMENT = '/'[0]
|
||||
|
||||
|
||||
# Designates an XHTML doctype.
|
||||
DOCTYPE = '!'[0]
|
||||
|
||||
|
||||
# Designates script, the result of which is output.
|
||||
SCRIPT = '='[0]
|
||||
|
||||
|
||||
# Designates script, the result of which is flattened and output.
|
||||
FLAT_SCRIPT = '~'[0]
|
||||
|
||||
|
||||
# Designates script which is run but not output.
|
||||
SILENT_SCRIPT = '-'[0]
|
||||
|
||||
|
||||
# When following SILENT_SCRIPT, designates a comment that is not output.
|
||||
SILENT_COMMENT = '#'[0]
|
||||
|
||||
|
||||
# Designates a non-parsed line. Not actually a character.
|
||||
PLAIN_TEXT = -1
|
||||
|
||||
# Keeps track of the ASCII values of the characters that begin a
|
||||
|
||||
# Keeps track of the ASCII values of the characters that begin a
|
||||
# specially-interpreted line.
|
||||
SPECIAL_CHARACTERS = [
|
||||
ELEMENT,
|
||||
|
@ -65,21 +65,21 @@ module Haml
|
|||
# The value of the character that designates that a line is part
|
||||
# of a multiline string.
|
||||
MULTILINE_CHAR_VALUE = '|'[0]
|
||||
|
||||
|
||||
# Characters that designate that a multiline string may be about
|
||||
# to begin.
|
||||
MULTILINE_STARTERS = SPECIAL_CHARACTERS - ["/"[0]]
|
||||
|
||||
|
||||
# Keywords that appear in the middle of a Ruby block with lowered
|
||||
# indentation. If a block has been started using indentation,
|
||||
# lowering the indentation with one of these won't end the block.
|
||||
# For example:
|
||||
#
|
||||
#
|
||||
# - if foo
|
||||
# %p yes!
|
||||
# - else
|
||||
# %p no!
|
||||
#
|
||||
#
|
||||
# The block is ended after <tt>%p no!</tt>, because <tt>else</tt>
|
||||
# is a member of this array.
|
||||
MID_BLOCK_KEYWORDS = ['else', 'elsif', 'rescue', 'ensure', 'when']
|
||||
|
@ -92,7 +92,7 @@ module Haml
|
|||
# to REFERENCE!
|
||||
#++
|
||||
#
|
||||
|
||||
|
||||
def initialize(template, options = {})
|
||||
@options = {
|
||||
:suppress_eval => false,
|
||||
|
@ -104,6 +104,10 @@ module Haml
|
|||
@to_close_stack = []
|
||||
@tabulation = 0
|
||||
|
||||
# This is the base tabulation of the currently active
|
||||
# flattened block. -1 signifies that there is no such block.
|
||||
@flat_spaces = -1
|
||||
|
||||
# Only do the first round of pre-compiling if we really need to.
|
||||
# They might be passing in the precompiled string.
|
||||
do_precompile if @precompiled.nil? && (@precompiled = String.new)
|
||||
|
@ -121,9 +125,9 @@ module Haml
|
|||
# Return the result string
|
||||
@buffer.buffer
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
#Precompile each line
|
||||
def do_precompile
|
||||
push_silent <<-END
|
||||
|
@ -132,55 +136,61 @@ module Haml
|
|||
_erbout = _hamlout.buffer
|
||||
END
|
||||
@template.each_with_index do |line, index|
|
||||
count, line = count_soft_tabs(line)
|
||||
suppress_render = handle_multiline(count, line, index)
|
||||
|
||||
if !suppress_render && count && line && (line.strip.size > 0)
|
||||
count, line = process_line(count, line, index)
|
||||
spaces, tabs = count_soft_tabs(line)
|
||||
line = line.strip
|
||||
suppress_render = handle_multiline(spaces, tabs, line, index)
|
||||
|
||||
if !suppress_render && spaces
|
||||
count, line = process_line(spaces, tabs, line, index)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Make sure an ending multiline gets closed
|
||||
handle_multiline(0, nil, 0)
|
||||
|
||||
handle_multiline(0, 0, nil, 0)
|
||||
|
||||
# Close all the open tags
|
||||
@to_close_stack.length.times { close }
|
||||
|
||||
|
||||
push_silent "end"
|
||||
end
|
||||
|
||||
|
||||
# Processes a single line of HAML. <tt>count</tt> does *not* represent the
|
||||
# line number; rather, it represents the tabulation count (the number of
|
||||
# spaces before the line divided by two).
|
||||
#
|
||||
#
|
||||
# This method doesn't return anything; it simply processes the line and
|
||||
# adds the appropriate code to <tt>@precompiled</tt>.
|
||||
def process_line(count, line, index)
|
||||
if count > @to_close_stack.size
|
||||
|
||||
# Indentation has been increased without a new tag
|
||||
if @latest_command == SILENT_SCRIPT
|
||||
|
||||
# The indentation was increased after silent script,
|
||||
# it must be a block
|
||||
@to_close_stack.push [:script]
|
||||
end
|
||||
|
||||
elsif count <= @to_close_stack.size && @to_close_stack.size > 0
|
||||
# The tabulation has gone down, and it's not because of one of
|
||||
# Ruby's mid-block keywords
|
||||
to_close = @to_close_stack.size - count
|
||||
def process_line(spaces, count, line, index)
|
||||
if line.length > 0
|
||||
if count > @to_close_stack.size
|
||||
|
||||
to_close.times do |i|
|
||||
offset = to_close - 1 - i
|
||||
unless offset == 0 && line.length > 2 && line[0] == SILENT_SCRIPT &&
|
||||
MID_BLOCK_KEYWORDS.include?(line[1..-1].split[0])
|
||||
close
|
||||
# Indentation has been increased without a new tag
|
||||
if @latest_command == SILENT_SCRIPT
|
||||
|
||||
# The indentation was increased after silent script,
|
||||
# it must be a block
|
||||
@to_close_stack.push [:script]
|
||||
end
|
||||
|
||||
elsif count <= @to_close_stack.size && @to_close_stack.size > 0
|
||||
# The tabulation has gone down, and it's not because of one of
|
||||
# Ruby's mid-block keywords
|
||||
to_close = @to_close_stack.size - count
|
||||
|
||||
to_close.times do |i|
|
||||
offset = to_close - 1 - i
|
||||
unless offset == 0 && line.length > 2 && line[0] == SILENT_SCRIPT &&
|
||||
MID_BLOCK_KEYWORDS.include?(line[1..-1].split[0])
|
||||
close
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if line.length > 0
|
||||
|
||||
if @flat_spaces != -1
|
||||
@latest_command = PLAIN_TEXT
|
||||
push_flat(line, spaces)
|
||||
elsif line.length > 0
|
||||
@latest_command = line[0]
|
||||
case @latest_command
|
||||
when DIV_CLASS, DIV_ID
|
||||
|
@ -219,11 +229,11 @@ module Haml
|
|||
push_text doctype
|
||||
else
|
||||
@latest_command = PLAIN_TEXT
|
||||
push_text line.strip
|
||||
push_text line
|
||||
end
|
||||
else
|
||||
@latest_command = PLAIN_TEXT
|
||||
push_text line.strip
|
||||
push_text line
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -232,13 +242,13 @@ module Haml
|
|||
# the beginning, continuation, or end of a multiline sequence. Like
|
||||
# process_line, <tt>count</tt> represents the tabulation, not line
|
||||
# number.
|
||||
#
|
||||
#
|
||||
# This returns whether or not the line should be
|
||||
# rendered normally.
|
||||
def handle_multiline(count, line, index)
|
||||
def handle_multiline(spaces, count, line, index)
|
||||
# Multilines are denoting by ending with a `|` (124)
|
||||
if is_multiline?(line) && @multiline_buffer
|
||||
# A multiline string is active, and is being continued
|
||||
# A multiline string is active, and is being continued
|
||||
@multiline_buffer += line[0...-1]
|
||||
suppress_render = true
|
||||
elsif is_multiline?(line) && (MULTILINE_STARTERS.include? line[0])
|
||||
|
@ -246,17 +256,18 @@ module Haml
|
|||
@multiline_buffer = line[0...-1]
|
||||
@multiline_count = count
|
||||
@multiline_index = index
|
||||
@multiline_spaces = spaces
|
||||
suppress_render = true
|
||||
elsif @multiline_buffer
|
||||
# A multiline string has just ended, make line into the result
|
||||
process_line(@multiline_count, @multiline_buffer, @multiline_index)
|
||||
process_line(@multiline_spaces, @multiline_count, @multiline_buffer, @multiline_index)
|
||||
@multiline_buffer = nil
|
||||
suppress_render = false
|
||||
end
|
||||
|
||||
return suppress_render
|
||||
end
|
||||
|
||||
|
||||
# Checks whether or not +line+ is in a multiline sequence.
|
||||
def is_multiline?(line) # ' '[0] == 32
|
||||
line && line.length > 1 && line[-1] == MULTILINE_CHAR_VALUE && line[-2] == 32
|
||||
|
@ -273,12 +284,12 @@ module Haml
|
|||
@haml_stack ||= Array.new
|
||||
@haml_stack.push(buffer)
|
||||
self.class.instance_eval { include Haml::Helpers }
|
||||
|
||||
|
||||
class << self
|
||||
attr :haml_lineno
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
begin
|
||||
# Evaluate the buffer in the context of the scope object
|
||||
@scope_object.instance_eval @precompiled
|
||||
|
@ -292,27 +303,27 @@ module Haml
|
|||
# For some reason that I can't figure out,
|
||||
# @scope_object.methods.include? "haml_filename" && @scope_object.haml_filename
|
||||
# is false when it shouldn't be. Nested if statements work, though.
|
||||
|
||||
|
||||
if @scope_object.haml_filename
|
||||
filename = "#{@scope_object.haml_filename}.haml"
|
||||
end
|
||||
end
|
||||
lineno = @scope_object.haml_lineno
|
||||
|
||||
|
||||
if compile_error
|
||||
eval_line = compile_error[0].to_i
|
||||
line_marker = @precompiled.split("\n")[0...eval_line].grep(/@haml_lineno = [0-9]*/)[-1]
|
||||
lineno = line_marker.scan(/[0-9]+/)[0].to_i if line_marker
|
||||
end
|
||||
|
||||
|
||||
e.backtrace.unshift "#{filename}:#{lineno}"
|
||||
raise e
|
||||
end
|
||||
|
||||
|
||||
# Get rid of the current buffer
|
||||
@scope_object.instance_eval do
|
||||
@haml_stack.pop
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Evaluates <tt>text</tt> in the context of <tt>@scope_object</tt>, but
|
||||
|
@ -332,9 +343,15 @@ module Haml
|
|||
@precompiled << "_hamlout.push_text(#{text.dump}, #{@tabulation})\n"
|
||||
end
|
||||
|
||||
# Adds +text+ to <tt>@buffer</tt> while flattening text.
|
||||
def push_flat(text, spaces)
|
||||
tabulation = spaces - @flat_spaces
|
||||
@precompiled << "_hamlout.push_text(#{text.dump}, #{tabulation > -1 ? tabulation : 0}, true)\n"
|
||||
end
|
||||
|
||||
# Causes <tt>text</tt> to be evaluated in the context of
|
||||
# <tt>@scope_object</tt> and the result to be added to <tt>@buffer</tt>.
|
||||
#
|
||||
#
|
||||
# If <tt>flattened</tt> is true, Haml::Helpers#find_and_flatten is run on
|
||||
# the result before it is added to <tt>@buffer</tt>
|
||||
def push_script(text, flattened, index)
|
||||
|
@ -361,14 +378,15 @@ module Haml
|
|||
# the most recently opened tag.
|
||||
def close_tag(tag)
|
||||
@tabulation -= 1
|
||||
@flat_spaces = -1
|
||||
@precompiled << "_hamlout.close_tag(#{tag.dump}, #{@tabulation})\n"
|
||||
end
|
||||
|
||||
|
||||
# Closes a Ruby block.
|
||||
def close_block
|
||||
push_silent "end"
|
||||
end
|
||||
|
||||
|
||||
# Closes a comment.
|
||||
def close_comment(has_conditional)
|
||||
@tabulation -= 1
|
||||
|
@ -380,27 +398,27 @@ module Haml
|
|||
def render_tag(line, index)
|
||||
line.scan(/[%]([-:_a-zA-Z0-9]+)([-_a-zA-Z0-9\.\#]*)(\{.*\})?(\[.*\])?([=\/\~]?)?(.*)?/) do |tag_name, attributes, attributes_hash, object_ref, action, value|
|
||||
value = value.to_s
|
||||
|
||||
|
||||
case action
|
||||
when '/'
|
||||
atomic = true
|
||||
when '=', '~'
|
||||
flattened = (action == '~')
|
||||
parse = true
|
||||
else
|
||||
value = value.strip
|
||||
end
|
||||
|
||||
|
||||
flattened = (action == '~')
|
||||
value_exists = !value.empty?
|
||||
attributes_hash = "nil" unless attributes_hash
|
||||
object_ref = "nil" unless object_ref
|
||||
|
||||
push_silent "_hamlout.open_tag(#{tag_name.inspect}, #{@tabulation}, #{atomic.inspect}, #{value_exists.inspect}, #{attributes.inspect}, #{attributes_hash}, #{object_ref})\n"
|
||||
|
||||
|
||||
push_silent "_hamlout.open_tag(#{tag_name.inspect}, #{@tabulation}, #{atomic.inspect}, #{value_exists.inspect}, #{attributes.inspect}, #{attributes_hash}, #{object_ref}, #{flattened.inspect})"
|
||||
|
||||
unless atomic
|
||||
@to_close_stack.push [:element, tag_name]
|
||||
@tabulation += 1
|
||||
|
||||
|
||||
if value_exists
|
||||
if parse
|
||||
push_script(value, flattened, index)
|
||||
|
@ -408,6 +426,10 @@ module Haml
|
|||
push_text(value)
|
||||
end
|
||||
close
|
||||
elsif flattened
|
||||
# @flat_spaces is the number of indentations in the template
|
||||
# that forms the base of the flattened area
|
||||
@flat_spaces = @to_close_stack.size * 2
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,7 +22,8 @@ module Haml
|
|||
|
||||
# Counts the tabulation of a line. Mostly for internal use.
|
||||
def count_soft_tabs(line)
|
||||
line.index(/[^ ]/) ? [line.index(/[^ ]/)/2, line.strip] : []
|
||||
spaces = line.index(/[^ ]/)
|
||||
spaces ? [spaces, spaces/2] : []
|
||||
end
|
||||
|
||||
# Takes an array and a block and iterates the array,
|
||||
|
|
|
@ -24,3 +24,15 @@
|
|||
<textarea>BLAH
</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class='hithere'>
|
||||
Foo bar
|
||||
<pre>foo bar</pre>
|
||||
<pre>foo
bar</pre>
|
||||
<p><pre>foo
bar</pre></p>
|
||||
<p>
|
||||
foo
|
||||
bar
|
||||
</p>
|
||||
<pre>
 ___
 ,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:"'..:.:.:.:.:.'
 ...:.'.:.::::"' . . . . .'
 .. . ....:."' ` . . . ''
 . . . ...."'
 .. . ."' -hrr-
 .


 It's a planet!
%strong This shouldn't be bold!
</pre>
|
||||
<strong>This should!</strong>
|
||||
</div>
|
||||
|
|
|
@ -43,7 +43,7 @@ class TemplateTest < Test::Unit::TestCase
|
|||
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'
|
||||
|
@ -52,17 +52,17 @@ class TemplateTest < Test::Unit::TestCase
|
|||
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)
|
||||
|
@ -71,19 +71,19 @@ class TemplateTest < Test::Unit::TestCase
|
|||
def test_template_renders_should_eval
|
||||
assert_equal("2\n", render("= 1+1"))
|
||||
end
|
||||
|
||||
|
||||
def test_rhtml_still_renders
|
||||
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
|
||||
template = <<END
|
||||
%p
|
||||
|
@ -101,14 +101,14 @@ END
|
|||
rescue Exception => e
|
||||
assert_equal("(test).haml:4", e.backtrace[0])
|
||||
end
|
||||
|
||||
|
||||
@base.haml_filename = nil
|
||||
begin
|
||||
render(template.chomp)
|
||||
rescue Exception => e
|
||||
assert_equal("(haml):4", e.backtrace[0])
|
||||
end
|
||||
|
||||
|
||||
template = <<END
|
||||
%p
|
||||
%h1 Hello!
|
||||
|
|
|
@ -4,3 +4,36 @@
|
|||
~ 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"
|
||||
%pre~
|
||||
___
|
||||
,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:"'..:.:.:.:.:.'
|
||||
...:.'.:.::::"' . . . . .'
|
||||
.. . ....:."' ` . . . ''
|
||||
. . . ...."'
|
||||
.. . ."' -hrr-
|
||||
.
|
||||
|
||||
|
||||
It's a planet!
|
||||
%strong This shouldn't be bold!
|
||||
%strong This should!
|
||||
|
|
Loading…
Add table
Reference in a new issue