What is the best way to inspect a running Ruby process - ruby

I was having problems with a Ruby process that was running wild.
What are the best ways to inspect such a process for debugging purposes?
I found a nice article about using GDB to inspect it.
What are you using for this purpose, do you have any good resources to read?

Perhaps a good way is beginning by the Tracer lib
use it with
ruby -rtracer
or
strace
on Linux with -f flag, to following forks
truss
on BSD with the same flag

Haven't tried this, but saw this new library yesterday get_process_mem.

If you are interested in current_process_memory_size you can implement method #memstats (thanks to Avdi Grimm and his rubytapas lessons).
require 'csv'
def memstats
size = `ps -o size= #{$$}`.strip.to_i
p "Size: #{size}"
end
memstats # => "Size: 5168"
CSV.open('simple.csv', headers: true) do |csv|
visitors = csv.each
memstats # => "Size: 5170"
p visitors.count{|v| v} # => 168
end
memstats # => "Size: 5168"
$$ is a special variable in ruby, which allows you to get a numeric process ID of the current process

Related

How to require one of two possible options in a Ruby script?

I'm trying to configure a couple options in a Ruby script using OptionParser. I'd like them both to be optional but require that at least one is used. One option would allow for a single value to be passed from the command line. The other option will tell the script to use a file containing multiple values to be iterated over.
This is all I've been able to come up with:
options = {}
parser = OptionParser.new do |opts|
opts.banner = "Usage: sat_server_delete.rb [options]"
opts.on('-f', '--file file', 'File') do |file|
options[:file] = file;
end
opts.on('-s', '--server server', 'Server') do |server|
options[:server] = server
end
end.parse!
I haven't worked out the logic each will use yet. Right now I'd be happy to just see an error indicating that neither have been provided. So far I'm not getting even that. The script simply runs to completion and returns to a prompt.
I looked at the Ruby Doc for OptionParser, but It isn't clear to me how to accomplish what I'm trying. Is it even possible to have an either/or situation with options? I'm not even sure if what I already have makes sense. I'm basically just attempting to copy the logic without fully understanding what it is doing.
You can check the options hash after the parse! as in
if options[:file] && options[:server]
puts "may have only one of -f and -s"
exit
elsif !options[:file] && !options[:server]
puts "must have at least one of -f and -s"
exit
end

Ruby and SHA256 - Difference between MacOS and Windows?

I wrote this little test script in Ruby (on MacOS):
#!/usr/bin/ruby
require 'digest/sha2'
def calc_sha(file)
# calc hash
hash = Digest::SHA2.new
File.open(file, 'r') do |fh|
fh.each_line do |l|
hash << l
end
end
hash.to_s
end
puts calc_sha('dont-panic.jpeg')
puts '40075d8441ab6a9abeceb7039552704320f471667b8f9ac3c18b9b5b0a1fee7e'
puts calc_sha('dont-panic.jpeg') == '40075d8441ab6a9abeceb7039552704320f471667b8f9ac3c18b9b5b0a1fee7e'
Which outputs (on MacOS):
~/shatest $ ./sha.rb
40075d8441ab6a9abeceb7039552704320f471667b8f9ac3c18b9b5b0a1fee7e
40075d8441ab6a9abeceb7039552704320f471667b8f9ac3c18b9b5b0a1fee7e
true
Then I run the exact same Script in Windows XP:
F:\shatest>ruby sha.rb
9c787b71392551238b24915c888dbd44f4ff465c8e8aadca7af3bb6aaf66a3ca
40075d8441ab6a9abeceb7039552704320f471667b8f9ac3c18b9b5b0a1fee7e
false
Can anyone tell me whats the Problem here?
You're opening a JPEG (i.e. a binary file) and then reading every line of text from it. Don't do that. Any time you treat binary data as text, you're just asking for odd behaviour.
I don't know much about Ruby at all, but I'd generally expect to open the file, and repeatedly read chunks of binary data from it, updating the hash with that. Don't do anything which talks about "lines" or uses text at all.

irb history not working

in ~/.irbrc i have these lines:
require 'irb/ext/save-history'
#History configuration
IRB.conf[:SAVE_HISTORY] = 100
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history"
and yet when i run irb and hit the up arrow nothing happens. also the irb history file specified is not getting created and nothing is logged to it.
irb history works in Debian Linux out of the box. There's no etc/irbrc, nor do I have a ~/.irbrc. So, hmmmm.
This person put a bit more in his irbrc than you did. Do you suppose the ARGV.concat could be the missing piece?
require 'irb/completion'
require 'irb/ext/save-history'
ARGV.concat [ "--readline", "--prompt-mode", "simple" ]
IRB.conf[:SAVE_HISTORY] = 100
IRB.conf[:HISTORY_FILE] = "#{ENV['HOME']}/.irb-save-history"
I don't have an answer for you why the above doesn't work, but I did find a file, /etc/irbrc on my system (OS X - Snow Leopard, Ruby 1.8.7) that does provide a working, persistent history for me. So two pieces of advice: i) check your /etc/irbrc (or equivalent) to make sure that there isn't anything in there that might interfere with your settings, and ii) try out the settings below to see if you can get history working that way.
# Some default enhancements/settings for IRB, based on
# http://wiki.rubygarden.org/Ruby/page/show/Irb/TipsAndTricks
unless defined? ETC_IRBRC_LOADED
# Require RubyGems by default.
require 'rubygems'
# Activate auto-completion.
require 'irb/completion'
# Use the simple prompt if possible.
IRB.conf[:PROMPT_MODE] = :SIMPLE if IRB.conf[:PROMPT_MODE] == :DEFAULT
# Setup permanent history.
HISTFILE = "~/.irb_history"
MAXHISTSIZE = 100
begin
histfile = File::expand_path(HISTFILE)
if File::exists?(histfile)
lines = IO::readlines(histfile).collect { |line| line.chomp }
puts "Read #{lines.nitems} saved history commands from '#{histfile}'." if $VERBOSE
Readline::HISTORY.push(*lines)
else
puts "History file '#{histfile}' was empty or non-existant." if $VERBOSE
end
Kernel::at_exit do
lines = Readline::HISTORY.to_a.reverse.uniq.reverse
lines = lines[-MAXHISTSIZE, MAXHISTSIZE] if lines.nitems > MAXHISTSIZE
puts "Saving #{lines.length} history lines to '#{histfile}'." if $VERBOSE
File::open(histfile, File::WRONLY|File::CREAT|File::TRUNC) { |io| io.puts lines.join("\n") }
end
rescue => e
puts "Error when configuring permanent history: #{e}" if $VERBOSE
end
ETC_IRBRC_LOADED=true
end
This is a known bug with a patch available. Easiest solution is to overwrite save-history.rb:
/usr/lib/ruby/1.8/irb/ext/save-history.rb
with a fixed version:
http://pastie.org/513500
or to do it in one go:
wget -O /usr/lib/ruby/1.8/irb/ext/save-history.rb http://pastie.org/pastes/513500/download
Check to make sure you built ruby with libreadline as irb history seems to not work without it.
This may also happen if you have extra irb config file, e.g. ~/.irbrc. If this is the case, copy the content from liwp's answer to the extra config and it should work.
I had the same problem on ubuntu 20.04 and fixed it by running:
gem install irb

How to view/save/load work space in ruby's interactive mode

I need an interactive environment to play with some algorithm stuff. I want to be able to view what's been defined (data, function) so far and be able save/load so I can continue from a previous saved snapshot if something went wrong. Since I chose ruby as my main scripting language, I hope it had these features built in.
If ruby interactive mode does not provide these functionality, what else you recommend for that?
Thanks
So here’s a technique that will append commands entered in your IRB session to a file in your home directory (idea from ruby-talk:58931). Put the following in your .irbrc:
module Readline
module History
LOG = "#{ENV['HOME']}/.irb-history"
def self.write_log(line)
File.open(LOG, 'ab') {|f| f << "#{line}
"}
end
def self.start_session_log
write_log("
# session start: #{Time.now}
")
at_exit { write_log("
# session stop: #{Time.now}
") }
end
end
alias :old_readline :readline
def readline(*args)
ln = old_readline(*args)
begin
History.write_log(ln)
rescue
end
ln
end
end
Readline::History.start_session_log
You should check out the sketches gem which let's you prototype code in a temporary file in your preferred editor. I don't think it supports snapshots.
In irb I would use it as follows:
>> sketch
# Write some code in an editor ...
# Lists sketches and their code
>> sketches
# Reopens the first sketch from above
>> sketch 1
If you want a more powerful interactive prototyping environment, see boson.

What is Ruby's equivalent of Python's sys.executable?

In Python, you can do
>>> import sys
>>> sys.executable
'/usr/bin/python'
to get at the executable's location. Can you do the same thing just using something built-in to Ruby? It can be a special variable, method, etc.
If there isn't, what is the cleanest, most reliable way of determining the ruby executable's location in a cross-platform way?
Related:
How to get the python.exe location programmatically?
Run this in IRB:
require 'rbconfig'
key_length = RbConfig::CONFIG.keys.max{ |a,b| a.length <=> b.length }.length
RbConfig::CONFIG.keys.sort_by{ |a| a.downcase }.each { |k| puts "%*s => %s" % [key_length, k, RbConfig::CONFIG[k]] }
It will output an "awesome print" style list of all the Ruby configuration info.
ALLOCA =>
AR => ar
arch => x86_64-darwin10.5.0
ARCH_FLAG =>
archdir => /Users/greg/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/x86_64-darwin10.5.0
ARCHFILE =>
AS => as
ASFLAGS =>
BASERUBY => ruby
bindir => /Users/greg/.rvm/rubies/ruby-1.9.2-p0/bin
bindir is the path to the currently running Ruby interpreter. Above it in the list is BASERUBY => ruby.
RbConfig::CONFIG.values_at('bindir', 'BASERUBY').join('/')
=> "/Users/greg/.rvm/rubies/ruby-1.9.2-p0/bin/ruby"
Checking my work:
greg-mbp-wireless:~ greg$ which ruby
/Users/greg/.rvm/rubies/ruby-1.9.2-p0/bin/ruby
There's a lot more information than this so it's worth running the code I added above to see what's available.
Linux-based systems are OK with
`whereis ruby`.split(" ")[1]
It will call whereis ruby and parse its' output for the second entry (first contains 'whereis:')
The more strict method is to call
puts `ls -al /proc/#{$$}/exe`.split(" ")[-1]
It will get the executable name for the current process (there is $$ variable and Process.pid method to obtain that) from /proc/pid/exe symlink information.
Looks like the only truly reliable way is
system("#{Gem.ruby} another_file.rb")
This works even for odd cases like jruby being run as a jar, etc.
Also see
OS.ruby_bin
https://github.com/rdp/os
It looks like the answer is in RbConfig::CONFIG
I think RbConfig::CONFIG['bindir'] provides the directory where the executable is located, the rest is s (or should be) straight forward.
RbConfig::CONFIG['bindir']+'/ruby' should work, even in windows as the exe can be ommitted
Works in a script, not from irb:
puts open($PROGRAM_NAME).readline.gsub /#! *([^ ]+).*/, '\1'
;-)

Resources