by justin
29. December 2009 22:54
via @HamletDRC
Ever since I started playing around with Boo this is exactly how I feel about declaring types for my variables…
C#
IFoo foo = (IFoo)Fetch(arg);
Boo
foo = Fetch(arg) as IFoo
IFoo only ever needs to be written once on any given line. And if Fetch returned IFoo it wouldn’t need to be written at all. Being explicit is great and all, but being redundant is absolutely not.
by justin
18. December 2009 14:31
The book DSLs in Boo: Domain-Specific Languages in .NET written by Oren Eini writing as Ayende Rahien has finally shipped. The final version is available online at Manning Press and I highly recommend it.
I was one of the technical reviewers so I have already read this book and I can tell you first hand it’s definitely one for your book shelf. The first few chapters describe the generalities of DSLs and Boo then the subsequent chapters describe all of the details you might need to know to implement an internal DSL in your application.
If you’ve been wondering about the whole DSL thing, this book would be a good gateway to the world. It’ll stretch your brain and certainly expose you to some new ideas. In addition the author makes a good case for some practical business applications and introduces a new addition to the open source scene: Rhino DSL.
I also got an honorable mention in the acknowledgments section of the book and a special quote on the Manning Press web site that’s pretty cool! Check out it out!
by justin
8. July 2009 03:55
This is essentially a redo of an earlier blog post of mine on how to create the illusion of a strongly typed xml in Boo using Duck Typing, except this time we’re using the dynamic keyword in C#.
Here is an example of how it might look to use such a thing.
dynamic builder = new XmlBuilder();
builder.Main.One = "Hello";
builder.Main.Two = "World";
Console.WriteLine(builder.ToString());
Console.WriteLine(
"{0} {1}!",
builder.Main.One,
builder.Main.Two);
builder = new XmlBuilder();
builder.Main["One"] = "Hello";
builder.Main["Two"] = "World";
Console.WriteLine(builder.ToString());
Console.WriteLine(
"{0} {1}!",
builder.Main["One"],
builder.Main["Two"]);
XmlBuilder is a class I created myself, it inherits from DynamicObject and it intercepts TryGetMember, TrySetMember, TryGetIndex and TrySetIndex in order to allow you to navigate an internal XmlDocument object. Here is the output when the above is run.
|
<Main><One>Hello</One><Two>World</Two></Main>
Hello World!
<Main One="Hello" Two="World" />
Hello World!
|
Notice the use of properties corresponds to drilling into elements and the use of indexers corresponds to drilling into Attributes. This is just a proof of concept but you could see how this sort of thing would be useful.
Here is the complete XmlBuilder class that makes it all happen.
public class XmlBuilder : DynamicObject
{
private Func<string, XmlElement> createElement;
private Func<string, XmlAttribute> createAttribute;
private XmlNode node;
public XmlBuilder()
{
this.node = new XmlDocument();
this.createElement = s => ((XmlDocument)this.node).CreateElement(s);
this.createAttribute = s => ((XmlDocument)this.node).CreateAttribute(s);
}
private XmlBuilder(
XmlNode node,
Func<string, XmlElement> createElement,
Func<string, XmlAttribute> createAttribute)
{
this.node = node;
this.createElement = createElement;
this.createAttribute = createAttribute;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
XmlNode found = this.node[binder.Name];
if (found == null)
{
found = this.createElement(binder.Name);
this.node.AppendChild(found);
}
result = new XmlBuilder(found, this.createElement, this.createAttribute);
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
XmlNode found = this.node[binder.Name];
if (found == null)
{
found = this.createElement(binder.Name);
this.node.AppendChild(found);
}
found.InnerText = value.ToString();
return true;
}
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
{
if (indexes.Length != 1)
{
throw new InvalidOperationException("You may only specify a single index.");
}
XmlNode found = null;
if (indexes[0] is string)
{
string name = (string)indexes[0];
found = this.node.Attributes[name];
if (found == null)
{
found = this.createElement(name);
this.node.AppendChild(found);
}
}
else if (indexes[0] is int)
{
int index = (int)indexes[0];
found = this.node.Attributes[index];
}
if (found != null)
{
result = new XmlBuilder(found, this.createElement, this.createAttribute);
return true;
}
else
{
result = null;
return false;
}
}
public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
{
if (indexes.Length != 1)
{
throw new InvalidOperationException("You may only specify a single index.");
}
XmlAttribute found = null;
if (indexes[0] is string)
{
string name = (string)indexes[0];
found = this.node.Attributes[name];
if (found == null)
{
found = this.createAttribute(name);
this.node.Attributes.Append(found);
}
}
else if (indexes[0] is int)
{
int index = (int)indexes[0];
found = this.node.Attributes[index];
}
if (found != null)
{
found.InnerText = value.ToString();
return true;
}
else
{
return false;
}
}
public override string ToString()
{
return this.node.InnerXml;
}
}