By Popular Demand
The trunk version of NHaml now lets you use tabs or a variable indent size for indentation.
Now, no more arguing! You may go about your business.
P.S. 2 spaces is the best
NHaml 2.0 Beta
Simone rightly pointed out that requiring NHaml users to pull the source from SVN was just downright lazy. So I finally got around to putting together an actual release: 2.0 Beta.
With 2.0 we’ve made some substantial changes and improvements and also greatly simplified the API. Here’s a sneak peak of what’s coming:
- The biggest change by far has been the introduction of pluggable back-end compilers. NHaml templates can now be authored in one of four languages: C# 2, C# 3, Boo and IronRuby.
- We have greatly simplified our ASP.NET MVC View Engine which now inherits from the framework provided VirtualPathProviderViewEngine.
- NHaml 2.0 implements the Haml rules for convenient handling of HTML encoding.
- We made some major API usability improvements for stand-alone template rendering.
We still have a bunch of stuff on our backlog, some of which we’ll try and squeeze into 2.0 RTM - Hopefully sometime within the next month.
Enjoy and death to angle brackets!
NHaml Discussion Group
Using NHaml? Then head on over to nhaml-users.
Thanks to James Avery for setting it up.
NHaml 1.3 Released
Updated to support ASP.NET MVC Preview 5.
As always, get it here.
NHaml: Block Methods and RESTful Helpers
New in the trunk are a couple of cool features worth mentioning:
Block Methods
Block Methods are helper methods that accept a block of NHaml markup as a final argument.
An example (albeit contrived) to demonstrate:
- Html.Tag("div") () => Some regular NHaml markup here...
which results in:
<div> Some regular NHaml markup here... </div>
And the Tag method looks like this:
public void Tag(string name, Action yield) { _output.WriteLine("<" + name + ">"); yield(); _output.WriteLine("</" + name + ">"); }
As we can see, NHaml wraps up the nested block markup into a lambda (or anonymous method if targeting C# 2.0) and passes a delegate to the block as the last argument of the helper method. Invoking the delegate causes the markup within the block to be rendered. Notice too, we can write directly to the output stream: _output is an instance of NHaml’s IOutputWriter which is passed to our helper class when it’s instantiated. It has the following methods:
void WriteLine(string value); void Write(string value); void Indent(); void Outdent();
Output written using these methods will be correctly indented and we can also further control the indent level if we need to write nested output.
Worth mentioning is that we can also pass arguments to a block:
- Html.Tag("div", 21, 21) (i, j) => = "N was: " + (i + j)
which yields:
<div> N was: 42 </div>
And our helper method:
public void Tag<T1, T2>(string name, T1 t1, T2 t2, Action<T1, T2> yield) { _output.WriteLine("<" + name + ">"); yield(t1, t2); _output.WriteLine("</" + name + ">"); }
RESTful Helpers
Using a Block Method we can create a nice Rails-style helper that encapsulates building a form for a single model:
- var product = new Product { ProductName="Soap on a Rope" } - Html.Form(product) (f) => = f.Label(p => p.ProductName) = f.TextField(p => p.ProductName) %br = f.Label(p => p.UnitPrice) = f.TextField(p => p.UnitPrice) %p = Html.SubmitButton()
Results in:
<form action="/products.mvc/create" method="post"> <label for="Product.ProductName">Product Name</label> <input type="text" name="Product.ProductName" id="Product.ProductName" value="" /> <br /> <label for="Product.UnitPrice">Unit Price</label> <input type="text" name="Product.UnitPrice" id="Product.UnitPrice" value="" /> <p> <input type="submit" /> </p> </form>
A couple of things to note here:
- Our Form method takes a model object and uses the conventions of REST to generate the target action. To make this work our model needs to implement a small interface: IModel:
public interface IModel { int Id { get; } bool IsNew { get; } }
- Happily, we can bind our model attributes in a strongly typed fashion using Expressions.
Here’s what our Form method looks like:
public virtual void Form<TModel>(TModel model, Action<FormBuilder<TModel>> yield) where TModel : IModel { // this should be pluggable var formBuilder = new FormBuilder<TModel>(model, this, _outputWriter); formBuilder.OpenTag(FormMethod.Post, new RouteValueDictionary()); yield(formBuilder); formBuilder.CloseTag(); }
RESTful Link Helpers
Finally, we can apply RESTful conventions to link helpers too. Here are a few examples of some NHaml ActionLink helpers that work using REST conventions.
= Html.ActionLink<CategoriesController>() // /categories = Html.ActionLink<CategoriesController>(RestfulAction.New, "Add Category") // /categories/new = Html.ActionLink(category) // /categories/show/42 = Html.ActionLink(category, RestfulAction.Edit, "Edit Category") // /categories/edit/42 = Html.ActionLink(category, RestfulAction.Destroy, "Delete Category") // /categories/destroy/42
Thoughts/comments appreciated.


