what is the use of "#!/usr/local/bin/ruby -w" at the start of a ruby program - ruby

what is the use of writing the following command at the start of a ruby program ?
#!/usr/local/bin/ruby -w
Is it OS specific command? Is it valid for ruby on windows ? if not, then what is an equivalent command in windows ?

It is called a Shebang. It tells the program loader what command to use to execute the file. So when you run ./myscript.rb, it actually translates to /usr/local/bin/ruby -w ./myscript.rb.
Windows uses file associations for the same purpose; the shebang line has no effect (edit: see FMc's answer) but causes no harm either.
A portable way (working, say, under Cygwin and RVM) would be:
#!/usr/bin/env ruby
This will use the env command to figure out where the Ruby interpreter is, and run it.
Edit: apparently, precisely Cygwin will misbehave with /usr/bin/env ruby -w and try to look up ruby -w instead of ruby. You might want to put the effect of -w into the script itself.

The Shebang line is optional, and if you run the ruby interpreter and pass the script to it as a command line argument, then the flags you set on the command line are the flags ruby runs with.
A Shebang line is not ruby at all (unless you want to call it a ruby comment). It's really shell scripting. Most linux and unix users are running the BASH shell (stands for Borne Again SHell), but pretty much every OS has a command interpreter that will honor the Shebang.
“#!/usr/local/bin/ruby -w”
The "she" part is the octothorp (#), aka pound sign, number sign, hash mark, and now hash tag (I still call it tic-tac-toe just cuz).
The "bang" part is the exclaimation mark (!), and it's like banging your fist on the table to exclaim the command.
On Windows, the "Shell" is the command prompt, but even without a black DOS window, the command interpreter will run the script based on file associations. It doesn't really matter if the command interpreter or the programming langue is reading the shebang and making sure the flags are honored, the important point is, they are honored.
The "-w" is a flag. Basically it's an instruction for ruby to follow when it runs the script. In this case "-w" turns on warnings, so you'll get extra warnings (script keeps running) or errors (script stops running) during the execution of the script. Warnings and exceptions can be caught and acted upon during the program. These help programmers find problems that lead to unexpected behavior.
I'm a fan of quick and dirty scripts to get a job done, so no -w. I'm also a fan of high quality reusable coding, so definitely use -w. The right tool for the right job. If you're learning, then always use -w. When you know what you're doing, and stop using -w on quick tasks, you'll start to figure out when it would have helped to use -w instead of spending hours trouble shooting. (Hint, when the cause of a problem isn't pretty obvious, just add -w and run it to see what you get).
"-w" requires some extra coding to make it clear to ruby what you mean, so it doesn't immediately solve things, but if you already write code with -w, then you won't have much trouble adding the necessary bits to make a small script run with warnings. In fact, if you're used to using -w, you're probably already writing code that way and -w won't change anything unless you've forgotten something. Ruby requires far less "plumbing code" then most (maybe all) compiled languages like C++, so choosing to not use -w doesn't allow you to save much typing, it just lets you think less before you try running the script (IMHO).
-v is verbose mode, and does NOT change the running of the script (no warnings are raised, no stopping the script in new places). Several sites and discussions call -w verbose mode, but -w is warning mode and it changes the execution of the script.

Although the execution behavior of a shebang line does not translate directly to the Windows world, the flags included on that line (for example the -w in your question) do affect the running Ruby script.
Example 1 on a Windows machine:
#!/usr/local/bin/ruby -w
puts $VERBOSE # true
Example 2 on a Windows machine:
#!/usr/local/bin/ruby
puts $VERBOSE # false

Related

Ruby script equivalent to the bash `set` builtin's `-x` flag?

When a bash script is running, the set -x command can be used to print all commands and output as they're being executed.
I'm writing a Ruby script. Is there a way to also have this print the commands and output as they're being executed?
TL;DR
While interpreted, Ruby parses and runs code very differently from languages like Bash or Tcl, so there's no built-in way to do exactly what you want. You'll have to use a debugger or REPL to get something that approximates what you're trying to do, but it won't really be the same as using flags like -x or -v in Bash. An external or IDE-based debugger will probably come closest, though.
A Couple of Options
There is no built-in way to do this, as Ruby is not really a line-by-line interpreted language in the same way as Bash or Tcl. While Ruby is generally considered an interpreted language, it actually uses a tokenizer and parser to generate code that runs on a virtual machine such as YARV or GraalVM. You do have a couple of options, though:
Use the -d flag or set $DEBUG to a truthy value in your code, and then do some level of introspection based on whether the debug flag is enabled. For example:
# 1 is printed because $DEBUG is truthy
$ ruby -e 'BEGIN { $DEBUG = true }; puts 1 if $DEBUG'
1
# nothing is printed because $DEBUG is falsey
$ ruby -e 'puts 1 if $DEBUG'
Please note that Ruby 3.0.3 and 3.1.0 seem to have an issue with the -d flag, so the first example uses a BEGIN statement to set the value of the flag inside the program.
Use the debug gem (now standard with Ruby 3). You can either step through the code with rdbg and use the list command liberally, or (if you're clever) script a series of list commands on specific lines using the ~/.rdbgrc file.
Use an external debugger, with or without rdbg. Note that the new debugger supports IDE-based debugging (e.g. with RubyMine or VS Code) and remote debugging, but setting up IDE or remote debugging is likely a topic outside the scope of a reasonable SO answer.
Use irb or pry with the debugger of your choice, which usually gives you a number of ways to inspect source code, frames, expressions, variables, and so on, although you need to run from an on-disk file rather than a REPL to access some of the functionality you may be looking for.
For the most part, if you're not using an IDE or a debugger, you will generally need to rely on return values in a REPL or Kernel#pp statements in your code to inspect return values as you go along. However, short of a debugger or REPL that supports listing methods or lines of code on request, you'll either need to use external tools to solve whatever problem you're trying to solve via this approach another way.
Other Options
If you use pry, the pry-rescue gem along with pry-stack_explorer will allow you to automatically trigger a REPL session that allows you to traverse up and down the stack if you hit an exception without requiring you to start your session in the REPL or explicitly call binding.pry. On supported versions of Ruby, this can be very useful, especially since Pry supports a show-source -l command that will do something similar to what you want (at least interactively), although the line numbers may not be what you expect if the code is entered directly in the REPL rather than loaded from a Ruby program on disk.

How does this Ruby command line work? Seemingly running a CMD script with Ruby

I'm examining how ridk enable works in order to figure out how to hook it into Travis CI build logic. (The Ruby installation I'm studying is a RubyInstaller+Devkit installed locally; the commands are run from the "Start Command Prompt with Ruby" prompt.)
I've got stuck at a Ruby command line executed under the hood whose working is a mystery to me:
"C:\Ruby24-x64\bin\ruby" --disable-gems -x 'C:\Ruby24-x64\bin\ridk.cmd' enable
It seems to run a CMD script (?!) with Ruby -- which isn't supposed to be possible. Running it with -rtracer in place of --disable-gems shows that the execution somehow ends up jumping into C:/Ruby24-x64/lib/ruby/site_ruby/2.4.0/ruby_installer/runtime/ridk.rb.
Could someone explain to me how this command line works?
From man ruby:
-x[directory]
Tells Ruby that the script is embedded in a message. Leading garbage will be discarded until the first line that starts with #!
and contains the string, ruby
Any meaningful switches on that line
will be applied. The end of the script must be specified with either
EOF ^D ( control-D ^Z ( control-Z or the reserved word __END__ If the
directory name is specified, Ruby will switch to that directory before
executing script.
Which means the ridk.cmd has embedded ruby code.
The directory is optional, as indicated by both the square brackets around the name and the description. If provided, it should be directly after -x without any space, which effectively allows it to be an optional argument.

Difference in behaviour between Cygwin and Command Prompt when running Ruby scripts

I'm running exercise 14 of Learn Ruby the Hard Way. If I run the script in cmd it works fine, but I've been using Cygwin because it's nicer. When I run it in cygwin using this command:
ruby ex14.rb Devon
I get the following output
test
one
two
Hi Devon, I'm the ex14.rb script.
I'd like to ask you a few questions.
Do you like me Devon?
> Where do you live Devon?
> What kind of computer do you have?
> Alright, so you said test about liking me.
You live in one. Not sure where that is.
And you have a two computer. Nice.
That is to say, the program starts and immediately runs the three STDIN.gets.chomp() commands, and once it gets through those it puts and prints everything at once.
Is there a way to fix this behaviour? I would obviously want to have the lines run in the order they are written. I was unsure what to google for this type of error - combinations of "cygwin", "ruby", "puts output delayed" and "gets out of order" returned nothing relevant. Those search terms seem to vague anyway.
What exactly is going on, and is there a solution?
I think it is all to do with the CR LF differences between dos and unix.
try this...
set -o igncr
before running your script.

Interpretation of additional arguments to Ruby's Kernel::system method

Why does the first excerpt succeed and the second fail?
system 'emacs', '--batch', '--quick', '--eval="(require \'package)"'
system 'emacs --batch --quick --eval="(require \'package)"'
(If it matters, I'm executing the code on Mac OS X Mountain Lion with Ruby version 1.8.7 and Emacs version 22.1.1.)
First of all, those two system calls are different in ways that you may not expect. A quick example will probably explain the difference better than a bunch of words and hand waving. Start with a simple shell script:
#!/bin/sh
echo $1
I'll call that pancakes.sh because I like pancakes more than foo. Then we can step into irb and see what's going on:
>> system('./pancakes.sh --where-is="house?"')
--where-is=house?
>> system('./pancakes.sh', '--where-is="house?"')
--where-is="house?"
Do you see the significant difference? The single argument form of system hands the whole string to /bin/sh for processing and /bin/sh will deal with the double quotes in its own way so the program being called will never see them. The multi-argument form of system doesn't invoke /bin/sh to process the command line so the arguments are passed as-is with double quotes intact.
Back to your system calls. The first one will send this exact argument to emacs (note that Ruby will take care of converting \' to just '):
--eval="(require 'package)"
and emacs will try to evaluate "(require 'package)"; that looks more like a string than an elisp snippet to me and evaluating a string literal doesn't do much of anything. Your second will send this to emacs:
--eval=(require 'package)
and emacs will complain that it
Cannot open load file: package
Note that my elisp knowledge is buried under about 20 years of rust and forgetfulness so some of the emacs details may be a bit off.

Are shell scripts read in their entirety when invoked?

I ask because I recently made a change to a KornShell (ksh) script that was executing. A short while after I saved my changes, the executing process failed. Judging from the error message, it looked as though the running process had seen some -- but not all -- of my changes. This strongly suggests that when a shell script is invoked, the entire script is not read into memory.
If this conclusion is correct, it suggests that one should avoid making changes to scripts that are running.
$ uname -a
SunOS blahblah 5.9 Generic_122300-61 sun4u sparc SUNW,Sun-Fire-15000
No. Shell scripts are read either line-by-line, or command-by-command followed by ;s, with the exception of blocks such as if ... fi blocks which are interpreted as a chunk:
A shell script is a text file containing shell commands. When such a
file is used as the first non-option argument when invoking Bash, and
neither the -c nor -s option is supplied (see Invoking Bash), Bash
reads and executes commands from the file, then exits. This mode of
operation creates a non-interactive shell.
You can demonstrate that the shell waits for the fi of an if block to execute commands by typing them manually on the command line.
http://www.gnu.org/software/bash/manual/bashref.html#Executing-Commands
http://www.gnu.org/software/bash/manual/bashref.html#Shell-Scripts
It's funny that most OS'es I know, do NOT read the entire content of any script in memory, and run it from disk. Doing otherwise would allow making changes to the script, while running. I don't understand why that is done, given the fact :
scripts are usually very small (and don't take many memory anyway)
at some point, and shown in this thread, people would start making changes to a script that is already running anyway
But, acknowledging this, here's something to think about: If you decided that a script is not running OK (because you are writing/changing/debugging), do you care on the rest of the running of that script ? you can go ahead making the changes, save them, and ignore all output and actions, done by the current run.
But .. Sometimes, and that depends on the script in question, a subsequent run of the same script (modified or not), can become a problem since the current/previous run is doing an abnormal run. It would typically skip some stuff, or sudenly jump to parts in the script, it shouldn't. And THAT may be a problem. It may leave "things" in a bad state; particularly if file manipulation/creation is involved.
So, as a general rule : even if the OS supports the feature or not, it's best to let the current run finish, and THEN save the updated script. You can change it already, but don't save it.
It's not like in the old days of DOS, where you actually have only one screen in front of you (one DOS screen), so you can't say you need to wait on run completion, before you can open a file again.
No they are not and there are many good reasons for that.
One of the things you should keep in mind is that a shell is not an interpreter even if there are some similarities. Shells are designed to work with a stream of commands. Either from the TTY ,a PIPE, FIFO or even a socket.
The shell reads from its resource line by line until a EOF is returned by the kernel.
The most shells have no extra support for interpreting files. they work with a file as they would work with a terminal.
In fact this is considered to be a nice feature because you can do interesting stuff like this How do Linux binary installers (.bin, .sh) work?
You can use a binary file and prepend shell scripts. You can't do this with an interpreter. because it parses the whole file or at least it would try it and fail. A shell would just interpret it line by line and doesnt care about the garbage at the end of the file. You just have to make sure the execution of the script gets terminated before it reaches the binary part.

Resources