This site has been deprecated. Do not edit pages here. Please visit the new Pico Labs documentation.


Skip to end of metadata
Go to start of metadata

 

Any KRL ruleset can function as a module if it contains the provides pragma in the meta section of the ruleset. KRL modules are parameterized and can be included more than once with different parameters. A module may include, and use, other modules.

When defined as a module, any of the global definitions may be provided to rulesets that use the module. Rules cannot be shared.

Using a Module

A ruleset uses another ruleset as a module with the use module pragma. The syntax is:

The <ruleset name> is the name of the ruleset to use as a module. Note that this is the RID that the ruleset manager knows the ruleset by, not the name declared in the meta section of the ruleset.

Any global definitions in that ruleset that have been declared in the provides pragma of the module will be available in the using ruleset. You can reference these declarations in the using ruleset by namespacing the variable name from the module with the module's name (i.e. it's ruleset name).

For example, if ruleset a16x78 provides flip then it can be referenced in a ruleset using a16x78 as follows:

Aliasing

The optional alias keyword declares an alias for the ruleset name. So if a16x78 ruleset is used as follows:

then, the preceding example would look like this:

Note: the following are reserved and may not be used as module aliases:

  • ent
  • app
  • dataset
  • datasource

Configuration

The optional with clause declares configuration values for the used module. The expressions on the righthand side of the with clause must be evaluable before anything in the ruleset has been evaluated. That means that the righthand side is limited to expressions that use:

  • literals
  • keys
  • event attributes
  • page parameters
  • environment values

See below for more information on module configuration.

Declaring a Module

Strictly speaking, any ruleset can be used as a module but only rulesets that contain the provides pragma in their meta section will be useful since only global definitions explicitly marked for export in the provides pragma will be available in the using ruleset. If the ruleset contains no provides pragma or one that is empty or names values not declared in the module, nothing will be usable in the using ruleset.

The syntax for provides is

The list of provided declaration is given as a comma separated list of names.

Often it's useful to know whether or not a ruleset is running as a module. The meta library provides functions that give information about the running ruleset, including whether it's running as a module or not. 

Configuring a Module

When a module is used, the with clause allows the module to be configured. This provides for module parameterization. The configuration is declared using the configure pragma in the meta section of the module. The syntax is as follows:

Only variables declared in the configure pragma will be configurable from the using ruleset. The <expr> gives a default value for the configuration parameter. If the with clause is used to declare configuration values when the module is used, then those values will override any defaults in the configuration of the module.

Variables declared in the configuration are available as regular variables throughout the module. A typical use of the module configuration is to pass in user keys from a ruleset's keys declaration so that the module can use them.

Example

Consider the following ruleset that is intended for use as a module (note the provides and configure pragmas):

 

Suppose that we used this module as follows:

When rules in ruleset foobar execute, x will have the value 9, y will have the value 10, and z will contain the query term "kynetx" since that's what we pick out of the JSON response. Note that if we had referenced a16x78:b it would be undefined since b is not in the provides pragma in the module. 

Also note that the datasource declaration of twitter_search in the module is not visible in rulesets that use the module because it's not in the provides pragma.  However, the function search_twitter() is available and can use the twitter_search datasource because a module is a closure over the global values declared therein.

Module Configuration and Aliasing

The following example shows how module configuration and aliasing can be used effectively. 

The following ruleset defines a module that defines a function and two actions to interact with a data service called StringBin (a simple cloud-based key-value pair storage system). StringBin requires a developer pin.

Two important things to note in this module definition are the provide and configure pragmas. The provide pragma is followed by a list of names that will be available outside the module. Note that the datasource declaration sb_data is not provided to rulesets using the module and thus the implementation details are hidden. The only way to reach the datasource is using the provided function named read.

The configure keyword indicates the module parameters and their default values. In this case there is one parameter, the value of the developer pin. Any ruleset using this module must supply a pin or it won’t work since the default value is “nopin.”

We use a module by declaring its use in the meta section, giving any configuration parameters using a with clause. The use module pragma requires a ruleset name and an optional alias (StringBin in this case)

Later we can use one of the module’s actions in a rule like so:

This rule writes the value “mellow” to the StringBin store using the key “yellow.” Note that when we declared the module’s use we gave it an alias and the alias is used to namespace the action (StringBin:write() in this case)

Because modules are parameterized and can be aliased, you can use a given module multiple times in a single ruleset with different parameters. For example, suppose we had two StringBins and we wanted to copy a value out of one into the other. First, we declare the module’s use twice with different aliases and configurations:

Because we give each use of the StringBin module a different pin, they will reference different string bins. 

We can use the aliased modules to write a rule that copies data from BinA into BinB:

In this rule, we’ve read data from BinA and then written it to BinB. Of course, in a real rule to accomplish this, the key (“yellow”) would likely be computed from event parameters in some way.

Modules are Closures

Rulesets form closures over the value defined in them. This is true when the ruleset is used as a module as well. All variables are scoped statically, not dynamically, whether in the global variable bindings or inside rules. This applied to persistent variables as well. 

This has important implications for how rulesets that are also modules behave.   Here’s a detailed look at what this means. Suppose we defined the following ruleset:

The provides pragma in the meta section indicates that this ruleset is intended to be used as a module. Note that get_item() references an entity variable (ent:elements). An entity variable with the same name is mutated in the rule add_item. Because this ruleset will function as a closure over the value in  ent:elements, the value of ent:elements retrieved by get_item() is the same as the one mutates in the rule.

Module Caching

When a module is evaluated, a variable environment is created based on the declarations in the module and the module configuration. The environment is cached for performance reasons when possible. The performance benefits of module caching are substantial. 

Cachability

In general, as long as the global declarations in your module fall into the following categories, your module will be cachable:

  • function definitions
  • action definitions
  • literals
  • simple variables
  • expressions involving the preceding items

Any expression involving a persistent variable will not be cachable unless the persistent variable is wrapped in a function or action definition. Also, some specific built-in functions that have dynamic values cannot be cached. If your module cannot be cached, it will still work, but may perform poorly. Developers should work to ensure their modules are cachable. 

Don't Try to Fool the Caching Algorithm

You can wrap something that isn't cachable (such as a persistent variable) in a function to make it cachable and then immediately call the function, providing the result from the module (see the examples below). Why the system will determine that your module is cachable, the result provided will be stale if the wrapped persistent variable is updated since that will not invalidate the cache.

Examples

Is My Module Being Cached

If you turn logging on for a ruleset including your module, you'll be able to see whether or not your module is being cached in the debug information. 

 

 

Labels: