Liquid 3

546 views
Skip to first unread message

DBA

unread,
Aug 25, 2010, 8:09:41 AM8/25/10
to Liquid Templates
Hello guys,

I would like to ask everyone their thoughts on Liquid, more
accurately: should there be a liquid 3, what would you change / add?

Getting the party started, here's my personal favorites:

* Make Liquid thread safe (currently it relies quite a bit in Class
Variables)
* Introduce a configuration class that holds the default behavior of a
given Liquid instance, further enhanced with runtime overridable
values
* Add the notion of plug n' play TemplateParser and PreProcessor
* Internationalization
* In line with the architecture used for tags, make filters more
modular and plug n' play friendly
* Clear and non ambiguous namespaces and class hierarchy. For example,
the current implementation of Document (the object returned by
Template.parse) extends Block, which in turn extends Tag. Semantically
this means that the whole Document is a tag, which is (in my opinion)
inaccurate. Furthermore, tags, filters, filesystems, etc, should have
their very own namespace
* Drop liquid as an ActiveView::TemplateHandler
* Migrate the tests to RSpec 2 (currently in beta)

These are my personal favorites for a 3rd major release of Liquid.
Where do you stand? What's your personal favorites?

Best regards,
DBA

Tobias Lütke

unread,
Aug 25, 2010, 10:21:31 AM8/25/10
to liquid-t...@googlegroups.com
I'll comment line by line.

On Wed, Aug 25, 2010 at 8:09 AM, DBA <diogo.borg...@gmail.com> wrote:
> Hello guys,
>
> I would like to ask everyone their thoughts on Liquid, more
> accurately: should there be a liquid 3, what would you change / add?
>
> Getting the party started, here's my personal favorites:

Good idea

>
> * Make Liquid thread safe (currently it relies quite a bit in Class
> Variables)

Liquid is thread save as long as you don't use a template between
threads. Originally I designed it fully thread safe but some
requirements came up with went against this, for example the need to
share assigned variables between layout and inner templates. I'm not
sure if this is worth addressing. Perhaps we can implement a proper
.dup method on the template so threads can quickly dup templates
before using them instead on relying on re-parsing.

> * Introduce a configuration class that holds the default behavior of a
> given Liquid instance, further enhanced with runtime overridable
> values

I dislike configurability of this kind. It serves no purpose other
then confuse users.

> * Add the notion of plug n' play TemplateParser and PreProcessor

We need a stronger parser but pluggable anything is almost always a bad idea.

> * Internationalization

Absolutely. All strings used by liquid should be overrideable on a per
render run.

> * In line with the architecture used for tags, make filters more
> modular and plug n' play friendly

again I dislike pluggable but I think we should look to radius and
change the way filters and tags are defined to use a nice DSL rather
then the current system.

> * Clear and non ambiguous namespaces and class hierarchy. For example,
> the current implementation of Document (the object returned by
> Template.parse) extends Block, which in turn extends Tag. Semantically
> this means that the whole Document is a tag, which is (in my opinion)
> inaccurate. Furthermore, tags, filters, filesystems, etc, should have
> their very own namespace

Hmm thanks for bringing this to my attention. I definitely agree that
a Document isn't a Tag. I think this can be addressed by renaming the
tag class to Fragment or something like this.

> * Drop liquid as an ActiveView::TemplateHandler

Yes.

> * Migrate the tests to RSpec 2 (currently in beta)

I massively dislike RSpec, It's a dumb idea.

> These are my personal favorites for a 3rd major release of Liquid.
> Where do you stand? What's your personal favorites?

A new parser. I wrote one in ragel recently but now determined that
Ragel is a poor fit for something like Liquid. I think a parser based
on string scanner would be the right thing to do. Mustache had a lot
of success with this. A new parser would allow us to:

* Report errors much more accurately
* Report line & character numbers of errors
* Remove preprocessor again.
* Improve render performance by an order of magnitude by resolving
variable lookups at compile time.

>
> Best regards,
> DBA
>
> --
> You received this message because you are subscribed to the Google Groups "Liquid Templates" group.
> To post to this group, send email to liquid-t...@googlegroups.com.
> To unsubscribe from this group, send email to liquid-templat...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/liquid-templates?hl=en.
>
>

Nick Zalabak

unread,
Aug 25, 2010, 11:23:08 AM8/25/10
to liquid-t...@googlegroups.com
To throw another idea into the mix is to add a variety of cache stores when reading liquid files (pre and/or post substitution) in the file system class. This is something that I've hand rolled for my current project by duck typing a custom implementation of the file system class and so far it nicely

I like internationalization, I've implemented something of a conventions based approach to finding liquids to their appropriately named intl. folder.

An ActionView liquid template renderer ( render :liquid => "foo.liquid" ) would awesome.

I would be more than happy to help implementing these features in a new version on liquid.



DBA

unread,
Aug 25, 2010, 12:40:37 PM8/25/10
to Liquid Templates
Hello guys.

I'll reply by major topic.

# plug n' play:

Perhaps I'll rephrase what I mean. It's effectively an organization
improvement.

Currently, when you look at tags, if you wish to add a tag you can
create a class and just go for it, or even use Tag.new. However, when
it comes to filters, the behavior is abruptly different.
StandardFilters are all cluttered in a single class and you cannot add
or remove single filters, like you can with tags (Template.tags.delete
'name').

With this in mind, what I'm suggesting is to use the same behavior.
Each filter should be its own entity within liquid that people can
enable or disable as they wish.


# parser and pre-processors

I agree that the fundamental issue (which now includes pre-processors)
is a need for a new parser. In that regard I totally agree with you.
However, even a new parser should be configurable by the user, not
imposed by liquid.

For instance, some people may prefer HAML like syntax (eg "= 'liquid'
| upcase" instead of "{{ 'liquid' | upcase }}". Having said that, I
believe the parser itself should be "configurable"


# configuration

In light of what I've mentioned for parser, I think would feel quite
natural if people could configure liquid's behavior. For instance:

Liquid.configure do |conf|
conf.locale 'en-US'
conf.parser :liquid
conf.tags :all
conf.filters :all
end


# testing

I actually hated rspec myself until about 2 months ago. Now I find
that the tests are just easier to read. I specially like the contex /
describe blocks, though pretty much the same can be achieved with
shoulda


# File Cache

I can see the improvements of caching the files. Though, for the sake
of memory consumption in large installations, I think it would need
some management mechanisms:
* which files are hot and need to be cached?
* which files are cold and can be dropped out?
* are we running under or above memory cap for liquid templates?

Having said that, I wonder if it wouldn't be simpler to add an
interface to stash the processed objects in memcached, redis, or
similar.. I'm still new to liquid and not familiar with enough liquid
use cases to make a good call on this issue.


Best regards,
DBA

DBA

unread,
Aug 25, 2010, 12:48:35 PM8/25/10
to Liquid Templates
On a side note: liquid is a vital component for a product I'm
developing, where it is used much like shopify does.

In that regard, I'm very interesting in liquid and available to
contribute for its development and maintenance over time.

Best regards,
DBA

Jacques Crocker

unread,
Oct 1, 2010, 3:04:23 PM10/1/10
to Liquid Templates
I updated Liquid to use RSpec. I think its a big improvement, and
makes Liquid easier to hack on. One great benefit is the documentation
output of the spec run: http://gist.github.com/606670

Fork is here: github.com/locomotivecms/liquid

I think Liquid could be an awesome Rails templating language. Just
look at the success of Django templates. http://docs.djangoproject.com/en/dev/topics/templates/

The locomotive fork has template inheritance fully implemented:
http://docs.djangoproject.com/en/dev/topics/templates/#id1

My end goal is all my Rails templates hosted on an alternate datastore
(mongodb for example). Where what is checked in is more like the
"Starter" templates, and anything can be overridden at runtime.

If you guys agree with this approach, I do think I can help make
Liquid3 a first class templating language for Rails.


On Aug 25, 7:21 am, Tobias Lütke <tobias.lue...@gmail.com> wrote:
> I'll comment line by line.
>

Diogo Almeida

unread,
Oct 6, 2010, 6:56:46 PM10/6/10
to liquid-t...@googlegroups.com
Hello!

Sorry for the late response.

1) Inheritance: Cool stuff. Need to take a deepr look into it.
2) As previously discussed, due to its origins and purpose of existence, I'm not entirely sure in if Liquid should ever have a role as a first class Rails templating engine. For such scenarios, where sandboxing is not the issue, ERB and HAML seem more adequate. Did I miss interpret your point?
3) Regarding RSpec, even though I fancy RSpec, tobi is not in favor of such migration. For that reason, and in favor of a unified Liquid Mainline, for now I think we should focus in a new parser, rather than RSPEC.
4) Liquid 3: Liquid needs a new parser, kinda in line with mustache as tobi pointed. That's something we need to tackle ASAP if we want liquid 3 to ever exist

Best regards,
DBA

Magnus Holm

unread,
Jan 17, 2011, 12:51:08 PM1/17/11
to liquid-t...@googlegroups.com
Hey folks,

It's been a while since I've played with Liquid so please correct me if there's something I've missed, but this is what I want (from a template engine implementator' point of view):

1. A specifiction of the syntax and semantics of Liquid
2. Don't allow custom syntax of new tags
3. Move filter-checking from runtime to compile time (this means the parser/compiler can simply raise an error if it sees an undefined filter and we can get rid of the Strainer-thing).

This would make me it far easier to implement Liquid and therefore easier to port Liquid to other languages (or merge with other engines). I'd love to write a single engine (or maybe framework is a better word) which supports both Mustache, Handlebars and Liquid. 

Dane Harrigan

unread,
Jan 25, 2011, 11:42:19 PM1/25/11
to Liquid Templates
After reading the thread about Liquid 3 it looks like the question of
"what you'd like to see in Liquid 3" is being primarily answered from
the implementation standpoint. I'm looking at from the usage point of
view. I've been using Liquid in a CMS I'm putting together and after a
certain point I wanted to make some improvements, to my workflow at
least, so I started working on the Liquify gem. This is not an attempt
to advertise a gem, the question is, "what I'd like to see in Liquid
3," these are some of my thoughts with code...

You can register tags and filters in a single place, but you have to
register drops elsewhere. I can understand why you might want to make
only specific drops available at times, but I haven't had that need so
I register all of my drops, tags and filters at the same time:

Liquify.setup do |config|
config.register_tag :tag_name, TagClass
config.register_filter FilterModule
config.register_drop :drop_name, DropClass
# or if processing has to happen
config.register_drop :drop_name, lambda
{ DropClass.with_stuff_happening }
end

The drop lambda's get called when the template renders. This allowed
me to keep my Liquid prep in one place.

When creating a tag, I always have to accept the context argument and
I have to parse my @markup. It doesn't feel natural. In Liquify I
reserved the "invoke" method. I have the Liquid::Tag#render method
call invoke, but before calling it, the arity of invoke it checked to
see whether or not the parsed markup should be passed in. The markup
gets parsed to an array/hash. 'a', 'b', 'c' gets parsed to ['a', 'b',
'c']. 'a', 'b', foo: 'bar', baz: 'cux' gets parsed into ['a', 'b',
{ 'foo' => 'bar', 'baz' => 'cux' }]. The markup parsing is definitely
opinionated, but its handy.

Lastly, liquid_methods works great, but I made one more enhancement to
it. I allow you to set a lambda which has the instance of your active
record object passed in:

class Foo < ActiveRecord::Base
liquify_method :foo, :bar, :baz => lambda { |f| "#{f.foo}
#{f.bar}" }
end

This allowed me to make additional liquid methods without having to
make extra methods on my object.

Looking at Liquid 3 from the eyes of a user, these are things that
would make it easier for me, so I've been making it happen. I'd love
to hear your thoughts on any of these approaches appearing in Liquid
3.


Ok, not quite done yet. On the topic of RSpec and test::unit/minitest.
I use RSpec by choice, I think it reads extremely well. By going with
a testing framework that comes stock with Ruby Liquid can keep going
with one less dependency, even if its a development dependency. I can
see pros/cons to both.


-Dane

did

unread,
Jan 28, 2011, 8:47:58 AM1/28/11
to Liquid Templates
Hey guys,

Very interesting discussion and I've to recognize that your
expectations are way way beyond mines.

Liquid as it is now is flexible enough to do what we want. And it
looks like we don't need the same things. For example, does everyone
need to pass a context during the parsing time ? Meaning, do we have
to implement it in Liquid 3 ? Not sure. It will make it more complex
for beginners to get into.

Actually, my only concern about liquid would be its speed comparable
to a snail (not) on steroids. But as Tobias mentions all over the
place, use caching. I'm not really against caching though but if I can
do without, I feel better. So basically, in my mind, Liquid 3 should
be like Liquid 2 but with a more powerful parser :-)

Having said that, I think I get Tobias's point of view on Liquid 3
(Tobias, correct me if I'm wrong). I mean Shopify is great product,
stable and the shops don't suffer from the Liquid slowness so there
are no benefits for their customers to enhance Liquid. Even though, as
a shopify shop owner, I'd like to have better CMS features (hey the
shopify team, I've got plenty of ideas about improving this section)
but that's another topic.

Did

John Maxwell

unread,
Jan 28, 2011, 10:09:55 AM1/28/11
to liquid-t...@googlegroups.com
Liquid is slow? I really really don't get that, and have changed to using Liquid over HAML/ERB because it is demonstrably SO much faster!

I keep all my liquid templates in Redis, ready parsed using Marshal.dump(Liquid::Template.parse(xxx)). It cuts the time spent rendering views of my application down by anywhere up to 80% compared to HAML/ERB. Instead of accessing them through view files, I call render :text => @liquidtemplatebit.render() in my controllers which seems to work a treat.

Just my £0.02

John

Diogo Almeida

unread,
Jan 28, 2011, 10:37:46 AM1/28/11
to liquid-t...@googlegroups.com
Hello guys,

I believe liquid 3 could:
  • Use a new parser, similar to Mustache;
  • Have a cleaner API;
  • Consolidation of the various Liquid branches, namely mainline, Locomotive and Gnomeslab;
  • A standardized way of adding new features

Currently there are 3 active liquid branches. And, as I mentioned before, I believe the easiest route to liquid 3 starts with the unification of these branches. Only after that we can effectively start working on a new Parser and API in a single codebase.

Liquid is a great gem that allows us, developers and product / applications creators, to empower our users with Template Changing functionality within a very secure sandbox and in a smarty like syntax, aligned designers know-how. Liquid 3 is a necessary evolution, namely in regards to parser. However I don't see it coming to life unless we get together to pull it off (reads: create a single codebase).

Best regards,
DBA
Reply all
Reply to author
Forward
0 new messages