Skip to main content

Defeating the Purpose of a DSL

First, I neglected to mention in my previous post that I found Paul Cowan's blog to be a tremendous help in figuring out how build a DSL with Boo and Rhino DSL.

Second, I wanted to point out that, because this is an internal DSL written in Boo, it's still possible to use familiar programming constructs in the DSL scripts. For example, I could dynamically generate the team definitions from some other datasource, like so:

stats = GetData()

for row as DataRow in stats.Rows:
define row["name"]:
defense Determine.DefenseFromRanking(cast(int,row["defenseRanking"]))
pass_offense Determine.PassOffenseFromRanking(cast(int,row["passOffenseRanking"])), with_qb_type(Determine.QbTypeFromRatingAndExperience(cast(double,row["qbRating"]), cast(int,row["qbExperience"])))
run_offense Determine.RunOffenseFromRanking(cast(int,row["runOffenseRanking"]))

where GetData() returns a DataTable with multiple team statistics, and Determine is a static class that gets the name of different team components based on relevant stats.

The meta methods that define the keywords won't work as is for this. Remember, they're operating on the AST. In this case, the parameter types simply need to be relaxed from StringLiteralExpression to Expression. Here's the new run_offense meta method as an example:


[Meta]
public static def run_offense(expression as Expression):
return [|
_currentTeam.RunOffense = $expression
|]

So, string literals and method calls both work here. One thing that slightly limits the extensibility of the language in this matter is the use of the implicit base class as a container for the script. The body of the script (minus any import statements) goes directly into the implementation of an abstract method declared on the base class, so extending the language by adding methods directly to the script is out. Other than that, everything should work like normal. All the constructs of the language are available. Of course, doing something like what's listed above sort of defeats the purpose of creating a language for easy data scripting in the first place, as it isn't very readable or maintainable...

Comments

Popular posts from this blog

Who I'm Is

I am a junior .NET developer currently working in Chicago, IL. I am starting this blog in order to enhance my knowledge of programming subject matter. Hopefully, someone else will be helped along the way. This first post will probably be edited soon...

Stubbing Static Methods with PostSharp

TypeMock uses the Profiler API to allow mocking, stubbing, etc. of classes used by code under test. It has the ability to handle sealed classes, static classes, non-virtual methods, and other troublesome-yet-oft-encountered scenarios in the world of unit testing. Other frameworks rely on proxies to intercept method calls, limiting them to be able to only fake virtual, abstract, and interface members. They also rely on dependecy injection to place the proxies as the concrete implementation of calls to the abstracted interface members. Anyone working with a legacy codebase is bound to run into static method calls (especially in the data access layer), dependencies on concrete types with non-virtual methods, and sealed class dependencies (HttpContext anyone?). The only way to unit test this without refactoring is with TypeMock. I've never used TypeMock, and I'm sure it's a great product, but it's not free. I decided to spike some code to see if I could solve the prob...

Strongly-Typed Property Constraints in Rhino Mocks

UPDATE: As I suspected, this functionality was right in front of my face – it’s called PredicateConstraint in Rhino Mocks. I also realize that I managed to completely ignore the existence of Predicate<T> in the framework, and write my own predicate delegate. Hey, I was on a roll. Rhino Mocks has a PropertyConstraint class that allows you to check the values on properties of objects passed into the method as part of the verification for that method being called. Unfortunately, the name of the property is specified as a string, which means the benefits of strong-typing that Rhino Mocks is normally so good at preserving are lost. Here’s an example (using Rhino Mocks 3.3 and .NET 2.0): [Test] public void Main_Form_Should_Show_Start_Panel_On_Load() { MockRepository mockRepository = new MockRepository(); IMainFormView mockView = mockRepository.DynamicMock<IMainFormView>(); IEventRaiser loadEventRaiser = GetEventRaiserFor(delegate { mockView.Load += null; });...