Created
October 21, 2012 19:36
-
-
Save pachacamac/3928204 to your computer and use it in GitHub Desktop.
Some very nice tricks and helpful magic in Ruby
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# $ 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