rivescript 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Changes.md +13 -0
- data/LICENSE +22 -0
- data/README.md +131 -0
- data/bin/riveshell +81 -0
- data/eg/brain/admin.rive +15 -0
- data/eg/brain/begin.rive +190 -0
- data/eg/brain/clients.rive +72 -0
- data/eg/brain/eliza.rive +301 -0
- data/eg/brain/myself.rive +61 -0
- data/eg/brain/rpg.rive +294 -0
- data/lib/rivescript/brain.rb +986 -0
- data/lib/rivescript/inheritance.rb +105 -0
- data/lib/rivescript/lang/ruby.rb +72 -0
- data/lib/rivescript/parser.rb +581 -0
- data/lib/rivescript/sessions.rb +205 -0
- data/lib/rivescript/sorting.rb +158 -0
- data/lib/rivescript/utils.rb +116 -0
- data/lib/rivescript/version.rb +9 -0
- data/lib/rivescript.rb +460 -0
- metadata +69 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# RiveScript Ruby port, https://jvmlab.org/, MIT License
|
|
2
|
+
|
|
3
|
+
# Topic inheritance functions.
|
|
4
|
+
#
|
|
5
|
+
# Helper functions to assist with topic inheritance and includes.
|
|
6
|
+
|
|
7
|
+
require_relative "utils"
|
|
8
|
+
|
|
9
|
+
class RiveScript
|
|
10
|
+
module Inheritance
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
# Recursively scan through a topic and retrieve a listing of all triggers in
|
|
14
|
+
# that topic and in all included/inherited topics. Some triggers will come out
|
|
15
|
+
# with an {inherits} tag to signify inheritance depth.
|
|
16
|
+
def get_topic_triggers(rs, topic, thats = false, depth = 0, inheritance = 0, inherited = false)
|
|
17
|
+
rs_depth = rs._depth
|
|
18
|
+
rs_topics = rs._topics
|
|
19
|
+
rs_thats = rs._thats
|
|
20
|
+
rs_includes = rs._includes
|
|
21
|
+
rs_inherits = rs._inherits
|
|
22
|
+
|
|
23
|
+
if depth > rs_depth
|
|
24
|
+
rs.warn("Deep recursion while scanning topic inheritance (gave up in topic #{topic})!")
|
|
25
|
+
return []
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
rs.say("Collecting trigger list for topic #{topic} (depth=#{depth}; inheritance=#{inheritance}; inherited=#{inherited})")
|
|
29
|
+
|
|
30
|
+
if rs_topics[topic].nil?
|
|
31
|
+
rs.warn("Inherited or included topic '#{topic}' doesn't exist or has no triggers")
|
|
32
|
+
return []
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
triggers = []
|
|
36
|
+
in_this_topic = []
|
|
37
|
+
|
|
38
|
+
unless thats
|
|
39
|
+
rs_topics[topic]&.each do |trigger|
|
|
40
|
+
in_this_topic.push([trigger["trigger"], trigger])
|
|
41
|
+
end
|
|
42
|
+
else
|
|
43
|
+
rs_thats[topic]&.each do |_cur_trig, previous_map|
|
|
44
|
+
previous_map.each do |_previous, pointer|
|
|
45
|
+
in_this_topic.push([pointer["trigger"], pointer])
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
includes = rs_includes[topic] || {}
|
|
51
|
+
if includes.any?
|
|
52
|
+
includes.each_key do |inc|
|
|
53
|
+
rs.say("Topic #{topic} includes #{inc}")
|
|
54
|
+
triggers.concat(get_topic_triggers(rs, inc, thats, depth + 1, inheritance + 1, false))
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
inherits = rs_inherits[topic] || {}
|
|
59
|
+
if inherits.any?
|
|
60
|
+
inherits.each_key do |inh|
|
|
61
|
+
rs.say("Topic #{topic} inherits #{inh}")
|
|
62
|
+
triggers.concat(get_topic_triggers(rs, inh, thats, depth + 1, inheritance + 1, true))
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
topic_inherits = rs_inherits[topic] || {}
|
|
67
|
+
if topic_inherits.any? || inherited
|
|
68
|
+
in_this_topic.each do |trigger|
|
|
69
|
+
rs.say("Prefixing trigger with {inherits=#{inheritance}} #{trigger}")
|
|
70
|
+
triggers.push(["{inherits=#{inheritance}}#{trigger[0]}", trigger[1]])
|
|
71
|
+
end
|
|
72
|
+
else
|
|
73
|
+
triggers.concat(in_this_topic)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
triggers
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Given a topic, return an array of every topic related to it (all topics it
|
|
80
|
+
# includes or inherits, plus all topics included or inherited by those topics,
|
|
81
|
+
# and so on). The array includes the original topic, too.
|
|
82
|
+
def get_topic_tree(rs, topic, depth = 0)
|
|
83
|
+
rs_depth = rs._depth
|
|
84
|
+
rs_includes = rs._includes
|
|
85
|
+
rs_inherits = rs._inherits
|
|
86
|
+
|
|
87
|
+
if depth > rs_depth
|
|
88
|
+
rs.warn("Deep recursion while scanning topic tree!")
|
|
89
|
+
return []
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
topics = [topic]
|
|
93
|
+
|
|
94
|
+
(rs_includes[topic] || {}).each_key do |inc|
|
|
95
|
+
topics.concat(get_topic_tree(rs, inc, depth + 1))
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
(rs_inherits[topic] || {}).each_key do |inh|
|
|
99
|
+
topics.concat(get_topic_tree(rs, inh, depth + 1))
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
topics
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# RiveScript Ruby port
|
|
4
|
+
# Byte <byte@jvmlab.org>, https://jvmlab.org/
|
|
5
|
+
# MIT License
|
|
6
|
+
|
|
7
|
+
class RiveScript
|
|
8
|
+
module Lang
|
|
9
|
+
# Ruby language support for RiveScript object macros.
|
|
10
|
+
#
|
|
11
|
+
# Object macros defined in RiveScript source are compiled and executed via
|
|
12
|
+
# Kernel#eval. Loading untrusted third-party RiveScript personalities can
|
|
13
|
+
# therefore execute arbitrary Ruby code in your process. Disable this handler
|
|
14
|
+
# when loading untrusted sources:
|
|
15
|
+
#
|
|
16
|
+
# bot.set_handler("ruby", nil)
|
|
17
|
+
#
|
|
18
|
+
# This handler is enabled by default in the Ruby port.
|
|
19
|
+
class RubyHandler
|
|
20
|
+
attr_reader :objects, :sources
|
|
21
|
+
|
|
22
|
+
def initialize(master)
|
|
23
|
+
@master = master
|
|
24
|
+
@objects = {}
|
|
25
|
+
@sources = {}
|
|
26
|
+
@binding = binding
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Called by RiveScript to load Ruby object macro source.
|
|
30
|
+
# +code+ may be a Proc or an Array of source lines.
|
|
31
|
+
def load(name, code)
|
|
32
|
+
if code.is_a?(Proc)
|
|
33
|
+
@objects[name] = code
|
|
34
|
+
@sources[name] = nil
|
|
35
|
+
return
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
lines = code.is_a?(Array) ? code.join("\n") : code.to_s
|
|
39
|
+
@sources[name] = lines
|
|
40
|
+
source = <<~RUBY
|
|
41
|
+
@objects[#{name.inspect}] = lambda do |rs, args|
|
|
42
|
+
#{lines}
|
|
43
|
+
end
|
|
44
|
+
RUBY
|
|
45
|
+
|
|
46
|
+
begin
|
|
47
|
+
eval(source, @binding, "(rivescript object #{name})", 1)
|
|
48
|
+
rescue StandardError => e
|
|
49
|
+
@master.warn("Error evaluating Ruby object: #{e.message}")
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Called by RiveScript to execute a Ruby object macro.
|
|
54
|
+
def call(rs, name, fields, scope = nil)
|
|
55
|
+
func = @objects[name]
|
|
56
|
+
return @master.errors["objectNotFound"] if func.nil?
|
|
57
|
+
|
|
58
|
+
reply =
|
|
59
|
+
if scope
|
|
60
|
+
scope.instance_exec(rs, fields, &func)
|
|
61
|
+
else
|
|
62
|
+
func.call(rs, fields)
|
|
63
|
+
end
|
|
64
|
+
rescue StandardError => e
|
|
65
|
+
reply = "[ERR: Error when executing Ruby object: #{e.message}]"
|
|
66
|
+
ensure
|
|
67
|
+
reply = "" if reply.nil?
|
|
68
|
+
reply
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|