How do I make a Ruby script run once a second?
There are a few ways to do this.
The quick-and-dirty versions:
shell (kornish):
while :; do
my_ruby_script.rb
sleep 1
donewatch(1):
shell$ watch -n 1 my_ruby_script.rb
This will run your script every second and keep the output of the most recent run displayed in your terminal.
in ruby:
while true
do_my_stuff
sleep 1
end
These all suffer from the same issue: if the actual script/function takes time to run, it makes the loop run less than every second.
Here is a ruby function that will make sure the function is called (almost) exactly every second, as long as the function doesn't take longer than a second:
def secondly_loop
last = Time.now
while true
yield
now = Time.now
_next = [last + 1,now].max
sleep (_next-now)
last = _next
end
end
Use it like this:
secondly_loop { my_function }
Running another ruby script from a ruby script
Avdi Grimm wrote a series of articles on the Devver blog about different ways to start Ruby subprocesses last summer:
- A Dozen (or so) Ways to Start Subprocesses in Ruby: Part 1
- A Dozen (or so) Ways to Start Subprocesses in Ruby: Part 2
- A Dozen (or so) Ways to Start Subprocesses in Ruby: Part 3
- Beware of pipe duplication in subprocesses
[Note: it appears that part 4 hasn't been published yet.]
A ruby script to run other ruby scripts
You can use load
to run the script you need (the difference between load
and require
is that require
will not run the script again if it has already been loaded).
To make each run have different arguments (given that they are read from the ARGV variable), you need to override the ARGV variable:
(1..6).each do |i|
ARGV = ["cmd_line_arg_#{i}","cmd_line_arg2"]
load 'program1.rb'
end
Ruby running two scripts with mulithreading
So one possible solution I've found is
system("ruby app.rb & ruby app2.rb")
This only works however if running from linux I think however so I would still appreciate any further solutions.
Run two ruby scripts from rake task
It might be easier to require the ruby class directly into your rake task, but if you want to run a script from a rake task you can run any shell code in Ruby using backticks, like this:
`ruby first_script.rb param1 param2 | ruby second_script.rb`
ruby script - redirect output from one script to another script
Instead of reading just one line (msg = gets.chomp
) you need to iterate through the lines of stdin
$stdin.each_line do |msg|
# ...
end
This does not wait for the entire output to be generated, it will process the stream as lines are printed by the first process (ignoring buffering).
For example, with these two scripts
# one.rb
i = 0
loop { puts i += 1 }
# two.rb
$stdin.each_line { |msg| puts "#{msg.chomp}!" }
The first has infinite output, but you will still see output when you run
ruby one.rb | ruby two.rb
ping function every x amount seconds
If you simply sleep
for a constant amount of time as suggested in other answers, the error will contaminate as it keeps running, and will not be accurate. In fact, each iteration would take longer than the given interval.
The answer shown below adjusts the lag each time per iteration.
module Kernel
def tick_every sec, &pr
Thread.new do loop do
pr.call
t = Time.now.to_f
frac = t.modulo(sec.to_f)
sleep(sec - frac)
end end
end
end
thread = tick_every(2) do
puts "foo"
end
...
some_other_tasks
...
thread.kill
How to execute Ruby files from another Ruby file
In general your code isn't written in the Ruby way. This is untested but it looks about right:
class Launch
FILES = ['sum_of_digits', 'compressed_sequence', 'shortest_repetition']
def get_program
FILES.each_with_index do |fname, i|
puts "#{i} . #{fname}"
end
loop do
puts "Enter program number to execute: "
program_number = gets.to_i
file_to_load = FILES[program_number]
puts "loading program #{file_to_load}"
begin
system("ruby #{file_to_load}.rb #{file_to_load}.txt")
rescue => e
puts "loading error: #{e}"
puts "'#{file_to_load}' cannot be loaded, it may have been moved or not exist."
end
puts 'Do you want to continue Y/N'
break if gets.chomp.strip.upcase == 'N'
end
end
end
launch = Launch.new
launch.get_program
Some things to study:
block
andend
are used to start exception handling, not to define control loops. Well, they can, but there are better, more idiomatic, ways.loop
is recommended by Matz.- You used
load
but I don't think that's really what you'd want to do. Instead, you should tell the OS to load and run the code in a sub-shell usingsystem
, not in the context of your currently running code. - Instead of using a bare
rescue
, your code should at least capture the exception usingrescue => e
so you can output what occurred. In "real life", AKA, production, you should be even more discerning and capture only the exceptions you expect, but that's a different discussion. - When using a
begin
/rescue
/end
, try to keep them as small as possible, at least until you're more familiar with how they work.rescue
is a great way to shoot yourself in the foot, and debugging raised exceptions that could be generated by many lines of code can be a pain.
In general, when you have a list of things that's likely to change, or any variable that's more likely to change than the rest of the code, put that definition at the top of the script, or the top of the class or module definition, then reference it as a constant. That helps avoid magical dust being sprinkled through the code that has to be searched for if you want to add or delete things. Like files. Or magical dust.
Issue One command and Run Multiple Ruby Files
I would do it ruby-style and use rake
gem.
I would create file named "rakefile.rb" and this would be its content:
task :default do
FileList['file*.rb'].each { |file| ruby file }
end
Then I would call rake
in my favourite shell and I would enjoy it.
Bonus: It's multiplatform.
Related Topics
Making a Soap Request by Using Xml in Rails
Ruby - Difference Between :Variable and @Variable
C1 or C2 Coverage Tool for Ruby
Env: Ruby\R: No Such File or Directory
No Source for Ruby-2.0.0-P451 Provided with Debugger-Ruby_Core_Source Gem
How to See the Ruby Code in a Proc
Installing Native Ruby Extensions on Windows for Jekyll
Dynamic CSS in Rails Asset Pipeline, Compile on Fly
Testing Hash Contents Using Rspec
How to Integrate Rubocop with Rake
Rails First_Or_Create Activerecord Method
Ruby, Run Linux Commands One by One, by Ssh and Log Everything
Carrierwave File Upload with Different File Types
Ruby Net::Smtp - Send Email with Bcc: Recipients
Stream and Unzip Large CSV File with Ruby
How to Set the Rails Environment for My Somewhat Stand Alone Ruby Script