Skip to content

Commit

Permalink
Add custom error messages, reorganize tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kirsle committed Mar 28, 2016
1 parent 0a8479d commit 0584e7b
Show file tree
Hide file tree
Showing 20 changed files with 1,443 additions and 1,152 deletions.
2 changes: 1 addition & 1 deletion Gruntfile.coffee
Expand Up @@ -74,4 +74,4 @@ module.exports = (grunt) ->
grunt.registerTask "dist", ["coffee", "browserify", "uglify"]
grunt.registerTask "server", ["dist", "connect:server"]
grunt.registerTask "lint", ["coffeelint"]
grunt.registerTask "test", ["nodeunit"]
grunt.registerTask "test", ["coffee", "nodeunit"]
9 changes: 7 additions & 2 deletions README.md
Expand Up @@ -9,8 +9,13 @@ scripting language for chatterbots, making it easy to write trigger/response
pairs for building up a bot's intelligence.

This library can be used both in a web browser or as a Node module.
See the `eg/` folder for a web browser example. There's a `node/` folder with
an example Node TCP server.
See the `eg/` folder for examples.

## DOCUMENTATION

[Documentation](https://github.com/aichaos/rivescript-js/tree/master/docs) for
the module's API is available in the `docs/` directory and is browseable in
Markdown and HTML format.

## INSTALLATION

Expand Down
17 changes: 17 additions & 0 deletions docs/README.md
@@ -0,0 +1,17 @@
# RiveScript.js Documentation

This provides documentation for the RiveScript JS module.

You probably want the public facing API: [RiveScript](./rivescript.md)

The rest of the documentation covers internal modules and functions which aren't
necessarily available over the public API.

* [rivescript.RiveScript](./rivescript.md)
* [rivescript.Brain](./brain.md)
* [rivescript.inheritance](./inheritance.md)
* [rivescript.lang.coffee](./lang.coffee.md)
* [rivescript.lang.javascript](./lang.javascript.md)
* [rivescript.Parser](./parser.md)
* [rivescript.sorting](./sorting.md)
* [rivescript.utils](./utils.md)
48 changes: 47 additions & 1 deletion docs/html/rivescript.html
Expand Up @@ -15,6 +15,7 @@ <h1>RiveScript (hash options)</h1>
<li>bool strict: Strict mode (default true)</li>
<li>bool utf8: Enable UTF-8 mode (default false)</li>
<li>func onDebug: Set a custom handler to catch debug log messages (default null)</li>
<li>obj errors: Customize certain error messages (see below)</li>
</ul>
<h2>UTF-8 Mode</h2>
<p>In UTF-8 mode, most characters in a user's message are left intact, except for
Expand All @@ -27,6 +28,51 @@ <h2>UTF-8 Mode</h2>
bot.unicodePunctuation = new RegExp(/[.,!?;:]/g);</code></pre>


<h2>Custom Error Messages</h2>
<p>You can provide any or all of the following properties in the <code>errors</code>
argument to the constructor to override certain internal error messages:</p>
<ul>
<li><code>replyNotMatched</code>: The message returned when the user's message does not
match any triggers in your RiveScript code.</li>
</ul>
<p>The default is "ERR: No Reply Matched"</p>
<p><strong>Note:</strong> the recommended way to handle this case is to provide a trigger of
simply <code>*</code>, which serves as the catch-all trigger and is the default one
that will match if nothing else matches the user's message. Example:</p>
<p><code>+ *
- I don't know what to say to that!</code>
<em> <code>replyNotFound</code>: This message is returned when the user </em>did* in fact match
a trigger, but no response was found for the user. For example, if a trigger
only checks a set of conditions that are all false and provides no "normal"
reply, this error message is given to the user instead.</p>
<p>The default is "ERR: No Reply Found"</p>
<p><strong>Note:</strong> the recommended way to handle this case is to provide at least one
normal reply (with the <code>-</code> command) to every trigger to cover the cases
where none of the conditions are true. Example:</p>
<p><code>+ hello
* &lt;get name&gt; != undefined =&gt; Hello there, &lt;get name&gt;.
- Hi there.</code>
* <code>objectNotFound</code>: This message is inserted into the bot's reply in-line when
it attempts to call an object macro which does not exist (for example, its
name was invalid or it was written in a programming language that the bot
couldn't parse, or that it had compile errors).</p>
<p>The default is "[ERR: Object Not Found]"
* <code>deepRecursion</code>: This message is inserted when the bot encounters a deep
recursion situation, for example when a reply redirects to a trigger which
redirects back to the first trigger, creating an infinite loop.</p>
<p>The default is "ERR: Deep Recursion Detected"</p>
<p>These custom error messages can be provided during the construction of the
RiveScript object, or set afterwards on the object's <code>errors</code> property.</p>
<p>Examples:</p>
<pre class="codehilite"><code class="language-javascript">var bot = new RiveScript({
errors: {
replyNotFound: &quot;I don't know how to reply to that.&quot;
}
});

bot.errors.objectNotFound = &quot;Something went terribly wrong.&quot;;</code></pre>


<h1>Constructor and Debug Methods</h1>
<h2>string version ()</h2>
<p>Returns the version number of the RiveScript.js library.</p>
Expand Down Expand Up @@ -68,7 +114,7 @@ <h2>int loadFile (string path || array path[, onSuccess[, onError]])</h2>
<p><code>onSuccess</code> receives: int batchNumber
<code>onError</code> receives: string errorMessage[, int batchNumber]</p>
<h2>void loadDirectory (string path[, func onSuccess[, func onError]])</h2>
<p>Load RiveScript documents from a directory.</p>
<p>Load RiveScript documents from a directory recursively.</p>
<p>This function is not supported in a web environment.</p>
<h2>bool stream (string code[, func onError])</h2>
<p>Stream in RiveScript code dynamically. <code>code</code> should be the raw RiveScript
Expand Down
64 changes: 63 additions & 1 deletion docs/rivescript.md
Expand Up @@ -8,6 +8,7 @@ following keys:
* bool strict: Strict mode (default true)
* bool utf8: Enable UTF-8 mode (default false)
* func onDebug: Set a custom handler to catch debug log messages (default null)
* obj errors: Customize certain error messages (see below)

## UTF-8 Mode

Expand All @@ -24,6 +25,67 @@ var bot = new RiveScript({utf8: true});
bot.unicodePunctuation = new RegExp(/[.,!?;:]/g);
```

## Custom Error Messages

You can provide any or all of the following properties in the `errors`
argument to the constructor to override certain internal error messages:

* `replyNotMatched`: The message returned when the user's message does not
match any triggers in your RiveScript code.

The default is "ERR: No Reply Matched"

**Note:** the recommended way to handle this case is to provide a trigger of
simply `*`, which serves as the catch-all trigger and is the default one
that will match if nothing else matches the user's message. Example:

```
+ *
- I don't know what to say to that!
```
* `replyNotFound`: This message is returned when the user *did* in fact match
a trigger, but no response was found for the user. For example, if a trigger
only checks a set of conditions that are all false and provides no "normal"
reply, this error message is given to the user instead.

The default is "ERR: No Reply Found"

**Note:** the recommended way to handle this case is to provide at least one
normal reply (with the `-` command) to every trigger to cover the cases
where none of the conditions are true. Example:

```
+ hello
* <get name> != undefined => Hello there, <get name>.
- Hi there.
```
* `objectNotFound`: This message is inserted into the bot's reply in-line when
it attempts to call an object macro which does not exist (for example, its
name was invalid or it was written in a programming language that the bot
couldn't parse, or that it had compile errors).

The default is "[ERR: Object Not Found]"
* `deepRecursion`: This message is inserted when the bot encounters a deep
recursion situation, for example when a reply redirects to a trigger which
redirects back to the first trigger, creating an infinite loop.

The default is "ERR: Deep Recursion Detected"

These custom error messages can be provided during the construction of the
RiveScript object, or set afterwards on the object's `errors` property.

Examples:

```javascript
var bot = new RiveScript({
errors: {
replyNotFound: "I don't know how to reply to that."
}
});

bot.errors.objectNotFound = "Something went terribly wrong.";
```

# Constructor and Debug Methods

## string version ()
Expand Down Expand Up @@ -85,7 +147,7 @@ argument, in case you want to correlate it with your call to `loadFile()`.

## void loadDirectory (string path[, func onSuccess[, func onError]])

Load RiveScript documents from a directory.
Load RiveScript documents from a directory recursively.

This function is not supported in a web environment.

Expand Down
20 changes: 10 additions & 10 deletions src/brain.coffee
Expand Up @@ -110,7 +110,7 @@ class Brain
break

text = utils.strip(match[1])

# get subroutine name
subroutineNameMatch = (/(\S+)/ig).exec(text)
subroutineName = subroutineNameMatch[0]
Expand Down Expand Up @@ -142,7 +142,7 @@ class Brain
else
output = "[ERR: No Object Handler]"
else
output = "[ERR: Object Not Found]"
output = @master.errors.objectNotFound

# if we get a promise back and we are not in the async mode,
# leave an error message to suggest using an async version of rs
Expand Down Expand Up @@ -185,7 +185,7 @@ class Brain
doubleQuoteRe = /"/ig

flushBuffer = () ->
if buff.length isnt 0
if buff.length isnt 0
result.push(buff)
buff = ""

Expand All @@ -208,7 +208,7 @@ class Brain
# wrap arguments inside <call></call> in {__call_arg__}{/__call_arg__}
callRegEx = /<call>\s*(.*?)\s*<\/call>/ig
callArgsRegEx = /<call>\s*[^\s]+ (.*)<\/call>/ig

callSignatures = []

while true
Expand All @@ -224,20 +224,20 @@ class Brain
argsMatch = callArgsRegEx.exec(originalCallSignature)
if not argsMatch
break

originalArgs = argsMatch[1]
args = @_parseCallArgsString(originalArgs)
wrappedArgs = []

for a in args
wrappedArgs.push "{__call_arg__}#{a}{/__call_arg__}"

wrappedCallSignature = wrappedCallSignature.replace(originalArgs,
wrappedCallSignature = wrappedCallSignature.replace(originalArgs,
wrappedArgs.join(' '))

callSignatures.push
original: originalCallSignature
wrapped: wrappedCallSignature
wrapped: wrappedCallSignature

for cs in callSignatures
reply = reply.replace cs.original, cs.wrapped
Expand Down Expand Up @@ -277,7 +277,7 @@ class Brain

# Avoid deep recursion.
if step > @master._depth
return "ERR: Deep Recursion Detected"
return @master.errors.deepRecursion

# Are we in the BEGIN block?
if context is "begin"
Expand Down Expand Up @@ -506,9 +506,9 @@ class Brain

# Still no reply?
if not foundMatch
reply = "ERR: No Reply Matched"
reply = @master.errors.replyNotMatched
else if reply is undefined or reply.length is 0
reply = "ERR: No Reply Found"
reply = @master.errors.replyNotFound

@say "Reply: #{reply}"

Expand Down
2 changes: 1 addition & 1 deletion src/lang/coffee.coffee
Expand Up @@ -48,7 +48,7 @@ class CoffeeObjectHandler
call: (rs, name, fields, scope) ->
# We have it?
if not @_objects[name]
return "[ERR: Object Not Found]"
return @_master.errors.objectNotFound

# Call the dynamic method.
func = @_objects[name]
Expand Down
2 changes: 1 addition & 1 deletion src/lang/javascript.coffee
Expand Up @@ -50,7 +50,7 @@ class JSObjectHandler
call: (rs, name, fields, scope) ->
# We have it?
if not @_objects[name]
return "[ERR: Object Not Found]"
return @_master.errors.objectNotFound

# Call the dynamic method.
func = @_objects[name]
Expand Down
74 changes: 74 additions & 0 deletions src/rivescript.coffee
Expand Up @@ -30,6 +30,7 @@ readDir = require("fs-readdir-recursive")
# * bool strict: Strict mode (default true)
# * bool utf8: Enable UTF-8 mode (default false)
# * func onDebug: Set a custom handler to catch debug log messages (default null)
# * obj errors: Customize certain error messages (see below)
#
# ## UTF-8 Mode
#
Expand All @@ -45,6 +46,68 @@ readDir = require("fs-readdir-recursive")
# var bot = new RiveScript({utf8: true});
# bot.unicodePunctuation = new RegExp(/[.,!?;:]/g);
# ```
#
# ## Custom Error Messages
#
# You can provide any or all of the following properties in the `errors`
# argument to the constructor to override certain internal error messages:
#
# * `replyNotMatched`: The message returned when the user's message does not
# match any triggers in your RiveScript code.
#
# The default is "ERR: No Reply Matched"
#
# **Note:** the recommended way to handle this case is to provide a trigger of
# simply `*`, which serves as the catch-all trigger and is the default one
# that will match if nothing else matches the user's message. Example:
#
# ```
# + *
# - I don't know what to say to that!
# ```
# * `replyNotFound`: This message is returned when the user *did* in fact match
# a trigger, but no response was found for the user. For example, if a trigger
# only checks a set of conditions that are all false and provides no "normal"
# reply, this error message is given to the user instead.
#
# The default is "ERR: No Reply Found"
#
# **Note:** the recommended way to handle this case is to provide at least one
# normal reply (with the `-` command) to every trigger to cover the cases
# where none of the conditions are true. Example:
#
# ```
# + hello
# * <get name> != undefined => Hello there, <get name>.
# - Hi there.
# ```
# * `objectNotFound`: This message is inserted into the bot's reply in-line when
# it attempts to call an object macro which does not exist (for example, its
# name was invalid or it was written in a programming language that the bot
# couldn't parse, or that it had compile errors).
#
# The default is "[ERR: Object Not Found]"
# * `deepRecursion`: This message is inserted when the bot encounters a deep
# recursion situation, for example when a reply redirects to a trigger which
# redirects back to the first trigger, creating an infinite loop.
#
# The default is "ERR: Deep Recursion Detected"
#
# These custom error messages can be provided during the construction of the
# RiveScript object, or set afterwards on the object's `errors` property.
#
# Examples:
#
# ```javascript
# var bot = new RiveScript({
# errors: {
# replyNotFound: "I don't know how to reply to that."
# }
# });
#
# bot.errors.objectNotFound = "Something went terribly wrong.";
# ```
#
##
class RiveScript

Expand All @@ -66,6 +129,17 @@ class RiveScript
# UTF-8 punctuation, overridable by the user.
@unicodePunctuation = new RegExp(/[.,!?;:]/g)

# Customized error messages.
@errors =
replyNotMatched: "ERR: No Reply Matched"
replyNotFound: "ERR: No Reply Found"
objectNotFound: "[ERR: Object Not Found]"
deepRecursion: "ERR: Deep Recursion Detected"
if typeof(opts.errors) is "object"
for key, value of opts.errors
if opts.errors.hasOwnProperty(key)
@errors[key] = value

# Identify our runtime environment. Web, or node?
@_node = {} # NodeJS objects
@_runtime = @runtime()
Expand Down

0 comments on commit 0584e7b

Please sign in to comment.