Module: Sus::Fixtures::IsolatedRubyContext
- Defined in:
- lib/sus/fixtures/isolated_ruby_context.rb
Overview
Evaluates Ruby in a fresh process and returns its result through Marshal.
Defined Under Namespace
Classes: Error
Instance Method Summary collapse
-
#isolated_ruby(source, chdir: Dir.pwd, env: {}, requires: []) ⇒ Object
Evaluate source using the current Ruby interpreter, without sharing Ruby state or changing the caller's working directory.
Instance Method Details
#isolated_ruby(source, chdir: Dir.pwd, env: {}, requires: []) ⇒ Object
Evaluate source using the current Ruby interpreter, without sharing Ruby state or changing the caller's working directory. The final expression is serialized with Marshal.dump and restored with Marshal.load. Printed output goes to the inherited stderr. Exceptions are marshaled back and re-raised with their original backtraces. SystemExit follows the child process's exit status.
37 38 39 40 41 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/sus/fixtures/isolated_ruby_context.rb', line 37 def isolated_ruby(source, chdir: Dir.pwd, env: {}, requires: []) script = <<~'RUBY' ->(output) do $stdout.reopen($stderr) begin source = $stdin.read ARGV.each{|feature| require feature} result = eval(source, TOPLEVEL_BINDING, File.join(Dir.pwd, "(isolated ruby)")) output.write(Marshal.dump([result, nil])) rescue SystemExit raise rescue Exception => error output.write(Marshal.dump([nil, error])) end end.call($stdout.dup.binmode) RUBY output = IO.popen([env, RbConfig.ruby, "-e", script, "--", *requires], "r+b", chdir: chdir) do |process| begin process.write(source) rescue Errno::EPIPE # A startup failure may close stdin before accepting the source: end process.close_write process.read end status = $? raise Error.new(status) unless status.success? return nil if output.empty? result, error = Marshal.load(output) raise error if error result end |