I love Ruby! But as in any relationship, to love means that you (often) have to accept the “dark side” too! Ruby is human in nature and has a lot of gotchas, tricks, weirdness and sometimes scary features that I plan to highlight. This talk aims to provide the “Ah-ha!” moments when working in Ruby.
This talk is for beginners and experts alike - in fact, I tag slides to mark their level and beginners can choose to tune out of the heavy stuff! My talk shall cover the dark side of the following features of Ruby (in no particular order)
Keyword wierdness
method missing
Module inheritance! (huh?)
Accessor righteousness
Curried Procs for the hungry
Base Conversions
Cherry picking module methods
Oniguruma games
Object id weirdness
procs, blocks and our friend stabby.
==, ===, eql? and equal?
and more…
As with most of my talks, humor plays an important role and I shall aim to get everyone high on Ruby with a deep dive!
30. Base Conversions
$ irb> 12345.to_s(8)
$ irb> 12345.to_s(36)
=> "30071" # => Octal
=> "9ix" # That is an actual number
31. Base Conversions
$ irb> 12345.to_s(8)
$ irb> 12345.to_s(36)
$ irb> 1234.to_s(64)
=> "30071" # => Octal
=> "9ix" # That is an actual number
32. Base Conversions
$ irb> 12345.to_s(8)
$ irb> 12345.to_s(36)
$ irb> 1234.to_s(64)
=> "30071" # => Octal
=> "9ix" # That is an actual number
=> ArgumentError: invalid radix 64
69. The Case Statement
def multiple_of(factor)!
Proc.new {|p| p.modulo(factor).zero?}!
end!
!
number = 9!
case number!
when multiple_of(3)!
puts "Multiple of 3"!
when multiple_of(7)!
puts "Multiple of 7"!
end
70. The Case Statement
def multiple_of(factor)!
Proc.new {|p| p.modulo(factor).zero?}!
end!
!
number = 9!
case number!
when multiple_of(3)!
puts "Multiple of 3"!
when multiple_of(7)!
puts "Multiple of 7"!
end
71. Behind every case is a ===
number = 9!
case number !
when multiple_of(3)
Proc.new {|p| p.modulo(3).zero?} === 9
72. Behind every case is a ===
number = 9!
case number !
when multiple_of(3)
Proc.new {|p| p.modulo(3).zero?} === 9
73. Behind every case is a ===
number = 9!
case number !
when multiple_of(3)
Proc.new {|p| p.modulo(3).zero?} === 9
Proc#=== is an alias to Proc#call.
74. Behind every case is a ===
number = 9!
case number !
when multiple_of(3)
Proc.new {|p| p.modulo(3).zero?} === 9
Proc.new { |p| !
p.modulo(3).zero?!
}.call(9)
Proc#=== is an alias to Proc#call.
94. 3 Pulls for the Jackpot
jackpot = lambda { |x, y, z|
(x == y) == (x == z)
}
# 3 pulls
pull = jackpot.curry[rand(5)]
2.times { pull = pull.curry[rand(5)] }
!
p pull ? "Jackpot" : "Sucker!"
95. 3 Pulls for the Jackpot
jackpot = lambda { |x, y, z|
(x == y) == (x == z)
}
# 3 pulls
pull = jackpot.curry[rand(5)]
2.times { pull = pull.curry[rand(5)] }
!
p pull ? "Jackpot" : "Sucker!"
96. 3 Pulls for the Jackpot
jackpot = lambda { |x, y, z|
(x == y) == (x == z)
}
# 3 pulls
pull = jackpot.curry[rand(5)]
2.times { pull = pull.curry[rand(5)] }
!
p pull ? "Jackpot" : "Sucker!"
97. The curry recipe
• Return lambda till all parameters are passed.
• Evaluate the block if all parameters are passed.
pull = jackpot.curry[rand(5)]
=> #<Proc:0x007f9eec0990b0 (lambda)>
2.times { pull = pull.curry[rand(5)] }
=> true # or false
98. The curry recipe
• Return lambda till all parameters are passed.
• Evaluate the block if all parameters are passed.
pull = jackpot.curry[rand(5)]
=> #<Proc:0x007f9eec0990b0 (lambda)>
2.times { pull = pull.curry[rand(5)] }
=> true # or false
99. So! So you think you can tell…
Heaven from Hell
- Pink Floyd
100. So! So you think you can tell…
Protected from Private
110. Protected methods
• Work with objects not classes.
• Invoke a protected method on
another object in the same lineage
111. Protected methods
• Work with objects not classes.
• Invoke a protected method on
another object in the same lineage
What the …
112. class Autobot
def initialize(nick); @nick = nick; end
!
protected
attr_accessor :nick
end
!
prime = Autobot.new("Optimus Prime")
p prime.nick
113. class Autobot
def initialize(nick); @nick = nick; end
!
protected
attr_accessor :nick
end
!
prime = Autobot.new("Optimus Prime")
p prime.nick
114. class Autobot
def initialize(nick); @nick = nick; end
!
protected
attr_accessor :nick
end
!
prime = Autobot.new("Optimus Prime")
p prime.nick
protected method `nick' called for
#<Autobot:0x007f92ba082330 @nick="Optimus
Prime"> (NoMethodError)
115. class Autobot
def fights(target)
p "I am #{self.nick}"
p "Kicking #{target.nick}'s ass"
end
protected
attr_accessor :nick
end
!
optimus = Autobot.new("Optimus Prime")
megatron = Autobot.new('Megatron')
!
optimus.fights megatron
116. class Autobot
def fights(target)
p "I am #{self.nick}"
p "Kicking #{target.nick}'s ass"
end
protected
attr_accessor :nick
end
!
optimus = Autobot.new("Optimus Prime")
megatron = Autobot.new('Megatron')
!
optimus.fights megatron
117. class Autobot
def fights(target)
p "I am #{self.nick}"
p "Kicking #{target.nick}'s ass"
end
protected
attr_accessor :nick
end
!
optimus = Autobot.new("Optimus Prime")
megatron = Autobot.new('Megatron')
!
optimus.fights megatron
"I am Optimus Prime"
"Kicking Megatron's ass"
118. class Autobot
def fights(target)
p "I am #{self.nick}"
p "Kicking #{target.nick}'s ass"
end
protected
attr_accessor :nick
end
!
optimus = Autobot.new("Optimus Prime")
megatron = Autobot.new('Megatron')
!
optimus.fights megatron
"I am Optimus Prime"
"Kicking Megatron's ass"
120. Keywords - hmm…
class Serious
def true
false
end
def false
true
end
end
die = Serious.new
p "seriously!" if die.false
121. Keywords - hmm…
class Serious
def true
false
end
def false
true
end
end
die = Serious.new
p "seriously!" if die.false
122. Keywords - hmm…
class Serious
def true
false
end
def false
true
end
end
die = Serious.new
p "seriously!" if die.false
stack too deep?
123. superlative
class Search!
def search!
p "Default Search algorithm"!
end!
end!
class KeywordSearch < Search !
def search(keyword:)!
super!
end!
end!
KeywordSearch.new.search(keyword: "Ruby")
124. superlative
class Search!
def search!
p "Default Search algorithm"!
end!
end!
class KeywordSearch < Search !
def search(keyword:)!
super!
end!
end!
KeywordSearch.new.search(keyword: "Ruby")
125. superlative
class Search!
def search!
p "Default Search algorithm"!
end!
end!
class KeywordSearch < Search !
def search(keyword:)!
super!
end!
end!
KeywordSearch.new.search(keyword: "Ruby")
126. superlative
class Search!
def search!
p "Default Search algorithm"!
end!
end!
class KeywordSearch < Search !
def search(keyword:)!
super!
end!
end!
KeywordSearch.new.search(keyword: "Ruby")
`search`: wrong number
of arguments (1 for 0)
127. superlative
class Search!
def search!
p "Default Search algorithm"!
end!
end!
class KeywordSearch < Search !
def search(keyword:)!
super()!
end!
end!
KeywordSearch.new.search(keyword: "Ruby")
128. superlative
class Search!
def search!
p "Default Search algorithm"!
end!
end!
class KeywordSearch < Search !
def search(keyword:)!
super()!
end!
end!
KeywordSearch.new.search(keyword: "Ruby")
129. superlative
class Search!
def search!
p "Default Search algorithm"!
end!
end!
class KeywordSearch < Search !
def search(keyword:)!
super()!
end!
end!
KeywordSearch.new.search(keyword: "Ruby")
130. superlative
class Search!
def search!
p "Default Search algorithm"!
end!
end!
class KeywordSearch < Search !
def search(keyword:)!
super()!
end!
end!
KeywordSearch.new.search(keyword: "Ruby")
And we thought parenthesis for
method invocation didn’t matter
131. Module mixins are funny
module Superman!
def fly; p "Superman: It's a bird"; end!
end!
!
module Batman!
def fly; p "Batman: Fly? Me?"; end!
end!
!
module Ironman!
def fly; p "Iroman: That's flying!"; end!
end
132. Module mixins are funny
module Superman!
def fly; p "Superman: It's a bird"; end!
end!
!
module Batman!
def fly; p "Batman: Fly? Me?"; end!
end!
!
module Ironman!
def fly; p "Iroman: That's flying!"; end!
end
133. Module mixins are funny
class Tinyman!
include Superman!
include Batman!
include Ironman!
end!
!
Tinyman.new.fly
"Iroman: That's how you fly!"
134. Module mixins are funny
class Tinyman!
include Superman!
include Batman!
include Ironman!
end!
!
Tinyman.new.fly
"Iroman: That's how you fly!"
135. Module Inheritance?
module Superman!
def fly; p "Superman: It's a bird"; end!
end!
!
module Batman!
def fly; p "Batman: Fly? Me?"; end!
end!
!
module Ironman!
def fly; super; p "Iroman: That's flying!"; end!
end
136. Module Inheritance?
module Superman!
def fly; p "Superman: It's a bird"; end!
end!
!
module Batman!
def fly; p "Batman: Fly? Me?"; end!
end!
!
module Ironman!
def fly; super; p "Iroman: That's flying!"; end!
end
137. Module Inheritance?
module Superman!
def fly; p "Superman: It's a bird"; end!
end!
!
module Batman!
def fly; p "Batman: Fly? Me?"; end!
end!
!
module Ironman!
def fly; super; p "Iroman: That's flying!"; end!
end
"Batman: Fly? Me?”!
"Iroman: That's flying!"
140. class Tinyman!
include Superman!
include Ironman!
include Batman!
end
Dynamic Inheritance!
class Tinyman!
include Superman!
include Batman!
include Ironman!
end
141. class Tinyman!
include Superman!
include Ironman!
include Batman!
end
Dynamic Inheritance!
class Tinyman!
include Superman!
include Batman!
include Ironman!
end
142. Cherry pick from Modules
module Megatron!
def power!
p "Megatron's super strength"!
end!
!
def evil!
p 'Evil genius'!
end!
end
143. Cherry pick from Modules
module Megatron!
def power!
p "Megatron's super strength"!
end!
!
def evil!
p 'Evil genius'!
end!
end