The Dark Side of Ruby
@gautamrege!
@joshsoftware
What’s the talk about?
What’s the talk about?
• Ruby is AWESOME but …
What’s the talk about?
• Ruby is AWESOME but …
• Nothing scary
What’s the talk about?
• Ruby is AWESOME but …
• Nothing scary really
What’s the talk about?
• Ruby is AWESOME but …
• Nothing scary
• Weirdness and Gotcha’s
really
What’s the talk about?
• Ruby is AWESOME but …
• Nothing scary
• Weirdness and Gotcha’s
Ah-ha! Moments
really
Slides are Tagged
Slides are Tagged
Beginner
Slides are Tagged
Expert
(In)Famous Infinityhttp://www.flickr.com/photos/emdot/482622478/sizes/l/
(In)Famous Infinity
(In)Famous Infinity
(In)Famous Infinity
$ irb> 1/0
(In)Famous Infinity
$ irb> 1/0
=> ZeroDivisionError: divided by 0
(In)Famous Infinity
$ irb> 1/0
$ irb> 1.0/0
=> ZeroDivisionError: divided by 0
(In)Famous Infinity
$ irb> 1/0
$ irb> 1.0/0
=> ZeroDivisionError: divided by 0
=> Infinity
(In)Famous Infinity
$ irb> 1/0
$ irb> 1.0/0
$ irb> Infinity
=> ZeroDivisionError: divided by 0
=> Infinity
(In)Famous Infinity
$ irb> 1/0
$ irb> 1.0/0
$ irb> Infinity
=> ZeroDivisionError: divided by 0
=> Infinity
=> NameError: uninitialized constant
Infinity
(In)Famous Infinity
(In)Famous Infinity
(In)Famous Infinity
#if !defined(INFINITY) || !defined(NAN)!
union bytesequence4_or_float {!
unsigned char bytesequence[4];!
float float_value;!
};!
#endif!
!
RUBY_EXTERN const union
bytesequence4_or_float rb_infinity;
(In)Famous Infinity
#if !defined(INFINITY) || !defined(NAN)!
union bytesequence4_or_float {!
unsigned char bytesequence[4];!
float float_value;!
};!
#endif!
!
RUBY_EXTERN const union
bytesequence4_or_float rb_infinity;
include/ruby/missing.h
Base Jumping
http://www.flickr.com/photos/shahdi/8035647153/sizes/l/
Base Conversions
Base Conversions
Base Conversions
$ irb> 12345.to_s(8)
Base Conversions
$ irb> 12345.to_s(8)
=> "30071" # => Octal
Base Conversions
$ irb> 12345.to_s(8)
$ irb> 12345.to_s(36)
=> "30071" # => Octal
Base Conversions
$ irb> 12345.to_s(8)
$ irb> 12345.to_s(36)
=> "30071" # => Octal
=> "9ix" # That is an actual number
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
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
Hashes and Arrays
Hashes and Arrays
Hashes and Arrays
a=[1,2,3,4,5,6]!
h=Hash[*a]
Hashes and Arrays
a=[1,2,3,4,5,6]!
h=Hash[*a]
=> {1=>2, 3=>4, 5=>6}
Hashes and Arrays
a=[1,2,3,4,5,6]!
h=Hash[*a]
=> {1=>2, 3=>4, 5=>6}
[1,2,3] * 3
Hashes and Arrays
a=[1,2,3,4,5,6]!
h=Hash[*a]
=> {1=>2, 3=>4, 5=>6}
[1,2,3] * 3
=> [1,2,3,1,2,3,1,2,3]
Hashes and Arrays
a=[1,2,3,4,5,6]!
h=Hash[*a]
=> {1=>2, 3=>4, 5=>6}
[1,2,3] * 3
=> [1,2,3,1,2,3,1,2,3]
[1,2,3] * "%"
Hashes and Arrays
a=[1,2,3,4,5,6]!
h=Hash[*a]
=> {1=>2, 3=>4, 5=>6}
[1,2,3] * 3
=> [1,2,3,1,2,3,1,2,3]
[1,2,3] * "%"
=> "1%2%3"
Calling out to Stabby
Calling out to Stabby
blk = ->(f, *m, sl, l) do
puts sl
end
Calling out to Stabby
blk = ->(f, *m, sl, l) do
puts sl
end
blk.call(1, 2, 3, 4, 5, 6)
Calling out to Stabby
blk = ->(f, *m, sl, l) do
puts sl
end
blk.call(1, 2, 3, 4, 5, 6)
=> 5
blk.(1, 2, 3, 4, 5, 6)
Calling out to Stabby
blk = ->(f, *m, sl, l) do
puts sl
end
blk.call(1, 2, 3, 4, 5, 6)
=> 5
blk.(1, 2, 3, 4, 5, 6)
Calling out to Stabby
blk = ->(f, *m, sl, l) do
puts sl
end
blk.call(1, 2, 3, 4, 5, 6)
=> 5
blk.(1, 2, 3, 4, 5, 6)
=> 5
syntax sugar for call
blk[1,2,3,4,5,6]
Calling out to Stabby
blk = ->(f, *m, sl, l) do
puts sl
end
blk.call(1, 2, 3, 4, 5, 6)
=> 5
Syntax
Syntax
def foo(a=1, b=1,opts={})
end
Syntax
def foo(a: 1, b: 2)
end
Syntax
def foo(a: 1, b: 2)
end
keyword arguments
Syntax
def foo(a: 1, b:, c: 2)
end
def foo(a: 1, b: 2)
end
keyword arguments
Syntax
def foo(a: 1, b:, c: 2)
end
def foo(a: 1, b: 2)
end
keyword arguments
Syntax
def foo(a: 1, b:, c: 2)
end
foo(a: 2)
=> ArgumentError: missing keyword: b
Mandatory keyword
arguments
def foo(a: 1, b: 2)
end
keyword arguments
Syntax
Syntax
def foo(a, b)
p a, b
end
Syntax
def foo(a, b)
p a, b
end
foo (1, 2)
Syntax
def foo(a, b)
p a, b
end
foo (1, 2)
syntax error, unexpected
',', expecting ')'
Syntax
def foo(a, b)
p a, b
end
foo (1, 2)
foo(1, 2)
Syntax
def foo(a, b)
p a, b
end
foo (1, 2)
foo(1, 2)
Syntax
def foo(a, b)
p a, b
end
foo (1, 2)
foo(1, 2) syntax error, unexpected
',', expecting ')'
Syntax
Syntax
irb> a[1]
What is the
data type of a ?
Syntax
irb> a[1]
a = [ 10, 11, 12] # Array
Syntax
irb> a[1]
a = [ 10, 11, 12] # Array
a = { 1 => "one" } # Hash
Syntax
irb> a[1]
a = [ 10, 11, 12] # Array
a = { 1 => "one" } # Hash
a = Proc.new { |e| p e }
Case Complexity
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
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
Behind every case is a ===
number = 9!
case number !
when multiple_of(3)
Proc.new {|p| p.modulo(3).zero?} === 9
Behind every case is a ===
number = 9!
case number !
when multiple_of(3)
Proc.new {|p| p.modulo(3).zero?} === 9
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.
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.
Override the === method
to customise case
evaluation.
==, ===, eql?, equal?
http://www.flickr.com/photos/gak/2418146934/sizes/o/
==, ===, eql?, equal?
==, ===, eql?, equal?
irb> 1 == 1.0
==, ===, eql?, equal?
irb> 1 == 1.0
=> true # generic equality
==, ===, eql?, equal?
irb> 1 == 1.0
=> true # generic equality
irb> 1 === 1.0
==, ===, eql?, equal?
irb> 1 == 1.0
=> true # generic equality
irb> 1 === 1.0
=> true # case equality
==, ===, eql?, equal?
irb> 1 == 1.0
=> true # generic equality
irb> 1 === 1.0
=> true # case equality
irb> 1.eql? 1.0
==, ===, eql?, equal?
=> false # alias of == except Numeric
irb> 1 == 1.0
=> true # generic equality
irb> 1 === 1.0
=> true # case equality
irb> 1.eql? 1.0
==, ===, eql?, equal?
=> false # alias of == except Numeric
irb> 1 == 1.0
=> true # generic equality
irb> 1 === 1.0
=> true # case equality
irb> 1.eql? 1.0
irb> 1.equal? 1.0
==, ===, eql?, equal?
=> false # alias of == except Numeric
irb> 1 == 1.0
=> true # generic equality
irb> 1 === 1.0
=> true # case equality
irb> 1.eql? 1.0
irb> 1.equal? 1.0
=> false # object identity
==, ===, eql?, equal?
=> false # alias of == except Numeric
irb> 1 == 1.0
=> true # generic equality
irb> 1 === 1.0
=> true # case equality
irb> 1.eql? 1.0
irb> 1.equal? 1.0
=> false # object identity
irb> 'a'.equal? 'a'
==, ===, eql?, equal?
=> false # alias of == except Numeric
=> false # gotcha?
irb> 1 == 1.0
=> true # generic equality
irb> 1 === 1.0
=> true # case equality
irb> 1.eql? 1.0
irb> 1.equal? 1.0
=> false # object identity
irb> 'a'.equal? 'a'
==, ===, eql?, equal?
=> false # alias of == except Numeric
=> false # gotcha?
irb> 1 == 1.0
=> true # generic equality
irb> 1 === 1.0
=> true # case equality
irb> 1.eql? 1.0
irb> 1.equal? 1.0
=> false # object identity
irb> 'a'.equal? 'a'
irb> 1.equal? 1
==, ===, eql?, equal?
=> false # alias of == except Numeric
=> false # gotcha?
irb> 1 == 1.0
=> true # generic equality
irb> 1 === 1.0
=> true # case equality
irb> 1.eql? 1.0
irb> 1.equal? 1.0
=> false # object identity
irb> 'a'.equal? 'a'
=> true # gotcha?
irb> 1.equal? 1
Object Ids & Fixnum
Object Ids & Fixnum
Fixnum * 2 + 1
irb> 23 * 2 + 1
=> 47
irb > 23.object_id
=> 47
Object Ids & Fixnum
Fixnum * 2 + 1
irb> 23 * 2 + 1
=> 47
irb > 23.object_id
=> 47
irb> (2**62 - 1).class
=> Fixnum
irb> (2**62).class
=> Bignum
http://www.flickr.com/photos/miscdebris/6748016253/sizes/o/
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!"
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!"
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!"
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
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
So! So you think you can tell…
Heaven from Hell
- Pink Floyd
So! So you think you can tell…
Protected from Private
Private methods
class Soldier
private
def ryan
puts "Saving private ryan"
end
end
class Movie < Soldier
def name
ryan
end
end
Private methods
class Soldier
private
def ryan
puts "Saving private ryan"
end
end
class Movie < Soldier
def name
ryan
end
end
Private methods
class Soldier
private
def ryan
puts "Saving private ryan"
end
end
class Movie < Soldier
def name
ryan
end
end
Private Methods are
inherited!
class Base!
include Mongoid::Document!
end
The elusive include
class Base!
include Mongoid::Document!
end
The elusive include
Private method!
Instance method !
Defined the class Module
class Base!
include Mongoid::Document!
end
The elusive include
Protected methods
Protected methods
Protected methods
• Work with objects not classes.
Protected methods
• Work with objects not classes.
• Invoke a protected method on
another object in the same lineage
Protected methods
• Work with objects not classes.
• Invoke a protected method on
another object in the same lineage
What the …
class Autobot
def initialize(nick); @nick = nick; end
!
protected
attr_accessor :nick
end
!
prime = Autobot.new("Optimus Prime")
p prime.nick
class Autobot
def initialize(nick); @nick = nick; end
!
protected
attr_accessor :nick
end
!
prime = Autobot.new("Optimus Prime")
p prime.nick
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)
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
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
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"
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"
Keywords in Ruby?
Keywords - hmm…
class Serious
def true
false
end
def false
true
end
end
die = Serious.new
p "seriously!" if die.false
Keywords - hmm…
class Serious
def true
false
end
def false
true
end
end
die = Serious.new
p "seriously!" if die.false
Keywords - hmm…
class Serious
def true
false
end
def false
true
end
end
die = Serious.new
p "seriously!" if die.false
stack too deep?
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")
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")
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")
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)
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")
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")
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")
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
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
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
Module mixins are funny
class Tinyman!
include Superman!
include Batman!
include Ironman!
end!
!
Tinyman.new.fly
"Iroman: That's how you fly!"
Module mixins are funny
class Tinyman!
include Superman!
include Batman!
include Ironman!
end!
!
Tinyman.new.fly
"Iroman: That's how you fly!"
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
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
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!"
Dynamic Inheritance!
class Tinyman!
include Superman!
include Batman!
include Ironman!
end
Dynamic Inheritance!
class Tinyman!
include Superman!
include Batman!
include Ironman!
end
class Tinyman!
include Superman!
include Ironman!
include Batman!
end
Dynamic Inheritance!
class Tinyman!
include Superman!
include Batman!
include Ironman!
end
class Tinyman!
include Superman!
include Ironman!
include Batman!
end
Dynamic Inheritance!
class Tinyman!
include Superman!
include Batman!
include Ironman!
end
Cherry pick from Modules
module Megatron!
def power!
p "Megatron's super strength"!
end!
!
def evil!
p 'Evil genius'!
end!
end
Cherry pick from Modules
module Megatron!
def power!
p "Megatron's super strength"!
end!
!
def evil!
p 'Evil genius'!
end!
end
class Hanuman!
include Megatron!
end
Hanuman.new.power!
# => "Megatron's super strength"!
Hanuman.new.evil !
# => "Evil genius" # Oh no!
Cherry pick from Modules
class Hanuman!
include Megatron!
end
Hanuman.new.power!
# => "Megatron's super strength"!
Hanuman.new.evil !
# => "Evil genius" # Oh no!
Cherry pick from Modules
Cherry pick from Modules
class Hanuman!
def power!
Megatron.instance_method(:power).!
bind(self).call!
end!
end
Cherry pick from Modules
class Hanuman!
def power!
Megatron.instance_method(:power).!
bind(self).call!
end!
end
Cherry pick from Modules
class Hanuman!
def power!
Megatron.instance_method(:power).!
bind(self).call!
end!
end
Hanuman.new.power
# => "Megatron's super strength"
Hanuman.new.evil
# => undefined method `evil’...>
That’s all Folks!
@gautamrege
@joshsoftware
That’s all Folks!
@gautamrege
@joshsoftware
since 2007

RedDot Ruby Conf 2014 - Dark side of ruby