RyanWilcox
RyanWilcox

Reputation: 13972

Pry not stopping when called from a Ruby script that reads from stdin

I've created a console Ruby script that uses ARGF to load data from a file or stdin, that then calls Pry.

This works great when I pass a file in (Pry pauses) but fails (Pry doesn't stop and just exits Ruby) when I pass my data using stdin.

This is weird, anyone know why? I would like to pass data in via stdin and have Pry pause.

Behold, an example script:

require 'rubygems'
require 'pry'


def pry_it(str)
    binding.pry
end

pry_it(ARGF.read)

When I call this app with a file in ARGV I get my proper response - pry pausing

% bundle exec ruby pry_test.rb file.txt

From: /Users/wilcoxr/Development/json_pry/pry_test.rb @ line 8 Object#pry_it:

    6: def pry_it(str)
    7:
 => 8:  binding.pry
    9: end

[1] pry(main)>

Great! I can execute Pry commands all I want

When I try to use STDIN to send data into my tool:

% cat file.txt | bundle exec ruby pry_test.rb

From: /Users/wilcoxr/Development/json_pry/pry_test.rb @ line 8 Object#pry_it:

    6: def pry_it(str)
    7:
 => 8:  binding.pry
    9: end

[1] pry(main)>
% 

Look closely: note I'm back at my shell prompt, not pauses in IRB. Weird! I don't understand why I'm getting this behavior....

Upvotes: 13

Views: 3180

Answers (1)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

Try ARGF with simple:

require 'rubygems'
require 'pry'
binding.pry

Now IO operations are not covered internally by ARGF.read and it became evident what’s wrong here. ARGF is “glued” to STDIN, therefore whatever is being passed to STDIN goes directly to pry’s input.

I do not know exactly, what instruction in your file.txt forces pry to quit, but there is one.


UPDATE

It looks like if a Ruby script yields anything on stdin (e. g. through a pipe,) both $stdin and STDIN are set to this pipe, messing up pry’s “where am I run from” detection.

I came up with this not-so-elegant solution:

# read input from ARGF
text = ARGF.read

# prepare new stdin to satisfy pry
pry_fd_stdin = IO.sysopen("/dev/tty")
pry_stdin = IO.new(pry_fd_stdin, "r")

# load pry and cheat it with our stdio
require 'pry'
Pry.config.input = pry_stdin

binding.pry

This solution has some glitches (e.g. pry prompt is shown only after input).

Upvotes: 8

Related Questions