Run ruby script on page refresh - ruby

I've got a ruby script run-this.rb that outputs live calculations to a text file when I run
ruby run-this.rb > output.txt
However, I need to load this same procedure onto a web server where the Ruby script will run on page load and the web page will read the result from the txt file.
My question is two part,
1) How do you tell the web page to run this script on load?
and
2) How do I output the results of run-this.rb to output.txt on page refresh?
Thanks!

You can build a simple web application with the Sinatra framework that will
Run your script
Save the output in a variable
Write the variable contents to a file
Then also write the variable contents to a HTTP response
I would however advise you to encapsulate your script in a Ruby class, which makes it easier to run from another file. For example, in run-this.rb:
class FooRunner
def self.run!
# write to string instead of printing with puts
result = ''
# do your computations and append to result
result << 'hello, world!'
# return string
result
end
end
# maintain old functionality: when running the script
# directly with `ruby run-this.rb`, simply run the code
# above and print the result to stdout
if __FILE__ == $0
puts FooRunner.run!
end
In the same directory, you can now have a second file server.rb, which will perform the steps outlined in the list above:
require 'sinatra'
require './run-this'
get '/' do
# run script and save result to variable
result = FooRunner.run!
# write result to output.txt
File.open('output.txt','w') do |f|
f.write result
end
# return result to be written to HTTP response
content_type :text
result
end
After installing Sinatra with gem install sinatra, you can start the server with ruby server.rb. The output will tell you where to point your browser:
[2014-01-08 07:06:58] INFO WEBrick 1.3.1
[2014-01-08 07:06:58] INFO ruby 2.0.0 (2013-06-27) [x86_64-darwin12.3.0]
== Sinatra/1.4.4 has taken the stage on 4567 for development with backup from WEBrick
[2014-01-08 07:06:58] INFO WEBrick::HTTPServer#start: pid=92108 port=4567
This means your page is now available at http://127.0.0.1:4567, so go ahead and type this in your browser. Et voilá!
After you have displayed the page, the directory will also contain output.txt with the same contents.

Related

How do some files not execute when required in irb?

If I have file.rb:
puts "Hello, World"
then in irb type:
require "./file.rb"
the output will be Hello, World.
Why then, if I have a sinatra file, e.g.
require "sinatra"
get "/" do
return "Hi"
end
and require that, there is no output?
Clarification
What executing the sinatra file via ruby sinatra_app.rb it will start a rack server, and not stop until CTRL+C is pressed. Why does it not do that when required in irb, but it does do that when it is explicitly run with ruby sinatra_app.rb?
Because the script doesn't output anything. There is nothing in the script you showed that would generate any sort of output, there are no calls to print, puts, or p, no writes to any file, nothing.
The first script prints something when required, because it prints something, the second prints nothing when required because, well, it prints nothing. Remove the call to puts from the first script and it won't print anything either. Add a call to puts to the second script and it will print something.
Workaround is require sinatra before requiring file.
Root file:
require "sinatra"
require "/tmp/ddd.rb"
Required file:
get "/" do
return "Hi"
end
I guess it's somehow related to Sinatra startup process. They put get method in default namespace, without namespacing it to separate module.

How can I execute Ruby code with WEBrick instead of dumping the code to my browser?

I'm facing a problem when I run my program in a browser with the WEBrick server. It shows me my code as written in the 2loop.rb file.
When I run ruby -run -e -httpd. -p 5000 at the command prompt, and load http://localhost:5000/2loop.rb in the browser, it shows the code from 2loop.rb instead of running it.
How can I execute the 2loop.rb program instead?
TL;DR
You're doing this to yourself by serving your current working directory as the root of your web server. You aren't actually running the code in your file; you're just telling WEBrick to serve any file you name in the URI. http://localhost:5000/2loop.rb will serve "2loop.rb" as text/html in your posted example.
Using un.rb
The flag you're using isn't actually "run." Instead, the -r flag actually loads a module, which in this case is the un.rb module. Using un.rb to start WEBrick is done like this:
$ ruby -run -e httpd . -p 5000
and starts a web server in the document root. In this case, the dot means to use the current working directory as the root. This is not really what you want to start code you've placed inside a Ruby file.
Running WEBrick Programmatically
Using some snippets from the WEBrick documentation, you will see that you can create a file named "2loop.rb" containing the following:
#!/usr/bin/env ruby
require 'webrick'
root = File.path '/tmp/public_html'
server = WEBrick::HTTPServer.new :Port => 5000, :DocumentRoot => root
trap 'INT' do server.shutdown end
server.start
This will serve files out of the /tmp/public_html directory on port 5000, which you can reach at http://localhost:5000. You can then make the file executable and start the server with ./2loop.rb, or just run ruby 2loop.rb if you don't want to make your file executable for some reason.
If you don't want WEBrick just to serve files, you will have to add custom behavior to your web server inside the 2loop.rb script. This is a fairly low-level thing to do, but may suit your needs.
Sensible Alternatives
You should probably use a web framework like Ruby on Rails or Sinatra if you don't want to have write all the low-level behaviors yourself. Sinatra in particular is a very lightweight alternative. This example:
#!/usr/bin/env ruby
require 'sinatra'
set :port, 5000
get '/hello' do
"Hello, World!"
end
will create a URL at http://localhost:5000/hello with a custom action that returns "Hello, World!" as an in-browser response.
Well, I'd suggest you to use Common Gateway Interface (CGI). Let me provide you an example.
Firstly, create a file named server.rb:
require 'webrick'
server = WEBrick::HTTPServer.new(
:Port => 6789, # a server's port
:DocumentRoot => File.join(Dir.pwd, "/scripts") # a folder with scripts
)
server.start
Secondly, create a folder scripts and put the following file (the_best_program.cgi) into it. Note the .cgi extension. It matters. Look here for details on the first line of the script (shebang) if you are working under Windows.
#!/usr/bin/env ruby
require 'cgi'
print "Content-type: text/plain\n\n"
5.times { |i| puts "Hello world #{i}!"}
puts 'So many worlds there. :('
Finally,
Launch your server from command-line (ruby server.rb).
Start browser and go to localhost:6789/the_best_program.cgi (or 0.0.0.0:6789/the_best_program.cgi)
Enjoy!
Notes
You might need to change permissions to your scripts folder / script. On unix-like system do: chmod 755 scripts scripts/the_best_program.cgi.
You can launch not only ruby scripts this way.

how to write selenium ruby webdriver test results from Ruby terminal to output files

Currently, I'm running all selenium scripts in my test suite (written by Selenium Ruby Webdriver) at one time by using rake gem in "Start Command Prompt with Ruby" terminal.
To do this I have to create a file with name "rakefile.rb" with below content and just call "rake" in my terminal: (I have known this knowledge based on the guide of a person in my previous post how to export results when running selenium ruby webdriver scripts to output files from command prompt ruby window).
task :default do
$stdout = File.new('console.out', 'w')
$stdout.sync = true
FileList['test*.rb'].each { |file|
begin
ruby file
rescue
puts "The following tests reported unexpected behavior:"
puts "#{file} \n"
end
}
end
However, I do not know how to modify "rakefile.rb" to be able to export the content of executing each failed tests (that being displayed on my Terminal) to each output file ? It means that I expect the content of executing each my script will be written to output files instead of displaying on my Ruby terminal (ex: when I'm running the test script "test_GI-1.rb", then the content of executing this script will be written to an output file "test_GI-1.rb.out" instead of showing in my Terminal.
I modified my "rakefile.rb" to something like ruby file >> test.rb.out, but it does not work at all (this thing only works when I type directly the thing like ruby test.rb >> output.out on my Ruby Terminal). Anybody please guide me a way. Thanks so much.
I have not tried this out, but I guess this should work
task :default do
FileList['test*.rb'].each { |file|
begin
system("ruby #{file} > #{file}.log")
rescue
puts "The following tests reported unexpected behavior:"
puts "#{file} \n"
end
}
end
Based on new requirements -
UPDATE
task :default do
logfile.new("console.out", "w")
FileList['test*.rb'].each { |file|
begin
system("ruby #{file} > #{file}.log")
rescue
logfile.puts("The following tests reported unexpected behavior:")
logfile.puts("#{file} \n")
end
}
end

passing arguaments to a system call in Rails, but not plain ruby program

Ubuntu 12.04
Sinatra 1.3.3
Why does passing an argument to a ruby system call (%x[] or ``) give me a 'not found' error in my sinatra app? The same code works fine in a normal ruby script running from the same directory.
I have a file test.rb like this
output = %x["ls"]
p output
When I run it with "ruby test.rb" I get the contents of the current directory in the console, as expected.
If I modify the program to give an argument to the system call like so:
output = %x["ls sub_dir/"]
p output
I get the contents of sub_dir, which sits in the current directory, as expected.
So far so good.
Now if I make a Sintra app with a post method:
require 'rubygems'
require 'bundler/setup'
require 'sinatra'
post "/" do
output = x["ls"]
return output
end
The response to a Post call to "/" returns the contents of the current directory, which includes 'sub_dir', as expected.
If I try to add the argument to the system call to the sinatra app like so:
require 'rubygems'
require 'bundler/setup'
require 'sinatra'
post "/" do
output = x["ls sub_dir/"]
return output
end
the response is nil and there is an error in the console:
sh: 1: ls sub_dir/: not found
Why does adding a parameter to a system call in my sinatra app cause it to crash, when the same code called from a plain ruby script, run from the same location works perfectly.
By the way, the 'ls' example shown here is not the command I really need to run, so please don't explain a different way to get this information. I have an executable file that takes a file name as a parameter that I need to run, which behaves exactly the same way.
Thanks in advance!
If you want to specify a path in relation to the application, you could use something like this:
post "/" do
path = File.join(File.dirname(__FILE__), "sub_dir")
%x[ls #{path}]
end
However, if you want to list the contents of a directory, why not do it in Ruby?
I rewrote the sinatra app in another file in the same directory.
Everything works as expected.
I did not find the reason and I deleted the original file so that I won't lose anymore time trying to figure it out.

How to read an open file in Ruby

I want to be able to read a currently open file. The test.rb is sending its output to test.log which I want to be able to read and ultimately send via email.
I am running this using cron:
*/5 * * * /tmp/test.rb > /tmp/log/test.log 2>&1
I have something like this in test.rb:
#!/usr/bin/ruby
def read_file(file_name)
file = File.open(file_name, "r")
data = file.read
file.close
return data
end
puts "Start"
puts read_file("/tmp/log/test.log")
puts "End"
When I run this code, it only gives me this output:
Start
End
I would expect the output to be something like this:
Start
Start (from the reading of the test.log since it should have the word start already)
End
Ok, you're trying to do several things at once, and I suspect you didn't systematically test before moving from one step to the next.
First we're going to clean up your code:
def read_file(file_name)
file = File.open(file_name, "r")
data = file.read
file.close
return data
end
puts "Start"
puts read_file("/tmp/log/test.log")
puts "End"
can be replaced with:
puts "Start"
puts File.read("./test.log")
puts "End"
It's plain and simple; There's no need for a method or anything complicated... yet.
Note that for ease of testing I'm working with a file in the current directory. To put some content in it I'll simply do:
echo "foo" > ./test.log
Running the test code gives me...
Greg:Desktop greg$ ruby test.rb
Start
foo
End
so I know the code is reading and printing correctly.
Now we can test what would go into the crontab, before we deal with its madness:
Greg:Desktop greg$ ruby test.rb > ./test.log
Greg:Desktop greg$
Hmm. No output. Something is broken with that. We knew there was content in the file previously, so what happened?
Greg:Desktop greg$ cat ./test.log
Start
End
Cat'ing the file shows it has the "Start" and "End" output of the code, but the part that should have been read and output is now missing.
What happening is that the shell truncated "test.log" just before it passed control to Ruby, which then opened and executed the code, which opened the now empty file to print it. In other words, you're asking the shell to truncate (empty) it just before you read it.
The fix is to read from a different file than you're going to write to, if you're trying to do something with the contents of it. If you're not trying to do something with its contents then there's no point in reading it with Ruby just to write it to a different file: We have cp and/or mv to do those things for us witout Ruby being involved. So, this makes more sense if we're going to do something with the contents:
ruby test.rb > ./test.log.out
I'll reset the file contents using echo "foo" > ./test.log, and cat'ing it showed 'foo', so I'm ready to try the redirection test again:
Greg:Desktop greg$ ruby test.rb > ./test.log.out
Greg:Desktop greg$ cat test.log.out
Start
foo
End
That time it worked. Trying it again has the same result, so I won't show the results here.
If you're going to email the file you could add that code at this point. Replacing the puts in the puts File.read('./test.log') line with an assignment to a variable will store the file's content:
contents = File.read('./test.log')
Then you can use contents as the body of a email. (And, rather than use Ruby for all of this I'd probably do it using mail or mailx or pipe it directly to sendmail, using the command-line and shell, but that's your call.)
At this point things are in a good position to add the command to crontab, using the same command as used on the command-line. Because it's running in cron, and errors can happen that we'd want to know about, we'd add the 2>&1 redirect to capture STDERR also, just as you did before. Just remember that you can NOT write to the same file you're going to read from or you'll have an empty file to read.
That's enough to get your app working.
class FileLineRead
File.open("file_line_read.txt") do |file|
file.each do |line|
phone_number = line.gsub(/\n/,'')
user = User.find_by_phone_number(line)
user.destroy unless user.nil?
end
end
end
open file
read line
DB Select
DB Update
In the cron job you have already opened and cleared test.log (via redirection) before you have read it in the Ruby script.
Why not do both the read and write in Ruby?
It may be a permissions issue or the file may not exist.
f = File.open("test","r")
puts f.read()
f.close()
The above will read the file test. If the file exists in the current directory
The problem is, as I can see, already solved by Slomojo. I'll only add:
to read and print a text file in Ruby, just:
puts File.read("/tmp/log/test.log")

Resources