Skip to content

Instantly share code, notes, and snippets.

@pachacamac
Created October 21, 2012 19:36
Show Gist options
  • Save pachacamac/3928204 to your computer and use it in GitHub Desktop.
Save pachacamac/3928204 to your computer and use it in GitHub Desktop.
Some very nice tricks and helpful magic in Ruby
# $ grep '^###' ruby_nuggets.rb
# if you just want all headlines
### multiple heredoc goodness
head,body = <<END_HEAD,<<END_BODY
this is the head
yea still head
END_HEAD
and now some body
it is #{Time.now} now
enough body
END_BODY
### inspecting the source
SCRIPT_LINES__ = {} #format: {"file_name.rb" => ["line 1", "line 2", ...]}
require 'time'
puts SCRIPT_LINES__.values.flatten.select{ |line| line.size > 80 }
### automatic tailcall optimization
RubyVM::InstructionSequence.compile_option = { tailcall_optimization: true, trace_instruction: false }
eval <<END
def factorial(n, result = 1)
n == 1 ? result : factorial(n - 1, n * result)
end
END
p factorial(30_000)
### being more verbose
$VERBOSE = true
@x || 42
### variables from regex
if /\A(?<last>\w+),\s*(?<first>\w+)\z/ =~ "Gray, James"
puts "#{first} #{last}"
end
### iterating through more than one collection
letters, numbers = "a".."d", 1..3
letters.zip(numbers){|letter, number| p(letter: letter, number: number)}
### a struct takes a block
Name = Struct.new(:first, :last){def full; "#{first} #{last}"; end}
james = Name.new("James", "Gray")
# OR
Struct.new("Name", :first, :last){def full; "#{first} #{last}"; end}
james = Struct::Name.new("James", "Gray")
### profile the garbage collector
GC::Profiler.enable
10.times{ array = Array.new(1_000_000) { |i| i.to_s } }
puts GC::Profiler.result
### for debugging threaded code
Thread.abort_on_exception = true
### the built in debug variable
puts 42
puts "that's the answer!" if $DEBUG
#ruby -d fourtytwo.rb
### two tests in one
p 2.between?(1, 10)
p "cat".between?("bat", "rat")
### file read/write shortcut
File.write("output.txt", "one\ntwo\nthree\n", :mode=>'a')
puts File.read("output.txt")
### daemonize your script
Process.daemon(true) #don't change current directory
loop{ sleep }
### serious subprocess launching with spawn
spawn({"A_VAR" => "Whatever"}, cmd) # set an environment variable
spawn({"A_VAR" => nil}, cmd) # clear an environment variable
spawn(env, cmd, unsetenv_others: true) # clear unset environment variables
spawn("rm *.txt") # normal shell expansion
spawn("rm", "*.txt") # bypass the shell, no expansion
spawn(["rm", "sweeper"], "*.txt") # rename command in process list
spawn(cmd, pgroup: 0) # change the process group
spawn(cmd, rlimit_cpu: Process.getrlimit(:CPU).last) # raise resource limits
spawn(cmd, chdir: path) # change working directory
spawn(cmd, umask: 0222) # change permissions
spawn(cmd, in: io) # redirect IO
spawn(cmd, io => [open, args])
spawn(cmd, io => :close) # close an IO
spawn(cmd, close_others: true) # close unset IO
pid = spawn(cmd); Process.detach(pid) # asynchronous
pid = spawn(cmd); Process.wait(pid) # synchronous
### simple benchmarking
def measure(count, &block)
t = Time.now
count.times{ |i| yield i }
t = Time.now - t
{:iterations => count, :duration => t, :per_unit => t / count.to_f}
end
### handling strings like the unix shell
require 'shellwords'
Shellwords.shellwords('"escaped \"quote\" characters"')
Shellwords.shellwords('escaped\ spaces')
Shellwords.shellescape('"quotes" included')
Shellwords.shelljoin(["two words", '"quotes" included'])
### easiest database (multiprocess safe!)
require "pstore"
db = PStore.new("accounts.pstore")
# OR human readable
require "yaml/store"
db = YAML::Store.new("accounts.yml")
# AND THEN
db.transaction do
db["james"] = 100.00
db["dana"] = 100.00
end
db.transaction do
db["dana"] += 200.00
db["james"] -= 200.00
db.abort if db["james"] < 0.0
end
db.transaction(true) do
puts "James: %p" % db["james"]
puts "Dana:
%p" % db["dana"]
end
### sets are pretty cool
require "set"
animals = Set.new
animals << "cat"
animals.add("bat")
p animals.add?("rat")
p animals.add?("rat")
p animals
p animals.member?("tiger")
p animals.subset?(Set["bat", "cat"])
p animals.superset?(%w[lions tigers bears].to_set)
ordered = SortedSet.new
(1..10).to_a.shuffle.each{ |n| ordered << n }
p ordered
### mini ruby programs, commandline switches -p, -i, -e, -n
$ cat data.txt
ones
twos
$ ruby -pi.bak -e 'sub(/s\Z/, "")' data.txt
$ cat data.txt
one
two
$ cat data.txt.bak
ones
twos
### spawn an irb from your code
require "irb"
@foo = 'bar'
trap(:INT) do
IRB.start
trap(:INT, "EXIT")
end
loop{ puts "value of @foo is #{@foo}"; sleep 1 }
### clean up your shit when you leave
at_exit do
if $! and not [SystemExit, Interrupt].include?($!.class)
#error
else
#interrupted
end
end
### only one running instance
DATA.flock(File::LOCK_EX | File::LOCK_NB) or abort "Already running."
trap("INT", "EXIT")
puts "Running..."
loop{ sleep }
__END__
DO NOT DELETE:
used for locking
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment