Execute shell commands from Ruby code - ruby

Note: If you think of a better title/question, feel free to suggest it. I wasn't sure how to articulate this question in one brief sentence.
I created a command line Mastermind game. To play the game, you type play.rb at the command line.
play.rb is a Ruby script that fires up the game. Within the script, the game is sent an interface, called CommandLineInterface.
If you want to play using a GUI (I'm using a Ruby GUI called Limelight), you cd into the limelight directory and type limelight open production and the GUI opens.
There is a mastermind_game directory that contains a lib, a spec, and a limelight directory. The limelight directory contains a production directory.
Now I'm making a few changes. You can pass arguments to the script at the command line. Either you enter play.rb "command line game" or play.rb "limelight game".
ARGV is an array of the arguments passed at the command line.
if ARGV.include?("command line game")
interface = CommandLineInterface.new
elsif ARGV.include?("limelight game")
interface = LimelightInterface.new
end
If I want to play my command line game, I enter play.rb "command line game" and it works fine.
I want to be able to type play.rb "limelight game" at the command line and have that open the GUI. In ARGV, the argument "limelight game" would be found so interface would be set to LimelightInterface.new. Within my LimelightInterface class I want the initialize method to open the GUI. It should essentially have the same functionality as typing limelight open production at the command line.
I'm not sure if this is possible or how to do it, so any help would be appreciated! Thanks!
EDITED: I'm trying to execute the command rvm use jruby by including this line in my script:
system("rvm use jruby")
I get back: "RVM is not a function, selecting rubies with 'rvm use ...' will not work."

Ryan, there's several ways to call out to the system:
Backticks:
ruby -e 'p ARGV' '1 2' '3 4' # => "[\"1 2\", \"3 4\"]\n"
The %x literal (note that you can use any delimiter you like, you're not restricted to parentheses)
%x(ruby -e 'p ARGV' '1 2' '3 4') # => "[\"1 2\", \"3 4\"]\n"
The system command. The difference here is that it passes stdin / out / err on through. (the above return the stdout, this one prints it on your process' stdout).
system('ruby', '-e p ARGV', '1 2', '3 4')
# >> ["1 2", "3 4"]
And if you need more sophisticated usage, something like open3 from the stdlib has gotten me pretty far. If you really need the big guns (it doesn't sound like you do), there's a gem open4.
Edit:
It sounds like you're wanting to do something like this:
require 'open3'
bash_script = <<SCRIPT
source "$HOME/.rvm/scripts/rvm"
rvm use jruby
ruby -v
exit
SCRIPT
out, err, status = Open3.capture3 'bash', stdin_data: bash_script
puts out
# >> Using /Users/joshcheek/.rvm/gems/jruby-1.6.7
# >> jruby 1.6.7 (ruby-1.8.7-p357) (2012-02-22 3e82bc8) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_29) [darwin-x86_64-java]
But honestly, I don't think it's a good solution for your situation, because there's many legitimate ways to set up jruby for your environment. I think it would be better to just check that the limelight binary exists, and tell your user to fix their environment if it doesn't.

Here's the first result from googling the title: http://tech.natemurray.com/2007/03/ruby-shell-commands.html
If that's not what you need, I don't understand the question.

Related

Ruby - How to use -r switch with ruby command line tool

I was trying to figure out how to work the command line switch -r.
My understanding is that the code is typed out as follows:
ruby -r*nameOfRequired*
I am finding that this is not the case. When I type out the above and press enter, the terminal expects an "end of input syntax" and does not continue.
What am I missing? Does there need to be a space in between the switch and the name of the required file?
Please and thank you!
EDIT:
I am currently reading "The Well Grounded Rubyist" by David A. Black, and I came up with this question while reading the section on command line switches.
Having said that, I created a "test.rb" file, containing:
puts Date.today
Then, in the terminal, I typed out:
ruby -r date
I thought this would 'require' the date module, and then enable me to run the "test.rb" file, using ruby test.rb (given that I am in the correct directory).
Instead, the terminal cursor moves to a newline, expecting more input. Let me know if I need to clarify anything else. Thanks!
If you just type ruby -rmodule, then Ruby will load the module and wait for you to type the main program that requires that module.
If you just want to run the module and do nothing else, you can do do rubyfull-path-to-module without the -r, or ruby -rmodule -e exit, or ruby -rmodule </dev/null, or similar.
In general, the ruby command does not record any state from one run to the next, so you need to tell it every thing that it needs to know whenever you run it.
Whenever you run it, you need to tell it the main program to run or else it will expect you to type that program on the standard input. The -r does not specify the main program.
Try this:
ruby -rdate test.rb
According to ruby -h:
-rlibrary require the library, before executing your script
Without giving your script file path, it read the script from stdin.
Try following (You can omit script file path when you give -e command):
ruby -r**nameOfRequired** -e ""

Ruby .gets doesn't work

I'm trying to get simple user input in Ruby, but I can't get it working. I'm using the gets method, but the program never stops to ask me for input. I'm using Sublime Text 2 as my text editor, and I run the program in it, too (if this makes a difference).
Here's my code:
puts "What is your name?"
name = gets
puts "Hello " + name + ". How are you?"
And here's the error (and output) given to me:
C:/Users/Sten Sootla/Desktop/Ruby workspace/exercise.rb:3:in `+': can't convert nil into String (TypeError)
from C:/Users/Sten Sootla/Desktop/Ruby workspace/exercise.rb:3:in `'
What is your name?
[Finished in 0.1s with exit code 1]
Why doesn't the program stop to ask me for input?
Try using $stdin.gets instead of just a plain gets, this will force the input to come from stdin
Here's how I understand it. gets and puts are instance methods of IO, and the default IOs are $stdout and $stdin.
Calls to gets/puts will only be effective if the translator is capable of handling stdout/in e.g. IRB
If you run a ruby file from bash it works too.
io_test.rb
puts gets
in bash
ruby io_test.rb
Then it will "put" into stdout whatever it "gets" from stdin.
If you want to run code within ST2, check out the SublimeREPL plugin, available through Package Control. While you can use IRB, its main Ruby interface is through pry, which is a lot more powerful. You can use it as a classic REPL (think Clojure or LISP), and you can also transfer your code from one tab into the running REPL in another tab by selection, line range, or block.
Interestingly, your code above works in IRB for me, but not pry for some reason - it's reading my $EDITOR environment variable, which is set to subl -w but failing with Errno::ENOENT: No such file or directory - subl -w. Strange...
At any rate, I highly highly recommend SublimeREPL, as it's a really powerful tool, and is self-contained within ST2, so you don't have to keep flipping back and forth to your terminal, saving and reloading your programs.

Ruby's irb with [what?] is equivalent to the Python Shell with IDLE? (On Windows, if relevant.)

This has been a surprisingly hard question to find an answer to.
(A few questions seem to be asking something at least similar, like:
Ruby console alternative for IRB (Windows)
IDLE like interactive console for Ruby
A recommended Ruby interactive console
But I couldn't get what I need from any of those.)
Also, I'm a bit unsure of the precise terminology I should be using, so I'll try to be really concrete here:
Say you're using IDLE with the Python shell.
You have one of IDLE's text-editor windows open with a script "example.py" in it.
You hit F5 and the Python shell comes up and does exactly what it would do if you had just entered every line in "example.py" into the shell line-by-line.
Functionally, that's exactly what it's doing is automatically entering every line, only without cluttering up the screen by displaying them. (Also it resets the shell to a fresh state every time you do this, but that's not really the important point at the moment; Sometimes it'd be nice to have the option of having it not reset the state of the shell, whatever.)
So the outcome is that now you can play around in the shell, and all the functions and variables etc that were in the script that you just ran are all there.
But with irb...
How do I get the same effect?
For instance, I tried irb example.rb (an equivalent ruby script) in the Windows console, and it just literally enters each line one-by-one into irb, spewing them down the screen, then automatically exits back to the Windows command prompt.
(Although even if that did work the way I wanted (is there some option flaggy argument thingy that would make it do more what I want here?), I'd still have to alt-tab from the text-editor to a console window, and enter the command and file name, which is inferior to just pressing F5, obvs.)
To make really sure I'm being clear in what I mean, here are concrete examples of:
1) a Python script for "example.py"
2) an example of running it in the shell then doing some things in the shell (copy-pasted from the actual shell)
3) an equivalent Ruby script to that Python one
4) an example of running it in the kludgy, slow online-interpreter at repl.it, and doing the exact same things in that irb shell (again, copy-pasted)
1) example.py :
x = "some value you don't want to keep reassigning to this variable"
y = "some other value like that"
def some_function(var):
return "do something complicated with `"+var+"`"
print("example.py just ran")
2) Python shell :
Python 3.2.3 (default, Apr 11 2012, 07:15:24) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>>
example.py just ran
>>> x
"some value you don't want to keep reassigning to this variable"
>>> y
'some other value like that'
>>> print(some_function(x))
do something complicated with `some value you don't want to keep reassigning to this variable`
>>> x = "a frog"
>>> print(some_function(x))
do something complicated with `a frog`
>>> print("gonna run example.py again")
gonna run example.py again
>>> ================================ RESTART ================================
>>>
example.py just ran
>>> print("x is back to: `\""+x+"\"`")
x is back to: `"some value you don't want to keep reassigning to this variable"`
3) example.rb :
x = "some value you don't want to keep reassigning to this variable"
y = "some other value like that"
def some_function var
"do something complicated with `#{var}`"
end
puts "test.rb just ran"
4) online Ruby irb shell thing at repl.it :
Ruby 1.8.7 (2008-05-31 patchlevel 0) [x86-linux]
[GCC 4.2.1 (LLVM, Emscripten 1.5, Emscripted-Ruby)]
test.rb just ran
=> nil
x
=> "some value you don't want to keep reassigning to this variable"
y
=> "some other value like that"
puts some_function x
do something complicated with `some value you don't want to keep reassigning to this variable`
=> nil
x = "a frog"
=> "a frog"
puts some_function x
do something complicated with `a frog`
=> nil
puts "gonna run this script again..."
gonna run this script again...
=> nil
test.rb just ran
=> nil
puts "x is back to: `\"#{x}\"`"
x is back to: `"some value you don't want to keep reassigning to this variable"`
=> nil
The best answer I've found so far seems to be to install pry (enter gem install pry at the command prompt).
Now if you run a script by entering pry scriptname.rb, and it encounters an exception, it will automatically go interactive.
Furthermore, if you add require 'pry' inside the script at the top, then you can put binding.pry in the script at ay point.
Now when you run the script (simply by entering scriptname.rb at the command prompt), it will stop executing and go interactive in pry at that point.
Pressing ^D (ie, ctrl-d) will resume execution.
Getting a script to run in a command prompt window when you press F5 (or whatever) in your editor (eg, Notepad++) is apparently somewhat trickier. Solutions like this have some problems that I haven't figure out how to tweak away yet.
So currently I'm just alt-tabbing to the command prompt window and running the script from there (again, by entering pry scriptname.rb or just scriptname.rb, depending on what exactly what I want and whether I put a binding.pry in the script anywhere. Up-arrow recall, tab completion, blah blah.)
I'm working on figuring it out.
I am not 100% sure if this is what you want, but from my experience, using ruby scriptname.rb will run the code

What's the point of ARGV in Ruby?

What's the point of ARGV in Ruby?
first, second, third = ARGV
puts "The script is called: #{$0}"
puts "Your first variable is: #{first}"
puts "Your second variable is: #{second}"
puts "Your third variable is: #{third}"
What's the point of this when to run the file I need to do:
ruby ex1.rb
and to put in the first, second and third variables I need to type in
ruby ex1.rb blah blah blah
How does this benefit at all the person running the program? They can't do it anyway since I'd assume it be an executable:
user = ARGV.first
prompt = '> '
puts "Hi #{user}, I'm the #{$0} script."
puts "I'd like to ask you a few questions."
puts "Do you like me #{user}?"
print prompt
likes = STDIN.gets.chomp()
puts "Where do you live #{user}?"
print prompt
lives = STDIN.gets.chomp()
puts "What kind of computer do you have?"
print prompt
computer = STDIN.gets.chomp()
puts <<MESSAGE
Alright, so you said #{likes} about liking me.
You live in #{lives}. Not sure where that is.
And you have a #{computer} computer. Nice.
MESSAGE
Can someone please explain this to me?
What's the point of ARGV in Ruby?
ARGV "contains the arguments passed to your script, one per element."
What's the point of this when to run the file you need to do: ruby ex1.rb and to put in the first, second and third variables you need to type in ruby ex1.rb blah blah blah.
That is the exact point, to be able to specify arguments when running the file like:
ruby ex1.rb -a -b 3
How does this benefit at all the person running the program?
Same benefit any other command-line program gets from being able to do so: the user can specify upfront what they want, and it's easier to script than an interactive CLI.
They can't do it anyway since I'd assume it be an executable.
Yes, they can. You just gave an example of exactly how the user would run your program that way. Whether it's executable or not doesn't change anything.
ARGV has a long tradition and comes from the UNIX/POSIX world where most C programs must contain the following:
int main(int argc, char **argv)
{
return(0);
}
There argc represents the number of arguments supplied, and argv is a low-level pointer to the first of potentially a number of string pointers. The name argv has stuck around in various forms.
Command-line arguments are very popular with developers, though they're usually not used quite as you seem to think. Un-named arguments are much harder to deal with. That's why things like optparse exist to help deal with them.
Here's an example from the OptionParser documentation:
require 'optparse'
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: example.rb [options]"
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
options[:verbose] = v
end
end.parse!
p options
p ARGV
This allows you to define much more usable command-line arguments and then use them. For your example, I'd expect it to work like this:
test_script --live "New York" --computer "Lenovo" --like
That makes it quite obvious what the arguments are because they're named.
Consider some Ruby command line utilities like rails, rake,gem, or bundle. While none of these are end-user applications (like web apps or GUI apps), they are still programs written in Ruby that users interact with. All of them take arguments:
$ rails new my_app
$ rake tests
$ gem install rails --no-rdoc --no-ri
$ bundle update
It is possible to use ARGV to implement these kinds of command line programs that accept arguments. While we'll often use the OptionParser standard library or some other tool for this purpose, ARGV is the low level collection those tools are built on top of.
So if you've ever run gem, rails, rake, or bundle, or any command line developer tool that is written in Ruby, you will have benefited from ARGV!
The point of ARGV is that it enables scripts to be able to run without human input, and also allows for the case where the input may vary from one iteration to the next.
For example you may be running three different scripts to get three values. These values could then be passed into this script and ARGV can be used to get the values of these options.
I used to run a script that asked me for an email and password. It was used to log into one of 100's of accounts. Like most Ruby scripts, I'd run it from the command line. This had to semblance to being an "executable", especially not one with an icon that you click.
I'd run the program and it would ask me for email and password then log me in using Watir.
puts "Email of Account"
account_email = gets.chomp
puts "Enter Password"
password = gets.chomp
# code that logs me in
However, I found that taking in those values via ARGV was much faster for my purposes.
account_email, password = ARGV
# code that logs me in
Then I could just type
$ ruby my_script.rb my.email#emailplace.com mypassword
and hit enter. Also I could just press the up arrow in the console to run it again and again or recent versions with different names and passwords to test my script quickly.
Taking it a step further, I made a shell script that could run this scripts, args and all in many combinations
ruby my_script.rb oneofmy#emails.com mypassword
ruby my_script.rb another#emails.com otherpassword
Finally, sometimes I needed to set dozens of settings per each time I ran a script, and then run that script many times. So I could also easily insert a dozens variables into a script from the command line
ruby my_script.rb option1 option2 option3 option4
I'm very new to using ARGV and hope to learn better ways to use it, but this is one feature I found very useful.

Simple Ruby Command Line Question

Um - I feel like an idiot, but....
ruby -e '3+5'
Outputs nothing (Windows 7, Ruby 1.8.7, Cygwin or Git Bash). What am I missing? Extra credit - will this also allow the extra cool bundle (stolen from TextMate) Execute and Update # => markers to work properly?
EDIT
Ok that worked, and I'll accept the answer, but e-texteditor still doesn't work with that really cool bundle. Too bad.
try:
ruby -e 'puts 3+5'
You're missing a call to puts or any other method that produces output. ruby -e doesn't print the return value of the expression - it just executes it. It acts exactly as if you were executing a rb file containing "3+5".

Resources