Haml and Sass Extension

Added both the above requests.

Plus the output view file now defaults to a .php file (which of course it is :) )

The extension of the output view file is set from an additional property -

$viewFileExtension - that can be set in the configuration; the default is .php

To control were the output view file is written use the $useRuntimePath path property

defined in CViewRenderer - set it in the configuration along with other renderer

properties.

The default is true; output files are written to protected.runtime.views.nnnnnnn

If set to false output files are written to the source file directory.

R0019 is available for download.

And yes, very interested in the syntax highlighting.

Attached the files needed for syntax highlighting in Emacs. The zip file contains php-mode.el and haml-mode.el. Copy these to your emacs/lisp/progmodes directory.

Add the line


(require 'haml-mode)

to your .emacs file (This file may need to be created).

R0020 is available. This fixes a Sass issue (Issue 13)

Thanks

Thanks for this extensions, it works great so far.

I encountered a small situation i cannot solve. Is it possible to change the haml behavior depending an a variable? Example:

i want to convert this php view code to haml:




<div class="waypointarea">

<span class="waypoint 

<?php echo ($point == 1) ? 'active' : ''; ?>"> One </span>

<span class="waypoint 

<?php echo ($point == 2) ? 'active' : ''; ?>"> Two </span>

</div> <!-- waypointarea>



Now, this goes like this:




.waypointarea

  %span.waypoint

    One

  %span.waypoint

    Two



but HOW is it possible to give the span.waypoint the class active only where $point is set… i know there is a way, but how to do this with haml?

thanks

Hi thyseus,

Glad you like the extension.

The way to do what you want is with code interpolation - the #{<PHP code>} construct. Code interpolation isn’t supported (yet) in the class and id shortcuts, so you need to declare the class as an attribute. I will investigate to see if I can get interpolation working in the shortcuts. If I can I’ll put in the next release.

To take your example verbatim, here is the Haml code (I’ve put the text on the same line as it’s short, but can be on the next line and indented)




-# setup

- $point = 2

	

.waypointarea

  %span(class="waypoint #{($point == 1 ? 'active' : '')}") One

  %span(class="waypoint #{($point == 2 ? 'active' : '')}") Two



This parses to:




<?php $point = 2; ?>

<div class="waypointarea">

  <span class="waypoint <?php echo ($point == 1 ? 'active' : ''); ?>">

    One

  </span>

  <span class="waypoint <?php echo ($point == 2 ? 'active' : ''); ?>">

    Two

  </span>

</div>



and the HTML is:




<div class="waypointarea">

  <span class="waypoint ">

    One

  </span>

  <span class="waypoint active">

    Two

  </span>

</div>



Another method (depending on what you are passing to your view) is to use a loop; for example:

Haml




-# setup

- $points = array('One', 'Two', 'Three')

- $point = 2


.waypointarea

  - foreach ($points as $p => $pointText)

    %span(class="waypoint #{($point == ++$p ? 'active' : '')}")= $pointText



parsed




<?php $points = array('One', 'Two', 'Three'); ?>

<?php $point = 2; ?>

<div class="waypointarea">

  <?php foreach ($points as $p => $pointText) { ?>

    <span class="waypoint <?php echo ($point == ++$p ? 'active' : ''); ?>">

      <?php echo $pointText; ?>

    </span>

  <?php }  ?>

</div>



HTML




<div class="waypointarea">

  <span class="waypoint ">

    One

  </span>

  <span class="waypoint active">

    Two

  </span>

  <span class="waypoint ">

    Three

  </span>

</div>



And it works !! ;D

Haml




-# setup

- $point = 2

- $points = array('One', 'Two', 'Three')

	

.waypointarea

  - foreach ($points as $p => $pointText)

    %span.waypoint.#{($point == ++$p ? 'active' : '')}##{"point$p"}= $pointText



parses to




<?php $point = 2; ?>

<?php $points = array('One', 'Two', 'Three'); ?>

<div class="waypointarea">

  <?php foreach ($points as $p => $pointText) { ?>

    <span class="waypoint <?php echo ($point == ++$p ? 'active' : ''); ?>" id="<?php echo "point$p"; ?>">

      <?php echo $pointText; ?>

    </span>

  <?php }  ?>

</div>



and renders the HTML as




<div class="waypointarea">

  <span class="waypoint " id="point1">

    One

  </span>

  <span class="waypoint active" id="point2">

    Two

  </span>

  <span class="waypoint " id="point3">

    Three

  </span>

</div>



And of course




-# setup

- $point = 2

- $points = array('One', 'Two', 'Three')


.waypointarea

  - foreach ($points as $p => $pointText)

    .waypoint.#{($point == ++$p ? 'active' : '')}##{"point$p"} = $pointText



will become:




<div class="waypointarea">

  <div class="waypoint " id="point1">

    One

  </div>

  <div class="waypoint active" id="point2">

    Two

  </div>

  <div class="waypoint " id="point3">

    Three

  </div>

</div>



The update is in SVN and I’ll make another release of the extension by the end of this week.

Thanks for the inspiration.

Thanks Chris. I know I’ll need this too.

Chris, you might also want to include all this in the documentation. I would also suggest going through the Haml doc and at least rewriting the ones that mention Ruby. For example, how would {} attributes work, or attribute methods, Object Reference: []

Question: How do I create an empty textarea. I had to resort to plain HTML.


	//%textarea(rows="6" cols="80" name="body" id="body")

	<textarea class="resizable" rows="6" cols="80" name="body" id="body"></textarea>



I’d kind of hoped I could get away with the Haml and Sass documentation ;), but you’re probably right.

Ruby style attributes work:


%a{:href => 'http://example.com', :title => 'An example'} text

is the equivalent of


%a(href="http://example.com" title="Another example") text

both becoming (actual rendering dependant on the renderer being used)


<a href="http://example.com" title="Another example">text</a>

and so do Object references - though use the latest SVN version of HamlParser (there was an issue with class and id having a leading space in earlier versions)


%p[$object, prefix] Text

will become ($object instanceof MyObject, $object->id == 23)


<p class="prefix_my_object" id="prefix_my_object_23">Text</p>

For me the following works




%form

  %textarea(rows="6" cols="80" name="body" id="body")

-# Doesn't have to be in a form to work

%textarea(rows="6" cols="80" name="body" id="body1")

-# Using .class#id and attributes works fine

%textarea.class#body2(rows="6" cols="80" name="body")



producing




<form>

  <textarea rows="6" cols="80" name="body" id="body">

  </textarea>

</form>

<textarea rows="6" cols="80" name="body" id="body1">

</textarea>

<textarea rows="6" cols="80" name="body" id="body2" class="class">

</textarea>



Thanks for clarifying the docs.

The problem with the textarea I was talking about shows up in your examples too (the spaces that get included within the textarea).

I’d also tried


%form

  %textarea(rows="6" cols="80" name="body" id="body")><



but that hadn’t worked either.

I’ll check that out. The whitespace removal should work I think.

Big thanks! Both your variants work like a charm.

Are you the only developer of Phamlp and why did you choose the yii framework as an ‘framework implementation’ example? PhamlP being framework-independent…

I am just going to switch all my view templates to haml. Really like it. Unfortunately the html2haml script contributed by the haml ruby gem breaks some -> to ?> in many cases… but that’s ok since there aren’t man views yet to convince :)

Keep up the good work!

Does now.


%form

  %textarea(rows="6" cols="80" name="body" id="body")><

does what it should do and produces


<form><textarea rows="6" cols="80" name="body" id="body"></textarea></form>

The fix is in SVN.

Yes, just me.

Why Yii as the first framework example? Because I’ve been using Yii for a while and it’s the best framework I’ve used. There is now a CakePHP wrapper and someone is working on a Kohana wrapper (am I allowed to mention those here? :) ).

Glad you like it. Personally I would not go back to plain old PHP/HTML templates or CSS; for me the claims Haml and Sass make about readability and manageability are true.

This does indeed make the templates more readable.

I don’t know if this is a bug or a feature but consider it an enhancement request anyway.

When we are within a filter block (php, plain or something else), any extra indentation should not throw an exception. I keep getting errors like the following in my php and javascript filters.


Illegal indentation level (4); indentation level can only increase by one.

Feature sounds much better ;)

Fixed in SVN

Any plans on upgrading to Haml/Sass version 3? The version 3 RC1 is already out.

Short answer is "Yes".

I’ve been tracking the Development of V3 and have implemented the new SassScript functions in my dev environment. The next step is to implement the parser for the new .scss syntax and it should be good to go. I’ll try to make some time to do this, but no promises as to when. Would you be OK to test some early code and report the bugs - of which there will be many I’m sure :D

Very good Work Yeti, we are planning to use this template engine for our next large web project.

There are a bunch of good php templates out there, but most of them downgrade the performance considerably, do you have any benchmark or performance numbers for this template engine? I mean: phaml vs php.

Another question in relation with this, do you support the ugly haml mode?

http://www.shaldybin…erformance.html

we would be pleased if you could include some benchmark numbers here or in the project wiki.

thanks in advance,

alex

EDIT: Thinking about it a bit more, I guess it precompiles the haml code to php, am I right?

But then, why there are some benchmarks test for haml 2.2 from the owner?

http://nex-3.com/posts/87-haml-benchmark-numbers-for-2-2

What is the real workflow? I mean, who parse, who render, and when?

Another question: does it handle the cache system in anyway? what is the best way to declare those fragment or page cache?

I’m a bit confused, so sorry and thanks again,

Alex

Hi Alex,

Firstly, I am very pleased to hear the extension is getting used in a large project and I’d like to hear how that goes.

As you are asking on the Yii forums I am assuming you are using Yii, so my answers are based on this. Your main concern seems to be performance. The short answer is:

Unless the PHP view file does not exist or is out of date there is no performance hit.

Now the long answer :)

There’s a few points here:

  • I don’t think of Haml as a templating engine; it does not do any processing in the same way that, for example, Smarty does. Haml is just a different (better :) ) way of writing the template, but it ends up as the same thing in that …

  • The Haml parser simply transforms Haml to PHP.

  • Haml does not introduce any performance hit as it is a PHP file that is rendered. The exception is if either the output PHP view file does not exist or the corresponding Haml file is newer, i.e. has been modified; then the Haml file is parsed.

Yes. This is the default rendering.

The performance improvement is not in the parsing of the Haml file, but in reducing the size of the page by removing as much whitespace as it can.

Note that all in rendering modes, including Ugly, inserted markup (from a widget for example) is sent as is.

Benchmark figures are not really relevant - you answered that one below :)

That is exactly what happens.

Why the benchmark figures you mention? Don’t know, perhaps Ruby and or Rails does things differently, but there is one comment that is very relevant: “Much more time can be saved by caching intelligently”.

Because Yii caches the output PHP view file the hit from Haml is one time only other than to decide whether to parse the Haml file or not (very quick).

This is the key as to why there is no real performance hit using Haml.

The Haml file is parsed if the output PHP view file does not exist or is older than the Haml file.

In the extension; the Haml class extends CViewRenderer; this checks to see if the Haml file needs parsing (the output PHP view file does not exist or is older) and calls the HamlParser if so.

The output PHP view file is rendered by Yii in the normal way.

Yii handles the caching.

Your only decision about caching is whether the output PHP view file goes; into Yii’s runtime directory (the default) or into the same directory as the Haml file (declare useRuntimePath=>false in your config for the extension; $useRuntimePath is defined in CViewRenderer). There is no performance difference.

As for page fragments - or anything else for that matter; use them just as you would in a PHP template ('coz that’s what you end up with). The Haml parser does not do anything special here, it just turns Haml into PHP, and anything you can do in PHP can be represented in Haml.

Here’s a Haml snippet to list blog posts:




%h1 Posts

- $this->widget('CLinkPager', compact('pages'))

.hfeed

  - foreach ($posts as $index=>$post)

    - $this->renderPartial('_show', compact('post', 'index', 'tags'))



Here you can see the CLinkPager widget is used to create the paging for the list and a call to CController::renderPartial() to render individual posts.

The partial views can be Haml or PHP files. If Haml they will be parsed the first time they are used, after which the output PHP view file will be rendered.

This is what the PHP output looks like (nested rendering) and it is this that is rendered by Yii.




<h1>

  <?php echo Posts; ?>

</h1>

<?php $this->widget('CLinkPager', compact('pages')); ?>

<div class="hfeed">

  <?php foreach ($posts as $index=>$post) { ?>

    <?php $this->renderPartial('_show', compact('post', 'index', 'tags')); ?>

  <?php }  ?>

</div>



To clarify and summarise:

  • The Haml Parser itself does not perform any caching or check whether the file it is given needs parsing or not; if it is called it will parse the file and return the PHP.

  • Yii handles all of the caching and decisions about what needs to be parsed and does all the rendering using the PHP files generated.

  • A Haml view file is only parsed if the output PHP view file either does not exist or is out of date; making the performance hit of parsing a one time only hit the first time a page is viewed or a partial used.

  • Partials, widgets, etc. etc. are used in exactly the same way as in a Yii PHP template.

I hope this helps.

Chris