Running an interactive program from Ruby - ruby

I am trying to run gnuplot from ruby (not using an external gem) and parsing its textual output also. I tried IO.popen, PTY.spawn and Open3.popen3 but whenever I try to get the output it just "hangs" -I guess waiting for more output to come. I feel like its somehow done using Thread.new but I couldn't find the correct way to implement it.
Anyone know how it is done?

I guess this is what you want:
require 'pty'
require 'expect'
PTY.spawn('gnuplot') do |input, output, pid|
str = input.expect(/gnuplot>/)
puts str
output.puts "mlqksdf"
str = input.expect(/gnuplot>/)
puts str
output.puts "exit"
end

The problem is that the sub-program is waiting for input that isn't being sent.
Typically, when we call a program that expects input on STDIN, we have to close STDIN, which then signals that program to begin processing. Look through the various Open3 methods and you'll see where stdin.close occurs in many examples, but they don't explain why.
Open3 also includes capture2 and capture3, which make it nice when trying to deal with a program that wants STDIN and you don't have anything to send to it. In both methods, STDIN is immediately closed, and the method returns the STDOUT, STDERR and exit status of the called program.
You need "expect" functionality. Ruby's Pty class includes an expect method.
Creates and managed pseudo terminals (PTYs). See also en.wikipedia.org/wiki/Pseudo_terminal
It's not very well documented though, and doesn't offer a lot of functionality from what I've seen. An example of its use is available at "Using Ruby Expect Library to Reboot Ruckus Wireless Access Points via ssh".
Instead, you might want to look at RubyExpect which is better documented and appears to be current.

Related

Using Ruby to execute arbitrary system calls

This problem is to get into an internship within a devops department:
"Write a ruby library that executes arbitrary system calls (eg: “dmesg", "ping -c 1 www.google.com”) and provides separated output streams of stderr and stdout as well are providing the final return code of the process. Show your work with unit tests.”
Am I supposed to use already established system calls and replicate them in Ruby code? That seems silly to me. Am I supposed to come up with my own arbitrary calls and write a library complete with errors and status calls?
I am not looking for someone to write this for me. I feel that the first step to solving this problem is understanding it.
Get Clarification from the Source
The assignment is poorly worded, and misuses a number of terms. In addition, we can only guess what they really expect; the appropriate thing to do would be to ask the company directly for clarification.
Re-Implement Open3
With that said, what they probably want is a way to process any given command and its arguments as a decorated method, akin to the way Open3#capture3 from the standard library works. That means the code you write should take the command and any arguments as parameters.
For example, using Open3#capture3 from the standard library:
require 'open3'
def command_wrapper cmd, *args
stdout_str, stderr_str, status = Open3.capture3 "#{cmd} #{args.join ' '}"
end
command_wrapper "/bin/echo", "-n", "foo", "bar", "baz"
#=> ["foo bar baz", "", #<Process::Status: pid 31661 exit 0>]
I sincerely doubt that it's useful to re-implement this library, but that certainly seems like what they're asking you to do. Shrug.
You're also supposed to write unit tests for the re-implementation, so you will have to swot something up with a built-in framework like Test::Unit or MiniTest, or an external testing framework like RSpec, or Wrong. See the Ruby Toolbox for a more comprehensive list of available unit testing frameworks.
Luckily for you, Ruby makes it very easy to interact with the underlying operative system.
You can start by reading the documentation for these methods:
Kernel#`
Kernel#system
Kernel#exec
Kernel#spawn
IO#popen
Also, there is the Open3 module from the stdlib.

Ruby: Is there any way to create a program that can be opened by double clicking and that doesn't close instantly?

If I create a program, for instance, that just says puts "Hello world!" it will open and close instantly or if I create a program that just says
puts "Enter some text!"
response = gets.chomp
puts "You said '#{response}'"
it will close right after entering input with enter.
So, is there anything I can put in the code that will keep the program open? I've heard of solutions like putting gets at the end of the program but that doesn't wok for me. I also don't want to open it with command prompt since double clicking it seems to work other than that the program closes abruptly.
What do you mean by open? Files can be open, but not programs: Programs run. If you want to keep your program running, just use an endless loop before you reach the last statement.
That much being said, you might be concerned about interfaces. There are basically two kinds of interfaces: Textual or graphical. Both have advantages and disadvantages. If you are into graphical interfaces, you might be interested in GUI gems such as gtk2 / gtk3. You can use them to pop up windows with input boxes, buttons etc. that keep running until the user takes an action that closes them.
But you seem to be interested in textual interfaces. In that case, let me announce it to you that there is an excellent textual interface platform in Ruby: irb.
Newbies frequently make a mistake of reinventing REPL interface, like having main loop that always ask via gets what the user wants to do and giving options A, B, C, ..., or allowing the user to type in a command etc.
Thanks to irb, your program often does not need the main loop. Instead of using gets with a set of commands, you can simply define methods and let the user interact with them inside irb. To provide a concrete example, a newbie programmer might decide to write the following program:
loop do
puts "Enter some text!"
response = gets.chomp
puts "you said '#{response}'"
end
This program provides its own REPL loop that echoes back whatever you type in. A more experienced programmer would realize that this is reinventing the wheel and would simply define a method #echo:
def echo text
puts "you said '#{text}'"
end
echo "hello"
#=> you said 'hello'
Your program "ends" but irb REPL keeps running, it's there for you to type echo "something" as many times as you wish. The morale of the story is, in Ruby, avoid reinventing REPL interfaces unles you know what you are doing. Other good textual interface with additional capabilities is pry (gem install pry).

Make Ruby console execution more verbose

I want to watch the flow the execution of my ruby code when I am in the console. For example, if I have this :
def process
hash = {a:1,b:2}
hash.values.map!{|e| e+1}
end
And I want to see something like this in console when I type process :
hash = {a:1,b:2}
=> {:a=>1, :b=>2}
hash.values.map!{|e| e+1}
=> [2, 3]
Is there a useful way to do something like this?
$VERBOSE doesn't seems to do anything and $DEBUG seems as the opposite to be too verbose.
You're talking about "trace" functionality.
Some languages, like shell and good-ol' GWBasic, have a flag to show their currently executing line. Ruby's $DEBUG output can flood you with information overload, not so much from your code, but from any gems that look for it and dump their current state or turn on their tracing.
Many people sprinkle their code with puts to have it show some indicator of where they are, during their development/testing. If you do that, I'd recommend writing it as a method to bottleneck your output and let you easily turn it on/off. Also, use a flag to check whether you want to debug. You might even want to use OptionParser to let you create a --debug flag to pass on the command-line. Another nice side-effect of using a method is it's easy to redirect the output to a file you can tail and watch the output as it occurs, and later use for triage.
Another alternative is to load the code into the debugger and tell it to trace. You'll see every step of the code, which is very verbose, but the detail is good. You can also tell it to run to certain points so you can poke at the code and dig around, dropping into IRB if needed.
Personally, being old-school and having cut my teeth on assembly-language, I'm comfortable in debuggers, so I use Ruby's a lot. It's easy to tell it to run to a certain spot and stop, or you can embed include 'debugger'; debugger into your code and it'll stop at that point. Once there, it's possible to see what's going on, then c to continue, and let the program run until it hits the debugger statement again. I find the debugger to be very powerful and a nice selective magnifying glass for those times I want to know what's going on.
"Debugging in Ruby" has lots of nice tips you might find useful too.
EDIT:
I like Alex D's suggestion to look into Ruby's set_trace_func. I haven't used it (and, frankly forgot about it), but that'd be a good way to set up a nice trace in an app. With a little code you could set up toggling it on/off and selectively outputting given a certain class or condition since you're in control of the proc being called.
One option would be to use set_trace_func (http://apidock.com/ruby/Kernel/set_trace_func) to set up a hook which will print out each line as it is executed. Be aware that may overwhelm you with a bunch of information on the internals of irb.
Another option would be to dig into the source code for irb and add an option to print each line as it is executed.
Have you tried the pry gem? Put require 'pry'; binding.pry inside your code and run your script. You will have a ruby console just where your put it. Maybe that is what you are looking for.
Otherwise you should take a look at a ruby debugger.

Ruby: console.log?

I recently put console.log statements in every line of a JavaScript program and found that it's now much easier to understand. Is there a way to do that with server side code, specifically Ruby? I presume there's no way to read it in firebug, but would it be visible in irb? what console.log equivalent statements would I put in the Ruby code?
puts is the equivalent in ruby.
Example
puts 'Hello World!'
If you are running your server in the console, you can use puts. Otherwise, you will need to write to a file, possibly via a logger (like Rails.logger.info).

How can you interact with Perl programs from Ruby?

It's my understanding that there's no "bridge" between Ruby and Perl to let you call into Perl functions directly from Ruby. It's also my understanding that to call a Perl program from Ruby, you simply put it in backticks(i.e. result = `./helloWorld.pl`). However, this doesn't allow interaction with the Perl program(i.e. you can't interact with prompts or provide input). My quesitons are as follows:
Is there any way to provide input to Perl programs from Ruby(aside from arguments)?
Am I wrong that there is no bridge between Ruby and Perl? Interacting with a program's stdin seems like the wrong way to go when navigating prompts, and the programs I'm dealing with are well-designed and have libraries with the appropriate Perl functions in them.
There's the Inline::Ruby module, though I don't have any direct experience with it that I can share.
EDIT: I did try it out last night -- here's the review: Inline::Ruby was last updated in 2002, when v5.6 was the latest stable release. Docs say it has only been tested on Linux; I was trying to use it with v5.10.1 on Cygwin. Got it to build after some hacking of the XS/C code that comes with the module. Passed some unit tests but failed others. Seemed to import Ruby class's into Perl's namespace ok but was less successful importing standalone functions. Summary: if you need a quick and dirty bridge for Perl and Ruby, Inline::Ruby will probably disappoint you. If you have the patience to figure out how to build the module on your system, and to massage your Ruby code to work with the module, you could find it useful.
Use Ruby's exec()
rubypl.rb
#!/usr/bin/ruby -w
script = 'perlscript.pl'
exec("/usr/bin/perl #{script}")
perlscript.pl
#!/usr/bin/perl -w
use strict;
print "Please enter your name: ";
my $name = <STDIN>;
chop($name);
if ($name eq "")
{
print "You did not enter a name!\n";
exit(1);
} else {
print "Hello there, " . $name . "\n";
exit(0);
}
perldoc perlipc states:
DESCRIPTION
The basic IPC facilities of Perl are built out of the good old Unix
signals, named pipes, pipe opens, the Berkeley socket routines, and
SysV IPC calls. Each is used in slightly different situations.
Ruby is capable of operating each of these.
Here's how ruby can use a python script, interacting with the script's stdin and stdout.
foo.py reads two integers (each on its own line) from standard input, adds them, and writes the result to standard-out. I don't know perl, so be nice to me:
#!/usr/bin/perl
$a = <STDIN>;
$b = <STDIN>;
$c = int($a) + int($b);
print $c;
foo.rb executes foo.py, giving it two numbers to add, getting back the result and printing it:
#!/usr/bin/ruby1.8
a = 1
b = 2
c = IO.popen('./foo.py', 'w+') do |pipe|
pipe.puts(a)
pipe.puts(b)
pipe.close_write
pipe.read
end
raise "foo.py failed" unless $? != 0
print "#{a} + #{b} = #{c}" # => 1 + 2 = 3
What you want doesn't really exist, to my knowledge.
The closest thing to what you want, on a generic level, is XDebug. It turns a process into a little server that will accept debugging commands. This is generally used for debugging and profiling and not as interprocess communication, but its a possibility. I believe ActiveState's Perl can be run as an XDebug server.
Otherwise, you need explicitly program in some sort of side-channel that your Perl program listens to for commands (which is what XDebug does). It can be as simple as opening a socket that reads a string, evals it, encodes the result as YAML (or whatever) and writes it back. A REPL, but on a socket rather than on a terminal.
There are, obviously, security implications which will be left as an exercise for the reader. You also don't want listening to the socket to interrupt the program so you will now need something event-driven or threaded.
Sorry I don't have anything more specific. It would make a great CPAN module.
Perl and Ruby both have various "glues". Perl programs using the Expect module can do a lot more than just "wait for output". More likely though, you could communicate with a well-known protocol like HTTP... a Ruby daemon could put up a listener, and Perl could contact it, or vice versa.
But no, you can't just "embed" ruby code into Perl, or vice versa. You've got to run separate processes and communicate somehow.
Try Open4 . It is not designed specific for interacting with perl but with any program that need input and ouput. I am still learning to use it ,but I feel it might suit your need.
You mentioned in one of your comments that you want to run Perl code inside Ruby. This will not work unless you can make the Ruby interpreter understand Perl syntax. Can I get a BNF/yacc/RE for the Perl language? will help you understand the challenges you will face.

Resources