For ruby/webrick, I need windows to recognize shebang (#!) notation - windows

(Bear with me, I promise this gets to shebang and windows.)
I have about the simplest of WEBRick servers put together:
require 'webrick'
include WEBrick
s = HTTPServer.new(:Port=>2000, :DocumentRoot=>Dir::pwd)
s.start
Couldn't be simpler. This basic server does accept http connections (firefox, internet exploder, wget, TELENT) and deals with them appropriately, as long as I'm just fetching static documents. If, however, I set one of the files in the directory to have a .cgi extension, I get a 500 back and the following on the server's terminal:
ERROR CGIHandler: c:/rubyCGI/test.cgi:
C:/...[snip]...webrick/httpservlet/cgi_runner.rb:45: in 'exec': Exec format error - ...[snip]...
I've done a few things on the command line to mimic what is going on in line 45 of cgi_runner.rb
c:\>ruby
exec "c:/rubyCGI/test.cgi"
^Z
(same error erupts)
c:\>ruby
exec "ruby c:/rubyCGI/test.cgi"
^Z
Content-type: text/html
Mares eat oats and does eat oats and I'll be home for Christmas.
Clearly, WEBrick hasn't been cleared for landing on windows. Your usual headaches of corporate paranoia prevent me from modifying webrick, so can I get the shebang notation in c:/rubyCGI/test.cgi recognized by the OS (windows) so I don't have to explicitly tell it each time which interpreter to use? I could assign all .cgi files to be associated with ruby, but that would be limiting in the long run.
UPDATE:
Since posting this, it has occurred to me that it may not be possible at all to run a cgi web server from ruby; ruby has no forking support. With no ability to fork a process, a cgi server would have to execute each cgi script one-at-a-time, neglecting all concurrent requests while the first one completed. While this may be acceptable for some, it would not work for my application. Nevertheless, I would still be very interested in an answer to my original question—that of getting shebang working under windows.

I think what you want is to associate the file extension with Ruby. I don't think it's possible to get the !# notation to work on Windows but it is possible to get Windows to automatically launch a script with a particular interpreter (as in your second example). A good step by step discussion of what you'd want to do is here. You specifically want the section headed: "To create file associations for unassociated file types". I think that will accomplish what you're trying to do.

A generic solution that works for both Ruby 1.8.6.pxxx and 1.9.1.p0 on
Windows is the following:
Edit the file: c:\ruby\lib\ruby\1.9.1\webrick\httpservlet\cgi_runner.rb
Add the following lines at the top of the file:
if "1.9.1" == RUBY_VERSION
require 'rbconfig' #constants telling where Ruby runs from
end
Now, locate the last line where is says: exec ENV["SCRIPT_FILENAME"]
Comment that line out and add the following code:
# --- from here ---
if "1.9.1" == RUBY_VERSION #use RbConfig
Ruby = File::join(RbConfig::CONFIG['bindir'],
RbConfig::CONFIG['ruby_install_name'])
Ruby << RbConfig::CONFIG['EXEEXT']
else # use ::Config
Ruby = File::join(::Config::CONFIG['bindir'],
::Config::CONFIG['ruby_install_name'])
Ruby << ::Config::CONFIG['EXEEXT']
end
if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
exec "#{Ruby}", ENV["SCRIPT_FILENAME"]
else
exec ENV["SCRIPT_FILENAME"]
end
# --- to here ---
Save the file and restart the webrick server.
Explanation:
This code just builds a variable 'Ruby' with the full path to
"ruby.exe", and
(if you're running on Windows) it passes the additional parameter
"c:\ruby\bin\ruby.exe" , to the Kernel.exec() method, so that your
script can be executed.

Not really to argue... but why bother webrick when mongrel is much faster and with native compiled with windows? And of coz, that means no shebang is needed.

Actually, it is possible to get Windows to recognize shebang notation in script files. It can be done in a relatively short script in say, Ruby or AutoIt. Only a rather simple parser for the first line of a script file is required, along with some file manipulation. I have done this a couple times when either cross-compatibilty of script files was required or when Windows file extensions did not suffice.

Related

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.

Ruby on Windows: Require is not recognized as an internal or external command

I'm trying to use Guard to monitor changes in AsciiDoctor file. Here is Guardfile from official docs:
require 'asciidoctor'
guard 'shell' do
watch(/^mydoc\.adoc$/) {|m|
Asciidoctor.convert_file m[0]
}
end
It works for me. But now, I'm trying to launch the same things without creating Guardfile - i.e. I want simply write these commands in Windows cmd.exe.
But when I write require 'asciidoctor' command prompt gives me an error:
'require' is not recognized as an internal or external command, operable program or batch file.
Well, I know that such error messages are often have something with Windows %Path% environment variable. But I don't understand how to fix it in this particular case.
Ruby and DOS Batch are two completely different programming languages that have absolutely nothing to do with each other. You simply cannot expect an interpreter for DOS Batch to be able to run Ruby code and vice versa. (Especially considering that Ruby didn't even exist when CMD.EXE was written, so how could CMD.EXE possibly know how to interpret Ruby code?)
You need to run Ruby code in a Ruby interpreter (or use a Ruby compiler to compile it to something that you have an interpreter for).

How to find files in ruby which were edited in some time interval?

How to find files in a directory which were edited in last n minutes?
In unix which is -mmin -60.
In host
ruby /home/ava/test works fine!
Net::SSH.start('host', 'ava') do |ssh|
`ruby /home/ava/test`
end
gives ruby: No such file or directory -- /home/ava/test (LoadError)
You could get a list of files using Dir.[], and use File.mtime on each one to filter them:
Dir["*"].select { |fname| File.mtime(fname) > (Time.now - 60) }
The problem with your code is that Ruby isn't control on the remote system you connect to, instead, the shell on that system is, and you're merely able to issue commands, as if you'd ssh'd into your own local system. Ruby's built-in commands, like Dir.chdir only apply locally, not to the remote session.
Your best bet is to write a script you execute that resides on that system, otherwise the task of executing commands becomes more difficult and you'll need to anticipate prompts and possibly various responses from commands on that system as your code executes things.
The Net::SSH gem includes examples showing how to issue remote commands; You need to remember that once you've connected you're issuing commands to the shell, not to Ruby.
Net::SSH.start('host', 'ava') do |ssh|
`ruby /home/ava/test`
end
gives ruby: No such file or directory -- /home/ava/test (LoadError)
The best way to diagnose this is to start by SSHing to your own local box and executing the code locally, or using surrogate code that only echoes the commands you'd be using in real life on the other machine. Then you can test to see if the actions would be called.
Instead of:
ruby /home/ava/test
issue a command like:
ls -al /home/ava
first, to see what files are visible.
Follow that with something like:
ruby -pe '%x(ls /home/ava)'
to see if Ruby is found and it can execute that command in the path.
Dealing with remote systems isn't the same as running scripts locally. Your environment can be different, meaning your PATH or variables you expect might not be the same.

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

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

Piping stdin to ruby script via `myapp | myscript.rb`

I have an app that runs continuously, dumping output from a server and sending strings to stdout. I want to process this output with a Ruby script. The strings are \n-terminated.
For example, I'm trying to run this on the command line:
myapp.exe | my_script.rb
...with my_script.rb defined as:
while $stdin.gets
puts $_
end
I ultimately am going to process the strings using regexes and display some summary data, but for now I'm just trying to get the basic functionality hooked up. When I run the above, I get the following error:
my_script.rb:1:in `gets': Bad file descriptor (Errno::EBADF)
from my_script.rb:1
I am running this on Windows Server 2003 R2 SP2 and Ruby 1.8.6.
How do I continuously process stdin in a Ruby script? (Continuously as in not processing a file, but running until I kill it.)
EDIT:
I was able to make this work, sort of. There were several problems standing in my way. For one thing, it may be that using Ruby to process the piped-in stdin from another process doesn't work on Windows 2003R2. Another direction, suggested by Adrian below, was to run my script as the parent process and use popen to connect to myapp.exe as a forked child process. Unfortunately, fork isn't implemented in Windows, so this didn't work either.
Finally I was able to download POpen4, a RubyGem that does implement popen on Windows. Using this in combination with Adrian's suggestion, I was able to write this script which does what I really want -- processes the output from myapp.exe:
file: my_script.rb
require 'rubygems'
require 'popen4'
status =
POpen4::popen4("myapp.exe") do |stdout, stderr, stdin, pid|
puts pid
while s = stdout.gets
puts s
end
end
This script echoes the output from myapp.exe, which is exactly what I want.
Try just plain gets, without the $stdin. If that doesn't work, you might have to examine the output of myapp.exe for non-printable characters with another ruby script, using IO.popen.
gets doesn't always use stdin but instead tries to open a file.
See SO.
Try executing your Ruby script by explicitly calling ruby:
myapp.exe | ruby my_script.rb
I've experienced some odd behavior using stdin in Ruby when relying on Windows to invoke the correct program based on the file associations.

Resources