Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > stubborn program using readline

Reply
Thread Tools

stubborn program using readline

 
 
Wybo Dekker
Guest
Posts: n/a
 
      06-16-2005
Hi,

I've been on the list a few days ago with a readline-problem, for which
there doesn't seem to be a quick fix. I'm now trying a dirty fix... but
this seems to be a very stubborn problem.

Here is my original test program

# rltest - test for readline
# run me like this: (i.e. operating on a file)
#
# ruby rltest rltest
#
# and all is fine. But run me like so: (i.e. operating on stdin)
#
# ruby rltest < rltest
#
# and see that I successfully count my own lines,
# then also print the "type return to quit" prompt,
# but finally seem to be looping in the readline function, and
# can only be stopped with ctrl-C,
# ( not even with ctrl-D - I'm not looking at the terminal)

require 'readline'
include Readline

# count lines in stdin (the mail message):
n=0; while gets: n+=1 end
puts "#{n} lines"

readline("type return to quit: ")
puts "quitting..."

I tried to get around this problem by testing if input is from stdin,
and if so, making a temporary copy of stdin and re-running the program
on that copied file:

file = ARGV.shift || ''
if file == ''
require 'tempfile'
f = Tempfile.new('vpp')
name = f.path
puts "Making temporary file: #{name}"
n = 0
while gets
f.puts
n += 1
end
f.close
puts "Wrote #{n} lines"
system($0, name)
else
require 'readline'
include Readline
puts "reading #{file}"
# count lines in stdin (the mail message):
n = 0
open(file).each do
n+=1
end
puts "Saw #{n} lines"

readline("type return to quit: ")
puts "quitting..."
end

Running this with: ruby rltest rltest says:

reading rltest
Saw 30 lines
type return to quit:
quitting...

But to my astonishment, running with: ruby rltest < rltest stays in a
loop, like the original test program:

Making temporary file: /data/tmp/vpp19009.0
Wrote 30 lines
reading /data/tmp/vpp19009.0
Saw 30 lines
type return to quit:
./rltest:28:in `readline': Interrupt
from ./rltest:28

Can anybody explain this?

--
Wybo


 
Reply With Quote
 
 
 
 
Logan Capaldo
Guest
Posts: n/a
 
      06-16-2005
On 6/16/05, Wybo Dekker <> wrote:
> Hi,
>=20
> I've been on the list a few days ago with a readline-problem, for which
> there doesn't seem to be a quick fix. I'm now trying a dirty fix... but
> this seems to be a very stubborn problem.
>=20
> Here is my original test program
>=20
> # rltest - test for readline
> # run me like this: (i.e. operating on a file)
> #
> # ruby rltest rltest
> #
> # and all is fine. But run me like so: (i.e. operating on stdin)
> #
> # ruby rltest < rltest
> #
> # and see that I successfully count my own lines,
> # then also print the "type return to quit" prompt,
> # but finally seem to be looping in the readline function, and
> # can only be stopped with ctrl-C,
> # ( not even with ctrl-D - I'm not looking at the terminal)
>=20
> require 'readline'
> include Readline
>=20
> # count lines in stdin (the mail message):
> n=3D0; while gets: n+=3D1 end
> puts "#{n} lines"
>=20
> readline("type return to quit: ")
> puts "quitting..."
>=20
> I tried to get around this problem by testing if input is from stdin,
> and if so, making a temporary copy of stdin and re-running the program
> on that copied file:
>=20
> file =3D ARGV.shift || ''
> if file =3D=3D ''
> require 'tempfile'
> f =3D Tempfile.new('vpp')
> name =3D f.path
> puts "Making temporary file: #{name}"
> n =3D 0
> while gets
> f.puts
> n +=3D 1
> end
> f.close
> puts "Wrote #{n} lines"
> system($0, name)
> else
> require 'readline'
> include Readline
> puts "reading #{file}"
> # count lines in stdin (the mail message):
> n =3D 0
> open(file).each do
> n+=3D1
> end
> puts "Saw #{n} lines"
>=20
> readline("type return to quit: ")
> puts "quitting..."
> end
>=20
> Running this with: ruby rltest rltest says:
>=20
> reading rltest
> Saw 30 lines
> type return to quit:
> quitting...
>=20
> But to my astonishment, running with: ruby rltest < rltest stays in a
> loop, like the original test program:
>=20
> Making temporary file: /data/tmp/vpp19009.0
> Wrote 30 lines
> reading /data/tmp/vpp19009.0
> Saw 30 lines
> type return to quit:
> ./rltest:28:in `readline': Interrupt
> from ./rltest:28
>=20
> Can anybody explain this?
>=20
> --
> Wybo
>=20
>=20


Theory: readline reads from STDIN correct? using rltest < rltest means
that STDIN gets EOF, which means STDIN is closed which means readlien
can't read anything from it. I don't think you can have your cake and
eat it too in this case. If you want the interactive prompt your going
to have pass the file name on the command line instead of using IO
redirection. I'm a bit confused as to the purpose of this.


 
Reply With Quote
 
 
 
 
Wybo Dekker
Guest
Posts: n/a
 
      06-16-2005
On Thu, 16 Jun 2005, Logan Capaldo wrote:

> Theory: readline reads from STDIN correct? using rltest < rltest means
> that STDIN gets EOF, which means STDIN is closed which means readlien
> can't read anything from it.


No, readline should not necessarily read from STDIN. It can read from the
console, /dev/tty or so.

> I don't think you can have your cake and
> eat it too in this case. If you want the interactive prompt your going
> to have pass the file name on the command line instead of using IO
> redirection. I'm a bit confused as to the purpose of this.


What I want is a program that reads data from either a file or STDIN and
then lets the user run various commands on those data.

To be more specific, it's a program (vpp, http://www.servalys.nl/scripts/vpp)
that I have written in Perl and it reads a PDF (or PostScript) file,
displays it, and after this offers the user a command prompt where she can
choose to print some pages, or all pages, in various formats (booklet,
one-sided, two-sided), either to a printer or to an other PDF file.

PDF (or PostScript) files can be offered to it:

vpp some_pdf_or_postscript_file

or piped to it:

vpp <some_pdf_or_postscript_file

The latter is particularly useful if, for example, you want to print
selected pages from a man page. For example:

man -t ruby |vpp

This worked fine in Perl, but can't be done in the Ruby version which
I'm trying to make...

I quess you cannot translate the following Perl script into Ruby

#!/usr/bin/perl -w

# showline - read lines from stdin,
# then let user interrogate lines by number

my @x;
while (<>) {
push(@x,$_);
}

use Term::ReadLine;
my $t=new Term::ReadLine 'vpp';

while ( (my $n = $t->readline("type line number (0 to stop): ")) > 0) {
if ( $n > @x) {
print "no such line\n";
} else {
print "line $n: $x[$n-1]";
}
}

and then run it like so:

$ showline < showline
type line number (0 to stop): 1
line 1: #!/usr/bin/perl -w
type line number (0 to stop): 3
line 3: # showline - read lines from stdin,
type line number (0 to stop): 20
line 20: }
type line number (0 to stop): 21
no such line
type line number (0 to stop): 0
$

--
Wybo


 
Reply With Quote
 
Wybo Dekker
Guest
Posts: n/a
 
      06-17-2005
On Fri, 17 Jun 2005, Jonathan Paisley wrote:

> On Fri, 17 Jun 2005 08:41:22 +0900, Wybo Dekker wrote:
>
> > On Thu, 16 Jun 2005, Logan Capaldo wrote:
> >
> >> Theory: readline reads from STDIN correct? using rltest < rltest means
> >> that STDIN gets EOF, which means STDIN is closed which means readlien
> >> can't read anything from it.

> >
> > No, readline should not necessarily read from STDIN. It can read from the
> > console, /dev/tty or so.

>
> Since you always want to readline from the terminal, try that:
>
> tty = open("/dev/tty","a+")
> tty.readline


That's too simple: it does not use the readline library with its editing
and completion facilities.

What I need is a translation of this simple Perl example into Ruby -
I think Ruby can't do this:

#!/usr/bin/perl -w

# showline - read lines from stdin (either file or pipe),
# then let user interrogate lines by number

use Term::ReadLine;

push(@x,$_) while <>;
print scalar(@x)," lines\n";

$t=new Term::ReadLine 'vpp';

while (1) {
$_ = $t->readline("type line number (0 to stop): ");
PROMPT: {
/^\d+$/ or do { print "Not a positive number\n"; last PROMPT};
$_ > @x and do { print "No such line\n"; last PROMPT};
$_ and do { print "line $_: $x[$_-1]"; last PROMPT};
die "thanks!\n";
}
}

Typical run:

$ showline <showline
21 lines
type line number (0 to stop): 1
line 1: #!/usr/bin/perl -w
type line number (0 to stop): 3
line 3: # showline - read lines from stdin (either file or pipe),
type line number (0 to stop): 20
line 20: }
type line number (0 to stop): 30
No such line
type line number (0 to stop): 0
thanks!
$

--
Wybo


 
Reply With Quote
 
James Edward Gray II
Guest
Posts: n/a
 
      06-17-2005
On Jun 17, 2005, at 9:28 AM, Wybo Dekker wrote:

> What I need is a translation of this simple Perl example into Ruby -
> I think Ruby can't do this:


[snip code]

I think it can:

#!/usr/local/bin/ruby -w

require "readline"
include Readline

lines = ARGF.readlines
puts "#{lines.size} lines."

loop do
line = readline("Line number: ", true)

if line !~ /^\d+$/
puts "Please enter a positive integer."
else
number = line.to_i
case number
when 0
break
when 1..lines.size
puts "Line #{number}: #{lines[number - 1]}"
else
puts "No such line."
end
end
end

__END__

My run:

$ ruby showlines.rb showlines.rb
25 lines.
Line number: 1
Line 1: #!/usr/local/bin/ruby -w
Line number: 16
Line 16: case number
Line number: 17
Line 17: when 0
Line number: 18
Line 18: break
Line number: 1003
No such line.
Line number: darn
Please enter a positive integer.
Line number: 0

Hope that helps.

James Edward Gray II


 
Reply With Quote
 
Wybo Dekker
Guest
Posts: n/a
 
      06-17-2005
On Sat, 18 Jun 2005, James Edward Gray II wrote:

> On Jun 17, 2005, at 9:28 AM, Wybo Dekker wrote:
>
> > What I need is a translation of this simple Perl example into Ruby -
> > I think Ruby can't do this:

>
> [snip code]
>
> I think it can:


Sure, when you run it with a file argument.
But now try to run it on stdin.
For example:

$ showlines.rb < showlines.rb

It won't work. In Perl, it will.

> #!/usr/local/bin/ruby -w
>
> require "readline"
> include Readline
>
> lines = ARGF.readlines
> puts "#{lines.size} lines."
>
> loop do
> line = readline("Line number: ", true)
>
> if line !~ /^\d+$/
> puts "Please enter a positive integer."
> else
> number = line.to_i
> case number
> when 0
> break
> when 1..lines.size
> puts "Line #{number}: #{lines[number - 1]}"
> else
> puts "No such line."
> end
> end
> end
>
> __END__
>
> My run:
>
> $ ruby showlines.rb showlines.rb
> 25 lines.
> Line number: 1
> Line 1: #!/usr/local/bin/ruby -w
> Line number: 16
> Line 16: case number
> Line number: 17
> Line 17: when 0
> Line number: 18
> Line 18: break
> Line number: 1003
> No such line.
> Line number: darn
> Please enter a positive integer.
> Line number: 0
>
> Hope that helps.
>
> James Edward Gray II
>
>


--
Wybo


 
Reply With Quote
 
Ara.T.Howard
Guest
Posts: n/a
 
      06-17-2005
On Fri, 17 Jun 2005, Wybo Dekker wrote:

> On Thu, 16 Jun 2005, Logan Capaldo wrote:
>
>> Theory: readline reads from STDIN correct? using rltest < rltest means
>> that STDIN gets EOF, which means STDIN is closed which means readlien
>> can't read anything from it.

>
> No, readline should not necessarily read from STDIN. It can read from the
> console, /dev/tty or so.
>
>> I don't think you can have your cake and
>> eat it too in this case. If you want the interactive prompt your going
>> to have pass the file name on the command line instead of using IO
>> redirection. I'm a bit confused as to the purpose of this.

>
> What I want is a program that reads data from either a file or STDIN and
> then lets the user run various commands on those data.


put another way - you want the program to ALWAYS read from EITHER a file or
stdin and you ALWAYS want to interactively (eg. from a tty) run commands after
reading the file - so why not just say that in the code?

#
# program which does the above
#
jib:~ > cat a.rb
require 'readline'
include Readline

inpath = ARGV.shift
infile = inpath ? open(inpath) : STDIN

# count lines in stdin (the mail message):
n=0; while infile.gets: n+=1 end
puts "#{n} lines"

# always get commands interactively
STDIN.reopen '/dev/tty' unless STDIN.tty?
readline("type return to quit: ")
puts "quitting..."

#
# reading interactively from stdin and typing ctrl-D
#
jib:~ > ruby a.rb
one
two
three
3 lines
type return to quit:
quitting...

#
# reading non-interactively from stdin
#
jib:~ > ruby a.rb < a.rb
13 lines
type return to quit:
quitting...

#
# reading from file
#
jib:~ > ruby a.rb a.rb
13 lines
type return to quit:
quitting...


you could take other approaches with dup'ing and forking but this might work
for you.

hth.

-a
--
================================================== =============================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple. My religion is kindness.
| --Tenzin Gyatso
================================================== =============================



 
Reply With Quote
 
Wybo Dekker
Guest
Posts: n/a
 
      06-17-2005
On Sat, 18 Jun 2005, Ara.T.Howard wrote:

> put another way - you want the program to ALWAYS read from EITHER a file or
> stdin and you ALWAYS want to interactively (eg. from a tty) run commands after
> reading the file - so why not just say that in the code?
>
> #
> # program which does the above
> #
> jib:~ > cat a.rb
> require 'readline'
> include Readline
>
> inpath = ARGV.shift
> infile = inpath ? open(inpath) : STDIN
>
> # count lines in stdin (the mail message):
> n=0; while infile.gets: n+=1 end
> puts "#{n} lines"
>
> # always get commands interactively
> STDIN.reopen '/dev/tty' unless STDIN.tty?
> readline("type return to quit: ")
> puts "quitting..."
>
> you could take other approaches with dup'ing and forking but this might work
> for you.


This did it!!
The essential line is: STDIN.reopen '/dev/tty' unless STDIN.tty?
and I would say that this should actually be done in Readline at the first
call of readline.
I rewrote my Perl program showlines:

#!/usr/bin/env ruby

#
# showlines - read lines from stdin (either file or pipe),
# then let user interrogate lines by number

require 'readline'
include Readline

# store and count lines in stdin:
x = []
while gets: x.push($_) end
puts "#{x.size} lines"

# always get commands interactively
STDIN.reopen '/dev/tty' unless STDIN.tty?
loop do
line = readline("type line number (0 to stop): ",true)
if line !~ /^\d+$/
puts "Please enter a positive integer."
else
number = line.to_i
case number
when 0
puts "quitting..."
exit 0
when 1..x.size
puts "Line #{number}: #{x[number - 1]}"
else
puts "No such line."
end
end
end

and this now works as expected:

$ showlines <showlines
33 lines
type line number (0 to stop): 1
Line 1: #!/usr/bin/env ruby
type line number (0 to stop): 16
Line 16: STDIN.reopen '/dev/tty' unless STDIN.tty?
type line number (0 to stop): 33
Line 33: end
type line number (0 to stop): 133
No such line.
type line number (0 to stop): 0
quitting...
$

Thank you very much!

--
Wybo


 
Reply With Quote
 
Ara.T.Howard
Guest
Posts: n/a
 
      06-17-2005
On Sat, 18 Jun 2005, Wybo Dekker wrote:

> On Sat, 18 Jun 2005, Ara.T.Howard wrote:
>
>> put another way - you want the program to ALWAYS read from EITHER a file or
>> stdin and you ALWAYS want to interactively (eg. from a tty) run commands after
>> reading the file - so why not just say that in the code?
>>
>> #
>> # program which does the above
>> #
>> jib:~ > cat a.rb
>> require 'readline'
>> include Readline
>>
>> inpath = ARGV.shift
>> infile = inpath ? open(inpath) : STDIN
>>
>> # count lines in stdin (the mail message):
>> n=0; while infile.gets: n+=1 end
>> puts "#{n} lines"
>>
>> # always get commands interactively
>> STDIN.reopen '/dev/tty' unless STDIN.tty?
>> readline("type return to quit: ")
>> puts "quitting..."
>>
>> you could take other approaches with dup'ing and forking but this might work
>> for you.

>
> This did it!!
> The essential line is: STDIN.reopen '/dev/tty' unless STDIN.tty?
> and I would say that this should actually be done in Readline at the first
> call of readline.
> I rewrote my Perl program showlines:


i think it's a bit more complicated than that because then you could not do

readline_program.rb < commands.txt

which would be bad. i'd have to look into perl module to see what they do -
but i suspect it would also give some suprising behaviour under certain
conditions too... it's just too tough to imagine all the combinations of
tty/stdin one might want in a program... but maybe not.

cheers.

-a
--
================================================== =============================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| My religion is very simple. My religion is kindness.
| --Tenzin Gyatso
================================================== =============================



 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
compiling python 3.1.2 with local readline fails to get readline - help! gavino Python 4 09-20-2010 05:17 AM
Getting application ReadLine and Perl debugger ReadLine to cooperate Andrew DeFaria Perl Misc 1 01-30-2008 11:46 PM
Readline::readline() blocking all other threads Jean-Michel Ruby 0 12-22-2007 01:00 AM
Re: Ejecting stubborn thanatoid - was - Re: Ejecting stubborn CD thanatoid Computer Support 0 03-29-2007 12:03 AM
Firefox 1.5 being stubborn with some links RyeTronics Firefox 6 01-13-2006 06:42 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57