/// Monday, October 31

Brail, the genesis

A Jason fellow left a comment about the simliarities of TemplateCodeBuilder to Ayende's Brail. Funny he should mention that. I have been thinking about creating an open-source project for quite some time. I initially wanted to create a .NET Web MVC framework but stumbled upon Castle. Why build yet another web framework?

Castle has multiple view engines. I found Brail intriguing because of Ayende's choice of language, Boo. I knew Ayende was a keen guy based on the ideas written on his blog, so Boo was worth a looksie. Wow!

One day I was coding and it hit me ... In one hand I had just discovered a great .NET language, Boo, built on an exensible compiler architecture. In my other hand I was creating a SQLite provider for CodeSmith. Why not create an open source code generation framework? Why not extend Boo to convert templates into code so you don't need CodeSmith or MyGeneration? Why not generalize the idea and transform any metadata into code? Why not indeed.

It comes as no surprise then that my first example is Brail like. It's funny how things come full circle.

/// Sunday, October 30

CodeInjection next steps

I'm close to releasing the CodeInjection library. The only issue I have left is how to force the debugger to step into the intermediate files InjectCode generates. I'll chat with the Boo masters on IRC and get some ideas.

So, what's next? I'll write yet another article on how to use this new facility to fill in your classes from an iBATIS.NET data mapping.

iBATIS.NET is a data access framework. If I had to categorize it, it's somewhere between Microsoft's Enterprise DAAB and NHibernate. Most enterprise projects I've been involved with forbid me or any developer from touching the database. (They eventually let me since I'm pretty good with T-SQL). In general, DBAs are responsible for creating stored procs and permissions. No direct SQL to the database. iBATIS is perfect for this since it can map any SQL including stored procedures to objects. It doesn't try to do what NHibernate does but it does map to objects which the DAAB doesn't. With code injection your code will always be in sync with your data mapping file. Of course, you could take it a step further and generate your data mapping file using AspTemplateCodeBuilder.

FYI: The ANTLR packaged with Boo generates Boo code. NICE! I found a couple of bugs and entered them into JIRA but they're minor. I used it to parse the ASP-like template files.

Boo as a configuration language

I wrote an article for CodeProject.com extolling the benefits of scripting (Boo, C#) over static XML, INI files for application configuration. I never submitted and now I can't find it! It explained how a script file can perform a precheck of the environment before starting the application. For example, the configuration file could check a database connection, pull down a WSDL to validate a web service connection, etc. Boo is perfect for this since an administrator can change a value in the Boo script and simply run it again with booi. The application uses the script file to configure itself without having to do any casts to strings, etc. Moreover, scripts can detect missing key values across different environments---development, test and production.

I'll write it up again. If you're wondering, it's Boo + dependency injection, a potent combination.

/// Saturday, October 29

Boo is mixin it up

What is a mixin? A mixin is an interface with implemented methods. When a class includes a mixin, the class implements the interface and includes, not inherits, all the mixin's attributes and methods. They become part of the class during compilation. Interestingly enough mixins don't need to implement an interface. The advantage of implementing an interface is obvious so that the class may be passed to methods requiring that interface.

Ayende's idea about using code injection to implement static mixins motivated me. How would you define a mixin? You could try this, but Boo wouldn't like it. It's not an interface:


interface IMath:
 def Add(a as int, b as int):
  return a + b

Here is what I've come up with. To create a mixin define the interface as usual, then define mixin attributes and methods in a separate file and inject them during compilation.

# IMath.boo - interface to our math mixin
interface IMath:
 def Add(a as int, b as int) as int:
  pass

# IMath.mxn - implementation of the interface with a bonus
[property(Result)]
_result as int

def Add(a as int, b as int) as int:
 _result = a + b
 return _result

The first file is self explanatory. The second is interesting in that it implements the IMath.Add() method and a Result accessor. To mix this in with a class use the InjectCode attribute using MixinCodeBuilder.


# english.boo
import MGutz.CodeInjector from "MGutz.CodeInjector"

[InjectCode(MixinCodeBuilder, "IMath.mxn")]
class English(IMath):
 def construtor():
  pass

 def Noun() as string:
  return "Boo"

When booc compiles english.boo, MixinCodeBuilder comes alive and parses the code in "IMath.mxn" and adds Add() and Result to English. Here is the test:


mixin = English() as IMath
print mixin.Add(2, 3)

o = English()
o.Add(6,6)
print o.Result

As you can see, English implements IMath as well as has a Result accessor. I like this approach as you have the option to implement the mixin methods by simply not injecting the mixin code. The downside is declaring the interface and injecting the code are two steps.

This wasn't that difficult to implement. To be honest the CodeInjector is probably less than 400 lines of code and that may be an exaggerated number. Boo just does so much. OK, I haven't really tested other scenarios but so far, so good!

/// Friday, October 28

Must-have free Win utilities

AutoHotKey: Program your keyboard to do anything. Use it to map or remap your entire keyboard. For example, I have Win+V start Visual Studio, Win+space to start a command window, PrtScrn to start Snagit. More powerful than any commercial keyboard utility, guaranteed.

Autoruns: These guys probably know more about Windows internals than Microsoft. This utility shows you *every* exe, dll that runs at startup with the option to prevent them.

CDX: A change directory utility for the command line. When you type cdx an Explorer dialog pops up to select your folder. Use the arrows key to select your folder. Right arrow to expand. Left arrow to contract. Hit enter. You don't need no stinkin' mouse and the focus remains on the command line. It's faster than Tab. The link is direct to the download since I don't read Japanese. Winrar will open the LZH file.

KeyNote: Jot your ideas down in a tree-type (outline) metaphor. Use it to store code snippets, URLs or whatever.

Regulator: A regular expression builder, tester focused on .NET regular expressions. This was featured on "Ten must have tools...". I don't mention the others in that article, you probably use or know of them.

Smart Paster: Grabs text from the clipboard and pastes it into Visual Studio as a StringBuilder, string, comment, etc. Saves you from having to escape newline, tabs, quotes, etc.

I think a generic taskbar applet that has the functionality of Smart Paster would be neat. This way it could be used in any editor, IDE. Hmmm ... maybe my first GUI-based Boo app. Of course it would have to be extensible so you could do things like convert to HTML.

Visual Studio 2005 Gotcha

I guess I'm old school in that I always partition my drives into an operating system drive (C:) and an applications/data drive (D:). My small form factor PC allows for a single drive. When I partitioned the drive, I figured 6 gigs would be enough for the Windows operating system.

Apparently not! Microsoft and other companies tend to install parts of its application on the C: drive even if you tell it to install in D:\program files. The .NET Framework for example will always install itself in the Windows directory. I finally finished downloading Visual Studio 2005 and tried to install it. Bam!

You cannot change the installation location for these products. These products have a dependency on a file already installed in another location, which prevents these products from being installed in a custom directory. The products you are trying to install are dependent on the following programs: * Microsoft .NET Framework 2.0 SDK - ENU

What? I installed the .NET 2.0 SDK on my D: drive earlier in the day. Further reading tells me I should first uninstall then reinstall the Framework to the drive where I want to install Visual Studio. Where do you think it is dummy?! VS needs 2.6 GB of space and my C: drive has 3.0 GB of free space. That doesn't leave Windows enough room to download and apply upgrades, etc. Been there, done that. Aaargh. I have an old version of Partition Magic, I hope it works on XP SP2. Otherwise, I'll have to run to the nearest software store to buy partitioning software. I bet this eats up one day. Visual Studio 2005 better be worth it!

/// Thursday, October 27

Boo as a template compiler

Lazy Style Code Fu master (ahem) me presents Boo the template compiler.

If you read "custom preprocessor idea for Boo" then now you'll see the start of one of the projects I had in mind. Thanks to the Boo newsgroup I discovered Boo has compiler attributes that have the behaviour I want. I started working on it yesterday and code generation works.

Say you want to generate classes for tables in your databases. First retrieve the database metadata. I represent the metadata returned in a Hash named model. model contains the tables for the database as well as the name and columns for each table.

# controller.boo
import test from "test"

model = {
    "tables" : [
        {   "name": "user",
            "columns": ["user_id", "username", "password"]
        },
        {   "name": "item",
            "columns": ["item_id", "name", "description"]
        }
    ]
}

f = View(model)
print f.RunTemplate()

Don't let the Hash scare you. If you plan to do any AJAX, get used to the JSON format. I much prefer it over XML. You would probably build stongly typed classes for the metadata. JSON is just a quick way to represent objects. Back on topic, staying within the MVC pattern, create a view for model.

# view.boo
import MGutz.CodeInjector from "MGutz.CodeInjector"

[InjectCode(TemplateCodeBuilder, "view.tpl")]
class View:
    [property(Model)]
    _model as Hash

    def constructor(model as Hash):
        _model = model

View doesn't do much but accept a model. The magic happens in the compiler. InjectCode is a special attribute instructing the Boo compiler, "invoke me when you compile this class." When the atribute is invoked, it instantiates TemplateCodeBuilder to process the contents of the view.tpl file. TemplateCodeBuilder converts the file into Boo code and it becomes the body for a RunTemplate() method. InjectCode then injects RunTemplate() into the class View.

Look at the view's template using the model.

# view.tpl - template for the view
<% for table as Hash in Model['tables']: %>
class <%= table['name'] %>:

    <% for column in table['columns']: %>
    [property(<%=column%>)]
    _<%=column%> as string

    <% end %>
<% end %>

It's ASP(.NET) syntax. Notice how Model is accessible here. You could access the instance variable _model just as well. Remember this template is injected as a function into View, it has access to private methods, private fields, ... like any member of the View. Also note the end keyword. This is an alternate Boo syntax when using it in markup scripts. end is a required keyword in your templates.

Compile this baby. view.boo + view.tpl merges into a single class into test.dll.

> booc -t:library -out:test.dll view.boo

Run the controller.

> booi controller.boo

class user:
        [property(user_id)]
        _user_id as string

        [property(username)]
        _username as string

        [property(password)]
        _password as string

class item:
        [property(item_id)]
        _item_id as string

        [property(name)]
        _name as string

        [property(description)]
        _description as string

Voila! Instant classes for your database. Remember, the template is compiled. Think of a template as a function in an abstract format. You now have a compiled class that executes your template without any run-time parsing, merging, etc. This is ideal not only for code generation but also for views in a web framework.

I'll finish up by saying Boo is such a wonderful language. It's what VB.NET should have been. Even down at the compiler pipeline level you just sense how solid Boo is.

If you're wondering what the generated code for View.RunTemplate() looks like.

def RunTemplate() as string:
        out = System.Text.StringBuilder()
         for table as Hash in Model['tables']:
out.Append("class ")
out.Append( table['name'] )
out.Append(":\r\n")

 for column in table['columns']:
out.Append("\t")
out.Append("[property(")
out.Append(column)
out.Append(")]\r\n")
out.Append("\t")
out.Append("_")
out.Append(column)
out.Append(" as string\r\n\r\n")

 end
 end
out.Append("\r\n\r\n")

        return out.ToString()
end
/// Tuesday, October 25

custom preprocessor idea for Boo

I remember reading the possibility of adding language directives to Boo. If they do, then I propose a feature which I have not seen in other compilers---the ability to invoke a custom preprocessor.

Imagine the possibilities. You could include an ORM XML mapping file, preprocess it to automatically generate accessors within the class. You could include a XAML file and bind events. There are so many more neat things you could do.

Here's an example applied to my yet to be released MVC framework. A view is comprised of a template and code-behind much like ASP.NET. What's the advantage? There is no run-time compilation, no parsing, no reflection, etc. The view and template merge and compile into a single type. I realize ASP.NET gets compiled as well but it's a separate framework, this becomes a first class feature of the language.

# MyTemplate.html - maintainted by a designer. Rows between <%=* %> and <%*%>
# are omitted when rendering. It's an aid for designers.
<html>
    <table>
        <%=* Cycle([EvenRow, OddRow], Model['Items']) %>
        <tr class='even'><td>even row omitted when compiled</td></tr>
        <tr class='odd'><td>odd row omitted when compiled</td></tr> 
        <tr class='even'><td>even row omitted when compiled</td></tr>
        <%*%>
    </table>
</html>

# MyView.boo - code-upfront (code-behind)
class MyView(ViewBase):
    def OddRow(s as string) as string:
        return "<tr class='odd'><td>${s}</td></tr>\n"

    def EvenRow(s as string) as string:
        return "<tr class='even'><td>${s}</td></tr>\n"
        
    #include "MyTemplate.html", TemplateProcessor

The line above means preprocess MyTemplate.html using a custom preprocessor TemplateProcessor. Here's the pseudocode:

#converts an html template into a boo snippet
class TemplateProcessor(Boo.IPreProcessor):
    def Process(filename as string) as string:
        // read the contents of the file
        // convert html template into code
        // return BuildOutput() code

After preprocessing the class contains the generated BuildOutput()

# class with generated function
class MyView(ViewBase):
    ... 
    
    // called by ViewBase.Render()
    def BuildOutput() as string:
        out = StringBuilder()
        out.Append("html\n\t<table>\n")
        Indent("\t\t")
        out.Append(Cycle([OddRow, EvenRow], Model['Items'])
        Dedent()
        out.Append("\t</table></html>")
        return out.ToString()

The view simply cycles between OddRow() and EvenRow() applying values from Items resulting in an HTML table with alternating row styles.

This page is powered by Blogger. Isn't yours?