Dans le cadre d’un projet plus vaste, j’essaie d’intégrer un interpréteur interactif Python dans un processus Ruby. J’aimerais pouvoir effectuer les tâches suivantes:
$ irb
irb(main):001:0> pipe = IO.popen("python", "w+")
=> #<IO:0x7f3dba4977e0>
irb(main):002:0> pipe.puts "print "hello""
=> nil
irb(main):003:0> pipe.gets
=> "hellon"
Malheureusement, le gets
semble bloquer plutôt que de renvoyer n'importe quel type de sortie du processus Python. J'ai "essayé des variantes de cette procédure avec open3
, en utilisant le mode r+
au lieu de w+
et quelques autres options mineures (python -u
parmi eux), sans succès.
Y a-t-il un moyen d’établir une relation interactive?communication avec un shell Python de Ruby - en effet, pour "envelopper" la CLI Python? J'utilise Ruby 1.8.7 (patch du niveau 29/06/2010 299) et Python 2.6.6 sur un ordinateur x86_64, même si, espérons-le, les solutions seront portables (ish) entre les versions Python.
Réponses:
1 pour la réponse № 1popen
ne ressemble pas à un terminal pour python, vous ne pouvez donc pas exécuter le mode interactif. Vous pouvez forcer le démarrage de python en mode interactif avec -i
:
IO.popen("python -i", "r+") do |py|
while cmd = gets
py.puts cmd
puts py.gets
end
end
Vous devrez probablement travailler pour enlever le >>>
invite, etc.
MODIFIER: voici la version multi-lignes conviviale (je conserve le code est clair et répond à la question initiale):
IO.popen("python -i", "r+") do |py|
loop do
fds = IO.select [py, STDIN]
fds.each do |(fd)|
case fd
when nil; next
when STDIN; py.puts gets
else; puts py.gets
end
end
end
end
2 pour la réponse № 2
Voici une approche alternative utilisant la bibliothèque de pseudo-terminaux de Ruby. J'ai "testé cela avec Ruby 1.9 sur Linux et MacOS X, il ne fonctionnera probablement pas sous Windows:
require "pty"
begin
# stty -echo turns off terminal echo, without it tty input would be repeated
# on output
PTY.spawn( "stty -echo; python" ) do |r, w, pid|
begin
cmd = nil
begin
w.puts cmd if cmd != nil
# non-blocking read of stdout with 2 seconds timeout
while IO.select([r], nil, nil, 2)
print r.getc
end
end while cmd = gets
rescue Errno::EIO
puts "end of output"
end
end
rescue PTY::ChildExited => e
puts "The child process exited."
end