dsl boo3个例子 9
ƒ The Message-Routing DSL is an example of an imperative DSL. It’s executed to
perform some goals.
ƒ The Authorization DSL is a more declarative example (but still mostly impera-
tive). It’s executed to produce a value, which is later used.
ƒ The Quote-Generation DSL is a mostly declarative example. It produces an
object graph that’s later taken up by the processing engine.
Message-Routing DSL
The main reason that we want to use a DSL here is to keep the system flexible and
make it easy to add new messages and transformations. This DSL will be used by tech-
nical people, most probably the developers on the project. This, in turn, means that
we can use a technical DSL here. Each script using this DSL will probably have the fol-
lowing responsibilities:
ƒDeciding whether the script can handle the message
ƒTransforming the message to the internal message representation
ƒDeciding where to dispatch the message
RouteNewOrder.boo DSL定义
# decide if this message match this DSL script
return if msg.type != "NewOrder" and msg.version == "1.0"
# decide which handle is going to handle it
HandleWithNewOrderHandler:
# define a new list
lines = []
# add order lines to the list
for line in msg.order_lines:
lines.Add(OrderLine( line.product, line.qty ) )
# create internal message representation
returnNewOrderMessage(
msg.customer_id,
msg.type,
lines.ToArray(OrderLine) )
IQuackFu it allows us to handle unknown method calls at runtime in asmart fashion.
RoutingBaseThe Message-Routing DSL script will be compiled into a class thatinherits from RoutingBase, and all the code in the script
will go into the Route()method, while the msg field will contain the current message during execution
RoutingDslEnginecompile this DSL. We do it using a DSL engine
RouterThe Routerclass hook it up to the Routerclass
使用:
// translate from the post body to a json object
byte[] bytes = context.Request.BinaryRead(context.Request.TotalBytes);
string json = Encoding.UTF8.GetString(bytes);
JsonSerializer jsonSerializer = new JsonSerializer();
JsonReader reader = new JsonReader(new StringReader(json)); JavaScriptObject javaScriptObject = (JavaScriptObject)jsonSerializer.Deserialize(reader);
// send the json object to be routed
string scriptsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin");
string returnMessage = Router.Route(scriptsPath,
new JsonMessageAdapter(javaScriptObject));
context.Response.Write(returnMessage);
context.Response.Write(returnMessage);
JsonMessageAdapter class is responsible for translating the JavaScriptObject into an IQuackFu, which is what we expect in the MessageRouting DSL
using Boo.Lang;
using Newtonsoft.Json;
public class JsonMessageAdapter : IQuackFu
{
private readonly JavaScriptObject js;
public JsonMessageAdapter(JavaScriptObject js)
{
this.js = js;
}
public object QuackGet(string name, object[] parameters)
{
object value = js[name];
JavaScriptArray array = value as JavaScriptArray;
if(array!=null)
{
return array.ConvertAll(delegate(object obj)
{
return new JsonMessageAdapter((JavaScriptObject) obj);
});
}
return value;
}
Authorization DSL
ƒThe CheckAuthorization() method and the Operation property are both
abstract, so derived classes (and our DSL) have to implement them.
ƒThe Allow() and Deny() methods are the only ways for the derived class to
affect the state of the rule. Both methods accept a reason string, which means
that we’re automatically documenting the reason for the decision.
operation "/account/login"
if Principal.IsInRole("Administrators"):
Allow("Administrators can always log in")
return
if date.Now.Hour < 9 or date.Now.Hour > 17:
Deny("Cannot log in outside of business hours, 09:00 - 17:00")
e make use of the Boo date keyword
to reference System.DateTime, which we haven’t seen before, but that isn’t very
interesting.
There is one interesting thing here: the first line isn’t something that we’ve seen so
far. We know that we need to provide an implementation of the Operation property,
but how can we do it?
It’s done using a macro, which takes the first argument of the macro, generates a
property, and returns that argument from the property.
使用
WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
bool? allowed = Authorization.IsAllowed(principal, "/account/login");
Console.WriteLine("Allowed login: {0}", allowed);
Console.WriteLine(Authorization.WhyAllowed(principal, "/account/login"));
The Quote-Generation DSL
The first is that we use astrange naming convention for some of the methods (requires, same_machine_as,specification, and users_per_machine do not follow the standard .NET namingconvention). This is the easiest way to get keywords in the DSL.
Note that thespecification() method accepts a delegate as the last parameter, so we’re using
anonymous blocks again, like we did in the Message-Routing DSL Handle method.
The second thing to note is all the @ signs scattered through the DSL (listing 4.16).
Those are called symbols, and they translate to string literals without the annoying
The last thing that’s worth noting about the QuoteGeneratorRule class is that itaccepts a RequirementsInformation class. This allows it to understand what context itruns in, which will be important later on.
The QuoteGeneratorRule class is responsible for building the object model thatwill later be processed by the quote-generation engine.
specification @vacations:
requires @scheduling_work
requires @external_connections
specification @salary:
users_per_machine 150
specification @taxes:
users_per_machine 50
specification @pension:
same_machine_as @health_insurance