what's new in ruby 2.0
TRANSCRIPT
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