Wednesday, December 05, 2007
Well this blog, the wiki and all the other associated services disappeared for most of today... thanks to the magic of NoAuth ... for no reason that anyone could explain to me beyond "it sometimes happens" - Orcon lost Authority over my business DSL connection, and it reverted back to Telecom/Xtra (New Zealands "legacy" telco)... and it took must of today for them to get the authority changed back, I don't think this was any fault of Orcons, but it still pissed me off no end.

So appologies to anyone wondering where my blog went, or any of the related services - I do have plans to migrate the blog to US servers in the not to distant future.  And big appologies to all the Architecture chat participants, sorry I couldn't get a reminder email out sooner.

On a different note - It did identify a need for me to maintain a secondary connection, with a static IP, that I can fall back to if required... thankfully the three concurrent projects that have been in UAT over the last couple of weeks have all wound down now - so it didn't have as much impact as it could of.

Though at least they wouldn't have been able to log bugs about servers being unavailable, Trac would've been unavailable too ;o)

... so any suggestions as to what would make an adequate fall back technology (something other then DSL, I've used wired country two-way-radio to the sky tower in the past which has worked well, but it doesn't give much "bang" for buck and has a high up-front cost last time I checked) ... I'm not too worried about 1 day downtime, but if this had been 3 or 4 days it would've been quite damaging for me, customers and those intangibles like reputation.


At any rate - thanks for the patience, and I'll see some of you at the Architecture Chat tomorrow.

Cheers,

 - Alex
posted @ Wednesday, December 05, 2007 10:34:04 AM (New Zealand Daylight Time, UTC+13:00)    Comments [1] | Trackback |
 Tuesday, July 03, 2007

So I've tidied up the source for the DSL from my last post a little... though my "test" was to represent a DSL similar to the one Ayende displayed in Brail - I haven't implemented any monorail view engine integration, there's little point I feel, I was more interested in being able to display a nested DSL-like syntax, and parse the necessary information out of it as required. 

You can grab it from SVN repository here (edit: I've now fix the PROPFIND proxy issue, so the link should work)

At any rate, probably the most interesting example is the one that takes this code:

var people = new List<Person>()
{
    new Person() { FirstName = "Alex", LastName = "Henderson"},
    new Person() { FirstName = "Joe", LastName = "Bloggs"}
};
 
var compDsl = new ComponentDsl();
 
compDsl.Add
(
    GridComponent => compDsl.Component
    (
        compDsl.Parameters
        (
            source => people
        ),
        header => compDsl.Section
        (
            tr => compDsl.As
            (
                th => compDsl.As
                (
                    compDsl.Text("Names")
                )
            )
        ),
        item => compDsl.Section
        (
            tr => compDsl.As
            (
                td => compDsl.As
                (
                    compDsl.Item<Person>(p => p.FirstName + " " + p.LastName)
                )
            )
        )
    )
);
 
var dsl = new StandardDsl();
 
dsl.Add
(
    html => dsl.As
    (
        body => compDsl
    )
);

And converts it to this xhtml...

<html>
  <body>
    <table>
      <tr>
        <th>Names</th>
      </tr>
      <tr>
        <td>Alex Henderson</td>
      </tr>
      <tr>
        <td>Joe Bloggs</td>
      </tr>
    </table>
  </body>
</html>

You can pretty quickly figure out what's going on by placing a breakpoint on the Execute() method of the StandardDsl class and tracing through all the calls - in essence all the nodes are emitted by calling the top-level Batch delegate which causes a recursive call down the "tree", with the information being emitted as a side-effect to an evaluation scope.

Though I used nodes - effectively creating a structure that's easier to parse, there's no reason why you couldn't make immediate calls to some kind of object, avoiding the need for a second round of parsing - the only trick is that you'd still need to use some kind of scoped stack to push/pop the names of the components because in a statement like this:

dsl.As
(
    GridComponent => dsl.Component
    (
      // etc. etc.
    )  
)


the call to dsl.Component needs some way to inspect the stack of names and pull "GridComponent" off the top.

I'd love to hear from anyone who could see a use for this kind of thing... it'd be nice to get a more realistic example... I'm struggling to think of anything practical myself.

[Edit: I Noticed the code formatting was pretty awful, so I've tidied it up a little... anyone got a good solution for copy/pasting code out of orcas (CopyAsHtml2005 doesn't appear to install under Orcas)]
 |  | 
posted @ Tuesday, July 03, 2007 11:01:26 AM (New Zealand Standard Time, UTC+12:00)    Comments [2] | Trackback |
 Friday, June 29, 2007

Following on from my posts on creating hashes (dictionaries) using lambdas (here, and here) and the little annotations "framework" I produced (here and here) which leverage the idea for annotating classes via extension methods... I've decided to turn my hand to creating a DSL using lambdas, on my continuing theme of C# 3.0 lambda abuse.

So first off... go have a look at Ayende's post DSL Support for brail ... that'll give you an idea of kinda what I'm trying to achieve.... so, here's an example of a simple DSL for building say a html table.

var dsl = new StandardDsl();

dsl.Add(
table => dsl.As(
  tr => dsl.As(
    td => dsl.Text(
"header1"
),
    td => dsl.Text(
"header2"
))));

Console
.WriteLine(DslToXml.ToXml(dsl));

which gives an output of:

<table><tr><td>header1</td><td>header2</td></tr></table>

Depending on taste you could lay it out differently, avoiding the mess of closing parentheses at the end of the Add call, say like:

var dsl = new StandardDsl();

dsl.Add
(
  table => dsl.As
  (
    tr => dsl.As
    (
      td => dsl.Text(
"header1"
),
      td => dsl.Text(
"header2"
)
    )
  )
);

Which is pretty easy on the eyes... now what about something a little more domain specific like the view component example Ayende gave for monorail... well here's my take on that, so say we have some people:

var people = new List<Person>()
{
 
new Person() { FirstName = "Alex", LastName = "Henderson"
},
 
new Person() { FirstName = "Joe", LastName = "Bloggs"
}
};

And we have a DSL specific to components...

var compDsl = new ComponentDsl();

compDsl.Add
(
  GridComponent => compDsl.As
  (
    compDsl.Component(source => people),
    header => compDsl.Section
    (
      tr => compDsl.As
      (
        th => compDsl.As
        (
          compDsl.Text(
"Names")
        )
      )
   
),
    item => compDsl.Section
    (
      tr => compDsl.As
      (
        td => compDsl.As
        (
          compDsl.Item<
Person>(p => p.FirstName + " "
+ p.LastName)
        )
      )
    )
  )
);

And now we could do this in-line with a bigger DSL for say a whole view, but we can also just reference them so I could do something like this to create the overall view:

var dsl = new StandardDsl();

dsl.Add
(
  html => dsl.As
  (
    body => compDsl
  )
);

Now once I've tidied the code up a bit I'll probably put it up for people to have a play with - I don't necessarily consider a "good idea" - but it's cute.  However for now let's have a quick look at how I'm doing it...

So to start with we have a delegate called "Batch" with the signature below - batch probably isn't the right name for this, I'm not really sure it matters all that much.

public delegate Batch[] Batch(Batch batch);

Batch takes a Batch and returns an array of Batch ;o) and to match that we then have say the "As" method on the DSL:

public Batch[] As(params Batch[] batches)
{
  Batch asBatch = new Batch(delegate(Batch
ignore)
  {
    ExecuteBatches(batches);
   
return null
;
  });
 
  IgnoreBatch(asBatch);

  return new Batch[] { asBatch };
}

Notice it takes one or more Batch instances, and returns a delegate which executes the batches, ignores the batch we just generated and returning the one Batch as an array... conforming to the expected return type of the Batch delegate.  Clear as mud? ;o)

Ignoring the batches actually just uses the annotation framework, so IgnoreBatch looks like this:

public void IgnoreBatch(Batch batch)
{
  batch.Annotate(Ignore =>
true
);
}

And then we check if a batch is ignored before processing it down the line by calling this method.

public bool IsBatchIgnored(Batch batch)
{
 
return batch.HasAnnotation("Ignore"
);
}

Last of all to actually "render" the DSL into some useful format we execute it (no Expression<>'s required, so it's very fast) ... which just call the top with null, which in turn calls the arguments, and those arguments arguments etc.  While doing that we write nodes (much like an Xml writer) against an "evaluation" scope, which associates a NodeWriter with the current thread.... basically the DSL ends up as a bunch of calls like:

NodeWriter writer = new NodeWriter();
writer.WriteStartNode(
new NamedNode("table"
))
  .WriteStartNode(
new NamedNode("tr"
))
    .WriteStartNode(
new NamedNode("td"
))
      .WriteNode(
new TextNode("column1"
))
    .WriteEndNode()
  .WriteEndNode()
.WriteEndNode();

where the nodes conform to this interface:

public interface INode
{
 
INode Parent { get; set
; }
 
List<INode> Nodes { get
; }
}


At which point it's trivial to walk the tree of INode's and do whatever you like with the information stored within it, and we can encapsulate new concepts by creating new types of node, which have payloads of additional information.

At any rate, next time I'll post a little more about how I'm doing it, and attach the code for people to have a play with.

 |  | 
posted @ Friday, June 29, 2007 10:12:23 AM (New Zealand Standard Time, UTC+12:00)    Comments [2] | Trackback |
Search
FeedCount

Tags...
Who am I?
Alex Henderson
Alex Henderson
Auckland, New Zealand
Managing Director at Dev|Defined Limited

"Self Confessed Coding Junky for 15 years"
View Alex Henderson's profile on LinkedIn
 
Mobile: +64-21-402-969
Email: bittercoder 'at' gmail 'dot' com
MSN: bittercoder_nz@hotmail
Skype: alex.devdefined
Navigation