What's new in Ruby 2.0

Preview:

Citation preview

What’s new in Ruby 2.0?Tikkl Tech Talk

Mar 08, 2014By Kartik Sahoo

TopicsWhat’s new in Ruby 1.9

BasicObject: A new Root

Insertion-ordered Hash

Block Params are now Local

Splat in middle of Arguments

Default Parameters

New Proc literal & Named groups

Fiber: Lighter than Threads

Topics continues...What’s new in Ruby 2.0

Keyword Argument

Module#prepend

Lazy Enumerators

Module#refine

“__dir__”, “to_h” and “%i”

Default UTF-8 Encoding

What’s new in Ruby 1.9

BasicObject: A new rootParent of all classes.

For creating object hierarchy independent of Ruby’s object hierarchy

class Car # bodyend

# Ruby 1.8 Car.ancestors=> [Car, Object, Kernel]

# Ruby 1.9 Car.ancestors=> [Car, Object, Kernel, BasicObject]

# Ruby 1.9BasicObject.instance_methods=> [:==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]

{Hash}Elements are kept in the order they were inserted

# Ruby 1.8{:name => 'Gomez', :age => 34, :gender => 'male'} => {:age=>34, :gender=>"male", :name=>"Gomez"}

# Ruby 1.9{:name => 'Gomez', :age => 34, :gender => 'male'} => {:name=>"Gomez", :age=>34, :gender=>"male"}

Alternative syntax for Symbol as Hash key

# Ruby 1.9{name: 'Gomez', age: 34, gender: 'male'} => {:name=>"Gomez", :age=>34, :gender=>"male"}

SHORT

Block ParamsBlock params are now LOCAL

# Ruby 1.8foo, bar = 10, 20!2.times do |foo| bar = bar + 1 foo = bar + 2end!foo => 24bar => 22

# Ruby 1.9foo, bar = 10, 20!2.times do |foo| bar = bar + 1 foo = bar + 2end!foo => 10bar => 22

Splat in middle of args..Splats can now be placed anywhere in method definition

Adds Flexibility

# Ruby 1.9def report(name, *marks, age = 22) [name, marks, age]end!report(‘Mark’, 50, 60, 70, 18)

# Ruby 1.8def report(name, age, *marks) [name, marks, age]end!report(‘Mark’, 18, 50, 60, 70)=> "["Mark", [50, 60, 70], 18]

Default ParametersAny parameter can have default value not only the trailing ones.

More flexible

# Ruby 1.9def tech_talk(about = ‘Ruby 2.0’, by = ‘Kartik’, on) “A Tech Talk about #{about}, by #{by} on #{on}”end!tech_talk(‘1st Mar, 2014’)=> “A Tech Talk about Ruby 2.0, by Kartik on 1st Mar, 2014”!tech_talk(‘Rails 4’, ‘12th Sept, 2013’)=> “A Tech Talk about Rails 4, by Kartik on 12th Sept, 2013

New Proc literal (->)Stored blocks

# Ruby 1.8greet = lambda do |name| puts “Hello #{name}!”end!greet.call(‘Everyone’)=> “Hello Everyone!”

# Ruby 1.9greet = -> (name) do puts “Hello #{name}!”end!greet.(‘Everyone’)=> “Hello Everyone!”

Adds Readability

‘lambda’ has a symbolic representation “->”

Proc continues...lambdas can now have default arguments

# Ruby 1.9greet = -> (time=‘Morning’, name) do puts “Good #{time}, #{name}!”end!greet[‘All’]=> “Good Morning, All!”!greet.yield(‘Evening’, ‘Sir’)=> “Good Evening, Sir!”

Named groupRegExp groups now have names

# Ruby 1.8“Good Morning, Everyone!”.match(/, (.*)!/)[1]=> “Everyone”!$1 => “Everyone”

# Ruby 1.9“Good Morning, Everyone!”.match(/, (?<name>.*)!/)[:name]=> “Everyone”!result = “Good Morning, Everyone!”.match(/, (?<name>.*)!/)=> #<MatchData ", Everyone!" name:"Everyone">!result[:name] or result[1] or $1=> “Everyone”

Fiber: Lighter than ThreadLight-weight processes: Memory footprint is only 4KB.

Code blocks that can be paused and resumed, like threads.

Never preempted, scheduled by programmer not VM.

Fiber#resume to run.

Fiber: Example-1First call to Fiber#resume takes arguments

fiber = Fiber.new do |arg| puts “In a Fiber” Fiber.yield arg + 2 puts “After first yield” arg = arg + 2 Fiber.yield arg puts “After second yield” argend

fiber.resume 10“In a Fiber”=> 12!fiber.resume 20“After first yield”=> 12!fiber.resume“After second yield”=> 12!fiber.resume=> FiberError: dead fiber called

Fiber: Example-2Fiber#resume method takes arbitrary number of args

fiber = Fiber.new do |arg1, arg2| puts “In a Fiber” temp = arg1, arg2 Fiber.yield arg1 + 2 puts “After first yield” Fiber.yield temp puts “After second yield” Fiber.yieldend

fiber.resume 10, 20, 30“In a Fiber”=> 12!fiber.resume 20“After first yield”=> [10, 20]!fiber.resume“After second yield”=> nil!fiber.resume 1, 2, 3=> [1, 2, 3]

IGNORED

Returns the passed args, if no explicit value to return.

What’s new in Ruby 2.0

Keyword ArgumentsNew syntax for defining method parameters

Syntax sugar, helps create simpler APIs

Flexible, easy to read, write & more descriptive

def tech_talk(about: ‘Ruby 2.0’, by: ‘Kartik’, at: ‘RubyConf-14’) “A Tech Talk about #{about} at #{at}, by #{by}”end!tech_talk at: ‘Tikkl India office”=> “A Tech Talk about Ruby 2.0 at Tikkl India office, by Kartik!tech_talk about: ‘Rails 4.0’, by: ‘Mano’=> “A Tech Talk about Rails 4.0 at RubyConf-14, by Mano”

… Keyword Arguments

Poor readability

Arguments should be in order from left to right

# Alternative-1def tech_talk(about = ‘Ruby 2.0’, by = ‘Kartik’, at = ‘RubyConf-14’) “A Tech Talk about #{about} at #{at}, by #{by}”end!tech_talk ‘Tikkl India office”=> “A Tech Talk about Tikkl India office at RubyConf-14, by Kartik!tech_talk ‘Rails 4.0’, ‘Mano’=> “A Tech Talk about Rails 4.0 at RubyConf-14, by Mano”

… Keyword Arguments# Alternative-2def tech_talk(opts = {}) defaults = { about: ‘Ruby 2.0’, by: ‘Kartik’, at: ‘RubyConf-14’ } opts = defaults.merge(opts) “A Tech Talk about #{opts[:about]} at #{opts[:at]}, by #{opts[:by]}”end!tech_talk at: ‘Tikkl India office”=> “A Tech Talk about Ruby 2.0 at Tikkl India office, by Kartik!tech_talk about: ‘Rails 4.0’, by: ‘Mano’=> “A Tech Talk about Rails 4.0 at RubyConf-14, by Mano”

More coding

Method signature doesn’t say much about its args

Module#prependOpposite of Module#include

Inserts module in-front of a class it was prepended to

# Ancestor Chainclass Carend!Car.ancestors=> [Car, Object, Kernel, BasicObject]

Method call in Ruby traverses its ancestor chain until finds a match.

Module#prepend ...# Module#includemodule Afterend!class Car include Afterend!Car.ancestors=> [Car, After, Object, Kernel, BasicObject]

# Module#prependmodule Beforeend!class Car prepend Beforeend!Car.ancestors=> [Before, Car, Object, Kernel, BasicObject]

VS

Lazy EnumeratorsLets us handle an array i.e. either huge or infinite.

Ruby <= 2.0range = 1..Float::INFINITYrange.collect { |x| x*x }.first(5)!

Endless loop

Range firstcollect ArrayArray

Endless Loop Never Executed

each each

… Lazy Enumerators

The right side of Enumeration chain actually controls the execution flow.

Ruby 2.0range = 1..Float::INFINITYrange.lazy.collect { |x| x*x }.first(5)!=> [1, 4, 9, 16, 25]

Enumerator::Lazy!

collect method ArrayEnumerable#firstRange

my block

each

yields

yields

Module#refineRuby classes are open. Redefinition and adding new functionalities are possible.

Scope of these changes are global.

class String def length self.reverse end end!‘Monkey Patching’.length=> “gnihctaP yeknoM”

… Module#refineRefinements: To reduce the impact of monkey patching on other users.

module StringExtensions refine String do def greet “#{self} says: Hello!” end end end!=>#<refinement:String@StringExtensions>

class Test using StringExtensions! def say puts ‘Williams’.greet end end!Test.new.say=> “Williams says: Hello!”!‘Williams’.greet=> NoMethodError: undefined method ‘greet’ for String

Literal Symbol Creation (%i)Returns array of symbols

%i {what’s new in ruby 2.0}!=> [:"what's", :new, :in, :ruby, :"2.0"]

“__dir__” returns the directory name of the file currently being executed.

File.dirname(__FILE___) usages can be replaced with __dir__

__dir__

“to_h” methodNew convention to retrieve hash representation of an object.

Student = Struct.new(:name, :age, :class) do def info #… end end! Student.new(‘Gomez’, 34, 2).to_h => {:name=>"Gomez", :age=>34, :year=>2}

Default Encoding (UTF-8)In Ruby 1.9.X, default encoding was US-ASCII (7 bits)

To specify different encoding, magic comments were used.

!# encoding: UTF-8 OR# coding: UTF-8 OR#blah blah coding: US-ASCII

… Why UTF-8 ?It’s possible to represent the characters of every encoding in UTF-8.

!“Olé!”.encode("UTF-8") => “Olé!” !“Olé!".encode("US-ASCII") => Encoding::UndefinedConversionError

Thank You