Oren Eini

CEO of RavenDB

a NoSQL Open Source Document Database

Get in touch with me:

oren@ravendb.net +972 52-548-6969

Posts: 7,592
|
Comments: 51,223
Privacy Policy · Terms
filter by tags archive
time to read 1 min | 111 words

How do I test the syntax in this DSL? HandleWith should translate to a method call with typeof(RoutingTestHandler) and a delegate.

import BDSLiB.Tests

HandleWith RoutingTestHandler:
	lines = []
	return NewOrderMessage( 15,  "NewOrder", lines.ToArray(OrderLine) ) 

Well, I use interaction based testing, obviously. I find this test utterly fascinating, because it is fairly advance, in a roundabout sort of way, and yet it is so simple.

[Test]
public void WillCallHandlesWithWithRouteTestHanlderWhenRouteCalled()
{
	const IQuackFu msg = null;

	var mocks = new MockRepository();

	var routing = dslFactory.Create<RoutingBase>(@"Routing\simple.boo");

	var mockedRouting = (RoutingBase)mocks.PartialMock(routing.GetType());
	Expect.Call(() => mockedRouting.HandleWith(null, null))
		.Constraints(Is.Equal(typeof(RoutingTestHandler)), Is.Anything());

	mocks.ReplayAll();

	mockedRouting.Initialize(msg);

	mockedRouting.Route();

	mocks.VerifyAll();
}
time to read 2 min | 219 words

I saw several solution for extending NUnit and MbUnit to add new functionality, all of them were far too complex for me. I didn't want this complexity. Here is the entire code that I had to write in order to make xUnit integrate with my DSL:

public class DslFactAttribute : FactAttribute
{
	private readonly string path;

	public DslFactAttribute(string path)
	{
		this.path = path;
	}

	protected override IEnumerable<ITestCommand> EnumerateTestCommands(MethodInfo method)
	{
		DslFactory dslFactory = new DslFactory();
		dslFactory.Register<TestQuoteGeneratorBase>(
				new TestQuoteGenerationDslEngine());
		TestQuoteGeneratorBase[] tests = dslFactory.CreateAll<TestQuoteGeneratorBase>(path);
		for(var test in tests)
		{
			Type dslType = test.GetType();
			BindingFlags flags = BindingFlags.DeclaredOnly |
				BindingFlags.Public |
				BindingFlags.Instance;
			foreach (MethodInfo info in dslType
				.GetMethods(flags))
			{
				if (info.Name.StartsWith("with"))
					yield return new DslRunnerTestCommand(dslType, info);
			}
		}
		
	}
}

And the DslTestRunnerCommand:

public class DslRunnerTestCommand : ITestCommand
{
	private readonly MethodInfo testToRun;
	private readonly Type dslType;

	public DslRunnerTestCommand(Type dslType, MethodInfo testToRun)
	{
		this.dslType = dslType;
		this.testToRun = testToRun;
	}

	public MethodResult Execute(object ignored)
	{
		object instance = Activator.CreateInstance(dslType);
		return new TestCommand(testToRun).Execute(instance);
	}

	public string Name
	{
		get { return testToRun.Name; }
	}
}

That is what I am talking about when I am talking about easy extensibility.

time to read 1 min | 87 words

Yesterday I asked how we can efficiently test this piece of code:

specification @vacations:
	requires @scheduling_work
	requires @external_connections

Trying to test that with C# code resulted in 1500% disparity in number of lines of code. Obviously a different approach was needed. Since I am in a DSL state of mind, I wrote a test DSL for this:

script "quotes/simple.boo"

with @vacations:
	should_require @scheduling_work
	should_require @external_connections	

with @scheduling_work:
	should_have_no_requirements

I like this.

You can take a look at the code here.

time to read 1 min | 136 words

There is something that really bothers me when I want to test this code:

specification @vacations:
	requires @scheduling_work
	requires @external_connections

And I come up with this test:

[TestFixture]
public class QuoteGenerationTest
{
	private DslFactory dslFactory;

	[SetUp]
	public void SetUp()
	{
		dslFactory = new DslFactory();
		dslFactory.Register<QuoteGeneratorRule>(new QuoteGenerationDslEngine());
	}

	[Test]
	public void CanCompile()
	{
		QuoteGeneratorRule rule = dslFactory.Create<QuoteGeneratorRule>(
			@"Quotes/simple.boo",
			new RequirementsInformation(200, "vacations"));
		Assert.IsNotNull(rule);
	}

	[Test]
	public void WhenUsingVacations_SchedulingWork_And_ExternalConnections_AreRequired()
	{
		QuoteGeneratorRule rule = dslFactory.Create<QuoteGeneratorRule>(
			@"Quotes/simple.boo",
			new RequirementsInformation(200, "vacations"));
		rule.Evaluate();

		SystemModule module = rule.Modules[0];
		Assert.AreEqual("vacations", module.Name);
		Assert.AreEqual(2, module.Requirements.Count);
		Assert.AreEqual("scheduling_work", module.Requirements[0]);
		Assert.AreEqual("external_connections", module.Requirements[1]);
	}

	[Test]
	public void WhenUsingSchedulingWork_HasNoRequirements()
	{
		QuoteGeneratorRule rule = dslFactory.Create<QuoteGeneratorRule>(
			@"Quotes/simple.boo",
			new RequirementsInformation(200, "scheduling_work"));
		rule.Evaluate();

		Assert.AreEqual(0, rule.Modules.Count);
	}
}

I mean, I heard about disparity in number of lines, but I think that this is beyond ridiculous.

time to read 2 min | 365 words

Martin Fowler talks about the almost instinctive rejection of external DSLs because writing parsers is hard. I agree with Fowler on that writing a parser to deal with a fairly simple grammar is not a big task, certainly there isn't anything to recommend XML for the task over an textual parser.

The problem that I have with external DSL is actually different. It is not the actual parsing that I object to, it is the processing that needs to be done on the parse tree (or the XML DOM) in order to get to an interesting result that I dislike.

My own preference is to utilize an existing language to build an internal DSL. This allows me to build on top of all the existing facilities, without having to deal with all the work that is required to get from the parse tree to a usable output.

In the case of the example that Fowler uses for his book (the state machine outlined here), the use of an internal DSL allows me to go from the DSL script to a fully populated semantic model without any intermediate steps. I give up some syntactic flexibility in exchange of not worrying about all the details in the middle.

The benefit of that is huge, which is why I would almost always recommend going with an internal DSL over building an external one. Here is a simple example, a business rule DSL:

suggest_preferred_customer:
    when not customer.IsPreferred and order.Total > 1000

apply_discount_of 5.precent:
    when customer.IsPreferred and order.Total > 1000

I wrote the code to use this DSL as a bonus DSL for my DSL talk in DevTeach. It took half an hour to forty five minutes, and it was at 4 AM. I extended this DSL during the talk to support new concepts and to demonstrate how easy it is.

I got to that point by leaning heavily on the host language to provide as much facilities as I could.

In short, it is not the parsing that I fear, it is all the other work associated with it.

time to read 1 min | 117 words

For various reasons which will be made clear soon, I needed to write the same test twice, once using Rhino Mocks, the second time using hand rolled stubs. I thought it was an interesting exercise, since this is not demo level code.

[Test]
public void WillCallHandlesWithWithRouteTestHanlderWhenRouteCalled_UsingRhinoMocks()
{
	const IQuackFu msg = null;

	var mocks = new MockRepository();

	var routing = dslFactory.Create<RoutingBase>(@"Routing\simple.boo");

	var mockedRouting = (RoutingBase)mocks.PartialMock(routing.GetType());
	Expect.Call(() => mockedRouting.HandleWith(null, null))
		.Constraints(Is.Equal(typeof(RoutingTestHandler)), Is.Anything());

	mocks.ReplayAll();

	mockedRouting.Initialize(msg);

	mockedRouting.Route();

	mocks.VerifyAll();
}

[Test]
public void WillCallHandlesWithWithRouteTestHanlderWhenRouteCalled()
{
	const IQuackFu msg = null;

	dslFactory.Register<StubbedRoutingBase>(new StubbedRoutingDslEngine());

	var routing = dslFactory.Create<StubbedRoutingBase>(@"Routing\simple.boo");

	routing.Initialize(msg);

	routing.Route();

	Assert.AreEqual(typeof (RoutingTestHandler), routing.HandlerType);

	Assert.IsInstanceOfType(
		typeof(NewOrderMessage), 
		routing.Transformer()
		);
}
time to read 1 min | 180 words

You can register here for a two days course in building DSL with Boo.

It is going to take place two weeks from today, in Austin. (19 - 20 May)

I know that this is short notice, but it wasn't something that was planned well in advance. It came out of the ALT.Net conference.

Topics:

  • Creating Domain Specific Languages
  • The Boo Language
  • Flexible compiler and malleable language
  • Creating applications with embedded DSL
  • Management, tracing and debugging
  • Tooling support
  • Testing and maintainability concerns

There are ten seats open for that.

I hope we would have fun.

I would also like to thank Jeffrey Palermo and Headspring for hosting the course.

FUTURE POSTS

  1. Semantic image search in RavenDB - about one day from now

There are posts all the way to Jul 28, 2025

RECENT SERIES

  1. RavenDB 7.1 (7):
    11 Jul 2025 - The Gen AI release
  2. Production postmorterm (2):
    11 Jun 2025 - The rookie server's untimely promotion
  3. Webinar (7):
    05 Jun 2025 - Think inside the database
  4. Recording (16):
    29 May 2025 - RavenDB's Upcoming Optimizations Deep Dive
  5. RavenDB News (2):
    02 May 2025 - May 2025
View all series

Syndication

Main feed ... ...
Comments feed   ... ...
}