liquid_assets
Description
Allows you to use the Liquid template language in Rails, both as templates and as JavaScript via the asset_pipeline.
The Ruby bits are via the standard Liquid http://liquidmarkup.org/ gem.
The JavaScript support is possible through the TinyLiquid https://github.com/leizongmin/tinyliquid JavaScript library, which execjs calls to compiles the templates to JavaScript. I did have to perform a few small modifications to the library in order to get it to support partials in the same manner as the Ruby library
Javascript version of templates may be rendered by calling
LQT.Render( path, data );
and partials by:
LQT.RenderPartial( path, data );
Rationale
I am currently developing a largish project that has a requirement for user edited html that needs to be rendered both as a standard website and as a single page Backbone application.
I'd originally attempted to use Mustache templates but discarded that idea after not being able to do simple things like formatting numbers in the views.
Liquid templates were ideal, but they lacked a suitable JS environment. I then ran across the TinyLiquid project and created this gem in order to cleanly unite the them.
Configuration
Set the root in an initializer, i.e. config/initializers/liquid_assets.rb The root defaults to app/assets/templates.
LiquidAssets::Config.configure do |config|
config.path_prefix = 'app/assets/templates'
config.filters = MyFilterModule
config.namespace = 'LQT'
config.globals = lambda{ { 'website_name': 'A Website of Excellence!' } }
config.content_provider = lambda{ |path|
path == 'hello-world' ? LiquidAssets::Template.new( 'Hello World!', Time.now ) : false
}
end
By default the Ruby filters are set to Liquid::StandardFilters http://liquid.rubyforge.org/classes/Liquid/StandardFilters.html. Javascript versions are also included in the liquid_assets.js file under the LQT.Filters namespace.
Content_provider config
A content provider option can be set on the configuration. It can be used to retrieve a template
Example
Simple rendering
tmpl = LiquidAssets.parse <<END_TEMPLATE
Hello {{visitor.name | capitalize }},
So long and thanks for all the fish!
END_TEMPLATE
tmpl.render({'visitor'=>{'name'=>'Bob'}})
Or with a file 'foo/bar.liquid', containing the content (under Config.path_prefix): tmpl = LiquidAssets.template( 'foo/bar' ) ``
Rendering via rails engine
Given the below configuration: LiquidAssets::Config.configure do |config| config.globals = { copyright_holder: 'BigCorp Inc.' } end
A liquid template with content:
Hello {{visitor.name | capitalize }},
Thanks for stopping by!
{{ author.name | capitalize }}'s age is {{author.age}}.
They will be {{ author.age| plus:10 }} in ten years.
{{ include 'blog/legalease' }}
stored at: app/assets/templates/blog/about.liquid
And a partial:
This post is copyright {{ copyright_holder }}
stored at: app/assets/templates/blog/_legalease.liquid
as Rails view
blog_controller.rb:
def show
@visitor = { 'name' => 'bob' }
@author = { 'name' => 'jimmy smith', 'age'=>23 }
render :template=>'blog/about'
end
Note: Since the template is written in Liquid, it DOES NOT have access to the normal rails helper methods.
It does have access to instance variables, but can only interact with simple Strings, Numbers, Arrays, & Hashes. An additional restriction is that Hashes must use strings for keys, not symbols.
I'm sure some of these limitations could be worked around, but my needs do not include supporting them at this time. Patches are welcomed
as AssetPipeline pre-compiled javascript
You can include your liquid templates in the asset_pipeline by using the standard //= syntax in one of your existing JavaScript files
//=require liquid_assets
//=require blog/_welcome // Could also require_tree, or an index.js manifest file
//=require blog/post
Will compile post.liquid to JavaScript using TinyLiquid and include it at:
LQT.Templates['blog/post']
It can then be rendered by
LQT.Render('blog/post',{ author: { name: jimmy smith', age: 23}, visitor: {name: 'bob' } } )
A set of standard filters are included at LQT.Filters, which may be extended with custom filter functions.
Note: The LQT namespace is short for LiQuid Template, à la JST from underscore. It can be modified by configuring:
LiquidAssets::Config.configure do |config|
config.namespace = 'FANCY_NAME'
end
If you do modify the namespace, you may have to clean Rails asset cache by running 'rake assets:clean' In my experience, sometimes Rails doesn't notice when vendor assets ERB variables change and may not regenerate the template.
Result
The output from the template should be identical from both Ruby & Javascript:
Hello Bob,
Thanks for stopping by!
Jimmy Smith's age is 23.
They will be 33 in ten years.
This post is copyright BigCorp Inc.
evaluating liquid templates from string
template = LiquidAssets.parse( 'A {{name|upcase}} template' )
template.render({ :name=>'liquid' })
=> 'A Liquid template'
Thanks
Shopify for creating the liquid template language and Ruby implementation. leizongmin for the tinyliquid Javascript support.
I cribbed from hogan_assets, Poirot and Stache in creating this gem. Good parts are thanks to those projects, mistakes are mine.
Contributing
Fork on github, implement your change, submit a pull request.
Copyright
Copyright (c) 2013 Nathan Stitt. See LICENSE.txt for further details, it's MIT