Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What's new in ruby Since 2.0.0

What's new in ruby Since 2.0.0

A short overview of new and changed things in Ruby since 2.0.0 given at the October 2014 Ruby Ireland meetup.

Source: https://github.com/chrismcg/presentations/blob/master/whats_new_in_ruby_since_200/whats_new_in_ruby_since_200.md

Best viewed with Deckset App

Chris McGrath

October 22, 2014
Tweet

More Decks by Chris McGrath

Other Decks in Technology

Transcript

  1. What's'new'in'Ruby'since'2.0.0
    Chris&McGrath
    @chrismcg
    1

    View Slide

  2. Speed
    2

    View Slide

  3. Garbage'Collector
    3

    View Slide

  4. Mark%and%Sweep%in%Ruby%1.8
    • Stop&everything&Ruby&is&doing
    • Go&through&and&mark&all&objects&that&have&a&reference&to&them
    • Sweep&all&the&objects&that&aren’t&marked
    4

    View Slide

  5. 1.8
    (Images(from(Aman(Gupta's(blog)
    5

    View Slide

  6. 1.9.3
    Ruby%1.9.3%made%the%sweep%phase%"lazy"%so%the%pause%is%just%the%
    mark%phase
    (Images(from(Aman(Gupta's(blog)
    6

    View Slide

  7. Ruby%2.0
    Copy%On%Write
    (Images(from(Aman(Gupta's(blog)
    7

    View Slide

  8. Ruby%2.1
    Genera&onal)GC
    (Images(from(Aman(Gupta's(blog)
    8

    View Slide

  9. Ruby%2.2
    Symbols
    Incremental*GC
    9

    View Slide

  10. GC#Tuning
    10

    View Slide

  11. Refinements
    • Extend(classes((monkeypatch)(locally(instead(of(globally
    • Introduced(as(experimental(in(2.0
    • Reduced(in(scope(and(complexity(since([email protected](idea
    • Not(experimental(in(2.1
    11

    View Slide

  12. Refinements
    module Stats
    refine Array do
    def mean
    inject(0) { |sum, x| sum + x } / size
    end
    end
    end
    12

    View Slide

  13. Refinements
    a1 = [1, 2, 3, 4]
    a1.mean rescue "no mean method" # => "no mean method"
    using Stats
    a2 = [2, 4, 6, 8]
    a2.mean # => 5
    a1.mean # => 2
    13

    View Slide

  14. Refinements
    class Analyzer
    using Stats
    def initialize(array)
    @array = array
    end
    def summary
    { mean: @array.mean }
    end
    end
    14

    View Slide

  15. Refinements
    a1 = [1, 2, 3, 4]
    analyzer = Analyzer.new(a1)
    a1.mean rescue "no mean method" # => "no mean method"
    analyzer.summary # => {:mean=>2}
    15

    View Slide

  16. Refinements()(Lexically(scoped
    • using"to"end"of"file
    • using"to"end"of"module
    • using"to"end"of"string"being"evaled
    • Don't"apply"when"re:opening"classes
    16

    View Slide

  17. Refinements
    class Analyzer
    def short_summary
    { m: @array.mean }
    end
    end
    a1 = [1, 2, 3, 4]
    analyzer = Analyzer.new(a1)
    analyzer.summary # => {:mean=>2}
    analyzer.short_summary rescue "no mean method" # => "no mean method"
    17

    View Slide

  18. Refinements
    • Seem%like%a%great%fit%for%gem%authors
    • Not%in%JRuby%yet%(but%coming)
    • Not%in%Rubinius
    • What%should%something%like%Ac?veSupport%do?
    • Haven't%seen%any%benchmarks%yet%(but%not%expec?ng%them%to%be%
    slow)
    18

    View Slide

  19. Keyword(Arguments
    • Introduced+in+Ruby+2.0
    • Improved+in+2.1
    • Backwards+compa• [email protected]+error+messages+for+missing+/+wrong+arguments
    19

    View Slide

  20. "Fake"&Keyword&Arguments&in&Ruby&1.8/1.9
    def render(content, opts = {})
    width = opts[:width]
    height = opts[:height]
    ...
    end
    render "* foo"
    20

    View Slide

  21. Need$some$defaults
    def render(content, opts = {})
    width = opts[:width] || 1920
    height = opts[:height] || 1080
    ...
    end
    render "* foo"
    21

    View Slide

  22. :full%means%use%width%or%height%of%page
    def render(content, opts = {})
    width = opts.fetch(:width) { 1920 }
    width = @page.width if width == :full
    height = opts.fetch(:height) { 1080 }
    height = @page.height if height == :full
    ...
    end
    render "* foo", :width => :full
    render "* bar", :hieght => 786 # doesn't pick up on typo
    22

    View Slide

  23. With%Ruby%2.x%keyword%arguments
    def render(content, width: 1920, height: 1080)
    width = @page.width if width == :full
    height = @page.height if height == :full
    ...
    end
    render "* foo"
    render "* bar", hieght: 786 # =>
    # ~> -:7:in `': unknown keyword: hieght (ArgumentError)
    23

    View Slide

  24. If#the#user#must#specify#width
    def render(content, width:, height: 1080)
    width = @page.width if width == :full
    height = @page.height if height == :full
    end
    render "* foo"
    # ~> -:6:in `': missing keyword: width (ArgumentError)
    24

    View Slide

  25. Benefits
    • Be$er&errors&and&programmer&doesn't&have&to&manually&check&
    arguments
    • Easier&to&add&named&arguments&to&those&methods&you&pass&four&
    numbers&into
    • Named&arguments&mean&you&can&change&argument&posi=on&
    without&needing&to&refactor
    • Named&arguments&make&it&clear&where&method&call&is&what&the&
    arguments&are
    25

    View Slide

  26. Drawbacks
    • More&typing&if&you're&making&lots&of&calls&with&named&arguments
    • ...
    (Check'out'RubyTapas'episodes'186'and'187'to'learn'how'to'
    handle'extra'arguments'with'the'**'operator'and'just'how'flexible'
    they'are.)
    26

    View Slide

  27. Module#prepend+(❤)
    • include"puts"module"a-er"current"class"in"method"lookup"
    chain
    • prepend"puts"it"before
    • Removes"need"for"alias_method_chain,"breaking"super"etc.
    27

    View Slide

  28. Module#include+/+prepend
    module Stats
    def mean
    puts "Stats#mean"
    super rescue puts "Stats#mean no superclass mean method"
    end
    end
    28

    View Slide

  29. Module#include+/+prepend
    class Analyzer
    include Stats
    def mean
    puts "Analyzer#mean"
    super
    end
    end
    Analyzer.ancestors # => [Analyzer, Stats, Object, Kernel, BasicObject]
    Analyzer.new.mean # => nil
    # >> Analyzer#mean
    # >> Stats#mean
    # >> Stats#mean no superclass mean method
    29

    View Slide

  30. Module#include+/+prepend
    class Analyzer2
    prepend Stats
    def mean
    puts "Analyzer2#mean"
    super rescue puts "Analyzer2#mean no superclass mean method"
    end
    end
    Analyzer2.ancestors # => [Stats, Analyzer2, Object, Kernel, BasicObject]
    Analyzer2.new.mean # => nil
    # >> Stats#mean
    # >> Analyzer2#mean
    # >> Analyzer2#mean no superclass mean method
    30

    View Slide

  31. Cache&decorator
    class Analyzer
    def expensive_method
    puts "thinking really hard!"
    # do lots of calculations
    42
    end
    end
    31

    View Slide

  32. Cache&decorator
    module AnalyzerCacher
    def expensive_method
    @expensive_method_result ||= super
    end
    end
    class Analyzer
    prepend AnalyzerCacher
    end
    32

    View Slide

  33. Cache&decorator
    a = Analyzer.new
    a.expensive_method # => 42
    # >> thinking really hard!
    a.expensive_method # => 42
    a.expensive_method # => 42
    (This&could&of&course&be&generalized&with&meta&programming)
    33

    View Slide

  34. Method'Cache
    • Pre%Ruby%2.1%any%change%to%any%class%would%clear%all%the%method%
    caches
    • Performance%hit,%especially%if%you're%doing%something%like%DCI
    • Post%Ruby%2.1%just%the%cache%for%the%class%and%it's%subclasses%is%
    changed
    • Can%use%Busted%tool%to%see%where%cache%is%busted%on%2.1+
    34

    View Slide

  35. Other&op)miza)ons
    • Kernel#require+op.mized+to+make+rails+loading+fast
    • Backtrace+genera.on+op.mized
    • Hash#shi<+performance+increased,+so+along+with+preserving+
    [email protected]+LRU+Cache+with+it
    35

    View Slide

  36. __dir__
    (instead)of)File.dirname(__FILE__))
    require __dir__ + '/foo'
    File.read(__dir__ + '/.config')
    (note&lower&case)
    36

    View Slide

  37. %i#and#%I
    Create&arrays&of&symbols
    [1] pry(main)> n = 10
    => 10
    [2] pry(main)> %i(foo bar#{n})
    => [:foo, :"bar\#{n}"]
    [3] pry(main)> %I(foo bar#{n})
    => [:foo, :bar10]
    37

    View Slide

  38. def$returns$method$name$as$symbol
    (Ruby&2.1+)
    method = def foo
    puts "bar"
    end
    method # => :foo
    38

    View Slide

  39. def$returns$method$name$as$symbol
    (Ruby&2.1+)
    Handy&for&metaprogramming&and&just&making&one&method&private
    private def foo
    #...
    end
    39

    View Slide

  40. Excep&on#cause-(2.1)
    class Downloader
    class DownloadException < StandardError; end
    def download!
    begin
    raise "boom!"
    rescue RuntimeError
    raise DownloadException
    end
    end
    end
    40

    View Slide

  41. Excep&on#cause-(2.1)
    begin
    Downloader.new.download!
    rescue => e
    e.to_s # => "Downloader::DownloadException"
    e.cause # => #
    end
    41

    View Slide

  42. Lazy%enumerators
    #lazy!can!be!called!on!any!enumerable.!Can!do!FP!style!stuff!like:
    [25] pry(main)> [1, 2, 3, 4].lazy.cycle.take(20)
    => #
    [26] pry(main)> [1, 2, 3, 4].lazy.cycle.take(20).to_a
    => [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
    42

    View Slide

  43. Lazy%enumerators
    Find%first%three%four%le0er%words%in%/usr/share/dict/words%
    without%loading%whole%file%into%memory:
    File.open('/usr/share/dict/words').lazy.
    map(&:chomp).
    select { |w| w.length == 4 }.
    take(3).
    force
    => ["Aani", "Aaru", "abac"]
    43

    View Slide

  44. Module.const_get
    Knows&about&namespaces&since&2.0
    module Foo
    class Bar
    end
    end
    Object.const_get("Foo::Bar") # => Foo::Bar
    44

    View Slide

  45. Kernel#itself+(2.2)
    [1, 2, 3, 4, 1, 5, 2, 3, 5, 6].group_by(&:itself)
    => {1=>[1, 1], 2=>[2, 2], 3=>[3, 3], 4=>[4], 5=>[5, 5], 6=>[6]}
    (This&is&my&favourite&new&method&name)
    45

    View Slide

  46. warn%accepts%mul.ple%arguments
    (warn&==&puts&for&stderr)
    pry(main)> warn "warning 1", "warning 2"
    warning 1
    warning 2
    46

    View Slide

  47. Thread'and'Fibre'stack'sizes
    • Fibre'stack'size'hardcoded'at'4K'in'1.9.x
    • Now'se:able'via'ENV'variable'in'2.x
    47

    View Slide

  48. Thread'and'Fibre'stack'sizes
    • RUBY_THREAD_VM_STACK_SIZE:4vm4stack4size4used4at4thread4
    creaCon.4default:4128KB4(32bit4CPU)4or4256KB4(64bit4CPU).
    • RUBY_THREAD_MACHINE_STACK_SIZE:4machine4stack4size4
    used4at4thread4creaCon.4default:4512KB4or41024KB.
    • RUBY_FIBER_VM_STACK_SIZE:4vm4stack4size4used4at4fiber4
    creaCon.4default:464KB4or4128KB.
    • RUBY_FIBER_MACHINE_STACK_SIZE:4machine4stack4size4used4
    at4fiber4creaCon.4default:4256KB4or4256KB.
    48

    View Slide

  49. Thanks!!
    • Ruby&2.0&NEWS
    • Ruby&2.1&NEWS
    • Ruby&2.2&(trunk)&NEWS
    • Ruby&2.0.0&in&detail
    • Ruby&2.1&in&detail
    • Ruby&2&Keyword&Arguments
    49

    View Slide

  50. More%links
    • Ruby&2.1&Garbage&Collec3on:&ready&for&produc3on
    • Demys3fying&the&Ruby&GC
    • Visualizing&Garbage&Collec3on&in&Ruby&and&Python
    • Introducing&Incremental&GC&algorithm
    • Ruby&2.1:&OutDofDBand&GC
    • MRI's&Method&Caches
    50

    View Slide