Giter Club home page Giter Club logo

tilt's Introduction

Tilt Test suite Inline docs

Tilt is a thin interface over a bunch of different Ruby template engines in an attempt to make their usage as generic as possible. This is useful for web frameworks, static site generators, and other systems that support multiple template engines but don't want to code for each of them individually.

The following features are supported for all template engines (assuming the feature is relevant to the engine):

  • Custom template evaluation scopes / bindings
  • Ability to pass locals to template evaluation
  • Support for passing a block to template evaluation for "yield"
  • Backtraces with correct filenames and line numbers
  • Template file caching and reloading
  • Fast, method-based template source compilation

The primary goal is to get all of the things listed above right for all template engines included in the distribution.

Support for these template engines is included with the package:

Engine File Extensions Required Libraries Maintainer
Asciidoctor .ad, .adoc, .asciidoc asciidoctor (>= 0.1.0) Community
ERB .erb, .rhtml none (included ruby stdlib) Tilt team
InterpolatedString .str none (included ruby core) Tilt team
Erubi .erb, .rhtml, .erubi erubi Community
Erubis .erb, .rhtml, .erubis erubis Tilt team
Haml .haml haml Tilt team
Sass .sass sass-embedded (>= 1.0) or sassc (>=2.0) Tilt team
Scss .scss sass-embedded (>= 1.0) or sassc (>=2.0) Tilt team
Builder .builder builder Tilt team
Liquid .liquid liquid Community
RDiscount .markdown, .mkd, .md rdiscount Community
Redcarpet .markdown, .mkd, .md redcarpet Community
Kramdown .markdown, .mkd, .md kramdown Community
Pandoc .markdown, .mkd, .md pandoc Community
reStructuredText .rst pandoc Community
Maruku .markdown, .mkd, .md maruku Community
CommonMarker .markdown, .mkd, .md commonmarker Community
RedCloth .textile redcloth Community
RDoc .rdoc rdoc Tilt team
Radius .radius radius Community
Markaby .mab markaby Tilt team
Nokogiri .nokogiri nokogiri Community
CoffeeScript .coffee coffee-script (+ javascript) Tilt team
CoffeeScript (literate) .litcoffee coffee-script (>= 1.5.0) (+ javascript) Tilt team
LiveScript .ls livescript (+ javascript) Tilt team
TypeScript .ts typescript (+ javascript) Tilt team
Creole (Wiki markup) .wiki, .creole creole Community
WikiCloth (Wiki markup) .wiki, .mediawiki, .mw wikicloth Community
Yajl .yajl yajl-ruby Community
CSV .rcsv none (included ruby stdlib) Tilt team
Prawn .prawn prawn (>= 2.0.0) Community
Babel .es6, .babel, .jsx babel-transpiler Tilt team
Opal .rb opal Community

Every supported template engine has a maintainer. Note that this is the maintainer of the Tilt integration, not the maintainer of the template engine itself. The maintainer is responsible for providing an adequate integration and keeping backwards compatibility across Tilt version. Some integrations are maintained by the community, which is handled in the following way:

  • The Tilt team will liberally accept pull requests to update existing community-maintained template integrations. It's up to the community as a whole to make sure the integration stays consistent and backwards compatible over time.
  • Test failures in community-maintained integrations will not be prioritized by the Tilt team and a new version of Tilt might be released even though these tests are failing.
  • Anyone can become a maintainer for a template engine integration they care about. Just open an issue and we'll figure it out.
  • The Tilt team is no longer accepting new community-maintained template integrations.

These template engines ship with their own Tilt integration:

Engine File Extensions Required Libraries
Slim .slim slim (>= 0.7)
Embedded JavaScript sprockets
Embedded CoffeeScript sprockets
JST sprockets
Org-mode .org org-ruby (>= 0.6.2)
Emacs Org .org tilt-emacs_org
Handlebars .hbs, handlebars tilt-handlebars
Jbuilder .jbuilder tilt-jbuilder

See TEMPLATES.md for detailed information on template engine options and supported features.

Basic Usage

Instant gratification:

require 'erb'
require 'tilt'
template = Tilt.new('templates/foo.erb')
=> #<Tilt::ERBTemplate @file="templates/foo.erb" ...>
output = template.render
=> "Hello world!"

It's recommended that calling programs explicitly require template engine libraries (like 'erb' above) at load time. Tilt attempts to lazy require the template engine library the first time a template is created but this is prone to error in threaded environments.

The {Tilt} module contains generic implementation classes for all supported template engines. Each template class adheres to the same interface for creation and rendering. In the instant gratification example, we let Tilt determine the template implementation class based on the filename, but {Tilt::Template} implementations can also be used directly:

require 'tilt/haml'
template = Tilt::HamlTemplate.new('templates/foo.haml')
output = template.render

The render method takes an optional evaluation scope and locals hash arguments. Here, the template is evaluated within the context of the Person object with locals x and y:

require 'tilt/erb'
template = Tilt::ERBTemplate.new('templates/foo.erb')
joe = Person.find('joe')
output = template.render(joe, :x => 35, :y => 42)

If no scope is provided, the template is evaluated within the context of an object created with Object.new.

A single Template instance's render method may be called multiple times with different scope and locals arguments. Continuing the previous example, we render the same compiled template but this time in jane's scope:

jane = Person.find('jane')
output = template.render(jane, :x => 22, :y => nil)

Blocks can be passed to render for templates that support running arbitrary ruby code (usually with some form of yield). For instance, assuming the following in foo.erb:

Hey <%= yield %>!

The block passed to render is called on yield:

template = Tilt::ERBTemplate.new('foo.erb')
template.render { 'Joe' }
# => "Hey Joe!"

Template Mappings

The {Tilt::Mapping} class includes methods for associating template implementation classes with filename patterns and for locating/instantiating template classes based on those associations.

The {Tilt} module has a global instance of Mapping that is populated with the table of template engines above.

The {Tilt.register} method associates a filename pattern with a specific template implementation. To use ERB for files ending in a .bar extension:

>> Tilt.register Tilt::ERBTemplate, 'bar'
>> Tilt.new('views/foo.bar')
=> #<Tilt::ERBTemplate @file="views/foo.bar" ...>

Retrieving the template class for a file or file extension:

>> Tilt['foo.bar']
=> Tilt::ERBTemplate
>> Tilt['haml']
=> Tilt::HamlTemplate

Retrieving a list of template classes for a file:

>> Tilt.templates_for('foo.bar')
=> [Tilt::ERBTemplate]
>> Tilt.templates_for('foo.haml.bar')
=> [Tilt::ERBTemplate, Tilt::HamlTemplate]

The template class is determined by searching for a series of decreasingly specific name patterns. When creating a new template with Tilt.new('views/foo.html.erb'), we check for the following template mappings:

  1. views/foo.html.erb
  2. foo.html.erb
  3. html.erb
  4. erb

Encodings

Tilt needs to know the encoding of the template in order to work properly:

Tilt will use Encoding.default_external as the encoding when reading external files. If you're mostly working with one encoding (e.g. UTF-8) we highly recommend setting this option. When providing a custom reader block (Tilt.new { custom_string }) you'll have ensure the string is properly encoded yourself.

Most of the template engines in Tilt also allows you to override the encoding using the :default_encoding-option:

tmpl = Tilt.new('hello.erb', :default_encoding => 'Big5')

Ultimately it's up to the template engine how to handle the encoding: It might respect :default_encoding, it might always assume it's UTF-8 (like CoffeeScript), or it can do its own encoding detection.

Template Compilation

Tilt compiles generated Ruby source code produced by template engines and reuses it on subsequent template invocations. Benchmarks show this yields a 5x-10x performance increase over evaluating the Ruby source on each invocation.

Template compilation is currently supported for these template engines: StringTemplate, ERB, Erubis, Erubi, Haml, Nokogiri, Builder and Yajl.

LICENSE

Tilt is Copyright (c) 2010 Ryan Tomayko and distributed under the MIT license. See the COPYING file for more info.

tilt's People

Contributors

alexgb avatar amarshall avatar amatsuda avatar aslakknutsen avatar daddye avatar jeremyevans avatar jmuheim avatar josh avatar juanmcuello avatar judofyr avatar k0kubun avatar kabturek avatar karloescota avatar kematzy avatar lilith avatar mattwildig avatar minad avatar mishina2228 avatar nesquena avatar ntkme avatar raphink avatar rkh avatar rtomayko avatar smtlaissezfaire avatar thinkerbot avatar timfel avatar tommay avatar trans avatar voxik avatar weppos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tilt's Issues

passing local variables to nokogiri templates

I've been asked to copy this issue from Sinatra (sinatra/sinatra#277)

Given the following application:

require 'sinatra'
require 'nokogiri'

get '/fail' do
  @thing = 'thing'
  nokogiri :fail
end

get '/success' do
  @thing = 'thing'
  nokogiri :success
end

get '/success2' do
  @thing = 'thing'
  Nokogiri::XML::Builder.new() { |xml|
    xml.test {
      xml.something @thing
    }
  }.to_xml
end

__END__

@@ fail
xml.test {
  xml.something @thing
}

@@ success
xml.something @thing

The instance variable @thing is nil inside of the "fail" template. Note that in the "success" and "success2" examples the variable @thing is non-nil. Is this something that is to be expected when using nokogiri templates in this way?

Environment (on ruby 1.9.2p136)

  nokogiri (1.4.4)
    rack (1.2.2)
    sinatra (1.2.6)
      rack (~> 1.1)
      tilt (>= 1.2.2, < 2.0)
    tilt (1.3)

gemspec doesn't include executables

When I install tilt via rubygems, the tilt binary doesn't get added to my path. Add the relevant executable bits to the gemspec to fix the issue:

s.default_executable = 'tilt'
s.executables = ['tilt']

Encoding issue with parsed templates

I tried to use tilt with slim templates, but it returned

Encoding::CompatibilityError at /
incompatible encoding regexp match (UTF-8 regexp with ASCII-8BIT string)
file: parser.rb location: =~ line: 276
(the error happened in slim 0.9.0's slim/parser.rb)

I have dived into the code, and I could find it happens because tilt reads the template file with File#binread (actionpack / active_view uses File#read). I could find a commit which changed this behavior in favor of erb templates, but it broke all the others, because default_encoding option is not handled anywhere:

20a7ce7

Encoding::CompatibilityError exception using UTF-8 locals with Haml on JRuby (1.9 mode)

When using non-ASCII locals (e.g. cyrillic) in souce encoded in UTF-8 without BOM and Haml template (must include non-ASCII characters too) UTF-8 - Encoding::CompatibilityError exception raises.

tilt1.rb (UTF-8 without BOM):

# encoding: utf-8
require 'haml'
require 'tilt'

template = Tilt.new('tilt1.haml')
puts template.render(self, :test_var => 'проверка')

tilt1.haml (UTF-8 without BOM):

-# encoding: utf-8
%p проверка
%p= test_var

Running on JRuby with command-line parameter --1.9 causes exception, but with --1.8 command-line parameter or on MRI Ruby it works as expected.

C:\aXe1\dev\ruby\test\jruby>jruby --1.9 tilt1.rb
Encoding::CompatibilityError: incompatible character encodings: ASCII-8BIT and U
TF-8
  evaluate_source at tilt1.haml:3
             eval at org/jruby/RubyKernel.java:1093
  evaluate_source at c:/jruby/jruby-1.6.1/lib/ruby/gems/1.9/gems/tilt-1.3/lib/ti
lt/template.rb:225
    instance_eval at org/jruby/RubyBasicObject.java:1699
  evaluate_source at c:/jruby/jruby-1.6.1/lib/ruby/gems/1.9/gems/tilt-1.3/lib/ti
lt/template.rb:225
  cached_evaluate at c:/jruby/jruby-1.6.1/lib/ruby/gems/1.9/gems/tilt-1.3/lib/ti
lt/template.rb:144
         evaluate at c:/jruby/jruby-1.6.1/lib/ruby/gems/1.9/gems/tilt-1.3/lib/ti
lt/template.rb:127
         evaluate at c:/jruby/jruby-1.6.1/lib/ruby/gems/1.9/gems/tilt-1.3/lib/ti
lt/haml.rb:24
           render at c:/jruby/jruby-1.6.1/lib/ruby/gems/1.9/gems/tilt-1.3/lib/ti
lt/template.rb:76
           (root) at tilt1.rb:7

C:\aXe1\dev\ruby\test\jruby>jruby --1.8 tilt1.rb
<p>╨┐╤А╨╛╨▓╨╡╤А╨║╨░</p>
<p>╨┐╤А╨╛╨▓╨╡╤А╨║╨░</p>

C:\aXe1\dev\ruby\test\jruby>ruby tilt1.rb
<p>╨┐╤А╨╛╨▓╨╡╤А╨║╨░</p>
<p>╨┐╤А╨╛╨▓╨╡╤А╨║╨░</p>

Don't see on incorrect characters above - it's ok, cause my console has CP866 encoding and not UTF-8.
Similar template in Erb works ok.

My environment:

C:\aXe1\dev\ruby\test\jruby>jgem list tilt

*** LOCAL GEMS ***

tilt (1.3)

C:\aXe1\dev\ruby\test\jruby>jgem list haml

*** LOCAL GEMS ***

haml (3.1.1)

C:\aXe1\dev\ruby\test\jruby>jruby -v
jruby 1.6.1 (ruby-1.9.2-p136) (2011-04-12 85838f6) (Java HotSpot(TM) Client VM 1
.6.0_21) [Windows 7-x86-java]

C:\aXe1\dev\ruby\test\jruby>ruby -v
ruby 1.9.2p180 (2011-02-18) [i386-mingw32]

sass no longer working in Sinatra — maybe something to do with tilt

I have updated all the gems in my Sinatra project and now my loading of sass templates doesn't work.

I have a route

get '/css/:sheet.css' do 
    content_type 'text/css', :charset => 'utf-8' 
    sass params[:sheet].to_sym 
end 

and when the code hits the sass line it throws

NoMethodError - undefined method `engine_options' for Sass::Plugin:Module: 
/Library/Ruby/Gems/1.8/gems/tilt-1.3.1/lib/tilt/css.rb:21:in `prepare' 
/Library/Ruby/Gems/1.8/gems/tilt-1.3.1/lib/tilt/template.rb:69:in `initialize' 
/Library/Ruby/Gems/1.8/gems/sinatra-1.2.6/lib/sinatra/base.rb:599:in `new' 
/Library/Ruby/Gems/1.8/gems/sinatra-1.2.6/lib/sinatra/base.rb:599:in `compile_template' 
/Library/Ruby/Gems/1.8/gems/tilt-1.3.1/lib/tilt.rb:127:in `fetch'  /Library/Ruby/Gems/1.8/gems/sinatra-1.2.6/lib/sinatra/base.rb:578:in `compile_template' 
/Library/Ruby/Gems/1.8/gems/sinatra-1.2.6/lib/sinatra/base.rb:562:in `render' 
/Library/Ruby/Gems/1.8/gems/sinatra-1.2.6/lib/sinatra/base.rb:468:in `sass' 
./showpony.rb:376:in `GET /css/:sheet.css'

Konstantin asked me to raise it as an issue here.

Cheers

Dave

Ship 1.3

All issues are closed now. We should run the tests on several machines/implementations and then we can finally ship this thing :D

Support inline Markaby

Builder does support it, Markaby doesn't:

Tilt[:mab].new do
  proc do
    html do
      head do
        # ...
      end
      body do
        # ...
      end
    end
  end
end.render

Need to render a string, rather then a file

I'm looking at using Tilt for a couple of projects of mine, but to do so I need to be able to pre-parse files, which means I need to pass text into the engine, not a file name.

I can see two ways of applying that to the interface. Either change the current interface to be like YAML's:

Tilt::ERBTemplate.new(File.new('templates/foo.erb'))

Or add a special constructor:

Tilt::ERBTemplate.string("...")

I think the former is technically superior but then it also is incompatible with current API.

RDocTemplate

Very cool to come across this project. I was just thinking yesterday that something like this would be a good idea. Lord knows I've implemented this kind of thing at least three or four times now. Anyway....

Definitely need to add RDoc markup support.

README outdated

"Template compilation is currently supported for these template engines: StringTemplate, ERB, Erubis, Haml, and Builder."

As a matter of fact Nokogiri templates also get compiled and it might be the case for some other templates.

cannot render "}" with string template

This:

Tilt::StringTemplate.new { '}' }.render

Will result in:

SyntaxError: compile error
    (__TEMPLATE__):1: syntax error, unexpected '}', expecting $end
from (__TEMPLATE__):1:in `evaluate_source'
from /Users/konstantin/.rvm/gems/ree-1.8.7-2010.02/gems/tilt-1.2.1/lib/tilt.rb:182:in `evaluate'
from /Users/konstantin/.rvm/gems/ree-1.8.7-2010.02/gems/tilt-1.2.1/lib/tilt.rb:118:in `render'
from (irb):17
from /Users/konstantin/.rvm/gems/ree-1.8.7-2010.02/specifications/activesupport-3.0.3.gemspec:12

It's clear from the code why this happens (@code = "%Q{#{data}}") and solving it would be kinda complex, I guess.

Register glob patterns

I have at least one use case were it might be useful to register a glob pattern, eg.

Tilt.register 'foo/*', Tilt::ERBTemplate

Better Tilt::Cache implementation

I mean, look at this shit:

# Extremely simple template cache implementation.
class Cache
  def initialize
    @cache = {}
  end

  def fetch(*key)
    key = key.map { |part| part.to_s }.join(":")
    @cache[key] ||= yield
  end

  def clear
    @cache = {}
  end
end

Gross.

Allow preprocessing of templates

It would be nice to be able to tell Tilt to preprocess templates before rendering them.

This is needed for applications like slideshow that use a format-agnostic directive to perform certain operations (for example !SLIDE to create a title-less new slide).

A possible syntax could be

Tilt.register_preprocessor 'markdown' { |content| my_preprocessor(content) }

This issue is specular to issue #68: issue #68 seeks a generic way to manage the output as it is generated, this issue is focused on the input only.

Any Reason For Using Only Symbols in Locals Hash?

Any reason why this method...

https://github.com/rtomayko/tilt/blob/master/lib/tilt/template.rb#L188

Isn't written like so...

https://gist.github.com/912847

The main difference being is the suggested implementation supports both symbols and string as hash keys, where as currently, using strings produces variables set to nil.

Can I propose that this be fixed (so I no longer have to monkey patch Tilt), or otherwise be given a reason why the current behaviour is intended/desireable.

Cheers

Normalize options for template/markup engines

Different engines use different options to specify the same things. This didn't really matter before fallback-mode (because Tilt['md'] could only return RDiscountTemplate), but now we need to make sure that i.e. Tilt['md'].new(:escape_html => true) works the same way for all Markdown templates.

MarkdownTemplate

Hi!

It took me some time to realize that MarkdownTemplate
(and possibly BlueClothTemplate, RedClothTemplate, and RDocTemplate)
is misnamed. Markdown engines do not execute pieces of
embedded Ruby code and do not have features common to most high-level
programming languages, such as variables, loops, etc.

Therefore, such engines could not be used as a base of template systems.
Nevertheless, they are extremely useful.

So, I tried to write proper doc for my favourite one.
See, TEMPLATES.md.

Regards

--Włodek

Multithreaded test suite error

Hi guys,

from time to time, I observe this multithreading error in test suite:

  1) Error:
test_using_compiled_templates_from_multiple_threads(CompileSiteTest):
SyntaxError: compile error
(__TEMPLATE__):2: syntax error, unexpected '=', expecting kEND
               local-71868248 = locals[:local-71868248]
                               ^
    (__TEMPLATE__):8:in `compile_template_method'
    ./test/tilt_compilesite_test.rb:48:in `join'
    ./test/tilt_compilesite_test.rb:48:in `test_using_compiled_templates_from_multiple_threads'
    ./test/tilt_compilesite_test.rb:48:in `each'
    ./test/tilt_compilesite_test.rb:48:in `test_using_compiled_templates_from_multiple_threads'
    ./test/tilt_compilesite_test.rb:34:in `times'
    ./test/tilt_compilesite_test.rb:34:in `test_using_compiled_templates_from_multiple_threads'

I observed this error on Fedora 16 recently. The Fedora package build passes due to this issues just sometimes. This is the Fedora bug report: https://bugzilla.redhat.com/show_bug.cgi?id=715713

How should we handle encodings?

Templates are very much based on files, which therefore means we'll have to worry about encodings. There are two ways templates can be passed to an engine: through a block (which returns a string: klass.new { 'foo' }) or through a filename.

Currently, encodings are handled as such:

  • Templates accessed through blocks are encoded in whatever encoding the string already has.
  • Templates accessed through the file systems are encoded in BINARY.

For all cases, you can pass :default_encoding => "FOO" as an option which will set the @default_encoding-ivar. In addition, if the precompiled code (when using precompiled mode) includes a magic comment (# coding: FOO) OR a @default_encoding is set, the generated code will include a magic comment before the preamble.

My thoughts

Some observation:

  • If a template is encoded in encoding FOO, we can assume the rendered string should also be in encoding FOO
  • If the template is fetched through a block, it already has a known encoding that we should respect
  • If the template is fetched from the file system, we don't know the encoding and our safest bet is to use BINARY
  • We can still give the template engine a hint of which encoding it's in (Encoding.default_external or the :default_encoding option)
  • In any case, the template engine might know better which encoding the template should be in and should be able to tell Tilt that the rendered string should be in encoding BAR.
  • The template engine shouldn't really need to worry about the file system or Encoding.default_external/internal. It should only get a template (encoded in some encoding) together with a guess from Tilt's side (which handles the file reading).

Let's go over each of the use cases and how I believe we should change Tilt:

Fetched through block

Any template that's fetched through a block already has an encoding. I think we should keep the current behaviour such that the template keeps its encoding and @default_encoding is set to options[:default_encoding] (which defaults to nil).

Fetched through file system

We don't know the encoding, so we'll read the file in binary mode and set @default_encoding to options[:default_encoding] || Encoding.default_external (this last one is different from today).

The precompiled code from the template engine

Because tilt.rb is written in UTF-8 and the precompiled code will be manipulated with literal strings from tilt.rb, the precompiled code generated by the template engine must be compatible with UTF-8 (not a code change, just a spec).

The encoding of the final generated code

The encoding of the final generated code should be decided by the template engine. There are two ways: the precompiled code is encoded in a specific encoding or the precompiled code includes a magic comment. Tilt should not add a magic comment based on @default_encoding because that's just a hint from Tilt's side and it's the engine responsibility to handle it correctly. (code change).

Why @default_encoding is only a hint

Even when you pass :default_encoding as an option (and it's not inherited from Encoding.default_external when reading from the file system) we'll have to depend on that the template engine handles it. The engine might have a different way of checking the encoding of the template, so we can't just @data.encode(@default_encoding) in case it leads to an encoding error. The default encoding is after all only that: the default encoding, which the engine should fall back to if it can't guess it.

How template engine should handle the encoding

Many simple template engine don't really need to work on the encoding-level, so from theirs point of view, this should be enough:

def compile(template, default_encoding)
  data = template.dup.force_encoding("BINARY")
  enc = encoding_specified_in_template(data) # extract magic comment or whatnot
  compiled = parse_and_compile(data)
  compiled.force_encoding(enc || default_encoding || template.encoding)
end

If you really need to be fully encoding-aware before you parse and compile, you should do something like this:

def compile(template, default_encoding)
  data = template.dup.force_encoding("BINARY")
  enc = encoding_specified_in_template(data) || default_encoding || template.encoding
  data.force_encoding(enc)
  compiled = parse_and_compile(data)
  compiled.force_encoding(enc) # You don't need this if you rather generate a magic comment
end

Your thoughs

What do you think?

Consider ripping Mustache view autoloading out

I think maybe the best way to do Mustache view class is just to require the caller to pass the view class in the options. Or, perhaps we can accept a view class in MustacheTemplate.new. I don't think the dynamic view class loading fits in Tilt. That should be in Sinatra or whatever the calling framework is.

Tilt::Cache with expire time support

source code:

# coding: utf-8
# Ruby 1.9
# super simple cache control
class Cachee < Hash
  #30 min default
  def fetch path, t=nil
  # page data, expire time
  data, et = self[path]
  now = Time.now
  if !et or et < now
    data = yield
    self[path] = [data, now + (t || 1800)]
  end
  data  
  end

  alias expire delete

  # clear expired caches
  def sweep
  now = Time.now
  delete_if do |_, (_, t)|
    t < now
  end
  end
end

Usage:

$cache = Cachee.new
get '/' do
  # expire after 1 hour
  $cache.fetch '/', 3600 do
    haml :index
  end
end

more infos here(in Chinese): http://www.javaeye.com/topic/592944

You can contact to the code author on GitHub: http://github.com/luikore

Template documentation

Each template engine should include docs on:

  • Basic usage and example template source.
  • All options supported by template engine.
  • Whether locals are supported.
  • Whether evaluating the template in an object scope is supported.
  • Link to template engine project page.
  • Link to template engine syntax reference / cheat sheet.

I'd prefer to not do this in rdoc. Use a separate templates.md file.

Two Types of Templates

I working with Tilt it has become quite clear to me that there are really two types of templates and that Tilt is try to handle them as if there were only one type. On the one hand, there are markup types: rdoc, markdown, textile, etc. These only render layout transformations, they don't handle interpolation of data. On the other side are the template types: erb, liquid, mustache, etc. which do interpolate data and have nothing to do with layouts.

I'm wondering if it might not be better to handle these two type separately, eg. separate base classes. Perhaps separate factory methods?

warnings about @data

Probably a good idea to initialize the @DaTa variable. I get a lot of this:

  /usr/lib/ruby/gems/1.8/gems/tilt-0.5/lib/tilt.rb:100: warning: instance variable @data not initialized

when I turn warnings on.

options are not passed to erubis

The following test fails:

it "passes options to erubis" do
  template = Tilt::ErubisTemplate.new(:pattern => '\{% %\}') { 'Hey {%= @name %}!' }
  scope = Object.new
  scope.instance_variable_set :@name, 'Joe'
  template.render(scope).should.equal "Hey Joe!"
end

See, Erubis User Guide
Changing Embedded Pattern.

It seems, that there is no way to pass options to ::Erubis::Eruby.new.

Regards, – Włodek Bzyl

Lazy loading template engines

I see that require_template_library(name) in called in #compile!, and you have a warning about it not being thread safe.

I suggest requiring the library when it's Template subclass is initialized. That would be a bit more robust, even if not completely thread safe (is it?). Also you don't need to use if defined?() on the require, because require won't require the same library twice.

TEMPLATES.md outdated

TEMPLATES.md is rather outdated and getting pretty large. Maybe we should move the documentation to each template class (now that they're in their own files)? That means we should put that documentation up somewhere though (unless we can generate TEMPLATES.md from that).

yield with Erb

Getting a yield called out of block attempting the simple example in the README.

in test.erb

Hey <%= yield %>

template = Tilt::ERBTemplate.new('test.erb')
template.render { 'Joe' }
#LocalJumpError: yield called out of block

New Release

Can we have a new release please? That would be awesome. Great work, btw.

Single Argument of Render Data

Something I've noticed about the render method. None of the engines ever use both scope and locals. They only use one or the other, forcing one to fit into the other as needed, and a bit willy-nilly I might add. I realized this while I was working on my own template engine and I wanted to support all variations. In the end I did not need an interface like Tilt's current:

def render(scope=Object.new, locals={}, &block)
  evaluate scope, locals || {}, &block
end

Rather I could use:

def render(scope_or_locals={}, &block)
  evaluate scope_or_locals || {}, &block
end

Then scope_or_locals could be either an Object scope, a locals Hash or even a Binding, and I could deal with each accordingly.

Test failures in tilt 1.1 due to negative object_id

object_id cannot be garantueed to be a positive number, but the "using compiled templates from multiple threads" assumes that. See https://bugs.gentoo.org/show_bug.cgi?id=339588 for a bug report about this. I can't reproduce this on a 64-bit system, but it does happen on 32-bit. Looking at the code of the test the "local#{thread_id}" is the cullprit, where thread_id is actually Thread.current.object_id. With a negative number this becomes local-123 and the parser is confused since that isn't a valid variable name.

Liquid scope

LiquidTemplate#evalutate doesn't appear to use +scope+ at all. B/c of the way Liquid works that's understandable, however support could be improved by offering the scope the option to participate using a #to_h method -- which is to say that the scope can represent itself as a hash.

Eg.

def evaluate(scope, locals, &block)
  locals = locals.rekey(&:to_s)
  if scope.respond_to?(:to_h)
    locals = scope.to_h.rekey(&:to_s).merge(locals)
  end
  @engine.render(locals)
end

Note the #rekey(&:to_s) call is just a shorthand Hash extension for:

.inject({}) { |hash,(k,v)| hash[k.to_s] = v ; hash }

Hmm... also can locals['yield'] be set to a lazy block.call maybe? Not sure about that one, but worth some thought.

MarkabyTemplate

smtlaissezfaire had a Tilt::MarkabyTemplate implementation but I can't seem to find it.

Add support for Kramdown.

Kramdown, the fast pure-Ruby markdown processor, is not yet supported by Tilt. Please support using Kramdown if BlueCloth nor RDiscount can be loaded.

Tilt 1.2.1 fails test with rdoc 3.x installed

I've ran tilt 1.2.1 tests against both rdoc 3.01 and rdoc 3.2. Both fail in the same way. Looks like an innocent failure in the real world, but it's nice to see all the tests pass.

  1) Failure:
test_preparing_and_evaluating_the_template_with_render(RDocTemplateTest) [./test/tilt_rdoctemplate_test.rb:14]:
<"

Hello World!

\n"> expected but was <"\n

Hello World!

\n">.

[Mustache] scope's variables are not setting in context while evaluating template

# in Tilt::MustacheTemplate.evaluate
483:       # copy instance variables from scope to the view
484:       scope.instance_variables.each do |name|
485:         instance.instance_variable_set(name, scope.instance_variable_get(name))
486:       end

# File lib/mustache.rb, line 294
def render(data = template, ctx = {})
  templateify(data).render(context.update(ctx))
end

So mustache only read the context hash while rendering.

# in Tilt::MustacheTemplate.evaluate
scope.instance_variables.each do |name|
  instance[name] = scope.instance_variable_get(name)  #set instance variables into context
end

Now, you can call the instance variable in the template file:

"Hello, {{@the_name_of_your_variable}}"

I think this is the right way to take instance variables to work with Mustache.

Better Mustache Support

Looking at the Mustache #evaluate code, the use of the scope's instance vars doesn't strike me as the "mustache way". I think, the code would be improved by creating a anonymous subclass of Mustache, eg.

klass = Class.new(Mustache)

Then delegating scope to klass, along the lines of:

scope.instance_methods.each do |m|
  klass.class_eval do
    define_method(m){ |*a| scope.__send__(m, *a) }
  end
end

And adding locals in the same manner:

locals.each do |k, v|
  klass.class_eval do
    define_method(k){ v }
  end
end

Then render

klass.render

That would conform to the Mustaches' stated usage pattern. See "Usage" at http://github.com/defunkt/mustache .

Outdated CoffeeScript

CoffeeScript support for Tilt is stuck at 0.3, current version is 0.6.2. I actually got it running on johnson, but was playing around with making the underlying embedded JavaScript engine pluggable (so it runs on other platforms as well). therubyrhino and therubyracer seem way to buggy and I have not tried lyndon yet.

[Mustache 0.5.1]The option :mustaches isn't work.

I put views rb files in views folder, then I set Tilt options hash with :path, :namespace and :mustaches, and initial my template like this:

Tilt.register 'mustache', Tilt::MustacheTemplate
layout = Tilt.new('templates/layout.mustache', tiltopt)

render it this way:

layout.render(self,:title => "Yet Another Title")

it seems working nicely.To make sure my views rb are really working, I

$ mv views view

restart server and reload the browser. Oops, it still working...

I check the tilt's source code and mustache's , it seems that :mustaches won't set on the engine.

# tilt.rb
475:         next if %w[view namespace mustaches].include?(key.to_s)
476:         @engine.send("#{key}=", value) if @engine.respond_to? "#{key}="

I searched mustache.rb, there is no attribute called mustaches.

Radius Template update

Check out the 'trans' fork. It has an update for the Radius docs and improvements to the implementation that need to go in.

There is one aspect to this that I need you to consider though, as I do not fully understand what is going on with CompileSite stuff. I tried to account for it via a respond_to?(:tilt), but I am not sure that's right --in fact I am pretty sure it is not.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.