Permalink
Browse files

Merge branch 'master' into delimiters

Conflicts:
	HISTORY.md
	test/mustache_test.rb
  • Loading branch information...
2 parents b3f1af1 + 8e233bb commit d2b84855ea08c363bb248d91ca44099ec289b65d @defunkt defunkt committed Oct 12, 2009
Showing with 134 additions and 5 deletions.
  1. +13 −0 HISTORY.md
  2. +18 −0 README.md
  3. +13 −0 Rakefile
  4. +12 −1 lib/mustache.rb
  5. +4 −1 lib/mustache/sinatra.rb
  6. +18 −3 lib/mustache/template.rb
  7. +56 −0 test/mustache_test.rb
View
13 HISTORY.md
@@ -2,6 +2,19 @@
* Set Delimiter tags are now supported. See the README
+## 0.2.3 (2009-??-??)
+
+* 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
+>>>>>>> master
+
## 0.2.2 (2009-10-11)
* Improved documentation
View
18 README.md
@@ -144,6 +144,24 @@ And this view code:
When rendered, our view will contain a list of all repository names in
the database.
+As a convenience, if a section returns a hash (as opposed to an array
+or a boolean) it will be treated as a single item array.
+
+With the above template, we could use this Ruby code for a single
+iteration:
+
+ def repo
+ { :name => Repository.first.to_s }
+ end
+
+This would be treated by Mustache as functionally equivalent to the
+following:
+
+ def repo
+ [ { :name => Repository.first.to_s } ]
+ end
+
+
### Comments
Comments begin with a bang and are ignored. The following template:
View
13 Rakefile
@@ -47,3 +47,16 @@ task :publish => [ :gemspec, :build ] do
system "git clean -fd"
exec "rake pages"
end
+
+desc "Install the edge gem"
+task :install_edge => [ :dev_version, :gemspec, :build ] do
+ exec "gem install pkg/mustache-#{Mustache::Version}.gem"
+end
+
+# Sets the current Mustache version to the current dev version
+task :dev_version do
+ $LOAD_PATH.unshift 'lib/mustache'
+ require 'mustache/version'
+ version = Mustache::Version + '.' + Time.now.to_i.to_s
+ Mustache.const_set(:Version, version)
+end
View
13 lib/mustache.rb
@@ -123,7 +123,18 @@ def self.template
end
def self.template=(template)
- @template = template
+ @template = templateify(template)
+ end
+
+ # Has this template already been compiled? Compilation is somewhat
+ # expensive so it may be useful to check this before attempting it.
+ def self.compiled?
+ @template.is_a? Template
+ end
+
+ # Has this instance or its class already compiled a template?
+ def compiled?
+ (@template && @template.is_a?(Template)) || self.class.compiled?
end
# template_partial => TemplatePartial
View
5 lib/mustache/sinatra.rb
@@ -67,6 +67,9 @@ def render_mustache(template, data, opts, locals, &block)
require "#{file}".chomp('.rb')
klass = namespace::Views.const_get(name)
+ # compile and cache the template
+ klass.template = data
+
else
# Still nothing. Use the stache.
klass = Mustache
@@ -90,7 +93,7 @@ def render_mustache(template, data, opts, locals, &block)
# lets us use {{yield}} in layout.html to render the actual page.
instance[:yield] = block.call if block
- instance.template = data
+ instance.template = data unless instance.compiled?
instance.to_html
end
end
View
21 lib/mustache/template.rb
@@ -53,9 +53,24 @@ def compile_sections(src)
name = $1.strip.to_sym.inspect
code = compile($2)
ctxtmp = "ctx#{tmpid}"
- res << ev("(v = ctx[#{name}]) ? v.respond_to?(:each) ? "\
- "(#{ctxtmp}=ctx.dup; r=v.map{|h|ctx.update(h);#{code}}.join; "\
- "ctx.replace(#{ctxtmp});r) : #{code} : ''")
+ res << ev(<<-compiled)
+ if v = ctx[#{name}]
+ v = [v] if v.is_a?(Hash) # shortcut when passed a single hash
+ if v.respond_to?(:each)
+ #{ctxtmp} = ctx.dup
+ begin
+ r = v.map { |h| ctx.update(h); #{code} }.join
+ rescue TypeError => e
+ raise TypeError,
+ "All elements in {{#{name.to_s[1..-1]}}} are not hashes!"
+ end
+ ctx.replace(#{ctxtmp})
+ r
+ else
+ #{code}
+ end
+ end
+ compiled
# $' = The string to the right of the last successful match
src = $'
end
View
56 test/mustache_test.rb
@@ -194,4 +194,60 @@ def test_render_from_file
:server => 'example.com',
:deploy_to => '/var/www/example.com' )
end
+
+ def test_reports_type_errors_in_sections
+ instance = Mustache.new
+ instance[:list] = [ :item, 1234 ]
+ instance.template = '{{#list}} <li>{{item}}</li> {{/list}}'
+
+ assert_raise TypeError do
+ instance.render
+ end
+ end
+
+ def test_enumerable_sections_accept_a_hash_as_a_context
+ instance = Mustache.new
+ instance[:list] = { :item => 1234 }
+ instance.template = '{{#list}} <li>{{item}}</li> {{/list}}'
+
+ assert_equal '<li>1234</li>', instance.render.strip
+ end
+
+ def test_knows_when_its_been_compiled_when_set_with_string
+ klass = Class.new(Mustache)
+
+ assert ! klass.compiled?
+ klass.template = 'Hi, {{person}}!'
+ assert klass.compiled?
+ end
+
+ def test_knows_when_its_been_compiled_when_using_a_file_template
+ klass = Class.new(Simple)
+ klass.template_file = File.dirname(__FILE__) + '/../examples/simple.html'
+
+ assert ! klass.compiled?
+ klass.render
+ assert klass.compiled?
+ end
+
+ def test_an_instance_knows_when_its_class_is_compiled
+ instance = Simple.new
+
+ assert ! Simple.compiled?
+ assert ! instance.compiled?
+
+ Simple.render
+
+ assert Simple.compiled?
+ assert instance.compiled?
+ end
+
+ def test_knows_when_its_been_compiled_at_the_instance_level
+ klass = Class.new(Mustache)
+ instance = klass.new
+
+ assert ! instance.compiled?
+ instance.template = 'Hi, {{person}}!'
+ assert instance.compiled?
+ end
end

0 comments on commit d2b8485

Please sign in to comment.