KRL (Kynetx Rule Language) started out as a fairly small domain specific language for augmenting Web pages. We integrated with several online services (like geolocation, weather, and so on) to make what we were doing simpler to write. Later, as KRL grew, we added more integrations with Web APIs and services like Twitter. We've increased the abstraction capabilities of the language by adding first-class functions.
Lately we've realized that many of the native integrations of external APIs we've done could--and should--be done by developers working in KRL. If only they had a way to encapsulate and share them! Now they do. This week we pushed code that added modules to KRL.
In KRL, any ruleset can be a module. At present, only declarations in the global block are available to the ruleset that uses the module. There are language changes in the works that will allow actions to defined and shared in a module as well. Please stand by, as they say. Not everything in the global block has to be exported, so you can keep things private. Modules can be parametrized and aliased. For details see the module documentation.
Alex Olsen created a nice little demo of modules that I'll share to show how they work. One of the little tools we use to make storing temporary information easier is called StringBin. StringBin allows you to create key-value pairs in the cloud and has a simple API. Alex defined his StringBin module like so (Gist here):
ruleset a369x115 { meta { name "StringBin Module" description << StringBin Module >> author "AKO" logging off provide read, write, destroy configure using pin = "nopin" } global { datasource write <- "http://api.stringbin.com/1/write?" cachable for 1 second datasource read <- "http://api.stringbin.com/1/read?" cachable for 1 second write = function(k,v) { datasource:write({"pin":pin,"key":k,"value":v}) } read = function(k) { datasource:read({"pin":pin,"key":k}) } destroy = function(k) { datasource:write({"pin":pin,"key":k,"value":""}) } } }
The important things to note here are the provide
and configure
clauses. The provide
keyword is followed by a list of names that will be available outside the module. The configure
keyword indicates the module parameters and their default values. Alex's module has one parameter, the StringBin pin or developer token and it defaults to "nopin". Note that that datasource declarations are not provided to rulesets using the module and the implementation details are effectively hidden.
You can use this module like so:
meta { use module a369x115 alias StringBin with pin = "X9ooUUsrR180MkpxZ2N1M" } ... rule write_to_stringbin { select when pageview ".*" pre { stuff = StringBin:write("yellow", "mellow"); } ... }
Note: I've cut out large pieces of Alex's example, for the complete sample ruleset that uses his module, see the Gist.
In the preceding code, the module is used by putting a use module
clause in the meta
block. The use module
clause needs a ruleset name and optionally an alias (StringBin
in this case) and configuration (setting the pin in this case). Later, the write
function from the StringBin
module is used to write the value "mellow"
to the key "yellow"
.
Because modules are parametrized and can be aliased, you can use the module multiple times with different parameters. For example, suppose we had two StringBins and we wanted to copy a value out of one into the other. We could accomplish that like so:
meta { use module a369x115 alias BinA with pin = "X9ooUUsrR180MkpxZ2N1M" use module a369x115 alias BinB with pin = "ada98u0ada0kkdad0a0da" } ... rule copy_stringbin { select when pageview ".*" pre { stuffToCopy = BinA:read("yellow"); results = BinB:write("yellow", stuffToCopy); } ... }
In the preceding code, we've attached to two bins called BinA
and BinB
and we're reading something out of one and writing to the other.
Parametrized modules provide a convenient way to encapsulate complex behavior and use it over and over again. Now that you don't need language mods to make your API calls all pretty, I'm expecting to see an explosion of APIs that are integrated--via modules--into KRL.