Skip to content

Commit

Permalink
Merge pull request #48 from aichaos/modernize
Browse files Browse the repository at this point in the history
Various modernization efforts
  • Loading branch information
kirsle authored Aug 16, 2023
2 parents e38f316 + f4d3c64 commit 5fe90d2
Show file tree
Hide file tree
Showing 12 changed files with 310 additions and 52 deletions.
79 changes: 79 additions & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,85 @@

This documents the history of significant changes to `rivescript-go`.

## v0.4.0 - Aug 15, 2023

This update will modernize the Go port of RiveScript bringing some of the
newer features that were available on the JavaScript or Python ports.

### The ?Keyword Command

This update adds support for the newer `?Keyword` command in RiveScript.

This command works around a Unicode matching bug that affected the
Go, JavaScript and Python ports of RiveScript. For example:

```rivescript
// You wanted this trigger to match if "你好" appears anywhere
// in a user's message, but it wasn't working before.
+ [*] 你好 [*]
- 你好!
// Now: use the ?Keyword command in place of +Trigger
? 你好
- 你好!
```

The optional wildcard `[*]` syntax didn't work when paired with Unicode
symbols because the regular expression that `[*]` is turned into (which
involves "word boundary" or `\b` characters) only worked with ASCII latin
characters. The ?Keyword command works around this by translating into a
+Trigger that tries _every_ combination of literal word, wildcard on either
or both sides, and optional wildcard, to ensure that your keyword trigger
will indeed match your keyword _anywhere_ in the user's message.

### CaseSensitive User Message Support

By default RiveScript would always lowercase the user's message as it
comes in. If this is undesirable and you'd like to preserve their _actual_
capitalization (when it gets captured by wildcards and comes out in their
`<star>` tags), provide the new CaseSensitive boolean to your RiveScript
constructor:

```go
bot := rivescript.New(&rivescript.Config{
CaseSensitive: true,
})
```

The built-in `rivescript` command line program adds a `-case` parameter
to enable this option for testing:

```bash
rivescript -case /path/to/brain
```

### JavaScript Object Macros

The official JavaScript object macro support library has a couple of
exciting new updates.

Firstly, the JavaScript engine has been replaced from
[github.com/robertkrimen/otto](https://github.com/robertkrimen/otto) with
[github.com/dop251/goja](https://github.com/dop251/goja) which should
provide a better quality of life for writing JavaScript functions for
your bot. Goja supports many of the modern ES6+ features including the
let and const keyword and arrow functions.

Additionally, the Goja runtime will be exposed at the `.VM` accessor
for the JavaScriptHandler class, so you can directly play with it and
set global variables or Go functions that can be called from your
JavaScript macros in your bot, allowing for much greater extensibility.

### Other Changes

* Add shellword parsing for `<call>` tags: you can pass "quoted strings"
in which will go in as one 'word' in the `args` array, instead of the
arguments being literally split by space characters. This brings the
Go port of RiveScript in line with the JavaScript port which has been
doing this for a while.
* Fix the rsts_test.go to properly load from the RSTS (RiveScript Test
Suite) git submodule.

## v0.3.1 - Aug 20, 2021

This release simply adds a `go.mod` to this project so that it gets along well
Expand Down
86 changes: 85 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ code to look up their answer via a web API.

The Go version of RiveScript has support for object macros written in Go
(at compile time of your application). It also has optional support for
JavaScript object macros using the Otto library.
JavaScript object macros using the [goja](https://github.com/dop251/goja) library.

Here is how to define a Go object macro:

Expand All @@ -166,6 +166,76 @@ bot.SetSubroutine(func(rs *rivescript.RiveScript, args []string) string {
})
```

### JavaScript Object Macros

Here is an example how to make JavaScript object macros available via
the [goja](https://github.com/dop251/goja) module:

```go
package main

import (
"fmt"
"github.com/aichaos/rivescript-go"
"github.com/aichaos/rivescript-go/lang/javascript"
)

func main() {
// Initialize RiveScript first.
bot := rivescript.New(rivescript.WithUTF8())

// Add the JavaScript object macro handler.
js := javascript.New(bot)
bot.SetHandler("javascript", js)

// You can access the goja VM and set your own global
// variable or function bindings to be called from your
// object macros.
js.VM.Set("helloFunc", func(name string) string {
return fmt.Sprintf("Hello, %s!", name)
})

// Load some RiveScript code. This example just tests the
// JavaScript object macro support.
err := bot.Stream(`
> object add javascript
let a = args[0];
let b = args[1];
return parseInt(a) + parseInt(b);
< object
> object fn javascript
let result = helloFunc(args[0])
return result
< object
+ add # and #
- <star1> + <star2> = <call>add <star1> <star2></call>
+ say hello *
- <call>fn <star></call>
`)
if err != nil {
fmt.Printf("Error loading RiveScript document: %s", err)
}

// Sort the replies after loading them!
bot.SortReplies()

// Get some replies!
inputs := []string{"add 5 and 12", "say hello goja"}
for _, message := range inputs {
fmt.Printf("You said: %s\n", message)
reply, err := bot.Reply("local-user", message)
if err != nil {
fmt.Printf("Error: %s\n", err)
} else {
fmt.Printf("The bot says: %s\n", reply)
}
}
}
```

## UTF-8 Support

UTF-8 support in RiveScript is considered an experimental feature. It is
Expand Down Expand Up @@ -216,6 +286,20 @@ relevant commands are:
* `make test` - runs the unit tests.
* `make clean` - cleans up the `.gopath`, `bin` and `dist` directories.

### Testing

The rivescript-go repo submodules the RiveScript Test Suite (rsts) project.
If you didn't do a `git clone --recursive` for rivescript-go you can pull the
submodule via the following commands:

```bash
git submodule init
git submodule update
```

Then `make test` (or `go test`) should show results from the tests run
out of the rsts/ folder.

### Releasing

You can build a release for an individual platform by running a command like
Expand Down
23 changes: 13 additions & 10 deletions cmd/rivescript/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,21 @@ var Build = "-unknown-"

var (
// Command line arguments.
version bool
debug bool
utf8 bool
depth uint
nostrict bool
nocolor bool
version bool
debug bool
utf8 bool
depth uint
caseSensitive bool
nostrict bool
nocolor bool
)

func init() {
flag.BoolVar(&version, "version", false, "Show the version number and exit.")
flag.BoolVar(&debug, "debug", false, "Enable debug mode.")
flag.BoolVar(&utf8, "utf8", false, "Enable UTF-8 mode.")
flag.UintVar(&depth, "depth", 50, "Recursion depth limit")
flag.BoolVar(&caseSensitive, "case", false, "Enable the CaseSensitive flag, preserving capitalization in user messages")
flag.BoolVar(&nostrict, "nostrict", false, "Disable strict syntax checking")
flag.BoolVar(&nocolor, "nocolor", false, "Disable ANSI colors")
}
Expand All @@ -68,10 +70,11 @@ func main() {

// Initialize the bot.
bot := rivescript.New(&rivescript.Config{
Debug: debug,
Strict: !nostrict,
Depth: depth,
UTF8: utf8,
Debug: debug,
Strict: !nostrict,
Depth: depth,
UTF8: utf8,
CaseSensitive: caseSensitive,
})

// JavaScript object macro handler.
Expand Down
5 changes: 5 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ type Config struct {
// RiveScript to choose its own seed, `time.Now().UnixNano()`
Seed int64

// Preserve the capitalization on a user's message instead of lowercasing it.
// By default RiveScript will lowercase all messages coming in - set this and
// the original casing will be preserved through wildcards and star tags.
CaseSensitive bool

// SessionManager is an implementation of the same name for managing user
// variables for the bot. The default is the in-memory session handler.
SessionManager sessions.SessionManager
Expand Down
12 changes: 6 additions & 6 deletions eg/brain/javascript.rive
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
> object setvar javascript
// Example of how to get the current user's ID and set
// variables for them.
var uid = rs.CurrentUser();
var name = args[0];
var value = args[1];
let uid = rs.CurrentUser();
let name = args[0];
let value = args[1];
rs.SetUservar(uid, name, value);
< object

> object add javascript
// Demonstrats that JS objects can return numbers.
var a = args[0];
var b = args[1];
let a = args[0];
let b = args[1];
return parseInt(a) + parseInt(b);
< object

+ add # and #
- <star1> + <star2> = <call>add <star1> <star2></call>

+ javascript set * to *
- Set user variable <star1> to <star2>.<call>setvar <star1> <star2></call>
- Set user variable <star1> to <star2>.<call>setvar <star1> "<star2>"</call>
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ module github.com/aichaos/rivescript-go
go 1.16

require (
github.com/dop251/goja v0.0.0-20230812105242-81d76064690d // indirect
github.com/mattn/go-shellwords v1.0.12 // indirect
github.com/onsi/gomega v1.15.0 // indirect
github.com/robertkrimen/otto v0.0.0-20211024170158-b87d35c0b86f
github.com/robertkrimen/otto v0.2.1
golang.org/x/text v0.12.0 // indirect
gopkg.in/redis.v5 v5.2.9
gopkg.in/yaml.v2 v2.4.0
)
Loading

0 comments on commit 5fe90d2

Please sign in to comment.