-
-
Save arthurariza/c31fae7221cafd4c068e333cc9e572a6 to your computer and use it in GitHub Desktop.
Exceptional Ruby: Master the Art of Handling Failure in Ruby by Avdi Grimm
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
# Great book! Here are my quiz notes: | |
# What is the diff bt raise and fail? | |
#=> no diff | |
# Are raise//fail ruby keywords or methods? | |
#=> Kernel#raise (are methods) | |
# Global exception variable | |
# => $! or $ERROR_INFO.inspect | |
require ’English’ | |
begin | |
puts $!.inspect | |
raise "Oops" | |
rescue | |
puts $!.inspect | |
puts $ERROR_INFO.inspect | |
end | |
puts $!.inspect | |
# Re-raise last exception | |
# With no arguments will re-raise exception in $! If nil then RuntimeError | |
# note $! value is nil initialized as soon as the begin..rescue.end block terminates raise | |
# What is the third argument of raise and give an example of what to put there. | |
#=> the backtrace, use for example Kernel#caller | |
# What is catch/throw used for? | |
#=> not related to exceptions, catch/throw allows you to quickly exit blocks back to a point where a catch is defined for a specific symbol | |
# Retry | |
tries = 0 | |
begin | |
tries += 1 | |
puts "Trying #{tries}..." | |
raise "Didn’t work" | |
rescue | |
retry if tries < 3 | |
puts "I give up" | |
end | |
# Diffs bt `redo` vs `retry` | |
#=> Both ruby keywords are used to re-execute parts of a loop but: | |
# redo only repeats the current iteration | |
# retry repeats the whole loop from the start in 1.8 but in 1.9 gives SyntaxError: Invalid retry | |
# Note retry should only be used inside immediate rescue blocks | |
# - What's caller() method used for, where's defined and what param takes? | |
#=> Kernel#caller(omit_from_start=1) | |
# Returns the current execution stack. | |
# An array containing strings in the form “file:line” or “file:line: in `method'” | |
# Has an optional start parameter with the number of initial stack entries to omit from the result. | |
# when omit=0 it will also show the current file:line:method where caller() was called | |
# Else | |
begin | |
puts "in body" | |
rescue | |
puts "in rescue" | |
else | |
puts "in else" | |
ensure | |
puts "in ensure" | |
end | |
puts "after end" | |
#=> in body | |
#=> in else | |
#=> in ensure | |
#=> after end | |
# Be specific when eating exceptions | |
# Antipattern | |
begin | |
# ... | |
rescue Exception | |
end | |
# Namespace your own exceptions | |
module MyLibrary | |
class Error < StandardError; end | |
end | |
# Raising Exceptions Require Extra Resources | |
def fib(n) | |
return n if n < 2 | |
vals = [0, 1] n.times do | |
vals.push(vals[-1] + vals[-2]) | |
end | |
return vals.last | |
end | |
def fib_raise(n) | |
return n if n < 2 | |
vals = [0, 1] | |
i=0 | |
loop do | |
vals.push(vals[-1] + vals[-2]) i += 1 | |
raise if i >= n | |
end | |
rescue RuntimeError | |
return vals.last | |
end | |
require ’benchmark’ | |
Benchmark.bm(10) { |bm| | |
bm.report("fib") { 1000.times { fib(100)} } #=> 0.073168 | |
bm.report("fib_raise") { 1000.times { fib_raise(100) } } #=> 0.111309 | |
} | |
# Alternatives to exceptions | |
# Multiple return values | |
#Array | |
def foo | |
result = 42 | |
success = true | |
[result, success] | |
end | |
result, success = foo | |
puts "#{success ? ’Succeeded’ : ’Failed’}; result: #{result}" | |
# Struct | |
def foo | |
result = 42 | |
success = true | |
OpenStruct.new(:result => 42, :status => :success) | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment