Class: SafeRuby

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

Constant Summary collapse

DEFAULTS =
{ timeout: 5,
raise_errors: true }
MAJOR_VERSION =
1
MINOR_VERSION =
0
RELEASE_VERSION =
2
VERSION =
[MAJOR_VERSION, MINOR_VERSION, RELEASE_VERSION].join('.')

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of SafeRuby.



11
12
13
14
15
16
17
# File 'lib/safe_ruby/runner.rb', line 11

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



52
53
54
# File 'lib/safe_ruby/runner.rb', line 52

def self.check(code, expected)
  eval(code) == eval(expected)
end

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



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



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/safe_ruby/runner.rb', line 23

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
      process.stop # tries increasingly harsher methods to kill the process.
      return e.message
    end
    write.close
    temp.unlink
  end

  data = read.read
  begin
    Marshal.load(data)
  rescue => e
    if @raise_errors
      raise data
    else
      return data
    end
  end
end