While learning ruby I’ve run into a few gotchas that I think may be worth discussion/sharing. It’s worth noting that I’m coming from a Java,C#,C based background. These may not seem that odd to people coming from different backgrounds.
irb(main):001:0> "1" + 1
TypeError: can't convert Fixnum into String
from (irb):1:in `+'
from (irb):1
irb(main):001:0> p "rats" if 1 == true
=> nil
irb(main):002:0> p "rats" if 0 == false
=> nil
irb(main):003:0> p "yay?" if nil
=> nil
irb(main):004:0> p "oro?" if 6
"oro?"
=> nil
irb(main):005:0> p "oro?" if -6
"oro?\n"
=> nil
irb(main):005:0> p "will print" if 0
"oro?\n"
=> nil
&& and || are the high priority AND/OR constructs, and and or are low priority versions
irb(main):016:0> x = nil or 99
=> 99
irb(main):017:0> x
=> nil
irb(main):018:0> x = 42 and 99
=> 99
irb(main):019:0> x
=> 42
irb(main):020:0> x = nil || 99
=> 99
irb(main):021:0> x
=> 99
irb(main):022:0> x = 49 && 100
=> 100
That last one came as a surprise to me, as I expected it to return true. Guess not.
Exceptions and raise vs catch
catch/throw are not the same as raise/rescue. catch/throw allows you to quickly exit blocks back to a point where a catch is defined for a specific symbol, raise rescue is the real exception handling stuff involving the Exception object. If your exception doesn’t inherit from StandardError it will NOT be caught by default!
irb(main):001:0> class MyException < Exception
irb(main):002:1> end
=> nil
irb(main):003:0> def exception_miss
irb(main):004:1> raise MyException.new
irb(main):005:1> rescue
irb(main):006:1> p "saved!"
irb(main):007:1> end
=> nil
irb(main):008:0> begin
irb(main):009:1* exception_miss
irb(main):010:1> rescue Exception
irb(main):011:1> p "not so much"
irb(main):012:1> end
"not so much"
=> nil
irb(main):015:0> def exception_hit
irb(main):016:1> raise NewException
irb(main):017:1> rescue
irb(main):018:1> p "excellent!"
irb(main):019:1> end
=> nil
irb(main):020:0> exception_hit
"excellent!"
=> nil
irb(main):021:0> def catcher
irb(main):022:1> throw :testing
irb(main):023:1> rescue
irb(main):024:1> p "gotcha?"
irb(main):025:1> end
=> nil
irb(main):026:0> catcher
"gotcha?"
=> nil
irb(main):071:0> def throw_no_rescue
irb(main):072:1> throw :gotme
irb(main):073:1> end
=> nil
irb(main):074:0> def fire
irb(main):075:1> catch(:gotme) do
irb(main):076:2* p "start"
irb(main):077:2> throw_no_rescue
irb(main):078:2> p "after throw"
irb(main):079:2> end
irb(main):080:1> p "after catch"
irb(main):081:1> end
=> nil
irb(main):082:0> throw_no_rescue
NameError: uncaught throw `gotme'
from (irb):72:in `throw'
from (irb):72:in `throw_no_rescue'
from (irb):82
from ♥:0
irb(main):083:0> fire
"start"
"after catch"
=> nil
irb(main):001:0> class MonkeyNinja
irb(main):002:1> private
irb(main):003:1> def secret_weakness
irb(main):004:2> p "eep! dead monkey!"
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> m = MonkeyNinja.new
=> #<MonkeyNinja:0x2c01d5c>
irb(main):008:0> m.methods
=> [...no secret weakness! ]
irb(main):009:0> m.private_methods
=> [stuff, "secret_weakness", "lambda"]
irb(main):010:0> m.send :secret_weakness
"eep! dead monkey!"
=> nil
irb(main):011:0> m.secret_weakness
NoMethodError: private method 'secret_weakness' called for #<MonkeyNinja:0x2c01d5c>
from (irb):10
from ♥:0
irb(main):012:0> m.instance_eval do
irb(main):013:1* secret_weakness
irb(main):014:1> end
"eep! dead monkey!"
=> nil
irb(main):015:0> def m.kill_you
irb(main):016:1> secret_weakness
irb(main):017:1> end
=> nil
irb(main):018:0> m.kill_you
"eep! dead monkey!"
=> nil
irb(main):010:0> 1.0/2
=> 0.5
irb(main):011:0> 1/2
=> 0
irb(main):012:0> p "normalcy" if 1/2 == 0.5
=> nil
irb(main):013:0> require 'mathn'
=> true
irb(main):014:0> 1/2
=> 1/2
irb(main):015:0> p "normalcy" if 1/2 == 0.5
"normalcy"
=> nil
irb(main):016:0> a = 0.5
=> 0.5
irb(main):017:0> a.class
=> Float
irb(main):018:0> b = 1/2
=> 1/2
irb(main):019:0> b.class
=> Rational
irb(main):001:0> class OmgFun
irb(main):002:1> @@taco = "testing"
irb(main):003:1> def taco
irb(main):004:2> @@taco = "me"
irb(main):005:2> end
irb(main):006:1> def self.to_s
irb(main):007:2> @@taco
irb(main):008:2> end
irb(main):009:1> end
=> nil
irb(main):010:0> class B < OmgFun
irb(main):011:1> @@taco = "B's taco"
irb(main):012:1> end
=> "B's taco"
irb(main):013:0> class C < B
irb(main):014:1> @@taco = "C's taco"
irb(main):015:1> end
=> "C's taco"
irb(main):016:0> C.to_s
=> "C's taco"
irb(main):017:0> B.to_s
=> "C's taco"
irb(main):018:0> OmgFun.to_s
=> "C's taco"
irb(main):001:0> class Daffy
irb(main):002:1> @@mine = "all mine"
irb(main):003:1> def to_s
irb(main):004:2> @@mine
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> class << Daffy
irb(main):008:1> def jigga
irb(main):009:2> @@mine = "bunny time"
irb(main):010:2> end
irb(main):011:1> end
=> nil
irb(main):012:0> d = Daffy.new
=> all mine
irb(main):013:0> Daffy.jigga
(irb):9: warning: class variable access from toplevel singleton method
=> "bunny time"
irb(main):014:0> d
=> all mine
irb(main):015:0> d = Daffy.new
=> all mine
irb(main):016:0> def Daffy.wha
irb(main):017:1> @@mine = "wabbit"
irb(main):018:1> end
=> nil
irb(main):019:0> Daffy.wha
=> "wabbit"
irb(main):020:0> d
=> all mine
irb(main):021:0> d = Daffy.new
=> all mine
or
irb(main):001:0> class A
irb(main):002:1> @@foo = "bar"
irb(main):003:1> def self.print_foo
irb(main):004:2> p @@foo
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> A.print_foo
"bar"
=> nil
irb(main):008:0> A.class_eval do
irb(main):009:1* @@foo = "no go"
irb(main):010:1> end
=> "no go"
irb(main):011:0> A.print_foo
"bar"
=> nil
irb(main):012:0> A.class_eval do
irb(main):013:1* def self.new_hotness
irb(main):014:2> p @@foo
irb(main):015:2> end
irb(main):016:1> end
=> nil
irb(main):017:0> A.new
A.new A.new_hotness
irb(main):017:0> A.new
A.new A.new_hotness
irb(main):017:0> A.new_hotness
"no go"
=> nil
irb(main):018:0> A.instance_eval do
irb(main):019:1* p @@foo
irb(main):020:1> end
"no go"
=> nil
irb(main):021:0> A.module_eval do
irb(main):022:1* p @@foo
irb(main):023:1> end
"no go"
=> nil
irb(main):024:0> A.print_foo
"bar"
=> nil
irb(main):001:0> class Foo
irb(main):002:1> def self.bar=(val)
irb(main):003:2> return "apeiros!"
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> Foo.bar = "meep"
=> "meep"
irb(main):007:0> Foo.bar
NoMethodError: undefined method 'bar' for Foo:Class
from (irb):7
from ♥:0
irb(main):008:0> class Pizza
irb(main):009:1> def my_hut
irb(main):010:2> p "tasty!"
irb(main):011:2> end
irb(main):012:1> def breadstick
irb(main):013:2> if nil
irb(main):014:3> my_hut = "never executed"
irb(main):015:3> end
irb(main):016:2> my_hut
irb(main):017:2> end
irb(main):018:1> end
=> nil
irb(main):019:0> m = Pizza.new
=> #<Pizza:0x2c63cc8>
irb(main):020:0> m.breadstick
=> nil
irb(main):001:0> class A
irb(main):002:1> @@avar = "hello"
irb(main):003:1> end
=> "hello"
irb(main):004:0> A.class_variables
=> ["@@avar"]
irb(main):005:0> A.class_eval { puts @@avar }
NameError: uninitialized class variable @@avar in Object
from (irb):5
from (irb):5:in 'class_eval'
from (irb):5
from ♥:0
irb(main):006:0> A.instance_eval { puts @@avar }
NameError: uninitialized class variable @@avar in Object
from (irb):6
from (irb):6:in 'instance_eval'
from (irb):6
from :0
irb(main):007:0> A.module_eval { puts @@avar }
NameError: uninitialized class variable @@avar in Object
from (irb):7
from (irb):7:in 'module_eval'
from (irb):7
from ♥:0
irb(main):008:0> class A
irb(main):009:1> def my_avar
irb(main):010:2> @@avar
irb(main):011:2> end
irb(main):012:1> end
=> nil
irb(main):013:0> a = A.new
=> #<A:0x2c27890>
irb(main):014:0> a.my_avar
=> "hello"
irb(main):015:0> a.instance_eval { puts @@avar }
NameError: uninitialized class variable @@avar in Object
from (irb):15
from (irb):15:in 'instance_eval'
from (irb):15
from :0