>>> A new internal dependency checking rule for Gendarme, featuring Boo-powered DSL for project-specific configuration
On an original idea from the amazing Rodrigo who wondered how some API design rules could be enforced consequently to a refactoring in the Boo project, I thought such a job would be a perfect match for Gendarme, the opensource rule-based static-analysis tool for .NET assemblies.
So in the excitement of the idea, I started hacking DependencyCheckingRule, which is an abstract rule inheritors can ..er.. subclass to enforce project-specific design rules regarding internal dependencies between types or namespaces of a project. This is also probably the first rule ever written in Boo, which added to the excitement ;-)
The rule being designed to be subclassed (it's abstract!) for project-specific needs, it was a great opportunity to write a DSL to specify allowed/disallowed internal dependencies in a readable and type-safe way :
An example DSL-representation of yet incomplete list of (dis)allowed dependencies within Boo project
Checking is done by running permissions chains in order (iptables-like)
#allow Ast namespace types to use interfaces from TypeSystem in non-visible members
allow Boo.Lang.Compiler.TypeSystem, Interface, NonVisible
#deny any other usage
To illustrate what it is about, this currently generates this report when compiled and run through Gendarme against Boo assemblies.
You can see how simple it is to write such a DSL here (includes a few more examples).
Moreover readability an advantage of using a DSL for this over say XML files, is the type-safety that comes almost for free, which ensures your dependencies map is correct and up-to-date with your code, otherwise the DSL will not compile.
Under the hood though, it is of course a regular CLI assembly that the Boo compiler generates using the following expanded code :
public class BooDependencyCheckingRule(Gendarme.Rules.Abstract.DependencyCheckingRule):
protected Permissions as DependencyCheckingRule.DependencyPermission*: #'*' means IEnumerable<T> in Boo
protected override get:
if self.DoesTargetMatchNamespace(self.CurrentType.FullName, 'Boo.Lang.Compiler.Ast'):
yield DependencyPermission(self, Namespace: 'Boo.Lang.Compiler.TypeSystem', \
Deny: false, Relation: DependencyRelation.Dynamic, Visibility: DependencyVisibility.NonVisible)
yield DependencyPermission(self, Namespace: 'Boo.Lang.Compiler.TypeSystem')
As you can see the only method that requires overriding is the Permissions getter, which then must yield permissions so that the base class can lazily check them if needed.
In effect DependencyCheckingRule can be manually subclassed (e.g in C#) and possibly yield permissions from a file, a database, whatever makes most sense for a particular project...