RiveScript as a Router
This example was created in response to the discussion in Issue #130 about using RiveScript as a router (in the web application sense of the word).
In web applications, you define routes (URIs) and function handlers to be called when a browser requests that route.
object macro handlers for many, many triggers, and you don't want to keep
<call> commands over and over again, this example offers an idea
for doing this in a D.R.Y.
This example covers multiple useful things:
controllers.js), without needing to repeatedly
require()them every single time in every macro handler.
- Defining triggers that directly map to your object macros without needing to
manually re-write the
<call>tags multiple times.
- Using the RiveScript engine (with its simplified regexp triggers and its sorting algorithm) without actually writing a single line of RiveScript code by hand.
This example doesn't cover, but it is possible, mixing a router-style approach
with normal RiveScript replies. For example, separately from all the code that
registers "routes" to handlers you could include a normal
loadDirectory() call, and load normal RiveScript sources that have their own
normal replies with them instead of needing to call function handlers for every
Run the Example
To run this, first run
grunt dist from the root of the rivescript-js project
and then run
[rivescript-js]$ grunt dist [rivescript-js]$ cd eg/router [router]$ node router.js
% node router.js Note: type `/quit` to exit. You> hello bot [Captain's Log] Unhandled message: hello bot Bot> No reply for that one. Try one of these: add 5 and 7 what is 12 divided by 3 reverse hello world say hi robot to me backwards You> add 5 and 7 Bot> 12 You> reverse how are you? Bot> uoy era woh You> say hi robot to me backwards Bot> tobor ih
How it Works
Review the source of
router.js, the entry point to this example bot.
replies object is where most of the magic happens. It creates simple
function to be called when one of those triggers is matched. The actual
implementations of the two functions exposed (
reverse) are in
controllers.js, which is an external Node module, and this demonstrates that
a module imported once in the global scope can be made available to the
individual object macros without each of them needing to import their own
At the bottom of
router.js is some "write once" boilerplate that iterates
replies object and dynamically creates RiveScript source code
The dynamically generated RiveScript source is loaded by the bot using the
stream() function, which allows you to import RiveScript source from a string
rather than a file. This way, the bot writer doesn't actually need to write a
single line of raw RiveScript code herself. An example of the dynamically
generated RiveScript code looks like this:
+ [*] what is # * [by|to|and] # - <call>math "<star1>" "<star2>" "<star3>"</call>
But you don't ever actually write that code out yourself!
The router example then enters a readline loop, similar to the
the root of the RiveScript-JS project, to enable chatting with the bot using
For this example, we make three functions available:
wildcard. Here are examples of how to invoke these with your messages:
add 5 and 7
what is 12 divided by 3
what is 4 times 8
what is 6 multiplied by 12
subtract 13 by 4
say hello to me backwards
say how are you in reverse
- Literally any message that doesn't match the other patterns.
The wildcard handler matches all uncaught messages (
*), and gives you examples
of messages to try the other handlers.