Monday, March 17, 2008

Recursive it is.

Well, for the gtk# presenter injection issue, I determined that I could do the recursive method for in about fifteen lines of code, so I implemented that. I was stumped for quite some time because the recursion wasn't descending at all -- it turns out I was casting widgets to Gtk.Bin when I should have been casting to Gtk.Container.

The code:

public class ViewAttribute : Attribute {}

public class InjectAttribute : Attribute {}

[CastleComponent("bootstrapViews", typeof(BootstrapViews))]
public class BootstrapViews
{
private IWindsorContainer _container;

public BootstrapViews(IWindsorContainer container)
{
_container = container;
}

public void Bootstrap(Widget widget)
{
Container bin = widget as Container;
if (bin == null)
{
return;
}
foreach (Widget child in bin.Children)
{
Bootstrap(child);
}

object[] attrs = bin.GetType().GetCustomAttributes(typeof(ViewAttribute), false);
if (attrs.Length > 0)
{
foreach (FieldInfo field in bin.GetType().GetFields())
{
if (field.GetCustomAttributes(typeof(InjectAttribute), false).Length > 0)
{
field.SetValue(bin, _container.Resolve(field.FieldType));
}
}
}
}
}

Sunday, March 16, 2008

gtksharp and MVP

Switching gears to C#, since, though I love D, I need a working mocks library to write any significant code in it, and dmd bugs prevent dmocks from working correctly.

I'm using gtk#/stetic to create a GUI of moderate complexity, and of course I'm using the Model-View-Presenter pattern. Reminiscent of ASP.NET MVP issues, the main problem is getting a reference to a presenter into a view -- gtk# doesn't use a central object builder that I can hook into; everything happens in a Build method.

So I have three options that I can pursue in achieving a reasonable MVP model:
  1. Each custom widget gets a reference to the Castle container and resolves its presenter that way.
  2. I build my GUI, then do a depth-first traversal of all the components, looking for an attribute set: [View(Type register)] on the class, [Inject] on the presenter(s). Any such classes, I register with the container, then fill in their dependencies. This works for everything that inherits from Gtk.Bin, but I have to copy it for any other gtk classes that my widgets derive from.
  3. Possibly using inheritance, my widgets subclass a SmartPart class and register themselves with a singleton (using the typical singleton pattern) that will register them with the container and fill in dependencies. This means I spend less time at runtime looking at widgets.
Option #1 is not happening.
Option #3, using generics, is reasonably simple, and it works unless I have one view with multiple presenters.
Option #2 is the fully general solution, which I probably won't be implementing. It'd be great, except for the speed, but it's rather yagni.

Of course, the problem with #2 is that my constructors will have to be modified, or the presenters might do something foolish:

public MyWidget()
{
this.Build();
base(whatever);
}
// was:
// public MyWidget() : base(whatever)
// {
// this.Build();
// }

As an aside, has anyone had luck getting CruiseControl.net running on debian?

Wednesday, March 12, 2008

DUnit

I whipped together a quick unittest library, DUnit. Took less than an hour; apparently, SUnit took about two hours to write, so I'm in decent company.

This doesn't offer very much; in particular, there's no measure of progress. That's a deviation from the xUnit standard. And there's no way to control which tests get run. But I'm working on a better version already that offers those features.

On an unrelated note, dmd2 is too unstable to be usable, so dmocks is dead. I'll be updating it to dmd2.011, but probably no further, at least until dmd2 is in late beta or beyond.

Tuesday, February 26, 2008

Horrible...

Everything I said about templates? Double for mixins.

A short mixin can be a wonderful thing. Like for unittests:

string test(string name)()
{
return `
Stdout("` ~ name ~ `");
scope (failure) Stdout("failed").newline;
scope (success) Stdout("passed").newline;`
}
unittest
{
mixin(test!("test naming test"));
}


But mixins should be passive, delegating to concrete methods and classes whenever possible. Line numbers are that important.

Monday, February 18, 2008

New project woes

Got a university project that's decidedly not Agile. And I don't have any time to do requirements analysis in this weakly waterfall style. If it were Agile, I'd only have time for about four or five iterations....

It's tempting to ignore the customers at this point and just code up an initial project that fulfills some need. Then I'd have something to talk about. The one source I have wants the system to have insane amounts of detail -- if I asked him to fill it out, he'd refuse, I think. And there's only one person in the department who would benefit from the information.

Sunday, February 17, 2008

CTFE and testability

A lot of my code makes heavy use of CTFE. Really heavy. As in, more lines of code get executed at compile time than at runtime. How do I start to write unittests for it?

Answer: I don't.

That's rather harsh. Let's look at one case, or actually an abbreviated form of it. This is taken from DMocks:


string Methods (T, string name) () {
string methodBodies = "";
foreach (method; __traits(getVirtualFunctions, T, name)) {
alias typeof(method) func;
static if (is(ReturnType!(func) == void)) {
methodBodies ~= VoidMethod!(T.stringof, name, ParameterTypeTuple!(func));
} else {
methodBodies ~= ReturningMethod!(
T.stringof,
name,
ReturnType!(func),
ParameterTypeTuple!(func));
}
}
return methodBodies;
}

string ReturningMethod (string type, string name, T, U...)() {
string qualified = type ~ `.` ~ name;
string args = String!(U)();
string argArgs = Arguments!(U);
string nameArgs = `"` ~ qualified ~ (U.length == 0 ? `"` : `", ` ~ Arguments!(U)());
string retArgs = T.stringof ~ (U.length == 0 ? `` : `, ` ~ args);
return `some very long string that uses those strings I just assigned above`;
}
// VoidMethod looks pretty much like ReturningMethod.


That is terribly ugly, of course. If I could do it at runtime, I could introduce about two classes for the first template, then use tango.text.convert.Layout and public static format strings to deal with ReturningMethod. I'd do it with a format string looking like this:


public const string methodOutline = `{0} {1} ({2}) {{{
{{0}}
}}}`;
public const string methodBodyPart1 = `{0} {1} ...`;
public const string methodBodyPart2 = `{0} {1} ...`; // and so on


Of course, Layout won't work at compile time. Even if it did, I'd be left with a glob of functions to go through for my "unit" tests. But at that rate, I might as well complete the integration test by running the code that mixes in this giant string.

So I've been thinking of how to do it. The answer lies in two parts:

  1. Write a compile-time string formatting function.

  2. Implement any method I want to test as a string that I mix in.



The former makes it much easier to make sure the result string has the right arguments in the right place. The latter means I can test each in isolation by providing default implementations of templates that I'm not testing.

But for now, I've got some ugly, unmaintainable blobs of code to rewrite. The joy.

Continuous Integration for D

You don't need to use Agile to benefit from a Continuous Integration server. The basic idea is, you've got a server that checks out your code whenever there are updates, builds it according to a build script, and (almost always) runs some scripted tests on it.

I'm pondering how to set one up for D, using a daemon of some sort. The approach looks something like this:


  • A config file with the repository information and where to check it out to.

  • A DSSS file in the root of the repository.

  • A list of directories that contain tests. These should only contain tests; perhaps an exclude option for files and directories that contain helper methods.



The build process isn't that exciting:

  • Check for updates; if none, sleep.

  • Run dsss build.

  • Recursively go through the test directories, running rebuild on each .d file and executing the resulting executable.

  • Publish the results.



This requires that each test file contain a main() method. However, it has the benefit that the main executable does not contain unit tests, enforcing or at least encouraging separation of concerns and design practices that do require tests to have private access to the tested modules.