Saturday, April 09, 2005

Spyce + Tiles = ?

Tonight I added Tiles-like functionality to the Spyce trunk.

Now, this doesn't mean I cloned Tiles in Spyce. I took the usual Spyce approach of adding functionality found in the JSP world without adding all the complexity. (Actually, in this case it's actually more influenced by the OpenACS master and slave tags, but how many people would that mean anything to? :)

Specifically I added a way to create consistent site layout templates in the reverse-include style familiar to users of all modern web frameworks. (No, ASP.NET isn't modern by this definition. But ASP.NET 2.0 will be. They call it "Master pages," and googling for that is an excellent way to find a lot of people talking about how this is the best thing since sliced bread. This entry is long enough without me reiterating the reasons why this is a Good Thing.)

Instead of including header and footer in your content page, your content page declares that it belongs to a parent page, which defines all your common markup and a placeholder for the child. Simple example:

child

<spy:parent title="child title" />

Child content

parent

<html>
  <head>
    <title>[[= child['title'] ]]</title>
  </head>

  <body>[[= child['_body'] ]]</body>
</html>
which results in the final html of
<html>
  <head>
    <title>child title</title>
  </head>

  <body>Child content</body>
</html>

This is both recursive and dynamic.

Recursive, in that one parent template can itself be the child of another. This is useful wherever you have shared content or navigation on a group of pages; you can make them children of parent1 which is a child of your master parent, so site-wide changes still only need to be made in one place, and changes affecting only this group are also only made in one place.

Dynamic, in that all the arguments to spy:parent are evaluated at runtime, even the src argument. Here's an example that doesn't do much except demonstrate this:

[[  import os
  cwd = os.getcwd()
  s = '/parenttable.spy'
]]

<spy:parent src="=s" foo="=cwd" />
This results in the template located at /parenttable.spy being used instead of the default, and an argument named foo being passed with the result of the getcwd evaluation. (Changing which parent template to use at runtime is primarily useful for localizing different languages; passing other parameters that are evaluated at runtime is something you will use frequently even if you only care about English.)

In my opinion it's a phenomenal example of how robust Rimon's Spyce framework is that the diff for this changeset is only about 70 lines. Spyce is one of those rare projects that's a real pleasure to work on because the original author found just the right balance between thinking for future extensibility and overengineering. Tough line to walk, and Spyce does it well.

6 comments:

Jason Bunting said...

Jonathan,

ASP.NET 1.1 and 1.0 support "master pages" - it's just that for 2.0, Microsoft has provided better IDE support via the next version of Visual Studio (the designer will show the page elements in a fancier way than do the previous versions) and it is now more formalized, with a specific abstraction for people who are unable to handle the OO concepts that would allow them to do the same with the current version. I have used templates for a while in ASP.NET, just as many other users have. It is unfortunate but true that there are simply a lot of 'developers' using Microsoft products that don't think something is possible unless MS provides it to them on a silver platter and give it a nice marketing term. Sad, but true. Object/Relational mapping is a perfect example of this. I currently know quite a few people fighting the idea of it, but I bet as soon as Microsoft comes out with their "official" version of an O/RM tool, they will jump on the bandwagon.

Jonathan Ellis said...

Interesting -- I couldn't find anything on MSDN about master pages in ASP.NET 1, but I could have missed something. I did find someone who rolled his own: http://www.codeproject.com/aspnet/effectivempages.asp

Jason Bunting said...

That is exactly what I mean - as I said, using basic OO principles, you can do it yourself in many ways in 1.0 and 1.1, it's just that MS doesn't provide you with a fancy name for it, or IDE support.

There are many ways of implementing it in those older versions, I use their PlaceHolder controls and inheritance (a base page class) to create my own templates, and it works fine (the specific technique was one I learned from Dino Esposito's ASP.NET book). I guess my main point is that we don't have to wait until MS puts a pretty name on something to get it to work, as long as we know what we are doing with regards to OO and such; since ASP.NET supports OO constructs, I can make my own abstractions.

Anyway, I think you get my point. :P

Kevin Dangoor said...

Having come from the Java world not long ago, it's worth mentioning that a number of folks have been disenchanted by Tiles and have switched to SiteMesh.

John Reese said...

This is pretty neat. I was pretty much hoping I could use this right away. How frequence are spyce releases? How safe and easy is it to just use the SVN code? I ran into some make problems... a missing .eg file and a problem with include files in the doc directory.

Uh, anyway.

Jonathan Ellis said...

SVN trunk is reasonably safe if you keep an eye on the changelog. :)

I should have a beta out this week, and things will be even more stable then. I'll have a look at the makefile, but you don't need it if you co from svn -- just run spyceCmd.py -l and you're off.