Is there a way to use a keystroke to invoke the pry ruby gem? - ruby

I was just thinking about how great it would be to be able to run a program and then hit a keystroke to invoke pry and debug. Maybe there is a gem out there that injects binding.pry dynamically during runtime that I don't know about. If there isn't, how would you make a keystroke that inserts binding.pry before the next line of ruby script that is about to execute?

Assuming a POSIX OS, you could try adding a signal handler in your ruby program. The ruby documentation even gives an example of your use case:
.. your process may trap the USR1 signal and use it to toggle debugging (http://www.ruby-doc.org/core-2.1.3/Signal.html)
Signal.trap('USR1') do
binding.pry
end
Then, to send the signal:
kill -s SIGUSR1 [pid]
Edit: A more complete example: application.rb
My naïve suggestion above will fail with a ThreadError: current thread not owner. Here's a better example using a global $debug flag.
#!/usr/bin/env ruby
require 'pry'
$debug = false
Signal.trap('USR1') do
puts 'trapped USR1'
$debug = true
end
class Application
def run
while true
print '.'
sleep 5
binding.pry if $debug
end
end
end
Application.new.run
This seems to work best when application.rb is running in the foreground in one shell, and you send the SIGUSR1 signal from a separate shell.
Tested in Mac OS 10.9.5. YMMV.

Related

Forcing Code in Ruby on Windows when X button is hit

While writing a ruby script on Windows (ruby -v outputs ruby 1.9.3p545) I encountered an interesting and rather specific problem. I was attempting to close an opened file if a user terminates execution. For example,
begin
f = File.open("monkeys.txt", "w+")
#stuff with the file
rescue Exception => e #I know this is a bad idea
puts e.backtrace
ensure
f.close
end
Now, this works if I terminate execution via Ctrl+C while running this in cmd. However, when I hit the "X" on the cmd prompt window, the code in the ensure block doesn't run. I tried something like...
at_exit do
f.close if !f.closed?
end
...but that still doesn't execute the code I want it to when the X button is hit.
So, what do I do in order to force "ensure" code in Ruby if it's closed via that X button?
Well, I don't really program for windows, so I might get lost on the details, but let me try to shed some light with this workaround for Linux:
#ppid = Process.ppid
pid = fork do
loop do
sleep(1)
begin
Process.getsid(#ppid)
rescue Errno::ESRCH
File.new("process_down.txt", "a+")
exit(1)
end
end
end
Process.detach(pid)
puts "Process detached"
What this does is it creates a forked process, detaches it from the main process and keeps listening for when the main process is killed (it'll throw Errno::ESRCH on Process.getsid if the #ppid is no longer there), so it'll create a .txt file and exit. I don't know how to handle forking and pids in windows, but that's just to try and show you some possibilities =]

Killing Threads in Ruby Shoes doesn't seem to work?

I try to make this piece of code works in Ruby Shoes, but I can't succeed to kill the thread named "airodump". Each time I click on the "stop scanning" button, it doesn't do anything :s
Thanks
button "scan networks" do
airodump = Thread.new do
`sudo airodump-ng --write tuto wlan0`
end
Thread.new do
button "Stop scanning" do
Thread.kill(airodump)
end
end
end
Thread killing (in any language) is a pretty limited operation. In your case, the thread is stuck in a blocking call - the call to the subshell - and therefore cannot be killed.
What you would need to do is kill the subprocess first. I don't know how to get the PID out of the backtick operator, so you would need to rather use Process.spawn (on ruby 1.9), gey the PID of the subprocess, and call Process.kill
I think the main problem is that you should use class variables so define
#airodump=Thread.new do
...
end
And than kill it by:
Thread.kill(#airodump)

Kill process and sub-processes in Ruby on Windows

Currently I'm doing this in one command prompt
require 'win32/process'
p = Process.spawn("C:/ruby193/bin/bundle exec rails s")
puts p
Process.waitpid(p)
and then in another
require 'win32/process'
Process.kill(1,<p>)
The problem is that the process I spawn (the Rails server in this case) spawns a chain of sub-processes. The kill command doesn't kill them, it just leaves them orphaned with no parent.
Any ideas how can I kill the whole spawned process and all its children?
I eventually solved this in the following manner
First I installed the sys-proctable gem
gem install 'sys-proctable'
then used the originally posted code to spawn the process, and the following to kill it (error handling omitted for brevity)
require 'win32/process'
require 'sys/proctable'
include Win32
include Sys
to_kill = .. // PID of spawned process
ProcTable.ps do |proc|
to_kill << proc.pid if to_kill.include?(proc.ppid)
end
Process.kill(9, *to_kill)
to_kill.each do |pid|
Process.waitpid(pid) rescue nil
end
You could change the kill 9 to something a little less offensive of course, but this is the gist of the solution.
One-script solution without any gems. Run the script, CTRL-C to stop everything:
processes = []
processes << Process.spawn("<your process>")
loop do
trap("INT") do
processes.each do |p|
Process.kill("KILL", p) rescue nil
Process.wait(p) rescue nil
end
exit 0
end
sleep(1)
end

Troubles with parallel processes in IRB on Mac

I am working with a database via IRB, and I would like to make periodic changes in the database (e.g., every 10 sec) showing the log in STDOUT.
Also, I would like to have manual control being able to change the database and to stop the first process.
So far I came up to the following
def start
stop
#running = Thread.new do
loop do
fork do
puts 'change the database'
end
sleep 10
end
end
nil
end
def stop
#running.kill if #running
end
However, this is not running every 10 sec unless I enter something in the main IRB thread.
How to make it working?
Some versions of readline on OSX are blocking. If one experiences the behavior you described, they can disable readline by putting
IRB.conf[:USE_READLINE] = false
in .irbrc
Works fine for me (tested in irb with ruby 1.9.2-p180 and 1.8.7-p334).

How can I create a daemon with Thor (ruby)?

I would like to use the popular Thor gem to create a daemonized task. My Thor class looks like this:
require 'rubygems'
require 'daemons'
require 'thor'
class CLI < Thor
desc "start", "Startup the App"
method_option :daemonize, :aliases => "-d", :default => false, :type => :boolean, :banner => "Run as daemon"
def start
run_app(options[:daemonize])
end
desc "stop", "Stop the daemon"
def stop
stop_app
end
no_tasks {
def run_app(run_as_daemon)
# Run the application code
Daemons.daemonize if run_as_daemon
# loop until stopped or interrupted
# ...
end
def stop_app
#stop the app
end
}
end
So here I've setup a basic thor class with two tasks, start and stop. I'm also, currently using the Daemons gem, but that isn't required. The part that I'm struggling with is that when this app runs as "run_thor_app.rb start" everything runs just fine. Obviously the stop task isn't needed in this instance. But when I run "run_thor_app.rb start -d" the app runs until Daemons.daemonize runs and then it quits. Checking the running processes shows that nothing is running in the background.
Even if something were running, I wouldn't know how to approach the stop task. For example, how do you detect that the app is running as a daemon and stop it. I've looked at Daemons::Monitor, but the documentation isn't clear on how that works and when I tried it, it didn't work.
It seems to me that this would be a good use case for something that is built into Thor, but searching through the code on github hasn't revealed anything to me. Maybe I just missed it somewhere. In any case, I think it would be good to document a best practice or a pattern for handling daemons with Thor for others to reference.
The way you usually manage daemon processes is by having them write their PID in a file. This makes it possible for another process to discover the daemon's PID, and kill it (or send some other signal).
Your code should work. I tried a bare bones script that used the deamons gem, and it took me a few tries until I found the deamonized process. I figured it would get the same name as the parent process, or something similar, but instead it's name was "self". Remember that the daemonized process will no longer write to STDOUT.
Anyway, try this:
# set up everything
# then daemonize
Daemons.daemonize
# and write a pid file
File.open('/tmp/mydaemon.pid', 'w') { |f| f.puts(Process.pid) }
loop do
# do something
# this loop is important, if the script ends the daemon dies
end
and check the /tmp/mydaemon.pid file for the PID. Then run ps ax | grep x where x is the PID. Run cat /tmp/mydaemon.pid | xargs kill` to kill the daemon.
I think the daemons' gem has some helpers for managing PidFiles, check out PidFile in http://rubydoc.info/gems/daemons/1.1.0/frames

Resources