Ruby, not that there’s anything wrong with that
A little while ago, I issued my Summer of Learning Challenge. As a suggestion, Ioke would be a great thing to learn for those that would like to learn something this summer, but aren’t sure what to learn. My project for the challenge is Ruby based, though I have a goal for the year to learn Ioke. As you can see from my Calendar About Nothing, which currently has a 15 day string of commits, I’ve been busily plugging away at both.
A few days back, Sam Aaron stopped by and commented on part 2 of this series, pointing out an error with my code.
Oops
Well, there were two errors there. First my spec stated that Bag should evaluate nil as an empty string, but code specified that it should be nil. Secondly, I had a problem with the way I had constructed my message chain so that my spec was evaluating nil should == nil. Of course this will always evaluate to true. I patched it up with the help of some advice in the comments. In the future I’ll need to remember to be more explicit in my intent by remembering to use parens when passing parameters to methods so that they aren’t interpreted as part of the message chain.
My initial solution, which I updated to the post, was to monkeypatch bag so that the cell nil returned an empty string. This solution didn’t really set well with me, but it passed the spec so I stuck with it. After some rest, I remembered reading about the keyword let.
The joy of let
I wasn’t familiar with the let method from the other languages I use, which are primarily Ruby and C#. But a little research showed that it provided an alternate solution to the specification. Opening up the specification for let, you will see that it accepts zero or more comma separated name value pairs and a block of code. It will then create a new temporary scope where the name is assigned the value and the code block is evaluated. At the end of the execution of the code block, the scope goes away and everything returns to normal.
Evaluator = Origin mimic
Evaluator initialize = method (
"Pass the property bag into the evaluator, this will be used for future evaluations.",
bag,
@bag = bag
)
Evaluator evaluate = macro (
"Takes the supplied message and evaluates it on the property bag. If nil is passed, it will return an empty string",
msg = call arguments first
let(bag nil, "",
msg evaluateOn(bag)
)
)This is an interesting alternative. It provides a way to temporarily modify an object while ensuring that your modifications don’t touch anything else once you are done.
Variations on a theme
One thing that I found particularly interesting is that all of the following variations seem to work
let(@bag nil, "",
msg evaluateOn(bag)
) let(bag nil, "",
msg evaluateOn(@bag)
) let(Bag nil, "",
msg evaluateOn(bag)
)I assume that the first two versions work because the sigil version of bag (@bag) simply points to the instance stored in the cell bag on the evaluator object. In other words, when using Evaluator as ground, from inside the object, bag and @bag have the same meaning. I’ll need to look into this to see if what I suspect is true.
I think that the third variation works because bag mimics Bag and so changes to Bag cascade to bag. If it is true that modifications to the parent object made after the mimic has been made will cascade to all mimics, then that is a very powerful and easily abused feature of Ioke. Again these are speculation on my part, and I will need to look into the truth of the matter.
Starting Templates
Once I had that figured out I started thinking of the next specification to tackle. I decided that if I’m going to be able to use Ioke, I’d need to figure out how to work with files. I feared that working with files might have been left out of the Ioke implementation as it is a very young language. As it turns out, I was dead wrong. The FileSystem object is implemented and quite easy to use.
Ioke and the FileSystem
I was quite happy to find a spec for the FileSystem so that I could get a feel for it. It turns out that there are a number of useful methods available and it appears to have support for Windows filesystems as well.
I decided to have my template object check to see if the string passed to it is a valid file. If it is, it will load it. If not, it will assume that the string passed to it is the template text. I made it this way for testing purposes more than anything, and may change it around if it causes issues. But it was simple to setup and it works.
Template = Origin mimic
Template load = method("load will load a template file.",
template,
if(FileSystem exists?(template),
Template text = FileSystem readFully(template),
Template text = template
)
)The Code
Current source snapshot is available on github tagged as start_ispec_3
Tags: ispec