pax_global_header 0000666 0000000 0000000 00000000064 15147275312 0014521 g ustar 00root root 0000000 0000000 52 comment=ccc31e29ad46d07e71a754543253d4955c8f95d6
mustache-mustache-ccc31e2/ 0000775 0000000 0000000 00000000000 15147275312 0015626 5 ustar 00root root 0000000 0000000 mustache-mustache-ccc31e2/.gitignore 0000664 0000000 0000000 00000000132 15147275312 0017612 0 ustar 00root root 0000000 0000000 docs
Gemfile.lock
*.gem
# IDE
.idea
# Docs
.yardoc
doc/*
benchmarks/*.html
/coverage/
mustache-mustache-ccc31e2/.gitmodules 0000664 0000000 0000000 00000000124 15147275312 0020000 0 ustar 00root root 0000000 0000000 [submodule "ext/spec"]
path = ext/spec
url = https://github.com/mustache/spec.git
mustache-mustache-ccc31e2/.travis.yml 0000664 0000000 0000000 00000000750 15147275312 0017741 0 ustar 00root root 0000000 0000000 language: ruby
rvm:
- 2.1.0
- 2.4.0
addons:
code_climate:
repo_token: 197d6b3eb448e97f94a63414e2f6b6a96d0bf0d44514cf57100be14483302d12
deploy:
provider: rubygems
api_key:
secure: mRAdriYspBlUjzvhZGr81MKNG3l/4aDr89RSRg64eJEQNStNy3nFWgHTxtKxemhUg9TLFRx82tlI0sAKhoCrKH/1d49P4mFW/aebY+nMFpMPIWJ8MSIKl0knoPvd/8usrBZ/wPFrqBuWoGCwwDBHgo1PO/JeRQ0aCaAxaVKofAU=
gem: mustache
on:
tags: true
repo: mustache/mustache
after_success:
- bundle exec codeclimate-test-reporter
mustache-mustache-ccc31e2/CONTRIBUTING.md 0000664 0000000 0000000 00000001041 15147275312 0020053 0 ustar 00root root 0000000 0000000 # Contributing
## Building the manual
The Mustache Manual — [mustache(5)](http://mustache.github.io/mustache.5.html) and [mustache(1)](http://mustache.github.io/mustache.1.html) — is automatically generated by [Ronn](http://rtomayko.github.io/ronn/). To update the manual, edit [mustache.5.ronnn](https://github.com/mustache/mustache/blob/master/man/mustache.5.ronn) and [mustache.1.ronn](https://github.com/mustache/mustache/blob/master/man/mustache.5.ronn), then run `rake man`. Commit all compiled manual files and open a pull request!
mustache-mustache-ccc31e2/Gemfile 0000664 0000000 0000000 00000000173 15147275312 0017122 0 ustar 00root root 0000000 0000000 source "https://rubygems.org"
gemspec
group :test do
gem "simplecov"
gem "codeclimate-test-reporter", "~> 1.0.0"
end
mustache-mustache-ccc31e2/HISTORY.md 0000664 0000000 0000000 00000017204 15147275312 0017315 0 ustar 00root root 0000000 0000000 ## 1.1.2 (2026-02-24)
- [bug] Removes "warning: literal string will be frozen in the future" deprecation message (#285)
## 1.1.1 (2019-12-03)
- [improvement] Improve yardoc documentation (#247)
- [bug] Fix warnings about instance variables (#246)
## 1.1.0 (2018-10-13)
- [feat] Introduces `Mustache#escape`.
This method receives a non-stringified value to allow for
more flexibility in the escaping, like JSON. (#245)
- [bug] Raise correct error when closing unopened section (#240)
- [bug] Fix use of deprecated `File.exists?` (#241)
- [bug] Fix variable shadowing warning (#241)
## 1.0.5 (2017-03-23)
- Fixes error introduced in v1.0.4. (#235)
## 1.0.4 (2017-03-23)
- Hashes with default_procs may lazily fetch values. (#223)
- Relax dependency on Ruby (#232)
## 1.0.3 (2016-03-24)
- Raise on deep context miss (#214)
- Allow hyphens in tags (#218)
## 1.0.2 (2015-06-24)
- Adds benchmarks (#197)
- Clarify documentation around content without HTML escaping (#203)
- Fix some Ruby warnings (#204)
- Improve performance when using partials inside loops (#205)
## 1.0.1 (2015-02-23)
- Always cast to hash on hash-like object lookups (#187)
- Fixed -v option in the binary (#189)
- Missing partial returns "" per the spec (#200)
# 1.0.0 (2015-01-11)
- Bugfixes
- Now requires Ruby >= 2.0
- Removed mustache_sinatra to separate gem
- Removed rack-bug-mustache_panel to separate gem
## 0.99.6 (2014-07-22)
- Fixed and updated documentation
- Added license to gemspec
- Allows Hash default proc to work in context
- Avoids raising ContextMiss when testing for key presence
- Refactored Parser to allow for better extensibility
- 1.9.3+ YAML compatibility
- Support allowed liberal tag names in classes
- Removed redundant Parser#scan_tag> code
- Mustache command works with pure json files
- Enumerate any object tagged with Mustache::Enumerable
- Rescue NameError when Views module isn't found
- Adds Gemfile
## 0.99.5 (2013-11-11)
- Added line offsets to parser ast
- Sinatra: `mustache` takes a View class to skip lookups
- Fixed warning for shadowing outer local variable
- Fixed typos
## 0.99.4 (2011-05-26)
- Reverted automatically attr_accessors in Sinatra. Too much magic.
## 0.99.3 (2011-03-06)
- Fixed method_missing support
- Fixed whitespace errors
## 0.99.2 (2011-03-06)
- Added some HTML5 tags to tpl-mode.el
- Bugfix: {{#sections}} and whitespace
## 0.99.1 (2011-03-01)
- Bugfix: Strings used in sections no longer enumerate.
## 0.99.0 (2011-02-28)
- Unary methods of Mustache view can now be used in sections as procs.
- Added instance-level versions of all view settings.
- Emacs mode: Support for dot notation
- Sinatra: Support for `mustache "views/in/sub/directories"`
## 0.98.0 (2011-02-24)
- Dot Notation: {{person.name}}
- Implicit Iterators: {{# people}} {{.}} {{/ people}}
- Automagic attr_readers for ivars you set in Sinatra routes.
- Ability to customize escaping by overriding Mustache#escapeHTML
## 0.13.0 (2011-02-23)
- Mustache.render accepts a symbol to specify a template name.
- Bugfix: Struct can be used as sections again
## 0.12.1 (2011-02-22)
- Bugfixes!
## 0.12.0 (2010-12-10)
- Passing the full draft Mustache spec.
- Instance render: `@view.render(:thing => :world)`
- Sinatra bugfix: 'layout not found' fix
## 0.11.2 (2010-05-13)
- Sinatra bugfix: `mustache :"TEMPLATE.atom"`
## 0.11.1 (2010-05-12)
- mustache(1) bugfix: Render even without data.
## 0.11.0 (2010-04-18)
- Higher Order Sections. See mustache(5) for details.
- Add inheritable class ivars on Mustache for @options.
## 0.10.0 (2010-04-02)
- Added Inverted Sections (^). See mustache(5) for details.
- Added Template#source for accessing the template's string source.
- Bugfix: 1.9 encoding fix
- Sinatra Bugfix: 1.9 compat
## 0.9.2 (2010-03-29)
- Sinatra: Bugfix for `mustache :view, :layout => true`
- Mustache class now implements `partial` so you can call `super`
when providing a custom `partial` method.
- Bugfix: Allow slashes in tags, especially partials.
## 0.9.1 (2010-03-27)
- Bugfix: Partials use the nearest context when being rendered.
- Bugfix: Partials returned by the partial method are now rendered.
## 0.9.0 (2010-03-26)
- New, cleaner parser by Magnus Holm!
- Improved error messages!
- Bugfixes!
- Faster runtime!
- Sinatra 1.0 compatibility with layout tag overriding!
## 0.7.0 (2010-03-25)
- `Mustache.compile` for compiling a template into Ruby.
- `mustache -c FILE` to see a template's compiled Ruby.
- Recursive partial support.
- Added `&` as an alias for the triple mustache (unescaped HTML).
- Simpler examples. Old examples are now test fixtures.
## 0.6.0 (2010-03-08)
- Ruby objects can be used in sections, not just hashes. See
http://github.com/defunkt/mustache/commit/9477619638
- As a result, `TypeError` is no longer thrown when hashes are not
passed.
- mustache(1) man page is now included
- mustache(5) man page is now included
- tpl-mode.el has been renamed mustache-mode.el
- Improved README
## 0.5.1 (2009-12-15)
- Added "mail merge" functionality to `mustache` script.
- Support for multi-line tags (useful for comments)
- Sinatra Bugfix: Use Sinatra app's view path, not Sinatra base class'.
## 0.5.0 (2009-11-23)
- Partial classes are no longer supported. Use modules!
- Added `mustache` script for rendering templates on the command line.
- ctemplate compat: Partials are indicated by >, not <
- Bugfix: Context miss should return nil, not empty string. Fixes 1.9.x
## 0.4.2 (2009-10-28)
- Bugfix: Ignore bad constant names when autoloading
## 0.4.1 (2009-10-27)
- Partials now respect the `view_namespace` setting.
- Added tpl-mode.el to contrib/ for us Emacs users.
- Rack::Bug bugfix: ensure benchmark is required before using it
- Rack::Bug: truncate too-large variables (click expands them)
## 0.4.0 (2009-10-27)
- Stopped raising context miss exceptions by default
- Added `Mustache.raise_on_context_miss` setting (defaults to false)
- Throw Mustache::ContextMiss when raise_on_context_miss is true and
we encounter a miss.
- The default template extension is now "mustache" (instead of "html").
- Added the `view_namespace` and `view_path` settings to `Mustache`
- Added `Mustache.view_class` method which autoloads a class using the
new `view_namespace` and `view_path` settings. Should be used by
plugin developers.
- Updated the Sinatra extension to use the new `view_class` method
- Unclosed sections now throw a helpful error message
- Report line numbers on unclosed section errors
- Added Rack::Bug panel
## 0.3.2 (2009-10-19)
- Bugfix: Partials in Sinatra were using the wrong path.
## 0.3.1 (2009-10-19)
- Added mustache.vim to contrib/ (Thanks Juvenn Woo!)
- Support string keys in contexts (not just symbol keys).
- Bugfix: # and / were not permitted in tag names. Now they are.
- Bugfix: Partials in Sinatra needed to know their extension and path
- Bugfix: Using the same boolean section twice was failing
## 0.3.0 (2009-10-14)
- Set Delimiter tags are now supported. See the README
- Improved error message when an enumerable section did not return all
hashes.
- Added a shortcut: if a section's value is a single hash, treat is as
a one element array whose value is the hash.
- Bugfix: String templates set at the class level were not compiled
- Added a class-level `compiled?` method for checking if a template
has been compiled.
- Added an instance-level `compiled?` method.
- Cache template compilation in Sinatra
## 0.2.2 (2009-10-11)
- Improved documentation
- Fixed single line sections
- Broke preserved indentation (issue #2)
## 0.2.1 (2009-10-11)
- Mustache.underscore can now be called without an argument
- Settings now mostly live at the class level, excepting `template`
- Any setting changes causes the template to be recompiled
mustache-mustache-ccc31e2/LICENSE 0000664 0000000 0000000 00000002043 15147275312 0016632 0 ustar 00root root 0000000 0000000 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-mustache-ccc31e2/README.md 0000664 0000000 0000000 00000023013 15147275312 0017104 0 ustar 00root root 0000000 0000000 # Mustache
[](http://badge.fury.io/rb/mustache)
[](https://travis-ci.org/mustache/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.
## Installation
Install the gem locally with:
$ gem install mustache
Or add it to your `Gemfile`:
```ruby
gem "mustache", "~> 1.0"
```
## 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:
```ruby
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;
```ruby
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: `& \ " < >` (as
well as `'` in Ruby `>= 2.0`). To disable escaping, simply use triple
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:
```ruby
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:
```ruby
view[:name] = 'Tony'
view.render # => Hello Tony\nYou 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:
```ruby
class Simple < Mustache
self.template_path = __dir__
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:
```ruby
Simple.template_file = './blah.mustache'
```
Mustache also allows you to define the extension it'll use.
```ruby
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:
```ruby
Simple.template = 'Hi {{person}}!'
```
Or set a different template for a single instance:
```ruby
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.
```ruby
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:
```ruby
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 an example which illustrates a key feature of Mustache: you
are free to use the `initialize` method just as you would in any
normal class.
```ruby
class Simple < Mustache
include ViewHelpers
def initialize(ssl = false)
@ssl = ssl
end
end
```
Now:
```ruby
Simple.new(request.ssl?).render
```
Finally, our template might look like this:
{{# users}}
{{ login }}
{{/ users}}
## Integrations
### Sinatra
Sinatra integration is available with the
[mustache-sinatra gem](https://github.com/mustache/mustache-sinatra).
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][diff] 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 provides a `Rack::Bug` panel.
First you have to install the `rack-bug-mustache_panel` gem, then in your `config.ru` add the following code:
```ruby
require 'rack/bug/panels/mustache_panel'
use Rack::Bug::MustachePanel
```
Using Rails? Add this to your initializer or environment file:
```ruby
require 'rack/bug/panels/mustache_panel'
config.middleware.use "Rack::Bug::MustachePanel"
```
![Rack::Bug][5]
### Vim
vim-mustache-handlebars is available at [mustache/vim-mustache-handlebars][vim]
### Emacs
mustache-mode.el is available at [mustache/emacs][emacs]
### TextMate
[Mustache.tmbundle][tmbundle]
See for installation instructions.
### Command Line
See `mustache(1)` man page or
for command line docs.
## Acknowledgements
Thanks to [Tom Preston-Werner](https://github.com/mojombo) for showing
me ctemplate and [Leah Culver](https://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!
## 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 .~~
The mailing list hasn't been updated in quite a while, please join us on Gitter
or IRC:
[](https://gitter.im/mustache/mustache?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[#{ on Freenode][irc]
## Meta
* Code: `git clone https://github.com/mustache/mustache.git`
* Home:
* Bugs:
* List:
* Gems:
[1]: https://github.com/olafvdspek/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]: https://github.com/brynary/rack-bug/
[5]: http://img.skitch.com/20091027-n8pxwwx8r61tc318a15q1n6m14.png
[fk]: https://help.github.com/forking/
[is]: https://github.com/mustache/mustache/issues
[irc]: irc://irc.freenode.net/#{
[vim]: https://github.com/mustache/vim-mustache-handlebars
[emacs]: https://github.com/mustache/emacs
[tmbundle]: https://github.com/defunkt/Mustache.tmbundle
[diff]: https://gist.github.com/defunkt/345490
mustache-mustache-ccc31e2/Rakefile 0000664 0000000 0000000 00000002434 15147275312 0017276 0 ustar 00root root 0000000 0000000 require 'rake/testtask'
require 'rdoc/task'
#
# Helpers
#
def command?(command)
system("type #{command} &> /dev/null")
end
#
# Tests
#
task :default => :test
Rake::TestTask.new do |t|
t.libs << 'lib'
t.pattern = 'test/**/*_test.rb'
t.verbose = false
end
#
# Ron
#
if command? :ronn
desc "Show the manual"
task :man => "man:build" do
exec "man man/mustache.1"
end
desc "Build the manual"
task "man:build" do
sh "ronn -br5 --organization=DEFUNKT --manual='Mustache Manual' man/*.ron"
end
end
#
# Gems
#
desc "Push a new version to Gemcutter and publish docs."
task :publish do
require File.dirname(__FILE__) + '/lib/mustache/version'
system "git tag v#{Mustache::Version}"
sh "gem build mustache.gemspec"
sh "gem push mustache-#{Mustache::Version}.gem"
sh "git push origin master --tags"
sh "git clean -fd"
exec "rake pages"
end
#
# Documentation
#
desc "Publish to GitHub Pages"
task :pages => [ "man:build" ] do
Dir['man/*.html'].each do |f|
cp f, File.basename(f).sub('.html', '.newhtml')
end
`git commit -am 'generated manual'`
`git checkout site`
Dir['*.newhtml'].each do |f|
mv f, f.sub('.newhtml', '.html')
end
`git add .`
`git commit -m updated`
`git push site site:master`
`git checkout master`
puts :done
end
mustache-mustache-ccc31e2/benchmarks/ 0000775 0000000 0000000 00000000000 15147275312 0017743 5 ustar 00root root 0000000 0000000 mustache-mustache-ccc31e2/benchmarks/compile_template_benchmark.rb 0000664 0000000 0000000 00000001064 15147275312 0025626 0 ustar 00root root 0000000 0000000 $:.unshift 'lib'
require 'benchmark/ips'
require 'mustache'
template = """
{{#products}}
{{/products}}
"""
Benchmark.ips do |x|
x.report("Compile template") do |times|
Mustache::Template.new(template).compile
end
end
mustache-mustache-ccc31e2/benchmarks/compile_template_profile.rb 0000664 0000000 0000000 00000001526 15147275312 0025337 0 ustar 00root root 0000000 0000000 $:.unshift 'lib'
require "ruby-prof"
require 'mustache'
require "pathname"
template = """
{{#products}}
{{/products}}
"""
# Uncomment to measure object allocations. Requires ruby 2.0.0
# RubyProf.measure_mode = RubyProf::ALLOCATIONS
RubyProf.start
20000.times do
Mustache::Template.new(template).compile
end
result = RubyProf.stop
printer = RubyProf::GraphHtmlPrinter.new(result)
Pathname.new(FileUtils.pwd).join("benchmarks/compile_template_profile.html").open("w+") do |file|
printer.print(file, {})
end
mustache-mustache-ccc31e2/benchmarks/html_escape_benchmark.rb 0000664 0000000 0000000 00000002047 15147275312 0024571 0 ustar 00root root 0000000 0000000 $:.unshift 'lib'
require 'benchmark/ips'
require 'mustache'
template = """
"""
data_without_escaping = {
:external_index=>"product",
:url=>"/products/7",
:image=>"products/product.jpg"
}
data_with_escaping = {
:external_index=>"Bear > Shark
",
:url=>"/Bear > Shark
/7",
:image=>"products/Bear > Shark
.jpg"
}
template = Mustache::Template.new(template)
Benchmark.ips do |x|
x.report("render template without escaping") do |times|
ctx = Mustache::Context.new(Mustache.new); ctx.push(data_without_escaping)
template.render(ctx)
end
x.report("render template with escaping") do |times|
ctx = Mustache::Context.new(Mustache.new); ctx.push(data_with_escaping)
template.render(ctx)
end
end
mustache-mustache-ccc31e2/benchmarks/render_collection_benchmark.rb 0000664 0000000 0000000 00000002457 15147275312 0026004 0 ustar 00root root 0000000 0000000 $:.unshift 'lib'
require 'benchmark/ips'
require 'mustache'
template = """
{{#products}}
{{/products}}
"""
data_10 = {
products: []
}
10.times do
data_10[:products] << {
:external_index=>"product",
:url=>"/products/7",
:image=>"products/product.jpg"
}
end
data_100 = {
products: []
}
100.times do
data_100[:products] << {
:external_index=>"product",
:url=>"/products/7",
:image=>"products/product.jpg"
}
end
data_1000 = {
products: []
}
1000.times do
data_1000[:products] << {
:external_index=>"product",
:url=>"/products/7",
:image=>"products/product.jpg"
}
end
view = Mustache.new
view.template = template
view.render # Call render once so the template will be compiled
Benchmark.ips do |x|
x.report("render list of 10") do |times|
view.render(data_10)
end
x.report("render list of 100") do |times|
view.render(data_100)
end
x.report("render list of 1000") do |times|
view.render(data_1000)
end
end
mustache-mustache-ccc31e2/benchmarks/render_collection_profile.rb 0000664 0000000 0000000 00000002121 15147275312 0025476 0 ustar 00root root 0000000 0000000 $:.unshift 'lib'
require "ruby-prof"
require 'mustache'
require "pathname"
template = """
{{#products}}
{{/products}}
"""
data = {
products: []
}
200.times do
data[:products] << {
:external_index=>"product",
:url=>"/products/7",
:image=>"products/product.jpg"
}
end
# Uncomment to measure object allocations. Requires ruby 2.0.0
# RubyProf.measure_mode = RubyProf::ALLOCATIONS
view = Mustache.new
view.template = template
view.render # Call render once so the template will be compiled
RubyProf.start
500.times do
view.render(data)
end
result = RubyProf.stop
printer = RubyProf::GraphHtmlPrinter.new(result)
Pathname.new(FileUtils.pwd).join("benchmarks/render_collection_profile.html").open("w+") do |file|
printer.print(file, {})
end
mustache-mustache-ccc31e2/benchmarks/render_lambda_benchmark.rb 0000664 0000000 0000000 00000001445 15147275312 0025065 0 ustar 00root root 0000000 0000000 $:.unshift "lib"
require "mustache"
require "benchmark/ips"
BASE_TEMPLATE = <Lambdas
{{#lambdas}}
{{#lambda}}
Here is some text inside the lambda.\n
Also a variable is present: {{name}}.
{{/lambda}}
{{/lambdas}}
end_of_template
one_name = [
{
name: "Charlie Chaplin",
lambda: lambda {|text| "\n--\n#{text}\n--\n" }
},
]
data_10 = {
lambdas: one_name * 10,
}
data_100 = {
lambdas: one_name * 100,
}
data_1000 = {
lambdas: one_name * 1000,
}
mustache = Mustache.new
mustache.template = BASE_TEMPLATE
Benchmark.ips do |x|
x.report("render list of 10") do
mustache.render(data_10)
end
x.report("render list of 100") do
mustache.render(data_100)
end
x.report("render list of 1000") do
mustache.render(data_1000)
end
end
mustache-mustache-ccc31e2/benchmarks/render_partials_benchmark.rb 0000664 0000000 0000000 00000001423 15147275312 0025460 0 ustar 00root root 0000000 0000000 $:.unshift "lib"
require "mustache"
require "benchmark/ips"
BASE_TEMPLATE = <Names
{{#names}}
{{> user}}
{{/names}}
end_of_template
PARTIAL_TEMPLATE = <{{name}}
end_of_template
one_name = [
{name: "Charlie Chaplin"},
]
data_10 = {
names: one_name * 10,
}
data_100 = {
names: one_name * 100,
}
data_1000 = {
names: one_name * 1000,
}
class Custom < Mustache
def partial(name)
PARTIAL_TEMPLATE
end
end
mustache = Custom.new
mustache.template = BASE_TEMPLATE
Benchmark.ips do |x|
x.report("render list of 10") do
mustache.render(data_10)
end
x.report("render list of 100") do
mustache.render(data_100)
end
x.report("render list of 1000") do
mustache.render(data_1000)
end
end
mustache-mustache-ccc31e2/benchmarks/render_template_benchmark.rb 0000664 0000000 0000000 00000002725 15147275312 0025462 0 ustar 00root root 0000000 0000000 $:.unshift 'lib'
require 'benchmark/ips'
require 'mustache'
template = """
{{#products}}
{{/products}}
"""
data_10 = {
products: []
}
10.times do
data_10[:products] << {
:external_index=>"product",
:url=>"/products/7",
:image=>"products/product.jpg"
}
end
data_100 = {
products: []
}
100.times do
data_100[:products] << {
:external_index=>"product",
:url=>"/products/7",
:image=>"products/product.jpg"
}
end
data_1000 = {
products: []
}
1000.times do
data_1000[:products] << {
:external_index=>"product",
:url=>"/products/7",
:image=>"products/product.jpg"
}
end
template = Mustache::Template.new(template)
Benchmark.ips do |x|
x.report("render list of 10") do |times|
ctx_10 = Mustache::Context.new(Mustache.new); ctx_10.push(data_10)
template.render(ctx_10)
end
x.report("render list of 100") do |times|
ctx_100 = Mustache::Context.new(Mustache.new); ctx_100.push(data_100)
template.render(ctx_100)
end
x.report("render list of 1000") do |times|
ctx_1000 = Mustache::Context.new(Mustache.new); ctx_1000.push(data_1000)
template.render(ctx_1000)
end
end
mustache-mustache-ccc31e2/benchmarks/render_template_profile.rb 0000664 0000000 0000000 00000002116 15147275312 0025162 0 ustar 00root root 0000000 0000000 $:.unshift 'lib'
require "ruby-prof"
require 'mustache'
require "pathname"
template = """
{{#products}}
{{/products}}
"""
data = {
products: []
}
200.times do
data[:products] << {
:external_index=>"product",
:url=>"/products/7",
:image=>"products/product.jpg"
}
end
template = Mustache::Template.new(template)
# Uncomment to measure object allocations. Requires ruby 2.0.0
# RubyProf.measure_mode = RubyProf::ALLOCATIONS
RubyProf.start
2000.times do
ctx = Mustache::Context.new(Mustache.new); ctx.push(data)
template.render(ctx)
end
result = RubyProf.stop
printer = RubyProf::GraphHtmlPrinter.new(result)
Pathname.new(FileUtils.pwd).join("benchmarks/render_template_profile.html").open("w+") do |file|
printer.print(file, {})
end
mustache-mustache-ccc31e2/bin/ 0000775 0000000 0000000 00000000000 15147275312 0016376 5 ustar 00root root 0000000 0000000 mustache-mustache-ccc31e2/bin/mustache 0000775 0000000 0000000 00000005105 15147275312 0020136 0 ustar 00root root 0000000 0000000 #!/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] [-e] [-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("-e", "--error",
"Raise an error on context misses.") do |e|
Mustache.raise_on_context_miss = true
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 the command line then
# processing them. The meat of this script, if you will.
def self.process_files(input_files)
doc = input_files.file.read
yaml = nil
begin
yaml = YAML.load_stream(doc)
rescue
abort "Unable to parse yaml!"
end
if yaml.nil?
puts Mustache.render(doc)
else
template = input_files.skip.file.read
puts Mustache.render template, yaml.compact.reduce(&:merge)
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 rest of ARGF
Mustache::CLI.process_files(ARGF)
mustache-mustache-ccc31e2/examples/ 0000775 0000000 0000000 00000000000 15147275312 0017444 5 ustar 00root root 0000000 0000000 mustache-mustache-ccc31e2/examples/hash.rb 0000664 0000000 0000000 00000000604 15147275312 0020714 0 ustar 00root root 0000000 0000000 $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
require 'mustache'
Mustache.template_file = File.dirname(__FILE__) + '/simple.mustache'
view = Mustache.new
print "Your name: "
view[:name] = gets
view[:value] = value = rand(10_000)
print "Are you in CA? [y/n] "
if view[:in_ca] = gets.to_s.downcase[0].chr == 'y'
view[:taxed_value] = value - (value * 0.4)
end
puts view.render
mustache-mustache-ccc31e2/examples/hash.yml 0000664 0000000 0000000 00000000054 15147275312 0021111 0 ustar 00root root 0000000 0000000 ---
name: Chris
value: 10,000
in_ca: no
---
mustache-mustache-ccc31e2/examples/i18n/ 0000775 0000000 0000000 00000000000 15147275312 0020223 5 ustar 00root root 0000000 0000000 mustache-mustache-ccc31e2/examples/i18n/mustache_i18n.rb 0000664 0000000 0000000 00000000423 15147275312 0023217 0 ustar 00root root 0000000 0000000 class Stache18n
@@tags = {
'comment-and-close' => 'Comment and close',
'github' => 'GitHub',
'social-coding' => 'Social Coding'
}
def self.t
@@tags
end
end
puts Mustache.render(<{{t.github}} - {{t.social-coding}}
END
mustache-mustache-ccc31e2/examples/i18n/mustache_i18n2.rb 0000664 0000000 0000000 00000000571 15147275312 0023305 0 ustar 00root root 0000000 0000000 class Stache18n
@@tags = {
'comment-and-close' => 'Comment and close',
'github' => 'GitHub',
'social-coding' => 'Social Coding'
}
def self.t
new
end
def method_missing(tag)
@@tags[tag.to_s]
end
def respond_to?(tag)
@@tags[tag.to_s]
end
end
puts Mustache.render(<{{t.github}} - {{t.social-coding}}
END
mustache-mustache-ccc31e2/examples/projects.mustache 0000664 0000000 0000000 00000000673 15147275312 0023036 0 ustar 00root root 0000000 0000000
projects
projects
mustache-mustache-ccc31e2/examples/projects.yml 0000664 0000000 0000000 00000001454 15147275312 0022024 0 ustar 00root root 0000000 0000000 ---
projects:
- name: resque
url: http://github.com/defunkt/resque
description: A Redis-backed Ruby library for queueing and working.
- name: mustache
url: http://defunkt.github.com/mustache
description: Logic-less templates.
- name: pystache
url: http://github.com/defunkt/pystache
description: Mustache in Python
- name: hub
url: http://github.com/defunkt/hub
description: hub introduces git to GitHub
- name: repl
url: http://github.com/defunkt/repl
description: sometimes you need a repl
- name: gist
url: http://github.com/defunkt/gist
description: Absolutely the best command line gister.
- name: gem-man
url: http://defunkt.github.com/gem-man/
description: "View a RubyGem's man page"
- name: hurl
url: http://hurl.it/
description: Hurl makes HTTP requests
width: 4968
---
mustache-mustache-ccc31e2/examples/self.mustache 0000664 0000000 0000000 00000000062 15147275312 0022126 0 ustar 00root root 0000000 0000000 The Beatles were:
{{#names}}
* {{.}}
{{/names}}
mustache-mustache-ccc31e2/examples/self.yml 0000664 0000000 0000000 00000000054 15147275312 0021117 0 ustar 00root root 0000000 0000000 ---
names: [ John, Paul, George, Ringo ]
--- mustache-mustache-ccc31e2/examples/simple.mustache 0000664 0000000 0000000 00000000260 15147275312 0022466 0 ustar 00root root 0000000 0000000 Hello {{name}}
You have just won ${{value}}!
{{#in_ca}}
Well, ${{taxed_value}}, after taxes.
{{/in_ca}}
{{^in_ca}}
You're lucky - in CA you'd be taxed like crazy!
{{/in_ca}}
mustache-mustache-ccc31e2/examples/simple.rb 0000664 0000000 0000000 00000000474 15147275312 0021267 0 ustar 00root root 0000000 0000000 $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
require 'mustache'
class Simple < Mustache
self.path = File.dirname(__FILE__)
def name
"Chris"
end
def value
10_000
end
def taxed_value
value - (value * 0.4)
end
def in_ca
true
end
end
puts Simple.render if $0 == __FILE__
mustache-mustache-ccc31e2/ext/ 0000775 0000000 0000000 00000000000 15147275312 0016426 5 ustar 00root root 0000000 0000000 mustache-mustache-ccc31e2/ext/spec/ 0000775 0000000 0000000 00000000000 15147275312 0017360 5 ustar 00root root 0000000 0000000 mustache-mustache-ccc31e2/lib/ 0000775 0000000 0000000 00000000000 15147275312 0016374 5 ustar 00root root 0000000 0000000 mustache-mustache-ccc31e2/lib/mustache.rb 0000664 0000000 0000000 00000022320 15147275312 0020531 0 ustar 00root root 0000000 0000000 require 'mustache/enumerable'
require 'mustache/template'
require 'mustache/context'
require 'mustache/settings'
require 'mustache/utils'
# 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 use 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
# Initialize a new Mustache instance.
#
# @param [Hash] options An options hash
# @option options [String] template_path
# @option options [String] template_extension
# @option options [String] template_file
# @option options [String] template
# @option options [String] view_namespace
# @option options [String] view_path
def initialize(options = {})
@options = options
initialize_settings
end
# Instantiates an instance of this class and calls `render` with
# the passed args.
#
# @return A rendered String version of a template.
def self.render(*args)
new.render(*args)
end
# Parses our fancy pants template file and returns normal file with
# all special {{tags}} and {{#sections}}replaced{{/sections}}.
#
# @example Render view
# @view.render("Hi {{thing}}!", :thing => :world)
#
# @example Set view template and then render
# View.template = "Hi {{thing}}!"
# @view = View.new
# @view.render(:thing => :world)
#
# @param [String,Hash] data A String template or a Hash context.
# If a Hash is given, we'll try to figure
# out the template from the class.
# @param [Hash] ctx A Hash context if `data` is a String template.
# @return [String] Returns a rendered version of a template.
def render(data = template, ctx = {})
case data
when Hash
ctx = data
when Symbol
self.template_name = data
end
tpl = case data
when Hash
templateify(template)
when Symbol
templateify(template)
else
templateify(data)
end
return tpl.render(context) if ctx == {}
begin
context.push(ctx)
tpl.render(context)
ensure
context.pop
end
end
# Context accessors.
#
# @example 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)
self.new.partial(name)
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)
path = "#{template_path}/#{name}.#{template_extension}"
begin
File.read(path)
rescue
raise if raise_on_context_miss?
""
end
end
# Override this to provide custom escaping.
# By default it uses `CGI.escapeHTML`.
#
# @example Overriding #escape
# class PersonView < Mustache
# def escape(value)
# my_html_escape_method(value.to_s)
# end
# end
#
# @param [Object] value Value to escape.
# @return [String] Escaped content.
def escape(value)
self.escapeHTML(value.to_s)
end
# Override this to provide custom escaping.
#
# @example Overriding #escapeHTML
# class PersonView < Mustache
# def escapeHTML(str)
# my_html_escape_method(str)
# end
# end
#
# @deprecated Use {#escape} instead.
#
# Note that {#escape} can receive any kind of object.
# If your override logic is expecting a string, you will
# have to call to_s on it yourself.
# @param [String] str String to escape.
# @return [String] Escaped HTML.
def escapeHTML(str)
CGI.escapeHTML(str)
end
# Has this instance or its class already compiled a template?
def compiled?
(@template && @template.is_a?(Template)) || self.class.compiled?
end
private
# When given a symbol or string representing a class, will try to produce an
# appropriate view class.
#
# @example
# Mustache.view_namespace = Hurl::Views
# Mustache.view_class(:Partial) # => Hurl::Views::Partial
def self.view_class(name)
name = classify(name.to_s)
# Emptiness begets emptiness.
return Mustache if name.to_s.empty?
name = "#{view_namespace}::#{name}"
const = rescued_const_get(name)
return const if const
const_from_file(name)
end
def self.rescued_const_get name
const_get(name, true) || Mustache
rescue NameError
nil
end
def self.const_from_file name
file_name = underscore(name)
file_path = "#{view_path}/#{file_name}.rb"
return Mustache unless File.exist?(file_path)
require file_path.chomp('.rb')
rescued_const_get(name)
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
# template_partial => TemplatePartial
# template/partial => Template::Partial
def self.classify(underscored)
Mustache::Utils::String.new(underscored).classify
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 = superclass.name if classified.to_s.empty?
Mustache::Utils::String.new(classified).underscore(view_namespace)
end
# @param [Template,String] obj Turns `obj` into a template
# @param [Hash] options Options for template creation
def self.templateify(obj, options = {})
obj.is_a?(Template) ? obj : Template.new(obj, options)
end
def templateify(obj)
opts = {:partial_resolver => self.method(:partial)}
opts.merge!(@options) if @options.is_a?(Hash)
self.class.templateify(obj, opts)
end
# Return the value of the configuration setting on the superclass, or return
# the default.
#
# @param [Symbol] attr_name Name of the attribute. It should match
# the instance variable.
# @param [Object] default Default value to use if the superclass does
# not respond.
#
# @return 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-mustache-ccc31e2/lib/mustache/ 0000775 0000000 0000000 00000000000 15147275312 0020205 5 ustar 00root root 0000000 0000000 mustache-mustache-ccc31e2/lib/mustache/context.rb 0000664 0000000 0000000 00000012215 15147275312 0022217 0 ustar 00root root 0000000 0000000 require 'mustache/context_miss'
class Mustache
# A Context represents the context which a Mustache template is
# executed within. All Mustache tags reference keys in the Context.
#
class Context
# Initializes a Mustache::Context.
#
# @param [Mustache] mustache A Mustache instance.
#
def initialize(mustache)
@stack = [mustache]
@partial_template_cache = {}
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)
# Get a template object for the partial and render the result.
template_for_partial(part).render(self)
end
def template_for_partial(partial)
@partial_template_cache[partial] ||= Template.new(partial)
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.
#
# @return [Mustache] First Mustache in the stack.
#
def mustache_in_stack
@mustache_in_stack ||= @stack.find { |frame| frame.is_a?(Mustache) }
end
# Allows customization of how Mustache escapes things.
#
# @param [Object] value Value to escape.
#
# @return [String] Escaped string.
#
def escape(value)
mustache_in_stack.escape(value)
end
# Adds a new object to the context's internal stack.
#
# @param [Object] new_obj Object to be added to the internal stack.
#
# @return [Context] Returns the Context.
#
def push(new_obj)
@stack.unshift(new_obj)
@mustache_in_stack = nil
self
end
# Removes the most recently added object from the context's
# internal stack.
#
# @return [Context] Returns the Context.
#
def pop
@stack.shift
@mustache_in_stack = nil
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, false)
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)
return value if :__missing != value
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.
#
# @param [Object] obj The object to perform the lookup on.
# @param [String,Symbol] key The key whose value you want
# @param [Object] default An optional default value, to return if the key is not found.
#
# @return [Object] The value of key in object if it is found, and default otherwise.
#
def find(obj, key, default = nil)
return find_in_hash(obj.to_hash, key, default) if obj.respond_to?(:to_hash)
unless obj.respond_to?(key)
# no match for the key, but it may include a hyphen, so try again replacing hyphens with underscores.
key = key.to_s.tr('-', '_')
return default unless obj.respond_to?(key)
end
meth = obj.method(key) rescue proc { obj.send(key) }
meth.arity == 1 ? meth.to_proc : meth.call
end
def current
@stack.first
end
private
# Fetches a hash key if it exists, or returns the given default.
def find_in_hash(obj, key, default)
return obj[key] if obj.has_key?(key)
return obj[key.to_s] if obj.has_key?(key.to_s)
return obj[key] if obj.respond_to?(:default_proc) && obj.default_proc && obj[key]
# If default is :__missing then we are from #fetch which is hunting through the stack
# If default is nil then we are reducing dot notation
if :__missing != default && mustache_in_stack.raise_on_context_miss?
raise ContextMiss.new("Can't find #{key} in #{obj}")
else
obj.fetch(key, default)
end
end
end
end
mustache-mustache-ccc31e2/lib/mustache/context_miss.rb 0000664 0000000 0000000 00000000670 15147275312 0023254 0 ustar 00root root 0000000 0000000 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
end
mustache-mustache-ccc31e2/lib/mustache/enumerable.rb 0000664 0000000 0000000 00000000055 15147275312 0022651 0 ustar 00root root 0000000 0000000 class Mustache
Enumerable = Module.new
end
mustache-mustache-ccc31e2/lib/mustache/generator.rb 0000664 0000000 0000000 00000014247 15147275312 0022530 0 ustar 00root root 0000000 0000000 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 can be used to manipulate the resulting ruby code string behavior.
def initialize(options = {})
@options = options
@option_static_lambdas = options[:static_lambdas] == true
end
# Given an array of tokens, returns an interpolatable Ruby string.
def compile(exp)
"\"#{compile!(exp)}\""
end
private
# 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,
# [:mustache, :fetch, ["name"]]],
# [:static, "\nYou have just won $"],
# [:mustache, :etag,
# [:mustache, :fetch, ["value"]]],
# [:static, "!\n"],
# [:mustache,
# :section,
# [:mustache, :fetch, ["in_ca"]],
# [:multi,
# [:static, "Well, $"],
# [:mustache, :etag,
# [:mustache, :fetch, ["taxed_value"]]],
# [:static, ", after taxes.\n"]],
# "Well, ${{taxed_value}}, after taxes.\n",
# ["{{", "}}"]]]
def compile!(exp)
case exp.first
when :multi
exp[1..-1].reduce("".dup) { |sum, e| sum << compile!(e) }
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, offset, content, raw, delims)
# Convert the tokenized content of this section into a Ruby
# string we can use.
code = compile(content)
# Lambda handling - default handling is to dynamically interpret
# the returned lambda result as mustache source
proc_handling = if @option_static_lambdas
<<-compiled
v.call(lambda {|v| #{code}}.call(v)).to_s
compiled
else
<<-compiled
t = Mustache::Template.new(v.call(#{raw.inspect}).to_s)
def t.tokens(src=@source)
p = Mustache::Parser.new
p.otag, p.ctag = #{delims.inspect}
p.compile(src)
end
t.render(ctx.dup)
compiled
end
# Compile the Ruby for this section now that we know what's
# inside the section.
ev(<<-compiled)
case v = #{compile!(name)}
when NilClass, FalseClass
when TrueClass
#{code}
when Proc
#{proc_handling}
when Array, Enumerator, Mustache::Enumerable
v.map { |_| ctx.push(_); r = #{code}; ctx.pop; r }.join
else
ctx.push(v); r = #{code}; ctx.pop; r
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, offset, 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 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, offset, indentation)
ev("ctx.partial(#{name.to_sym.inspect}, #{indentation.inspect})")
end
# An unescaped tag.
def on_utag(name, offset)
ev(<<-compiled)
v = #{compile!(name)}
if v.is_a?(Proc)
v = #{@option_static_lambdas ? 'v.call' : 'Mustache::Template.new(v.call.to_s).render(ctx.dup)'}
end
v.to_s
compiled
end
# An escaped tag.
def on_etag(name, offset)
ev(<<-compiled)
v = #{compile!(name)}
if v.is_a?(Proc)
v = #{@option_static_lambdas ? 'v.call' : 'Mustache::Template.new(v.call.to_s).render(ctx.dup)'}
end
ctx.escape(v)
compiled
end
def on_fetch(names)
return "ctx.current" if names.empty?
names = names.map { |n| n.to_sym }
initial, *rest = names
if rest.any?
<<-compiled
#{rest.inspect}.reduce(ctx[#{initial.inspect}]) { |value, key| value && ctx.find(value, key) }
compiled
else
<<-compiled
ctx[#{initial.inspect}]
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-mustache-ccc31e2/lib/mustache/parser.rb 0000664 0000000 0000000 00000026706 15147275312 0022041 0 ustar 00root root 0000000 0000000 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
# The sigil types which are valid after an opening `{{`
VALID_TYPES = [ '#', '^', '/', '=', '!', '<', '>', '&', '{' ].map(&:freeze)
def self.valid_types
@valid_types ||= Regexp.new(VALID_TYPES.map { |t| Regexp.escape(t) }.join('|') )
end
# Add a supported sigil type (with optional aliases) to the Parser.
#
# Requires a block, which will be sent the following parameters:
#
# * content - The raw content of the tag
# * fetch- A mustache context fetch expression for the content
# * padding - Indentation whitespace from the currently-parsed line
# * pre_match_position - Location of the scanner before a match was made
#
# The provided block will be evaluated against the current instance of
# Parser, and may append to the Parser's @result as needed.
def self.add_type(*types, &block)
types = types.map(&:to_s)
type, *aliases = types
method_name = "scan_tag_#{type}".to_sym
define_method(method_name, &block)
aliases.each { |a| alias_method "scan_tag_#{a}", method_name }
types.each { |t| VALID_TYPES << t unless VALID_TYPES.include?(t) }
@valid_types = nil
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 = [ '#', '^', '/', '<', '>', '=', '!' ].map(&:freeze)
# 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 = [ '!', '=' ].map(&:freeze)
attr_reader :otag, :ctag
# Accepts an options hash which does nothing but may be used in
# the future.
def initialize(options = {})
@options = options
@option_inline_partials_at_compile_time = options[:inline_partials_at_compile_time]
if @option_inline_partials_at_compile_time
@partial_resolver = options[:partial_resolver]
raise ArgumentError.new "Missing or invalid partial_resolver" unless @partial_resolver.respond_to? :call
end
# Initialize default tags
self.otag ||= '{{'
self.ctag ||= '}}'
end
# The opening tag delimiter. This may be changed at runtime.
def otag=(value)
regex = regexp value
@otag_regex = /([ \t]*)?#{regex}/
@otag_not_regex = /(^[ \t]*)?#{regex}/
@otag = value
end
# The closing tag delimiter. This too may be changed at runtime.
def ctag=(value)
@ctag_regex = regexp value
@ctag = value
end
# Given a string template, returns an array of tokens.
def compile(template)
@encoding = nil
if template.respond_to?(:encoding)
@encoding = template.encoding
template = template.dup.force_encoding("BINARY")
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
unless @sections.empty?
# We have parsed the whole file, but there's still opened sections.
type, pos, _ = @sections.pop
error "Unclosed section #{type.inspect}", pos
end
@result
end
private
def content_tags type, current_ctag_regex
if ANY_CONTENT.include?(type)
r = /\s*#{regexp(type)}?#{current_ctag_regex}/
scan_until_exclusive(r)
else
@scanner.scan(ALLOWED_CONTENT)
end
end
def dispatch_based_on_type type, content, fetch, padding, pre_match_position
send("scan_tag_#{type}", content, fetch, padding, pre_match_position)
end
def find_closing_tag scanner, current_ctag_regex
error "Unclosed tag" unless scanner.scan(current_ctag_regex)
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 @scanner.scan @otag_regex
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_regex = @ctag_regex
type = @scanner.scan(self.class.valid_types)
@scanner.skip(/\s*/)
# ANY_CONTENT tags allow any character inside of them, while
# other tags (such as variables) are more strict.
content = content_tags(type, current_ctag_regex)
# 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
dispatch_based_on_type(type, content, fetch, padding, pre_match_position)
# The closing } in unescaped tags is just a hack for
# aesthetics.
type = "}" if type == "{"
# Skip whitespace and any balancing sigils after the content
# inside this tag.
@scanner.skip(/\s+/)
@scanner.skip(regexp(type)) if type
find_closing_tag(@scanner, current_ctag_regex)
# 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 @otag_not_regex
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
def offset
position[0, 2]
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.new Regexp.escape(thing) if 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
#
# Scan tags
#
# These methods are called in `scan_tags`. Because they contain nonstandard
# characters in their method names, they are aliased to
# better named methods.
#
# This function handles the cases where the scanned tag does not have
# a type.
def scan_tag_ content, fetch, padding, pre_match_position
@result << [:mustache, :etag, fetch, offset]
end
def scan_tag_block content, fetch, padding, pre_match_position
block = [:multi]
@result << [:mustache, :section, fetch, offset, block]
@sections << [content, position, @result]
@result = block
end
alias_method :'scan_tag_#', :scan_tag_block
def scan_tag_inverted content, fetch, padding, pre_match_position
block = [:multi]
@result << [:mustache, :inverted_section, fetch, offset, block]
@sections << [content, position, @result]
@result = block
end
alias_method :'scan_tag_^', :scan_tag_inverted
def scan_tag_close content, fetch, padding, pre_match_position
section, pos, result = @sections.pop
if section.nil?
error "Closing unopened #{content.inspect}"
end
raw = @scanner.pre_match[pos[3]...pre_match_position] + padding
(@result = result).last << raw << [self.otag, self.ctag]
if section != content
error "Unclosed section #{section.inspect}", pos
end
end
alias_method :'scan_tag_/', :scan_tag_close
def scan_tag_comment content, fetch, padding, pre_match_position
end
alias_method :'scan_tag_!', :scan_tag_comment
def scan_tag_delimiter content, fetch, padding, pre_match_position
self.otag, self.ctag = content.split(' ', 2)
end
alias_method :'scan_tag_=', :scan_tag_delimiter
def scan_tag_open_partial content, fetch, padding, pre_match_position
@result << if @option_inline_partials_at_compile_time
partial = @partial_resolver.call content
partial.gsub!(/^/, padding) unless padding.empty?
self.class.new(@options).compile partial
else
[:mustache, :partial, content, offset, padding]
end
end
alias_method :'scan_tag_<', :scan_tag_open_partial
alias_method :'scan_tag_>', :scan_tag_open_partial
def scan_tag_unescaped content, fetch, padding, pre_match_position
@result << [:mustache, :utag, fetch, offset]
end
alias_method :'scan_tag_{', :'scan_tag_unescaped'
alias_method :'scan_tag_&', :'scan_tag_unescaped'
end
end
mustache-mustache-ccc31e2/lib/mustache/settings.rb 0000664 0000000 0000000 00000013226 15147275312 0022376 0 ustar 00root root 0000000 0000000 # Settings which can be configured for all view classes, a single
# view class, or a single Mustache instance.
class Mustache
def initialize_settings
@template = nil
@template_path = nil
@template_extension = nil
@template_name = nil
@template_file = nil
@raise_on_context_miss = nil
end
def self.initialize_settings
@template = nil
@template_path = nil
@template_extension = nil
@template_name = nil
@template_file = nil
@raise_on_context_miss = nil
end
initialize_settings
def self.inherited(subclass)
subclass.initialize_settings
end
#
# 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
alias_method :path, :template_path
def template_path=(path)
@template_path = File.expand_path(path)
@template = nil
end
# Alias for `template_path`
def self.path
template_path
end
# Alias for `template_path`
def self.path=(path)
self.template_path = path
end
#
# 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-mustache-ccc31e2/lib/mustache/template.rb 0000664 0000000 0000000 00000010206 15147275312 0022344 0 ustar 00root root 0000000 0000000 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. Options may be passed.
def initialize(source, options = {})
@source = source
@options = options
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(@options).compile(tokens(src))
end
alias_method :to_s, :compile
# Returns an array of tokens for a given template.
#
# @return [Array] Array of tokens.
#
def tokens(src = @source)
Parser.new(@options).compile(src)
end
# Returns an array of tags.
#
# Tags that belong to sections will be of the form `section1.tag`.
#
# @return [Array] Returns an array of tags.
#
def tags
Template.recursor(tokens, []) do |token, section|
if [:etag, :utag].include?(token[1])
[ new_token=nil, new_section=nil, result=((section + [token[2][2][0]]).join('.')), stop=true ]
elsif [:section, :inverted_section].include?(token[1])
[ new_token=token[4], new_section=(section + [token[2][2][0]]), result=nil, stop=false ]
else
[ new_token=token, new_section=section, result=nil, stop=false ]
end
end.flatten.reject(&:nil?).uniq
end
# Returns an array of sections.
#
# Sections that belong to other sections will be of the form `section1.childsection`
#
# @return [Array] Returns an array of section.
#
def sections
Template.recursor(tokens, []) do |token, section|
if [:section, :inverted_section].include?(token[1])
new_section=(section + [token[2][2][0]])
[ new_token=token[4], new_section, result=new_section.join('.'), stop=false ]
else
[ new_token=token, new_section=section, result=nil, stop=false ]
end
end.flatten.reject(&:nil?).uniq
end
# Returns an array of partials.
#
# Partials that belong to sections are included, but the section name is not preserved
#
# @return [Array] Returns an array of partials.
#
def partials
Template.recursor(tokens, []) do |token, section|
if token[1] == :partial
[ new_token=token, new_section=section, result=token[2], stop=true ]
else
[ new_token=token, new_section=section, result=nil, stop=false ]
end
end.flatten.reject(&:nil?).uniq
end
# Simple recursive iterator for tokens
def self.recursor(toks, section, &block)
toks.map do |token|
next unless token.is_a? Array
if token.first == :mustache
new_token, new_section, result, stop = yield(token, section)
[ result ] + ( stop ? [] : recursor(new_token, new_section, &block))
else
recursor(token, section, &block)
end
end
end
end
end
mustache-mustache-ccc31e2/lib/mustache/utils.rb 0000664 0000000 0000000 00000001243 15147275312 0021672 0 ustar 00root root 0000000 0000000 class Mustache
module Utils
class String
def initialize string
@string = string
end
def classify
@string.split('/').map do |namespace|
namespace.split(/[-_]/).map do |part|
part[0] = part.chars.first.upcase
part
end.join
end.join('::')
end
def underscore(view_namespace)
@string
.dup
.split("#{view_namespace}::")
.last
.split('::')
.map do |part|
part[0] = part[0].downcase
part.gsub(/[A-Z]/) { |s| '_'.dup << s.downcase }
end
.join('/')
end
end
end
end
mustache-mustache-ccc31e2/lib/mustache/version.rb 0000664 0000000 0000000 00000000047 15147275312 0022220 0 ustar 00root root 0000000 0000000 class Mustache
VERSION = '1.1.2'
end
mustache-mustache-ccc31e2/man/ 0000775 0000000 0000000 00000000000 15147275312 0016401 5 ustar 00root root 0000000 0000000 mustache-mustache-ccc31e2/man/mustache.1 0000664 0000000 0000000 00000005762 15147275312 0020306 0 ustar 00root root 0000000 0000000 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3
.
.TH "MUSTACHE" "1" "November 2016" "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 begins 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}}
$ mustache data\.yml template\.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}}!
$ mustache data\.yml template\.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, therefore, 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 <