public
Last active

Deploying a Sinatra app to Heroku

  • Download Gist
README
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# Deploying a Sinatra app to Heroku
 
## Database
The location of the database Heroku provides can be found in the environment
variable DATABASE_URL. Check the configure-block of toodeloo.rb for an example
on how to use this.
 
## Rackup file
Heroku can serve all Rack applications. It looks for a rackup file named
'config.ru' in the root directory. Thus serving a Sinatra app is simple:
 
require 'toodeloo'
run Sinatra::Application
 
## Create app and deploy
The whole process of deploying this small Sinatra app was as follows:
 
$ git clone git://gist.github.com/68277.git toodeloo
$ cd toodeloo
$ heroku create toodeloo
$ git remote add heroku git@heroku.com:toodeloo.git
$ git push heroku master
 
That's it. You can see it in action at http://toodeloo.heroku.com
config.ru
Ruby
1 2 3
require 'toodeloo'
 
run Sinatra::Application
toodeloo.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
require 'sinatra'
require 'dm-core'
 
# Heroku has a limited number of gems installed, and chance is that you need
# some additional gems, like haml. The trick is to vendor them with your app.
# First, add this snippet, which will add vendor/*/lib to your load path:
Dir['vendor/*'].each do |lib|
$:.unshift(File.join(File.dirname(__FILE__), lib, 'lib'))
end
# Next, unpack all the gems you need in vendor:
#
# $ mkdir vendor
# $ cd vendor/
# $ gem unpack haml
#
# And finally require it (which isn't really necesarry in this case, since
# Sinatra does it for you, but for sake of the example we'll do it):
require 'haml'
 
# Make fuckin' sure your DataMapper models are defined *before* the configure
# block, otherwise your DB won't be updated and you're in for trouble and
# what-not.
class Todo
include DataMapper::Resource
property :id, Integer, :serial => true
property :text, String
end
 
configure do
# Heroku has some valuable information in the environment variables.
# DATABASE_URL is a complete URL for the Postgres database that Heroku
# provides for you, something like: postgres://user:password@host/db, which
# is what DM wants. This is also a convenient check wether we're in production
# / not.
DataMapper.setup(:default, (ENV["DATABASE_URL"] || "sqlite3:///#{Dir.pwd}/db.sqlite3"))
DataMapper.auto_upgrade!
end
 
get '/' do
@todos = Todo.all
haml :index
end
 
post '/' do
Todo.create(:text => params['todo'])
redirect '/'
end
 
__END__
 
@@ index
!!!
%html
%head
%title Toodeloo
%body
%h1 Toodeloo
%ul
- @todos.each do |todo|
%li= todo.text
%form{:action => '/', :method => 'POST'}
%input{:type => 'text', :name => 'todo'}
%input{:type => 'submit', :name => 'Todo!'}
%a{:href => 'http://gist.github.com/68277'} Read more..
vendor/haml-2.0.9/FAQ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
= Frequently Asked Questions
 
== Haml
 
=== How do I put a punctuation mark after an element, like "<tt>I like <strong>cake</strong>!</tt>"?
 
Expressing the structure of a document
and expressing inline formatting are two very different problems.
Haml is mostly designed for structure,
so the best way to deal with formatting is to leave it to other languages
that are designed for it.
You could use Textile:
 
%p
:textile
I like *cake*!
 
or Markdown:
 
%p
:markdown
I like **cake**!
 
or plain old XHTML:
 
%p I like <strong>cake</strong>!
 
If you're inserting something that's generated by a helper, like a link,
then it's even easier:
 
%p== I like #{link_to 'chocolate', 'http://franschocolates.com'}!
 
=== How do I stop Haml from indenting the contents of my +pre+ and +textarea+ tags?
 
Because Haml automatically indents the HTML source code,
the contents of whitespace-sensitive tags like +pre+ and +textarea+
can get screwed up.
The solution is to replace the newlines inside these tags
with HTML newline entities (<tt>&#x000A;</tt>),
which Haml does using the Haml::Helpers#preserve and Haml::Helpers#find_and_preserve helpers.
 
Normally, Haml will do this for you automatically
when you're using a tag that needs it
(this can be customized using the <tt>:preserve</tt> option;
see the Options section of the {Haml reference}(../classes/Haml.html)).
For example,
 
%p
%textarea= "Foo\nBar"
 
will be compiled to
 
<p>
<textarea>Foo&#x000A;Bar</textarea>
</p>
 
However, if a helper is generating the tag,
Haml can't detect that and so you'll have to call +find_and_preserve+ yourself.
You can also use <tt>~</tt>, which is the same as <tt>=</tt>
except that it automatically runs +find_and_preserve+ on its input.
For example:
 
%p= find_and_preserve "<textarea>Foo\nBar</textarea>"
 
is the same as
 
%p~ "<textarea>Foo\nBar</textarea>"
 
and renders
 
<p><textarea>Foo&#x000A;Bar</textarea></p>
 
=== How do I make my long lines of Ruby code look nicer in my Haml document?
 
Put them in a helper or your model.
 
Haml purposefully makes it annoying to put lots of Ruby code into your templates,
because lots of code doesn't belong in the view.
If you take that huge +link_to_remote+ call
and move it to a +update_sidebar_link+ helper,
it'll make your view both easier to read and more semantic.
 
If you absolutely must put lots of code in your template,
Haml offers a somewhat awkward multiline-continuation tool.
Put a <tt>|</tt> (pipe character) at the end of each line you want to be merged into one
(including the last line!).
For example:
 
%p= @this.is(way.too.much). |
code("and I should"). |
really_move.it.into( |
:a => @helper) |
 
=== I have Haml installed. Why is Rails (only looking for <tt>.html.erb</tt> files | rendering Haml files as plain text | rendering Haml files as blank pages)?
 
There are several reasons these things might be happening.
First of all, make sure vendor/plugins/haml really exists
and has an init.rb file in there.
Then try restarting Mongrel or WEBrick or whatever you might be using.
 
Finally, if none of these work,
chances are you've got some localization plugin like Globalize installed.
Such plugins often don't play nicely with Haml.
Luckily, there's usually an easy fix.
For Globalize, just edit globalize/lib/globalize/rails/action_view.rb
and change
 
@@re_extension = /\.(rjs|rhtml|rxml)$/
 
to
 
@@re_extension = /\.(rjs|rhtml|rxml|erb|builder|haml)$/
 
For other plugins, a little searching will probably turn up a way to fix them as well.
 
== Sass
 
=== Can I use a variable from my controller in my Sass file?
 
No. Sass files aren't views.
They're compiled once into static CSS files,
then left along until they're changed and need to be compiled again.
Not only don't you want to be running a full request cycle
every time someone requests a stylesheet,
but it's not a great idea to put much logic in there anyway
due to how browsers handle them.
 
If you really need some sort of dynamic CSS,
the best thing to do is put only the snippet you need to dynamically set
in the +head+ of your HTML document.
 
== You still haven't answered my question!
 
Sorry! Try looking at the Haml or Sass references,
in the doucmentation for the haml and Sass modules, respectively.
If you can't find an answer there,
feel free to ask in #haml on irc.freenode.net
or send an email to the {mailing list}[http://groups.google.com/group/haml?hl=en].
vendor/haml-2.0.9/MIT-LICENSE
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Copyright (c) 2006-2008 Hampton Catlin
 
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
 
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
vendor/haml-2.0.9/README.rdoc
RDoc

Haml and Sass

Haml and Sass are templating engines for the two most common types of documents on the web: HTML and CSS, respectively. They are designed to make it both easier and more pleasant to code HTML and CSS documents, by eliminating redundancy, reflecting the underlying structure that the document represents, and providing elegant, easily understandable, and powerful syntax.

Using

There are several ways to use Haml and Sass. They can be used as a plugin for Rails or Merb, or embedded on their own in other applications. The first step of all of these is to install the Haml gem:

gem install haml

To install Haml and Sass as a Rails plugin, just run haml --rails path/to/rails/app and both Haml and Sass will be installed. Views with the .haml (or .html.haml for edge) extension will automatically use Haml. Sass is a little more complicated; .sass files should be placed in public/stylesheets/sass, where they'll be automatically compiled to corresponding CSS files in public/stylesheets when needed (the Sass template directory is customizable… see the Sass module docs for details).

For Merb, .html.haml views will work without any further modification. To enable Sass, you also need to add a dependency. To do so, just add

dependency "merb-haml"

to config/dependencies.rb (or config/init.rb in a flat/very flat Merb application). Then it'll work just like it does in Rails.

To use Haml and Sass programatically, check out the RDocs for the Haml and Sass modules.

Formatting

Haml

The most basic element of Haml is a shorthand for creating HTML tags:

%tagname{ :attr1 => 'value1', :attr2 => 'value2' } Contents

No end-tag is needed; Haml handles that automatically. Adding class and id attributes is even easier. Haml uses the same syntax as the CSS that styles the document:

%tagname#id.class

In fact, when you're using the <div> tag, it becomes even easier. Because <div> is such a common element, a tag without a name defaults to a div. So

#foo Hello!

becomes

<div id='foo'>Hello!</div>

Haml uses indentation to bring the individual elements to represent the HTML structure. A tag's children are indented two spaces more than the parent tag. Again, a closing tag is automatically added. For example:

%ul
  %li Salt
  %li Pepper

becomes:

<ul>
  <li>Salt</li>
  <li>Pepper</li>
</ul>

You can also put plain text as a child of an element:

%p
  Hello,
  World!

It's even possible to embed Ruby code into Haml documents. An equals sign, =, will output the result of the code. A hyphen, -, will run the code but not output the result. You can even use control statements like if and while:

%p
  Date/Time:
  - now = DateTime.now
  %strong= now
  - if now > DateTime.parse("December 31, 2006")
    = "Happy new " + "year!"

Haml provides far more tools than those presented here. Check out the reference documentation in the Haml module.

Sass

At its most basic, Sass is just another way of writing CSS. Although it's very much like normal CSS, the basic syntax offers a few helpful features: tabulation (using *two spaces*) indicates the attributes in a rule, rather than non-DRY brackets; and newlines indicate the end of an attribute, rather than a semicolon. For example:

#main
  :background-color #f00
  :width 98%

becomes:

#main {
  background-color: #f00;
  width: 98% }

However, Sass provides much more than a way to make CSS look nice. In CSS, it's important to have accurate selectors, so your styles don't just apply to everything. However, in order to do this, you need to use nested element selectors. These get very ugly very quickly. I'm sure everyone's had to write something like “#main .sidebar .top p h1 a”, followed by “#main .sidebar .top p h1 a:visited” and “#main .sidebar .top p h1 a:hover”. Well, Sass gets rid of that. Like Haml, it uses indentation to indicate the structure of the document. So, what was:

#main {
  width: 90%;
}
#main p {
  border-style: solid;
  border-width: 1px;
  border-color: #00f;
}
#main p a {
  text-decoration: none;
  font-weight: bold;
}
#main p a:hover {
  text-decoration: underline;
}

becomes:

#main
  :width 90%
  p
    :border-style solid
    :border-width 1px
    :border-color #00f
    a
      :text-decoration none
      :font-weight bold
    a:hover
      :text-decoration underline

Pretty nice, no? Well, it gets better. One of the main complaints against CSS is that it doesn't allow constants. What if have a color or a width you re-use all the time? In CSS, you just have to re-type it each time, which is a nightmare when you decide to change it later. Not so for Sass! You can use the “!” character to set constants. Then, if you put “=” after your attribute name, you can set it to a constant. For example:

!note_bg= #55aaff

#main
  :width 70%
  .note
    :background-color= !note_bg
  p
    :width 5em
    :background-color= !note_bg

becomes:

#main {
  width: 70%; }
  #main .note {
    background-color: #55aaff; }
  #main p {
    width: 5em;
    background-color: #55aaff; }

You can even do simple arithmetic operations with constants, adding numbers and even colors together:

!main_bg= #46ar12
!main_width= 40em

#main
  :background-color= !main_bg
  :width= !main_width
  .sidebar
    :background-color= !main_bg + #333333
    :width= !main_width - 25em

becomes:

#main {
  background-color: #46a312;
  width: 40em; }
  #main .sidebar {
    background-color: #79d645;
    width: 15em; }

Taking the idea of constants a bit further are mixins. These let you group whole swathes of CSS attributes into a single directive and then include those anywhere you want:

=blue-border
  :border
    :color blue
    :width 2px
    :style dotted

.comment
  +blue-border
  :padding 2px
  :margin 10px 0

.reply
  +blue-border

becomes:

.comment {
  border-color: blue;
  border-width: 2px;
  border-style: dotted;
  padding: 2px;
  margin: 10px 0;
}

.reply {
  border-color: blue;
  border-width: 2px;
  border-style: dotted;
}

A comprehensive list of features is in the documentation for the Sass module.

Executables

The Haml gem includes several executables that are useful for dealing with Haml and Sass from the command line.

haml

The haml executable transforms a source Haml file into HTML. See haml --help for further information and options.

sass

The sass executable transforms a source Sass file into CSS. See sass --help for further information and options.

html2haml

The html2haml executable attempts to transform HTML, optionally with ERB markup, into Haml code. Since HTML is so variable, this transformation is not always perfect; it's a good idea to have a human check the output of this tool. See html2haml --help for further information and options.

css2sass

The css2sass executable attempts to transform CSS into Sass code. This transformation attempts to use Sass nesting where possible. See css2sass --help for further information and options.

Authors

Haml and Sass are designed by Hampton Catlin (hcatlin) and he is the author of the original implementation. However, Hampton doesn't even know his way around the code anymore and mostly just concentrates on the language issues. Hampton lives in Toronto, Ontario (though he's an American by birth) and is a partner at Unspace Interactive.

Nathan Weizenbaum is the primary maintainer and architect of the “modern” Ruby implementation of Haml. His hard work has kept the project alive by endlessly answering forum posts, fixing bugs, refactoring, finding speed improvements, writing documentation, implementing new features, and getting Hampton coffee (a fitting task for a boy-genius). Nathan lives in Seattle, Washington and while not being a student at University of Washington he consults for Unspace Interactive and Microsoft.

If you use this software, you must pay Hampton a compliment. And buy Nathan some jelly beans. Maybe pet a kitten. Yeah. Pet that kitty.

Some of the work on Haml was supported by Unspace Interactive.

Beyond that, the implementation is licensed under the MIT License. Ok, fine, I guess that means compliments aren't required.

vendor/haml-2.0.9/REVISION
1
(release)
vendor/haml-2.0.9/Rakefile
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
require 'rubygems'
require 'rake'
 
# ----- Benchmarking -----
 
desc <<END
Benchmark haml against ERb.
TIMES=n sets the number of runs. Defaults to 1000.
END
task :benchmark do
sh "ruby test/benchmark.rb #{ENV['TIMES']}"
end
 
# ----- Default: Testing ------
 
if ENV["RUN_CODE_RUN"] == "true"
task :default => :"test:rails_compatibility"
else
task :default => :test
end
 
require 'rake/testtask'
 
Rake::TestTask.new do |t|
t.libs << 'lib'
test_files = FileList['test/**/*_test.rb']
test_files.exclude('test/rails/*')
t.test_files = test_files
t.verbose = true
end
Rake::Task[:test].send(:add_comment, <<END)
To run with an alternate version of Rails, make test/rails a symlink to that version.
END
 
# ----- Packaging -----
 
require 'rake/gempackagetask'
load 'haml.gemspec'
 
Rake::GemPackageTask.new(HAML_GEMSPEC) do |pkg|
if Rake.application.top_level_tasks.include?('release')
pkg.need_tar_gz = true
pkg.need_tar_bz2 = true
pkg.need_zip = true
end
end
 
task :revision_file do
require 'lib/haml'
 
if Haml.version[:rev] && !Rake.application.top_level_tasks.include?('release')
File.open('REVISION', 'w') { |f| f.puts Haml.version[:rev] }
elsif Rake.application.top_level_tasks.include?('release')
File.open('REVISION', 'w') { |f| f.puts "(release)" }
else
File.open('REVISION', 'w') { |f| f.puts "(unknown)" }
end
end
Rake::Task[:package].prerequisites.insert(0, :revision_file)
 
# We also need to get rid of this file after packaging.
at_exit { File.delete('REVISION') rescue nil }
 
desc "Install Haml as a gem."
task :install => [:package] do
sudo = RUBY_PLATFORM =~ /win32/ ? '' : 'sudo'
sh %{#{sudo} gem install --no-ri pkg/haml-#{File.read('VERSION').strip}}
end
 
desc "Release a new Haml package to Rubyforge. Requires the NAME and VERSION flags."
task :release => [:package] do
name, version = ENV['NAME'], ENV['VERSION']
raise "Must supply NAME and VERSION for release task." unless name && version
sh %{rubyforge login}
sh %{rubyforge add_release haml haml "#{name} (v#{version})" pkg/haml-#{version}.gem}
sh %{rubyforge add_file haml haml "#{name} (v#{version})" pkg/haml-#{version}.tar.gz}
sh %{rubyforge add_file haml haml "#{name} (v#{version})" pkg/haml-#{version}.tar.bz2}
sh %{rubyforge add_file haml haml "#{name} (v#{version})" pkg/haml-#{version}.zip}
end
 
# ----- Documentation -----
 
begin
require 'hanna/rdoctask'
rescue LoadError
require 'rake/rdoctask'
end
 
Rake::RDocTask.new do |rdoc|
rdoc.title = 'Haml/Sass'
rdoc.options << '--line-numbers' << '--inline-source'
rdoc.rdoc_files.include(*FileList.new('*') do |list|
list.exclude(/(^|[^.a-z])[a-z]+/)
list.exclude('TODO')
end.to_a)
rdoc.rdoc_files.include('lib/**/*.rb')
rdoc.rdoc_files.exclude('TODO')
rdoc.rdoc_files.exclude('lib/haml/buffer.rb')
rdoc.rdoc_files.exclude('lib/sass/tree/*')
rdoc.rdoc_dir = 'rdoc'
rdoc.main = 'README.rdoc'
end
 
# ----- Coverage -----
 
begin
require 'rcov/rcovtask'
 
Rcov::RcovTask.new do |t|
t.test_files = FileList['test/**/*_test.rb']
t.rcov_opts << '-x' << '"^\/"'
if ENV['NON_NATIVE']
t.rcov_opts << "--no-rcovrt"
end
t.verbose = true
end
rescue LoadError; end
 
# ----- Profiling -----
 
begin
require 'ruby-prof'
 
desc <<END
Run a profile of haml.
ENGINE=str sets the engine to be profiled. Defaults to Haml.
TIMES=n sets the number of runs. Defaults to 1000.
FILE=str sets the file to profile.
Defaults to 'standard' for Haml and 'complex' for Sass.
OUTPUT=str sets the ruby-prof output format.
Can be Flat, CallInfo, or Graph. Defaults to Flat. Defaults to Flat.
END
task :profile do
engine = (ENV['ENGINE'] || 'haml').downcase
times = (ENV['TIMES'] || '1000').to_i
file = ENV['FILE']
 
if engine == 'sass'
require 'lib/sass'
 
file = File.read("#{File.dirname(__FILE__)}/test/sass/templates/#{file || 'complex'}.sass")
result = RubyProf.profile { times.times { Sass::Engine.new(file).render } }
else
require 'lib/haml'
 
file = File.read("#{File.dirname(__FILE__)}/test/haml/templates/#{file || 'standard'}.haml")
obj = Object.new
Haml::Engine.new(file).def_method(obj, :render)
result = RubyProf.profile { times.times { obj.render } }
end
 
RubyProf.const_get("#{(ENV['OUTPUT'] || 'Flat').capitalize}Printer").new(result).print
end
rescue LoadError; end
 
# ----- Testing Multiple Rails Versions -----
 
rails_versions = [
"v2.3.0",
"v2.2.2",
"v2.1.2",
"v2.0.5"
]
 
namespace :test do
desc "Test all supported versions of rails. This takes a while."
task :rails_compatibility do
`rm -rf test/rails`
puts "Checking out rails. Please wait."
`git clone git://github.com/rails/rails.git test/rails` rescue nil
begin
rails_versions.each do |version|
Dir.chdir "test/rails" do
`git checkout #{version}`
end
puts "Testing Rails #{version}"
Rake::Task['test'].reenable
Rake::Task['test'].execute
end
ensure
`rm -rf test/rails`
end
end
end
vendor/haml-2.0.9/VERSION
1
2.0.9
vendor/haml-2.0.9/bin/css2sass
Ruby
1 2 3 4 5 6 7
#!/usr/bin/env ruby
 
require File.dirname(__FILE__) + '/../lib/haml'
require 'haml/exec'
 
opts = Haml::Exec::CSS2Sass.new(ARGV)
opts.parse!
vendor/haml-2.0.9/bin/haml
Ruby
1 2 3 4 5 6 7 8 9
#!/usr/bin/env ruby
# The command line Haml parser.
 
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
require 'haml'
require 'haml/exec'
 
opts = Haml::Exec::Haml.new(ARGV)
opts.parse!
vendor/haml-2.0.9/bin/html2haml
Ruby
1 2 3 4 5 6 7
#!/usr/bin/env ruby
 
require File.dirname(__FILE__) + '/../lib/haml'
require 'haml/exec'
 
opts = Haml::Exec::HTML2Haml.new(ARGV)
opts.parse!
vendor/haml-2.0.9/bin/sass
Ruby
1 2 3 4 5 6 7 8
#!/usr/bin/env ruby
# The command line Sass parser.
 
require File.dirname(__FILE__) + '/../lib/haml'
require 'haml/exec'
 
opts = Haml::Exec::Sass.new(ARGV)
opts.parse!
vendor/haml-2.0.9/extra/haml-mode.el
Emacs Lisp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
;;; haml-mode.el -- Major mode for editing Haml files
;;; Written by Nathan Weizenbaum
 
;;; Because Haml's indentation schema is similar
;;; to that of YAML and Python, many indentation-related
;;; functions are similar to those in yaml-mode and python-mode.
 
;;; To install, save this somewhere and add the following to your .emacs file:
;;;
;;; (add-to-list 'load-path "/path/to/haml-mode.el")
;;; (require 'haml-mode nil 't)
;;; (add-to-list 'auto-mode-alist '("\\.haml$" . haml-mode))
;;;
 
;;; Code:
 
(eval-when-compile (require 'cl))
 
;; User definable variables
 
(defgroup haml nil
"Support for the Haml template language."
:group 'languages
:prefix "haml-")
 
(defcustom haml-mode-hook nil
"Hook run when entering Haml mode."
:type 'hook
:group 'haml)
 
(defcustom haml-indent-offset 2
"Amount of offset per level of indentation."
:type 'integer
:group 'haml)
 
(defcustom haml-backspace-backdents-nesting t
"Non-nil to have `haml-electric-backspace' re-indent all code
nested beneath the backspaced line be re-indented along with the
line itself."
:type 'boolean
:group 'haml)
 
(defface haml-tab-face
'((((class color)) (:background "hotpink"))
(t (:reverse-video t)))
"Face to use for highlighting tabs in Haml files."
:group 'faces
:group 'haml)
 
(defvar haml-indent-function 'haml-indent-p
"This function should look at the current line and return true
if the next line could be nested within this line.")
 
(defvar haml-block-openers
`("^ *\\([%\\.#][^ \t]*\\)\\(\\[.*\\]\\)?\\({.*}\\)?\\(\\[.*\\]\\)?[ \t]*$"
"^ *[-=].*do[ \t]*\\(|.*|[ \t]*\\)?$"
,(concat "^ *-[ \t]*\\("
(regexp-opt '("else" "elsif" "rescue" "ensure" "when"))
"\\)")
"^ */\\(\\[.*\\]\\)?[ \t]*$"
"^ *-#"
"^ *:")
"A list of regexps that match lines of Haml that could have
text nested beneath them.")
 
;; Font lock
 
(defconst haml-font-lock-keywords
'(("^ *\\(\t\\)" 1 'haml-tab-face)
("^!!!.*" 0 font-lock-constant-face)
("\\('[^']*'\\)" 1 font-lock-string-face append)
("\\(\"[^\"]*\"\\)" 1 font-lock-string-face append)
("&?:\\w+" 0 font-lock-constant-face append)
("@[a-z0-9_]+" 0 font-lock-variable-name-face append)
("| *$" 0 font-lock-string-face)
("^[ \t]*\\(/.*\\)$" 1 font-lock-comment-face append)
("^ *\\(#[a-z0-9_]+\/?\\)" 1 font-lock-keyword-face)
("^ *\\(\\.[a-z0-9_]+\/?\\)" 1 font-lock-type-face)
("^ *\\(%[a-z0-9_]+\/?\\)" 1 font-lock-function-name-face)
("^ *\\(#[a-z0-9_]+\/?\\)" (1 font-lock-keyword-face)
("\\.[a-z0-9_]+" nil nil (0 font-lock-type-face)))
("^ *\\(\\.[a-z0-9_]+\/?\\)" (1 font-lock-type-face)
("\\.[a-z0-9_]+" nil nil (0 font-lock-type-face)))
("^ *\\(\\.[a-z0-9_]+\/?\\)" (1 font-lock-type-face)
("\\#[a-z0-9_]+" nil nil (0 font-lock-keyword-face)))
("^ *\\(%[a-z0-9_]+\/?\\)" (1 font-lock-function-name-face)
("\\.[a-z0-9_]+" nil nil (0 font-lock-type-face)))
("^ *\\(%[a-z0-9_]+\/?\\)" (1 font-lock-function-name-face)
("\\#[a-z0-9_]+" nil nil (0 font-lock-keyword-face)))
("^ *\\([~=-] .*\\)" 1 font-lock-preprocessor-face prepend)
("^ *[\\.#%a-z0-9_]+\\([~=-] .*\\)" 1 font-lock-preprocessor-face prepend)
("^ *[\\.#%a-z0-9_]+\\({[^}]+}\\)" 1 font-lock-preprocessor-face prepend)
("^ *[\\.#%a-z0-9_]+\\(\\[[^]]+\\]\\)" 1 font-lock-preprocessor-face prepend)))
 
;; Mode setup
 
(defvar haml-mode-syntax-table
(let ((table (make-syntax-table)))
(modify-syntax-entry ?: "." table)
(modify-syntax-entry ?_ "w" table)
table)
"Syntax table in use in haml-mode buffers.")
 
(defvar haml-mode-map
(let ((map (make-sparse-keymap)))
(define-key map [backspace] 'haml-electric-backspace)
(define-key map "\C-?" 'haml-electric-backspace)
(define-key map "\C-\M-f" 'haml-forward-sexp)
(define-key map "\C-\M-b" 'haml-backward-sexp)
(define-key map "\C-\M-u" 'haml-up-list)
(define-key map "\C-\M-d" 'haml-down-list)
(define-key map "\C-C\C-k" 'haml-kill-line-and-indent)
map))
 
;;;###autoload
(define-derived-mode haml-mode fundamental-mode "Haml"
"Major mode for editing Haml files.
 
\\{haml-mode-map}"
(set-syntax-table haml-mode-syntax-table)
(set (make-local-variable 'indent-line-function) 'haml-indent-line)
(set (make-local-variable 'indent-region-function) 'haml-indent-region)
(set (make-local-variable 'forward-sexp-function) 'haml-forward-sexp)
(setq indent-tabs-mode nil)
(setq font-lock-defaults '((haml-font-lock-keywords) nil t)))
 
;; Navigation
 
(defun haml-forward-through-whitespace (&optional backward)
"Move the point forward at least one line, until it reaches
either the end of the buffer or a line with no whitespace.
 
If `backward' is non-nil, move the point backward instead."
(let ((arg (if backward -1 1))
(endp (if backward 'bobp 'eobp)))
(loop do (forward-line arg)
while (and (not (funcall endp))
(looking-at "^[ \t]*$")))))
 
(defun haml-at-indent-p ()
"Returns whether or not the point is at the first
non-whitespace character in a line or whitespace preceding that
character."
(let ((opoint (point)))
(save-excursion
(back-to-indentation)
(>= (point) opoint))))
 
(defun haml-forward-sexp (&optional arg)
"Move forward across one nested expression.
With `arg', do it that many times. Negative arg -N means move
backward across N balanced expressions.
 
A sexp in Haml is defined as a line of Haml code as well as any
lines nested beneath it."
(interactive "p")
(or arg (setq arg 1))
(if (and (< arg 0) (not (haml-at-indent-p)))
(back-to-indentation)
(while (/= arg 0)
(let ((indent (current-indentation)))
(loop do (haml-forward-through-whitespace (< arg 0))
while (and (not (eobp))
(not (bobp))
(> (current-indentation) indent)))
(back-to-indentation)
(setq arg (+ arg (if (> arg 0) -1 1)))))))
 
(defun haml-backward-sexp (&optional arg)
"Move backward across one nested expression.
With ARG, do it that many times. Negative arg -N means move
forward across N balanced expressions.
 
A sexp in Haml is defined as a line of Haml code as well as any
lines nested beneath it."
(interactive "p")
(haml-forward-sexp (if arg (- arg) -1)))
 
(defun haml-up-list (&optional arg)
"Move out of one level of nesting.
With ARG, do this that many times."
(interactive "p")
(or arg (setq arg 1))
(while (> arg 0)
(let ((indent (current-indentation)))
(loop do (haml-forward-through-whitespace t)
while (and (not (bobp))
(>= (current-indentation) indent)))
(setq arg (- arg 1))))
(back-to-indentation))
 
(defun haml-down-list (&optional arg)
"Move down one level of nesting.
With ARG, do this that many times."
(interactive "p")
(or arg (setq arg 1))
(while (> arg 0)
(let ((indent (current-indentation)))
(haml-forward-through-whitespace)
(when (<= (current-indentation) indent)
(haml-forward-through-whitespace t)
(back-to-indentation)
(error "Nothing is nested beneath this line"))
(setq arg (- arg 1))))
(back-to-indentation))
 
(defun haml-mark-sexp-but-not-next-line ()
"Marks the next Haml sexp, but puts the mark at the end of the
last line of the sexp rather than the first non-whitespace
character of the next line."
(mark-sexp)
(set-mark
(save-excursion
(goto-char (mark))
(forward-line -1)
(end-of-line)
(point))))
 
;; Indentation and electric keys
 
(defun haml-indent-p ()
"Returns true if the current line can have lines nested beneath it."
(loop for opener in haml-block-openers
if (looking-at opener) return t
finally return nil))
 
(defun haml-compute-indentation ()
"Calculate the maximum sensible indentation for the current line."
(save-excursion
(beginning-of-line)
(if (bobp) 0
(haml-forward-through-whitespace t)
(+ (current-indentation)
(if (funcall haml-indent-function) haml-indent-offset
0)))))
 
(defun haml-indent-region (start end)
"Indent each nonblank line in the region.
This is done by indenting the first line based on
`haml-compute-indentation' and preserving the relative
indentation of the rest of the region.
 
If this command is used multiple times in a row, it will cycle
between possible indentations."
(save-excursion
(goto-char end)
(setq end (point-marker))
(goto-char start)
(let (this-line-column current-column
(next-line-column
(if (and (equal last-command this-command) (/= (current-indentation) 0))
(* (/ (- (current-indentation) 1) haml-indent-offset) haml-indent-offset)
(haml-compute-indentation))))
(while (< (point) end)
(setq this-line-column next-line-column
current-column (current-indentation))
;; Delete whitespace chars at beginning of line
(delete-horizontal-space)
(unless (eolp)
(setq next-line-column (save-excursion
(loop do (forward-line 1)
while (and (not (eobp)) (looking-at "^[ \t]*$")))
(+ this-line-column
(- (current-indentation) current-column))))
;; Don't indent an empty line
(unless (eolp) (indent-to this-line-column)))
(forward-line 1)))
(move-marker end nil)))
 
(defun haml-indent-line ()
"Indent the current line.
The first time this command is used, the line will be indented to the
maximum sensible indentation. Each immediately subsequent usage will
back-dent the line by `haml-indent-offset' spaces. On reaching column
0, it will cycle back to the maximum sensible indentation."
(interactive "*")
(let ((ci (current-indentation))
(cc (current-column))
(need (haml-compute-indentation)))
(save-excursion
(beginning-of-line)
(delete-horizontal-space)
(if (and (equal last-command this-command) (/= ci 0))
(indent-to (* (/ (- ci 1) haml-indent-offset) haml-indent-offset))
(indent-to need)))
(if (< (current-column) (current-indentation))
(forward-to-indentation 0))))
 
(defun haml-reindent-region-by (n)
"Add N spaces to the beginning of each line in the region.
If N is negative, will remove the spaces instead. Assumes all
lines in the region have indentation >= that of the first line."
(let ((ci (current-indentation)))
(save-excursion
(replace-regexp (concat "^" (make-string ci ? ))
(make-string (max 0 (+ ci n)) ? )
nil (point) (mark)))))
 
(defun haml-electric-backspace (arg)
"Delete characters or back-dent the current line.
If invoked following only whitespace on a line, will back-dent
the line and all nested lines to the immediately previous
multiple of `haml-indent-offset' spaces.
 
Set `haml-backspace-backdents-nesting' to nil to just back-dent
the current line."
(interactive "*p")
(if (or (/= (current-indentation) (current-column))
(bolp)
(looking-at "^[ \t]+$"))
(backward-delete-char arg)
(let ((ci (current-column)))
(beginning-of-line)
(if haml-backspace-backdents-nesting
(haml-mark-sexp-but-not-next-line)
(set-mark (save-excursion (end-of-line) (point))))
(haml-reindent-region-by (* (- arg) haml-indent-offset))
(back-to-indentation)
(pop-mark))))
 
(defun haml-kill-line-and-indent ()
"Kill the current line, and re-indent all lines nested beneath it."
(interactive)
(beginning-of-line)
(haml-mark-sexp-but-not-next-line)
(kill-line 1)
(haml-reindent-region-by (* -1 haml-indent-offset)))
 
;; Setup/Activation
 
(provide 'haml-mode)
vendor/haml-2.0.9/extra/sass-mode.el
Emacs Lisp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
;;; sass-mode.el -- Major mode for editing Sass files
;;; Written by Nathan Weizenbaum
 
;;; Because Sass's indentation schema is similar
;;; to that of YAML and Python, many indentation-related
;;; functions are similar to those in yaml-mode and python-mode.
 
;;; To install, save this somewhere and add the following to your .emacs file:
;;;
;;; (add-to-list 'load-path "/path/to/sass-mode.el")
;;; (require 'sass-mode nil 't)
;;; (add-to-list 'auto-mode-alist '("\\.sass$" . sass-mode))
;;;
 
;;; Code:
 
(require 'haml-mode)
 
;; User definable variables
 
(defgroup sass nil
"Support for the Sass template language."
:group 'languages
:prefix "sass-")
 
(defcustom sass-mode-hook nil
"Hook run when entering Sass mode."
:type 'hook
:group 'sass)
 
(defcustom sass-indent-offset 2
"Amount of offset per level of indentation."
:type 'integer
:group 'sass)
 
(defvar sass-non-block-openers
'("^ *:[^ \t]+[ \t]+[^ \t]"
"^ *[^ \t:]+[ \t]*[=:][ \t]*[^ \t]")
"A list of regexps that match lines of Sass that couldn't have
text nested beneath them.")
 
;; Font lock
 
(defconst sass-font-lock-keywords
'(("^ *\\(\t\\)" 1 'haml-tab-face)
("^@.*" 0 font-lock-constant-face)
("\\(\'[^']*'\\)" 1 font-lock-string-face append)
("\\(\"[^\"]*\"\\)" 1 font-lock-string-face append)
("\\(#[0-9a-fA-F]\\{3\\}\\{1,2\\}\\>\\)" 1 font-lock-string-face append)
("\\(:[A-Za-z-]+\\|[A-Za-z-]+:\\)" 0 font-lock-constant-face append)
("![a-z0-9_-]+" 0 font-lock-variable-name-face append)
("^ *\\(/[/*].*\\)$" 1 font-lock-comment-face append)
("\\(?:^\\|,\\) *\\(#[a-z0-9_-]+\/?\\)" 1 font-lock-keyword-face)
("\\(?:^\\|,\\) *\\(\\.[a-z0-9_-]+\/?\\)" 1 font-lock-type-face)
("\\(?:^\\|,\\) *\\(&\\|[a-z0-9_]+\/?\\)" 1 font-lock-function-name-face)
("\\([=]\\)" 0 font-lock-preprocessor-face prepend)
("\\(?:^\\|,\\) *\\(#[a-z0-9_]+\/?\\)" (1 font-lock-keyword-face)
("\\.[a-z0-9_-]+" nil nil (0 font-lock-type-face)))
("\\(?:^\\|,\\) *\\(\\.[a-z0-9_]+\/?\\)" (1 font-lock-type-face)
("\\.[a-z0-9_-]+" nil nil (0 font-lock-type-face)))
("\\(?:^\\|,\\) *\\(\\.[a-z0-9_]+\/?\\)" (1 font-lock-type-face)
("\\#[a-z0-9_-]+" nil nil (0 font-lock-keyword-face)))
("\\(?:^\\|,\\) *\\(&\\|[a-z0-9_]+\/?\\)" (1 font-lock-function-name-face)
("\\.[a-z0-9_-]+" nil nil (0 font-lock-type-face)))
("\\(?:^\\|,\\) *\\(&\\|[a-z0-9_]+\/?\\)" (1 font-lock-function-name-face)
("\\#[a-z0-9_-]+" nil nil (0 font-lock-keyword-face)))))
 
;; Constants
 
;; Mode setup
 
;;;###autoload
(define-derived-mode sass-mode haml-mode "Sass"
"Major mode for editing Sass files."
(set (make-local-variable 'haml-indent-function) 'sass-indent-p)
(set (make-local-variable 'haml-indent-offset) sass-indent-offset)
(setq font-lock-defaults '(sass-font-lock-keywords nil t)))
 
;; Indentation
 
(defun sass-indent-p ()
"Returns true if the current line can have lines nested beneath it."
(loop for opener in sass-non-block-openers
unless (looking-at opener) return t
return nil))
 
;; Setup/Activation
 
(provide 'sass-mode)
vendor/haml-2.0.9/init.rb
Ruby
1 2 3 4 5 6 7 8
begin
require File.join(File.dirname(__FILE__), 'lib', 'haml') # From here
rescue LoadError
require 'haml' # From gem
end
 
# Load Haml and Sass
Haml.init_rails(binding)
vendor/haml-2.0.9/lib/haml.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018
dir = File.dirname(__FILE__)
$LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
 
require 'haml/version'
 
# = 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 as PHP, ERB, and ASP.
# However, Haml avoids the need for explicitly coding XHTML into the template,
# because it is actually an abstract description of the XHTML,
# with some code to generate dynamic content.
#
# == Features
#
# * Whitespace active
# * Well-formatted markup
# * DRY
# * Follows CSS conventions
# * Integrates Ruby code
# * Implements Rails templates with the .haml extension
#
# == Using Haml
#
# Haml can be used in three ways:
# as a plugin for Ruby on Rails,
# as a standalone Ruby module,
# and as a command-line tool.
# The first step for all of these is to install the Haml gem:
#
# gem install haml
#
# To enable it as a Rails plugin,
# then run
#
# haml --rails path/to/rails/app
#
# Once it's installed, all view files with the ".html.haml" extension
# will be compiled using Haml.
#
# To run Haml from the command line, just use
#
# haml input.haml output.html
#
# Use <tt>haml --help</tt> for full documentation.
#
# You can access instance variables in Haml templates
# the same way you do in ERb templates.
# Helper methods are also available in Haml templates.
# For example (this example uses Rails, but the principle for Merb is the same):
#
# # file: app/controllers/movies_controller.rb
#
# class MoviesController < ApplicationController
# def index
# @title = "Teen Wolf"
# end
# end
#
# -# file: app/views/movies/index.haml
#
# #content
# .title
# %h1= @title
# = link_to 'Home', home_url
#
# may be compiled to:
#
# <div id='content'>
# <div class='title'>
# <h1>Teen Wolf</h1>
# <a href='/'>Home</a>
# </div>
# </div>
#
# === Ruby Module
#
# Haml can also be used completely separately from Rails and ActionView.
# To do this, install the gem with RubyGems:
#
# gem install haml
#
# You can then use it by including the "haml" gem in Ruby code,
# and using Haml::Engine like so:
#
# engine = Haml::Engine.new("%p Haml code!")
# engine.render #=> "<p>Haml code!</p>\n"
#
# == Characters with meaning to Haml
#
# Various characters, when placed at a certain point in a line,
# instruct Haml to render different types of things.
#
# === XHTML Tags
#
# These characters render XHTML tags.
#
# ==== %
#
#
# The percent character is placed at the beginning of a line.
# It's followed immediately by the name of an element,
# then optionally by modifiers (see below), a space,
# and text to be rendered inside the element.
# It creates an element in the form of <tt><element></element></tt>.
# For example:
#
# %one
# %two
# %three Hey there
#
# is compiled to:
#
# <one>
# <two>
# <three>Hey there</three>
# </two>
# </one>
#
# Any string is a valid element name;
# Haml will automatically generate opening and closing tags for any element.
#
# ==== {}
#
# Brackets represent a Ruby hash
# that is used for specifying the attributes of an element.
# It is literally evaluated as a Ruby hash,
# so logic will work in it and local variables may be used.
# Quote characters within the attribute
# will be replaced by appropriate escape sequences.
# The hash is placed after the tag is defined.
# For example:
#
# %head{ :name => "doc_head" }
# %script{ 'type' => "text/" + "javascript",
# :src => "javascripts/script_#{2 + 7}" }
#
# is compiled to:
#
# <head name='doc_head'>
# <script src='javascripts/script_9' type='text/javascript'>
# </script>
# </head>
#
# ===== Attribute Methods
#
# A Ruby method call that returns a hash
# can be substituted for the hash contents.
# For example, Haml::Helpers defines the following method:
#
# def html_attrs(lang = 'en-US')
# {:xmlns => "http://www.w3.org/1999/xhtml", 'xml:lang' => lang, :lang => lang}
# end
#
# This can then be used in Haml, like so:
#
# %html{html_attrs('fr-fr')}
#
# This is compiled to:
#
# <html lang='fr-fr' xml:lang='fr-fr' xmlns='http://www.w3.org/1999/xhtml'>
# </html>
#
# You can use as many such attribute methods as you want
# by separating them with commas,
# like a Ruby argument list.
# All the hashes will me merged together, from left to right.
# For example, if you defined
#
# def hash1
# {:bread => 'white', :filling => 'peanut butter and jelly'}
# end
#
# def hash2
# {:bread => 'whole wheat'}
# end
#
# then
#
# %sandwich{hash1, hash2, :delicious => true}/
#
# would compile to:
#
# <sandwich bread='whole wheat' delicious='true' filling='peanut butter and jelly' />
#
# Note that the Haml attributes list has the same syntax as a Ruby method call.
# This means that any attribute methods must come before the hash literal.
#
# ===== Boolean Attributes
#
# Some attributes, such as "checked" for <tt>input</tt> tags or "selected" for <tt>option</tt> tags,
# are "boolean" in the sense that their values don't matter -
# it only matters whether or not they're present.
# In HTML (but not XHTML), these attributes can be written as
#
# <input selected>
#
# To do this in Haml, just assign a Ruby true value to the attribute:
#
# %input{:selected => true}
#
# In XHTML, the only valid value for these attributes is the name of the attribute.
# Thus this will render in XHTML as
#
# <input selected='selected'>
#
# To set these attributes to false, simply assign them to a Ruby false value.
# In both XHTML and HTML
#
# %input{:selected => false}
#
# will just render as
#
# <input>
#
# ==== []
#
# Square brackets follow a tag definition and contain a Ruby object
# that is used to set the class and id of that tag.
# The class is set to the object's class
# (transformed to use underlines rather than camel case)
# and the id is set to the object's class, followed by its id.
# Because the id of an object is normally an obscure implementation detail,
# this is most useful for elements that represent instances of Models.
# Additionally, the second argument (if present) will be used as a prefix for
# both the id and class attributes.
# For example:
#
# # file: app/controllers/users_controller.rb
#
# def show
# @user = CrazyUser.find(15)
# end
#
# -# file: app/views/users/show.haml
#
# %div[@user, :greeting]
# %bar[290]/
# Hello!
#
# is compiled to:
#
# <div class='greeting_crazy_user' id='greeting_crazy_user_15'>
# <bar class='fixnum' id='fixnum_581' />
# Hello!
# </div>
#
# ==== /
#
# The forward slash character, when placed at the end of a tag definition,
# causes the tag to be self-closed.
# For example:
#
# %br/
# %meta{'http-equiv' => 'Content-Type', :content => 'text/html'}/
#
# is compiled to:
#
# <br />
# <meta http-equiv='Content-Type' content='text/html' />
#
# Some tags are automatically closed, as long as they have no content.
# +meta+, +img+, +link+, +script+, +br+, and +hr+ tags are closed by default.
# This list can be customized by setting the <tt>:autoclose</tt> option (see below).
# For example:
#
# %br
# %meta{'http-equiv' => 'Content-Type', :content => 'text/html'}
#
# is also compiled to:
#
# <br />
# <meta http-equiv='Content-Type' content='text/html' />
#
# ==== . and #
#
# The period and pound sign are borrowed from CSS.
# They are used as shortcuts to specify the <tt>class</tt>
# and <tt>id</tt> attributes of an element, respectively.
# Multiple class names can be specified in a similar way to CSS,
# by chaining the class names together with periods.
# They are placed immediately after the tag and before an attributes hash.
# For example:
#
# %div#things
# %span#rice Chicken Fried
# %p.beans{ :food => 'true' } The magical fruit
# %h1.class.otherclass#id La La La
#
# is compiled to:
#
# <div id='things'>
# <span id='rice'>Chicken Fried</span>
# <p class='beans' food='true'>The magical fruit</p>
# <h1 class='class otherclass' id='id'>La La La</h1>
# </div>
#
# And,
#
# #content
# .articles
# .article.title
# Doogie Howser Comes Out
# .article.date
# 2006-11-05
# .article.entry
# Neil Patrick Harris would like to dispel any rumors that he is straight
#
# is compiled to:
#
# <div id='content'>
# <div class='articles'>
# <div class='article title'>Doogie Howser Comes Out</div>
# <div class='article date'>2006-11-05</div>
# <div class='article entry'>
# Neil Patrick Harris would like to dispel any rumors that he is straight
# </div>
# </div>
# </div>
#
# ==== Implicit Div Elements
#
# Because the div element is used so often, it is the default element.
# If you only define a class and/or id using the <tt>.</tt> or <tt>#</tt> syntax,
# a div element is automatically used.
# For example:
#
# #collection
# .item
# .description What a cool item!
#
# is the same as:
#
# %div{:id => collection}
# %div{:class => 'item'}
# %div{:class => 'description'} What a cool item!
#
# and is compiled to:
#
# <div id='collection'>
# <div class='item'>
# <div class='description'>What a cool item!</div>
# </div>
# </div>
#
# ==== > and <
#
# <tt>></tt> and <tt><</tt> give you more control over the whitespace near a tag.
# <tt>></tt> will remove all whitespace surrounding a tag,
# while <tt><</tt> will remove all whitespace immediately within a tag.
# You can think of them as alligators eating the whitespace:
# <tt>></tt> faces out of the tag and eats the whitespace on the outside,
# and <tt><</tt> faces into the tag and eats the whitespace on the inside.
# They're placed at the end of a tag definition,
# after class, id, and attribute declarations
# but before <tt>/</tt> or <tt>=</tt>.
# For example:
#
# %blockquote<
# %div
# Foo!
#
# is compiled to:
#
# <blockquote><div>
# Foo!
# </div></blockquote>
#
# And:
#
# %img
# %img>
# %img
#
# is compiled to:
#
# <img /><img /><img />
#
# And:
#
# %p<= "Foo\nBar"
#
# is compiled to:
#
# <p>Foo
# Bar</p>
#
# And finally:
#
# %img
# %pre><
# foo
# bar
# %img
#
# is compiled to:
#
# <img /><pre>foo
# bar</pre><img />
#
# ==== =
#
# <tt>=</tt> is placed at the end of a tag definition,
# after class, id, and attribute declarations.
# It's just a shortcut for inserting Ruby code into an element.
# It works the same as <tt>=</tt> without a tag:
# it inserts the result of the Ruby code into the template.
# However, if the result is short enough,
# it is displayed entirely on one line.
# For example:
#
# %p= "hello"
#
# is not quite the same as:
#
# %p
# = "hello"
#
# It's compiled to:
#
# <p>hello</p>
#
# ==== ~
#
# ~ works just like =, except that it runs Haml::Helpers#find_and_preserve on its input.
# For example,
#
# ~ "Foo\n<pre>Bar\nBaz</pre>"
#
# is the same as:
#
# = find_and_preserve("Foo\n<pre>Bar\nBaz</pre>")
#
# and is compiled to:
#
# Foo
# <pre>Bar&#x000A;Baz</pre>
#
# See also Whitespace Preservation, below.
#
# === XHTML Helpers
#
# ==== No Special Character
#
# If no special character appears at the beginning of a line,
# the line is rendered as plain text.
# For example:
#
# %gee
# %whiz
# Wow this is cool!
#
# is compiled to:
#
# <gee>
# <whiz>
# Wow this is cool!
# </whiz>
# </gee>
#
# ==== !!!
#
# When describing XHTML documents with Haml,
# you can have a document type or XML prolog generated automatically
# by including the characters <tt>!!!</tt>.
# For example:
#
# !!! XML
# !!!
# %html
# %head
# %title Myspace
# %body
# %h1 I am the international space station
# %p Sign my guestbook
#
# is compiled to:
#
# <?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">
# <html>
# <head>
# <title>Myspace</title>
# </head>
# <body>
# <h1>I am the international space station</h1>
# <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">
#
# while
#
# !!! Basic
#
# is compiled to:
#
# <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
#
# and
#
# !!! Mobile
#
# is compiled to:
#
# <!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">
#
# If you're not using the UTF-8 character set for your document,
# you can specify which encoding should appear
# in the XML prolog in a similar way.
# For example:
#
# !!! XML iso-8859-1
#
# is compiled to:
#
# <?xml version='1.0' encoding='iso-8859-1' ?>
#
# ==== /
#
# The forward slash character, when placed at the beginning of a line,
# wraps all text after it in an HTML comment.
# For example:
#
# %peanutbutterjelly
# / This is the peanutbutterjelly element
# I like sandwiches!
#
# is compiled to:
#
# <peanutbutterjelly>
# <!-- This is the peanutbutterjelly element -->
# I like sandwiches!
# </peanutbutterjelly>
#
# The forward slash can also wrap indented sections of code. For example:
#
# /
# %p This doesn't render...
# %div
# %h1 Because it's commented out!
#
# is compiled to:
#
# <!--
# <p>This doesn't render...</p>
# <div>
# <h1>Because it's commented out!</h1>
# </div>
# -->
#
# You can also use Internet Explorer conditional comments
# (about)[http://www.quirksmode.org/css/condcom.html]
# by enclosing the condition in square brackets after the <tt>/</tt>.
# For example:
#
# /[if IE]
# %a{ :href => 'http://www.mozilla.com/en-US/firefox/' }
# %h1 Get Firefox
#
# is compiled to:
#
# <!--[if IE]>
# <a href='http://www.mozilla.com/en-US/firefox/'>
# <h1>Get Firefox</h1>
# </a>
# <![endif]-->
#
# ==== \
#
# The backslash character escapes the first character of a line,
# allowing use of otherwise interpreted characters as plain text.
# For example:
#
# %title
# = @title
# \- MySite
#
# is compiled to:
#
# <title>
# MyPage
# - MySite
# </title>
#
# ==== |
#
# The pipe character designates a multiline string.
# It's placed at the end of a line
# and means that all following lines that end with <tt>|</tt>
# will be evaluated as though they were on the same line.
# For example:
#
# %whoo
# %hoo I think this might get |
# pretty long so I should |
# probably make it |
# multiline so it doesn't |
# look awful. |
# %p This is short.
#
# is compiled to:
#
# <whoo>
# <hoo>
# I think this might get pretty long so I should probably make it multiline so it doesn't look awful.
# </hoo>
# <p>This is short</p>
# </whoo>
#
# ==== :
#
# The colon character designates a filter.
# This allows you to pass an indented block of text as input
# to another filtering program and add the result to the output of Haml.
# The syntax is simply a colon followed by the name of the filter.
# For example,
#
# %p
# :markdown
# Textile
# =======
#
# Hello, *World*
#
# is compiled to
#
# <p>
# <h1>Textile</h1>
#
# <p>Hello, <em>World</em></p>
# </p>
#
# Filters can have Ruby code interpolated, like with ==.
# For example,
#
# - flavor = "raspberry"
# #content
# :textile
# I *really* prefer _#{h flavor}_ jam.
#
# is compiled to
#
# <div id='content'>
# <p>I <strong>really</strong> prefer <em>raspberry</em> jam.</p>
# </div>
#
# Haml has the following filters defined:
#
# [plain] Does not parse the filtered text.
# This is useful for large blocks of text without HTML tags,
# when you don't want lines starting with <tt>.</tt> or <tt>-</tt>
# to be parsed.
#
# [javascript] Surrounds the filtered text with <script> and CDATA tags.
# Useful for including inline Javascript.
#
# [escaped] Works the same as plain, but HTML-escapes the text
# before placing it in the document.
#
# [ruby] Parses the filtered text with the normal Ruby interpreter.
# All output sent to <tt>$stdout</tt>, like with +puts+,
# is output into the Haml document.
# Not available if the <tt>suppress_eval</tt> option is set to true.
# The Ruby code is evaluated in the same context as the Haml template.
#
# [preserve] Inserts the filtered text into the template with whitespace preserved.
# <tt>preserve</tt>d blocks of text aren't indented,
# and newlines are replaced with the HTML escape code for newlines,
# to preserve nice-looking output.
# See also Whitespace Preservation, below.
#
# [erb] Parses the filtered text with ERB, like an RHTML template.
# Not available if the <tt>suppress_eval</tt> option is set to true.
# Embedded Ruby code is evaluated in the same context as the Haml template.
#
# [sass] Parses the filtered text with Sass to produce CSS output.
#
# [textile] Parses the filtered text with Textile (http://www.textism.com/tools/textile).
# Only works if RedCloth is installed.
#
# [markdown] Parses the filtered text with Markdown (http://daringfireball.net/projects/markdown).
# Only works if RDiscount, RPeg-Markdown, Maruku, or BlueCloth are installed.
#
# [maruku] Parses the filtered text with Maruku, which has some non-standard extensions to Markdown.
#
# You can also define your own filters (see Haml::Filters).
#
# === Ruby evaluators
#
# ==== =
#
# The equals character is followed by Ruby code,
# which is evaluated and the output inserted into the document as plain text.
# For example:
#
# %p
# = ['hi', 'there', 'reader!'].join " "
# = "yo"
#
# is compiled to:
#
# <p>
# hi there reader!
# yo
# </p>
#
# If the <tt>:escape_html</tt> option is set, <tt>=</tt> will sanitize any
# HTML-sensitive characters generated by the script. For example:
#
# = '<script>alert("I\'m evil!");</script>'
#
# would be compiled to
#
# &lt;script&gt;alert(&quot;I'm evil!&quot;);&lt;/script&gt;
#
# ==== -
#
# The hyphen character makes the text following it into "silent script":
# Ruby script that is evaluated, but not output.
#
# <b>It is not recommended that you use this widely;
# almost all processing code and logic should be restricted
# to the Controller, the Helper, or partials.</b>
#
# For example:
#
# - foo = "hello"
# - foo << " there"
# - foo << " you!"
# %p= foo
#
# is compiled to:
#
# <p>
# hello there you!
# </p>
#
# ==== ==
#
# Two equals characters interpolates Ruby code into plain text,
# similarly to Ruby string interpolation.
# For example,
#
# %p== This is #{h quality} cake!
#
# is the same as
#
# %p= "This is #{h quality} cake!"
#
# and might compile to
#
# <p>This is scrumptious cake!</p>
#
# Backslashes can be used to escape "#{" strings,
# but they don't act as escapes anywhere else in the string.
# For example:
#
# %p
# == \\ Look at \\#{h word} lack of backslash: \#{foo}
#
# might compile to
#
# <p>
# \\ Look at \yon lack of backslash: #{foo}
# </p>
#
# ==== &=
#
# An ampersand followed by one or two equals characters
# evaluates Ruby code just like the equals without the ampersand,
# but sanitizes any HTML-sensitive characters in the result of the code.
# For example:
#
# &= "I like cheese & crackers"
#
# compiles to
#
# I like cheese &amp; crackers
#
# If the <tt>:escape_html</tt> option is set,
# &= behaves identically to =.
#
# ==== !=
#
# An exclamation mark followed by one or two equals characters
# evaluates Ruby code just like the equals would,
# but never sanitizes the HTML.
#
# By default, the single equals doesn't sanitize HTML either.
# However, if the <tt>:escape_html</tt> option is set, = will sanitize the HTML, but != still won't.
# For example, if <tt>:escape_html</tt> is set:
#
# = "I feel <strong>!"
# != "I feel <strong>!"
#
# compiles to
#
# I feel &lt;strong&gt;!
# I feel <strong>!
#
# ===== Blocks
#
# Ruby blocks, like XHTML tags, don't need to be explicitly closed in Haml.
# Rather, they're automatically closed, based on indentation.
# A block begins whenever the indentation is increased
# after a silent script command.
# It ends when the indentation decreases
# (as long as it's not an +else+ clause or something similar).
# For example:
#
# - (42...47).each do |i|
# %p= i
# %p See, I can count!
#
# is compiled to:
#
# <p>
# 42
# </p>
# <p>
# 43
# </p>
# <p>
# 44
# </p>
# <p>
# 45
# </p>
# <p>
# 46
# </p>
#
# Another example:
#
# %p
# - case 2
# - when 1
# = "1!"
# - when 2
# = "2?"
# - when 3
# = "3."
#
# is compiled to:
#
# <p>
# 2?
# </p>
#
# ==== -#
#
# The hyphen followed immediately by the pound sign
# signifies a silent comment.
# Any text following this isn't rendered in the resulting document
# at all.
#
# For example:
#
# %p foo
# -# This is a comment
# %p bar
#
# is compiled to:
#
# <p>foo</p>
# <p>bar</p>
#
# You can also nest text beneath a silent comment.
# None of this text will be rendered.
# For example:
#
# %p foo
# -#
# This won't be displayed
# Nor will this
# %p bar
#
# is compiled to:
#
# <p>foo</p>
# <p>bar</p>
#
# == Other Useful Things
#
# === Whitespace Preservation
#
# Sometimes you don't want Haml to indent all your text.
# For example, tags like +pre+ and +textarea+ are whitespace-sensitive;
# indenting the text makes them render wrong.
#
# Haml deals with this by "preserving" newlines before they're put into the document --
# converting them to the XHTML whitespace escape code, <tt>&#x000A;</tt>.
# Then Haml won't try to re-format the indentation.
#
# Literal +textarea+ and +pre+ tags automatically preserve their content.
# Dynamically can't be caught automatically,
# and so should be passed through Haml::Helpers#find_and_preserve or the <tt>~</tt> command,
# which has the same effect (see above).
#
# Blocks of literal text can be preserved using the :preserve filter (see above).
#
# === Helpers
#
# Haml offers a bunch of helpers that are useful
# for doing stuff like preserving whitespace,
# creating nicely indented output for user-defined helpers,
# and other useful things.
# The helpers are all documented in the Haml::Helpers and Haml::Helpers::ActionViewExtensions modules.
#
# === Haml Options
#
# Options can be set by setting the <tt>Haml::Template.options</tt> hash
# in <tt>environment.rb</tt> in Rails...
#
# Haml::Template.options[:format] = :html5
#
# ...or by setting the <tt>Merb::Plugin.config[:haml]</tt> hash in <tt>init.rb</tt> in Merb...
#
# Merb::Plugin.config[:haml][:format] = :html5
#
# ...or by passing an options hash to Haml::Engine.new.
# Available options are:
#
# [<tt>:format</tt>] Determines the output format. The default is :xhtml.
# Other options are :html4 and :html5, which are
# identical to :xhtml except there are no self-closing tags,
# XML prolog is ignored and correct DOCTYPEs are generated.
#
# [<tt>:escape_html</tt>] Sets whether or not to escape HTML-sensitive characters in script.
# If this is true, = behaves like &=;
# otherwise, it behaves like !=.
# Note that if this is set, != should be used for yielding to subtemplates
# and rendering partials.
# Defaults to false.
#
# [<tt>:suppress_eval</tt>] Whether or not attribute hashes and Ruby scripts
# designated by <tt>=</tt> or <tt>~</tt> should be
# evaluated. If this is true, said scripts are
# rendered as empty strings. Defaults to false.
#
# [<tt>:attr_wrapper</tt>] The character that should wrap element attributes.
# This defaults to <tt>'</tt> (an apostrophe). Characters
# of this type within the attributes will be escaped
# (e.g. by replacing them with <tt>&apos;</tt>) if
# the character is an apostrophe or a quotation mark.
#
# [<tt>:filename</tt>] The name of the Haml file being parsed.
# This is only used as information when exceptions are raised.
# This is automatically assigned when working through ActionView,
# so it's really only useful for the user to assign
# when dealing with Haml programatically.
#
# [<tt>:line</tt>] The line offset of the Haml template being parsed.
# This is useful for inline templates,
# similar to the last argument to Kernel#eval.
#
# [<tt>:autoclose</tt>] A list of tag names that should be automatically self-closed
# if they have no content.
# Defaults to <tt>['meta', 'img', 'link', 'br', 'hr', 'input', 'area', 'param', 'col', 'base']</tt>.
#
# [<tt>:preserve</tt>] A list of tag names that should automatically have their newlines preserved
# using the Haml::Helpers#preserve helper.
# This means that any content given on the same line as the tag will be preserved.
# For example:
#
# %textarea= "Foo\nBar"
#
# compiles to:
#
# <textarea>Foo&&#x000A;Bar</textarea>
#
# Defaults to <tt>['textarea', 'pre']</tt>.
#
# See also Whitespace Preservation, above.
#
module Haml
 
extend Haml::Version
 
# A string representing the version of Haml.
# A more fine-grained representation is available from Haml.version.
VERSION = version[:string] unless defined?(Haml::VERSION)
 
# This method is called by init.rb,
# which is run by Rails on startup.
# We use it rather than putting stuff straight into init.rb
# so we can change the initialization behavior
# without modifying the file itself.
def self.init_rails(binding)
# No &method here for Rails 2.1 compatibility
%w[haml/template sass sass/plugin].each {|f| require f}
end
end
 
require 'haml/util'
require 'haml/engine'
vendor/haml-2.0.9/lib/haml/buffer.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
module Haml
# This class is used only internally. It holds the buffer of XHTML that
# is eventually output by Haml::Engine's to_html method. It's called
# from within the precompiled code, and helps reduce the amount of
# processing done within instance_eval'd code.
class Buffer
include Haml::Helpers
 
# The string that holds the compiled XHTML. This is aliased as
# _erbout for compatibility with ERB-specific code.
attr_accessor :buffer
 
# The options hash passed in from Haml::Engine.
attr_accessor :options
 
# The Buffer for the enclosing Haml document.
# This is set for partials and similar sorts of nested templates.
# It's nil at the top level (see #toplevel?).
attr_accessor :upper
 
# See #active?
attr_writer :active
 
# True if the format is XHTML
def xhtml?
not html?
end
 
# True if the format is any flavor of HTML
def html?
html4? or html5?
end
 
# True if the format is HTML4
def html4?
@options[:format] == :html4
end
 
# True if the format is HTML5
def html5?
@options[:format] == :html5
end
 
# True if this buffer is a top-level template,
# as opposed to a nested partial.
def toplevel?
upper.nil?
end
 
# True if this buffer is currently being used to render a Haml template.
# However, this returns false if a subtemplate is being rendered,
# even if it's a subtemplate of this buffer's template.
def active?
@active
end
 
# Gets the current tabulation of the document.
def tabulation
@real_tabs + @tabulation
end
 
# Sets the current tabulation of the document.
def tabulation=(val)
val = val - @real_tabs
@tabulation = val > -1 ? val : 0
end
 
# Creates a new buffer.
def initialize(upper = nil, options = {})
@active = true
@upper = upper
@options = {
:attr_wrapper => "'",
:ugly => false,
:format => :xhtml
}.merge options
@buffer = ""
@tabulation = 0
 
# The number of tabs that Engine thinks we should have
# @real_tabs + @tabulation is the number of tabs actually output
@real_tabs = 0
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, dont_tab_up = false, tab_change = 0)
if @tabulation > 0 && !@options[:ugly]
# Have to push every line in by the extra user set tabulation.
# Don't push lines with just whitespace, though,
# because that screws up precompiled indentation.
text.gsub!(/^(?!\s+$)/m, tabs)
text.sub!(tabs, '') if dont_tab_up
end
 
@buffer << text
@real_tabs += tab_change
@dont_tab_up_next_line = false
end
 
# Properly formats the output of a script that was run in the
# instance_eval.
def push_script(result, preserve_script, in_tag = false, preserve_tag = false,
escape_html = false, nuke_inner_whitespace = false)
tabulation = @real_tabs
 
result = result.to_s.rstrip
result = result.lstrip if nuke_inner_whitespace
result = html_escape(result) if escape_html
 
if preserve_tag
result = Haml::Helpers.preserve(result)
elsif preserve_script
result = Haml::Helpers.find_and_preserve(result, options[:preserve])
end
 
has_newline = result.include?("\n")
if in_tag && !nuke_inner_whitespace && (@options[:ugly] || !has_newline || preserve_tag)
@buffer << result
@real_tabs -= 1
return
end
 
@buffer << "\n" if in_tag && !nuke_inner_whitespace
 
# Precompiled tabulation may be wrong
if @tabulation > 0 && !in_tag
result = tabs + result
end
 
if has_newline && !@options[:ugly]
result = result.gsub "\n", "\n" + tabs(tabulation)
 
# Add tabulation if it wasn't precompiled
result = tabs(tabulation) + result if in_tag && !nuke_inner_whitespace
end
@buffer << "#{result}"
@buffer << "\n" unless nuke_inner_whitespace
 
if in_tag && !nuke_inner_whitespace
# We never get here if @options[:ugly] is true
@buffer << tabs(tabulation-1)
@real_tabs -= 1
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, self_closing, try_one_line, preserve_tag, escape_html, class_id,
nuke_outer_whitespace, nuke_inner_whitespace, obj_ref, content, *attributes_hashes)
tabulation = @real_tabs
 
attributes = class_id
attributes_hashes.each do |old|
self.class.merge_attrs(attributes, old.inject({}) {|h, (key, val)| h[key.to_s] = val; h})
end
self.class.merge_attrs(attributes, parse_object_ref(obj_ref)) if obj_ref
 
if self_closing && xhtml?
str = " />" + (nuke_outer_whitespace ? "" : "\n")
else
str = ">" + ((if self_closing && html?
nuke_outer_whitespace
else
try_one_line || preserve_tag || nuke_inner_whitespace
end) ? "" : "\n")
end
 
attributes = Precompiler.build_attributes(html?, @options[:attr_wrapper], attributes)
@buffer << "#{nuke_outer_whitespace || @options[:ugly] ? '' : tabs(tabulation)}<#{name}#{attributes}#{str}"
 
if content
@buffer << "#{content}</#{name}>" << (nuke_outer_whitespace ? "" : "\n")
return
end
 
@real_tabs += 1 unless self_closing || nuke_inner_whitespace
end
 
def self.merge_attrs(to, from)
if to['id'] && from['id']
to['id'] << '_' << from.delete('id')
elsif to['id'] || from['id']
from['id'] ||= to['id']
end
 
if to['class'] && from['class']
# Make sure we don't duplicate class names
from['class'] = (from['class'].split(' ') | to['class'].split(' ')).join(' ')
elsif to['class'] || from['class']
from['class'] ||= to['class']
end
 
to.merge!(from)
end
 
private
 
# Some of these methods are exposed as public class methods
# so they can be re-used in helpers.
 
@@tab_cache = {}
# Gets <tt>count</tt> tabs. Mostly for internal use.
def tabs(count = 0)
tabs = [count + @tabulation, 0].max
@@tab_cache[tabs] ||= ' ' * tabs
end
 
# Takes an array of objects and uses the class and id of the first
# one to create an attributes hash.
# The second object, if present, is used as a prefix,
# just like you can do with dom_id() and dom_class() in Rails
def parse_object_ref(ref)
prefix = ref[1]
ref = ref[0]
# Let's make sure the value isn't nil. If it is, return the default Hash.
return {} if ref.nil?
class_name = underscore(ref.class)
id = "#{class_name}_#{ref.id || 'new'}"
if prefix
class_name = "#{ prefix }_#{ class_name}"
id = "#{ prefix }_#{ id }"
end
 
{'id' => id, 'class' => class_name}
end
 
# Changes a word from camel case to underscores.
# Based on the method of the same name in Rails' Inflector,
# but copied here so it'll run properly without Rails.
def underscore(camel_cased_word)
camel_cased_word.to_s.gsub(/::/, '_').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end
end
end
vendor/haml-2.0.9/lib/haml/engine.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
require 'haml/helpers'
require 'haml/buffer'
require 'haml/precompiler'
require 'haml/filters'
require 'haml/error'
 
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 <tt>to_html</tt> to render the template. For example:
#
# template = File.read('templates/really_cool_template.haml')
# haml_engine = Haml::Engine.new(template)
# output = haml_engine.to_html
# puts output
class Engine
include Precompiler
 
# Allow reading and writing of the options hash
attr :options, true
 
# This string contains the source code that is evaluated
# to produce the Haml document.
attr :precompiled, true
 
# True if the format is XHTML
def xhtml?
not html?
end
 
# True if the format is any flavor of HTML
def html?
html4? or html5?
end
 
# True if the format is HTML4
def html4?
@options[:format] == :html4
end
 
# True if the format is HTML5
def html5?
@options[:format] == :html5
end
 
# Creates a new instace of Haml::Engine that will compile the given
# template string when <tt>render</tt> is called.
# See the Haml module documentation for available options.
#
#--
# When adding options, remember to add information about them
# to lib/haml.rb!
#++
#
def initialize(template, options = {})
@options = {
:suppress_eval => false,
:attr_wrapper => "'",
 
# Don't forget to update the docs in lib/haml.rb if you update these
:autoclose => %w[meta img link br hr input area param col base],
:preserve => %w[textarea pre],
 
:filename => '(haml)',
:line => 1,
:ugly => false,
:format => :xhtml,
:escape_html => false
}
@options.merge! options
@index = 0
 
unless [:xhtml, :html4, :html5].include?(@options[:format])
raise Haml::Error, "Invalid format #{@options[:format].inspect}"
end
 
@template = template.rstrip + "\n-#\n-#"
@to_close_stack = []
@output_tabs = 0
@template_tabs = 0
@flat_spaces = -1
@flat = false
@newlines = 0
@precompiled = ''
@merged_text = ''
@tab_change = 0
 
if @template =~ /\A(\s*\n)*[ \t]+\S/
raise SyntaxError.new("Indenting at the beginning of the document is illegal.", ($1 || "").count("\n"))
end
 
if @options[:filters]
warn <<END
DEPRECATION WARNING:
The Haml :filters option is deprecated and will be removed in version 2.2.
Filters are now automatically registered.
END
end
 
precompile
rescue Haml::Error => e
e.backtrace.unshift "#{@options[:filename]}:#{(e.line ? e.line + 1 : @index) + @options[:line] - 1}" if @index
raise
end
 
# Processes the template and returns the result as a string.
#
# +scope+ is the context in which the template is evaluated.
# If it's a Binding or Proc object,
# Haml uses it as the second argument to Kernel#eval;
# otherwise, Haml just uses its #instance_eval context.
#
# Note that Haml modifies the evaluation context
# (either the scope object or the "self" object of the scope binding).
# It extends Haml::Helpers, and various instance variables are set
# (all prefixed with "haml").
# For example:
#
# s = "foobar"
# Haml::Engine.new("%p= upcase").render(s) #=> "<p>FOOBAR</p>"
#
# # s now extends Haml::Helpers
# s.responds_to?(:html_attrs) #=> true
#
# +locals+ is a hash of local variables to make available to the template.
# For example:
#
# Haml::Engine.new("%p= foo").render(Object.new, :foo => "Hello, world!") #=> "<p>Hello, world!</p>"
#
# If a block is passed to render,
# that block is run when +yield+ is called
# within the template.
#
# Due to some Ruby quirks,
# if scope is a Binding or Proc object and a block is given,
# the evaluation context may not be quite what the user expects.
# In particular, it's equivalent to passing <tt>eval("self", scope)</tt> as scope.
# This won't have an effect in most cases,
# but if you're relying on local variables defined in the context of scope,
# they won't work.
def render(scope = Object.new, locals = {}, &block)
buffer = Haml::Buffer.new(scope.instance_variable_get('@haml_buffer'), options_for_buffer)
 
if scope.is_a?(Binding) || scope.is_a?(Proc)
scope_object = eval("self", scope)
scope = scope_object.instance_eval{binding} if block_given?
else
scope_object = scope
scope = scope_object.instance_eval{binding}
end
 
set_locals(locals.merge(:_hamlout => buffer, :_erbout => buffer.buffer), scope, scope_object)
 
scope_object.instance_eval do
extend Haml::Helpers
@haml_buffer = buffer
end
 
eval(@precompiled, scope, @options[:filename], @options[:line])
 
# Get rid of the current buffer
scope_object.instance_eval do
@haml_buffer = buffer.upper
end
 
buffer.buffer
end
alias_method :to_html, :render
 
# Returns a proc that, when called,
# renders the template and returns the result as a string.
#
# +scope+ works the same as it does for render.
#
# The first argument of the returned proc is a hash of local variable names to values.
# However, due to an unfortunate Ruby quirk,
# the local variables which can be assigned must be pre-declared.
# This is done with the +local_names+ argument.
# For example:
#
# # This works
# Haml::Engine.new("%p= foo").render_proc(Object.new, :foo).call :foo => "Hello!"
# #=> "<p>Hello!</p>"
#
# # This doesn't
# Haml::Engine.new("%p= foo").render_proc.call :foo => "Hello!"
# #=> NameError: undefined local variable or method `foo'
#
# The proc doesn't take a block;
# any yields in the template will fail.
def render_proc(scope = Object.new, *local_names)
if scope.is_a?(Binding) || scope.is_a?(Proc)
scope_object = eval("self", scope)
else
scope_object = scope
scope = scope_object.instance_eval{binding}
end
 
eval("Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {};" +
precompiled_with_ambles(local_names) + "}\n", scope, @options[:filename], @options[:line])
end
 
# Defines a method on +object+
# with the given name
# that renders the template and returns the result as a string.
#
# If +object+ is a class or module,
# the method will instead by defined as an instance method.
# For example:
#
# t = Time.now
# Haml::Engine.new("%p\n Today's date is\n .date= self.to_s").def_method(t, :render)
# t.render #=> "<p>\n Today's date is\n <div class='date'>Fri Nov 23 18:28:29 -0800 2007</div>\n</p>\n"
#
# Haml::Engine.new(".upcased= upcase").def_method(String, :upcased_div)
# "foobar".upcased_div #=> "<div class='upcased'>FOOBAR</div>\n"
#
# The first argument of the defined method is a hash of local variable names to values.
# However, due to an unfortunate Ruby quirk,
# the local variables which can be assigned must be pre-declared.
# This is done with the +local_names+ argument.
# For example:
#
# # This works
# obj = Object.new
# Haml::Engine.new("%p= foo").def_method(obj, :render, :foo)
# obj.render(:foo => "Hello!") #=> "<p>Hello!</p>"
#
# # This doesn't
# obj = Object.new
# Haml::Engine.new("%p= foo").def_method(obj, :render)
# obj.render(:foo => "Hello!") #=> NameError: undefined local variable or method `foo'
#
# Note that Haml modifies the evaluation context
# (either the scope object or the "self" object of the scope binding).
# It extends Haml::Helpers, and various instance variables are set
# (all prefixed with "haml").
def def_method(object, name, *local_names)
method = object.is_a?(Module) ? :module_eval : :instance_eval
 
object.send(method, "def #{name}(_haml_locals = {}); #{precompiled_with_ambles(local_names)}; end",
@options[:filename], @options[:line])
end
 
private
 
def set_locals(locals, scope, scope_object)
scope_object.send(:instance_variable_set, '@_haml_locals', locals)
set_locals = locals.keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n")
eval(set_locals, scope)
end
 
# Returns a hash of options that Haml::Buffer cares about.
# This should remain loadable from #inspect.
def options_for_buffer
{
:autoclose => @options[:autoclose],
:preserve => @options[:preserve],
:attr_wrapper => @options[:attr_wrapper],
:ugly => @options[:ugly],
:format => @options[:format]
}
end
end
end
vendor/haml-2.0.9/lib/haml/error.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
module Haml
# An exception raised by Haml code.
class Error < StandardError
# :stopdoc:
 
# By default, an error is taken to refer to the line of the template
# that was being processed when the exception was raised.
# However, if line is non-nil, it + 1 is used instead.
attr_reader :line
 
def initialize(message = nil, line = nil)
super(message)
@line = line
end
# :startdoc:
end
 
# SyntaxError is the type of exception raised when Haml encounters an
# ill-formatted document.
# It's not particularly interesting, except in that it includes Haml::Error.
class SyntaxError < Haml::Error; end
end
vendor/haml-2.0.9/lib/haml/exec.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
require 'optparse'
require 'fileutils'
 
module Haml
# This module contains code for working with the
# haml, sass, and haml2html executables,
# such as command-line parsing stuff.
# It shouldn't need to be invoked by client code.
module Exec # :nodoc:
# A class that encapsulates the executable code
# for all three executables.
class Generic # :nodoc:
def initialize(args)
@args = args
@options = {}
end
 
def parse!
begin
@opts = OptionParser.new(&method(:set_opts))
@opts.parse!(@args)
 
process_result
 
@options
rescue Exception => e
raise e if @options[:trace] || e.is_a?(SystemExit)
 
$stderr.puts e.message
exit 1
end
exit 0
end
 
def to_s
@opts.to_s
end
 
protected
 
def get_line(exception)
# SyntaxErrors have weird line reporting
# when there's trailing whitespace,
# which there is for Haml documents.
return exception.message.scan(/:(\d+)/).first.first if exception.is_a?(::SyntaxError)
exception.backtrace[0].scan(/:(\d+)/).first.first
end
 
private
 
def set_opts(opts)
opts.on('-s', '--stdin', :NONE, 'Read input from standard input instead of an input file') do
@options[:input] = $stdin
end
 
opts.on('--trace', :NONE, 'Show a full traceback on error') do
@options[:trace] = true
end
 
opts.on_tail("-?", "-h", "--help", "Show this message") do
puts opts
exit
end
 
opts.on_tail("-v", "--version", "Print version") do
puts("Haml #{::Haml.version[:string]}")
exit
end
end
 
def process_result
input, output = @options[:input], @options[:output]
input_file, output_file = if input
[nil, open_file(ARGV[0], 'w')]
else
[open_file(ARGV[0]), open_file(ARGV[1], 'w')]
end
 
input ||= input_file
output ||= output_file
input ||= $stdin
output ||= $stdout
 
@options[:input], @options[:output] = input, output
end
 
def open_file(filename, flag = 'r')
return if filename.nil?
File.open(filename, flag)
end
end
 
# A class encapsulating the executable functionality
# specific to Haml and Sass.
class HamlSass < Generic # :nodoc:
def initialize(args)
super
@options[:for_engine] = {}
end
 
private
 
def set_opts(opts)
opts.banner = <<END
Usage: #{@name.downcase} [options] [INPUT] [OUTPUT]
 
Description:
Uses the #{@name} engine to parse the specified template
and outputs the result to the specified file.
 
Options:
END
 
opts.on('--rails RAILS_DIR', "Install Haml and Sass from the Gem to a Rails project") do |dir|
original_dir = dir
 
dir = File.join(dir, 'vendor', 'plugins')
 
unless File.exists?(dir)
puts "Directory #{dir} doesn't exist"
exit
end
 
dir = File.join(dir, 'haml')
 
if File.exists?(dir)
print "Directory #{dir} already exists, overwrite [y/N]? "
exit if gets !~ /y/i
FileUtils.rm_rf(dir)
end
 
begin
Dir.mkdir(dir)
rescue SystemCallError
puts "Cannot create #{dir}"
exit
end
 
File.open(File.join(dir, 'init.rb'), 'w') do |file|
file.puts "require 'rubygems'"
file << File.read(File.dirname(__FILE__) + "/../../init.rb")
end
 
puts "Haml plugin added to #{original_dir}"
exit
end
 
opts.on('-c', '--check', "Just check syntax, don't evaluate.") do
require 'stringio'
@options[:check_syntax] = true
@options[:output] = StringIO.new
end
 
super
end
 
def process_result
super
require File.dirname(__FILE__) + "/../#{@name.downcase}"
end
end
 
# A class encapsulating executable functionality
# specific to Sass.
class Sass < HamlSass # :nodoc:
def initialize(args)
super
@name = "Sass"
end
 
def set_opts(opts)
super
 
opts.on('-t', '--style NAME',
'Output style. Can be nested (default), compact, compressed, or expanded.') do |name|
@options[:for_engine][:style] = name.to_sym
end
end
 
def process_result
super
input = @options[:input]
output = @options[:output]
 
template = input.read()
input.close() if input.is_a? File
 
begin
# We don't need to do any special handling of @options[:check_syntax] here,
# because the Sass syntax checking happens alongside evaluation
# and evaluation doesn't actually evaluate any code anyway.
result = ::Sass::Engine.new(template, @options[:for_engine]).render
rescue ::Sass::SyntaxError => e
raise e if @options[:trace]
raise "Syntax error on line #{get_line e}: #{e.message}"
end
 
output.write(result)
output.close() if output.is_a? File
end
end
 
# A class encapsulating executable functionality
# specific to Haml.
class Haml < HamlSass # :nodoc:
def initialize(args)
super
@name = "Haml"
@options[:requires] = []
@options[:load_paths] = []
end
 
def set_opts(opts)
super
 
opts.on('-t', '--style NAME',
'Output style. Can be indented (default) or ugly.') do |name|
@options[:for_engine][:ugly] = true if name.to_sym == :ugly
end
 
opts.on('-f', '--format NAME',
'Output format. Can be xhtml (default), html4, or html5.') do |name|
@options[:for_engine][:format] = name.to_sym
end
 
opts.on('-e', '--escape-html',
'Escape HTML characters (like ampersands and angle brackets) by default.') do
@options[:for_engine][:escape_html] = true
end
 
opts.on('-r', '--require FILE', "Same as 'ruby -r'.") do |file|
@options[:requires] << file
end
 
opts.on('-I', '--load-path PATH', "Same as 'ruby -I'.") do |path|
@options[:load_paths] << path
end
 
opts.on('--debug', "Print out the precompiled Ruby source.") do
@options[:debug] = true
end
end
 
def process_result
super
input = @options[:input]
output = @options[:output]
 
template = input.read()
input.close() if input.is_a? File
 
begin
engine = ::Haml::Engine.new(template, @options[:for_engine])
if @options[:check_syntax]
puts "Syntax OK"
return
end
 
@options[:load_paths].each {|p| $LOAD_PATH << p}
@options[:requires].each {|f| require f}
 
if @options[:debug]
puts engine.precompiled
puts '=' * 100
end
 
result = engine.to_html
rescue Exception => e
raise e if @options[:trace]
 
case e
when ::Haml::SyntaxError; raise "Syntax error on line #{get_line e}: #{e.message}"
when ::Haml::Error; raise "Haml error on line #{get_line e}: #{e.message}"
else raise "Exception on line #{get_line e}: #{e.message}\n Use --trace for backtrace."
end
end
 
output.write(result)
output.close() if output.is_a? File
end
end
 
# A class encapsulating executable functionality
# specific to the html2haml executable.
class HTML2Haml < Generic # :nodoc:
def initialize(args)
super
 
@module_opts = {}
 
begin
require 'haml/html'
rescue LoadError => err
dep = err.message.scan(/^no such file to load -- (.*)/)[0]
puts "Required dependency #{dep} not found!"
exit 1
end
end
 
def set_opts(opts)
opts.banner = <<END
Usage: html2haml [options] [INPUT] [OUTPUT]
 
Description: Transforms an HTML file into corresponding Haml code.
 
Options:
END
 
opts.on('-r', '--rhtml', 'Parse RHTML tags.') do
@module_opts[:rhtml] = true
end
 
opts.on('--no-rhtml', "Don't parse RHTML tags.") do
@options[:no_rhtml] = true
end
 
opts.on('-x', '--xhtml', 'Parse the input using the more strict XHTML parser.') do
@module_opts[:xhtml] = true
end
 
super
end
 
def process_result
super
 
input = @options[:input]
output = @options[:output]
 
@module_opts[:rhtml] ||= input.respond_to?(:path) && input.path =~ /\.(rhtml|erb)$/
@module_opts[:rhtml] &&= @options[:no_rhtml] != false
 
output.write(::Haml::HTML.new(input, @module_opts).render)
end
end
 
# A class encapsulating executable functionality
# specific to the css2sass executable.
class CSS2Sass < Generic # :nodoc:
def initialize(args)
super
 
@module_opts = {}
 
require 'sass/css'
end
 
def set_opts(opts)
opts.banner = <<END
Usage: css2sass [options] [INPUT] [OUTPUT]
 
Description: Transforms a CSS file into corresponding Sass code.
 
Options:
END
 
opts.on('-a', '--alternate', 'Output using alternative Sass syntax (margin: 1px)') do
@module_opts[:alternate] = true
end
 
super
end
 
def process_result
super
 
input = @options[:input]
output = @options[:output]
 
output.write(::Sass::CSS.new(input, @module_opts).render)
end
end
end
end
vendor/haml-2.0.9/lib/haml/filters.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
module Haml
# The module containing the default filters,
# as well as the base module,
# Haml::Filters::Base.
module Filters
# Returns a hash of defined filters.
def self.defined
@defined ||= {}
end
 
# The base module for Haml filters.
# User-defined filters should be modules including this module.
#
# A user-defined filter should override either Base#render or Base #compile.
# Base#render is the most common.
# It takes a string, the filter source,
# and returns another string,
# the result of the filter.
# For example:
#
# module Haml::Filters::Sass
# include Haml::Filters::Base
#
# def render(text)
# ::Sass::Engine.new(text).render
# end
# end
#
# For details on overriding #compile, see its documentation.
#
module Base
def self.included(base) # :nodoc:
Filters.defined[base.name.split("::").last.downcase] = base
base.extend(base)
base.instance_variable_set "@lazy_requires", nil
end
 
# Takes a string, the source text that should be passed to the filter,
# and returns the string resulting from running the filter on <tt>text</tt>.
#
# This should be overridden in most individual filter modules
# to render text with the given filter.
# If compile is overridden, however, render doesn't need to be.
def render(text)
raise Error.new("#{self.inspect}#render not defined!")
end
 
# Same as render, but takes the Haml options hash as well.
# It's only safe to rely on options made available in Haml::Engine#options_for_buffer.
def render_with_options(text, options)
render(text)
end
 
def internal_compile(*args) # :nodoc:
resolve_lazy_requires
compile(*args)
end
 
# compile should be overridden when a filter needs to have access
# to the Haml evaluation context.
# Rather than applying a filter to a string at compile-time,
# compile uses the Haml::Precompiler instance to compile the string to Ruby code
# that will be executed in the context of the active Haml template.
#
# Warning: the Haml::Precompiler interface is neither well-documented
# nor guaranteed to be stable.
# If you want to make use of it,
# you'll probably need to look at the source code
# and should test your filter when upgrading to new Haml versions.
def compile(precompiler, text)
resolve_lazy_requires
filter = self
precompiler.instance_eval do
if contains_interpolation?(text)
return if options[:suppress_eval]
 
push_script(<<RUBY, false)
find_and_preserve(#{filter.inspect}.render_with_options(#{unescape_interpolation(text)}, _hamlout.options))
RUBY
return
end
 
rendered = Haml::Helpers::find_and_preserve(filter.render_with_options(text, precompiler.options), precompiler.options[:preserve])
 
if !options[:ugly]
push_text(rendered.rstrip.gsub("\n", "\n#{' ' * @output_tabs}"))
else
push_text(rendered.rstrip)
end
end
end
 
# This becomes a class method of modules that include Base.
# It allows the module to specify one or more Ruby files
# that Haml should try to require when compiling the filter.
#
# The first file specified is tried first,
# then the second, etc.
# If none are found, the compilation throws an exception.
#
# For example:
#
# module Haml::Filters::Markdown
# lazy_require 'rdiscount', 'peg_markdown', 'maruku', 'bluecloth'
#
# ...
# end
#
def lazy_require(*reqs)
@lazy_requires = reqs
end
 
private
 
def resolve_lazy_requires
return unless @lazy_requires
 
@lazy_requires[0...-1].each do |req|
begin
@required = req
require @required
return
rescue LoadError; end # RCov doesn't see this, but it is run
end
 
begin
@required = @lazy_requires[-1]
require @required
rescue LoadError => e
classname = self.name.match(/\w+$/)[0]
 
if @lazy_requires.size == 1
raise Error.new("Can't run #{classname} filter; required file '#{@lazy_requires.first}' not found")
else
raise Error.new("Can't run #{classname} filter; required #{@lazy_requires.map { |r| "'#{r}'" }.join(' or ')}, but none were found")
end
end
end
end
end
end
 
# :stopdoc:
 
begin
require 'rubygems'
rescue LoadError; end
 
module Haml
module Filters
module Plain
include Base
 
def render(text); text; end
end
 
module Javascript
include Base
 
def render_with_options(text, options)
<<END
<script type=#{options[:attr_wrapper]}text/javascript#{options[:attr_wrapper]}>
//<![CDATA[
#{text.rstrip.gsub("\n", "\n ")}
//]]>
</script>
END
end
end
 
module Cdata
include Base
 
def render(text)
"<![CDATA[#{("\n" + text).rstrip.gsub("\n", "\n ")}\n]]>"
end
end
 
module Escaped
include Base
 
def render(text)
Haml::Helpers.html_escape text
end
end
 
module Ruby
include Base
lazy_require 'stringio'
 
def compile(precompiler, text)
return if precompiler.options[:suppress_eval]
precompiler.instance_eval do
push_silent <<-FIRST.gsub("\n", ';') + text + <<-LAST.gsub("\n", ';')
_haml_old_stdout = $stdout
$stdout = StringIO.new(_hamlout.buffer, 'a')
FIRST
_haml_old_stdout, $stdout = $stdout, _haml_old_stdout
_haml_old_stdout.close
LAST
end
end
end
 
module Preserve
include Base
 
def render(text)
Haml::Helpers.preserve text
end
end
 
module Sass
include Base
lazy_require 'sass/plugin'
 
def render(text)
::Sass::Engine.new(text, ::Sass::Plugin.engine_options).render
end
end
 
module ERB
include Base
lazy_require 'erb'
 
def compile(precompiler, text)
return if precompiler.options[:suppress_eval]
src = ::ERB.new(text).src.sub(/^#coding:.*?\n/, '').
sub(/^_erbout = '';/, "").gsub("\n", ';')
precompiler.send(:push_silent, src)
end
end
 
module Textile
include Base
lazy_require 'redcloth'
 
def render(text)
::RedCloth.new(text).to_html(:textile)
end
end
RedCloth = Textile
Filters.defined['redcloth'] = RedCloth
 
# Uses BlueCloth or RedCloth to provide only Markdown (not Textile) parsing
module Markdown
include Base
lazy_require 'rdiscount', 'peg_markdown', 'maruku', 'bluecloth'
 
def render(text)
engine = case @required
when 'rdiscount'
::RDiscount
when 'peg_markdown'
::PEGMarkdown
when 'maruku'
::Maruku
when 'bluecloth'
::BlueCloth
end
engine.new(text).to_html
end
end
 
module Maruku
include Base
lazy_require 'maruku'
 
def render(text)
::Maruku.new(text).to_html
end
end
end
end
 
# :startdoc:
vendor/haml-2.0.9/lib/haml/helpers.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357