Esecuzione di un altro script ruby da uno script ruby

In ruby, è ansible specificare di chiamare un altro script ruby ​​usando lo stesso interprete ruby ​​come viene eseguito lo script originale?

Ad esempio, se a.rb esegue b.rb un paio di volte, è ansible sostituire

system("ruby", "b.rb", "foo", "bar") 

con qualcosa di simile

 run_ruby("b.rb", "foo", "bar") 

in modo che se hai usato ruby1.9.1 a.rb sull’originale, ruby1.9.1 sarebbe stato usato su b.rb, ma se hai appena usato ruby a.rb sull’originale, ruby sarebbe stato usato su b.rb?

Preferirei non usare gli shebang, perché mi piacerebbe che fosse in grado di girare su diversi computer, alcuni dei quali non hanno /usr/bin/env .

Modifica: non intendevo load o require e simili, ma generare nuovi processi (in modo da poter utilizzare più CPU).

Avdi Grimm ha scritto una serie di articoli sul blog Devver su diversi modi per avviare i subprocessi Ruby la scorsa estate:

  • Una dozzina (o giù di lì) modi per avviare sottoprocessi in Ruby: parte 1
  • Una dozzina (o giù di lì) modi per avviare i sottoprocessi in Ruby: parte 2
  • Una dozzina (o giù di lì) modi per avviare sottoprocessi in Ruby: parte 3
  • Fai attenzione alla duplicazione dei tubi nei sottoprocessi

[Nota: sembra che la parte 4 non sia stata ancora pubblicata.]

 require "b.rb" 

eseguirà il contenuto di b.rb (si chiama lasciare fuori “.rb”, e c’è un percorso di ricerca). Nel tuo caso, probabilmente faresti qualcosa come:

a.rb:

 require "b.rb"; b("Hello", "world") 

b.rb:

 def b(first, second) puts first + ", " + second end 

Si noti che se si utilizza require , Ruby caricherà ed eseguirà il file una volta sola (ogni volta che si chiama load verrà ricaricato), ma è ansible chiamare i metodi definiti nel file tutte le volte che lo si desidera.

Man mano che le cose diventano più complesse, ti consigliamo di passare a un design orientato agli oggetti.

EDIT: In tal caso, si dovrebbe esaminare il threading di Ruby. Un semplice esempio è:

a.rb:

 require "b"; t1 = Thread.new{b("Hello", "world");} t2 = Thread.new{b("Hello", "galaxy");} t1.join t2.join 

b.rb:

 def b(first, second) 10.times { puts first + ", " + second; sleep(0.1); } end 

Il trucco richiesto è una buona idea, presupponendo che lo script in questione non soffochi di tentare di ridefinire le costanti che si possono impostare, o di chiamare metodi su oggetti che potrebbero avere patch runtime per non onorare più i loro contratti standard.

In entrambi i casi, il problema è meno l’approccio che il codice negli script stessi. Mostra le buone maniere, metti le tue costanti in uno spazio dei nomi e non scimmiottare in modo descrittivo la runtime.

Per garantire che lo script in questione non abbia a che fare con il runtime del tuo script chiamante, e per evitare la possibilità che possa chiamare Kernel / Process.exit () da qualche parte, prova quanto segue

 pid=Process.fork do require 'script.rb' Process.exit end ignored, status = Process.waitpid2(pid, Process::WNOHANG) puts "script.rb PID #{pid} exited, exit status: #{status.exitstatus}" 

Per cose più avanzate come scrivere sul suo stream stdin o leggere dai suoi stream stdout o stderr, usa la gem Open4.

Se vuoi solo eseguire uno script nel contesto di un processo esistente, puoi farlo anche tu

 eval File.read("/path/to/your/script.rb") 

Non sei sicuro di quale sia il tuo caso d’uso ma potrebbe essere utile ad esempio se hai una console Rails aperta e vuoi eseguire del codice in un file scratch, ma non vuoi dover continuare a copiare l’intero blocco di codice nel tuo console.

Questo è quello che ho usato

/myapp/script/main_script.rb


load rails env, solo se necessario

 ENV['RAILS_ENV'] = ARGV.first || ENV['RAILS_ENV'] || 'development' require File.expand_path(File.dirname(__FILE__) + "/../config/environment") 

eseguire altri script slave da main_script.rb

 require File.expand_path(File.dirname(__FILE__) + "/../script/populate_wh_grape_varieties_table.rb") 

Charles Nutter, di fama JRuby, suggerisce un metodo Kernel#ruby per chiamare uno script Ruby usando la stessa implementazione di Ruby che stai usando.

Modifica : la proposta è stata respinta. Matz ha detto che MVM (più macchine virtuali) può fornire la soluzione.