Ruby 2
some new things

 David A. Black
  Lead Developer
  Cyrus Innovation
  @david_a_black

 Ruby Blind meetup
   April 10, 2013
About me
• Rubyist since 2000 (Pickaxe baby)
• Lead Developer, Cyrus Innovation
• Developer, author, trainer, speaker, event
  organizer
• Author of The Well-Grounded Rubyist
• Co-founder of Ruby Central
• Chief author of scanf.rb (standard library)
Today's topics
• Lazy enumerators
• Module#prepend
• String#bytes and friends
• Keyword arguments
• Miscellaneous changes and new features
Lazy enumerators
What's wrong with this code?
# find the first 10 multiples of 3

(0..Float::INFINITY).select {|x| x % 3 == 0 }.first(10)
Lazy enumerators
# find the first 10 multiples of 3

(0..Float::INFINITY).select {|x| x % 3 == 0 }.first(10)



It runs forever!
Lazy enumerators

# find the first 10 multiples of 3

(0..Float::INFINITY).lazy.select {|x| x % 3 == 0 }.first(10)
Lazy enumerators

# find the first 10 multiples of 3

(0..Float::INFINITY).lazy.select {|x| x % 3 == 0 }.first(10)

=> [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
Lazy enumerators
r = 0..Float::INFINITY
s = 0..Float::INFINITY

r.zip(s).first(5)   # runs forever
Lazy enumerators
r = 0..Float::INFINITY
s = 0..Float::INFINITY

r.lazy.zip(s).first(5)

=> [[0, 0], [1, 1], [2, 2], [3, 3], [4, 4]]
Lazy enumerators
# From Ruby source documentation

fib = Enumerator.new do |y|
  a = b = 1
  loop do
    y << a
    a, b = b, a + b
  end
end

fib.zip(0..Float::INFINITY).first(5)   # runs forever
Lazy enumerators

fib = Enumerator.new do |y|
  a = b = 1
  loop do
    y << a
    a, b = b, a + b
  end
end.lazy

fib.zip(0..Float::INFINITY).first(5)

# => [[1, 0], [1, 1], [2, 2], [3, 3], [5, 4]]
Lazy enumerators
• can be created via #lazy on an Enumerable
 • [1,2,3].lazy
 • (0..Float::INFINITY).lazy
 • an_enumerator.lazy (see Fibonacci
   example)
Module#prepend
What will the output be?
    class Person
      def talk
        puts "Hello"
      end
    end

    module Yeller
      def talk
        super
        puts "I said... HELLLLLOOO!!!!"
      end
    end

    class Person
      include Yeller
    end

    david = Person.new
    david.talk
Module#prepend
class Person
  def talk
    puts "Hello"
  end
end

module Yeller
  def talk
    super
    puts "I said... HELLLLLOOO!!!!"
  end
end

class Person
  include Yeller
end

david = Person.new
david.talk

# => Hello
p Person.ancestors

# => [Person, Yeller, Object, Kernel, BasicObject]
Module#prepend
What will the output be?
    class Person
      def talk
        puts "Hello"
      end
    end

    module Yeller
      def talk
        super
        puts "I said... HELLLLLOOO!!!!"
      end
    end

    class Person
      prepend Yeller
    end

    david = Person.new
    david.talk
Module#prepend
class Person
  def talk
    puts "Hello"
  end
end

module Yeller
  def talk
    super
    puts "I said... HELLLLLOOO!!!!"
  end
end

class Person
  prepend Yeller
end

david = Person.new
david.talk

# => Hello
     I said... HELLLLLOOO!!!!
p Person.ancestors

# => [Yeller, Person, Object, Kernel, BasicObject]
Module#prepend
• Puts the module *before* the receiver
(class or module) in the method lookup
path
• A good way to avoid messing with alias
     class Person
       def talk
         puts "Hello!"
       end
     end

     class Person
       alias old_talk talk
       def talk
         old_talk
         puts "I said... HELLLLLOOO!!!!"
       end
     end
String#bytes/each_byte
         (and friends)
• String#bytes, #lines, #chars, #codepoints
  now return arrays
• #each_byte/line/char/codepoint still return
  enumerators
• Saves you having to do #to_a when you
  want an array
Keyword arguments
    def my_method(a, b, c: 3)
      p a, b, c
    end

    my_method(1, 2)            # 1 2 3
    my_method(1, 2, c: 4)      # 1 2 4




  Lets you specify a default value for a
  parameter, and use the parameter's name in
  your method call
Keyword arguments

def my_method(a, b, *array, c: 3)
  p a, b, array, c
end

my_method(1, 2, 3, 4, c: 5) # 1, 2, [3, 4], 5




      Non-keyword arguments still work
      essentially the same way that they did.
Keyword arguments

def my_method(a, b, *array, c: 3, **others)
  p a, b, array, c, others
end

my_method(1, 2, 3, 4, c: 5, d: 6, e: 7)
  # 1, 2, [3, 4], 5, {:d=>6, :e=>7}



     Extra keyword arguments get passed
     along in the **others parameter.
Keyword arguments

  def my_method(a, b, c)
    p a, b, c
  end

  my_method(1, 2, z: 3)    # 1 2 {:z=>3}



   Hash-like arguments that don't
   correspond to a named argument get
   passed along as a hash.
Keyword arguments
Order doesn't matter:
  class Person
    attr_accessor :name, :email, :age

    def initialize(name: "", email: "", age: 0)
      self.name = name
      self.email = email
      self.age = age
    end
  end

  david = Person.new(email: "dblack@rubypal.com",
                     name: "David",
                     age: Float::INFINITY)
Miscellaneous
•   %i{} and %I{}
•   Default encoding now UTF-8 (no need for magic
    comment)
•   Struct#to_h, nil#to_h, Hash#to_h
•   Kernel#Hash (like Array, Integer, Float)
•   const_get now parses nested constants
    •   Object.const_get("A::B::C")
•   #inspect doesn't call #to_s any more
• Questions?
• Comments?


 David A. Black
  Lead Developer
  Cyrus Innovation
  @david_a_black

  Ruby Blind meetup
    April 10, 2013

Ruby 2: some new things

  • 1.
    Ruby 2 some newthings David A. Black Lead Developer Cyrus Innovation @david_a_black Ruby Blind meetup April 10, 2013
  • 2.
    About me • Rubyistsince 2000 (Pickaxe baby) • Lead Developer, Cyrus Innovation • Developer, author, trainer, speaker, event organizer • Author of The Well-Grounded Rubyist • Co-founder of Ruby Central • Chief author of scanf.rb (standard library)
  • 3.
    Today's topics • Lazyenumerators • Module#prepend • String#bytes and friends • Keyword arguments • Miscellaneous changes and new features
  • 4.
    Lazy enumerators What's wrongwith this code? # find the first 10 multiples of 3 (0..Float::INFINITY).select {|x| x % 3 == 0 }.first(10)
  • 5.
    Lazy enumerators # findthe first 10 multiples of 3 (0..Float::INFINITY).select {|x| x % 3 == 0 }.first(10) It runs forever!
  • 6.
    Lazy enumerators # findthe first 10 multiples of 3 (0..Float::INFINITY).lazy.select {|x| x % 3 == 0 }.first(10)
  • 7.
    Lazy enumerators # findthe first 10 multiples of 3 (0..Float::INFINITY).lazy.select {|x| x % 3 == 0 }.first(10) => [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]
  • 8.
    Lazy enumerators r =0..Float::INFINITY s = 0..Float::INFINITY r.zip(s).first(5) # runs forever
  • 9.
    Lazy enumerators r =0..Float::INFINITY s = 0..Float::INFINITY r.lazy.zip(s).first(5) => [[0, 0], [1, 1], [2, 2], [3, 3], [4, 4]]
  • 10.
    Lazy enumerators # FromRuby source documentation fib = Enumerator.new do |y| a = b = 1 loop do y << a a, b = b, a + b end end fib.zip(0..Float::INFINITY).first(5) # runs forever
  • 11.
    Lazy enumerators fib =Enumerator.new do |y| a = b = 1 loop do y << a a, b = b, a + b end end.lazy fib.zip(0..Float::INFINITY).first(5) # => [[1, 0], [1, 1], [2, 2], [3, 3], [5, 4]]
  • 12.
    Lazy enumerators • canbe created via #lazy on an Enumerable • [1,2,3].lazy • (0..Float::INFINITY).lazy • an_enumerator.lazy (see Fibonacci example)
  • 13.
    Module#prepend What will theoutput be? class Person def talk puts "Hello" end end module Yeller def talk super puts "I said... HELLLLLOOO!!!!" end end class Person include Yeller end david = Person.new david.talk
  • 14.
    Module#prepend class Person def talk puts "Hello" end end module Yeller def talk super puts "I said... HELLLLLOOO!!!!" end end class Person include Yeller end david = Person.new david.talk # => Hello
  • 15.
    p Person.ancestors # =>[Person, Yeller, Object, Kernel, BasicObject]
  • 16.
    Module#prepend What will theoutput be? class Person def talk puts "Hello" end end module Yeller def talk super puts "I said... HELLLLLOOO!!!!" end end class Person prepend Yeller end david = Person.new david.talk
  • 17.
    Module#prepend class Person def talk puts "Hello" end end module Yeller def talk super puts "I said... HELLLLLOOO!!!!" end end class Person prepend Yeller end david = Person.new david.talk # => Hello I said... HELLLLLOOO!!!!
  • 18.
    p Person.ancestors # =>[Yeller, Person, Object, Kernel, BasicObject]
  • 19.
    Module#prepend • Puts themodule *before* the receiver (class or module) in the method lookup path • A good way to avoid messing with alias class Person def talk puts "Hello!" end end class Person alias old_talk talk def talk old_talk puts "I said... HELLLLLOOO!!!!" end end
  • 20.
    String#bytes/each_byte (and friends) • String#bytes, #lines, #chars, #codepoints now return arrays • #each_byte/line/char/codepoint still return enumerators • Saves you having to do #to_a when you want an array
  • 21.
    Keyword arguments def my_method(a, b, c: 3) p a, b, c end my_method(1, 2) # 1 2 3 my_method(1, 2, c: 4) # 1 2 4 Lets you specify a default value for a parameter, and use the parameter's name in your method call
  • 22.
    Keyword arguments def my_method(a,b, *array, c: 3) p a, b, array, c end my_method(1, 2, 3, 4, c: 5) # 1, 2, [3, 4], 5 Non-keyword arguments still work essentially the same way that they did.
  • 23.
    Keyword arguments def my_method(a,b, *array, c: 3, **others) p a, b, array, c, others end my_method(1, 2, 3, 4, c: 5, d: 6, e: 7) # 1, 2, [3, 4], 5, {:d=>6, :e=>7} Extra keyword arguments get passed along in the **others parameter.
  • 24.
    Keyword arguments def my_method(a, b, c) p a, b, c end my_method(1, 2, z: 3) # 1 2 {:z=>3} Hash-like arguments that don't correspond to a named argument get passed along as a hash.
  • 25.
    Keyword arguments Order doesn'tmatter: class Person attr_accessor :name, :email, :age def initialize(name: "", email: "", age: 0) self.name = name self.email = email self.age = age end end david = Person.new(email: "dblack@rubypal.com", name: "David", age: Float::INFINITY)
  • 26.
    Miscellaneous • %i{} and %I{} • Default encoding now UTF-8 (no need for magic comment) • Struct#to_h, nil#to_h, Hash#to_h • Kernel#Hash (like Array, Integer, Float) • const_get now parses nested constants • Object.const_get("A::B::C") • #inspect doesn't call #to_s any more
  • 27.
    • Questions? • Comments? David A. Black Lead Developer Cyrus Innovation @david_a_black Ruby Blind meetup April 10, 2013