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:
[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
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.