Skip to content
Browse files

Generate ERB docs for war. Other docs improvements.

  • Loading branch information...
1 parent 4d07e91 commit 7999d410b9d9ce36779a47e190f2a1d212b646ff @AE9RB committed Feb 20, 2011
Showing with 2,274 additions and 12 deletions.
  1. +1 −0 .gitignore
  2. +2 −0 .yardopts
  3. +18 −9 Rakefile
  4. +2 −3 lib/closure.rb
  5. +1,349 −0 scripts/docs/HAML_REFERENCE.md
  6. +902 −0 scripts/docs/erb.rb
View
1 .gitignore
@@ -6,5 +6,6 @@ tmp/*
scripts/docs/closure/*
scripts/docs/haml/*
scripts/docs/rack/*
+scripts/docs/erb/*
closure-library/closure/bin/*.pyc
closure-library/closure/bin/build/*.pyc
View
2 .yardopts
@@ -1,3 +1,5 @@
+--default-return ""
+--hide-void-return
--no-private
-
LICENSE
View
27 Rakefile
@@ -8,7 +8,7 @@ require 'yard'
# All docs are distributed with the war
# Only closure is packaged with the gem
-DOCS_GEMS = %w{closure rack haml}
+DOCS = %w{closure erb rack haml}
# These versions are important for war packaging.
# Gem users are free to mix and match any sensible versions.
@@ -35,6 +35,7 @@ end
desc 'Start the Closure Script welcome server'
task 'welcome' do
mkdir_p 'tmp' if !File.exist?('tmp')
+ rm Dir.glob 'tmp/*'
chdir 'tmp'
require 'rack'
print "Closure Script Welcome Server is running\n"
@@ -140,7 +141,7 @@ task 'war' do
dir = war_config.autodeploy_dir
mkdir_p dir if !File.exist?(dir)
# ensure all docs were built
- DOCS_GEMS.each do |gem_name|
+ DOCS.each do |gem_name|
unless File.exists? "scripts/docs/#{gem_name}/index.html"
print "ERROR: Docs for #{gem_name} not built.\n"
exit 1
@@ -167,21 +168,29 @@ end
# DOCS
-DOCS_GEMS.each do |gem_name|
- if gem_name == 'closure'
- spec = nil
+DOCS.each do |gem_name|
+ if %w{closure}.include? gem_name
+ base_path = '.'
+ elsif %w{erb}.include? gem_name
+ # Where yard won't magically find the wrong README
+ base_path = 'scripts/docs'
else
spec = Gem.loaded_specs[gem_name]
unless spec
print "ERROR: Gem #{gem_name} not loaded."
exit 1
end
+ base_path = spec.full_gem_path
end
- #TODO we can hijack the --readme
if gem_name == 'rack'
extra = '- SPEC'
+ elsif gem_name == 'erb'
+ extra = '--default-return "" --hide-void-return --title ERB --no-yardopts erb.rb'
elsif gem_name == 'haml'
- extra = '- MIT-LICENSE'
+ # Haml ships gem with incomplete docs
+ # https://github.com/nex3/haml/issues/351
+ haml_ref_file = File.expand_path("scripts/docs/HAML_REFERENCE.md")
+ extra = "- MIT-LICENSE #{haml_ref_file}"
else
extra = ''
end
@@ -192,13 +201,13 @@ DOCS_GEMS.each do |gem_name|
out_dir = File.expand_path("scripts/docs/#{gem_name}")
rm_rf out_dir
save_dir = Dir.getwd
- Dir.chdir(spec.full_gem_path) if spec
+ Dir.chdir(base_path)
`yardoc --db #{db_dir} --output-dir #{out_dir} #{extra}`
Dir.chdir save_dir
rm_rf db_dir # cleanup
end
end
desc 'Generate all documentation'
-task 'docs' => DOCS_GEMS.collect {|s| "docs:#{s}"}
+task 'docs' => DOCS.collect {|s| "docs:#{s}"}
View
5 lib/closure.rb
@@ -19,7 +19,6 @@
# middleware into a framework like Rails, or adapted to anything with a rack environment.
# @example config.ru
# #\ -p 8080 -E none
-# require 'rubygems'
# require 'closure'
# Closure.add_source :goog, '/goog'
# Closure.add_source './src/myapp', '/myapp'
@@ -70,8 +69,8 @@ def self.base_path
# @example
# Closure.add_source :goog, '/goog'
# Closure.add_source './myapp', '/myapp'
- # @overload script(path, directory)
- # @overload script(path, built_in)
+ # @overload add_source(directory, path=nil)
+ # @overload add_source(built_in, path=nil)
# @param (String) path http server mount point.
# @param (String) directory Where the scripts are in the filesystem.
# @param (Symbol) built_in
View
1,349 scripts/docs/HAML_REFERENCE.md
@@ -0,0 +1,1349 @@
+# 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 command-line tool,
+as a plugin for Ruby on Rails,
+and as a standalone Ruby module.
+The first step for all of these is to install the Haml gem:
+
+ gem install haml
+
+To run Haml from the command line, just use
+
+ haml input.haml output.html
+
+Use `haml --help` for full documentation.
+
+### Rails/Merb Plugin {#plugin}
+
+To enable Haml in Rails versions before Rails 3,
+add the following line to `environment.rb`:
+
+ config.gem "haml"
+
+For Rails 3, instead add the following line to the Gemfile:
+
+ gem "haml"
+
+Once it's installed, all view files with the `".html.haml"` extension
+will be compiled using Haml.
+Haml is enabled by default in Merb.
+
+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>
+
+#### Rails XSS Protection
+
+Haml supports Rails' XSS protection scheme,
+which was introduced in Rails 2.3.5+ and is enabled by default in 3.0.0+.
+If it's enabled, Haml's [`:escape_html`](#escape_html-option)
+option is set to `true` by default -
+like in ERB, all strings printed to a Haml template are escaped by default.
+Also like ERB, strings marked as HTML safe are not escaped.
+Haml also has [its own syntax for printing a raw string to the template](#unescaping_html).
+
+If the `:escape_html` option is set to false when XSS protection is enabled,
+Haml doesn't escape Ruby strings by default.
+However, if a string marked HTML-safe is passed to [Haml's escaping syntax](#escaping_html),
+it won't be escaped.
+
+Finally, all the {file:Haml/Helpers.html Haml helpers} that return strings
+that are known to be HTML safe are marked as such.
+In addition, string input is escaped unless it's HTML safe.
+
+### 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"
+
+### Options
+
+Options can be set by setting the {Haml::Template#options Haml::Template.options} hash
+in `environment.rb` in Rails...
+
+ Haml::Template.options[:format] = :html5
+
+...or by setting the `Merb::Plugin.config[:haml]` hash in `init.rb` in Merb...
+
+ Merb::Plugin.config[:haml][:format] = :html5
+
+...or by passing an options hash to {Haml::Engine#initialize}.
+Available options are:
+
+{#format-option} `:format`
+: Determines the output format. Normally the default is `:xhtml`,
+ although under Rails 3 it's `:html5`, since that's the Rails 3's default format.
+ Other options are `:html4` and `:html5`, which are
+ identical to `:xhtml` except there are no self-closing tags,
+ the XML prolog is ignored and correct DOCTYPEs are generated.
+
+{#escape_html-option} `:escape_html`
+: Sets whether or not to escape HTML-sensitive characters in script.
+ If this is true, `=` behaves like [`&=`](#escaping_html);
+ otherwise, it behaves like [`!=`](#unescaping_html).
+ Note that if this is set, `!=` should be used for yielding to subtemplates
+ and rendering partials.
+ See also [Escaping HTML](#escaping_html) and [Unescaping HTML](#unescaping_html)
+ Defaults to false.
+
+{#escape_attrs-option} `:escape_attrs`
+: Sets whether or not to escape HTML-sensitive characters in attributes.
+ If this is true, all HTML-sensitive characters in attributes are escaped.
+ If it's set to false, no HTML-sensitive characters in attributes are escaped.
+ If it's set to `:once`, existing HTML escape sequences are preserved,
+ but other HTML-sensitive characters are escaped.
+ Defaults to `:once`.
+
+{#ugly-option} `:ugly`
+: If set to `true`, Haml makes no attempt to properly
+ indent or format the HTML output.
+ This significantly improves rendering performance
+ but makes viewing the source unpleasant.
+ Defaults to `true` in Rails production mode, and `false`
+ everywhere else.
+
+{#suppress_eval-option} `:suppress_eval`
+: Whether or not attribute hashes and Ruby scripts
+ designated by `=` or `~` should be
+ evaluated. If this is `true`, said scripts are
+ rendered as empty strings. Defaults to `false`.
+
+{#attr_wrapper-option} `:attr_wrapper`
+: The character that should wrap element attributes.
+ This defaults to `'` (an apostrophe). Characters
+ of this type within the attributes will be escaped
+ (e.g. by replacing them with `&apos;`) if
+ the character is an apostrophe or a quotation mark.
+
+{#filename-option} `:filename`
+: 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.
+
+{#line-option} `:line`
+: The line offset of the Haml template being parsed.
+ This is useful for inline templates,
+ similar to the last argument to `Kernel#eval`.
+
+{#autoclose-option} `:autoclose`
+: A list of tag names that should be automatically self-closed
+ if they have no content.
+ This can also contain regular expressions that match tag names
+ (or any object which responds to `#===`).
+ Defaults to `['meta', 'img', 'link', 'br', 'hr', 'input', 'area', 'param', 'col', 'base']`.
+
+{#preserve-option} `:preserve`
+: 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 `['textarea', 'pre']`.
+ See also [Whitespace Preservation](#whitespace_preservation).
+
+{#encoding-option} `:encoding`
+: The encoding to use for the HTML output.
+ Only available in Ruby 1.9 or higher.
+ This can be a string or an `Encoding` Object.
+ Note that Haml **does not** automatically re-encode Ruby values;
+ any strings coming from outside the application should be converted
+ before being passed into the Haml template.
+ Defaults to `Encoding.default_internal`; if that's not set,
+ defaults to the encoding of the Haml template;
+ if that's `us-ascii`, defaults to `"utf-8"`.
+ <br/><br/> <!-- There's no better way to do a paragraph break in a dl in Maruku -->
+ Many Ruby database drivers are not yet Ruby 1.9 compatible;
+ in particular, they return strings marked as ASCII-encoded
+ even when those strings contain non-ASCII characters (such as UTF-8).
+ **This will cause encoding errors** if the Haml encoding isn't set to `"ascii-8bit"`.
+ To solve this, either call `#force_encoding` on all the strings returned from the database,
+ set `:encoding` to `"ascii-8bit"`, or try to get the authors of the database drivers
+ to make them Ruby 1.9 compatible.
+
+### Encodings
+
+When using Ruby 1.9 or later,
+Haml supports the same sorts of encoding-declaration comments that Ruby does.
+Although both Ruby and Haml support several different styles,
+the easiest it just to add `-# coding: encoding-name`
+at the beginning of the Haml template
+(it must come before all other lines).
+This will tell Haml that the template is encoded using the named encoding.
+
+By default, the HTML generated by Haml has the same encoding as the Haml template.
+However, if `Encoding.default_internal` is set, Haml will attempt to use that instead.
+In addition, the [`:encoding` option](#encoding-option) can be used
+to specify an output encoding manually.
+
+Note that, like Ruby, Haml does not support templates encoded in UTF-16 or UTF-32,
+since these encodings are not compatible with ASCII.
+It is possible to use these as the output encoding, though.
+
+## Plain Text
+
+A substantial portion of any HTML document is its content,
+which is plain old text.
+Any Haml line that's not interpreted as something else
+is taken to be plain text, and passed through unmodified.
+For example:
+
+ %gee
+ %whiz
+ Wow this is cool!
+
+is compiled to:
+
+ <gee>
+ <whiz>
+ Wow this is cool!
+ </whiz>
+ </gee>
+
+Note that HTML tags are passed through unmodified as well.
+If you have some HTML you don't want to convert to Haml,
+or you're converting a file line-by-line,
+you can just include it as-is.
+For example:
+
+ %p
+ <div id="blah">Blah!</div>
+
+is compiled to:
+
+ <p>
+ <div id="blah">Blah!</div>
+ </p>
+
+### Escaping: `\`
+
+The backslash character escapes the first character of a line,
+allowing use of otherwise interpreted characters as plain text.
+For example:
+
+ %title
+ = @title
+ \= @title
+
+is compiled to:
+
+ <title>
+ MyPage
+ = @title
+ </title>
+
+## HTML Elements
+
+
+### Element Name: `%`
+
+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 `<element></element>`.
+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.
+
+### Attributes: `{}` or `()` {#attributes}
+
+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:
+
+ %html{:xmlns => "http://www.w3.org/1999/xhtml", "xml:lang" => "en", :lang => "en"}
+
+is compiled to:
+
+ <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'></html>
+
+Attribute hashes can also be stretched out over multiple lines
+to accommodate many attributes.
+However, newlines may only be placed immediately after commas.
+For example:
+
+ %script{:type => "text/javascript",
+ :src => "javascripts/script_#{2 + 7}"}
+
+is compiled to:
+
+ <script src='javascripts/script_9' type='text/javascript'></script>
+
+#### `:class` and `:id` Attributes
+{#class-and-id-attributes}
+
+The `:class` and `:id` attributes can also be specified as a Ruby array
+whose elements will be joined together.
+A `:class` array is joined with `" "`
+and an `:id` array is joined with `"_"`.
+For example:
+
+ %div{:id => [@item.type, @item.number], :class => [@item.type, @item.urgency]}
+
+is equivalent to:
+
+ %div{:id => "#{@item.type}_#{@item.number}", :class => "#{@item.type} #{@item.urgency}"}
+
+The array will first be flattened
+and any elements that do not test as true will be removed.
+The remaining elements will be converted to strings.
+For example:
+
+ %div{:class => [@item.type, @item == @sortcol && [:sort, @sortdir]] } Contents
+
+could render as any of:
+
+ <div class="numeric sort ascending">Contents</div>
+ <div class="numeric">Contents</div>
+ <div class="sort descending">Contents</div>
+ <div>Contents</div>
+
+depending on whether `@item.type` is `"numeric"` or `nil`,
+whether `@item == @sortcol`,
+and whether `@sortdir` is `"ascending"` or `"descending"`.
+
+If a single value is specified and it evaluates to false it is ignored;
+otherwise it gets converted to a string.
+For example:
+
+ .item{:class => @item.is_empty? && "empty"}
+
+could render as either of:
+
+ class="item"
+ class="item empty"
+
+#### HTML-style Attributes: `()`
+
+Haml also supports a terser, less Ruby-specific attribute syntax
+based on HTML's attributes.
+These are used with parentheses instead of brackets, like so:
+
+ %html(xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en")
+
+Ruby variables can be used by omitting the quotes.
+Local variables or instance variables can be used.
+For example:
+
+ %a(title=@title href=href) Stuff
+
+This is the same as:
+
+ %a{:title => @title, :href => href} Stuff
+
+Because there are no commas separating attributes, though,
+more complicated expressions aren't allowed.
+For those you'll have to use the `{}` syntax.
+You can, however, use both syntaxes together:
+
+ %a(title=@title){:href => @link.href} Stuff
+
+You can also use `#{}` interpolation to insert complicated expressions
+in a HTML-style attribute:
+
+ %span(class="widget_#{@widget.number}")
+
+HTML-style attributes can be stretched across multiple lines
+just like hash-style attributes:
+
+ %script(type="text/javascript"
+ src="javascripts/script_#{2 + 7}")
+
+#### 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.
+
+Attribute methods aren't supported for HTML-style attributes.
+
+#### Boolean Attributes
+
+Some attributes, such as "checked" for `input` tags or "selected" for `option` 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 using hash-style attributes, 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>
+
+HTML-style boolean attributes can be written just like HTML:
+
+ %input(selected)
+
+or using `true` and `false`:
+
+ %input(selected=true)
+
+#### HTML5 Custom Data Attributes
+
+HTML5 allows for adding [custom non-visible data attributes](http://www.whatwg.org/specs/web-apps/current-work/multipage/elements.html#embedding-custom-non-visible-data)
+to elements using attribute names beginning with `data-`.
+Custom data attributes can be used in Haml by using the key `:data` with a Hash value
+in an attribute hash.
+Each of the key/value pairs in the Hash will be transformed into a custom data attribute.
+For example:
+
+ %a{:href=>"/posts", :data => {:author_id => 123}} Posts By Author
+
+will render as:
+
+ <a data-author_id='123' href='/posts'>Posts By Author</a>
+
+### Class and ID: `.` and `#`
+
+The period and pound sign are borrowed from CSS.
+They are used as shortcuts to specify the `class`
+and `id` 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,
+
+ %div#content
+ %div.articles
+ %div.article.title Doogie Howser Comes Out
+ %div.article.date 2006-11-05
+ %div.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>
+
+These shortcuts can be combined with long-hand attributes;
+the two values will be merged together
+as though they were all placed in an array
+(see [the documentation on `:class` and `:id` attributes](#class-and-id-attributes)).
+For example:
+
+ %div#Article.article.entry{:id => @article.number, :class => @article.visibility}
+
+is equivalent to
+
+ %div{:id => ['Article', @article.number], :class => ['article', 'entry', @article.visibility]} Gabba Hey
+
+and could compile to:
+
+ <div class="article entry visible" id="Article_27">Gabba Hey</div>
+
+#### Implicit Div Elements
+
+Because divs are used so often, they're the default elements.
+If you only define a class and/or id using `.` or `#`,
+a div is automatically used.
+For example:
+
+ #collection
+ .item
+ .description What a cool item!
+
+is the same as:
+
+ %div#collection
+ %div.item
+ %div.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>
+
+### Self-Closing Tags: `/`
+
+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 [`:autoclose`](#autoclose-option) option.
+For example:
+
+ %br
+ %meta{'http-equiv' => 'Content-Type', :content => 'text/html'}
+
+is also compiled to:
+
+ <br />
+ <meta http-equiv='Content-Type' content='text/html' />
+
+### Whitespace Removal: `>` and `<`
+
+`>` and `<` give you more control over the whitespace near a tag.
+`>` will remove all whitespace surrounding a tag,
+while `<` will remove all whitespace immediately within a tag.
+You can think of them as alligators eating the whitespace:
+`>` faces out of the tag and eats the whitespace on the outside,
+and `<` 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 `/` or `=`.
+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 />
+
+### Object Reference: `[]`
+
+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>
+
+If you require that the class be something other than the underscored
+object's class, you can implement the `haml_object_ref` method on the object.
+
+ # file: app/models/crazy_user.rb
+
+ class CrazyUser < ActiveRecord::Base
+ def haml_object_ref
+ "a_crazy_user"
+ end
+ end
+
+ -# file: app/views/users/show.haml
+
+ %div[@user]
+ Hello!
+
+is compiled to:
+
+ <div class='a_crazy_user' id='a_crazy_user_15'>
+ Hello!
+ </div>
+
+
+## Doctype: `!!!`
+
+When describing HTML documents with Haml,
+you can have a document type or XML prolog generated automatically
+by including the characters `!!!`.
+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 specific doctype after the `!!!`
+When the [`:format`](#format-option) is set to `:xhtml` (the default except in Rails 3),
+the following doctypes are supported:
+
+`!!!`
+: XHTML 1.0 Transitional<br/>
+ `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">`
+
+`!!! Strict`
+: XHTML 1.0 Strict<br/>
+ `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">`
+
+`!!! Frameset`
+: XHTML 1.0 Frameset<br/>
+ `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">`
+
+`!!! 5`
+: XHTML 5<br/>
+ `<!DOCTYPE html>`<br/>
+
+`!!! 1.1`
+: XHTML 1.1<br/>
+ `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">`
+
+`!!! Basic`
+: XHTML Basic 1.1<br/>
+ `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd"> `
+
+`!!! Mobile`
+: XHTML Mobile 1.2<br/>
+ `<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">`
+
+`!!! RDFa`
+: XHTML+RDFa 1.0<br/>
+ `<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd">`
+
+When the [`:format`](#format-option) option is set to `:html4`,
+the following doctypes are supported:
+
+`!!!`
+: HTML 4.01 Transitional<br/>
+ `<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">`
+
+`!!! Strict`
+: HTML 4.01 Strict<br/>
+ `<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">`
+
+`!!! Frameset`
+: HTML 4.01 Frameset<br/>
+ `<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">`
+
+When the [`:format`](#format-option) option is set to `:html5`,
+`!!!` is always `<!DOCTYPE html>`.
+
+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' ?>
+
+## Comments
+
+Haml supports two sorts of comments:
+those that show up in the HTML output
+and those that don't.
+
+### HTML Comments: `/`
+
+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>
+ -->
+
+#### Conditional Comments: `/[]`
+
+You can also use [Internet Explorer conditional comments](http://www.quirksmode.org/css/condcom.html)
+by enclosing the condition in square brackets after the `/`.
+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]-->
+
+### Haml Comments: `-#`
+
+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>
+
+## Ruby Evaluation
+
+### Inserting Ruby: `=`
+
+The equals character is followed by Ruby code.
+This code is evaluated and the output is inserted into the document.
+For example:
+
+ %p
+ = ['hi', 'there', 'reader!'].join " "
+ = "yo"
+
+is compiled to:
+
+ <p>
+ hi there reader!
+ yo
+ </p>
+
+If the [`:escape_html`](#escape_html-option) option is set, `=` 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;
+
+`=` can also be used at the end of a tag to insert Ruby code within that tag.
+For example:
+
+ %p= "hello"
+
+would be compiled to
+
+ <p>hello</p>
+
+A line of Ruby code can be stretched over multiple lines
+as long as each line but the last ends with a comma.
+For example:
+
+ = link_to_remote "Add to cart",
+ :url => { :action => "add", :id => product.id },
+ :update => { :success => "cart", :failure => "error" }
+
+Note that it's illegal to nest code within a tag that ends with `=`.
+
+### Running Ruby: `-`
+
+The hyphen character is also followed by Ruby code.
+This code is evaluated but *not* inserted into the document.
+
+**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.**
+
+For example:
+
+ - foo = "hello"
+ - foo << " there"
+ - foo << " you!"
+ %p= foo
+
+is compiled to:
+
+ <p>
+ hello there you!
+ </p>
+
+A line of Ruby code can be stretched over multiple lines
+as long as each line but the last ends with a comma.
+For example:
+
+ - links = {:home => "/",
+ :docs => "/docs",
+ :about => "/about"}
+
+#### Ruby 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 Ruby evaluation 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>
+ <p>See, I can count!</p>
+
+Another example:
+
+ %p
+ - case 2
+ - when 1
+ = "1!"
+ - when 2
+ = "2?"
+ - when 3
+ = "3."
+
+is compiled to:
+
+ <p>
+ 2?
+ </p>
+
+### Whitespace Preservation: `~` {#tilde}
+
+`~` 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](#whitespace_preservation).
+
+### Ruby Interpolation: `#{}`
+
+Ruby code can also be interpolated within plain text using `#{}`,
+similarly to Ruby string interpolation.
+For example,
+
+ %p This is #{h quality} cake!
+
+is the same as
+
+ %p= "This is the #{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}
+ And yon presence thereof: \{foo}
+
+might compile to
+
+ <p>
+ Look at \yon lack of backslash: #{foo}
+ And yon presence thereof: \{foo}
+ </p>
+
+Interpolation can also be used within [filters](#filters).
+For example:
+
+ :javascript
+ $(document).ready(function() {
+ alert(#{@message.to_json});
+ });
+
+might compile to
+
+ <script type='text/javascript'>
+ //<![CDATA[
+ $(document).ready(function() {
+ alert("Hi there!");
+ });
+ //]]>
+ </script>
+
+### Escaping HTML: `&=` {#escaping_html}
+
+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 [`:escape_html`](#escape_html-option) option is set,
+`&=` behaves identically to `=`.
+
+`&` can also be used on its own so that `#{}` interpolation is escaped.
+For example,
+
+ & I like #{"cheese & crackers"}
+
+compiles to
+
+ I like cheese &amp; crackers
+
+### Unescaping HTML: `!=` {#unescaping_html}
+
+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 [`:escape_html`](#escape_html-option) option is set,
+`=` will sanitize the HTML, but `!=` still won't.
+For example, if `:escape_html` is set:
+
+ = "I feel <strong>!"
+ != "I feel <strong>!"
+
+compiles to
+
+ I feel &lt;strong&gt;!
+ I feel <strong>!
+
+`!` can also be used on its own so that `#{}` interpolation is unescaped.
+For example,
+
+ ! I feel #{"<strong>"}!
+
+compiles to
+
+ I feel <strong>!
+
+## Filters {#filters}
+
+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 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>
+
+Currently, filters ignore the [`:escape_html`](#escape_html-option) option.
+This means that `#{}` interpolation within filters is never HTML-escaped.
+
+Haml has the following filters defined:
+
+{#plain-filter}
+### `: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 `.` or `-` to be parsed.
+
+{#javascript-filter}
+### `:javascript`
+Surrounds the filtered text with `<script>` and CDATA tags.
+Useful for including inline Javascript.
+
+{#css-filter}
+### `:css`
+Surrounds the filtered text with `<style>` and CDATA tags.
+Useful for including inline CSS.
+
+{#cdata-filter}
+### `:cdata`
+Surrounds the filtered text with CDATA tags.
+
+{#escaped-filter}
+### `:escaped`
+Works the same as plain, but HTML-escapes the text
+before placing it in the document.
+
+{#ruby-filter}
+### `:ruby`
+Parses the filtered text with the normal Ruby interpreter.
+All output sent to `$stdout`, like with `puts`,
+is output into the Haml document.
+Not available if the [`:suppress_eval`](#suppress_eval-option) option is set to true.
+The Ruby code is evaluated in the same context as the Haml template.
+
+{#preserve-filter}
+### `:preserve`
+Inserts the filtered text into the template with whitespace preserved.
+`preserve`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](#whitespace_preservation).
+
+{#erb-filter}
+### `:erb`
+Parses the filtered text with ERb, like an RHTML template.
+Not available if the [`:suppress_eval`](#suppress_eval-option) option is set to true.
+Embedded Ruby code is evaluated in the same context as the Haml template.
+
+{#sass-filter}
+### `:sass`
+Parses the filtered text with Sass to produce CSS output.
+
+{#textile-filter}
+### `:textile`
+Parses the filtered text with [Textile](http://www.textism.com/tools/textile).
+Only works if [RedCloth](http://redcloth.org) is installed.
+
+{#markdown-filter}
+### `:markdown`
+Parses the filtered text with [Markdown](http://daringfireball.net/projects/markdown).
+Only works if [RDiscount](http://github.com/rtomayko/rdiscount),
+[RPeg-Markdown](http://github.com/rtomayko/rpeg-markdown),
+[Maruku](http://maruku.rubyforge.org),
+or [BlueCloth](www.deveiate.org/projects/BlueCloth) are installed.
+
+{#maruku-filter}
+### `:maruku`
+Parses the filtered text with [Maruku](http://maruku.rubyforge.org),
+which has some non-standard extensions to Markdown.
+
+### Custom Filters
+
+You can also define your own filters. See {Haml::Filters} for details.
+
+## Multiline: `|` {#multiline}
+
+The pipe character designates a multiline string.
+It's placed at the end of a line (after some whitespace)
+and means that all following lines that end with `|`
+will be evaluated as though they were on the same line.
+**Note that even the last line in the multiline block
+should end with `|`.**
+For example:
+
+ %whoo
+ %hoo= h( |
+ "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>
+
+Using multiline declarations in Haml is intentionally awkward.
+This is designed to discourage people from putting lots and lots of Ruby code
+in their Haml templates.
+If you find yourself using multiline declarations, stop and think:
+could I do this better with a helper?
+
+Note that there are a few cases where it's useful to allow
+something to flow over onto multiple lines in a non-awkward manner.
+One of these is HTML attributes.
+Some elements just have lots of attributes,
+so you can wrap attributes without using `|` (see [Attributes](#attributes)).
+
+In addition, sometimes you need to call Ruby methods or declare data structures
+that just need a lot of template information.
+So data structures and functions that require lots of arguments
+can be wrapped over multiple lines,
+as long as each line but the last ends in a comma
+(see [Inserting Ruby](#inserting_ruby_)).
+
+## 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, `&#x000A;`.
+Then Haml won't try to re-format the indentation.
+
+Literal `textarea` and `pre` tags automatically preserve content given through `=`.
+Dynamically-generated `textarea`s and `pre`s can't be preserved automatically,
+and so should be passed through {Haml::Helpers#find\_and\_preserve} or the [`~` command](#tilde),
+which has the same effect.
+
+Blocks of literal text can be preserved using the [`:preserve` filter](#preserve-filter).
+
+## 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.
View
902 scripts/docs/erb.rb
@@ -0,0 +1,902 @@
+# = ERB -- Ruby Templating
+#
+# Author:: Masatoshi SEKI
+# Documentation:: James Edward Gray II and Gavin Sinclair
+#
+# See ERB for primary documentation and ERB::Util for a couple of utility
+# routines.
+#
+# Copyright (c) 1999-2000,2002,2003 Masatoshi SEKI
+#
+# You can redistribute it and/or modify it under the same terms as Ruby.
+
+#
+# = ERB -- Ruby Templating
+#
+# == Introduction
+#
+# ERB provides an easy to use but powerful templating system for Ruby. Using
+# ERB, actual Ruby code can be added to any plain text document for the
+# purposes of generating document information details and/or flow control.
+#
+# A very simple example is this:
+#
+# require 'erb'
+#
+# x = 42
+# template = ERB.new <<-EOF
+# The value of x is: <%= x %>
+# EOF
+# puts template.result(binding)
+#
+# <em>Prints:</em> The value of x is: 42
+#
+# More complex examples are given below.
+#
+#
+# == Recognized Tags
+#
+# ERB recognizes certain tags in the provided template and converts them based
+# on the rules below:
+#
+# <% Ruby code -- inline with output %>
+# <%= Ruby expression -- replace with result %>
+# <%# comment -- ignored -- useful in testing %>
+# % a line of Ruby code -- treated as <% line %> (optional -- see ERB.new)
+# %% replaced with % if first thing on a line and % processing is used
+# <%% or %%> -- replace with <% or %> respectively
+#
+# All other text is passed through ERB filtering unchanged.
+#
+#
+# == Options
+#
+# There are several settings you can change when you use ERB:
+# * the nature of the tags that are recognized;
+# * the value of <tt>$SAFE</tt> under which the template is run;
+# * the binding used to resolve local variables in the template.
+#
+# See the ERB.new and ERB#result methods for more detail.
+#
+# == Character encodings
+#
+# ERB (or ruby code generated by ERB) returns a string in the same
+# character encoding as the input string. When the input string has
+# a magic comment, however, it returns a string in the encoding specified
+# by the magic comment.
+#
+# # -*- coding: UTF-8 -*-
+# require 'erb'
+#
+# template = ERB.new <<EOF
+# <%#-*- coding: Big5 -*-%>
+# \_\_ENCODING\_\_ is <%= \_\_ENCODING\_\_ %>.
+# EOF
+# puts template.result
+#
+# <em>Prints:</em> \_\_ENCODING\_\_ is Big5.
+#
+#
+# == Examples
+#
+# === Plain Text
+#
+# ERB is useful for any generic templating situation. Note that in this example, we use the
+# convenient "% at start of line" tag, and we quote the template literally with
+# <tt>%q{...}</tt> to avoid trouble with the backslash.
+#
+# require "erb"
+#
+# # Create template.
+# template = %q{
+# From: James Edward Gray II <james@grayproductions.net>
+# To: <%= to %>
+# Subject: Addressing Needs
+#
+# <%= to[/\w+/] %>:
+#
+# Just wanted to send a quick note assuring that your needs are being
+# addressed.
+#
+# I want you to know that my team will keep working on the issues,
+# especially:
+#
+# <%# ignore numerous minor requests -- focus on priorities %>
+# % priorities.each do |priority|
+# * <%= priority %>
+# % end
+#
+# Thanks for your patience.
+#
+# James Edward Gray II
+# }.gsub(/^ /, '')
+#
+# message = ERB.new(template, 0, "%<>")
+#
+# # Set up template data.
+# to = "Community Spokesman <spokesman@ruby_community.org>"
+# priorities = [ "Run Ruby Quiz",
+# "Document Modules",
+# "Answer Questions on Ruby Talk" ]
+#
+# # Produce result.
+# email = message.result
+# puts email
+#
+# <i>Generates:</i>
+#
+# From: James Edward Gray II <james@grayproductions.net>
+# To: Community Spokesman <spokesman@ruby_community.org>
+# Subject: Addressing Needs
+#
+# Community:
+#
+# Just wanted to send a quick note assuring that your needs are being addressed.
+#
+# I want you to know that my team will keep working on the issues, especially:
+#
+# * Run Ruby Quiz
+# * Document Modules
+# * Answer Questions on Ruby Talk
+#
+# Thanks for your patience.
+#
+# James Edward Gray II
+#
+# === Ruby in HTML
+#
+# ERB is often used in <tt>.rhtml</tt> files (HTML with embedded Ruby). Notice the need in
+# this example to provide a special binding when the template is run, so that the instance
+# variables in the Product object can be resolved.
+#
+# require "erb"
+#
+# # Build template data class.
+# class Product
+# def initialize( code, name, desc, cost )
+# @code = code
+# @name = name
+# @desc = desc
+# @cost = cost
+#
+# @features = [ ]
+# end
+#
+# def add_feature( feature )
+# @features << feature
+# end
+#
+# # Support templating of member data.
+# def get_binding
+# binding
+# end
+#
+# # ...
+# end
+#
+# # Create template.
+# template = %{
+# <html>
+# <head><title>Ruby Toys -- <%= @name %></title></head>
+# <body>
+#
+# <h1><%= @name %> (<%= @code %>)</h1>
+# <p><%= @desc %></p>
+#
+# <ul>
+# <% @features.each do |f| %>
+# <li><b><%= f %></b></li>
+# <% end %>
+# </ul>
+#
+# <p>
+# <% if @cost < 10 %>
+# <b>Only <%= @cost %>!!!</b>
+# <% else %>
+# Call for a price, today!
+# <% end %>
+# </p>
+#
+# </body>
+# </html>
+# }.gsub(/^ /, '')
+#
+# rhtml = ERB.new(template)
+#
+# # Set up template data.
+# toy = Product.new( "TZ-1002",
+# "Rubysapien",
+# "Geek's Best Friend! Responds to Ruby commands...",
+# 999.95 )
+# toy.add_feature("Listens for verbal commands in the Ruby language!")
+# toy.add_feature("Ignores Perl, Java, and all C variants.")
+# toy.add_feature("Karate-Chop Action!!!")
+# toy.add_feature("Matz signature on left leg.")
+# toy.add_feature("Gem studded eyes... Rubies, of course!")
+#
+# # Produce result.
+# rhtml.run(toy.get_binding)
+#
+# <i>Generates (some blank lines removed):</i>
+#
+# <html>
+# <head><title>Ruby Toys -- Rubysapien</title></head>
+# <body>
+#
+# <h1>Rubysapien (TZ-1002)</h1>
+# <p>Geek's Best Friend! Responds to Ruby commands...</p>
+#
+# <ul>
+# <li><b>Listens for verbal commands in the Ruby language!</b></li>
+# <li><b>Ignores Perl, Java, and all C variants.</b></li>
+# <li><b>Karate-Chop Action!!!</b></li>
+# <li><b>Matz signature on left leg.</b></li>
+# <li><b>Gem studded eyes... Rubies, of course!</b></li>
+# </ul>
+#
+# <p>
+# Call for a price, today!
+# </p>
+#
+# </body>
+# </html>
+#
+#
+# == Notes
+#
+# There are a variety of templating solutions available in various Ruby projects:
+# * ERB's big brother, eRuby, works the same but is written in C for speed;
+# * Amrita (smart at producing HTML/XML);
+# * cs/Template (written in C for speed);
+# * RDoc, distributed with Ruby, uses its own template engine, which can be reused elsewhere;
+# * and others; search the RAA.
+#
+# Rails, the web application framework, uses ERB to create views.
+#
+class ERB
+ Revision = '$Date:: 2009-10-02 21:04:37 +0900#$' #'
+
+ # Returns revision information for the erb.rb module.
+ def self.version
+ "erb.rb [2.1.0 #{ERB::Revision.split[1]}]"
+ end
+end
+
+#--
+# ERB::Compiler
+class ERB
+ class Compiler # :nodoc:
+ class PercentLine # :nodoc:
+ def initialize(str)
+ @value = str
+ end
+ attr_reader :value
+ alias :to_s :value
+
+ def empty?
+ @value.empty?
+ end
+ end
+
+ class Scanner # :nodoc:
+ @scanner_map = {}
+ def self.regist_scanner(klass, trim_mode, percent)
+ @scanner_map[[trim_mode, percent]] = klass
+ end
+
+ def self.default_scanner=(klass)
+ @default_scanner = klass
+ end
+
+ def self.make_scanner(src, trim_mode, percent)
+ klass = @scanner_map.fetch([trim_mode, percent], @default_scanner)
+ klass.new(src, trim_mode, percent)
+ end
+
+ def initialize(src, trim_mode, percent)
+ @src = src
+ @stag = nil
+ end
+ attr_accessor :stag
+
+ def scan; end
+ end
+
+ class TrimScanner < Scanner # :nodoc:
+ def initialize(src, trim_mode, percent)
+ super
+ @trim_mode = trim_mode
+ @percent = percent
+ if @trim_mode == '>'
+ @scan_line = self.method(:trim_line1)
+ elsif @trim_mode == '<>'
+ @scan_line = self.method(:trim_line2)
+ elsif @trim_mode == '-'
+ @scan_line = self.method(:explicit_trim_line)
+ else
+ @scan_line = self.method(:scan_line)
+ end
+ end
+ attr_accessor :stag
+
+ def scan(&block)
+ @stag = nil
+ if @percent
+ @src.each_line do |line|
+ percent_line(line, &block)
+ end
+ else
+ @scan_line.call(@src, &block)
+ end
+ nil
+ end
+
+ def percent_line(line, &block)
+ if @stag || line[0] != ?%
+ return @scan_line.call(line, &block)
+ end
+
+ line[0] = ''
+ if line[0] == ?%
+ @scan_line.call(line, &block)
+ else
+ yield(PercentLine.new(line.chomp))
+ end
+ end
+
+ def scan_line(line)
+ line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
+ tokens.each do |token|
+ next if token.empty?
+ yield(token)
+ end
+ end
+ end
+
+ def trim_line1(line)
+ line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
+ tokens.each do |token|
+ next if token.empty?
+ if token == "%>\n"
+ yield('%>')
+ yield(:cr)
+ else
+ yield(token)
+ end
+ end
+ end
+ end
+
+ def trim_line2(line)
+ head = nil
+ line.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
+ tokens.each do |token|
+ next if token.empty?
+ head = token unless head
+ if token == "%>\n"
+ yield('%>')
+ if is_erb_stag?(head)
+ yield(:cr)
+ else
+ yield("\n")
+ end
+ head = nil
+ else
+ yield(token)
+ head = nil if token == "\n"
+ end
+ end
+ end
+ end
+
+ def explicit_trim_line(line)
+ line.scan(/(.*?)(^[ \t]*<%\-|<%\-|<%%|%%>|<%=|<%#|<%|-%>\n|-%>|%>|\z)/m) do |tokens|
+ tokens.each do |token|
+ next if token.empty?
+ if @stag.nil? && /[ \t]*<%-/ =~ token
+ yield('<%')
+ elsif @stag && token == "-%>\n"
+ yield('%>')
+ yield(:cr)
+ elsif @stag && token == '-%>'
+ yield('%>')
+ else
+ yield(token)
+ end
+ end
+ end
+ end
+
+ ERB_STAG = %w(<%= <%# <%)
+ def is_erb_stag?(s)
+ ERB_STAG.member?(s)
+ end
+ end
+
+ Scanner.default_scanner = TrimScanner
+
+ class SimpleScanner < Scanner # :nodoc:
+ def scan
+ @src.scan(/(.*?)(<%%|%%>|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
+ tokens.each do |token|
+ next if token.empty?
+ yield(token)
+ end
+ end
+ end
+ end
+
+ Scanner.regist_scanner(SimpleScanner, nil, false)
+
+ begin
+ require 'strscan'
+ class SimpleScanner2 < Scanner # :nodoc:
+ def scan
+ stag_reg = /(.*?)(<%%|<%=|<%#|<%|\z)/m
+ etag_reg = /(.*?)(%%>|%>|\z)/m
+ scanner = StringScanner.new(@src)
+ while ! scanner.eos?
+ scanner.scan(@stag ? etag_reg : stag_reg)
+ yield(scanner[1])
+ yield(scanner[2])
+ end
+ end
+ end
+ Scanner.regist_scanner(SimpleScanner2, nil, false)
+
+ class ExplicitScanner < Scanner # :nodoc:
+ def scan
+ stag_reg = /(.*?)(^[ \t]*<%-|<%%|<%=|<%#|<%-|<%|\z)/m
+ etag_reg = /(.*?)(%%>|-%>|%>|\z)/m
+ scanner = StringScanner.new(@src)
+ while ! scanner.eos?
+ scanner.scan(@stag ? etag_reg : stag_reg)
+ yield(scanner[1])
+
+ elem = scanner[2]
+ if /[ \t]*<%-/ =~ elem
+ yield('<%')
+ elsif elem == '-%>'
+ yield('%>')
+ yield(:cr) if scanner.scan(/(\n|\z)/)
+ else
+ yield(elem)
+ end
+ end
+ end
+ end
+ Scanner.regist_scanner(ExplicitScanner, '-', false)
+
+ rescue LoadError
+ end
+
+ class Buffer # :nodoc:
+ def initialize(compiler, enc=nil)
+ @compiler = compiler
+ @line = []
+ @script = enc ? "#coding:#{enc.to_s}\n" : ""
+ @compiler.pre_cmd.each do |x|
+ push(x)
+ end
+ end
+ attr_reader :script
+
+ def push(cmd)
+ @line << cmd
+ end
+
+ def cr
+ @script << (@line.join('; '))
+ @line = []
+ @script << "\n"
+ end
+
+ def close
+ return unless @line
+ @compiler.post_cmd.each do |x|
+ push(x)
+ end
+ @script << (@line.join('; '))
+ @line = nil
+ end
+ end
+
+ def content_dump(s)
+ n = s.count("\n")
+ if n > 0
+ s.dump + "\n" * n
+ else
+ s.dump
+ end
+ end
+
+ def compile(s)
+ enc = s.encoding
+ raise ArgumentError, "#{enc} is not ASCII compatible" if enc.dummy?
+ s = s.dup.force_encoding("ASCII-8BIT") # don't use constant Enoding::ASCII_8BIT for miniruby
+ enc = detect_magic_comment(s) || enc
+ out = Buffer.new(self, enc)
+
+ content = ''
+ scanner = make_scanner(s)
+ scanner.scan do |token|
+ next if token.nil?
+ next if token == ''
+ if scanner.stag.nil?
+ case token
+ when PercentLine
+ out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
+ content = ''
+ out.push(token.to_s)
+ out.cr
+ when :cr
+ out.cr
+ when '<%', '<%=', '<%#'
+ scanner.stag = token
+ out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
+ content = ''
+ when "\n"
+ content << "\n"
+ out.push("#{@put_cmd} #{content_dump(content)}")
+ content = ''
+ when '<%%'
+ content << '<%'
+ else
+ content << token
+ end
+ else
+ case token
+ when '%>'
+ case scanner.stag
+ when '<%'
+ if content[-1] == ?\n
+ content.chop!
+ out.push(content)
+ out.cr
+ else
+ out.push(content)
+ end
+ when '<%='
+ out.push("#{@insert_cmd}((#{content}).to_s)")
+ when '<%#'
+ # out.push("# #{content_dump(content)}")
+ end
+ scanner.stag = nil
+ content = ''
+ when '%%>'
+ content << '%>'
+ else
+ content << token
+ end
+ end
+ end
+ out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
+ out.close
+ return out.script, enc
+ end
+
+ def prepare_trim_mode(mode)
+ case mode
+ when 1
+ return [false, '>']
+ when 2
+ return [false, '<>']
+ when 0
+ return [false, nil]
+ when String
+ perc = mode.include?('%')
+ if mode.include?('-')
+ return [perc, '-']
+ elsif mode.include?('<>')
+ return [perc, '<>']
+ elsif mode.include?('>')
+ return [perc, '>']
+ else
+ [perc, nil]
+ end
+ else
+ return [false, nil]
+ end
+ end
+
+ def make_scanner(src)
+ Scanner.make_scanner(src, @trim_mode, @percent)
+ end
+
+ def initialize(trim_mode)
+ @percent, @trim_mode = prepare_trim_mode(trim_mode)
+ @put_cmd = 'print'
+ @insert_cmd = @put_cmd
+ @pre_cmd = []
+ @post_cmd = []
+ end
+ attr_reader :percent, :trim_mode
+ attr_accessor :put_cmd, :insert_cmd, :pre_cmd, :post_cmd
+
+ private
+ def detect_magic_comment(s)
+ if /\A<%#(.*)%>/ =~ s or (@percent and /\A%#(.*)/ =~ s)
+ comment = $1
+ comment = $1 if comment[/-\*-\s*(.*?)\s*-*-$/]
+ if %r"coding\s*[=:]\s*([[:alnum:]\-_]+)" =~ comment
+ enc = $1.sub(/-(?:mac|dos|unix)/i, '')
+ enc = Encoding.find(enc)
+ end
+ end
+ end
+ end
+end
+
+#--
+# ERB
+class ERB
+ #
+ # Constructs a new ERB object with the template specified in _str_.
+ #
+ # An ERB object works by building a chunk of Ruby code that will output
+ # the completed template when run. If _safe_level_ is set to a non-nil value,
+ # ERB code will be run in a separate thread with <b>$SAFE</b> set to the
+ # provided level.
+ #
+ # If _trim_mode_ is passed a String containing one or more of the following
+ # modifiers, ERB will adjust its code generation as listed:
+ #
+ # % enables Ruby code processing for lines beginning with %
+ # <> omit newline for lines starting with <% and ending in %>
+ # > omit newline for lines ending in %>
+ #
+ # _eoutvar_ can be used to set the name of the variable ERB will build up
+ # its output in. This is useful when you need to run multiple ERB
+ # templates through the same binding and/or when you want to control where
+ # output ends up. Pass the name of the variable to be used inside a String.
+ #
+ # === Example
+ #
+ # require "erb"
+ #
+ # # build data class
+ # class Listings
+ # PRODUCT = { :name => "Chicken Fried Steak",
+ # :desc => "A well messages pattie, breaded and fried.",
+ # :cost => 9.95 }
+ #
+ # attr_reader :product, :price
+ #
+ # def initialize( product = "", price = "" )
+ # @product = product
+ # @price = price
+ # end
+ #
+ # def build
+ # b = binding
+ # # create and run templates, filling member data variables
+ # ERB.new(<<-'END_PRODUCT'.gsub(/^\s+/, ""), 0, "", "@product").result b
+ # <%= PRODUCT[:name] %>
+ # <%= PRODUCT[:desc] %>
+ # END_PRODUCT
+ # ERB.new(<<-'END_PRICE'.gsub(/^\s+/, ""), 0, "", "@price").result b
+ # <%= PRODUCT[:name] %> -- <%= PRODUCT[:cost] %>
+ # <%= PRODUCT[:desc] %>
+ # END_PRICE
+ # end
+ # end
+ #
+ # # setup template data
+ # listings = Listings.new
+ # listings.build
+ #
+ # puts listings.product + "\n" + listings.price
+ #
+ # _Generates_
+ #
+ # Chicken Fried Steak
+ # A well messages pattie, breaded and fried.
+ #
+ # Chicken Fried Steak -- 9.95
+ # A well messages pattie, breaded and fried.
+ #
+ def initialize(str, safe_level=nil, trim_mode=nil, eoutvar='_erbout')
+ @safe_level = safe_level
+ compiler = ERB::Compiler.new(trim_mode)
+ set_eoutvar(compiler, eoutvar)
+ @src, @enc = *compiler.compile(str)
+ @filename = nil
+ end
+
+ # The Ruby code generated by ERB
+ attr_reader :src
+
+ # The optional _filename_ argument passed to Kernel#eval when the ERB code
+ # is run
+ attr_accessor :filename
+
+ #
+ # Can be used to set _eoutvar_ as described in ERB#new. It's probably easier
+ # to just use the constructor though, since calling this method requires the
+ # setup of an ERB _compiler_ object.
+ #
+ def set_eoutvar(compiler, eoutvar = '_erbout')
+ compiler.put_cmd = "#{eoutvar}.concat"
+ compiler.insert_cmd = "#{eoutvar}.concat"
+
+ cmd = []
+ cmd.push "#{eoutvar} = ''"
+
+ compiler.pre_cmd = cmd
+
+ cmd = []
+ cmd.push("#{eoutvar}.force_encoding(__ENCODING__)")
+
+ compiler.post_cmd = cmd
+ end
+
+ # Generate results and print them. (see ERB#result)
+ def run(b=TOPLEVEL_BINDING)
+ print self.result(b)
+ end
+
+ #
+ # Executes the generated ERB code to produce a completed template, returning
+ # the results of that code. (See ERB#new for details on how this process can
+ # be affected by _safe_level_.)
+ #
+ # _b_ accepts a Binding or Proc object which is used to set the context of
+ # code evaluation.
+ #
+ def result(b=TOPLEVEL_BINDING)
+ if @safe_level
+ proc {
+ $SAFE = @safe_level
+ eval(@src, b, (@filename || '(erb)'), 0)
+ }.call
+ else
+ eval(@src, b, (@filename || '(erb)'), 0)
+ end
+ end
+
+ # Define _methodname_ as instance method of _mod_ from compiled ruby source.
+ #
+ # example:
+ # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
+ # erb = ERB.new(File.read(filename))
+ # erb.def_method(MyClass, 'render(arg1, arg2)', filename)
+ # print MyClass.new.render('foo', 123)
+ def def_method(mod, methodname, fname='(ERB)')
+ src = self.src
+ magic_comment = "#coding:#{@enc}\n"
+ mod.module_eval do
+ eval(magic_comment + "def #{methodname}\n" + src + "\nend\n", binding, fname, -2)
+ end
+ end
+
+ # Create unnamed module, define _methodname_ as instance method of it, and return it.
+ #
+ # example:
+ # filename = 'example.rhtml' # 'arg1' and 'arg2' are used in example.rhtml
+ # erb = ERB.new(File.read(filename))
+ # erb.filename = filename
+ # MyModule = erb.def_module('render(arg1, arg2)')
+ # class MyClass
+ # include MyModule
+ # end
+ def def_module(methodname='erb')
+ mod = Module.new
+ def_method(mod, methodname, @filename || '(ERB)')
+ mod
+ end
+
+ # Define unnamed class which has _methodname_ as instance method, and return it.
+ #
+ # example:
+ # class MyClass_
+ # def initialize(arg1, arg2)
+ # @arg1 = arg1; @arg2 = arg2
+ # end
+ # end
+ # filename = 'example.rhtml' # @arg1 and @arg2 are used in example.rhtml
+ # erb = ERB.new(File.read(filename))
+ # erb.filename = filename
+ # MyClass = erb.def_class(MyClass_, 'render()')
+ # print MyClass.new('foo', 123).render()
+ def def_class(superklass=Object, methodname='result')
+ cls = Class.new(superklass)
+ def_method(cls, methodname, @filename || '(ERB)')
+ cls
+ end
+end
+
+#--
+# ERB::Util
+class ERB
+ # A utility module for conversion routines, often handy in HTML generation.
+ module Util
+ public
+ #
+ # A utility method for escaping HTML tag characters in _s_.
+ #
+ # require "erb"
+ # include ERB::Util
+ #
+ # puts html_escape("is a > 0 & a < 10?")
+ #
+ # _Generates_
+ #
+ # is a &gt; 0 &amp; a &lt; 10?
+ #
+ def html_escape(s)
+ s.to_s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
+ end
+ alias h html_escape
+ module_function :h
+ module_function :html_escape
+
+ #
+ # A utility method for encoding the String _s_ as a URL.
+ #
+ # require "erb"
+ # include ERB::Util
+ #
+ # puts url_encode("Programming Ruby: The Pragmatic Programmer's Guide")
+ #
+ # _Generates_
+ #
+ # Programming%20Ruby%3A%20%20The%20Pragmatic%20Programmer%27s%20Guide
+ #
+ def url_encode(s)
+ s.to_s.dup.force_encoding("ASCII-8BIT").gsub(/[^a-zA-Z0-9_\-.]/n) {
+ sprintf("%%%02X", $&.unpack("C")[0])
+ }
+ end
+ alias u url_encode
+ module_function :u
+ module_function :url_encode
+ end
+end
+
+#--
+# ERB::DefMethod
+class ERB
+ # Utility module to define eRuby script as instance method.
+ #
+ # === Example
+ #
+ # example.rhtml:
+ # <% for item in @items %>
+ # <b><%= item %></b>
+ # <% end %>
+ #
+ # example.rb:
+ # require 'erb'
+ # class MyClass
+ # extend ERB::DefMethod
+ # def_erb_method('render()', 'example.rhtml')
+ # def initialize(items)
+ # @items = items
+ # end
+ # end
+ # print MyClass.new([10,20,30]).render()
+ #
+ # result:
+ #
+ # <b>10</b>
+ #
+ # <b>20</b>
+ #
+ # <b>30</b>
+ #
+ module DefMethod
+ public
+ # define _methodname_ as instance method of current module, using ERB object or eRuby file
+ def def_erb_method(methodname, erb_or_fname)
+ if erb_or_fname.kind_of? String
+ fname = erb_or_fname
+ erb = ERB.new(File.read(fname))
+ erb.def_method(self, methodname, fname)
+ else
+ erb = erb_or_fname
+ erb.def_method(self, methodname, erb.filename || '(ERB)')
+ end
+ end
+ module_function :def_erb_method
+ end
+end

0 comments on commit 7999d41

Please sign in to comment.
Something went wrong with that request. Please try again.