The Dark Side of Ruby

http://www.flickr.com/photos/sashapo/2722924752/sizes/l/
The Dark Side of Ruby

@gautamrege!
@joshsoftware

http://www.flickr.com/photos/sashapo/2722924752/sizes/l/

since 2007
What’s the talk about?
•

Nothing scary

•

Weirdness and Gotcha’s

Ah-ha! Moments
Slides are Tagged

Beginner

Expert
(In)Famous Infinity
http://www.flickr.com/photos/emdot/482622478/sizes/l/
(In)famous Infinity
$ irb> 1/0
=> ZeroDivisionError: divided by 0
$ irb> 1.0/0
=> Infinity
$ irb> Infinity
=> NameError: uninitialized constant
Infinity
Base Jumping

http://www.flickr.com/photos/shahdi/8035647153/sizes/l/
Base Conversions
$ irb> 12345.to_s(8)
=> "30071"
# => Octal
$ irb> 12345.to_s(36)
=> "9ix"
# That is an actual number
$ irb> 1234.to_s(64)
=> ArgumentError: invalid radix 64
The Star - *
Splat Expander
Job = Struct.new(:name, :occupation)
tom = Job.new("Tom", "Developer")
name, occupation = *tom
=> ["Tom", "Developer"]
=> name
# "Tom"
=> occupation
# "Developer"
Splat Expander
Job = Struct.new(:name, :occupation)
tom = Job.new(occupation: "Developer",
name: "Tom")
name, occupation = *tom
=> name # {:occupation=>"Developer", :name=>
"Tom"}
=> occupation
# nil
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
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
call is implied for a stabby
proc or a Proc
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

Proc#=== is an alias to Proc#call.
Proc.new { |p| !
p.modulo(3).zero?!
}.call(9)
Override the === method
to customise case
evaluation.
==, ===, eql?, equal?

http://www.flickr.com/photos/gak/2418146934/sizes/o/
==, ===, eql?, equal?
irb> 1 == 1.0
=> true # generic equality
irb> 1 === 1.0
=> true # case equality
irb> 1.eql? 1.0
=> false # equality by value
irb> 1.equal? 1.0
=> false # object identity
irb> 'a'.equal? 'a'
=> false # gotcha!
Proc#curry
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!"
The curry recipe
pull = jackpot.curry[rand(5)]
=> #<Proc:0x007f9eec0990b0 (lambda)>
•

Return lambda till all parameters are passed.

•

Evaluate the block if all parameters are passed.

2.times { pull = pull.curry[rand(5)] }
=> true # or false
So! So you think you can tell…

Protected from Private
Private methods
class Base
private
def foo
puts "inside foo"
end
Private Methods are
end
inherited!
class Child < Base
def bar
foo
end
end
The elusive include
class Base!
include Mongoid::Document!
end

Private method!
Instance method !
Defined the class Module
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

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
!

prime = Autobot.new("Optimus Prime")
megatron = Autobot.new('Megatron')
!

prime.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
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
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!
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

GCRC 2014 - The Dark Side of Ruby

  • 1.
    The Dark Sideof Ruby http://www.flickr.com/photos/sashapo/2722924752/sizes/l/
  • 2.
    The Dark Sideof Ruby @gautamrege! @joshsoftware http://www.flickr.com/photos/sashapo/2722924752/sizes/l/ since 2007
  • 3.
    What’s the talkabout? • Nothing scary • Weirdness and Gotcha’s Ah-ha! Moments
  • 4.
  • 5.
  • 6.
    (In)famous Infinity $ irb>1/0 => ZeroDivisionError: divided by 0 $ irb> 1.0/0 => Infinity $ irb> Infinity => NameError: uninitialized constant Infinity
  • 7.
  • 8.
    Base Conversions $ irb>12345.to_s(8) => "30071" # => Octal $ irb> 12345.to_s(36) => "9ix" # That is an actual number $ irb> 1234.to_s(64) => ArgumentError: invalid radix 64
  • 9.
  • 10.
    Splat Expander Job =Struct.new(:name, :occupation) tom = Job.new("Tom", "Developer") name, occupation = *tom => ["Tom", "Developer"] => name # "Tom" => occupation # "Developer"
  • 11.
    Splat Expander Job =Struct.new(:name, :occupation) tom = Job.new(occupation: "Developer", name: "Tom") name, occupation = *tom => name # {:occupation=>"Developer", :name=> "Tom"} => occupation # nil
  • 12.
    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"
  • 13.
    Calling out toStabby 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 call is implied for a stabby proc or a Proc
  • 14.
    The Case Statement defmultiple_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
  • 15.
    Behind every caseis a === number = 9! case number ! when multiple_of(3) Proc.new {|p| p.modulo(3).zero?} === 9 Proc#=== is an alias to Proc#call. Proc.new { |p| ! p.modulo(3).zero?! }.call(9)
  • 16.
    Override the ===method to customise case evaluation.
  • 17.
    ==, ===, eql?,equal? http://www.flickr.com/photos/gak/2418146934/sizes/o/
  • 18.
    ==, ===, eql?,equal? irb> 1 == 1.0 => true # generic equality irb> 1 === 1.0 => true # case equality irb> 1.eql? 1.0 => false # equality by value irb> 1.equal? 1.0 => false # object identity irb> 'a'.equal? 'a' => false # gotcha!
  • 19.
  • 20.
    3 Pulls forthe 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!"
  • 21.
    The curry recipe pull= jackpot.curry[rand(5)] => #<Proc:0x007f9eec0990b0 (lambda)> • Return lambda till all parameters are passed. • Evaluate the block if all parameters are passed. 2.times { pull = pull.curry[rand(5)] } => true # or false
  • 22.
    So! So youthink you can tell… Protected from Private
  • 23.
    Private methods class Base private deffoo puts "inside foo" end Private Methods are end inherited! class Child < Base def bar foo end end
  • 24.
    The elusive include classBase! include Mongoid::Document! end Private method! Instance method ! Defined the class Module
  • 25.
    Protected methods • Work withobjects not classes. • Invoke a protected method on another object in the same lineage What the …
  • 26.
    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)
  • 27.
    class Autobot def fights(target) p"I am #{self.nick}" p "Kicking #{target.nick}'s ass" end protected attr_accessor :nick end ! prime = Autobot.new("Optimus Prime") megatron = Autobot.new('Megatron') ! prime.fights megatron "I am Optimus Prime" "Kicking Megatron's ass"
  • 28.
  • 29.
    Keywords - hmm… classSerious def true false end def false true end end die = Serious.new p "seriously!" if die.false
  • 30.
    Cherry pick fromModules module Megatron! def power! p "Megatron's super strength"! end! ! def evil! p 'Evil genius'! end! end
  • 31.
    Cherry pick fromModules class Hanuman! include Megatron! end Hanuman.new.power! # => "Megatron's super strength"! Hanuman.new.evil ! # => "Evil genius" # Oh no!
  • 32.
    Cherry pick fromModules 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’...>
  • 33.