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
data/lib/rivescript.rb
ADDED
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# RiveScript Ruby port
|
|
4
|
+
# Byte <byte@jvmlab.org>, https://jvmlab.org/
|
|
5
|
+
# MIT License
|
|
6
|
+
|
|
7
|
+
require_relative "rivescript/version"
|
|
8
|
+
require_relative "rivescript/utils"
|
|
9
|
+
require_relative "rivescript/sessions"
|
|
10
|
+
require_relative "rivescript/parser"
|
|
11
|
+
require_relative "rivescript/brain"
|
|
12
|
+
require_relative "rivescript/sorting"
|
|
13
|
+
require_relative "rivescript/inheritance"
|
|
14
|
+
require_relative "rivescript/lang/ruby"
|
|
15
|
+
|
|
16
|
+
# RiveScript interpreter for Ruby.
|
|
17
|
+
#
|
|
18
|
+
# Create a new instance with optional configuration:
|
|
19
|
+
#
|
|
20
|
+
# bot = RiveScript.new(debug: true, utf8: true)
|
|
21
|
+
# bot.load_directory("brain")
|
|
22
|
+
# bot.sort_replies
|
|
23
|
+
# reply = bot.reply("user", "hello")
|
|
24
|
+
class RiveScript
|
|
25
|
+
attr_accessor :unicode_punctuation, :errors
|
|
26
|
+
attr_reader :_strict, :_utf8, :_depth, :_force_case, :_concat, :_case_sensitive,
|
|
27
|
+
:_global, :_var, :_sub, :_submax, :_person, :_personmax, :_array,
|
|
28
|
+
:_session, :_includes, :_inherits, :_handlers, :_objlangs, :_topics,
|
|
29
|
+
:_thats, :_sorted, :parser, :brain
|
|
30
|
+
|
|
31
|
+
alias _forceCase _force_case
|
|
32
|
+
|
|
33
|
+
# Gem / checkout root (directory that contains lib/ and eg/).
|
|
34
|
+
def self.root
|
|
35
|
+
File.expand_path("..", __dir__)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Path to the bundled sample brain shipped with the gem.
|
|
39
|
+
#
|
|
40
|
+
# bot = RiveScript.new
|
|
41
|
+
# bot.load_directory(RiveScript.brain_path)
|
|
42
|
+
# bot.sort_replies
|
|
43
|
+
def self.brain_path
|
|
44
|
+
File.join(root, "eg", "brain")
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# @param opts [Hash] configuration options
|
|
48
|
+
# @option opts [Boolean] :debug debug mode (default false)
|
|
49
|
+
# @option opts [Integer] :depth recursion depth limit (default 50)
|
|
50
|
+
# @option opts [Boolean] :strict strict mode (default true)
|
|
51
|
+
# @option opts [Boolean] :utf8 enable UTF-8 mode (default false)
|
|
52
|
+
# @option opts [Boolean] :force_case force-lowercase triggers (default false)
|
|
53
|
+
# @option opts [Proc] :on_debug custom debug log handler
|
|
54
|
+
# @option opts [String] :concat global concatenation mode override
|
|
55
|
+
# @option opts [RiveScript::SessionManager] :session_manager custom session store
|
|
56
|
+
# @option opts [Boolean] :case_sensitive preserve user message capitalization
|
|
57
|
+
# @option opts [Boolean] :enable_object_macros register the default Ruby object
|
|
58
|
+
# macro handler (default true). Set to +false+ to disable executing Ruby
|
|
59
|
+
# object macros defined in RiveScript source.
|
|
60
|
+
# @option opts [Regexp] :unicode_punctuation punctuation regexp for UTF-8 mode
|
|
61
|
+
# @option opts [Hash] :errors customized error messages
|
|
62
|
+
def initialize(opts = {})
|
|
63
|
+
opts = {} if opts.nil?
|
|
64
|
+
|
|
65
|
+
@_debug = opts.fetch(:debug, false)
|
|
66
|
+
@_strict = opts.fetch(:strict, true)
|
|
67
|
+
@_depth = opts.key?(:depth) ? opts[:depth].to_i : 50
|
|
68
|
+
@_utf8 = opts.fetch(:utf8, false)
|
|
69
|
+
@_force_case = opts.fetch(:force_case, false)
|
|
70
|
+
@on_debug = opts[:on_debug]
|
|
71
|
+
@_concat = opts[:concat]
|
|
72
|
+
@_case_sensitive = opts.fetch(:case_sensitive, false)
|
|
73
|
+
|
|
74
|
+
@unicode_punctuation = opts.fetch(:unicode_punctuation, /[.,!?;:]/)
|
|
75
|
+
|
|
76
|
+
@errors = {
|
|
77
|
+
"replyNotMatched" => "ERR: No Reply Matched",
|
|
78
|
+
"replyNotFound" => "ERR: No Reply Found",
|
|
79
|
+
"objectNotFound" => "[ERR: Object Not Found]",
|
|
80
|
+
"deepRecursion" => "ERR: Deep Recursion Detected"
|
|
81
|
+
}
|
|
82
|
+
if opts[:errors].is_a?(Hash)
|
|
83
|
+
opts[:errors].each do |key, value|
|
|
84
|
+
@errors[key.to_s] = value
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
@runtime = runtime
|
|
89
|
+
|
|
90
|
+
@parser = Parser.new(self)
|
|
91
|
+
@brain = Brain.new(self)
|
|
92
|
+
|
|
93
|
+
@_pending = []
|
|
94
|
+
@_load_count = 0
|
|
95
|
+
|
|
96
|
+
@_global = {}
|
|
97
|
+
@_var = {}
|
|
98
|
+
@_sub = {}
|
|
99
|
+
@_submax = 1
|
|
100
|
+
@_person = {}
|
|
101
|
+
@_personmax = 1
|
|
102
|
+
@_array = {}
|
|
103
|
+
@_session = opts[:session_manager]
|
|
104
|
+
@_includes = {}
|
|
105
|
+
@_inherits = {}
|
|
106
|
+
@_handlers = {}
|
|
107
|
+
@_objlangs = {}
|
|
108
|
+
@_topics = {}
|
|
109
|
+
@_thats = {}
|
|
110
|
+
@_sorted = {}
|
|
111
|
+
|
|
112
|
+
@_session = MemorySessionManager.new if @_session.nil?
|
|
113
|
+
|
|
114
|
+
@_handlers["ruby"] = Lang::RubyHandler.new(self) unless opts[:enable_object_macros] == false
|
|
115
|
+
say("RiveScript Interpreter v#{VERSION} Initialized.")
|
|
116
|
+
say("Runtime Environment: #{@runtime}")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Returns the version number of the RiveScript Ruby library.
|
|
120
|
+
def version
|
|
121
|
+
VERSION
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Load a RiveScript document from one or more files.
|
|
125
|
+
def load_file(path)
|
|
126
|
+
paths = path.is_a?(Array) ? path : [path]
|
|
127
|
+
|
|
128
|
+
paths.each do |file|
|
|
129
|
+
say("Request to load file: #{file}")
|
|
130
|
+
data = File.read(file)
|
|
131
|
+
ok = parse(file, data)
|
|
132
|
+
raise "parser error" unless ok
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
true
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Load RiveScript documents from a directory recursively.
|
|
139
|
+
def load_directory(path)
|
|
140
|
+
raise "#{path} is not a directory" unless File.directory?(path)
|
|
141
|
+
|
|
142
|
+
say("Loading from directory #{path}")
|
|
143
|
+
files = Dir.glob(File.join(path, "**", "*.{rive,rs}"), File::FNM_CASEFOLD)
|
|
144
|
+
load_file(files)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Load RiveScript source code from a string.
|
|
148
|
+
# Returns true if the code parsed with no error.
|
|
149
|
+
def stream(code, on_error = nil)
|
|
150
|
+
parse("stream()", code, on_error)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Parse RiveScript code and load it into memory.
|
|
154
|
+
def parse(filename, code, on_error = nil)
|
|
155
|
+
say("Parsing code!")
|
|
156
|
+
|
|
157
|
+
ok = true
|
|
158
|
+
error_handler = lambda do |err, fn, ln|
|
|
159
|
+
on_error&.call(err, fn, ln)
|
|
160
|
+
ok = false
|
|
161
|
+
end
|
|
162
|
+
ast = @parser.parse(filename, code, error_handler)
|
|
163
|
+
|
|
164
|
+
ast["begin"].each do |type, vars|
|
|
165
|
+
internal = :"@_#{type}"
|
|
166
|
+
max_key = :"@_#{type}max"
|
|
167
|
+
|
|
168
|
+
vars.each do |name, value|
|
|
169
|
+
if %w[sub person].include?(type)
|
|
170
|
+
instance_variable_set(max_key, [instance_variable_get(max_key), name.split(" ").length].max)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
target = instance_variable_get(internal)
|
|
174
|
+
if value == "<undef>"
|
|
175
|
+
target.delete(name)
|
|
176
|
+
else
|
|
177
|
+
target[name] = value
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
@_debug = @_global["debug"] == "true" if @_global.key?("debug")
|
|
183
|
+
if @_global.key?("depth")
|
|
184
|
+
parsed_depth = @_global["depth"].to_i
|
|
185
|
+
@_depth = parsed_depth.zero? ? 50 : parsed_depth
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
ast["topics"].each do |topic, data|
|
|
189
|
+
@_includes[topic] ||= {}
|
|
190
|
+
@_inherits[topic] ||= {}
|
|
191
|
+
Utils.extend(@_includes[topic], data["includes"])
|
|
192
|
+
Utils.extend(@_inherits[topic], data["inherits"])
|
|
193
|
+
|
|
194
|
+
@_topics[topic] ||= []
|
|
195
|
+
data["triggers"].each do |trigger|
|
|
196
|
+
@_topics[topic] << trigger
|
|
197
|
+
|
|
198
|
+
next if trigger["previous"].nil?
|
|
199
|
+
|
|
200
|
+
@_thats[topic] ||= {}
|
|
201
|
+
@_thats[topic][trigger["trigger"]] ||= {}
|
|
202
|
+
@_thats[topic][trigger["trigger"]][trigger["previous"]] = trigger
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
ast["objects"].each do |object|
|
|
207
|
+
language = object["language"]
|
|
208
|
+
next unless @_handlers[language]
|
|
209
|
+
|
|
210
|
+
@_objlangs[object["name"]] = language
|
|
211
|
+
@_handlers[language].load(object["name"], object["code"])
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
ok
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Populate sort buffers after loading RiveScript code.
|
|
218
|
+
def sort_replies
|
|
219
|
+
@_sorted = { "topics" => {}, "thats" => {} }
|
|
220
|
+
say("Sorting triggers...")
|
|
221
|
+
|
|
222
|
+
@_topics.each_key do |topic|
|
|
223
|
+
say("Analyzing topic #{topic}...")
|
|
224
|
+
|
|
225
|
+
all_triggers = Inheritance.get_topic_triggers(self, topic)
|
|
226
|
+
@_sorted["topics"][topic] = Sorting.sort_trigger_set(all_triggers, true)
|
|
227
|
+
|
|
228
|
+
that_triggers = Inheritance.get_topic_triggers(self, topic, true)
|
|
229
|
+
@_sorted["thats"][topic] = Sorting.sort_trigger_set(that_triggers, false)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
@_sorted["sub"] = Sorting.sort_list(@_sub.keys)
|
|
233
|
+
@_sorted["person"] = Sorting.sort_list(@_person.keys)
|
|
234
|
+
@_sorted
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
# Translate the in-memory brain into a JSON-serializable structure.
|
|
238
|
+
def deparse
|
|
239
|
+
result = {
|
|
240
|
+
"begin" => {
|
|
241
|
+
"global" => Utils.clone(@_global),
|
|
242
|
+
"var" => Utils.clone(@_var),
|
|
243
|
+
"sub" => Utils.clone(@_sub),
|
|
244
|
+
"person" => Utils.clone(@_person),
|
|
245
|
+
"array" => Utils.clone(@_array),
|
|
246
|
+
"triggers" => []
|
|
247
|
+
},
|
|
248
|
+
"topics" => Utils.clone(@_topics),
|
|
249
|
+
"inherits" => Utils.clone(@_inherits),
|
|
250
|
+
"includes" => Utils.clone(@_includes),
|
|
251
|
+
"objects" => {}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
@_handlers.each do |key, handler|
|
|
255
|
+
next unless handler.respond_to?(:objects)
|
|
256
|
+
|
|
257
|
+
entry = { "_objects" => Utils.clone(handler.objects) }
|
|
258
|
+
entry["_sources"] = Utils.clone(handler.sources) if handler.respond_to?(:sources)
|
|
259
|
+
result["objects"][key] = entry
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
if result["topics"]["__begin__"]
|
|
263
|
+
result["begin"]["triggers"] = result["topics"].delete("__begin__")
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
result["begin"]["global"]["debug"] = @_debug if @_debug
|
|
267
|
+
result["begin"]["global"]["depth"] = @_depth if @_depth != 50
|
|
268
|
+
|
|
269
|
+
result
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Translate the in-memory brain back into RiveScript source code.
|
|
273
|
+
def stringify(deparsed = nil)
|
|
274
|
+
@parser.stringify(deparsed || deparse)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Write the in-memory RiveScript data into a text file.
|
|
278
|
+
def write(filename, deparsed = nil)
|
|
279
|
+
File.write(filename, stringify(deparsed))
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# Set a custom language handler for object macros.
|
|
283
|
+
# Omit +obj+ to remove the handler; pass +nil+ to disable it explicitly.
|
|
284
|
+
def set_handler(lang, obj = :__unset__)
|
|
285
|
+
if obj == :__unset__
|
|
286
|
+
@_handlers.delete(lang)
|
|
287
|
+
else
|
|
288
|
+
@_handlers[lang] = obj
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# Define a Ruby object macro from your program.
|
|
293
|
+
def set_subroutine(name, code = nil, &block)
|
|
294
|
+
code ||= block
|
|
295
|
+
return unless @_handlers["ruby"]
|
|
296
|
+
return if code.nil?
|
|
297
|
+
|
|
298
|
+
@_objlangs[name] = "ruby"
|
|
299
|
+
@_handlers["ruby"].load(name, code)
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# Set a global variable (! global).
|
|
303
|
+
def set_global(name, value = :__unset__)
|
|
304
|
+
if value == :__unset__
|
|
305
|
+
@_global.delete(name)
|
|
306
|
+
else
|
|
307
|
+
@_global[name] = value
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
# Set a bot variable (! var).
|
|
312
|
+
def set_variable(name, value = :__unset__)
|
|
313
|
+
if value == :__unset__
|
|
314
|
+
@_var.delete(name)
|
|
315
|
+
else
|
|
316
|
+
@_var[name] = value
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
# Set a substitution (! sub).
|
|
321
|
+
def set_substitution(name, value = :__unset__)
|
|
322
|
+
if value == :__unset__
|
|
323
|
+
@_sub.delete(name)
|
|
324
|
+
else
|
|
325
|
+
@_submax = [name.split(" ").length, @_submax].max
|
|
326
|
+
@_sub[name] = value
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# Set a person substitution (! person).
|
|
331
|
+
def set_person(name, value = :__unset__)
|
|
332
|
+
if value == :__unset__
|
|
333
|
+
@_person.delete(name)
|
|
334
|
+
else
|
|
335
|
+
@_personmax = [name.split(" ").length, @_personmax].max
|
|
336
|
+
@_person[name] = value
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# Set a user variable.
|
|
341
|
+
def set_uservar(user, name, value)
|
|
342
|
+
value = value.downcase if name == "topic" && @_force_case
|
|
343
|
+
|
|
344
|
+
@_session.set(user, { name => value })
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
# Set multiple user variables at once.
|
|
348
|
+
def set_uservars(user, data)
|
|
349
|
+
@_session.set(user, data)
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# Get a bot variable (<bot name>).
|
|
353
|
+
def get_variable(name)
|
|
354
|
+
@_var.key?(name) ? @_var[name] : "undefined"
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
# Get a user variable.
|
|
358
|
+
def get_uservar(user, name)
|
|
359
|
+
@_session.get(user, name)
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
# Get all variables about a user, or all users if +user+ is omitted.
|
|
363
|
+
def get_uservars(user = nil)
|
|
364
|
+
if user.nil?
|
|
365
|
+
@_session.get_all
|
|
366
|
+
else
|
|
367
|
+
@_session.get_any(user)
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Clear user variables for one user, or all users if +user+ is omitted.
|
|
372
|
+
def clear_uservars(user = nil)
|
|
373
|
+
if user.nil?
|
|
374
|
+
@_session.reset_all
|
|
375
|
+
else
|
|
376
|
+
@_session.reset(user)
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Freeze the variable state of a user.
|
|
381
|
+
def freeze_uservars(user)
|
|
382
|
+
@_session.freeze(user)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
# Thaw a user's frozen variables.
|
|
386
|
+
def thaw_uservars(user, action = "thaw")
|
|
387
|
+
@_session.thaw(user, action)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
# Retrieve the trigger the user matched most recently.
|
|
391
|
+
def last_match(user)
|
|
392
|
+
@_session.get(user, "__lastmatch__")
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Retrieve the trigger the user matched initially for the last reply.
|
|
396
|
+
def initial_match(user)
|
|
397
|
+
@_session.get(user, "__initialmatch__")
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
# Retrieve all triggers matched for the last reply.
|
|
401
|
+
def last_triggers(user)
|
|
402
|
+
@_session.get(user, "__last_triggers__")
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
# Retrieve triggers in the current topic for the specified user.
|
|
406
|
+
def get_user_topic_triggers(user)
|
|
407
|
+
topic = @_session.get(user, "topic")
|
|
408
|
+
Inheritance.get_topic_triggers(self, topic)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
# Retrieve the current user's ID (only valid inside object macros).
|
|
412
|
+
def current_user
|
|
413
|
+
if @brain.current_user.nil?
|
|
414
|
+
warn("currentUser() is intended to be called from within a Ruby object macro!")
|
|
415
|
+
end
|
|
416
|
+
@brain.current_user
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# Fetch a reply from the RiveScript brain.
|
|
420
|
+
def reply(user, msg, scope = nil)
|
|
421
|
+
@brain.reply(user, msg, scope)
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
# Deprecated alias for reply.
|
|
425
|
+
def reply_async(user, msg, scope = nil, &block)
|
|
426
|
+
warn("DEPRECATED FUNCTION: RiveScript#reply_async is deprecated; use reply instead")
|
|
427
|
+
result = reply(user, msg, scope)
|
|
428
|
+
block&.call(nil, result)
|
|
429
|
+
result
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
# Debug logger.
|
|
433
|
+
def say(message)
|
|
434
|
+
return unless @_debug
|
|
435
|
+
|
|
436
|
+
if @on_debug
|
|
437
|
+
@on_debug.call(message)
|
|
438
|
+
else
|
|
439
|
+
$stdout.puts(message)
|
|
440
|
+
end
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
# Warning/error logger.
|
|
444
|
+
def warn(message, filename = nil, lineno = nil)
|
|
445
|
+
message = "#{message} at #{filename} line #{lineno}" if filename && lineno
|
|
446
|
+
formatted = "[WARNING] #{message}"
|
|
447
|
+
|
|
448
|
+
if @on_debug
|
|
449
|
+
@on_debug.call(formatted)
|
|
450
|
+
else
|
|
451
|
+
$stderr.puts(formatted)
|
|
452
|
+
end
|
|
453
|
+
end
|
|
454
|
+
|
|
455
|
+
private
|
|
456
|
+
|
|
457
|
+
def runtime
|
|
458
|
+
"ruby"
|
|
459
|
+
end
|
|
460
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rivescript
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Byte
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-08-05 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: RiveScript is a scripting language for chatterbots. This gem is a Ruby
|
|
14
|
+
3.3 port of the RiveScript interpreter.
|
|
15
|
+
email:
|
|
16
|
+
- byte@jvmlab.org
|
|
17
|
+
executables:
|
|
18
|
+
- riveshell
|
|
19
|
+
extensions: []
|
|
20
|
+
extra_rdoc_files: []
|
|
21
|
+
files:
|
|
22
|
+
- Changes.md
|
|
23
|
+
- LICENSE
|
|
24
|
+
- README.md
|
|
25
|
+
- bin/riveshell
|
|
26
|
+
- eg/brain/admin.rive
|
|
27
|
+
- eg/brain/begin.rive
|
|
28
|
+
- eg/brain/clients.rive
|
|
29
|
+
- eg/brain/eliza.rive
|
|
30
|
+
- eg/brain/myself.rive
|
|
31
|
+
- eg/brain/rpg.rive
|
|
32
|
+
- lib/rivescript.rb
|
|
33
|
+
- lib/rivescript/brain.rb
|
|
34
|
+
- lib/rivescript/inheritance.rb
|
|
35
|
+
- lib/rivescript/lang/ruby.rb
|
|
36
|
+
- lib/rivescript/parser.rb
|
|
37
|
+
- lib/rivescript/sessions.rb
|
|
38
|
+
- lib/rivescript/sorting.rb
|
|
39
|
+
- lib/rivescript/utils.rb
|
|
40
|
+
- lib/rivescript/version.rb
|
|
41
|
+
homepage: https://github.com/LilOleByte/rivescript-rb
|
|
42
|
+
licenses:
|
|
43
|
+
- MIT
|
|
44
|
+
metadata:
|
|
45
|
+
homepage_uri: https://jvmlab.org/
|
|
46
|
+
source_code_uri: https://github.com/LilOleByte/rivescript-rb
|
|
47
|
+
changelog_uri: https://github.com/LilOleByte/rivescript-rb/blob/main/Changes.md
|
|
48
|
+
bug_tracker_uri: https://github.com/LilOleByte/rivescript-rb/issues
|
|
49
|
+
rubygems_mfa_required: 'true'
|
|
50
|
+
post_install_message:
|
|
51
|
+
rdoc_options: []
|
|
52
|
+
require_paths:
|
|
53
|
+
- lib
|
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - ">="
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: 3.3.0
|
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
|
+
requirements:
|
|
61
|
+
- - ">="
|
|
62
|
+
- !ruby/object:Gem::Version
|
|
63
|
+
version: '0'
|
|
64
|
+
requirements: []
|
|
65
|
+
rubygems_version: 3.5.22
|
|
66
|
+
signing_key:
|
|
67
|
+
specification_version: 4
|
|
68
|
+
summary: RiveScript interpreter for Ruby
|
|
69
|
+
test_files: []
|