mustache 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/HISTORY.md +16 -0
- data/README.md +37 -7
- data/examples/{comments.html → comments.mustache} +0 -0
- data/examples/{complex_view.html → complex_view.mustache} +0 -0
- data/examples/{delimiters.html → delimiters.mustache} +0 -0
- data/examples/{double_section.html → double_section.mustache} +0 -0
- data/examples/{escaped.html → escaped.mustache} +0 -0
- data/examples/{inner_partial.html → inner_partial.mustache} +0 -0
- data/examples/namespaced.mustache +1 -0
- data/examples/namespaced.rb +17 -0
- data/examples/{simple.html → simple.mustache} +0 -0
- data/examples/{template_partial.html → template_partial.mustache} +0 -0
- data/examples/{unescaped.html → unescaped.mustache} +0 -0
- data/examples/{view_partial.html → view_partial.mustache} +0 -0
- data/lib/mustache.rb +94 -6
- data/lib/mustache/context.rb +13 -1
- data/lib/mustache/sinatra.rb +9 -29
- data/lib/mustache/template.rb +27 -2
- data/lib/mustache/version.rb +1 -1
- data/lib/rack/bug/panels/mustache_panel.rb +81 -0
- data/lib/rack/bug/panels/mustache_panel/mustache_extension.rb +25 -0
- data/lib/rack/bug/panels/mustache_panel/view.mustache +32 -0
- data/test/autoloading_test.rb +38 -0
- data/test/mustache_test.rb +49 -1
- metadata +20 -12
    
        data/HISTORY.md
    CHANGED
    
    | @@ -1,3 +1,19 @@ | |
| 1 | 
            +
            ## 0.4.0 (2009-10-27)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            * Stopped raising context miss exceptions by default
         | 
| 4 | 
            +
            * Added `Mustache.raise_on_context_miss` setting (defaults to false)
         | 
| 5 | 
            +
            * Throw Mustache::ContextMiss when raise_on_context_miss is true and
         | 
| 6 | 
            +
              we encounter a miss.
         | 
| 7 | 
            +
            * The default template extension is now "mustache" (instead of "html").
         | 
| 8 | 
            +
            * Added the `view_namespace` and `view_path` settings to `Mustache`
         | 
| 9 | 
            +
            * Added `Mustache.view_class` method which autoloads a class using the
         | 
| 10 | 
            +
              new `view_namespace` and `view_path` settings. Should be used by
         | 
| 11 | 
            +
              plugin developers.
         | 
| 12 | 
            +
            * Updated the Sinatra extension to use the new `view_class` method
         | 
| 13 | 
            +
            * Unclosed sections now throw a helpful error message
         | 
| 14 | 
            +
            * Report line numbers on unclosed section errors
         | 
| 15 | 
            +
            * Added Rack::Bug panel
         | 
| 16 | 
            +
             | 
| 1 17 | 
             
            ## 0.3.2 (2009-10-19)
         | 
| 2 18 |  | 
| 3 19 | 
             
            * Bugfix: Partials in Sinatra were using the wrong path.
         | 
    
        data/README.md
    CHANGED
    
    | @@ -103,9 +103,11 @@ The most basic tag is the variable. A `{{name}}` tag in a basic | |
| 103 103 | 
             
            template will try to call the `name` method on your view. If there is
         | 
| 104 104 | 
             
            no `name` method, an exception will be raised.
         | 
| 105 105 |  | 
| 106 | 
            -
            All variables are HTML escaped by default. If you want | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 106 | 
            +
            All variables are HTML escaped by default. If you want to return
         | 
| 107 | 
            +
            unescaped HTML, use the triple mustache: `{{{name}}}`.
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            By default a variable "miss" returns an empty string. You can
         | 
| 110 | 
            +
            configure this by setting `Mustache.raise_on_context_miss` to true.
         | 
| 109 111 |  | 
| 110 112 | 
             
            ### Boolean Sections
         | 
| 111 113 |  | 
| @@ -215,7 +217,7 @@ ctemplate and friends want you to hand a dictionary to the template | |
| 215 217 | 
             
            processor. Mustache supports a similar concept. Feel free to mix the
         | 
| 216 218 | 
             
            class-based and this more procedural style at your leisure.
         | 
| 217 219 |  | 
| 218 | 
            -
            Given this template (winner. | 
| 220 | 
            +
            Given this template (winner.mustache):
         | 
| 219 221 |  | 
| 220 222 | 
             
                Hello {{name}}
         | 
| 221 223 | 
             
                You have just won ${{value}}!
         | 
| @@ -247,7 +249,7 @@ A word on templates. By default, a view will try to find its template | |
| 247 249 | 
             
            on disk by searching for an HTML file in the current directory that
         | 
| 248 250 | 
             
            follows the classic Ruby naming convention.
         | 
| 249 251 |  | 
| 250 | 
            -
                TemplatePartial => ./template_partial. | 
| 252 | 
            +
                TemplatePartial => ./template_partial.mustache
         | 
| 251 253 |  | 
| 252 254 | 
             
            You can set the search path using `Mustache.template_path`. It can be set on a
         | 
| 253 255 | 
             
            class by class basis:
         | 
| @@ -257,13 +259,13 @@ class by class basis: | |
| 257 259 | 
             
                  ... etc ...
         | 
| 258 260 | 
             
                end
         | 
| 259 261 |  | 
| 260 | 
            -
            Now `Simple` will look for `simple. | 
| 262 | 
            +
            Now `Simple` will look for `simple.mustache` in the directory it resides
         | 
| 261 263 | 
             
            in, no matter the cwd.
         | 
| 262 264 |  | 
| 263 265 | 
             
            If you want to just change what template is used you can set
         | 
| 264 266 | 
             
            `Mustache.template_file` directly:
         | 
| 265 267 |  | 
| 266 | 
            -
                Simple.template_file = './blah. | 
| 268 | 
            +
                Simple.template_file = './blah.mustache'
         | 
| 267 269 |  | 
| 268 270 | 
             
            Mustache also allows you to define the extension it'll use.
         | 
| 269 271 |  | 
| @@ -283,6 +285,15 @@ Or set a different template for a single instance: | |
| 283 285 | 
             
            Whatever works.
         | 
| 284 286 |  | 
| 285 287 |  | 
| 288 | 
            +
            Views
         | 
| 289 | 
            +
            -----
         | 
| 290 | 
            +
             | 
| 291 | 
            +
            Mustache supports a bit of magic when it comes to views. If you're
         | 
| 292 | 
            +
            authoring a plugin or extension for a web framework (Sinatra, Rails,
         | 
| 293 | 
            +
            etc), check out the `view_namespace` and `view_path` settings on the
         | 
| 294 | 
            +
            `Mustache` class. They will surely provide needed assistance.
         | 
| 295 | 
            +
             | 
| 296 | 
            +
             | 
| 286 297 | 
             
            Helpers
         | 
| 287 298 | 
             
            -------
         | 
| 288 299 |  | 
| @@ -364,6 +375,23 @@ An example Sinatra application is also provided: | |
| 364 375 | 
             
            <http://github.com/defunkt/mustache-sinatra-example>
         | 
| 365 376 |  | 
| 366 377 |  | 
| 378 | 
            +
            [Rack::Bug][4]
         | 
| 379 | 
            +
            ---------
         | 
| 380 | 
            +
             | 
| 381 | 
            +
            Mustache also ships with a `Rack::Bug` panel. In your `config.ru` add
         | 
| 382 | 
            +
            the following code:
         | 
| 383 | 
            +
             | 
| 384 | 
            +
                require 'rack/bug/panels/mustache_panel'
         | 
| 385 | 
            +
                use Rack::Bug::MustachePanel
         | 
| 386 | 
            +
             | 
| 387 | 
            +
            Using Rails? Add this to your initializer or environment file:
         | 
| 388 | 
            +
             | 
| 389 | 
            +
                require 'rack/bug/panels/mustache_panel'
         | 
| 390 | 
            +
                config.middleware.use "Rack::Bug::MustachePanel"
         | 
| 391 | 
            +
             | 
| 392 | 
            +
            [][5]
         | 
| 393 | 
            +
             | 
| 394 | 
            +
             | 
| 367 395 | 
             
            Vim
         | 
| 368 396 | 
             
            ---
         | 
| 369 397 |  | 
| @@ -405,3 +433,5 @@ Meta | |
| 405 433 | 
             
            [1]: http://code.google.com/p/google-ctemplate/
         | 
| 406 434 | 
             
            [2]: http://www.ivan.fomichev.name/2008/05/erlang-template-engine-prototype.html
         | 
| 407 435 | 
             
            [3]: http://google-ctemplate.googlecode.com/svn/trunk/doc/howto.html
         | 
| 436 | 
            +
            [4]: http://github.com/brynary/rack-bug/
         | 
| 437 | 
            +
            [5]: http://img.skitch.com/20091027-n8pxwwx8r61tc318a15q1n6m14.png
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            <h1>{{title}}</h1>
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
         | 
| 2 | 
            +
            require 'mustache'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module TestViews
         | 
| 5 | 
            +
              class Namespaced < Mustache
         | 
| 6 | 
            +
                self.path = File.dirname(__FILE__)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def title
         | 
| 9 | 
            +
                  "Dragon < Tiger"
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
             | 
| 15 | 
            +
            if $0 == __FILE__
         | 
| 16 | 
            +
              puts TestViews::Namespaced.to_html
         | 
| 17 | 
            +
            end
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
    
        data/lib/mustache.rb
    CHANGED
    
    | @@ -7,7 +7,7 @@ require 'mustache/context' | |
| 7 7 | 
             
            # The typical Mustache workflow is as follows:
         | 
| 8 8 | 
             
            #
         | 
| 9 9 | 
             
            # * Create a Mustache subclass: class Stats < Mustache
         | 
| 10 | 
            -
            # * Create a template: stats. | 
| 10 | 
            +
            # * Create a template: stats.mustache
         | 
| 11 11 | 
             
            # * Instantiate an instance: view = Stats.new
         | 
| 12 12 | 
             
            # * Render that instance: view.render
         | 
| 13 13 | 
             
            #
         | 
| @@ -30,12 +30,12 @@ require 'mustache/context' | |
| 30 30 | 
             
            # looking for a template. By default it is "."
         | 
| 31 31 | 
             
            # Setting it to /usr/local/templates, for example, means (given all
         | 
| 32 32 | 
             
            # other settings are default) a Mustache subclass `Stats` will try to
         | 
| 33 | 
            -
            # load /usr/local/templates/stats. | 
| 33 | 
            +
            # load /usr/local/templates/stats.mustache
         | 
| 34 34 | 
             
            #
         | 
| 35 35 | 
             
            # * template_extension
         | 
| 36 36 | 
             
            #
         | 
| 37 37 | 
             
            # The `template_extension` is the extension Mustache uses when looking
         | 
| 38 | 
            -
            # for template files. By default it is " | 
| 38 | 
            +
            # for template files. By default it is "mustache"
         | 
| 39 39 | 
             
            #
         | 
| 40 40 | 
             
            # * template_file
         | 
| 41 41 | 
             
            #
         | 
| @@ -56,6 +56,19 @@ require 'mustache/context' | |
| 56 56 | 
             
            #   view.template = "Hi, {{person}}!"
         | 
| 57 57 | 
             
            #   view[:person] = 'Mom'
         | 
| 58 58 | 
             
            #   view.render # => Hi, mom!
         | 
| 59 | 
            +
            #
         | 
| 60 | 
            +
            # * view_namespace
         | 
| 61 | 
            +
            #
         | 
| 62 | 
            +
            # To make life easy on those developing Mustache plugins for web frameworks or
         | 
| 63 | 
            +
            # other libraries, Mustache will attempt to load view classes (i.e. Mustache
         | 
| 64 | 
            +
            # subclasses) using the `view_class` class method. The `view_namespace` tells
         | 
| 65 | 
            +
            # Mustache under which constant view classes live. By default it is `Object`.
         | 
| 66 | 
            +
            #
         | 
| 67 | 
            +
            # * view_path
         | 
| 68 | 
            +
            #
         | 
| 69 | 
            +
            # Similar to `template_path`, the `view_path` option tells Mustache where to look
         | 
| 70 | 
            +
            # for files containing view classes when using the `view_class` method.
         | 
| 71 | 
            +
            #
         | 
| 59 72 | 
             
            class Mustache
         | 
| 60 73 | 
             
              # Helper method for quickly instantiating and rendering a view.
         | 
| 61 74 | 
             
              def self.render(*args)
         | 
| @@ -93,9 +106,9 @@ class Mustache | |
| 93 106 | 
             
                self.template_path = path
         | 
| 94 107 | 
             
              end
         | 
| 95 108 |  | 
| 96 | 
            -
              # A Mustache template's default extension is ' | 
| 109 | 
            +
              # A Mustache template's default extension is 'mustache'
         | 
| 97 110 | 
             
              def self.template_extension
         | 
| 98 | 
            -
                @template_extension ||= ' | 
| 111 | 
            +
                @template_extension ||= 'mustache'
         | 
| 99 112 | 
             
              end
         | 
| 100 113 |  | 
| 101 114 | 
             
              def self.template_extension=(template_extension)
         | 
| @@ -104,7 +117,7 @@ class Mustache | |
| 104 117 | 
             
              end
         | 
| 105 118 |  | 
| 106 119 | 
             
              # The template file is the absolute path of the file Mustache will
         | 
| 107 | 
            -
              # use as its template. By default it's ./class_name. | 
| 120 | 
            +
              # use as its template. By default it's ./class_name.mustache
         | 
| 108 121 | 
             
              def self.template_file
         | 
| 109 122 | 
             
                @template_file || "#{path}/#{underscore}.#{template_extension}"
         | 
| 110 123 | 
             
              end
         | 
| @@ -126,6 +139,75 @@ class Mustache | |
| 126 139 | 
             
                @template = templateify(template)
         | 
| 127 140 | 
             
              end
         | 
| 128 141 |  | 
| 142 | 
            +
              # The constant under which Mustache will look for views. By default it's
         | 
| 143 | 
            +
              # `Object`, but it might be nice to set it to something like `Hurl::Views` if
         | 
| 144 | 
            +
              # your app's main namespace is `Hurl`.
         | 
| 145 | 
            +
              def self.view_namespace
         | 
| 146 | 
            +
                @view_namespace || Object
         | 
| 147 | 
            +
              end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
              def self.view_namespace=(namespace)
         | 
| 150 | 
            +
                @view_namespace = namespace
         | 
| 151 | 
            +
              end
         | 
| 152 | 
            +
             | 
| 153 | 
            +
              # Mustache searches the view path for .rb files to require when asked to find a
         | 
| 154 | 
            +
              # view class. Defaults to "."
         | 
| 155 | 
            +
              def self.view_path
         | 
| 156 | 
            +
                @view_path ||= '.'
         | 
| 157 | 
            +
              end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
              def self.view_path=(path)
         | 
| 160 | 
            +
                @view_path = path
         | 
| 161 | 
            +
              end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
              # When given a symbol or string representing a class, will try to produce an
         | 
| 164 | 
            +
              # appropriate view class.
         | 
| 165 | 
            +
              # e.g.
         | 
| 166 | 
            +
              #   Mustache.view_namespace = Hurl::Views
         | 
| 167 | 
            +
              #   Mustache.view_class(:Partial) # => Hurl::Views::Partial
         | 
| 168 | 
            +
              def self.view_class(name)
         | 
| 169 | 
            +
                if name != classify(name.to_s)
         | 
| 170 | 
            +
                  name = classify(name.to_s)
         | 
| 171 | 
            +
                end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                # Emptiness begets emptiness.
         | 
| 174 | 
            +
                if name.to_s == ''
         | 
| 175 | 
            +
                  return Mustache
         | 
| 176 | 
            +
                end
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                file_name = underscore(name)
         | 
| 179 | 
            +
                namespace = view_namespace
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                if namespace.const_defined?(:Views) && namespace::Views.const_defined?(name)
         | 
| 182 | 
            +
                  namespace::Views.const_get(name)
         | 
| 183 | 
            +
                elsif namespace.const_defined?(name)
         | 
| 184 | 
            +
                  namespace.const_get(name)
         | 
| 185 | 
            +
                elsif File.exists?(file = "#{view_path}/#{file_name}.rb")
         | 
| 186 | 
            +
                  require "#{file}".chomp('.rb')
         | 
| 187 | 
            +
                  if namespace.const_defined?(:Views)
         | 
| 188 | 
            +
                    namespace::Views.const_get(name)
         | 
| 189 | 
            +
                  else
         | 
| 190 | 
            +
                    namespace.const_get(name)
         | 
| 191 | 
            +
                  end
         | 
| 192 | 
            +
                else
         | 
| 193 | 
            +
                  Mustache
         | 
| 194 | 
            +
                end
         | 
| 195 | 
            +
              end
         | 
| 196 | 
            +
             | 
| 197 | 
            +
              # Should an exception be raised when we cannot find a corresponding method
         | 
| 198 | 
            +
              # or key in the current context? By default this is false to emulate ctemplate's
         | 
| 199 | 
            +
              # behavior, but it may be useful to enable when debugging or developing.
         | 
| 200 | 
            +
              #
         | 
| 201 | 
            +
              # If set to true and there is a context miss, `Mustache::ContextMiss` will
         | 
| 202 | 
            +
              # be raised.
         | 
| 203 | 
            +
              def self.raise_on_context_miss?
         | 
| 204 | 
            +
                @raise_on_context_miss
         | 
| 205 | 
            +
              end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
              def self.raise_on_context_miss=(boolean)
         | 
| 208 | 
            +
                @raise_on_context_miss = boolean
         | 
| 209 | 
            +
              end
         | 
| 210 | 
            +
             | 
| 129 211 | 
             
              # Has this template already been compiled? Compilation is somewhat
         | 
| 130 212 | 
             
              # expensive so it may be useful to check this before attempting it.
         | 
| 131 213 | 
             
              def self.compiled?
         | 
| @@ -178,6 +260,12 @@ class Mustache | |
| 178 260 | 
             
                @template = templateify(template)
         | 
| 179 261 | 
             
              end
         | 
| 180 262 |  | 
| 263 | 
            +
              # Instance level version of `Mustache.raise_on_context_miss?`
         | 
| 264 | 
            +
              def raise_on_context_miss?
         | 
| 265 | 
            +
                self.class.raise_on_context_miss? || @raise_on_context_miss
         | 
| 266 | 
            +
              end
         | 
| 267 | 
            +
              attr_writer :raise_on_context_miss
         | 
| 268 | 
            +
             | 
| 181 269 | 
             
              # A helper method which gives access to the context at a given time.
         | 
| 182 270 | 
             
              # Kind of a hack for now, but useful when you're in an iterating section
         | 
| 183 271 | 
             
              # and want access to the hash currently being iterated over.
         | 
    
        data/lib/mustache/context.rb
    CHANGED
    
    | @@ -1,4 +1,14 @@ | |
| 1 1 | 
             
            class Mustache
         | 
| 2 | 
            +
              # A ContextMiss is raised whenever a tag's target can not be found
         | 
| 3 | 
            +
              # in the current context if `Mustache#raise_on_context_miss?` is
         | 
| 4 | 
            +
              # set to true.
         | 
| 5 | 
            +
              #
         | 
| 6 | 
            +
              # For example, if your View class does not respond to `music` but
         | 
| 7 | 
            +
              # your template contains a `{{template}}` tag this exception will be raised.
         | 
| 8 | 
            +
              #
         | 
| 9 | 
            +
              # By default it is not raised. See Mustache.raise_on_context_miss.
         | 
| 10 | 
            +
              class ContextMiss < RuntimeError;  end
         | 
| 11 | 
            +
             | 
| 2 12 | 
             
              # A Context represents the context which a Mustache template is
         | 
| 3 13 | 
             
              # executed within. All Mustache tags reference keys in the Context.
         | 
| 4 14 | 
             
              class Context < Hash
         | 
| @@ -14,8 +24,10 @@ class Mustache | |
| 14 24 | 
             
                    super(name.to_s)
         | 
| 15 25 | 
             
                  elsif @mustache.respond_to?(name)
         | 
| 16 26 | 
             
                    @mustache.send(name)
         | 
| 27 | 
            +
                  elsif @mustache.raise_on_context_miss?
         | 
| 28 | 
            +
                    raise ContextMiss.new("Can't find #{name} in #{@mustache.inspect}")
         | 
| 17 29 | 
             
                  else
         | 
| 18 | 
            -
                     | 
| 30 | 
            +
                    ''
         | 
| 19 31 | 
             
                  end
         | 
| 20 32 | 
             
                end
         | 
| 21 33 | 
             
              end
         | 
    
        data/lib/mustache/sinatra.rb
    CHANGED
    
    | @@ -49,38 +49,18 @@ class Mustache | |
| 49 49 | 
             
                  # This is called by Sinatra's `render` with the proper paths
         | 
| 50 50 | 
             
                  # and, potentially, a block containing a sub-view
         | 
| 51 51 | 
             
                  def render_mustache(template, data, opts, locals, &block)
         | 
| 52 | 
            -
                     | 
| 52 | 
            +
                    # If you have Hurl::App::Views, namespace should be set to Hurl::App.
         | 
| 53 | 
            +
                    Mustache.view_namespace = options.namespace
         | 
| 53 54 |  | 
| 54 | 
            -
                    # This is  | 
| 55 | 
            -
                    #  | 
| 56 | 
            -
                     | 
| 57 | 
            -
                    namespace = options.namespace
         | 
| 55 | 
            +
                    # This is probably the same as options.views, but we'll set it anyway.
         | 
| 56 | 
            +
                    # It's used to tell Mustache where to look for view classes.
         | 
| 57 | 
            +
                    Mustache.view_path = options.mustaches
         | 
| 58 58 |  | 
| 59 | 
            -
                     | 
| 60 | 
            -
             | 
| 61 | 
            -
                      # e.g. Hurl::Views::Index
         | 
| 62 | 
            -
                      klass = namespace::Views.const_get(name)
         | 
| 59 | 
            +
                    # Grab the class!
         | 
| 60 | 
            +
                    klass = Mustache.view_class(template)
         | 
| 63 61 |  | 
| 64 | 
            -
                     | 
| 65 | 
            -
             | 
| 66 | 
            -
                      # load in the view.
         | 
| 67 | 
            -
                      require "#{file}".chomp('.rb')
         | 
| 68 | 
            -
                      klass = namespace::Views.const_get(name)
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                      # compile and cache the template
         | 
| 71 | 
            -
                      klass.template = data
         | 
| 72 | 
            -
             | 
| 73 | 
            -
                    else
         | 
| 74 | 
            -
                      # Still nothing. Use the stache.
         | 
| 75 | 
            -
                      klass = Mustache
         | 
| 76 | 
            -
             | 
| 77 | 
            -
                    end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                    # Tell the view class its extension and path so finding partials
         | 
| 80 | 
            -
                    # works as expected.
         | 
| 81 | 
            -
                    if klass.template_extension != 'mustache'
         | 
| 82 | 
            -
                      klass.template_extension = 'mustache'
         | 
| 83 | 
            -
                    end
         | 
| 62 | 
            +
                    # Only cache the data if this isn't the generic base class.
         | 
| 63 | 
            +
                    klass.template = data unless klass == Mustache
         | 
| 84 64 |  | 
| 85 65 | 
             
                    # Confusingly Sinatra's `views` setting tells Mustache where the
         | 
| 86 66 | 
             
                    # templates are found. It's fine, blame Chris.
         | 
    
        data/lib/mustache/template.rb
    CHANGED
    
    | @@ -9,9 +9,30 @@ class Mustache | |
| 9 9 | 
             
              #
         | 
| 10 10 | 
             
              # You shouldn't use this class directly.
         | 
| 11 11 | 
             
              class Template
         | 
| 12 | 
            +
                # An UnclosedSection error is thrown when a {{# section }} is not
         | 
| 13 | 
            +
                # closed.
         | 
| 14 | 
            +
                #
         | 
| 15 | 
            +
                # For example:
         | 
| 16 | 
            +
                #   {{# open }} blah {{/ close }}
         | 
| 17 | 
            +
                class UnclosedSection < RuntimeError
         | 
| 18 | 
            +
                  attr_reader :message
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  # Report the line number of the offending unclosed section.
         | 
| 21 | 
            +
                  def initialize(source, matching_line, unclosed_section)
         | 
| 22 | 
            +
                    num = 0
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    source.split("\n").each_with_index do |line, i|
         | 
| 25 | 
            +
                      num = i + 1
         | 
| 26 | 
            +
                      break if line.strip == matching_line.strip
         | 
| 27 | 
            +
                    end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    @message = "line #{num}: ##{unclosed_section.strip} is not closed"
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 12 33 | 
             
                # Expects a Mustache template as a string along with a template
         | 
| 13 34 | 
             
                # path, which it uses to find partials.
         | 
| 14 | 
            -
                def initialize(source, template_path = '.', template_extension = ' | 
| 35 | 
            +
                def initialize(source, template_path = '.', template_extension = 'mustache')
         | 
| 15 36 | 
             
                  @source = source
         | 
| 16 37 | 
             
                  @template_path = template_path
         | 
| 17 38 | 
             
                  @template_extension = template_extension
         | 
| @@ -85,9 +106,13 @@ class Mustache | |
| 85 106 | 
             
                # 4. Partial tags - {{< partial_name }}
         | 
| 86 107 | 
             
                def compile_tags(src)
         | 
| 87 108 | 
             
                  res = ""
         | 
| 88 | 
            -
                  while src =~ /#{otag}( | 
| 109 | 
            +
                  while src =~ /#{otag}(#|=|!|<|\{)?(.+?)\1?#{ctag}+/
         | 
| 89 110 | 
             
                    res << str($`)
         | 
| 90 111 | 
             
                    case $1
         | 
| 112 | 
            +
                    when '#'
         | 
| 113 | 
            +
                      # Unclosed section - raise an error and
         | 
| 114 | 
            +
                      # report the line number
         | 
| 115 | 
            +
                      raise UnclosedSection.new(@source, $&, $2)
         | 
| 91 116 | 
             
                    when '!'
         | 
| 92 117 | 
             
                      # ignore comments
         | 
| 93 118 | 
             
                    when '='
         | 
    
        data/lib/mustache/version.rb
    CHANGED
    
    
| @@ -0,0 +1,81 @@ | |
| 1 | 
            +
            module Rack
         | 
| 2 | 
            +
              module Bug
         | 
| 3 | 
            +
                # MustachePanel is a Rack::Bug panel which tracks the time spent rendering
         | 
| 4 | 
            +
                # Mustache views as well as all the variables accessed during view
         | 
| 5 | 
            +
                # rendering.
         | 
| 6 | 
            +
                #
         | 
| 7 | 
            +
                # It can be used to track down slow partials and ensure you're only
         | 
| 8 | 
            +
                # generating data you need.
         | 
| 9 | 
            +
                #
         | 
| 10 | 
            +
                # Also, it's fun.
         | 
| 11 | 
            +
                class MustachePanel < Panel
         | 
| 12 | 
            +
                  require "rack/bug/panels/mustache_panel/mustache_extension"
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  # The view is responsible for rendering our panel. While Rack::Bug
         | 
| 15 | 
            +
                  # takes care of the nav, the content rendered by View is used for
         | 
| 16 | 
            +
                  # the panel itself.
         | 
| 17 | 
            +
                  class View < Mustache
         | 
| 18 | 
            +
                    self.path = ::File.dirname(__FILE__) + '/mustache_panel'
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    # We track the render times of all the Mustache views on this
         | 
| 21 | 
            +
                    # page load.
         | 
| 22 | 
            +
                    def times
         | 
| 23 | 
            +
                      MustachePanel.times.map do |key, value|
         | 
| 24 | 
            +
                        { :key => key, :value => value }
         | 
| 25 | 
            +
                      end
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    # Any variables used in this page load are collected and displayed.
         | 
| 29 | 
            +
                    def variables
         | 
| 30 | 
            +
                      vars = MustachePanel.variables.sort_by { |key, _| key.to_s }
         | 
| 31 | 
            +
                      vars.map do |key, value|
         | 
| 32 | 
            +
                        # Arrays can get too huge. Just show the first 10 to give you
         | 
| 33 | 
            +
                        # some idea.
         | 
| 34 | 
            +
                        if value.is_a?(Array) && value.size > 10
         | 
| 35 | 
            +
                          size = value.size
         | 
| 36 | 
            +
                          value = value.first(10)
         | 
| 37 | 
            +
                          value << "...and #{size - 10} more"
         | 
| 38 | 
            +
                        end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                        { :key => key, :value => value.inspect }
         | 
| 41 | 
            +
                      end
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  # Clear out our page load-specific variables.
         | 
| 46 | 
            +
                  def self.reset
         | 
| 47 | 
            +
                    Thread.current["rack.bug.mustache.times"] = {}
         | 
| 48 | 
            +
                    Thread.current["rack.bug.mustache.vars"] = {}
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  # The view render times for this page load
         | 
| 52 | 
            +
                  def self.times
         | 
| 53 | 
            +
                    Thread.current["rack.bug.mustache.times"] ||= {}
         | 
| 54 | 
            +
                  end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                  # The variables used on this page load
         | 
| 57 | 
            +
                  def self.variables
         | 
| 58 | 
            +
                    Thread.current["rack.bug.mustache.vars"] ||= {}
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  # The name of this Rack::Bug panel
         | 
| 62 | 
            +
                  def name
         | 
| 63 | 
            +
                    "mustache"
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  # The string used for our tab in Rack::Bug's navigation bar
         | 
| 67 | 
            +
                  def heading
         | 
| 68 | 
            +
                    "{{%.2fms}}" % self.class.times.values.inject(0.0) do |sum, obj|
         | 
| 69 | 
            +
                      sum + obj
         | 
| 70 | 
            +
                    end
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  # The content of our Rack::Bug panel
         | 
| 74 | 
            +
                  def content
         | 
| 75 | 
            +
                    View.render
         | 
| 76 | 
            +
                  ensure
         | 
| 77 | 
            +
                    self.class.reset
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
              end
         | 
| 81 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            if defined? Mustache
         | 
| 2 | 
            +
              Mustache.class_eval do
         | 
| 3 | 
            +
                alias_method :real_render, :render
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def render(*args, &block)
         | 
| 6 | 
            +
                  out = ''
         | 
| 7 | 
            +
                  Rack::Bug::MustachePanel.times[self.class.name] = Benchmark.realtime do
         | 
| 8 | 
            +
                    out = real_render(*args, &block)
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                  out
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                alias_method :to_html, :render
         | 
| 14 | 
            +
                alias_method :to_text, :render
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              Mustache::Context.class_eval do
         | 
| 18 | 
            +
                alias_method :real_get, :[]
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def [](name)
         | 
| 21 | 
            +
                  return real_get(name) if name == :yield || !@mustache.respond_to?(name)
         | 
| 22 | 
            +
                  Rack::Bug::MustachePanel.variables[name] = real_get(name)
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -0,0 +1,32 @@ | |
| 1 | 
            +
            <h3>Render Times</h3>
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            <table>
         | 
| 4 | 
            +
              <tr>
         | 
| 5 | 
            +
                <th>View</th>
         | 
| 6 | 
            +
                <th>Render Time</th>
         | 
| 7 | 
            +
              </tr>
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              {{# times }}
         | 
| 10 | 
            +
                <tr>
         | 
| 11 | 
            +
                  <td>{{ key }}</td>
         | 
| 12 | 
            +
                  <td>{{ value }}</td>
         | 
| 13 | 
            +
                </tr>
         | 
| 14 | 
            +
              {{/ times }}
         | 
| 15 | 
            +
            </table>
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            <h3>Variables</h3>
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            <table>
         | 
| 20 | 
            +
              <tr>
         | 
| 21 | 
            +
                <th>Name</th>
         | 
| 22 | 
            +
                <th>Value</th>
         | 
| 23 | 
            +
              </tr>
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              {{# variables }}
         | 
| 26 | 
            +
                <tr>
         | 
| 27 | 
            +
                  <td>{{ key }}</td>
         | 
| 28 | 
            +
                  <td>{{ value }}</td>
         | 
| 29 | 
            +
                </tr>
         | 
| 30 | 
            +
              {{/ variables }}
         | 
| 31 | 
            +
            </table>
         | 
| 32 | 
            +
             | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            require 'test/unit'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module TestViews; end
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            class AutoloadingTest < Test::Unit::TestCase
         | 
| 6 | 
            +
              def setup
         | 
| 7 | 
            +
                Mustache.view_path = File.dirname(__FILE__) + '/../examples'
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              def test_autoload
         | 
| 11 | 
            +
                klass = Mustache.view_class(:Comments)
         | 
| 12 | 
            +
                assert_equal Comments, klass
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              def test_autoload_lowercase
         | 
| 16 | 
            +
                klass = Mustache.view_class(:comments)
         | 
| 17 | 
            +
                assert_equal Comments, klass
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def test_autoload_nil
         | 
| 21 | 
            +
                klass = Mustache.view_class(nil)
         | 
| 22 | 
            +
                assert_equal Mustache, klass
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def test_autoload_empty_string
         | 
| 26 | 
            +
                klass = Mustache.view_class('')
         | 
| 27 | 
            +
                assert_equal Mustache, klass
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              def test_namespaced_autoload
         | 
| 31 | 
            +
                Mustache.view_namespace = TestViews
         | 
| 32 | 
            +
                klass = Mustache.view_class('Namespaced')
         | 
| 33 | 
            +
                assert_equal TestViews::Namespaced, klass
         | 
| 34 | 
            +
                assert_equal <<-end_render.strip, klass.render
         | 
| 35 | 
            +
            <h1>Dragon < Tiger</h1>
         | 
| 36 | 
            +
            end_render
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
    
        data/test/mustache_test.rb
    CHANGED
    
    | @@ -224,6 +224,29 @@ data | |
| 224 224 | 
             
                end
         | 
| 225 225 | 
             
              end
         | 
| 226 226 |  | 
| 227 | 
            +
              def test_reports_unclosed_sections
         | 
| 228 | 
            +
                instance = Mustache.new
         | 
| 229 | 
            +
                instance[:list] = [ :item => 1234 ]
         | 
| 230 | 
            +
                instance.template = '{{#list}} <li>{{item}}</li> {{/gist}}'
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                assert_raise Mustache::Template::UnclosedSection do
         | 
| 233 | 
            +
                  instance.render
         | 
| 234 | 
            +
                end
         | 
| 235 | 
            +
              end
         | 
| 236 | 
            +
             | 
| 237 | 
            +
              def test_unclosed_sections_reports_the_line_number
         | 
| 238 | 
            +
                instance = Mustache.new
         | 
| 239 | 
            +
                instance[:list] = [ :item => 1234 ]
         | 
| 240 | 
            +
                instance.template = "hi\nmom\n{{#list}} <li>{{item}}</li> {{/gist}}"
         | 
| 241 | 
            +
             | 
| 242 | 
            +
                begin
         | 
| 243 | 
            +
                  instance.render
         | 
| 244 | 
            +
                rescue => e
         | 
| 245 | 
            +
                end
         | 
| 246 | 
            +
             | 
| 247 | 
            +
                assert e.message.include?('line 3')
         | 
| 248 | 
            +
              end
         | 
| 249 | 
            +
             | 
| 227 250 | 
             
              def test_enumerable_sections_accept_a_hash_as_a_context
         | 
| 228 251 | 
             
                instance = Mustache.new
         | 
| 229 252 | 
             
                instance[:list] = { :item => 1234 }
         | 
| @@ -240,6 +263,31 @@ data | |
| 240 263 | 
             
                assert_equal '<li>1234</li>', instance.render.strip
         | 
| 241 264 | 
             
              end
         | 
| 242 265 |  | 
| 266 | 
            +
              def test_not_found_in_context_renders_empty_string
         | 
| 267 | 
            +
                instance = Mustache.new
         | 
| 268 | 
            +
                instance.template = '{{#list}} <li>{{item}}</li> {{/list}}'
         | 
| 269 | 
            +
             | 
| 270 | 
            +
                assert_equal '', instance.render.strip
         | 
| 271 | 
            +
              end
         | 
| 272 | 
            +
             | 
| 273 | 
            +
              def test_not_found_in_nested_context_renders_empty_string
         | 
| 274 | 
            +
                instance = Mustache.new
         | 
| 275 | 
            +
                instance[:list] = { :item => 1234 }
         | 
| 276 | 
            +
                instance.template = '{{#list}} <li>{{prefix}}{{item}}</li> {{/list}}'
         | 
| 277 | 
            +
             | 
| 278 | 
            +
                assert_equal '<li>1234</li>', instance.render.strip
         | 
| 279 | 
            +
              end
         | 
| 280 | 
            +
             | 
| 281 | 
            +
              def test_not_found_in_context_raises_when_asked_to
         | 
| 282 | 
            +
                instance = Mustache.new
         | 
| 283 | 
            +
                instance.raise_on_context_miss = true
         | 
| 284 | 
            +
                instance.template = '{{#list}} <li>{{item}}</li> {{/list}}'
         | 
| 285 | 
            +
             | 
| 286 | 
            +
                assert_raises Mustache::ContextMiss do
         | 
| 287 | 
            +
                  instance.render.strip
         | 
| 288 | 
            +
                end
         | 
| 289 | 
            +
              end
         | 
| 290 | 
            +
             | 
| 243 291 | 
             
              def test_knows_when_its_been_compiled_when_set_with_string
         | 
| 244 292 | 
             
                klass = Class.new(Mustache)
         | 
| 245 293 |  | 
| @@ -250,7 +298,7 @@ data | |
| 250 298 |  | 
| 251 299 | 
             
              def test_knows_when_its_been_compiled_when_using_a_file_template
         | 
| 252 300 | 
             
                klass = Class.new(Simple)
         | 
| 253 | 
            -
                klass.template_file = File.dirname(__FILE__) + '/../examples/simple. | 
| 301 | 
            +
                klass.template_file = File.dirname(__FILE__) + '/../examples/simple.mustache'
         | 
| 254 302 |  | 
| 255 303 | 
             
                assert ! klass.compiled?
         | 
| 256 304 | 
             
                klass.render
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: mustache
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.4.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors: 
         | 
| 7 7 | 
             
            - Chris Wanstrath
         | 
| @@ -9,7 +9,7 @@ autorequire: | |
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 11 |  | 
| 12 | 
            -
            date: 2009-10- | 
| 12 | 
            +
            date: 2009-10-27 00:00:00 -07:00
         | 
| 13 13 | 
             
            default_executable: 
         | 
| 14 14 | 
             
            dependencies: []
         | 
| 15 15 |  | 
| @@ -36,34 +36,40 @@ files: | |
| 36 36 | 
             
            - benchmarks/simple.erb
         | 
| 37 37 | 
             
            - benchmarks/speed.rb
         | 
| 38 38 | 
             
            - contrib/mustache.vim
         | 
| 39 | 
            -
            - examples/comments. | 
| 39 | 
            +
            - examples/comments.mustache
         | 
| 40 40 | 
             
            - examples/comments.rb
         | 
| 41 | 
            -
            - examples/complex_view. | 
| 41 | 
            +
            - examples/complex_view.mustache
         | 
| 42 42 | 
             
            - examples/complex_view.rb
         | 
| 43 | 
            -
            - examples/delimiters. | 
| 43 | 
            +
            - examples/delimiters.mustache
         | 
| 44 44 | 
             
            - examples/delimiters.rb
         | 
| 45 | 
            -
            - examples/double_section. | 
| 45 | 
            +
            - examples/double_section.mustache
         | 
| 46 46 | 
             
            - examples/double_section.rb
         | 
| 47 | 
            -
            - examples/escaped. | 
| 47 | 
            +
            - examples/escaped.mustache
         | 
| 48 48 | 
             
            - examples/escaped.rb
         | 
| 49 | 
            -
            - examples/inner_partial. | 
| 49 | 
            +
            - examples/inner_partial.mustache
         | 
| 50 50 | 
             
            - examples/inner_partial.txt
         | 
| 51 | 
            +
            - examples/namespaced.mustache
         | 
| 52 | 
            +
            - examples/namespaced.rb
         | 
| 51 53 | 
             
            - examples/passenger.conf
         | 
| 52 54 | 
             
            - examples/passenger.rb
         | 
| 53 | 
            -
            - examples/simple. | 
| 55 | 
            +
            - examples/simple.mustache
         | 
| 54 56 | 
             
            - examples/simple.rb
         | 
| 55 | 
            -
            - examples/template_partial. | 
| 57 | 
            +
            - examples/template_partial.mustache
         | 
| 56 58 | 
             
            - examples/template_partial.rb
         | 
| 57 59 | 
             
            - examples/template_partial.txt
         | 
| 58 | 
            -
            - examples/unescaped. | 
| 60 | 
            +
            - examples/unescaped.mustache
         | 
| 59 61 | 
             
            - examples/unescaped.rb
         | 
| 60 | 
            -
            - examples/view_partial. | 
| 62 | 
            +
            - examples/view_partial.mustache
         | 
| 61 63 | 
             
            - examples/view_partial.rb
         | 
| 62 64 | 
             
            - lib/mustache.rb
         | 
| 63 65 | 
             
            - lib/mustache/context.rb
         | 
| 64 66 | 
             
            - lib/mustache/sinatra.rb
         | 
| 65 67 | 
             
            - lib/mustache/template.rb
         | 
| 66 68 | 
             
            - lib/mustache/version.rb
         | 
| 69 | 
            +
            - lib/rack/bug/panels/mustache_panel.rb
         | 
| 70 | 
            +
            - lib/rack/bug/panels/mustache_panel/mustache_extension.rb
         | 
| 71 | 
            +
            - lib/rack/bug/panels/mustache_panel/view.mustache
         | 
| 72 | 
            +
            - test/autoloading_test.rb
         | 
| 67 73 | 
             
            - test/mustache_test.rb
         | 
| 68 74 | 
             
            has_rdoc: true
         | 
| 69 75 | 
             
            homepage: http://github.com/defunkt/mustache
         | 
| @@ -94,12 +100,14 @@ signing_key: | |
| 94 100 | 
             
            specification_version: 3
         | 
| 95 101 | 
             
            summary: Mustache is a framework-agnostic way to render logic-free views.
         | 
| 96 102 | 
             
            test_files: 
         | 
| 103 | 
            +
            - test/autoloading_test.rb
         | 
| 97 104 | 
             
            - test/mustache_test.rb
         | 
| 98 105 | 
             
            - examples/comments.rb
         | 
| 99 106 | 
             
            - examples/complex_view.rb
         | 
| 100 107 | 
             
            - examples/delimiters.rb
         | 
| 101 108 | 
             
            - examples/double_section.rb
         | 
| 102 109 | 
             
            - examples/escaped.rb
         | 
| 110 | 
            +
            - examples/namespaced.rb
         | 
| 103 111 | 
             
            - examples/passenger.rb
         | 
| 104 112 | 
             
            - examples/simple.rb
         | 
| 105 113 | 
             
            - examples/template_partial.rb
         |