Skip to content
codeaspects edited this page Sep 14, 2010 · 2 revisions

Le Tigre is one of the syntaxes in The Ruleby DSL. It defines four parameters for the rule method:

  1. An optional Symbol that is a unique identifier for the rule
  2. An optional Hash that contains rule attribute (such as priority)
  3. A variable number of Strings representing patterns (the “left hand side”)
  4. A block that will be executed if the rule is satisfied (the “right hand side”)

This syntax is designed to be very human readable, and as a result looks a little like SQL. The following is an example:


rule :hello, ‘For each Message as :m where #status == :HELLO’ do |context|
puts context[:m].message
end

This rule defines a pattern that checks for the existence of a Message object with a status property that is equal to :HELLO. The block parameter will be executed for each object that this pattern matches.

=The Left Hand Side=
The most important part of the example above is the content of the String parameter, which represents the left hand side of the rule. Each String begins with a universal quantifier. The example above uses 'For each' but it could use one of the variations accepted by the DSL. These are explained later on in the article.

Following the universal quantifier is a class name and an optional variable name that it is bound to:


Message as :m

This binding allows us to reference the value in another part of the rule.

Following the class and its binding is the where clause. This part of the pattern is optional. It is only needed if there are certain conditions you need to add to the pattern. The example above has one condition:


#status == :HELLO

The # symbol is used to denote that the following value is a method of the class we defined previously. If our rule had more conditions, we could string them together with the #&& symbol. For example:

#status == :HELLO #&& #message == ‘Hello World!’

The #&& operator, which reads as ‘and’, provides a logical concatenation of the conditions.

Bindings
We can bind the values that methods return to variables in the same way that we bound the object to a variable. This is done again with the as command. For example:


#status == :HELLO as :s

This would allow us to reference the :s variable later on in the rule. For example:

#message == #:s

We again use the # character. But this time it is followed by a symbol rather than a method. This symbol is replaced by the value of the status method when the pattern is compared to a fact.

Conditions
The conditions in the where clause are translated into Ruby blocks by the interpreter. Thus, the only requirement is that they must evaluate to true or false. Aside from that, we can do anything in these condition that we can do in Ruby. For example:


#status.reverse =~ /[aeiou](.)\\1/

You can also invoke methods on the variables you reference:

#message == #:s.capitalize

=The Right Hand Side=
The block parameter to the rule method is less complicated that the left hand side. It is simply a block of Ruby code that will be executed each time the rule is matched. This block has two parameters:
  1. engine – a handle to the Engine object (used for asserting and retracting facts)
  2. context – a Hash of bound variables that can be used in the block.

Of course, these parameters can be named whatever the developer desires to call them.

=Rule Attributes=
The Hash that contains the rule attributes typically looks something like the following example:


{ :priority => 5 }

At this time, the only rule attribute that Ruleby supports is :priority (a.k.a. ‘salience’).

=Quantifiers=
The quantifiers that begin a pattern in Le Tigre are as follows:

  • For each
  • not?
  • If there exists and exists?

The ‘For each’ quantifier means that the rule’s action (the right hand side) will be executed for each fact in working memory that the pattern matches.

The not? quantifier is an “existential quantifier”http://en.wikipedia.org/wiki/Existential_quantification that checks for the non-existence of a fact in working memory.

‘If there exists’ and exists? have the same semantics. They are existential qualifiers that check for the existence of something in working memory. With this qualifier, the rule’s action will only execute once regardless of how many facts in working memory match the pattern.

In no quantifier is specified, then Ruleby defaults to using 'For each'.

Clone this wiki locally