pax_global_header00006660000000000000000000000064151472753120014521gustar00rootroot0000000000000052 comment=ccc31e29ad46d07e71a754543253d4955c8f95d6 mustache-mustache-ccc31e2/000077500000000000000000000000001514727531200156265ustar00rootroot00000000000000mustache-mustache-ccc31e2/.gitignore000066400000000000000000000001321514727531200176120ustar00rootroot00000000000000docs Gemfile.lock *.gem # IDE .idea # Docs .yardoc doc/* benchmarks/*.html /coverage/ mustache-mustache-ccc31e2/.gitmodules000066400000000000000000000001241514727531200200000ustar00rootroot00000000000000[submodule "ext/spec"] path = ext/spec url = https://github.com/mustache/spec.git mustache-mustache-ccc31e2/.travis.yml000066400000000000000000000007501514727531200177410ustar00rootroot00000000000000language: 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.md000066400000000000000000000010411514727531200200530ustar00rootroot00000000000000# 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/Gemfile000066400000000000000000000001731514727531200171220ustar00rootroot00000000000000source "https://rubygems.org" gemspec group :test do gem "simplecov" gem "codeclimate-test-reporter", "~> 1.0.0" end mustache-mustache-ccc31e2/HISTORY.md000066400000000000000000000172041514727531200173150ustar00rootroot00000000000000## 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/LICENSE000066400000000000000000000020431514727531200166320ustar00rootroot00000000000000Copyright (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.md000066400000000000000000000230131514727531200171040ustar00rootroot00000000000000# Mustache [![Gem Version](https://badge.fury.io/rb/mustache.svg)](http://badge.fury.io/rb/mustache) [![Build Status](https://travis-ci.org/mustache/mustache.svg?branch=master)](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: ## 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: [![Join the chat at https://gitter.im/mustache/mustache](https://badges.gitter.im/Join%20Chat.svg)](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/Rakefile000066400000000000000000000024341514727531200172760ustar00rootroot00000000000000require '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/000077500000000000000000000000001514727531200177435ustar00rootroot00000000000000mustache-mustache-ccc31e2/benchmarks/compile_template_benchmark.rb000066400000000000000000000010641514727531200256260ustar00rootroot00000000000000$:.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.rb000066400000000000000000000015261514727531200253370ustar00rootroot00000000000000$:.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.rb000066400000000000000000000020471514727531200245710ustar00rootroot00000000000000$:.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.rb000066400000000000000000000024571514727531200260040ustar00rootroot00000000000000$:.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.rb000066400000000000000000000021211514727531200254760ustar00rootroot00000000000000$:.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.rb000066400000000000000000000014451514727531200250650ustar00rootroot00000000000000$:.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.rb000066400000000000000000000014231514727531200254600ustar00rootroot00000000000000$:.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.rb000066400000000000000000000027251514727531200254620ustar00rootroot00000000000000$:.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.rb000066400000000000000000000021161514727531200251620ustar00rootroot00000000000000$:.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/000077500000000000000000000000001514727531200163765ustar00rootroot00000000000000mustache-mustache-ccc31e2/bin/mustache000077500000000000000000000051051514727531200201360ustar00rootroot00000000000000#!/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/000077500000000000000000000000001514727531200174445ustar00rootroot00000000000000mustache-mustache-ccc31e2/examples/hash.rb000066400000000000000000000006041514727531200207140ustar00rootroot00000000000000$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.yml000066400000000000000000000000541514727531200211110ustar00rootroot00000000000000--- name: Chris value: 10,000 in_ca: no --- mustache-mustache-ccc31e2/examples/i18n/000077500000000000000000000000001514727531200202235ustar00rootroot00000000000000mustache-mustache-ccc31e2/examples/i18n/mustache_i18n.rb000066400000000000000000000004231514727531200232170ustar00rootroot00000000000000class 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.rb000066400000000000000000000005711514727531200233050ustar00rootroot00000000000000class 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.mustache000066400000000000000000000006731514727531200230360ustar00rootroot00000000000000 projects

projects

{{#projects}}

{{name}}

{{description}}

{{/projects}}
mustache-mustache-ccc31e2/examples/projects.yml000066400000000000000000000014541514727531200220240ustar00rootroot00000000000000--- 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.mustache000066400000000000000000000000621514727531200221260ustar00rootroot00000000000000The Beatles were: {{#names}} * {{.}} {{/names}} mustache-mustache-ccc31e2/examples/self.yml000066400000000000000000000000541514727531200211170ustar00rootroot00000000000000--- names: [ John, Paul, George, Ringo ] ---mustache-mustache-ccc31e2/examples/simple.mustache000066400000000000000000000002601514727531200224660ustar00rootroot00000000000000Hello {{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.rb000066400000000000000000000004741514727531200212670ustar00rootroot00000000000000$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/000077500000000000000000000000001514727531200164265ustar00rootroot00000000000000mustache-mustache-ccc31e2/ext/spec/000077500000000000000000000000001514727531200173605ustar00rootroot00000000000000mustache-mustache-ccc31e2/lib/000077500000000000000000000000001514727531200163745ustar00rootroot00000000000000mustache-mustache-ccc31e2/lib/mustache.rb000066400000000000000000000223201514727531200205310ustar00rootroot00000000000000require '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/000077500000000000000000000000001514727531200202055ustar00rootroot00000000000000mustache-mustache-ccc31e2/lib/mustache/context.rb000066400000000000000000000122151514727531200222170ustar00rootroot00000000000000require '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.rb000066400000000000000000000006701514727531200232540ustar00rootroot00000000000000class 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.rb000066400000000000000000000000551514727531200226510ustar00rootroot00000000000000class Mustache Enumerable = Module.new end mustache-mustache-ccc31e2/lib/mustache/generator.rb000066400000000000000000000142471514727531200225300ustar00rootroot00000000000000class 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.rb000066400000000000000000000267061514727531200220410ustar00rootroot00000000000000require '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.rb000066400000000000000000000132261514727531200223760ustar00rootroot00000000000000# 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.rb000066400000000000000000000102061514727531200223440ustar00rootroot00000000000000require '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.rb000066400000000000000000000012431514727531200216720ustar00rootroot00000000000000class 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.rb000066400000000000000000000000471514727531200222200ustar00rootroot00000000000000class Mustache VERSION = '1.1.2' end mustache-mustache-ccc31e2/man/000077500000000000000000000000001514727531200164015ustar00rootroot00000000000000mustache-mustache-ccc31e2/man/mustache.1000066400000000000000000000057621514727531200203060ustar00rootroot00000000000000.\" 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 < mustache(1) - Mustache processor
  1. mustache(1)
  2. Mustache Manual
  3. mustache(1)

NAME

mustache - Mustache processor

SYNOPSIS

mustache <YAML> <FILE>
mustache --compile <FILE>
mustache --tokens <FILE>

DESCRIPTION

Mustache is a logic-less templating system for HTML, config files, anything.

The mustache command processes a Mustache template preceded by YAML frontmatter from standard input and prints one or more documents to standard output.

YAML frontmatter begins with --- on a single line, followed by YAML, ending with another --- on a single line, e.g.

---
names: [ {name: chris}, {name: mark}, {name: scott} ]
---

If you are unfamiliar with YAML, it is a superset of JSON. Valid JSON should work fine.

After the frontmatter should come any valid Mustache template. See mustache(5) for an overview of Mustache templates.

For example:

{{#names}}
  Hi {{name}}!
{{/names}}

Now let's combine them.

$ 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!

If you provide multiple YAML documents (as delimited by ---), your template will be rendered multiple times. Like a mail merge.

For example:

$ 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!

OPTIONS

By default mustache will try to render a Mustache template using the YAML frontmatter you provide. It can do a few other things, however.

-c, --compile

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.

-t, --tokens

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.

INSTALLATION

If you have RubyGems installed:

gem install mustache

EXAMPLES

$ mustache data.yml template.mustache
$ cat data.yml | mustache - template.mustache
$ mustache -c template.mustache
$ cat <<data | ruby mustache - template.mustache
---
name: Bob
age: 30
---
data

Mustache is Copyright (C) 2009 Chris Wanstrath

Original CTemplate by Google

SEE ALSO

mustache(5), gem(1), http://mustache.github.io/

  1. DEFUNKT
  2. November 2016
  3. mustache(1)
mustache-mustache-ccc31e2/man/mustache.1.ron000066400000000000000000000053221514727531200210730ustar00rootroot00000000000000mustache(1) -- Mustache processor ================================= ## SYNOPSIS mustache mustache --compile mustache --tokens ## DESCRIPTION Mustache is a logic-less templating system for HTML, config files, anything. The `mustache` command processes a Mustache template preceded by YAML frontmatter from standard input and prints one or more documents to standard output. YAML frontmatter begins with `---` on a single line, followed by YAML, ending with another `---` on a single line, e.g. --- names: [ {name: chris}, {name: mark}, {name: scott} ] --- If you are unfamiliar with YAML, it is a superset of JSON. Valid JSON should work fine. After the frontmatter should come any valid Mustache template. See mustache(5) for an overview of Mustache templates. For example: {{#names}} Hi {{name}}! {{/names}} Now let's combine them. $ 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! If you provide multiple YAML documents (as delimited by `---`), your template will be rendered multiple times. Like a mail merge. For example: $ 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! ## OPTIONS By default `mustache` will try to render a Mustache template using the YAML frontmatter you provide. It can do a few other things, however. * `-c`, `--compile`: 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. * `-t`, `--tokens`: 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. ## INSTALLATION If you have RubyGems installed: gem install mustache ## EXAMPLES $ mustache data.yml template.mustache $ cat data.yml | mustache - template.mustache $ mustache -c template.mustache $ cat < mustache-mustache-ccc31e2/man/mustache.5000066400000000000000000000334001514727531200203000ustar00rootroot00000000000000.\" generated with Ronn-NG/v0.9.1 .\" http://github.com/apjanke/ronn-ng/tree/0.9.1 .TH "MUSTACHE" "5" "September 2022" "DEFUNKT" "Mustache Manual" .SH "NAME" \fBmustache\fR \- Logic\-less templates\. .SH "SYNOPSIS" A typical Mustache template: .IP "" 4 .nf Hello {{name}} You have just won {{value}} dollars! {{#in_ca}} Well, {{taxed_value}} dollars, after taxes\. {{/in_ca}} .fi .IP "" 0 .P Given the following hash: .IP "" 4 .nf { "name": "Chris", "value": 10000, "taxed_value": 10000 \- (10000 * 0\.4), "in_ca": true } .fi .IP "" 0 .P Will produce the following: .IP "" 4 .nf Hello Chris You have just won 10000 dollars! Well, 6000\.0 dollars, after taxes\. .fi .IP "" 0 .SH "DESCRIPTION" Mustache can be used for HTML, config files, source code \- anything\. It works by expanding tags in a template using values provided in a hash or object\. .P We call it "logic\-less" because there are no if statements, else clauses, or for loops\. Instead there are only tags\. Some tags are replaced with a value, some nothing, and others a series of values\. This document explains the different types of Mustache tags\. .P The Mustache language has a formal specification \fIhttps://github\.com/mustache/spec\fR\. The current manpage reflects version 1\.3\.0 of the specification, including the official\-but\-optional extensions for lambdas and inheritance\. .SH "TAG TYPES" Tags are indicated by the double mustaches\. \fB{{person}}\fR is a tag, as is \fB{{#person}}\fR\. In both examples, we'd refer to \fBperson\fR as the key or tag key\. Let's talk about the different types of tags\. .SS "Variables" The most basic tag type is the variable\. A \fB{{name}}\fR tag in a basic template will try to find the \fBname\fR key in the current context\. If there is no \fBname\fR key, the parent contexts will be checked recursively\. If the top context is reached and the \fBname\fR key is still not found, nothing will be rendered\. .P All variables are HTML escaped by default\. If you want to return raw contents without escaping, use the triple mustache: \fB{{{name}}}\fR\. .P You can also use \fB&\fR to return its raw contents: \fB{{& name}}\fR\. This may be useful when changing delimiters (see "Set Delimiter" below)\. .P By default a variable "miss" returns an empty string\. This can usually be configured in your Mustache library\. The Ruby version of Mustache supports raising an exception in this situation, for instance\. .P Template: .IP "" 4 .nf * {{name}} * {{age}} * {{company}} * {{{company}}} .fi .IP "" 0 .P Hash: .IP "" 4 .nf { "name": "Chris", "company": "GitHub" } .fi .IP "" 0 .P Output: .IP "" 4 .nf * Chris * * <b>GitHub</b> * GitHub .fi .IP "" 0 .P \fBDotted Names\fR .P If the \fBname\fR contains dots, it is split on the dots to obtain multiple keys\. The first key is looked up in the context as described above\. If it is found, the next key is looked up within the previous result\. This is repeated until a key is not found or until the last key is found\. The final result is interpolated as above\. .P Template: .IP "" 4 .nf * {{client\.name}} * {{age}} * {{client\.company\.name}} * {{{company\.name}}} .fi .IP "" 0 .P Hash: .IP "" 4 .nf { "client": { "name": "Chris & Friends", "age": 50 }, "company": { "name": "GitHub" } } .fi .IP "" 0 .P Output: .IP "" 4 .nf * Chris & Friends * * * GitHub .fi .IP "" 0 .P \fBImplicit Iterator\fR .P As a special case, if the \fBname\fR consists of only a dot and nothing else, the value that is the current context is interpolated as a whole\. This is especially useful if the parent context is a list; see \fBSections\fR below\. .P Template: .IP "" 4 .nf * {{\.}} .fi .IP "" 0 .P Current context: .IP "" 4 .nf "Hello!" .fi .IP "" 0 .P Output: .IP "" 4 .nf * Hello! .fi .IP "" 0 .P \fBLambdas\fR .P If any value found during the lookup is a callable object, such as a function or lambda, this object will be invoked with zero arguments\. The value that is returned is then used instead of the callable object itself\. .P An \fBoptional\fR part of the specification states that if the final key in the \fBname\fR is a lambda that returns a string, then that string should be rendered as a Mustache template before interpolation\. It will be rendered using the default delimiters (see \fBSet Delimiter\fR below) against the current context\. .P Template: .IP "" 4 .nf * {{time\.hour}} * {{today}} .fi .IP "" 0 .P Hash: .IP "" 4 .nf { "year": 1970, "month": 1, "day": 1, "time": function() { return { "hour": 0, "minute": 0, "second": 0 } }, "today": function() { return "{{year}}\-{{month}}\-{{day}}" } } .fi .IP "" 0 .P Output: .IP "" 4 .nf * 0 * 1970\-1\-1 .fi .IP "" 0 .SS "Sections" Sections render blocks of text zero or more times, depending on the value of the key in the current context\. .P Lookup of dotted names works in the same way as with variables, except for slightly different treatment of lambdas\. More on this below\. .P A section begins with a pound and ends with a slash\. That is, \fB{{#person}}\fR begins a "person" section while \fB{{/person}}\fR ends it\. .P The behavior of the section is determined by the final value of the key lookup\. .P \fBFalse Values or Empty Lists\fR .P If the \fBperson\fR key exists and has a value of false or an empty list, the HTML between the pound and slash will not be displayed\. .P Template: .IP "" 4 .nf Shown\. {{#person}} Never shown! {{/person}} .fi .IP "" 0 .P Hash: .IP "" 4 .nf { "person": false } .fi .IP "" 0 .P Output: .IP "" 4 .nf Shown\. .fi .IP "" 0 .P \fBNon\-Empty Lists\fR .P If the \fBperson\fR key exists and has a non\-false value, the HTML between the pound and slash will be rendered and displayed one or more times\. .P When the value is a non\-empty list, the text in the block will be displayed once for each item in the list\. The context of the block will be set to the current item for each iteration\. In this way we can loop over collections\. .P Template: .IP "" 4 .nf {{#repo}} {{name}} {{/repo}} .fi .IP "" 0 .P Hash: .IP "" 4 .nf { "repo": [ { "name": "resque" }, { "name": "hub" }, { "name": "rip" } ] } .fi .IP "" 0 .P Output: .IP "" 4 .nf resque hub rip .fi .IP "" 0 .P The same effect as above can be obtained without nested objects, by using the implicit iterator (see \fBVariables\fR above)\. .P Template: .IP "" 4 .nf {{#repo}} {{\.}} {{/repo}} .fi .IP "" 0 .P Hash: .IP "" 4 .nf { "repo": ["resque", "hub", "rip"] } .fi .IP "" 0 .P Output: .IP "" 4 .nf resque hub rip .fi .IP "" 0 .P \fBLambdas\fR .P When any value found during the lookup is a callable object, such as a function or lambda, the object will be invoked and passed the block of text\. The text passed is the literal block, unrendered\. \fB{{tags}}\fR will not have been expanded\. .P An \fBoptional\fR part of the specification states that if the final key in the \fBname\fR is a lambda that returns a string, then that string replaces the content of the section\. It will be rendered using the same delimiters (see \fBSet Delimiter\fR below) as the original section content\. In this way you can implement filters or caching\. .P Template: .IP "" 4 .nf {{#wrapped}}{{name}} is awesome\.{{/wrapped}} .fi .IP "" 0 .P Hash: .IP "" 4 .nf { "name": "Willy", "wrapped": function(text) { return "" + text + "" } } .fi .IP "" 0 .P Output: .IP "" 4 .nf Willy is awesome\. .fi .IP "" 0 .P \fBNon\-False Values\fR .P When the value is non\-false but not a list, it will be used as the context for a single rendering of the block\. .P Template: .IP "" 4 .nf {{#person?}} Hi {{name}}! {{/person?}} .fi .IP "" 0 .P Hash: .IP "" 4 .nf { "person?": { "name": "Jon" } } .fi .IP "" 0 .P Output: .IP "" 4 .nf Hi Jon! .fi .IP "" 0 .SS "Inverted Sections" An inverted section begins with a caret (hat) and ends with a slash\. That is \fB{{^person}}\fR begins a "person" inverted section while \fB{{/person}}\fR ends it\. .P While sections can be used to render text zero or more times based on the value of the key, inverted sections may render text once based on the inverse value of the key\. That is, they will be rendered if the key doesn't exist, is false, or is an empty list\. .P Template: .IP "" 4 .nf {{#repo}} {{name}} {{/repo}} {{^repo}} No repos :( {{/repo}} .fi .IP "" 0 .P Hash: .IP "" 4 .nf { "repo": [] } .fi .IP "" 0 .P Output: .IP "" 4 .nf No repos :( .fi .IP "" 0 .SS "Comments" Comments begin with a bang and are ignored\. The following template: .IP "" 4 .nf

Today{{! ignore me }}\.

.fi .IP "" 0 .P Will render as follows: .IP "" 4 .nf

Today\.

.fi .IP "" 0 .P Comments may contain newlines\. .SS "Partials" Partials begin with a greater than sign, like \fB{{> box}}\fR\. .P Partials are rendered at runtime (as opposed to compile time), so recursive partials are possible\. Just avoid infinite loops\. .P They also inherit the calling context\. Whereas in ERB you may have this: .IP "" 4 .nf <%= partial :next_more, :start => start, :size => size %> .fi .IP "" 0 .P Mustache requires only this: .IP "" 4 .nf {{> next_more}} .fi .IP "" 0 .P Why? Because the \fBnext_more\.mustache\fR file will inherit the \fBsize\fR and \fBstart\fR methods from the calling context\. .P In this way you may want to think of partials as includes, or template expansion, even though it's not literally true\. .P For example, this template and partial: .IP "" 4 .nf base\.mustache:

Names

{{#names}} {{> user}} {{/names}} user\.mustache: {{name}} .fi .IP "" 0 .P Can be thought of as a single, expanded template: .IP "" 4 .nf

Names

{{#names}} {{name}} {{/names}} .fi .IP "" 0 .P \fBDynamic Names\fR .P Partials can be loaded dynamically at runtime using Dynamic Names; an \fBoptional\fR part of the Mustache specification which allows to dynamically determine a tag's content at runtime\. .P Dynamic Names consists of an asterisk, followed by a dotted name which follows the same notation and the same resolution as in an variable tag\. That is \fB{{>*dynamic}}\fR\. It can be thought as the following \fBhypothetical\fR tag (which is \fBnot allowed\fR!): \fB{{>{{dynamic}}}}\fR\. .P Templates: .IP "" 4 .nf main\.mustache: Hello {{>*dynamic}} world\.template: everyone! .fi .IP "" 0 .P Hash: .IP "" 4 .nf { "dynamic": "world" } .fi .IP "" 0 .P Output: .IP "" 4 .nf Hello everyone! .fi .IP "" 0 .SS "Blocks" A block begins with a dollar and ends with a slash\. That is, \fB{{$title}}\fR begins a "title" block and \fB{{/title}}\fR ends it\. .P Blocks mark parts of the template that may be overridden\. This can be done with a block of the same name within a parent section in the calling template (see \fBParents\fR below)\. If not overridden, the contents of a block render just as if the \fB{{$title}}\fR and \fB{{/title}}\fR tags weren't there\. .P Blocks could be thought of as template parameters or as inline partials that may be passed to another template\. They are part of the optional inheritance extension\. .P Template \fBarticle\.mustache\fR: .IP "" 4 .nf

{{$title}}The News of Today{{/title}}

{{$body}}

Nothing special happened\.

{{/body}} .fi .IP "" 0 .P Output: .IP "" 4 .nf

The News of Today

Nothing special happened\.

.fi .IP "" 0 .SS "Parents" A parent begins with a less than sign and ends with a slash\. That is, \fB{{article}}\fR partial, a parent lets you expand another template inside the current one\. Unlike a partial, a parent also lets you override blocks of the other template\. .P Blocks within a parent can again be overridden by another including template\. Other content within a parent is ignored, like comments\. .P Template: .IP "" 4 .nf {{{{\.}}

{{/headlines}} {{/body}} {{/article}} {{The News of Today

A pug's handler grew mustaches\.

What an exciting day!

Yesterday

Nothing special happened\.

.fi .IP "" 0 .P \fBDynamic Names\fR .P Some mustache implementations may allow the use of Dynamic Names in parent tags, similar to dynamic names in partials\. Here's an example of how Dynamic Names in parent tags work\. .P Templates: .IP "" 4 .nf {{!normal\.mustache}} {{$text}}Here goes nothing\.{{/text}} {{!bold\.mustache}} {{$text}}Here also goes nothing but it's bold\.{{/text}} {{!dynamic\.mustache}} {{<*dynamic}} {{$text}}Hello World!{{/text}} {{/*dynamic}} .fi .IP "" 0 .P Hash: .IP "" 4 .nf { "dynamic": "bold" } .fi .IP "" 0 .P Output: .IP "" 4 .nf Hello World! .fi .IP "" 0 .SS "Set Delimiter" Set Delimiter tags start with an equal sign and change the tag delimiters from \fB{{\fR and \fB}}\fR to custom strings\. .P Consider the following contrived example: .IP "" 4 .nf * {{default_tags}} {{=<% %>=}} * <% erb_style_tags %> <%={{ }}=%> * {{ default_tags_again }} .fi .IP "" 0 .P Here we have a list with three items\. The first item uses the default tag style, the second uses erb style as defined by the Set Delimiter tag, and the third returns to the default style after yet another Set Delimiter declaration\. .P According to ctemplates \fIhttp://goog\-ctemplate\.sourceforge\.net/doc/howto\.html\fR, this "is useful for languages like TeX, where double\-braces may occur in the text and are awkward to use for markup\." .P Custom delimiters may not contain whitespace or the equals sign\. .SH "COPYRIGHT" Mustache is Copyright (C) 2009 Chris Wanstrath .P Original CTemplate by Google .SH "SEE ALSO" mustache(1), \fIhttp://mustache\.github\.io/\fR mustache-mustache-ccc31e2/man/mustache.5.html000066400000000000000000000445361514727531200212570ustar00rootroot00000000000000 mustache(5) - Logic-less templates.
  1. mustache(5)
  2. Mustache Manual
  3. mustache(5)

NAME

mustache - Logic-less templates.

SYNOPSIS

A typical Mustache template:

Hello {{name}}
You have just won {{value}} dollars!
{{#in_ca}}
Well, {{taxed_value}} dollars, after taxes.
{{/in_ca}}

Given the following hash:

{
  "name": "Chris",
  "value": 10000,
  "taxed_value": 10000 - (10000 * 0.4),
  "in_ca": true
}

Will produce the following:

Hello Chris
You have just won 10000 dollars!
Well, 6000.0 dollars, after taxes.

DESCRIPTION

Mustache can be used for HTML, config files, source code - anything. It works by expanding tags in a template using values provided in a hash or object.

We call it "logic-less" because there are no if statements, else clauses, or for loops. Instead there are only tags. Some tags are replaced with a value, some nothing, and others a series of values. This document explains the different types of Mustache tags.

The Mustache language has a formal specification. The current manpage reflects version 1.3.0 of the specification, including the official-but-optional extensions for lambdas and inheritance.

TAG TYPES

Tags are indicated by the double mustaches. {{person}} is a tag, as is {{#person}}. In both examples, we'd refer to person as the key or tag key. Let's talk about the different types of tags.

Variables

The most basic tag type is the variable. A {{name}} tag in a basic template will try to find the name key in the current context. If there is no name key, the parent contexts will be checked recursively. If the top context is reached and the name key is still not found, nothing will be rendered.

All variables are HTML escaped by default. If you want to return raw contents without escaping, use the triple mustache: {{{name}}}.

You can also use & to return its raw contents: {{& name}}. This may be useful when changing delimiters (see "Set Delimiter" below).

By default a variable "miss" returns an empty string. This can usually be configured in your Mustache library. The Ruby version of Mustache supports raising an exception in this situation, for instance.

Template:

* {{name}}
* {{age}}
* {{company}}
* {{{company}}}

Hash:

{
  "name": "Chris",
  "company": "<b>GitHub</b>"
}

Output:

* Chris
*
* &lt;b&gt;GitHub&lt;/b&gt;
* <b>GitHub</b>

Dotted Names

If the name contains dots, it is split on the dots to obtain multiple keys. The first key is looked up in the context as described above. If it is found, the next key is looked up within the previous result. This is repeated until a key is not found or until the last key is found. The final result is interpolated as above.

Template:

* {{client.name}}
* {{age}}
* {{client.company.name}}
* {{{company.name}}}

Hash:

{
  "client": {
    "name": "Chris & Friends",
    "age": 50
  },
  "company": {
    "name": "<b>GitHub</b>"
  }
}

Output:

* Chris &amp; Friends
*
*
* <b>GitHub</b>

Implicit Iterator

As a special case, if the name consists of only a dot and nothing else, the value that is the current context is interpolated as a whole. This is especially useful if the parent context is a list; see Sections below.

Template:

* {{.}}

Current context:

"Hello!"

Output:

* Hello!

Lambdas

If any value found during the lookup is a callable object, such as a function or lambda, this object will be invoked with zero arguments. The value that is returned is then used instead of the callable object itself.

An optional part of the specification states that if the final key in the name is a lambda that returns a string, then that string should be rendered as a Mustache template before interpolation. It will be rendered using the default delimiters (see Set Delimiter below) against the current context.

Template:

* {{time.hour}}
* {{today}}

Hash:

{
  "year": 1970,
  "month": 1,
  "day": 1,
  "time": function() {
    return {
      "hour": 0,
      "minute": 0,
      "second": 0
    }
  },
  "today": function() {
    return "{{year}}-{{month}}-{{day}}"
  }
}

Output:

* 0
* 1970-1-1

Sections

Sections render blocks of text zero or more times, depending on the value of the key in the current context.

Lookup of dotted names works in the same way as with variables, except for slightly different treatment of lambdas. More on this below.

A section begins with a pound and ends with a slash. That is, {{#person}} begins a "person" section while {{/person}} ends it.

The behavior of the section is determined by the final value of the key lookup.

False Values or Empty Lists

If the person key exists and has a value of false or an empty list, the HTML between the pound and slash will not be displayed.

Template:

Shown.
{{#person}}
  Never shown!
{{/person}}

Hash:

{
  "person": false
}

Output:

Shown.

Non-Empty Lists

If the person key exists and has a non-false value, the HTML between the pound and slash will be rendered and displayed one or more times.

When the value is a non-empty list, the text in the block will be displayed once for each item in the list. The context of the block will be set to the current item for each iteration. In this way we can loop over collections.

Template:

{{#repo}}
  <b>{{name}}</b>
{{/repo}}

Hash:

{
  "repo": [
    { "name": "resque" },
    { "name": "hub" },
    { "name": "rip" }
  ]
}

Output:

  <b>resque</b>
  <b>hub</b>
  <b>rip</b>

The same effect as above can be obtained without nested objects, by using the implicit iterator (see Variables above).

Template:

{{#repo}}
  <b>{{.}}</b>
{{/repo}}

Hash:

{
  "repo": ["resque", "hub", "rip"]
}

Output:

  <b>resque</b>
  <b>hub</b>
  <b>rip</b>

Lambdas

When any value found during the lookup is a callable object, such as a function or lambda, the object will be invoked and passed the block of text. The text passed is the literal block, unrendered. {{tags}} will not have been expanded.

An optional part of the specification states that if the final key in the name is a lambda that returns a string, then that string replaces the content of the section. It will be rendered using the same delimiters (see Set Delimiter below) as the original section content. In this way you can implement filters or caching.

Template:

{{#wrapped}}{{name}} is awesome.{{/wrapped}}

Hash:

{
  "name": "Willy",
  "wrapped": function(text) {
    return "<b>" + text + "</b>"
  }
}

Output:

<b>Willy is awesome.</b>

Non-False Values

When the value is non-false but not a list, it will be used as the context for a single rendering of the block.

Template:

{{#person?}}
  Hi {{name}}!
{{/person?}}

Hash:

{
  "person?": { "name": "Jon" }
}

Output:

  Hi Jon!

Inverted Sections

An inverted section begins with a caret (hat) and ends with a slash. That is {{^person}} begins a "person" inverted section while {{/person}} ends it.

While sections can be used to render text zero or more times based on the value of the key, inverted sections may render text once based on the inverse value of the key. That is, they will be rendered if the key doesn't exist, is false, or is an empty list.

Template:

{{#repo}}
  <b>{{name}}</b>
{{/repo}}
{{^repo}}
  No repos :(
{{/repo}}

Hash:

{
  "repo": []
}

Output:

  No repos :(

Comments

Comments begin with a bang and are ignored. The following template:

<h1>Today{{! ignore me }}.</h1>

Will render as follows:

<h1>Today.</h1>

Comments may contain newlines.

Partials

Partials begin with a greater than sign, like {{> box}}.

Partials are rendered at runtime (as opposed to compile time), so recursive partials are possible. Just avoid infinite loops.

They also inherit the calling context. Whereas in ERB you may have this:

<%= partial :next_more, :start => start, :size => size %>

Mustache requires only this:

{{> next_more}}

Why? Because the next_more.mustache file will inherit the size and start methods from the calling context.

In this way you may want to think of partials as includes, or template expansion, even though it's not literally true.

For example, this template and partial:

base.mustache:
<h2>Names</h2>
{{#names}}
  {{> user}}
{{/names}}

user.mustache:
<strong>{{name}}</strong>

Can be thought of as a single, expanded template:

<h2>Names</h2>
{{#names}}
  <strong>{{name}}</strong>
{{/names}}

Dynamic Names

Partials can be loaded dynamically at runtime using Dynamic Names; an optional part of the Mustache specification which allows to dynamically determine a tag's content at runtime.

Dynamic Names consists of an asterisk, followed by a dotted name which follows the same notation and the same resolution as in an variable tag. That is {{>*dynamic}}. It can be thought as the following hypothetical tag (which is not allowed!): {{>{{dynamic}}}}.

Templates:

main.mustache:
Hello {{>*dynamic}}

world.template:
everyone!

Hash:

{
  "dynamic": "world"
}

Output:

Hello everyone!

Blocks

A block begins with a dollar and ends with a slash. That is, {{$title}} begins a "title" block and {{/title}} ends it.

Blocks mark parts of the template that may be overridden. This can be done with a block of the same name within a parent section in the calling template (see Parents below). If not overridden, the contents of a block render just as if the {{$title}} and {{/title}} tags weren't there.

Blocks could be thought of as template parameters or as inline partials that may be passed to another template. They are part of the optional inheritance extension.

Template article.mustache:

<h1>{{$title}}The News of Today{{/title}}</h1>
{{$body}}
<p>Nothing special happened.</p>
{{/body}}

Output:

<h1>The News of Today</h1>
<p>Nothing special happened.</p>

Parents

A parent begins with a less than sign and ends with a slash. That is, {{<article}} begins an "article" parent and {{/article}} ends it.

Like an {{>article}} partial, a parent lets you expand another template inside the current one. Unlike a partial, a parent also lets you override blocks of the other template.

Blocks within a parent can again be overridden by another including template. Other content within a parent is ignored, like comments.

Template:

{{<article}}
  Never shown
  {{$body}}
    {{#headlines}}
    <p>{{.}}</p>
    {{/headlines}}
  {{/body}}
{{/article}}

{{<article}}
  {{$title}}Yesterday{{/title}}
{{/article}}

Hash:

{
  "headlines": [
    "A pug's handler grew mustaches.",
    "What an exciting day!"
  ]
}

Output, assuming the article.mustache from before:

<h1>The News of Today</h1>
<p>A pug's handler grew mustaches.</p>
<p>What an exciting day!</p>

<h1>Yesterday</h1>
<p>Nothing special happened.</p>

Dynamic Names

Some mustache implementations may allow the use of Dynamic Names in parent tags, similar to dynamic names in partials. Here's an example of how Dynamic Names in parent tags work.

Templates:

{{!normal.mustache}}
{{$text}}Here goes nothing.{{/text}}

{{!bold.mustache}}
<b>{{$text}}Here also goes nothing but it's bold.{{/text}}</b>

{{!dynamic.mustache}}
{{<*dynamic}}
  {{$text}}Hello World!{{/text}}
{{/*dynamic}}

Hash:

{
  "dynamic": "bold"
}

Output:

<b>Hello World!</b>

Set Delimiter

Set Delimiter tags start with an equal sign and change the tag delimiters from {{ and }} to custom strings.

Consider the following contrived example:

* {{default_tags}}
{{=<% %>=}}
* <% erb_style_tags %>
<%={{ }}=%>
* {{ default_tags_again }}

Here we have a list with three items. The first item uses the default tag style, the second uses erb style as defined by the Set Delimiter tag, and the third returns to the default style after yet another Set Delimiter declaration.

According to ctemplates, this "is useful for languages like TeX, where double-braces may occur in the text and are awkward to use for markup."

Custom delimiters may not contain whitespace or the equals sign.

Mustache is Copyright (C) 2009 Chris Wanstrath

Original CTemplate by Google

SEE ALSO

mustache(1), http://mustache.github.io/

  1. DEFUNKT
  2. September 2022
  3. mustache(5)
mustache-mustache-ccc31e2/man/mustache.5.ron000066400000000000000000000312051514727531200210760ustar00rootroot00000000000000mustache(5) -- Logic-less templates. ==================================== ## SYNOPSIS A typical Mustache template: Hello {{name}} You have just won {{value}} dollars! {{#in_ca}} Well, {{taxed_value}} dollars, after taxes. {{/in_ca}} Given the following hash: { "name": "Chris", "value": 10000, "taxed_value": 10000 - (10000 * 0.4), "in_ca": true } Will produce the following: Hello Chris You have just won 10000 dollars! Well, 6000.0 dollars, after taxes. ## DESCRIPTION Mustache can be used for HTML, config files, source code - anything. It works by expanding tags in a template using values provided in a hash or object. We call it "logic-less" because there are no if statements, else clauses, or for loops. Instead there are only tags. Some tags are replaced with a value, some nothing, and others a series of values. This document explains the different types of Mustache tags. The Mustache language has a [formal specification][spec]. The current manpage reflects version 1.3.0 of the specification, including the official-but-optional extensions for lambdas and inheritance. [spec]: https://github.com/mustache/spec ## TAG TYPES Tags are indicated by the double mustaches. `{{person}}` is a tag, as is `{{#person}}`. In both examples, we'd refer to `person` as the key or tag key. Let's talk about the different types of tags. ### Variables The most basic tag type is the variable. A `{{name}}` tag in a basic template will try to find the `name` key in the current context. If there is no `name` key, the parent contexts will be checked recursively. If the top context is reached and the `name` key is still not found, nothing will be rendered. All variables are HTML escaped by default. If you want to return raw contents without escaping, use the triple mustache: `{{{name}}}`. You can also use `&` to return its raw contents: `{{& name}}`. This may be useful when changing delimiters (see "Set Delimiter" below). By default a variable "miss" returns an empty string. This can usually be configured in your Mustache library. The Ruby version of Mustache supports raising an exception in this situation, for instance. Template: * {{name}} * {{age}} * {{company}} * {{{company}}} Hash: { "name": "Chris", "company": "GitHub" } Output: * Chris * * <b>GitHub</b> * GitHub **Dotted Names** If the `name` contains dots, it is split on the dots to obtain multiple keys. The first key is looked up in the context as described above. If it is found, the next key is looked up within the previous result. This is repeated until a key is not found or until the last key is found. The final result is interpolated as above. Template: * {{client.name}} * {{age}} * {{client.company.name}} * {{{company.name}}} Hash: { "client": { "name": "Chris & Friends", "age": 50 }, "company": { "name": "GitHub" } } Output: * Chris & Friends * * * GitHub **Implicit Iterator** As a special case, if the `name` consists of only a dot and nothing else, the value that is the current context is interpolated as a whole. This is especially useful if the parent context is a list; see **Sections** below. Template: * {{.}} Current context: "Hello!" Output: * Hello! **Lambdas** If any value found during the lookup is a callable object, such as a function or lambda, this object will be invoked with zero arguments. The value that is returned is then used instead of the callable object itself. An **optional** part of the specification states that if the final key in the `name` is a lambda that returns a string, then that string should be rendered as a Mustache template before interpolation. It will be rendered using the default delimiters (see **Set Delimiter** below) against the current context. Template: * {{time.hour}} * {{today}} Hash: { "year": 1970, "month": 1, "day": 1, "time": function() { return { "hour": 0, "minute": 0, "second": 0 } }, "today": function() { return "{{year}}-{{month}}-{{day}}" } } Output: * 0 * 1970-1-1 ### Sections Sections render blocks of text zero or more times, depending on the value of the key in the current context. Lookup of dotted names works in the same way as with variables, except for slightly different treatment of lambdas. More on this below. A section begins with a pound and ends with a slash. That is, `{{#person}}` begins a "person" section while `{{/person}}` ends it. The behavior of the section is determined by the final value of the key lookup. **False Values or Empty Lists** If the `person` key exists and has a value of false or an empty list, the HTML between the pound and slash will not be displayed. Template: Shown. {{#person}} Never shown! {{/person}} Hash: { "person": false } Output: Shown. **Non-Empty Lists** If the `person` key exists and has a non-false value, the HTML between the pound and slash will be rendered and displayed one or more times. When the value is a non-empty list, the text in the block will be displayed once for each item in the list. The context of the block will be set to the current item for each iteration. In this way we can loop over collections. Template: {{#repo}} {{name}} {{/repo}} Hash: { "repo": [ { "name": "resque" }, { "name": "hub" }, { "name": "rip" } ] } Output: resque hub rip The same effect as above can be obtained without nested objects, by using the implicit iterator (see **Variables** above). Template: {{#repo}} {{.}} {{/repo}} Hash: { "repo": ["resque", "hub", "rip"] } Output: resque hub rip **Lambdas** When any value found during the lookup is a callable object, such as a function or lambda, the object will be invoked and passed the block of text. The text passed is the literal block, unrendered. `{{tags}}` will not have been expanded. An **optional** part of the specification states that if the final key in the `name` is a lambda that returns a string, then that string replaces the content of the section. It will be rendered using the same delimiters (see **Set Delimiter** below) as the original section content. In this way you can implement filters or caching. Template: {{#wrapped}}{{name}} is awesome.{{/wrapped}} Hash: { "name": "Willy", "wrapped": function(text) { return "" + text + "" } } Output: Willy is awesome. **Non-False Values** When the value is non-false but not a list, it will be used as the context for a single rendering of the block. Template: {{#person?}} Hi {{name}}! {{/person?}} Hash: { "person?": { "name": "Jon" } } Output: Hi Jon! ### Inverted Sections An inverted section begins with a caret (hat) and ends with a slash. That is `{{^person}}` begins a "person" inverted section while `{{/person}}` ends it. While sections can be used to render text zero or more times based on the value of the key, inverted sections may render text once based on the inverse value of the key. That is, they will be rendered if the key doesn't exist, is false, or is an empty list. Template: {{#repo}} {{name}} {{/repo}} {{^repo}} No repos :( {{/repo}} Hash: { "repo": [] } Output: No repos :( ### Comments Comments begin with a bang and are ignored. The following template:

Today{{! ignore me }}.

Will render as follows:

Today.

Comments may contain newlines. ### Partials Partials begin with a greater than sign, like `{{> box}}`. Partials are rendered at runtime (as opposed to compile time), so recursive partials are possible. Just avoid infinite loops. They also inherit the calling context. Whereas in ERB you may have this: <%= partial :next_more, :start => start, :size => size %> Mustache requires only this: {{> next_more}} Why? Because the `next_more.mustache` file will inherit the `size` and `start` methods from the calling context. In this way you may want to think of partials as includes, or template expansion, even though it's not literally true. For example, this template and partial: base.mustache:

Names

{{#names}} {{> user}} {{/names}} user.mustache: {{name}} Can be thought of as a single, expanded template:

Names

{{#names}} {{name}} {{/names}} **Dynamic Names** Partials can be loaded dynamically at runtime using Dynamic Names; an **optional** part of the Mustache specification which allows to dynamically determine a tag's content at runtime. Dynamic Names consists of an asterisk, followed by a dotted name which follows the same notation and the same resolution as in an variable tag. That is `{{>*dynamic}}`. It can be thought as the following **hypothetical** tag (which is **not allowed**!): `{{>{{dynamic}}}}`. Templates: main.mustache: Hello {{>*dynamic}} world.template: everyone! Hash: { "dynamic": "world" } Output: Hello everyone! ### Blocks A block begins with a dollar and ends with a slash. That is, `{{$title}}` begins a "title" block and `{{/title}}` ends it. Blocks mark parts of the template that may be overridden. This can be done with a block of the same name within a parent section in the calling template (see **Parents** below). If not overridden, the contents of a block render just as if the `{{$title}}` and `{{/title}}` tags weren't there. Blocks could be thought of as template parameters or as inline partials that may be passed to another template. They are part of the optional inheritance extension. Template `article.mustache`:

{{$title}}The News of Today{{/title}}

{{$body}}

Nothing special happened.

{{/body}} Output:

The News of Today

Nothing special happened.

### Parents A parent begins with a less than sign and ends with a slash. That is, `{{article}}` partial, a parent lets you expand another template inside the current one. Unlike a partial, a parent also lets you override blocks of the other template. Blocks within a parent can again be overridden by another including template. Other content within a parent is ignored, like comments. Template: {{{{.}}

{{/headlines}} {{/body}} {{/article}} {{The News of Today

A pug's handler grew mustaches.

What an exciting day!

Yesterday

Nothing special happened.

**Dynamic Names** Some mustache implementations may allow the use of Dynamic Names in parent tags, similar to dynamic names in partials. Here's an example of how Dynamic Names in parent tags work. Templates: {{!normal.mustache}} {{$text}}Here goes nothing.{{/text}} {{!bold.mustache}} {{$text}}Here also goes nothing but it's bold.{{/text}} {{!dynamic.mustache}} {{<*dynamic}} {{$text}}Hello World!{{/text}} {{/*dynamic}} Hash: { "dynamic": "bold" } Output: Hello World! ### Set Delimiter Set Delimiter tags start with an equal sign and change the tag delimiters from `{{` and `}}` to custom strings. Consider the following contrived example: * {{default_tags}} {{=<% %>=}} * <% erb_style_tags %> <%={{ }}=%> * {{ default_tags_again }} Here we have a list with three items. The first item uses the default tag style, the second uses erb style as defined by the Set Delimiter tag, and the third returns to the default style after yet another Set Delimiter declaration. According to [ctemplates][ct], this "is useful for languages like TeX, where double-braces may occur in the text and are awkward to use for markup." Custom delimiters may not contain whitespace or the equals sign. [ct]: http://goog-ctemplate.sourceforge.net/doc/howto.html ## COPYRIGHT Mustache is Copyright (C) 2009 Chris Wanstrath Original CTemplate by Google ## SEE ALSO mustache(1), mustache-mustache-ccc31e2/mustache.gemspec000066400000000000000000000036101514727531200210040ustar00rootroot00000000000000$LOAD_PATH.unshift 'lib' require 'mustache/version' module RubyVersion def self.rbx? defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx' end def self.jruby? RUBY_PLATFORM =~ /java/ end end Gem::Specification.new do |s| s.name = "mustache" s.version = Mustache::VERSION s.date = Time.now.strftime('%Y-%m-%d') s.summary = "Mustache is a framework-agnostic way to render logic-free views." s.homepage = "https://github.com/mustache/mustache" s.email = "rokusu@gmail.com" s.authors = [ "Chris Wanstrath", "Magnus Holm", "Pieter van de Bruggen", "Ricardo Mendes" ] s.license = "MIT" s.files = %w( README.md Rakefile LICENSE ) s.files += Dir.glob("lib/**/*") s.files += Dir.glob("bin/**/*") s.files += Dir.glob("man/**/*") s.files += Dir.glob("test/**/*") s.executables = %w( mustache ) s.description = < 1.6' s.add_development_dependency 'rake', '~> 10.3' s.add_development_dependency 'minitest', '~> 5.4' s.add_development_dependency 'benchmark-ips' s.add_development_dependency 'ruby-prof' unless RubyVersion.rbx? || RubyVersion.jruby? s.add_development_dependency 'rdoc', '~> 4.1' s.add_development_dependency 'ronn', '~> 0.7' unless RubyVersion.rbx? || RubyVersion.jruby? end mustache-mustache-ccc31e2/test/000077500000000000000000000000001514727531200166055ustar00rootroot00000000000000mustache-mustache-ccc31e2/test/autoloading_test.rb000066400000000000000000000025141514727531200225010ustar00rootroot00000000000000require_relative 'helper' module TestViews; end class AutoloadingTest < Minitest::Test def setup Mustache.view_path = File.dirname(__FILE__) + '/fixtures' end def test_autoload klass = Mustache.view_class(:Comments) assert_equal Comments, klass end def test_autoload_lowercase klass = Mustache.view_class(:comments) assert_equal Comments, klass end def test_autoload_nil klass = Mustache.view_class(nil) assert_equal Mustache, klass end def test_autoload_empty_string klass = Mustache.view_class('') assert_equal Mustache, klass end def test_namespaced_autoload Mustache.view_namespace = TestViews klass = Mustache.view_class('Namespaced') assert_equal TestViews::Namespaced, klass assert_equal <<-end_render.strip, klass.render

Dragon < Tiger

end_render end def test_folder_autoload assert_equal TestViews::Namespaced, Mustache.view_class('test_views/namespaced') end def test_namespaced_partial_autoload Mustache.view_namespace = TestViews klass = Mustache.view_class(:namespaced_with_partial) assert_equal TestViews::NamespacedWithPartial, klass assert_equal <<-end_render.strip, klass.render My opinion: Again, Victory! end_render end def test_bad_constant_name assert_equal Mustache, Mustache.view_class(404) end end mustache-mustache-ccc31e2/test/fixtures/000077500000000000000000000000001514727531200204565ustar00rootroot00000000000000mustache-mustache-ccc31e2/test/fixtures/comments.mustache000066400000000000000000000001021514727531200240270ustar00rootroot00000000000000

{{title}}{{! just something interesting... #or not... }}

mustache-mustache-ccc31e2/test/fixtures/comments.rb000066400000000000000000000002621514727531200226300ustar00rootroot00000000000000require 'mustache' class Comments < Mustache self.path = File.dirname(__FILE__) def title "A Comedy of Errors" end end if $0 == __FILE__ puts Comments.to_html end mustache-mustache-ccc31e2/test/fixtures/complex_view.mustache000066400000000000000000000004241514727531200247120ustar00rootroot00000000000000

{{header}}

{{#list}}
    {{#item}} {{#current}}
  • {{name}}
  • {{/current}} {{#link}}
  • {{name}}
  • {{/link}} {{/item}}
{{/list}} {{^list}}

The list is empty.

{{/list}}mustache-mustache-ccc31e2/test/fixtures/complex_view.rb000066400000000000000000000010301514727531200234760ustar00rootroot00000000000000require 'mustache' class ComplexView < Mustache self.path = File.dirname(__FILE__) def header "Colors" end def item items = [] items << { :name => 'red', :current => true, :url => '#Red' } items << { :name => 'green', :current => false, :url => '#Green' } items << { :name => 'blue', :current => false, :url => '#Blue' } items end def link not self[:current] end def list not item.empty? end def empty item.empty? end end if $0 == __FILE__ puts ComplexView.to_html end mustache-mustache-ccc31e2/test/fixtures/crazy_recursive.mustache000066400000000000000000000001571514727531200254330ustar00rootroot00000000000000
    {{#top_nodes}} {{> node}} {{/top_nodes}}
mustache-mustache-ccc31e2/test/fixtures/crazy_recursive.rb000066400000000000000000000010761514727531200242260ustar00rootroot00000000000000require 'mustache' class CrazyRecursive < Mustache self.path = File.dirname(__FILE__) def top_nodes [{ :contents => "1", :children => [{ :contents => "2", :children => [{ :contents => "3", :children => [] }] }, { :contents => "4", :children => [{ :contents => "5", :children => [{ :contents => "6", :children => [] }] }] }] }] end end if $0 == __FILE__ puts CrazyRecursive.to_html end mustache-mustache-ccc31e2/test/fixtures/delimiters.mustache000066400000000000000000000001371514727531200243530ustar00rootroot00000000000000{{=<% %>=}} * <% start %> <%=| |=%> |# middle | * | item | |/ middle | |={{ }}=| * {{ final }} mustache-mustache-ccc31e2/test/fixtures/delimiters.rb000066400000000000000000000005721514727531200231500ustar00rootroot00000000000000require 'mustache' class Delimiters < Mustache self.path = File.dirname(__FILE__) def start "It worked the first time." end def middle [ { :item => "And it worked the second time." }, { :item => "As well as the third." } ] end def final "Then, surprisingly, it worked the final time." end end if $0 == __FILE__ puts Delimiters.to_html end mustache-mustache-ccc31e2/test/fixtures/dot_notation.mustache000066400000000000000000000007161514727531200247160ustar00rootroot00000000000000* {{person.name.first}} {{person.name.last}} * {{person.age}} * {{person.hometown.city}}, {{person.hometown.state}} * {{#person}}{{hometown.city}}, {{hometown.state}}{{/person}} * {{#person}}{{#hometown}}{{city}}, {{state}}{{/hometown}}{{/person}} * {{#person.hometown}}{{city}}, {{state}}{{/person.hometown}} * {{normal}} * {{{person.name.first}}} {{&person.name.last}} * {{^person.alien?}}{{person.hometown.city}}, {{person.hometown.state}}{{/person.alien?}} mustache-mustache-ccc31e2/test/fixtures/dot_notation.rb000066400000000000000000000006041514727531200235040ustar00rootroot00000000000000require 'mustache' class DotNotation < Mustache self.path = File.dirname(__FILE__) def person return { :name => OpenStruct.new(:first => 'Chris', :last => 'Firescythe'), :age => 24, :hometown => { :city => "Cincinnati", :state => "OH" } } end def normal "Normal" end end if $0 == __FILE__ puts DotNotation.to_html end mustache-mustache-ccc31e2/test/fixtures/double_section.mustache000066400000000000000000000000711514727531200252050ustar00rootroot00000000000000{{#t}} * first {{/t}} * {{two}} {{#t}} * third {{/t}}mustache-mustache-ccc31e2/test/fixtures/double_section.rb000066400000000000000000000002221514727531200237750ustar00rootroot00000000000000require 'mustache' class DoubleSection < Mustache self.path = File.dirname(__FILE__) def t true end def two "second" end end mustache-mustache-ccc31e2/test/fixtures/escaped.mustache000066400000000000000000000000221514727531200236070ustar00rootroot00000000000000

{{title}}

mustache-mustache-ccc31e2/test/fixtures/escaped.rb000066400000000000000000000003401514727531200224040ustar00rootroot00000000000000$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib' require 'mustache' class Escaped < Mustache self.path = File.dirname(__FILE__) def title "Bear > Shark" end end if $0 == __FILE__ puts Escaped.to_html end mustache-mustache-ccc31e2/test/fixtures/inner_partial.mustache000066400000000000000000000000211514727531200250310ustar00rootroot00000000000000Again, {{title}}!mustache-mustache-ccc31e2/test/fixtures/inner_partial.txt000066400000000000000000000000301514727531200240370ustar00rootroot00000000000000## Again, {{title}}! ## mustache-mustache-ccc31e2/test/fixtures/inverted_section.mustache000066400000000000000000000000711514727531200255530ustar00rootroot00000000000000{{^t}} * first {{/t}} * {{two}} {{^t}} * third {{/t}}mustache-mustache-ccc31e2/test/fixtures/inverted_section.rb000066400000000000000000000002251514727531200243460ustar00rootroot00000000000000require 'mustache' class InvertedSection < Mustache self.path = File.dirname(__FILE__) def t false end def two "second" end end mustache-mustache-ccc31e2/test/fixtures/lambda.mustache000066400000000000000000000001321514727531200234250ustar00rootroot00000000000000{{#rendered}} Hi {{name}}. {{/rendered}} {{#not_rendered}} Hi {{name}}. {{/not_rendered}}mustache-mustache-ccc31e2/test/fixtures/lambda.rb000066400000000000000000000007131514727531200222240ustar00rootroot00000000000000require 'mustache' class Lambda < Mustache self.path = File.dirname(__FILE__) attr_reader :calls def initialize(*args) super @calls = 0 @cached = nil end def rendered lambda do |text| return @cached if @cached @calls += 1 @cached = render(text) end end def not_rendered lambda { |text| "{{= | =}}#{text}" } end end if $0 == __FILE__ puts Lambda.to_html(Lambda.template, :name => "Jonny") end mustache-mustache-ccc31e2/test/fixtures/liberal.mustache000066400000000000000000000001011514727531200236130ustar00rootroot00000000000000{{first-name}} {{middle_name!}} {{lastName?}} {{street-address}} mustache-mustache-ccc31e2/test/fixtures/liberal.rb000066400000000000000000000004611514727531200224160ustar00rootroot00000000000000require 'mustache' class Liberal < Mustache self.path = File.dirname(__FILE__) def first_name "kevin" end def middle_name! 'j' end def lastName? 'sheurs' end define_method :'street-address' do '123 Somewhere St' end end if $0 == __FILE__ puts Liberal.to_html end mustache-mustache-ccc31e2/test/fixtures/method_missing.rb000066400000000000000000000004731514727531200240200ustar00rootroot00000000000000require 'mustache' class MethodMissing < Mustache self.template = '[ {{#list}}{{.}} {{/list}}]' def method_missing(name, *args, &block) return (0..10).to_a if name == :list return super end def respond_to?(method) method == :list end end if $0 == __FILE__ puts MethodMissing.to_html end mustache-mustache-ccc31e2/test/fixtures/namespaced.mustache000066400000000000000000000000221514727531200243030ustar00rootroot00000000000000

{{title}}

mustache-mustache-ccc31e2/test/fixtures/namespaced.rb000066400000000000000000000006211514727531200231020ustar00rootroot00000000000000require 'mustache' module TestViews class Namespaced < Mustache self.path = File.dirname(__FILE__) def title "Dragon < Tiger" end end class NamespacedWithPartial < Mustache self.path = File.dirname(__FILE__) self.template = "My opinion: {{>inner_partial}}" def title "Victory" end end end if $0 == __FILE__ puts TestViews::Namespaced.to_html end mustache-mustache-ccc31e2/test/fixtures/nested_objects.mustache000066400000000000000000000004241514727531200252040ustar00rootroot00000000000000

{{header}}

{{#list}}
    {{#item}} {{#current}}
  • {{name}}
  • {{/current}} {{#link}}
  • {{name}}
  • {{/link}} {{/item}}
{{/list}} {{^list}}

The list is empty.

{{/list}}mustache-mustache-ccc31e2/test/fixtures/nested_objects.rb000066400000000000000000000011221514727531200237720ustar00rootroot00000000000000require 'mustache' require 'ostruct' class NestedObjects < Mustache self.path = File.dirname(__FILE__) def header "Colors" end def item items = [] items << OpenStruct.new(:name => 'red', :current => true, :url => '#Red') items << OpenStruct.new(:name => 'green', :current => false, :url => '#Green') items << OpenStruct.new(:name => 'blue', :current => false, :url => '#Blue') items end def link not self[:current] end def list not item.empty? end def empty item.empty? end end if $0 == __FILE__ puts NestedObjects.to_html end mustache-mustache-ccc31e2/test/fixtures/node.mustache000066400000000000000000000001341514727531200231340ustar00rootroot00000000000000
  • {{contents}}
      {{#children}} {{> node}} {{/children}}
  • mustache-mustache-ccc31e2/test/fixtures/partial_with_module.mustache000066400000000000000000000000701514727531200262420ustar00rootroot00000000000000

    {{greeting}}

    {{>simple}}

    {{farewell}}

    mustache-mustache-ccc31e2/test/fixtures/partial_with_module.rb000066400000000000000000000006421514727531200250410ustar00rootroot00000000000000require 'mustache' module SimpleView def name "Bob" end def value 100_000 end def taxed_value value - (value * 0.4) end def in_ca false end end class PartialWithModule < Mustache include SimpleView self.path = File.dirname(__FILE__) def greeting "Welcome" end def farewell "Fair enough, right?" end end if $0 == __FILE__ puts PartialWithModule.to_html end mustache-mustache-ccc31e2/test/fixtures/passenger.conf000066400000000000000000000001511514727531200233110ustar00rootroot00000000000000 ServerName {{server}} DocumentRoot {{deploy_to}} RailsEnv {{stage}} mustache-mustache-ccc31e2/test/fixtures/passenger.rb000066400000000000000000000005441514727531200227750ustar00rootroot00000000000000require 'mustache' class Passenger < Mustache self.path = File.dirname(__FILE__) self.template_extension = 'conf' def server "example.com" end def deploy_to "/var/www/example.com" end def stage "production" end def timestamp Time.now.strftime('%Y%m%d%H%M%S') end end if $0 == __FILE__ puts Passenger.to_text end mustache-mustache-ccc31e2/test/fixtures/recursive.mustache000066400000000000000000000000551514727531200242200ustar00rootroot00000000000000It works! {{#show}} {{>recursive}} {{/show}} mustache-mustache-ccc31e2/test/fixtures/recursive.rb000066400000000000000000000002441514727531200230120ustar00rootroot00000000000000require 'mustache' class Recursive < Mustache self.path = File.dirname(__FILE__) def show false end end if $0 == __FILE__ puts Recursive.to_html end mustache-mustache-ccc31e2/test/fixtures/simple.mustache000066400000000000000000000001511514727531200234770ustar00rootroot00000000000000Hello {{name}} You have just won ${{value}}! {{#in_ca}} Well, ${{ taxed_value }}, after taxes. {{/in_ca}}mustache-mustache-ccc31e2/test/fixtures/simple.rb000066400000000000000000000004151514727531200222740ustar00rootroot00000000000000require '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 if $0 == __FILE__ puts Simple.to_html end mustache-mustache-ccc31e2/test/fixtures/simply_complicated.mustache000066400000000000000000000006531514727531200260760ustar00rootroot00000000000000Hi there {{yourname}}. Your home directory is {{HOME}}. {{#friend}} Your friend is named {{name}} {{#morr}} Hey {{word}} {{up}} {{{awesomesauce}}}. {{/morr}} {{^morr}} Booooo. {{hiss}} {{/morr}} {{notinmorr}} {{> partial1}} {{/friend}} {{^friend}} You have no friends, {{person}}. You suck. {{/friend}} {{> partial2}} {{! comments are awesome }} {{={% %}=}} {%love%} {%={{ }}=%} {{{triplestash}}} mustache-mustache-ccc31e2/test/fixtures/template_partial.mustache000066400000000000000000000000451514727531200255370ustar00rootroot00000000000000

    {{title}}

    {{>inner_partial}}mustache-mustache-ccc31e2/test/fixtures/template_partial.rb000066400000000000000000000003421514727531200243310ustar00rootroot00000000000000require 'mustache' class TemplatePartial < Mustache self.path = File.dirname(__FILE__) def title "Welcome" end def title_bars '-' * title.size end end if $0 == __FILE__ puts TemplatePartial.to_html end mustache-mustache-ccc31e2/test/fixtures/template_partial.txt000066400000000000000000000000551514727531200245460ustar00rootroot00000000000000{{title}} {{title_bars}} {{>inner_partial}} mustache-mustache-ccc31e2/test/fixtures/unescaped.mustache000066400000000000000000000000241514727531200241540ustar00rootroot00000000000000

    {{{title}}}

    mustache-mustache-ccc31e2/test/fixtures/unescaped.rb000066400000000000000000000002561514727531200227550ustar00rootroot00000000000000require 'mustache' class Unescaped < Mustache self.path = File.dirname(__FILE__) def title "Bear > Shark" end end if $0 == __FILE__ puts Unescaped.to_html end mustache-mustache-ccc31e2/test/fixtures/utf8.mustache000066400000000000000000000000551514727531200230770ustar00rootroot00000000000000

    中文 {{test}}

    {{> utf8_partial}} mustache-mustache-ccc31e2/test/fixtures/utf8_partial.mustache000066400000000000000000000000311514727531200246050ustar00rootroot00000000000000

    中文又来啦

    mustache-mustache-ccc31e2/test/helper.rb000066400000000000000000000002511514727531200204070ustar00rootroot00000000000000require 'simplecov' SimpleCov.start do add_filter '/test/' end require 'minitest/autorun' Dir[File.dirname(__FILE__) + '/fixtures/*.rb'].each do |f| require f end mustache-mustache-ccc31e2/test/mustache_test.rb000066400000000000000000000471711514727531200220140ustar00rootroot00000000000000# -*- coding: utf-8 -*- require_relative 'helper' require 'json' class MustacheTest < Minitest::Test def test_instance_render klass = Class.new(Mustache) klass.template = "Hi {{thing}}!" assert_equal "Hi world!", klass.render(:thing => :world) assert_equal "Nice.", klass.render("{{compliment}}.", :compliment => "Nice") assert_equal <<-end_simple, Simple.new.render(:name => "yo", :in_ca => false) Hello yo You have just won $10000! end_simple end def test_passenger assert_equal <<-end_passenger, Passenger.render ServerName example.com DocumentRoot /var/www/example.com RailsEnv production end_passenger end def test_complex_view assert_equal <<-end_complex, ComplexView.render

    Colors

    end_complex end def test_nested_objects assert_equal <<-end_complex, NestedObjects.render

    Colors

    end_complex end def test_single_line_sections html = %(

    ) instance = Mustache.new instance.template = html instance[:no_flash] = true assert_equal %Q'

    {{contact}}
    {{/contact}}" assert_equal "
    Call 1-888-FLOWERS\nAsk for Johnson.
    ", instance.render end def test_sassy_single_line_sections instance = Mustache.new instance[:full_time] = true instance.template = "\n {{#full_time}}full time{{/full_time}}\n" assert_equal "\n full time\n", instance.render end def test_sassier_single_line_sections instance = Mustache.new instance.template = "\t{{#list}}\r\n\t{{/list}}" assert_equal "", instance.render end def test_padding_before_section instance = Mustache.new instance.template = "\t{{#list}}a{{/list}}" assert_equal "\taa", instance.render(:list => [1, 2]) end def test_padding_before_section_on_eos instance = Mustache.new instance.template = "{{#list}}\n\t{{/list}}" assert_equal "", instance.render(:list => [1, 2]) end def test_two_line_sections html = %(

    ) instance = Mustache.new instance.template = html instance[:no_flash] = true assert_equal %Q'