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.
@@ -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