Skip to content

Commit b91a80c

Browse files
committed
Add Perl object handler example
Move the JavaScript object macro example to eg/js-objects. Create eg/perl-objects containing an extremely hackish example of how to get Perl object macro support for RiveScript-Python. Fix the way object handlers work on the back-end so that RiveScript will pass the user's ID along with the call request.
1 parent 62c893b commit b91a80c

7 files changed

Lines changed: 173 additions & 3 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def load(self, name, code):
1414
source = "function RSOBJ_" + name + "(args) {\n" + "\n".join(code) + "}\n"
1515
self._objects[name] = source
1616

17-
def call(self, rs, name, fields):
17+
def call(self, rs, name, user, fields):
1818
if not name in self._objects:
1919
return "[Object Not Found]"
2020

eg/perl-objects/accomplice.pl

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/perl
2+
3+
# The bridge between Python and Perl ;)
4+
5+
use strict;
6+
use warnings;
7+
use RiveScript;
8+
use JSON;
9+
10+
my $json = JSON->new->utf8;
11+
12+
# Read input from Python.
13+
my $input;
14+
while (my $line = <STDIN>) {
15+
$input .= $line;
16+
}
17+
18+
# JSON-decode it.
19+
my $data;
20+
eval {
21+
$data = $json->decode($input);
22+
};
23+
if ($@) {
24+
error("Invalid JSON data!");
25+
}
26+
27+
# Make sure all required fields are there.
28+
foreach my $key (qw(code vars id message)) {
29+
if (!exists $data->{$key}) {
30+
error("Required JSON key '$key' doesn't exist!");
31+
}
32+
}
33+
34+
# Set up RiveScript.
35+
my $rs = RiveScript->new(debug=>0);
36+
my $code = $data->{code};
37+
$rs->stream(qq{
38+
+ *
39+
- <call>handle <star></call>
40+
41+
> object handle perl
42+
$code
43+
< object
44+
});
45+
$rs->sortReplies();
46+
47+
# Set all the user vars.
48+
foreach my $var (keys %{$data->{vars}}) {
49+
$rs->setUservar($data->{id}, $var, $data->{vars}->{$var});
50+
}
51+
52+
# Get the reply.
53+
my $reply = $rs->reply($data->{id}, $data->{message});
54+
55+
# Recover the new user vars.
56+
my $raw = $rs->getUservars($data->{id});
57+
my $vars = {};
58+
foreach my $key (keys %{$raw}) {
59+
next if ref($raw->{$key});
60+
$vars->{$key} = $raw->{$key};
61+
}
62+
63+
my $out = {
64+
status => 'ok',
65+
reply => $reply,
66+
vars => $vars,
67+
};
68+
69+
print $json->encode($out);
70+
exit(0);
71+
72+
sub error {
73+
my $mess = shift;
74+
print $json->encode({
75+
status => 'error',
76+
message => $mess,
77+
});
78+
exit(0);
79+
}

eg/perl-objects/perl.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#!/usr/bin/env python
2+
3+
# Example for how to set a Perl object handler.
4+
5+
import rivescript
6+
from json import dumps, loads
7+
from subprocess import Popen, PIPE
8+
9+
class PerlObject:
10+
"""A Perl object handler for RiveScript."""
11+
_objects = {} # The cache of objects loaded
12+
13+
def load(self, name, code):
14+
"""Prepare a Perl code object given by the RS interpreter."""
15+
16+
source = "\n".join(code)
17+
self._objects[name] = source
18+
19+
def call(self, rs, name, user, fields):
20+
if not name in self._objects:
21+
return "[ERR: Object Not Found]"
22+
23+
# JSON data to send to Perl.
24+
outgoing = dict(
25+
id=user,
26+
message=" ".join(fields),
27+
code=self._objects[name],
28+
vars={},
29+
)
30+
31+
# Copy their current user vars over.
32+
vars = rs.get_uservars(user)
33+
for key, value in vars.iteritems():
34+
if type(value) != str:
35+
continue
36+
outgoing['vars'][key] = value
37+
38+
# Fire up Perl and give it all this data.
39+
proc = Popen(["perl", "accomplice.pl"], stdin=PIPE, stdout=PIPE)
40+
proc.stdin.write(dumps(outgoing))
41+
proc.stdin.close()
42+
result = proc.stdout.read()
43+
44+
# Hopefully that was JSON data we got!
45+
try:
46+
result = loads(result)
47+
except:
48+
return "[ERR: Got an unexpected result from Perl!]"
49+
50+
# OK?
51+
if result['status'] == 'error':
52+
return "[ERR: %s]" % result['message']
53+
54+
# Restore user variables from Perl, in case it changed anything.
55+
for key, value in result['vars'].iteritems():
56+
if type(value) != str:
57+
continue
58+
rs.set_uservar(user, key, value)
59+
60+
return result['reply']
61+
62+
bot = rivescript.RiveScript()
63+
bot.set_handler("perl", PerlObject())
64+
bot.load_file("perl.rs")
65+
bot.sort_replies()
66+
while True:
67+
msg = raw_input("You> ")
68+
reply = bot.reply("localuser", msg)
69+
print "Bot>", reply
70+
71+
# vim:expandtab

eg/perl-objects/perl.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Perl Object Example
2+
3+
> object add perl
4+
my ($rs, @args) = @_;
5+
return $args[0] + $args[1];
6+
< object
7+
8+
> object md5sum perl
9+
my ($rs, @args) = @_;
10+
use Digest::MD5 qw(md5_hex);
11+
return md5_hex(join(" ", @args));
12+
< object
13+
14+
// Say "add 5 plus 7"
15+
+ add * plus *
16+
- <star1> + <star2> = <call>add <star1> <star2></call>
17+
18+
// Say "hash something in md5"
19+
+ hash * in md5
20+
- MD5 hash: <call>md5sum <star></call>

rivescript/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1796,7 +1796,7 @@ def _process_tags(self, user, msg, reply, st=[], bst=[], depth=0):
17961796
lang = self._objlangs[obj]
17971797
if lang in self._handlers:
17981798
# We do.
1799-
output = self._handlers[lang].call(self, obj, args)
1799+
output = self._handlers[lang].call(self, obj, user, args)
18001800
else:
18011801
output = '[ERR: No Object Handler]'
18021802
else:

rivescript/python.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def load(self, name, code):
4646
print("Failed to load code from object", name)
4747
print("The error given was: ", e)
4848

49-
def call(self, rs, name, fields):
49+
def call(self, rs, name, user, fields):
5050
"""Invoke a previously loaded object."""
5151
# Call the dynamic method.
5252
func = self._objects[name]

0 commit comments

Comments
 (0)