mustache-0.99.4/ 0000755 0001750 0001750 00000000000 11643306253 013367 5 ustar virtual virtual mustache-0.99.4/metadata.yml 0000644 0001750 0001750 00000007213 11643306253 015675 0 ustar virtual virtual --- !ruby/object:Gem::Specification
name: mustache
version: !ruby/object:Gem::Version
hash: 411
prerelease:
segments:
- 0
- 99
- 4
version: 0.99.4
platform: ruby
authors:
- Chris Wanstrath
- Magnus Holm
- Pieter van de Bruggen
autorequire:
bindir: bin
cert_chain: []
date: 2011-05-26 00:00:00 -07:00
default_executable:
dependencies: []
description: |
Inspired by ctemplate, Mustache is a framework-agnostic way to render
logic-free views.
As ctemplates says, "It emphasizes separating logic from presentation:
it is impossible to embed application logic in this template
language.
Think of Mustache as a replacement for your views. Instead of views
consisting of ERB or HAML with random helpers and arbitrary logic,
your views are broken into two parts: a Ruby class and an HTML
template.
email: chris@ozmm.org
executables:
- mustache
extensions: []
extra_rdoc_files: []
files:
- README.md
- Rakefile
- LICENSE
- lib/mustache/context.rb
- lib/mustache/generator.rb
- lib/mustache/parser.rb
- lib/mustache/settings.rb
- lib/mustache/sinatra.rb
- lib/mustache/template.rb
- lib/mustache/version.rb
- lib/mustache.rb
- lib/rack/bug/panels/mustache_panel/mustache_extension.rb
- lib/rack/bug/panels/mustache_panel/view.mustache
- lib/rack/bug/panels/mustache_panel.rb
- bin/mustache
- man/mustache.1
- man/mustache.1.html
- man/mustache.1.ron
- man/mustache.5
- man/mustache.5.html
- man/mustache.5.ron
- test/autoloading_test.rb
- test/fixtures/comments.mustache
- test/fixtures/comments.rb
- test/fixtures/complex_view.mustache
- test/fixtures/complex_view.rb
- test/fixtures/crazy_recursive.mustache
- test/fixtures/crazy_recursive.rb
- test/fixtures/delimiters.mustache
- test/fixtures/delimiters.rb
- test/fixtures/dot_notation.mustache
- test/fixtures/dot_notation.rb
- test/fixtures/double_section.mustache
- test/fixtures/double_section.rb
- test/fixtures/escaped.mustache
- test/fixtures/escaped.rb
- test/fixtures/inner_partial.mustache
- test/fixtures/inner_partial.txt
- test/fixtures/inverted_section.mustache
- test/fixtures/inverted_section.rb
- test/fixtures/lambda.mustache
- test/fixtures/lambda.rb
- test/fixtures/method_missing.rb
- test/fixtures/namespaced.mustache
- test/fixtures/namespaced.rb
- test/fixtures/nested_objects.mustache
- test/fixtures/nested_objects.rb
- test/fixtures/node.mustache
- test/fixtures/partial_with_module.mustache
- test/fixtures/partial_with_module.rb
- test/fixtures/passenger.conf
- test/fixtures/passenger.rb
- test/fixtures/recursive.mustache
- test/fixtures/recursive.rb
- test/fixtures/simple.mustache
- test/fixtures/simple.rb
- test/fixtures/template_partial.mustache
- test/fixtures/template_partial.rb
- test/fixtures/template_partial.txt
- test/fixtures/unescaped.mustache
- test/fixtures/unescaped.rb
- test/fixtures/utf8.mustache
- test/fixtures/utf8_partial.mustache
- test/helper.rb
- test/mustache_test.rb
- test/parser_test.rb
- test/partial_test.rb
- test/spec_test.rb
- test/template_test.rb
has_rdoc: true
homepage: http://github.com/defunkt/mustache
licenses: []
post_install_message:
rdoc_options: []
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
none: false
requirements:
- - ">="
- !ruby/object:Gem::Version
hash: 3
segments:
- 0
version: "0"
required_rubygems_version: !ruby/object:Gem::Requirement
none: false
requirements:
- - ">="
- !ruby/object:Gem::Version
hash: 3
segments:
- 0
version: "0"
requirements: []
rubyforge_project:
rubygems_version: 1.5.2
signing_key:
specification_version: 3
summary: Mustache is a framework-agnostic way to render logic-free views.
test_files: []
mustache-0.99.4/README.md 0000644 0001750 0001750 00000023231 11643306253 014647 0 ustar virtual virtual Mustache
=========
Inspired by [ctemplate][1] and [et][2], Mustache is a
framework-agnostic way to render logic-free views.
As ctemplates says, "It emphasizes separating logic from presentation:
it is impossible to embed application logic in this template language."
For a list of implementations (other than Ruby) and tips, see
.
Overview
--------
Think of Mustache as a replacement for your views. Instead of views
consisting of ERB or HAML with random helpers and arbitrary logic,
your views are broken into two parts: a Ruby class and an HTML
template.
We call the Ruby class the "view" and the HTML template the
"template."
All your logic, decisions, and code is contained in your view. All
your markup is contained in your template. The template does nothing
but reference methods in your view.
This strict separation makes it easier to write clean templates,
easier to test your views, and more fun to work on your app's front end.
Why?
----
I like writing Ruby. I like writing HTML. I like writing JavaScript.
I don't like writing ERB, Haml, Liquid, Django Templates, putting Ruby
in my HTML, or putting JavaScript in my HTML.
Usage
-----
Quick example:
>> require 'mustache'
=> true
>> Mustache.render("Hello {{planet}}", :planet => "World!")
=> "Hello World!"
We've got an `examples` folder but here's the canonical one:
class Simple < Mustache
def name
"Chris"
end
def value
10_000
end
def taxed_value
value * 0.6
end
def in_ca
true
end
end
We simply create a normal Ruby class and define methods. Some methods
reference others, some return values, some return only booleans.
Now let's write the template:
Hello {{name}}
You have just won {{value}} dollars!
{{#in_ca}}
Well, {{taxed_value}} dollars, after taxes.
{{/in_ca}}
This template references our view methods. To bring it all together,
here's the code to render actual HTML;
Simple.render
Which returns the following:
Hello Chris
You have just won 10000 dollars!
Well, 6000.0 dollars, after taxes.
Simple.
Tag Types
---------
For a language-agnostic overview of Mustache's template syntax, see
the `mustache(5)` manpage or
.
Escaping
--------
Mustache does escape all values when using the standard double
Mustache syntax. Characters which will be escaped: `& \ " < >`. To
disable escaping, simply use tripple mustaches like
`{{{unescaped_variable}}}`.
Example: Using `{{variable}}` inside a template for `5 > 2` will
result in `5 > 2`, where as the usage of `{{{variable}}}` will
result in `5 > 2`.
Dict-Style Views
----------------
ctemplate and friends want you to hand a dictionary to the template
processor. Mustache supports a similar concept. Feel free to mix the
class-based and this more procedural style at your leisure.
Given this template (winner.mustache):
Hello {{name}}
You have just won {{value}} bucks!
We can fill in the values at will:
view = Winner.new
view[:name] = 'George'
view[:value] = 100
view.render
Which returns:
Hello George
You have just won 100 bucks!
We can re-use the same object, too:
view[:name] = 'Tony'
view.render
Hello Tony
You have just won 100 bucks!
Templates
---------
A word on templates. By default, a view will try to find its template
on disk by searching for an HTML file in the current directory that
follows the classic Ruby naming convention.
TemplatePartial => ./template_partial.mustache
You can set the search path using `Mustache.template_path`. It can be set on a
class by class basis:
class Simple < Mustache
self.template_path = File.dirname(__FILE__)
... etc ...
end
Now `Simple` will look for `simple.mustache` in the directory it resides
in, no matter the cwd.
If you want to just change what template is used you can set
`Mustache.template_file` directly:
Simple.template_file = './blah.mustache'
Mustache also allows you to define the extension it'll use.
Simple.template_extension = 'xml'
Given all other defaults, the above line will cause Mustache to look
for './blah.xml'
Feel free to set the template directly:
Simple.template = 'Hi {{person}}!'
Or set a different template for a single instance:
Simple.new.template = 'Hi {{person}}!'
Whatever works.
Views
-----
Mustache supports a bit of magic when it comes to views. If you're
authoring a plugin or extension for a web framework (Sinatra, Rails,
etc), check out the `view_namespace` and `view_path` settings on the
`Mustache` class. They will surely provide needed assistance.
Helpers
-------
What about global helpers? Maybe you have a nifty `gravatar` function
you want to use in all your views? No problem.
This is just Ruby, after all.
module ViewHelpers
def gravatar
gravatar_id = Digest::MD5.hexdigest(self[:email].to_s.strip.downcase)
gravatar_for_id(gravatar_id)
end
def gravatar_for_id(gid, size = 30)
"#{gravatar_host}/avatar/#{gid}?s=#{size}"
end
def gravatar_host
@ssl ? 'https://secure.gravatar.com' : 'http://www.gravatar.com'
end
end
Then just include it:
class Simple < Mustache
include ViewHelpers
def name
"Chris"
end
def value
10_000
end
def taxed_value
value * 0.6
end
def in_ca
true
end
def users
User.all
end
end
Great, but what about that `@ssl` ivar in `gravatar_host`? There are
many ways we can go about setting it.
Here's on example which illustrates a key feature of Mustache: you
are free to use the `initialize` method just as you would in any
normal class.
class Simple < Mustache
include ViewHelpers
def initialize(ssl = false)
@ssl = ssl
end
... etc ...
end
Now:
Simple.new(request.ssl?).render
Finally, our template might look like this:
{{# users}}
{{ login }}
{{/ users}}
Sinatra
-------
Mustache ships with Sinatra integration. Please see
`lib/mustache/sinatra.rb` or
for complete documentation.
An example Sinatra application is also provided:
If you are upgrading to Sinatra 1.0 and Mustache 0.9.0+ from Mustache
0.7.0 or lower, the settings have changed. But not that much.
See [this diff](http://gist.github.com/345490) for what you need to
do. Basically, things are named properly now and all should be
contained in a hash set using `set :mustache, hash`.
[Rack::Bug][4]
--------------
Mustache also ships with a `Rack::Bug` panel. In your `config.ru` add
the following code:
require 'rack/bug/panels/mustache_panel'
use Rack::Bug::MustachePanel
Using Rails? Add this to your initializer or environment file:
require 'rack/bug/panels/mustache_panel'
config.middleware.use "Rack::Bug::MustachePanel"
[][5]
Vim
---
Thanks to [Juvenn Woo](http://github.com/juvenn) for mustache.vim. It
is included under the contrib/ directory.
See for installation instructions.
Emacs
-----
mustache-mode.el is included under the contrib/ directory for any
Emacs users. Based on Google's tpl-mode for ctemplates, it adds
support for Mustache's more lenient tag values and includes a few
commands for your editing pleasure.
See for installation instructions.
TextMate
--------
[Mustache.tmbundle](http://github.com/defunkt/Mustache.tmbundle)
See for installation instructions.
Command Line
------------
See `mustache(1)` man page or
for command line docs.
Installation
------------
### [RubyGems](http://rubygems.org/)
$ gem install mustache
Acknowledgements
----------------
Thanks to [Tom Preston-Werner](http://github.com/mojombo) for showing
me ctemplate and [Leah Culver](http://github.com/leah) for the name "Mustache."
Special thanks to [Magnus Holm](http://judofyr.net/) for all his
awesome work on Mustache's parser.
Contributing
------------
Once you've made your great commits:
1. [Fork][fk] Mustache
2. Create a topic branch - `git checkout -b my_branch`
3. Push to your branch - `git push origin my_branch`
4. Create an [Issue][is] with a link to your branch
5. That's it!
You might want to checkout Resque's [Contributing][cb] wiki page for information
on coding standards, new features, etc.
Mailing List
------------
To join the list simply send an email to . This
will subscribe you and send you information about your subscription,
including unsubscribe information.
The archive can be found at .
Meta
----
* Code: `git clone git://github.com/defunkt/mustache.git`
* Home:
* Bugs:
* List:
* Test:
* Gems:
You can also find us in `#{` on irc.freenode.net.
[1]: http://code.google.com/p/google-ctemplate/
[2]: http://www.ivan.fomichev.name/2008/05/erlang-template-engine-prototype.html
[3]: http://google-ctemplate.googlecode.com/svn/trunk/doc/howto.html
[4]: http://github.com/brynary/rack-bug/
[5]: http://img.skitch.com/20091027-n8pxwwx8r61tc318a15q1n6m14.png
[cb]: http://wiki.github.com/defunkt/resque/contributing
[fk]: http://help.github.com/forking/
[is]: http://github.com/defunkt/mustache/issues
mustache-0.99.4/bin/ 0000755 0001750 0001750 00000000000 11643306253 014137 5 ustar virtual virtual mustache-0.99.4/bin/mustache 0000755 0001750 0001750 00000004556 11643306253 015710 0 ustar virtual virtual #!/usr/bin/env ruby
require 'yaml'
require 'optparse'
require 'mustache'
require 'mustache/version'
class Mustache
class CLI
# Return a structure describing the options.
def self.parse_options(args)
opts = OptionParser.new do |opts|
opts.banner = "Usage: mustache [-c] [-t] [-r library] FILE ..."
opts.separator " "
opts.separator "Examples:"
opts.separator " $ mustache data.yml template.mustache"
opts.separator " $ cat data.yml | mustache - template.mustache"
opts.separator " $ mustache -c template.mustache"
opts.separator " "
opts.separator " See mustache(1) or " +
"http://mustache.github.com/mustache.1.html"
opts.separator " for more details."
opts.separator " "
opts.separator "Options:"
opts.on("-c", "--compile FILE",
"Print the compiled Ruby for a given template.") do |file|
puts Mustache::Template.new(File.read(file)).compile
exit
end
opts.on("-t", "--tokens FILE",
"Print the tokenized form of a given template.") do |file|
require 'pp'
pp Mustache::Template.new(File.read(file)).tokens
exit
end
opts.on('-r', '--require LIB', 'Require a Ruby library before running.') do |lib|
require lib
end
opts.separator "Common Options:"
opts.on("-v", "--version", "Print the version") do |v|
puts "Mustache v#{Mustache::Version}"
exit
end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
end
end
opts.separator ""
opts.parse!(args)
end
# Does the dirty work of reading files from STDIN and the command
# line then processing them. The meat of this script, if you will.
def self.process_files(input_stream)
doc = input_stream.read
if doc =~ /^(\s*---(.+)---\s*)/m
yaml = $2.strip
template = doc.sub($1, '')
YAML.each_document(yaml) do |data|
puts Mustache.render(template, data)
end
else
puts Mustache.render(doc)
end
end
end
end
# Help is the default.
ARGV << '-h' if ARGV.empty? && $stdin.tty?
# Process options
Mustache::CLI.parse_options(ARGV) if $stdin.tty?
# Still here - process ARGF
Mustache::CLI.process_files(ARGF)
mustache-0.99.4/LICENSE 0000644 0001750 0001750 00000002043 11643306253 014373 0 ustar virtual virtual Copyright (c) 2009 Chris Wanstrath
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.
mustache-0.99.4/lib/ 0000755 0001750 0001750 00000000000 11643306253 014135 5 ustar virtual virtual mustache-0.99.4/lib/mustache/ 0000755 0001750 0001750 00000000000 11643306253 015746 5 ustar virtual virtual mustache-0.99.4/lib/mustache/generator.rb 0000644 0001750 0001750 00000012727 11643306253 020272 0 ustar virtual virtual class Mustache
# The Generator is in charge of taking an array of Mustache tokens,
# usually assembled by the Parser, and generating an interpolatable
# Ruby string. This string is considered the "compiled" template
# because at that point we're relying on Ruby to do the parsing and
# run our code.
#
# For example, let's take this template:
#
# Hi {{thing}}!
#
# If we run this through the Parser we'll get these tokens:
#
# [:multi,
# [:static, "Hi "],
# [:mustache, :etag, "thing"],
# [:static, "!\n"]]
#
# Now let's hand that to the Generator:
#
# >> puts Mustache::Generator.new.compile(tokens)
# "Hi #{CGI.escapeHTML(ctx[:thing].to_s)}!\n"
#
# You can see the generated Ruby string for any template with the
# mustache(1) command line tool:
#
# $ mustache --compile test.mustache
# "Hi #{CGI.escapeHTML(ctx[:thing].to_s)}!\n"
class Generator
# Options are unused for now but may become useful in the future.
def initialize(options = {})
@options = options
end
# Given an array of tokens, returns an interpolatable Ruby string.
def compile(exp)
"\"#{compile!(exp)}\""
end
# Given an array of tokens, converts them into Ruby code. In
# particular there are three types of expressions we are concerned
# with:
#
# :multi
# Mixed bag of :static, :mustache, and whatever.
#
# :static
# Normal HTML, the stuff outside of {{mustaches}}.
#
# :mustache
# Any Mustache tag, from sections to partials.
#
# To give you an idea of what you'll be dealing with take this
# template:
#
# Hello {{name}}
# You have just won ${{value}}!
# {{#in_ca}}
# Well, ${{taxed_value}}, after taxes.
# {{/in_ca}}
#
# If we run this through the Parser, we'll get back this array of
# tokens:
#
# [:multi,
# [:static, "Hello "],
# [:mustache, :etag, "name"],
# [:static, "\nYou have just won $"],
# [:mustache, :etag, "value"],
# [:static, "!\n"],
# [:mustache,
# :section,
# "in_ca",
# [:multi,
# [:static, "Well, $"],
# [:mustache, :etag, "taxed_value"],
# [:static, ", after taxes.\n"]]]]
def compile!(exp)
case exp.first
when :multi
exp[1..-1].map { |e| compile!(e) }.join
when :static
str(exp[1])
when :mustache
send("on_#{exp[1]}", *exp[2..-1])
else
raise "Unhandled exp: #{exp.first}"
end
end
# Callback fired when the compiler finds a section token. We're
# passed the section name and the array of tokens.
def on_section(name, content, raw, delims)
# Convert the tokenized content of this section into a Ruby
# string we can use.
code = compile(content)
# Compile the Ruby for this section now that we know what's
# inside the section.
ev(<<-compiled)
if v = #{compile!(name)}
if v == true
#{code}
elsif v.is_a?(Proc)
t = Mustache::Template.new(v.call(#{raw.inspect}).to_s)
def t.tokens(src=@source)
p = Parser.new
p.otag, p.ctag = #{delims.inspect}
p.compile(src)
end
t.render(ctx.dup)
else
# Shortcut when passed non-array
v = [v] unless v.is_a?(Array) || defined?(Enumerator) && v.is_a?(Enumerator)
v.map { |h| ctx.push(h); r = #{code}; ctx.pop; r }.join
end
end
compiled
end
# Fired when we find an inverted section. Just like `on_section`,
# we're passed the inverted section name and the array of tokens.
def on_inverted_section(name, content, raw, _)
# Convert the tokenized content of this section into a Ruby
# string we can use.
code = compile(content)
# Compile the Ruby for this inverted section now that we know
# what's inside.
ev(<<-compiled)
v = #{compile!(name)}
if v.nil? || v == false || v.respond_to?(:empty?) && v.empty?
#{code}
end
compiled
end
# Fired when the compiler finds a partial. We want to return code
# which calls a partial at runtime instead of expanding and
# including the partial's body to allow for recursive partials.
def on_partial(name, indentation)
ev("ctx.partial(#{name.to_sym.inspect}, #{indentation.inspect})")
end
# An unescaped tag.
def on_utag(name)
ev(<<-compiled)
v = #{compile!(name)}
if v.is_a?(Proc)
v = Mustache::Template.new(v.call.to_s).render(ctx.dup)
end
v.to_s
compiled
end
# An escaped tag.
def on_etag(name)
ev(<<-compiled)
v = #{compile!(name)}
if v.is_a?(Proc)
v = Mustache::Template.new(v.call.to_s).render(ctx.dup)
end
ctx.escapeHTML(v.to_s)
compiled
end
def on_fetch(names)
names = names.map { |n| n.to_sym }
if names.length == 0
"ctx[:to_s]"
elsif names.length == 1
"ctx[#{names.first.to_sym.inspect}]"
else
initial, *rest = names
<<-compiled
#{rest.inspect}.inject(ctx[#{initial.inspect}]) { |value, key|
value && ctx.find(value, key)
}
compiled
end
end
# An interpolation-friendly version of a string, for use within a
# Ruby string.
def ev(s)
"#\{#{s}}"
end
def str(s)
s.inspect[1..-2]
end
end
end
mustache-0.99.4/lib/mustache/version.rb 0000644 0001750 0001750 00000000062 11643306253 017756 0 ustar virtual virtual class Mustache
Version = VERSION = '0.99.4'
end
mustache-0.99.4/lib/mustache/parser.rb 0000644 0001750 0001750 00000017762 11643306253 017604 0 ustar virtual virtual require 'strscan'
class Mustache
# The Parser is responsible for taking a string template and
# converting it into an array of tokens and, really, expressions. It
# raises SyntaxError if there is anything it doesn't understand and
# knows which sigil corresponds to which tag type.
#
# For example, given this template:
#
# Hi {{thing}}!
#
# Run through the Parser we'll get these tokens:
#
# [:multi,
# [:static, "Hi "],
# [:mustache, :etag, "thing"],
# [:static, "!\n"]]
#
# You can see the array of tokens for any template with the
# mustache(1) command line tool:
#
# $ mustache --tokens test.mustache
# [:multi, [:static, "Hi "], [:mustache, :etag, "thing"], [:static, "!\n"]]
class Parser
# A SyntaxError is raised when the Parser comes across unclosed
# tags, sections, illegal content in tags, or anything of that
# sort.
class SyntaxError < StandardError
def initialize(message, position)
@message = message
@lineno, @column, @line, _ = position
@stripped_line = @line.strip
@stripped_column = @column - (@line.size - @line.lstrip.size)
end
def to_s
<<-EOF
#{@message}
Line #{@lineno}
#{@stripped_line}
#{' ' * @stripped_column}^
EOF
end
end
# After these types of tags, all whitespace until the end of the line will
# be skipped if they are the first (and only) non-whitespace content on
# the line.
SKIP_WHITESPACE = [ '#', '^', '/', '<', '>', '=', '!' ]
# The content allowed in a tag name.
ALLOWED_CONTENT = /(\w|[?!\/.-])*/
# These types of tags allow any content,
# the rest only allow ALLOWED_CONTENT.
ANY_CONTENT = [ '!', '=' ]
attr_reader :scanner, :result
attr_writer :otag, :ctag
# Accepts an options hash which does nothing but may be used in
# the future.
def initialize(options = {})
@options = {}
end
# The opening tag delimiter. This may be changed at runtime.
def otag
@otag ||= '{{'
end
# The closing tag delimiter. This too may be changed at runtime.
def ctag
@ctag ||= '}}'
end
# Given a string template, returns an array of tokens.
def compile(template)
if template.respond_to?(:encoding)
@encoding = template.encoding
template = template.dup.force_encoding("BINARY")
else
@encoding = nil
end
# Keeps information about opened sections.
@sections = []
@result = [:multi]
@scanner = StringScanner.new(template)
# Scan until the end of the template.
until @scanner.eos?
scan_tags || scan_text
end
if !@sections.empty?
# We have parsed the whole file, but there's still opened sections.
type, pos, result = @sections.pop
error "Unclosed section #{type.inspect}", pos
end
@result
end
# Find {{mustaches}} and add them to the @result array.
def scan_tags
# Scan until we hit an opening delimiter.
start_of_line = @scanner.beginning_of_line?
pre_match_position = @scanner.pos
last_index = @result.length
return unless x = @scanner.scan(/([ \t]*)?#{Regexp.escape(otag)}/)
padding = @scanner[1] || ''
# Don't touch the preceding whitespace unless we're matching the start
# of a new line.
unless start_of_line
@result << [:static, padding] unless padding.empty?
pre_match_position += padding.length
padding = ''
end
# Since {{= rewrites ctag, we store the ctag which should be used
# when parsing this specific tag.
current_ctag = self.ctag
type = @scanner.scan(/#|\^|\/|=|!|<|>|&|\{/)
@scanner.skip(/\s*/)
# ANY_CONTENT tags allow any character inside of them, while
# other tags (such as variables) are more strict.
if ANY_CONTENT.include?(type)
r = /\s*#{regexp(type)}?#{regexp(current_ctag)}/
content = scan_until_exclusive(r)
else
content = @scanner.scan(ALLOWED_CONTENT)
end
# We found {{ but we can't figure out what's going on inside.
error "Illegal content in tag" if content.empty?
fetch = [:mustache, :fetch, content.split('.')]
prev = @result
# Based on the sigil, do what needs to be done.
case type
when '#'
block = [:multi]
@result << [:mustache, :section, fetch, block]
@sections << [content, position, @result]
@result = block
when '^'
block = [:multi]
@result << [:mustache, :inverted_section, fetch, block]
@sections << [content, position, @result]
@result = block
when '/'
section, pos, result = @sections.pop
raw = @scanner.pre_match[pos[3]...pre_match_position] + padding
(@result = result).last << raw << [self.otag, self.ctag]
if section.nil?
error "Closing unopened #{content.inspect}"
elsif section != content
error "Unclosed section #{section.inspect}", pos
end
when '!'
# ignore comments
when '='
self.otag, self.ctag = content.split(' ', 2)
when '>', '<'
@result << [:mustache, :partial, content, padding]
when '{', '&'
# The closing } in unescaped tags is just a hack for
# aesthetics.
type = "}" if type == "{"
@result << [:mustache, :utag, fetch]
else
@result << [:mustache, :etag, fetch]
end
# Skip whitespace and any balancing sigils after the content
# inside this tag.
@scanner.skip(/\s+/)
@scanner.skip(regexp(type)) if type
# Try to find the closing tag.
unless close = @scanner.scan(regexp(current_ctag))
error "Unclosed tag"
end
# If this tag was the only non-whitespace content on this line, strip
# the remaining whitespace. If not, but we've been hanging on to padding
# from the beginning of the line, re-insert the padding as static text.
if start_of_line && !@scanner.eos?
if @scanner.peek(2) =~ /\r?\n/ && SKIP_WHITESPACE.include?(type)
@scanner.skip(/\r?\n/)
else
prev.insert(last_index, [:static, padding]) unless padding.empty?
end
end
# Store off the current scanner position now that we've closed the tag
# and consumed any irrelevant whitespace.
@sections.last[1] << @scanner.pos unless @sections.empty?
return unless @result == [:multi]
end
# Try to find static text, e.g. raw HTML with no {{mustaches}}.
def scan_text
text = scan_until_exclusive(/(^[ \t]*)?#{Regexp.escape(otag)}/)
if text.nil?
# Couldn't find any otag, which means the rest is just static text.
text = @scanner.rest
# Mark as done.
@scanner.terminate
end
text.force_encoding(@encoding) if @encoding
@result << [:static, text] unless text.empty?
end
# Scans the string until the pattern is matched. Returns the substring
# *excluding* the end of the match, advancing the scan pointer to that
# location. If there is no match, nil is returned.
def scan_until_exclusive(regexp)
pos = @scanner.pos
if @scanner.scan_until(regexp)
@scanner.pos -= @scanner.matched.size
@scanner.pre_match[pos..-1]
end
end
# Returns [lineno, column, line]
def position
# The rest of the current line
rest = @scanner.check_until(/\n|\Z/).to_s.chomp
# What we have parsed so far
parsed = @scanner.string[0...@scanner.pos]
lines = parsed.split("\n")
[ lines.size, lines.last.size - 1, lines.last + rest ]
end
# Used to quickly convert a string into a regular expression
# usable by the string scanner.
def regexp(thing)
/#{Regexp.escape(thing)}/
end
# Raises a SyntaxError. The message should be the name of the
# error - other details such as line number and position are
# handled for you.
def error(message, pos = position)
raise SyntaxError.new(message, pos)
end
end
end
mustache-0.99.4/lib/mustache/settings.rb 0000644 0001750 0001750 00000012334 11643306253 020136 0 ustar virtual virtual # Settings which can be configured for all view classes, a single
# view class, or a single Mustache instance.
class Mustache
#
# Template Path
#
# The template path informs your Mustache view where to look for its
# corresponding template. By default it's the current directory (".")
#
# A class named Stat with a template_path of "app/templates" will look
# for "app/templates/stat.mustache"
def self.template_path
@template_path ||= inheritable_config_for :template_path, '.'
end
def self.template_path=(path)
@template_path = File.expand_path(path)
@template = nil
end
def template_path
@template_path ||= self.class.template_path
end
def template_path=(path)
@template_path = File.expand_path(path)
@template = nil
end
# Alias for `template_path`
def self.path
template_path
end
alias_method :path, :template_path
# Alias for `template_path`
def self.path=(path)
self.template_path = path
end
alias_method :path=, :template_path=
#
# Template Extension
#
# A Mustache template's default extension is 'mustache', but this can be changed.
def self.template_extension
@template_extension ||= inheritable_config_for :template_extension, 'mustache'
end
def self.template_extension=(template_extension)
@template_extension = template_extension
@template = nil
end
def template_extension
@template_extension ||= self.class.template_extension
end
def template_extension=(template_extension)
@template_extension = template_extension
@template = nil
end
#
# Template Name
#
# The template name is the Mustache template file without any
# extension or other information. Defaults to `class_name`.
#
# You may want to change this if your class is named Stat but you want
# to re-use another template.
#
# class Stat
# self.template_name = "graphs" # use graphs.mustache
# end
def self.template_name
@template_name || underscore
end
def self.template_name=(template_name)
@template_name = template_name
@template = nil
end
def template_name
@template_name ||= self.class.template_name
end
def template_name=(template_name)
@template_name = template_name
@template = nil
end
#
# Template File
#
# The template file is the absolute path of the file Mustache will
# use as its template. By default it's ./class_name.mustache
def self.template_file
@template_file || "#{path}/#{template_name}.#{template_extension}"
end
def self.template_file=(template_file)
@template_file = template_file
@template = nil
end
# The template file is the absolute path of the file Mustache will
# use as its template. By default it's ./class_name.mustache
def template_file
@template_file || "#{path}/#{template_name}.#{template_extension}"
end
def template_file=(template_file)
@template_file = template_file
@template = nil
end
#
# Template
#
# The template is the actual string Mustache uses as its template.
# There is a bit of magic here: what we get back is actually a
# Mustache::Template object, but you can still safely use `template=`
# with a string.
def self.template
@template ||= templateify(File.read(template_file))
end
def self.template=(template)
@template = templateify(template)
end
# The template can be set at the instance level.
def template
return @template if @template
# If they sent any instance-level options use that instead of the class's.
if @template_path || @template_extension || @template_name || @template_file
@template = templateify(File.read(template_file))
else
@template = self.class.template
end
end
def template=(template)
@template = templateify(template)
end
#
# Raise on context miss
#
# Should an exception be raised when we cannot find a corresponding method
# or key in the current context? By default this is false to emulate ctemplate's
# behavior, but it may be useful to enable when debugging or developing.
#
# If set to true and there is a context miss, `Mustache::ContextMiss` will
# be raised.
def self.raise_on_context_miss?
@raise_on_context_miss
end
def self.raise_on_context_miss=(boolean)
@raise_on_context_miss = boolean
end
# Instance level version of `Mustache.raise_on_context_miss?`
def raise_on_context_miss?
self.class.raise_on_context_miss? || @raise_on_context_miss
end
def raise_on_context_miss=(boolean)
@raise_on_context_miss = boolean
end
#
# View Namespace
#
# The constant under which Mustache will look for views when autoloading.
# By default the view namespace is `Object`, but it might be nice to set
# it to something like `Hurl::Views` if your app's main namespace is `Hurl`.
def self.view_namespace
@view_namespace ||= inheritable_config_for(:view_namespace, Object)
end
def self.view_namespace=(namespace)
@view_namespace = namespace
end
#
# View Path
#
# Mustache searches the view path for .rb files to require when asked to find a
# view class. Defaults to "."
def self.view_path
@view_path ||= inheritable_config_for(:view_path, '.')
end
def self.view_path=(path)
@view_path = path
end
end
mustache-0.99.4/lib/mustache/context.rb 0000644 0001750 0001750 00000010335 11643306253 017761 0 ustar virtual virtual class Mustache
# A ContextMiss is raised whenever a tag's target can not be found
# in the current context if `Mustache#raise_on_context_miss?` is
# set to true.
#
# For example, if your View class does not respond to `music` but
# your template contains a `{{music}}` tag this exception will be raised.
#
# By default it is not raised. See Mustache.raise_on_context_miss.
class ContextMiss < RuntimeError; end
# A Context represents the context which a Mustache template is
# executed within. All Mustache tags reference keys in the Context.
class Context
# Expect to be passed an instance of `Mustache`.
def initialize(mustache)
@stack = [mustache]
end
# A {{>partial}} tag translates into a call to the context's
# `partial` method, which would be this sucker right here.
#
# If the Mustache view handling the rendering (e.g. the view
# representing your profile page or some other template) responds
# to `partial`, we call it and render the result.
def partial(name, indentation = '')
# Look for the first Mustache in the stack.
mustache = mustache_in_stack
# Indent the partial template by the given indentation.
part = mustache.partial(name).to_s.gsub(/^/, indentation)
# Call the Mustache's `partial` method and render the result.
result = mustache.render(part, self)
end
# Find the first Mustache in the stack. If we're being rendered
# inside a Mustache object as a context, we'll use that one.
def mustache_in_stack
@stack.detect { |frame| frame.is_a?(Mustache) }
end
# Allows customization of how Mustache escapes things.
#
# Returns a String.
def escapeHTML(str)
mustache_in_stack.escapeHTML(str)
end
# Adds a new object to the context's internal stack.
#
# Returns the Context.
def push(new)
@stack.unshift(new)
self
end
alias_method :update, :push
# Removes the most recently added object from the context's
# internal stack.
#
# Returns the Context.
def pop
@stack.shift
self
end
# Can be used to add a value to the context in a hash-like way.
#
# context[:name] = "Chris"
def []=(name, value)
push(name => value)
end
# Alias for `fetch`.
def [](name)
fetch(name, nil)
end
# Do we know about a particular key? In other words, will calling
# `context[key]` give us a result that was set. Basically.
def has_key?(key)
!!fetch(key)
rescue ContextMiss
false
end
# Similar to Hash#fetch, finds a value by `name` in the context's
# stack. You may specify the default return value by passing a
# second parameter.
#
# If no second parameter is passed (or raise_on_context_miss is
# set to true), will raise a ContextMiss exception on miss.
def fetch(name, default = :__raise)
@stack.each do |frame|
# Prevent infinite recursion.
next if frame == self
value = find(frame, name, :__missing)
if value != :__missing
return value
end
end
if default == :__raise || mustache_in_stack.raise_on_context_miss?
raise ContextMiss.new("Can't find #{name} in #{@stack.inspect}")
else
default
end
end
# Finds a key in an object, using whatever method is most
# appropriate. If the object is a hash, does a simple hash lookup.
# If it's an object that responds to the key as a method call,
# invokes that method. You get the idea.
#
# obj - The object to perform the lookup on.
# key - The key whose value you want.
# default - An optional default value, to return if the
# key is not found.
#
# Returns the value of key in obj if it is found and default otherwise.
def find(obj, key, default = nil)
hash = obj.respond_to?(:has_key?)
if hash && obj.has_key?(key)
obj[key]
elsif hash && obj.has_key?(key.to_s)
obj[key.to_s]
elsif !hash && obj.respond_to?(key)
meth = obj.method(key) rescue proc { obj.send(key) }
if meth.arity == 1
meth.to_proc
else
meth[]
end
else
default
end
end
end
end
mustache-0.99.4/lib/mustache/template.rb 0000644 0001750 0001750 00000003450 11643306253 020110 0 ustar virtual virtual require 'cgi'
require 'mustache/parser'
require 'mustache/generator'
class Mustache
# A Template represents a Mustache template. It compiles and caches
# a raw string template into something usable.
#
# The idea is this: when handed a Mustache template, convert it into
# a Ruby string by transforming Mustache tags into interpolated
# Ruby.
#
# You shouldn't use this class directly, instead:
#
# >> Mustache.render(template, hash)
class Template
attr_reader :source
# Expects a Mustache template as a string along with a template
# path, which it uses to find partials.
def initialize(source)
@source = source
end
# Renders the `@source` Mustache template using the given
# `context`, which should be a simple hash keyed with symbols.
#
# The first time a template is rendered, this method is overriden
# and from then on it is "compiled". Subsequent calls will skip
# the compilation step and run the Ruby version of the template
# directly.
def render(context)
# Compile our Mustache template into a Ruby string
compiled = "def render(ctx) #{compile} end"
# Here we rewrite ourself with the interpolated Ruby version of
# our Mustache template so subsequent calls are very fast and
# can skip the compilation stage.
instance_eval(compiled, __FILE__, __LINE__ - 1)
# Call the newly rewritten version of #render
render(context)
end
# Does the dirty work of transforming a Mustache template into an
# interpolation-friendly Ruby string.
def compile(src = @source)
Generator.new.compile(tokens(src))
end
alias_method :to_s, :compile
# Returns an array of tokens for a given template.
def tokens(src = @source)
Parser.new.compile(src)
end
end
end
mustache-0.99.4/lib/mustache/sinatra.rb 0000644 0001750 0001750 00000015022 11643306253 017734 0 ustar virtual virtual require 'sinatra/base'
require 'mustache'
class Mustache
# Support for Mustache in your Sinatra app.
#
# require 'mustache/sinatra'
#
# class Hurl < Sinatra::Base
# register Mustache::Sinatra
#
# set :mustache, {
# # Should be the path to your .mustache template files.
# :templates => "path/to/mustache/templates",
#
# # Should be the path to your .rb Mustache view files.
# :views => "path/to/mustache/views",
#
# # This tells Mustache where to look for the Views module,
# # under which your View classes should live. By default it's
# # the class of your app - in this case `Hurl`. That is, for an :index
# # view Mustache will expect Hurl::Views::Index by default.
# # If our Sinatra::Base subclass was instead Hurl::App,
# # we'd want to do `set :namespace, Hurl::App`
# :namespace => Hurl
# }
#
# get '/stats' do
# mustache :stats
# end
# end
#
# As noted above, Mustache will look for `Hurl::Views::Index` when
# `mustache :index` is called.
#
# If no `Views::Stats` class exists Mustache will render the template
# file directly.
#
# You can indeed use layouts with this library. Where you'd normally
# <%= yield %> you instead {{{yield}}} - the body of the subview is
# set to the `yield` variable and made available to you.
module Sinatra
module Helpers
# Call this in your Sinatra routes.
def mustache(template, options={}, locals={})
# Locals can be passed as options under the :locals key.
locals.update(options.delete(:locals) || {})
# Grab any user-defined settings.
if settings.respond_to?(:mustache)
options = settings.send(:mustache).merge(options)
end
# If they aren't explicitly disabling layouts, try to find
# one.
if options[:layout] != false
# Let the user pass in a layout name.
layout_name = options[:layout]
# If all they said was `true` (or nothing), default to :layout.
layout_name = :layout if layout_name == true || !layout_name
# If they passed a layout name use that.
layout = mustache_class(layout_name, options)
# If it's just an anonymous subclass then don't bother, otherwise
# give us a layout instance.
if layout.name && layout.name.empty?
layout = nil
else
layout = layout.new
end
end
# Find and cache the view class we want. This ensures the
# compiled template is cached, too - no looking up and
# compiling templates on each page load.
klass = mustache_class(template, options)
# Does the view subclass the layout? If so we'll use the
# view to render the layout so you can override layout
# methods in your view - tricky.
view_subclasses_layout = klass < layout.class if layout
# Create a new instance for playing with.
instance = klass.new
# Copy instance variables set in Sinatra to the view
instance_variables.each do |name|
instance.instance_variable_set(name, instance_variable_get(name))
end
# Render with locals.
rendered = instance.render(instance.template, locals)
# Now render the layout with the view we just rendered, if we
# need to.
if layout && view_subclasses_layout
rendered = instance.render(layout.template, :yield => rendered)
elsif layout
rendered = layout.render(layout.template, :yield => rendered)
end
# That's it.
rendered
end
# Returns a View class for a given template name.
def mustache_class(template, options = {})
@template_cache.fetch(:mustache, template) do
compile_mustache(template, options)
end
end
# Given a view name and settings, finds and prepares an
# appropriate view class for this view.
def compile_mustache(view, options = {})
options[:templates] ||= settings.views if settings.respond_to?(:views)
options[:namespace] ||= self.class
unless options[:namespace].to_s.include? 'Views'
options[:namespace] = options[:namespace].const_get(:Views)
end
factory = Class.new(Mustache) do
self.view_namespace = options[:namespace]
self.view_path = options[:views]
end
# If we were handed :"positions.atom" or some such as the
# template name, we need to remember the extension.
if view.to_s.include?('.')
view, ext = view.to_s.split('.')
end
# Try to find the view class for a given view, e.g.
# :view => Hurl::Views::Index.
klass = factory.view_class(view)
klass.view_namespace = options[:namespace]
klass.view_path = options[:views]
# If there is no view class, issue a warning and use the one
# we just generated to cache the compiled template.
if klass == Mustache
warn "No view class found for #{view} in #{factory.view_path}"
klass = factory
# If this is a generic view class make sure we set the
# template name as it was given. That is, an anonymous
# subclass of Mustache won't know how to find the
# "index.mustache" template unless we tell it to.
klass.template_name = view.to_s
elsif ext
# We got an ext (like "atom"), so look for an "Atom" class
# under the current View's namespace.
#
# So if our template was "positions.atom", try to find
# Positions::Atom.
if klass.const_defined?(ext_class = ext.capitalize)
# Found Positions::Atom - set it
klass = klass.const_get(ext_class)
else
# Didn't find Positions::Atom - create it by creating an
# anonymous subclass of Positions and setting that to
# Positions::Atom.
new_class = Class.new(klass)
new_class.template_name = "#{view}.#{ext}"
klass.const_set(ext_class, new_class)
klass = new_class
end
end
# Set the template path and return our class.
klass.template_path = options[:templates] if options[:templates]
klass
end
end
# Called when you `register Mustache::Sinatra` in your Sinatra app.
def self.registered(app)
app.helpers Mustache::Sinatra::Helpers
end
end
end
Sinatra.register Mustache::Sinatra
mustache-0.99.4/lib/rack/ 0000755 0001750 0001750 00000000000 11643306253 015055 5 ustar virtual virtual mustache-0.99.4/lib/rack/bug/ 0000755 0001750 0001750 00000000000 11643306253 015632 5 ustar virtual virtual mustache-0.99.4/lib/rack/bug/panels/ 0000755 0001750 0001750 00000000000 11643306253 017114 5 ustar virtual virtual mustache-0.99.4/lib/rack/bug/panels/mustache_panel.rb 0000644 0001750 0001750 00000004551 11643306253 022436 0 ustar virtual virtual module Rack
module Bug
# MustachePanel is a Rack::Bug panel which tracks the time spent rendering
# Mustache views as well as all the variables accessed during view
# rendering.
#
# It can be used to track down slow partials and ensure you're only
# generating data you need.
#
# Also, it's fun.
class MustachePanel < Panel
require "rack/bug/panels/mustache_panel/mustache_extension"
# The view is responsible for rendering our panel. While Rack::Bug
# takes care of the nav, the content rendered by View is used for
# the panel itself.
class View < Mustache
self.path = ::File.dirname(__FILE__) + '/mustache_panel'
# We track the render times of all the Mustache views on this
# page load.
def times
MustachePanel.times.map do |key, value|
{ :key => key, :value => value }
end
end
# Any variables used in this page load are collected and displayed.
def variables
vars = MustachePanel.variables.sort_by { |key, _| key.to_s }
vars.map do |key, value|
# Arrays can get too huge. Just show the first 10 to give you
# some idea.
if value.is_a?(Array) && value.size > 10
size = value.size
value = value.first(10)
value << "...and #{size - 10} more"
end
{ :key => key, :value => value.inspect }
end
end
end
# Clear out our page load-specific variables.
def self.reset
Thread.current["rack.bug.mustache.times"] = {}
Thread.current["rack.bug.mustache.vars"] = {}
end
# The view render times for this page load
def self.times
Thread.current["rack.bug.mustache.times"] ||= {}
end
# The variables used on this page load
def self.variables
Thread.current["rack.bug.mustache.vars"] ||= {}
end
# The name of this Rack::Bug panel
def name
"mustache"
end
# The string used for our tab in Rack::Bug's navigation bar
def heading
"{{%.2fms}}" % self.class.times.values.inject(0.0) do |sum, obj|
sum + obj
end
end
# The content of our Rack::Bug panel
def content
View.render
ensure
self.class.reset
end
end
end
end
mustache-0.99.4/lib/rack/bug/panels/mustache_panel/ 0000755 0001750 0001750 00000000000 11643306253 022104 5 ustar virtual virtual mustache-0.99.4/lib/rack/bug/panels/mustache_panel/mustache_extension.rb 0000644 0001750 0001750 00000001157 11643306253 026342 0 ustar virtual virtual if defined? Mustache
require 'benchmark'
Mustache.class_eval do
alias_method :real_render, :render
def render(*args, &block)
out = ''
Rack::Bug::MustachePanel.times[self.class.name] = Benchmark.realtime do
out = real_render(*args, &block)
end
out
end
alias_method :to_html, :render
alias_method :to_text, :render
end
Mustache::Context.class_eval do
alias_method :real_get, :[]
def [](name)
return real_get(name) if name == :yield || !@mustache.respond_to?(name)
Rack::Bug::MustachePanel.variables[name] = real_get(name)
end
end
end
mustache-0.99.4/lib/rack/bug/panels/mustache_panel/view.mustache 0000644 0001750 0001750 00000001362 11643306253 024613 0 ustar virtual virtual
Render Times
| View |
Render Time |
{{# times }}
| {{ key }} |
{{ value }} |
{{/ times }}
Variables
| Name |
Value |
{{# variables }}
| {{ key }} |
{{ value }} |
{{/ variables }}
mustache-0.99.4/lib/mustache.rb 0000644 0001750 0001750 00000020454 11643306253 016300 0 ustar virtual virtual require 'mustache/template'
require 'mustache/context'
require 'mustache/settings'
# Mustache is the base class from which your Mustache subclasses
# should inherit (though it can be used on its own).
#
# The typical Mustache workflow is as follows:
#
# * Create a Mustache subclass: class Stats < Mustache
# * Create a template: stats.mustache
# * Instantiate an instance: view = Stats.new
# * Render that instance: view.render
#
# You can skip the instantiation by calling `Stats.render` directly.
#
# While Mustache will do its best to load and render a template for
# you, this process is completely customizable using a few options.
#
# All settings can be overriden at the class level.
#
# For example, going with the above example, we can use
# `Stats.template_path = "/usr/local/templates"` to specify the path
# Mustache uses to find templates.
#
# Here are the available options:
#
# * template_path
#
# The `template_path` setting determines the path Mustache uses when
# looking for a template. By default it is "."
# Setting it to /usr/local/templates, for example, means (given all
# other settings are default) a Mustache subclass `Stats` will try to
# load /usr/local/templates/stats.mustache
#
# * template_extension
#
# The `template_extension` is the extension Mustache uses when looking
# for template files. By default it is "mustache"
#
# * template_file
#
# You can tell Mustache exactly which template to us with this
# setting. It can be a relative or absolute path.
#
# * template
#
# Sometimes you want Mustache to render a string, not a file. In those
# cases you may set the `template` setting. For example:
#
# >> Mustache.render("Hello {{planet}}", :planet => "World!")
# => "Hello World!"
#
# The `template` setting is also available on instances.
#
# view = Mustache.new
# view.template = "Hi, {{person}}!"
# view[:person] = 'Mom'
# view.render # => Hi, mom!
#
# * view_namespace
#
# To make life easy on those developing Mustache plugins for web frameworks or
# other libraries, Mustache will attempt to load view classes (i.e. Mustache
# subclasses) using the `view_class` class method. The `view_namespace` tells
# Mustache under which constant view classes live. By default it is `Object`.
#
# * view_path
#
# Similar to `template_path`, the `view_path` option tells Mustache where to look
# for files containing view classes when using the `view_class` method.
#
class Mustache
#
# Public API
#
# Instantiates an instance of this class and calls `render` with
# the passed args.
#
# Returns a rendered String version of a template
def self.render(*args)
new.render(*args)
end
class << self
alias_method :to_html, :render
alias_method :to_text, :render
end
# Parses our fancy pants template file and returns normal file with
# all special {{tags}} and {{#sections}}replaced{{/sections}}.
#
# data - A String template or a Hash context. If a Hash is given,
# we'll try to figure out the template from the class.
# ctx - A Hash context if `data` is a String template.
#
# Examples
#
# @view.render("Hi {{thing}}!", :thing => :world)
#
# View.template = "Hi {{thing}}!"
# @view = View.new
# @view.render(:thing => :world)
#
# Returns a rendered String version of a template
def render(data = template, ctx = {})
if data.is_a? Hash
ctx = data
tpl = templateify(template)
elsif data.is_a? Symbol
self.template_name = data
tpl = templateify(template)
else
tpl = templateify(data)
end
return tpl.render(context) if ctx == {}
begin
context.push(ctx)
tpl.render(context)
ensure
context.pop
end
end
alias_method :to_html, :render
alias_method :to_text, :render
# Context accessors.
#
# view = Mustache.new
# view[:name] = "Jon"
# view.template = "Hi, {{name}}!"
# view.render # => "Hi, Jon!"
def [](key)
context[key.to_sym]
end
def []=(key, value)
context[key.to_sym] = value
end
# A helper method which gives access to the context at a given time.
# Kind of a hack for now, but useful when you're in an iterating section
# and want access to the hash currently being iterated over.
def context
@context ||= Context.new(self)
end
# Given a file name and an optional context, attempts to load and
# render the file as a template.
def self.render_file(name, context = {})
render(partial(name), context)
end
# Given a file name and an optional context, attempts to load and
# render the file as a template.
def render_file(name, context = {})
self.class.render_file(name, context)
end
# Given a name, attempts to read a file and return the contents as a
# string. The file is not rendered, so it might contain
# {{mustaches}}.
#
# Call `render` if you need to process it.
def self.partial(name)
File.read("#{template_path}/#{name}.#{template_extension}")
end
# Override this in your subclass if you want to do fun things like
# reading templates from a database. It will be rendered by the
# context, so all you need to do is return a string.
def partial(name)
self.class.partial(name)
end
# Override this to provide custom escaping.
#
# class PersonView < Mustache
# def escapeHTML(str)
# my_html_escape_method(str)
# end
# end
#
# Returns a String
def escapeHTML(str)
CGI.escapeHTML(str)
end
#
# Private API
#
# When given a symbol or string representing a class, will try to produce an
# appropriate view class.
# e.g.
# Mustache.view_namespace = Hurl::Views
# Mustache.view_class(:Partial) # => Hurl::Views::Partial
def self.view_class(name)
if name != classify(name.to_s)
name = classify(name.to_s)
end
# Emptiness begets emptiness.
if name.to_s == ''
return Mustache
end
file_name = underscore(name)
name = "#{view_namespace}::#{name}"
if const = const_get!(name)
const
elsif File.exists?(file = "#{view_path}/#{file_name}.rb")
require "#{file}".chomp('.rb')
const_get!(name) || Mustache
else
Mustache
end
end
# Supercharged version of Module#const_get.
#
# Always searches under Object and can find constants by their full name,
# e.g. Mustache::Views::Index
#
# name - The full constant name to find.
#
# Returns the constant if found
# Returns nil if nothing is found
def self.const_get!(name)
name.split('::').inject(Object) do |klass, name|
klass.const_get(name)
end
rescue NameError
nil
end
# Has this template already been compiled? Compilation is somewhat
# expensive so it may be useful to check this before attempting it.
def self.compiled?
@template.is_a? Template
end
# Has this instance or its class already compiled a template?
def compiled?
(@template && @template.is_a?(Template)) || self.class.compiled?
end
# template_partial => TemplatePartial
# template/partial => Template::Partial
def self.classify(underscored)
underscored.split('/').map do |namespace|
namespace.split(/[-_]/).map do |part|
part[0] = part[0].chr.upcase; part
end.join
end.join('::')
end
# TemplatePartial => template_partial
# Template::Partial => template/partial
# Takes a string but defaults to using the current class' name.
def self.underscore(classified = name)
classified = name if classified.to_s.empty?
classified = superclass.name if classified.to_s.empty?
string = classified.dup.split("#{view_namespace}::").last
string.split('::').map do |part|
part[0] = part[0].chr.downcase
part.gsub(/[A-Z]/) { |s| "_#{s.downcase}"}
end.join('/')
end
# Turns a string into a Mustache::Template. If passed a Template,
# returns it.
def self.templateify(obj)
if obj.is_a?(Template)
obj
else
Template.new(obj.to_s)
end
end
def templateify(obj)
self.class.templateify(obj)
end
# Return the value of the configuration setting on the superclass, or return
# the default.
#
# attr_name - Symbol name of the attribute. It should match the instance variable.
# default - Default value to use if the superclass does not respond.
#
# Returns the inherited or default configuration setting.
def self.inheritable_config_for(attr_name, default)
superclass.respond_to?(attr_name) ? superclass.send(attr_name) : default
end
end
mustache-0.99.4/man/ 0000755 0001750 0001750 00000000000 11643306253 014142 5 ustar virtual virtual mustache-0.99.4/man/mustache.1 0000644 0001750 0001750 00000005726 11643306253 016047 0 ustar virtual virtual .\" generated with Ronn/v0.5
.\" http://github.com/rtomayko/ronn/
.
.TH "MUSTACHE" "1" "May 2010" "DEFUNKT" "Mustache Manual"
.
.SH "NAME"
\fBmustache\fR \-\- Mustache processor
.
.SH "SYNOPSIS"
.
.nf
mustache
mustache \-\-compile
mustache \-\-tokens
.
.fi
.
.SH "DESCRIPTION"
Mustache is a logic\-less templating system for HTML, config files,
anything.
.
.P
The \fBmustache\fR command processes a Mustache template preceded by YAML
frontmatter from standard input and prints one or more documents to
standard output.
.
.P
YAML frontmatter beings with \fB\-\-\-\fR on a single line, followed by YAML,
ending with another \fB\-\-\-\fR on a single line, e.g.
.
.IP "" 4
.
.nf
\-\-\-
names: [ {name: chris}, {name: mark}, {name: scott} ]
\-\-\-
.
.fi
.
.IP "" 0
.
.P
If you are unfamiliar with YAML, it is a superset of JSON. Valid JSON
should work fine.
.
.P
After the frontmatter should come any valid Mustache template. See
mustache(5) for an overview of Mustache templates.
.
.P
For example:
.
.IP "" 4
.
.nf
{{#names}}
Hi {{name}}!
{{/names}}
.
.fi
.
.IP "" 0
.
.P
Now let's combine them.
.
.IP "" 4
.
.nf
$ cat data.yml
\-\-\-
names: [ {name: chris}, {name: mark}, {name: scott} ]
\-\-\-
$ cat template.mustache
{{#names}}
Hi {{name}}!
{{/names}}
$ cat data.yml template.mustache | mustache
Hi chris!
Hi mark!
Hi scott!
.
.fi
.
.IP "" 0
.
.P
If you provide multiple YAML documents (as delimited by \fB\-\-\-\fR), your
template will be rendered multiple times. Like a mail merge.
.
.P
For example:
.
.IP "" 4
.
.nf
$ cat data.yml
\-\-\-
name: chris
\-\-\-
name: mark
\-\-\-
name: scott
\-\-\-
$ cat template.mustache
Hi {{name}}!
$ cat data.yml template.mustache | mustache
Hi chris!
Hi mark!
Hi scott!
.
.fi
.
.IP "" 0
.
.SH "OPTIONS"
By default \fBmustache\fR will try to render a Mustache template using the
YAML frontmatter you provide. It can do a few other things, however.
.
.TP
\fB\-c\fR, \fB\-\-compile\fR
Print the compiled Ruby version of a given template. This is the
code that is actually used when rendering a template into a
string. Useful for debugging but only if you are familiar with
Mustache's internals.
.
.TP
\fB\-t\fR, \fB\-\-tokens\fR
Print the tokenized form of a given Mustache template. This can be
used to understand how Mustache parses a template. The tokens are
handed to a generator which compiles them into a Ruby
string. Syntax errors and confused tags, therefor, can probably be
identified by examining the tokens produced.
.
.SH "INSTALLATION"
If you have RubyGems installed:
.
.IP "" 4
.
.nf
gem install mustache
.
.fi
.
.IP "" 0
.
.SH "EXAMPLES"
.
.nf
$ mustache data.yml template.mustache
$ cat data.yml | mustache \- template.mustache
$ mustache \-c template.mustache
$ cat <