Class: SafeRuby

Inherits:
Object
  • Object
show all
Defined in:
lib/safe_ruby/runner.rb,
lib/safe_ruby/version.rb

Overview

main class

Constant Summary collapse

VERSION =
[MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION].join('.')

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(code, options = {}) ⇒ SafeRuby

rubocop:disable Style/OptionHash



31
32
33
34
35
36
37
# File 'lib/safe_ruby/runner.rb', line 31

def initialize(code, options = {})
  options = DEFAULTS.merge(options)

  @code         = code
  @raise_errors = options[:raise_errors]
  @timeout      = options[:timeout]
end

Class Method Details

.check(code, expected) ⇒ Object

rubocop:enable Style/OptionHash



24
25
26
27
28
# File 'lib/safe_ruby/runner.rb', line 24

def self.check(code, expected)
  # rubocop:disable Security/Eval
  eval(code) == eval(expected)
  # rubocop:enable Security/Eval
end

.eval(code, options = {}) ⇒ Object

rubocop:disable Style/OptionHash



19
20
21
# File 'lib/safe_ruby/runner.rb', line 19

def self.eval(code, options = {})
  new(code, options).eval
end

Instance Method Details

#evalObject

rubocop:disable Metrics/AbcSize rubocop:disable Metrics/MethodLength



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/safe_ruby/runner.rb', line 42

def eval
  temp = build_tempfile
  read, write = IO.pipe
  ChildProcess.build('ruby', temp.path).tap do |process|
    process.io.stdout = write
    process.io.stderr = write
    process.start
    begin
      process.poll_for_exit(@timeout)
    rescue ChildProcess::TimeoutError => e
      # tries increasingly harsher methods to kill the process.
      process.stop
      return e.message
    end
    write.close
    temp.unlink
  end

  data = read.read
  begin
    # rubocop:disable Security/MarshalLoad
    Marshal.load(data)
    # rubocop:enable Security/MarshalLoad
  rescue StandardError
    raise(data) if @raise_errors

    data
  end
end