Class: RiveScript::Lang::RubyHandler

Inherits:
Object
  • Object
show all
Defined in:
lib/rivescript/lang/ruby.rb

Overview

Ruby language support for RiveScript object macros.

Object macros defined in RiveScript source are compiled and executed via Kernel#eval. Loading untrusted third-party RiveScript personalities can therefore execute arbitrary Ruby code in your process. Disable this handler when loading untrusted sources:

bot.set_handler("ruby", nil)

This handler is enabled by default in the Ruby port.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(master) ⇒ RubyHandler

Returns a new instance of RubyHandler.



22
23
24
25
26
27
# File 'lib/rivescript/lang/ruby.rb', line 22

def initialize(master)
  @master = master
  @objects = {}
  @sources = {}
  @binding = binding
end

Instance Attribute Details

#objectsObject (readonly)

Returns the value of attribute objects.



20
21
22
# File 'lib/rivescript/lang/ruby.rb', line 20

def objects
  @objects
end

#sourcesObject (readonly)

Returns the value of attribute sources.



20
21
22
# File 'lib/rivescript/lang/ruby.rb', line 20

def sources
  @sources
end

Instance Method Details

#call(rs, name, fields, scope = nil) ⇒ Object

Called by RiveScript to execute a Ruby object macro.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/rivescript/lang/ruby.rb', line 54

def call(rs, name, fields, scope = nil)
  func = @objects[name]
  return @master.errors["objectNotFound"] if func.nil?

  reply =
    if scope
      scope.instance_exec(rs, fields, &func)
    else
      func.call(rs, fields)
    end
rescue StandardError => e
  reply = "[ERR: Error when executing Ruby object: #{e.message}]"
ensure
  reply = "" if reply.nil?
  reply
end

#load(name, code) ⇒ Object

Called by RiveScript to load Ruby object macro source. code may be a Proc or an Array of source lines.



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/rivescript/lang/ruby.rb', line 31

def load(name, code)
  if code.is_a?(Proc)
    @objects[name] = code
    @sources[name] = nil
    return
  end

  lines = code.is_a?(Array) ? code.join("\n") : code.to_s
  @sources[name] = lines
  source = <<~RUBY
    @objects[#{name.inspect}] = lambda do |rs, args|
      #{lines}
    end
  RUBY

  begin
    eval(source, @binding, "(rivescript object #{name})", 1)
  rescue StandardError => e
    @master.warn("Error evaluating Ruby object: #{e.message}")
  end
end