• No results found

59Running the Scheduling DSL

In document DSLs in Boo (Page 82-86)

The drive toward DSLs

59Running the Scheduling DSL

return new WebSite("http://example.org"). IsNotResponding;

};

this.then( delegate {

this.notify( "[email protected]", "server down!");

});

});

Take a look back at the original DSL text in listing 3.11, and compare it to listing 3.14.

In terms of functionality, they’re the same, but the syntactic differences between them are huge, and we want a good syntax for our DSL.

We’ve skipped one important part; we haven’t talked yet about what the implicit base class will do. The result of the implicit base class resolving its base class is shown in listing 3.15, and the details of what the implicit base class is doing are discussed in section 3.8.

public class MyDemoTask ( BaseScheduler ):

def override Prepare():

task("warn if website is down"), def():

# the rest of the code

Now that we have a firm grasp of what code we’re getting out of the DSL, we need to get to grips with how we can run this code.

3.8 Running the Scheduling DSL

So far we’ve focused on the transformations we’re putting the code through, but we haven’t talked yet about how to compile and execute a DSL. Remember, we aren’t dealing with scripts in the strict sense of the word; we have no interpreter to run.

We’re going to compile our DSL to IL, and then execute this IL. The code that it takes to do this isn’t difficult, just annoying to write time after time, so I wrapped it up in a common project called Rhino DSL.2

Listing 3.15 The full class that was generated using the implicit base class

2 Rhino [Project Name] is a naming convention that I use for most of my projects. You may be familiar with Rhino Mocks, for example, which is part of the same group of projects as Rhino DSL. There is no connection to Mozilla’s Rhino project, which is a JavaScript implementation in Java.

The Rhino DSL project

The Rhino DSL project is a set of components that turned out to be useful across many DSL implementations. It contains classes to aid in building a DSL engine, implicit base classes, multifile DSLs, and so on.

We’re going to use Rhino DSL throughout this book; it’s an open source project, licensed under the BSD license, which means that you can use it freely in any type of application or scenario. We’re also going to spend chapter 7 dissecting Rhino DSL, to ensure that you understand how it works, so you could implement it on your own, if you ever need to.

Compilation is expensive, and once we load an assembly in the CLR, we have no way of freeing the occupied memory short of unloading the entire AppDomain. To deal with these two problems, we need to do at least some caching up front. Doing this on a DSL-by-DSL basis is annoying, and it would be nice to get the cost of creating a DSL down as much as possible.

For all of those reasons, Rhino DSL provides the DslFactory class, which takes care of all of that. It works closely with the DslEngine, which is the class we derive from to specify how we want the compilation of the DSL to behave.

Again, none of this is strictly necessary. You can do it yourself easily, if you choose to, but using Rhino DSL makes it easier and allows us to focus on the DSL implemen-tation instead of the compiler mechanics.

We’ve already looked at the BaseScheduler class. Now let’s take a peek at the SchedulingDslEngine class. Listing 3.16 shows the full source code of the class.

public class SchedulingDslEngine : DslEngine {

protected override void CustomizeCompiler(

BooCompiler compiler, CompilerPipeline pipeline, string[] urls)

{

pipeline.Insert(1,

new ImplicitBaseClassCompilerStep(

typeof (BaseScheduler), "Prepare",

// default namespace imports "Rhino.DSL.Tests.SchedulingDSL"));

} }

As you can see, it doesn’t do much, but what it does do is interesting. The method is called CustomizeCompiler, and you’re going to learn a whole lot more about cus-tomizing the compiler in chapter 4. For now, keep in mind that Boo allows you to move code around during compilation, and the ImplicitBaseClassCompilerStep does that.

The ImplicitBaseClassCompilerStep will create an implicit class that will derive from BaseScheduler. All the code in the file will be placed in the Prepare derived method. We can also specify default namespace imports. In listing 3.16, you can see that we add the Rhino.DSL.Tests.ShedulingDSL namespace. This namespace will be imported to all the DSL scripts, so we don’t have to explicitly import it. VB.NET users are familiar with this feature, using the project imports.

We’re nearly at the point when we can execute our DSL. The one thing that’s still missing is the DslFactory intervention. Listing 3.17 shows how we can work with that.

Listing 3.16 The implementation of SchedulingDslEngine

61 Summary

//initialization

DslFactory factory = new DslFactory();

factory.Register<BaseScheduler>(new SchedulingDslEngine());

//get the DSL instance

BaseScheduler scheduler = factory.Create<BaseScheduler>(

@"path/to/ValidateWebSiteUp.boo");

//This is where we run the code from the DSL file scheduler.Prepare();

//Run the prepared scheduler scheduler.Run();

First, we initialize the DslFactory, and then create and register a DslEngine for the specific base type we want. Note that you should only do this once, probably during the startup of the application. This usually means in the Main method in console and Windows applications, and in Application_Startup in web applications.

We then get the DSL instance from the factory. We pass both the base type we want (which is associated with the DslEngine that we registered and the return value of this method), and the path to the DSL script. Usually this will be a path in the filesystem, but I have seen embedded resources, URLs, and even source control links used.

Once we have the DSL instance, we can do whatever we want with it. Usually, this depends on the type of DSL it is. When using an imperative DSL, I would tend to call the Run() or Execute() methods. With a declarative DSL, I would usually call a Prepare() or Build() method, which would execute the code that we wrote using the DSL, and then I would call the Run() or Execute() method, which would take the result of the previous method call and act upon it. In more complex scenarios, you might ask a separate class to process the results, instead of having the base class share both responsibilities.

In the case of the Scheduling DSL, we use a declarative approach, so we call the Prepare() method to get whatever declarations were made in the DSL, and then we run the code. The Run() method in such a DSL will usually perform some sort of regis-tration into a scheduling engine.

And that’s it—all the building blocks that you need to write a good DSL. We’re going to spend a lot more time discussing all the things we can do with DSLs, how we can integrate them into real applications, and version, test, and deploy them, but you should now have an overall understanding of what’s involved.

3.9 Summary

We’ve gone over quite a bit of information in this chapter. We contrasted the imple-mentation of a simple problem (scheduling tasks) using both fluent interfaces in C#

and a full-blown Boo-based DSL, and we saw that it’s very easy to take a DSL further than a fluent interface. And that’s aside from the syntactic differences between the two solutions.

Listing 3.17 Executing a Scheduling DSL script

We also explored why we might want to build DSLs and what types of DSLs we can build: technical, business, and extensibility DSLs.

Then we rolled up our sleeves and went to work building the Scheduling DSL, from the initial syntax, to implementing the DSL base class, to creating the DSL engine and running the code.

Along the way we took a quick peek at combining DSLs and DDD, explored the dif-ferences between imperative and declarative DSLs, and generally had fun. We covered (at a high level) just about everything you’ll need to create a useful DSL.

But not quite everything. We’re still focused at too high a level. It’s time to get down into the details and start practicing what we’ve discussed so far. That’s up next.

63

In document DSLs in Boo (Page 82-86)

Related documents