Executar código Ruby destrutivo em uma sandbox

Tentar criar um código Ruby que não tenha um namespace adequado e, adicionalmente, não forneça uma API real para usuários externos pode ser frustrante. Fiz essa experiência ao construir braumeister.org um navegador de pacotes para o conhecido gerenciador de pacotes do OS X Homebrew . Homebrew é um programa CLI escrito em Ruby que fornece uma ótima interface de usuário, mas não apresenta uma API para acesso de terceiros.

O termo “código Ruby destrutivo” pode soar um pouco extremo, mas é quase perfeito para o Homebrew. Importar os pacotes (também conhecidos como fórmulas) do Homebrew sempre sujará o namespace global e limpar manualmente pode ser um pouco tedioso. Além disso, as fórmulas podem ser quebradas de vez em quando devido ao grande número de atualizações que recebem todos os dias. Então, como contornar esses problemas?

A solução é chamada IO.pipee vem com Ruby. 😉

# Open a pipe that can be used to communicate between two processes
pipe_main
, pipe_fork = IO.pipe

pid
= fork do
# The code in the fork block runs in another, forked Ruby process
# It won't interfere with your main process

begin
# First, close the main process' end of the pipe
pipe_main
.close

# Run the evil code here and dump any objects of interest into the pipe
Marshal.dump some_object, pipe_fork
rescue
# Dump any exception to the pipe
Marshal.dump $!, pipe_fork
end

# Close the pipe end of the forked process and exit
pipe_fork
.flush
pipe_fork
.close
exit!
end

# The following code will run in parallel to the forked process above

# First, close the forked process' end of the pipe
pipe_fork
.close
# Read objects of interest from the pipe
some_object
= Marshal.load pipe_main
# Wait for the forked process to end
Process.wait pid
# Close the pipe end of the main process
pipe_main
.close

# The forked process might also raise an exception, so you might want to re-raise it
raise some_object if some_object.is_a? Exception

É isso, o código externo não vai quebrar mais o seu código.