HAML: RoR's new templating engine

I agree with everything Seth pointed out. Why not let any amount of (non-newline) whitespace denote a new block, rather than only two spaces?

I'd also like to add my voice to those who feel that adding support for Ruby blocks would be a good idea. If you also added some character, say '-', that denoted code that was executed but not used as output, then you could do something like:

- for foo in @foolist   %h1 foo.name   %p foo.text

I echo this.

Have started using HAML for a major project, as it is simply beautiful.

However, I'm not going to write a partial for every tiny loop: it would be madness.

Neither do I want to mess around with generating layout from a helper object. Isn't that what views are for ?

Although I understand that 'code in views' == bad, surely the equivalent of "take this collection of things (which were collected together somewhere else) and show each one like this" is more markup than code ?

I'm now in the curious position of using HAML for pretty much everything, and calling in an rhtml partial when I need to pump out a list. Hardly ideal...

Terry

Chris wrote:

Nex3 wrote:

I agree with everything Seth pointed out. Why not let any amount of (non-newline) whitespace denote a new block, rather than only two spaces?

I'd also like to add my voice to those who feel that adding support for Ruby blocks would be a good idea. If you also added some character, say '-', that denoted code that was executed but not used as output, then you could do something like:

- for foo in @foolist   %h1 foo.name   %p foo.text

I'm not against using the - to mean "eval but don't print anything". However, the problem is the way that its all parsed and executed. We might be able to work something out, but the deal is that each line is currently evaluated in-itself.

So this seems more like an implementation issue rather then there is no reason to allow it right? I really like your syntax but I think you will keep getting pushback until multi line iterations and if statements are allowed. I looked at the codebase and I don't think it would be too hard to add a little state to the parse loop to keep track of multi line statements and eval them accordingly.

I'm not sold on the idea that this is a good thing and the implementation would become much more complex.

However, I still haven't seen any arguements on why this is a Good Thing, beyond forces of habit, and that some rails helpers use it. Tradition isn't a good arguement.

What about <% cache do %> blocks? what about content_for :sidebar blocks? there are really a ton of useful situations where the blocks in a view are very important.

Couldn't you do some look ahead when parsing the template? You already are loading all the lines into memory before processing with this line:

template.split(/\n/).map do |line|

What about preprocessing the template to combine multi line statements starting with == into one line statements starting with = and with the compressed lines separated with ;

so this:

%body    #posts      == @posts.each do |post|      == link_to post.title, :action => 'foo', :id => post      == end

becomes this internally after preprocessing before parsing:

%body    #posts      = @posts.each do |post| ; link_to post.title, :action => 'foo', :id => post ; end

Some stupid code that does this preprocessing:

       buffer =        seen = false        last = false        template.each_with_index do |line, index|          if line.strip =~ /^==/            unless seen              buffer << line.sub(/==/,'=').chomp              last = index              seen = true            else              buffer[last] << ';'+line.sub('==', '').strip            end          else            seen = false            buffer << line          end        end

And then go into your normal parse loop now that the multi line statements are compressed to single line statements? I am sure there is a better way to do it but this seems feasible.

In the three fairly-complex projects I have done in HAML, besides breaking habit, I haven't really *needed* blocks. The closest I got was a pang of rememberance for how i'd do it in rhtml.

Maybe you haven't needed block because you weren't allowed to do them :wink: I think HAML is truly something very cool, I just think it won't get as much adoption as it should until you allow multi line statements period.

just my two cents here of course...

Cheers- -Ezra

Chris wrote:

OK, i have > 30 controllers, with hundreds of views. Can you imagine all the work it would requrie to create sub-views for all my control loops!? I use rails to be speedy and efficient.

It's a pity HAML is doing this, otherwise it could be a massively used templating system.

I enjoyed Hampton's presentation at RailsConf yesterday, and I've just read through the whole of this thread.

One thing that strikes me is that Rails has an asymmetry between the use of files for helpers (where you can put many helpers in one file), and the use of files for partials (where you have have one file per partial). I get the impression that in Chris's case this would lead to an unmanageable mass of tiny files.

Would it be possible for HAML partials to get away from the "one file per partial" constraint? It would be good to be able to use named template fragments, defined either in the file that is using them or in a fragment library file looked up by convention (or explicitly imported).

In programming, it's a good idea to factor out a new method wherever you can put a meaningful name to a bunch of lines in an existing method. You wouldn't dream of doing this if every method had to live in its own file. Shouldn't the same principles apply to templates?

regards

   Justin Forder

In programming, it's a good idea to factor out a new method wherever you can put a meaningful name to a bunch of lines in an existing method. You wouldn't dream of doing this if every method had to live in its own file. Shouldn't the same principles apply to templates?

Now _that_ is a smart thought !

Justin Forder wrote:

Would it be possible for HAML partials to get away from the "one file per partial" constraint? It would be good to be able to use named template fragments, defined either in the file that is using them or in a fragment library file looked up by convention (or explicitly imported).

This idea needs further exploration... I like it. The concept reminds me a bit of XSL templates: you would usually have many per file, but HAML would of course have a different mechanism for including the partials.

Here's an example XSL file if you've never seen one: http://www.brics.dk/~amoeller/XML/xslt-4.1.html

John Philip Green

HI, does this new template engine code work well within Dreamweaver? I have had very good success with RHTML code within DW.

Thanks,

-Conrad

I have been following this thread, though not too closely so I may have missed some of the following points.

1. My first impression is HAML is so "leading edge" that current editors don't have any support for it yet.

2. Although RHTML isn't "special" or "better" than ASP, JSP and the likes. However, besides good compatibility, vanilla HTML do not need further processing. In HAML just about every line needs to be transformed (HAML -> HTML or whatever). This beg the question of performance. Are there performance issues we should be concerned about?

3. HAML perhaps may be easily learned but I wonder how well this works in practice. It is another layer of abstraction web designers/authors will need to deal with. I am not sure how well HAML will be accepted in their world.

Long

Justin-

Now, *that's* along with my thinking.

Very soon we will indeed have multi-line statements. I'm going to make it clear that I think 99% of the loops in views are *crap* and are against HAML style.

However, I have wanted to be able to say this.

#links   = link_to "signup", |                :action => "go" |                :id => @id |

I think this looks ok and works great for hashs and making stuff look good by taking one line and making it go on multiple. That being said, you could do a loop, though, I really don't recommend it most places.

Now, on to what you said! Your point that we need *another* solution is exactly what I'm thinking about these days. The fact is that ApplicationHelpers are weird things. They seem to be where you put it when you don't have any other idea of where it should go.

DHH said something in his talk that really hit me. "When you fix one thing, you notice how broken something else is!" That's exactly my opinion. I think that haml's general restraints (Good Thing) just show the awkwardness of Helpers at the moment. Or whatever it is that we can think of that might be better.

One of the solutions I'm thinking of are Markaby fragments. I wish I could have a backup file of markaby fragments that I can call and use to describe the little bits that I'm now putting in helpers.

I think the views themselves are better now, now is time to turn our attention towards new, totally crazy, rebellious ideas for helpers and fragments.

Please email me directly with your thoughts.

hcatlin@gmail.com

Thanks, Hampton.

I have been following this thread, though not too closely so I may have missed some of the following points.

I'm happy to clarify them.

1. My first impression is HAML is so "leading edge" that current editors don't have any support for it yet.

yes, wysiwyg editors have absolutely zero support. However, every designer I know has dropped wysiwyg for a powerful toolkit of in-browser css editors and etc.

I'd welcome someone to write that, but its not something any of the designers I know using this require (or have asked for).

2. Although RHTML isn't "special" or "better" than ASP, JSP and the likes. However, besides good compatibility, vanilla HTML do not need further processing. In HAML just about every line needs to be transformed (HAML -> HTML or whatever). This beg the question of performance. Are there performance issues we should be concerned about?

It is slower. And you are right that it will always be a bit slower. However, DBs remain the bottleneck in producing a page, not rendering. While RHTML may be 2% of the render-time for a certain page, HAML is about 3-4% of the time. That's absolutely acceptable in my mind when DBs take up 85% and are still the actual slowdowns.

Caching isn't implemented yet, but it will be soon. (Patches welcome!)

3. HAML perhaps may be easily learned but I wonder how well this works in practice. It is another layer of abstraction web designers/authors will need to deal with. I am not sure how well HAML will be accepted in their world.

Every designer that I know that has used it "in the real world" won't work without it now. They refuse to use anything else. *Not* coder-designers, just designers.

HAML makes it much easier for a designer to parse in their mind what is going on because of the syntax and etc. If statements, loops, blocks, and hand-coded XHTML is probably the worst thing for a designer to have to deal with. They should only care about understanding the structure in the DOM.

We at unspace interactive have been using this successfully in all of our projects over the past 3 months. It wasn't introduced after it was created. We held it back to give it its paces and to see how it worked out. There is a reason that we flew across the world to introduce it at RailsConf Europe. Its because it works in a real-life situation and produces great code with very little overhead.

Our goal is to deliver value to our clients, and HAML helps us accomplish that.

It works. Period.

-hampton.

PS: Though, we are always improving!!!!! It isn't finished yet. But, now is the world's chance to make improvements and to make it kick even more ass than we could do internally.

I'm going to have to agree on the designer issue. If your designer is using DreamWeaver or some other WYSIWYG program, they won't like HAML. At least at first. HAML is more like the underlying document structure. Not every design requires knowledge of the document structure, but most good designs are deliberate and are mindful of the document structure. If you design is not in this category, rhtml still works fine.

One thing that would really help me (and I believe others) understand the "it works" part of this equation is a non-trivial example of one action that really does something interesting. Something that really exercises HAML so we can learn by example.

This might include a form so we can understand why form_for blocks are not as interesting in the context of HAML. Additionally, please consider Ezra's comments about joining block statements because I know there are many instances where I do things like:

<% content_for :sidebar %> some arbitrary stuff, optionally drawn from instance variables <% end %>

or even more frequently:

<% content_for :title %>

Thanks for opening this up to the rest of the Rails world.

Hampton wrote:

Speaking to the implementation issues of using loops, I've submitted a patch that allows the following: - for page in @pages   %h1= page.name   .page     = page.text - end This works for all types of blocks. It should be possible to eliminate the need to manually type "end" as well. So it's not a problem to implement loops and blocks in HAML... it's just an issue of whether or not we want them.

Personally, I feel that loops and especially if statements are neccessary for the language. There are certainly many times when they're inappropriate, but there are also many times when they're legitimately useful. In addition, they're an integral part of Ruby; various methods built into the language and into Rails rely upon blocks, the ability to key off a boolean, and the like. HAML won't be able to use any of this if it doesn't support blocks.

And the patch is ... where?

Nex3 wrote:

@s.ross: Here: http://dev.hamptoncatlin.com/haml/ticket/16

I would add that one of the most Rails-esque things to do is just get something working and then polish it up later. TDD encourages this too. Here's an example from scaffold:

<% for column in Catalog.content_columns %> <p>   <%= column.human_name %>: <%=h @catalog.send(column.name) %> </p> <% end %>

<%= link_to 'Edit', :action => 'edit', :id => @catalog %> | <%= link_to 'Back', :action => 'list' %>

Without knowing anything about the underlying model, this view uses loops to iterate over the members of the content_columns collection twice. Yeah, the problem can be solved other ways. It probably *will* be solved a different way in the final implementation. But somethings just getting the CRUD to work is enough to see whether you're headed in the right direction.

Would this be sooooo evil to include in HAML?

--steve

Joe Ruby MUDCRAP-CE wrote:

I feel like the suggestions for how to handle multi-line blocks here are turning HAML into an ugly beast, should they come to fruition. It seems to me that there are probably ways to figure out when a multi-line statement terminates without any explicit help. For starters, if = is encountered, but no special symbols for subsequent lines, couldn't you assume the expression continues until the next special symbol is encountered?

For what it's worth, I can tell you right now that I'd pretty much drop HAML like a hot potato if it turned into something that required me to do == or | for every line of a block. That seems very far off the mark for what HAML promised out of the gates.

Don't worry, my patch deals with this. All you have to do for a block is:

- block_magic do |param|   = param.stuff   %p= param.magic

No closing tag or repetitive characters needed.

I applied this patch and as I noted in Trac, it causes certain breakage in my code. Maybe I did something wrong...

(eval):3:in `template_eval': compile error (eval):3: parse error, unexpected '(', expecting $ $HAML_instance << ""( "fine" * 3).to_s << "\n"                      ^ Extracted source (around line #0):

1: = "fine" * 3

Here's the template that breaks (expected result: finefinefine):

= "fine" * 3

And one that works around the above error:

%p= "fine" * 3

Nex3 wrote:

I am developing a Rails site and am gearing for deployment. The one last bit I want to do (and need help with) is to make the site more professional looking.

1. I need a good stylesheet color scheme for font, div borders and background.

2. I am somewhat a minimalist. I only need a handful of graphic icons and maybe a site logo.

3. The overall site layout is done and set. I may need help with layout for specific areas within a page.

Work will be off-site. I don't think it will require a lot of work (I could be wrong) but if you are interested in helping, send me a note to

long755[@]rogers[dot]com.

In the message, describe your background and current work. Please include links to live sites that you've designed or created graphics for. Note, resumes will NOT be read.

I want to thank you all for your interest, but only successful candidates will be contacted for round 2.

Cheers,

Long PS: If you know of a good designer please forward this message.

Checking back in.. I lost steam with HAML. Going back to the few templates I initially converted, I'm not sure I like it as much. I do want to keep an eye on it, though.

Hampton, you commented on DBs being the bottleneck, not rendering, but from what I've heard (including from members of Rails core), rendering has actually been one of the most notorious performance monkeys on our collective back for most of Rails life thus far.

This is just what I've heard, and I'd be interested for more of your take on this.