$30 off During Our Annual Pro Sale. View Details »

Ruby 2.0: new features

Ruby 2.0: new features

Slides for RubyConf Taiwan 2012 talk "Ruby 2.0: new features" http://rubyconf.tw/2012/

Akira Matsuda

December 07, 2012
Tweet

More Decks by Akira Matsuda

Other Decks in Programming

Transcript

  1. Ruby 2.0:
    New Features
    @a_matsuda

    View Slide

  2. whoami
    Akira Matsuda (দా ໌)
    GitHub: amatsuda
    Twitter: @a_matsuda

    View Slide

  3. View Slide

  4. works (gems)

    kaminari

    active_decorator

    action_args

    erd

    hocus_pocus

    i18n_generators

    html5_validators

    gem-src

    traceroute

    interactive_rspec

    ...

    View Slide

  5. works (the most recent one)
    AR.where.not
    AR.where.like
    https://github.com/rails/rails/commit/de75af7

    View Slide

  6. Ruby 2.0

    View Slide

  7. begin

    View Slide

  8. Ruby 2.0

    View Slide

  9. Major version update

    View Slide

  10. Simultaneous major version
    updates in the Ruby ecosystem

    Ruby 2.0

    Rails 4.0

    Rake 10.0

    RubyGems 2.0

    RDoc 4.0

    RSpec 3.0

    Sprockets 3.0

    Capybara 2.0

    Rubinius 2.0

    ...

    View Slide

  11. Ruby version numbers

    1993/02 Born

    1995/12 The first public release (0.95)

    1996/12 1.0

    1997/08 1.1

    1998/12 1.2

    1999/08 1.4

    2000/09 1.6

    2003/08 1.8

    2007/12 1.9.0 (unstable)

    2010/08 1.9.2 (stable)

    2011/10 1.9.3 (stable)

    View Slide

  12. Vaporware?
    1
    1.2
    1.4
    1.6
    1.8
    2
    1995/12 1996/12 1997/08 1998/12 1999/08 2000/09 2003/08 2007/12 2010/08 2011/10

    View Slide

  13. No! 2.0!!
    1
    1.2
    1.4
    1.6
    1.8
    2
    1995/121996/121997/081998/121999/082000/092003/082007/122010/082011/102013/02
    Title

    View Slide

  14. Why 2.0?
    '1.9'.succ
    Features
    Birthday

    View Slide

  15. '1.9'.succ

    View Slide

  16. '1.9'.succ
    '1.9'.succ #=> "2.0"

    View Slide

  17. Features

    View Slide

  18. Matz's slide for RubyConf 2003
    http://www.rubyist.net/~matz/slides/rc2003/
    mgp00009.html

    View Slide

  19. Optional Type?
    Optional Type!

    View Slide

  20. Happy 20th birthday!
    Ruby was "born" in
    1993/2/24
    Ruby will become 20 yrs
    old in 2013/2/24
    Ruby is no more a teenager!
    Let's call it Ruby 2.0

    View Slide

  21. New Features

    View Slide

  22. New Features
    Refinements
    Module#prepend
    Enumerable#lazy
    Keyword Arguments

    View Slide

  23. Refinements

    View Slide

  24. @shugomaeda

    View Slide

  25. View Slide

  26. @shugomaeda
    Lives in "the Ruby City"
    Matz-e
    Matz's boss at NaCl
    http://www.netlab.jp/
    Ruby Association
    http://www.ruby.or.jp/

    View Slide

  27. What are Refinements?
    Somewhat limited
    monkey-patching

    View Slide

  28. background
    "Monkey-patching" is
    sometimes too much
    powerful

    View Slide

  29. Monkey Battles
    God vs ActiveSupport
    Mail vs ActiveSupport

    View Slide

  30. God vs ActiveSupport
    require 'active_support/all'
    p 3.days.since(Date.today)
    #=> Mon, 10 Dec 2012
    gem 'god', '0.13.0'
    require 'god'
    p 3.days.since(Date.today)
    #=> Tue, 08 Aug 2722

    View Slide

  31. The new methods
    Module#refine
    Kernel#using

    View Slide

  32. Module#refine

    View Slide

  33. Module#refine
    module Foo
    refine String do
    def say
    puts "#{self}!!"
    end
    end
    'hello'.say
    end
    #=> hello!!

    View Slide

  34. Module#refine
    module Foo
    refine String do
    def say; puts "#{self}!!"; end
    end
    'hello'.say
    end
    #=> hello!!
    'world'.say
    #=> NoMethodError: undefined method `say'
    for "world":String

    View Slide

  35. Kernel#using

    View Slide

  36. using Kernel#using
    module Foo
    refine String do
    def say; puts "#{self}!!"; end
    end
    end
    class Bar
    using Foo
    def hello
    'hello'.say
    end
    end
    Bar.new.hello
    #=> hello!!

    View Slide

  37. using using in Module
    module Foo
    refine String do
    def say; puts "#{self}!!"; end
    end
    end
    module Bar
    using Foo
    end
    Bar.module_eval {
    'hello'.say
    }
    #=> hello!!

    View Slide

  38. using anonymous Module
    module Foo
    refine String do
    def say; puts "#{self}!!"; end
    end
    end
    Module.new { using Foo }.module_eval {
    'hello'.say
    }
    #=> hello!!
    'world'.say
    #=> NoMethodError: undefined method `say' for
    "world":String

    View Slide

  39. using lambda / Proc?
    module Foo
    refine String do
    def say; puts "#{self}!!"; end
    end; end
    -> {
    using Foo
    'hello'.say
    }.call
    #=> hello!!
    'world'.say
    #=> world!!

    View Slide

  40. using lambda + Module
    module Foo
    refine String do
    def say; puts "#{self}!!"; end
    end; end
    Module.new { using Foo }.module_eval {
    -> { 'hello'.say }
    }.call
    #=> hello!!
    'world'.say
    #=> undefined method `say' for
    "world":String

    View Slide

  41. example

    View Slide

  42. activerecord-refinements

    View Slide

  43. Feature
    User.where('age >= ?', 18)

    View Slide

  44. Feature
    User.where('age >= ?', 18)
    =>
    User.where { :age >= 18 }

    View Slide

  45. activerecord-refinements
    https://github.com/
    amatsuda/activerecord-
    refinements
    % gem i activerecord-
    refinements

    View Slide

  46. activerecord-refinements/lib/
    active_record/refinements.rb (1)
    module ActiveRecord::Refinements
    module WhereBlockSyntax
    refine Symbol do
    %i[== != =~ > >= < <=].each
    do |op|
    define_method(op) {|val|
    [self, op, val] }
    ennnnd

    View Slide

  47. activerecord-refinements/lib/
    active_record/refinements.rb (2)
    module ActiveRecord::Refinements
    module QueryMethods
    def where(opts = nil, *rest, &block)
    if block
    col, op, val = Module.new { using
    ActiveRecord::Refinements::WhereBlockSyntax }.module_eval &block
    arel_node = case op
    when :!=
    table[col].not_eq val
    when :=~
    table[col].matches val
    when :>
    table[col].gt val
    when ... # (snip)
    end
    clone.tap do |relation|
    relation.where_values += build_where(arel_node)
    end
    else
    super
    ennnnd

    View Slide

  48. activerecord-refinements/lib/
    activerecord-refinements.rb
    module ActiveRecord::QueryMethods
    prepend ActiveRecord::Refinements::QueryMethods
    end

    View Slide

  49. activerecord-refinements/
    spec/where_spec.rb
    describe 'Symbol enhancements' do
    describe '#!=' do
    subject { User.where { :name != 'nobu' }.to_sql }
    it { should =~ /WHERE \("users"."name" != 'nobu'\)/ }
    end
    describe '#>=' do
    subject { User.where { :age >= 18 }.to_sql }
    it { should =~ /WHERE \("users"."age" >= 18\)/ }
    end
    describe '#=~' do
    subject { User.where { :name =~ 'tender%' }.to_sql }
    it { should =~ /WHERE \("users"."name" LIKE 'tender%'\)/ }
    end
    context 'outside of where block' do
    it { expect { :omg > 1 }.to raise_error ArgumentError }
    end
    end

    View Slide

  50. View Slide

  51. "Refinements and nested
    methods"
    ruby-core:50336
    https://bugs.ruby-
    lang.org/issues/4085

    View Slide

  52. "Refining Ruby"
    http://blog.headius.com/
    2012/11/refining-ruby.html

    View Slide

  53. Charlie's worry
    module WeirdPlus
    refine String do
    def +(other)
    "#{self} plus #{other}"
    end
    end
    end
    class MyArray
    def initialize
    @ary = ['foo', 'bar', 'baz']
    end
    def inject(accum, &block)
    @ary.each do |str|
    accum = WeirdPlus.module_exec(str, accum, &block)
    end
    accum
    end
    end
    def add_all(str_ary)
    str_ary.inject('') do |str, accum|
    accum + str
    end
    end
    add_all(MyArray.new)
    #=> " plus foo plus bar plus baz"

    View Slide

  54. Matz's new plan
    (as of today)

    "using" is only allowed at top level.

    refined methods are called only after "using".

    or within blocks given to "refine".

    if you pass the proc to "refine" e.g.
    refine(C,&b) refined methods may not be
    called from b. It's implementation dependent.

    refinements are not available in subclasses,
    nor in reopened classes/modules.

    refinements are not available from
    module_eval/class_eval.

    View Slide

  55. Restrictions
    only allowed at top level
    not available in subclasses
    not available in reopened
    classes/modules
    not available from
    module_eval

    View Slide

  56. Matz's intension
    let `refine` + `using` be
    lexical (file scoped)
    not for library /
    framework authors, but
    for script writers (?)

    View Slide

  57. Moved to ext/refinement
    https://github.com/ruby/ruby/commit/328e0ff

    View Slide

  58. OMG

    View Slide

  59. Module#prepend

    View Slide

  60. background

    View Slide

  61. Ruby < 2, Rails < 3

    View Slide

  62. alias_method_chain
    def alias_method_chain(target, feature)
    alias_method "#{target}_without_#{feature}", target
    alias_method target, "#{target}_with_#{feature}"
    end
    https://github.com/rails/rails/commit/794d93f by @jamis

    View Slide

  63. AMC
    class A
    def foo; puts 'foo'; end
    end
    class A
    def foo_with_bar
    foo_without_bar
    puts 'bar'
    end
    alias_method_chain :foo, :bar
    end
    A.new.foo
    A.new.foo_without_bar

    View Slide

  64. simple pagination
    ActiveRecord::FinderMethods.module_eval do
    def all_with_page(*args)
    if args.any? && (page =
    args.first.delete(:page))
    limit(10).
    offset(10 * (page - 1)).
    all_without_page(*args)
    else
    all_without_page(*args)
    end
    end
    alias_method_chain :all, :page
    end

    View Slide

  65. Problem

    View Slide

  66. adding `baz` and
    calling foo "without_bar"
    class A
    def foo; puts 'foo'; end
    def foo_with_bar
    foo_without_bar
    puts 'bar'
    end
    alias_method_chain :foo, :bar
    def foo_with_baz
    foo_without_baz
    puts 'baz'
    end
    alias_method_chain :foo, :baz
    end

    View Slide

  67. AMC defines tons of messy
    public methods
    class A
    def foo; puts 'foo'; end
    def foo_with_bar
    foo_without_bar
    puts 'bar'
    end
    alias_method_chain :foo, :bar
    def foo_with_baz
    foo_without_baz
    puts 'baz'
    end
    alias_method_chain :foo, :baz
    end
    A.instance_methods.grep(/foo/)
    #=> [:foo,
    :foo_with_bar, :foo_without_bar, :foo_with_baz, :foo_without_baz]

    View Slide

  68. "without_bar" skips "baz"
    class A
    def foo; puts 'foo'; end
    def foo_with_bar
    foo_without_bar
    puts 'bar'
    end
    alias_method_chain :foo, :bar
    def foo_with_baz
    foo_without_baz
    puts 'baz'
    end
    alias_method_chain :foo, :baz
    end
    A.new.foo_without_bar
    #=> foo

    View Slide

  69. save_without_*
    gem 'activerecord', '<2.3'
    require 'active_record'
    ActiveRecord::Base.configurations = {'test' => {:adapter =>
    'sqlite3', :database => ':memory:'}}
    ActiveRecord::Base.establish_connection('test')
    class User < ActiveRecord::Base
    validates_presence_of :name
    end
    class CreateAllTables < ActiveRecord::Migration
    def self.up
    create_table(:users) {|t| t.column :name, :string}
    end
    end
    CreateAllTables.up
    # p User.new.save_without_validation
    p User.new.save_without_dirty
    p User.new.save

    View Slide

  70. Rails 3’s solution
    use the power of Ruby
    Module
    super

    View Slide

  71. https://github.com/rails/
    rails/commit/d916c62

    View Slide

  72. excerpt from d916c62
    included do
    - alias_method_chain :save, :dirty
    ...
    end
    - def save_with_dirty(*args)
    - if status =
    save_without_dirty(*args)
    + def save(*) #:nodoc:
    + if status = super
    ...

    View Slide

  73. @wycats style
    module Bar
    def foo
    puts 'bar'
    super
    end; end
    module Baz
    def foo
    puts 'baz'
    end; end
    class A
    include Baz
    include Bar
    def foo
    puts 'foo'
    super
    end
    end
    A.new.foo
    #=> foo
    bar
    baz

    View Slide

  74. the original foo method
    class A
    def foo
    puts 'foo'
    super
    end
    end

    View Slide

  75. how can we extend methods
    that are not calling super?
    class A
    def foo
    puts 'foo'
    end
    end
    (do something...)
    A.new.foo
    #=> foo
    bar

    View Slide

  76. Module#prepend

    View Slide

  77. Module#prepend
    @wycats
    @n0kada (Nobu)

    View Slide

  78. Nobu

    View Slide

  79. "The Patch Monster"
    % git clone git://github.com/ruby/ruby
    % git shortlog -ns | grep -v svn | head -10
    7233!
    nobu
    3471"
    akr
    2553"
    matz
    1568"
    naruse
    1502"
    usa
    1412"
    eban
    873"
    ko1
    601"
    knu
    561"
    drbrain
    536"
    mame

    View Slide

  80. Who's creating Ruby?
    Matz: designing
    Ko1: implementing
    Nobu: fixing

    View Slide

  81. Who's creating Ruby?
    Matz: designing
    Ko1: implementing
    Nobu: fixing

    View Slide

  82. View Slide

  83. AMC
    class A
    def foo
    puts 'foo'
    end
    end
    class A
    def foo_with_bar
    foo_without_bar
    puts ‘bar’
    end
    alias_method_chain :foo, :bar
    end
    A.new.foo
    #=> foo
    bar

    View Slide

  84. Module#prepend
    class A
    def foo; puts 'foo'; end
    end
    module Bar
    def foo
    super
    puts 'bar'
    end
    end
    class A
    prepend Bar
    end
    A.new.foo
    #=> foo
    bar

    View Slide

  85. prepending multiple Modules
    class A; def foo; puts 'foo'; end; end
    module Bar
    def foo
    super
    puts 'bar'
    end
    end
    module Baz
    def foo
    super
    puts 'baz'
    end
    end
    class A
    prepend Bar
    prepend Baz
    end
    A.new.foo
    #=> foo
    bar
    baz

    View Slide

  86. simple pagination with
    Module#prepend
    module PrependPaginator
    def all(*args)
    if args.any? && (page =
    args.first.delete(:page))
    self.limit_value = 10
    self.offset_value = 10 * (page - 1)
    end
    super
    end
    end
    ActiveRecord::FinderMethods.send :prepend,
    PrependPaginator

    View Slide

  87. activerecord-refinements/lib/
    activerecord-refinements.rb
    module ActiveRecord::Refinements
    module QueryMethods
    def where(opts = nil, *rest, &block)
    if block
    ... # (snip)
    else
    super
    ennnnd
    module ActiveRecord::QueryMethods
    prepend ActiveRecord::Refinements::QueryMethods
    end

    View Slide

  88. Enumerable#lazy

    View Slide

  89. @yhara

    View Slide

  90. @yhara
    Lives in "the Ruby City"
    Matz-e
    Matz's co-worker at NaCl
    http://www.netlab.jp/

    View Slide

  91. Ruby committers in NaCl
    @yukihiro_matz
    (since 15.years.ago)
    @shugomaeda
    @gotoyuzo
    @nari3
    @takaokouji
    @shyouhei (until October 2012)

    View Slide

  92. The proposal
    http://bugs.ruby-
    lang.org/issues/4890

    View Slide

  93. Enumerator
    [1, 2, 3].each
    => #3]:each>

    View Slide

  94. Enumerator::Lazy
    [1, 2, 3].lazy
    => #2, 3]>

    View Slide

  95. lazy evaluation
    (1..Float::INFINITY).lazy
    .select(&:even?)
    .take(20)
    .force
    #=> [2, 4, 6, 8, 10, 12, 14, 16,
    18, 20, 22, 24, 26, 28, 30, 32,
    34, 36, 38, 40]

    View Slide

  96. Friday the 13th
    (until ETERNITY)
    require 'date'
    ETERNITY = Float::INFINITY
    puts (Date.today..ETERNITY).
    lazy.
    select {|d| (d.day == 13) && d.friday?}.
    take(5).force
    #=> 2013-09-13
    2013-12-13
    2014-06-13
    2015-02-13
    2015-03-13

    View Slide

  97. Ruby implementation of
    UNIX wc command
    (ARGV.length == 0 ?
    [["", STDIN]] :
    ARGV.lazy.map { |filename|
    [filename, File.open(filename)]
    }).map { |filename, file|
    "%4d %4d %4d %s\n" % [*file.lines.lazy.map { |line|
    [1, line.split.length, line.length]
    }.inject([0, 0, 0]) { |(lc, wc, cc), (l, w, c)|
    [wc + w, lc + l, cc + c]
    }, filename]
    }.each(&:display)
    by @shugomaeda
    http://shugomaeda.blogspot.com/2012/03/
    enumerablelazy-and-its-benefits.html

    View Slide

  98. Keyword Arguments

    View Slide

  99. @mametter

    View Slide

  100. @mametter
    Quine artist
    Ruby 2.0 release manager

    View Slide

  101. "The Qlobe"
    http://
    mamememo.blogspot.tw/
    2010/09/qlobe.html

    View Slide

  102. "The Qlobe"
    v=0000;eval$s=%q~d=%!^LcfYoP
    4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_>yH?b[F^e7C/56j|pmRe+:)B "##% ::##########" O98(Zh)'Iof*nm.,$C5Nyt=
    PPu01Avw^6ygIL8xI#LNz3v}T=4W "# #. .####:#######" lL27FZ0ij)7TQCI)P7u
    }RT5-iJbbG5P-DHB<. " ##### # :############" R,YvZ_rnv6ky-G+4U'
    $*are@b4U351Q-ug5 " #######################" 00x8RR%`Om7VDp4M5
    PFixrPvl&y]0`_PstfUxOC(q " .#############:##% .## ." /,}.YOIFj(k&q_V
    zcaAi?]^lCVYp!; " %% .################. #. " ;s="v=%04o;ev"%
    (;v=(v-($*+[45, ":####: :##############% : " ])[n=0].to_i;)%
    360)+"al$s=%q#{ "%######. ######### " ;;"%c"%126+$s<<
    126}";d.gsub!(/ "##########. #######% " |\s|".*"/,"");;
    require"zlib"|| "########### :######. " ;d=d.unpack"C*"
    d.map{|c|n=(n|| ":#########: .######: . " )*90+(c-2)%91};
    e=["%x"%n].pack " :#######% :###### #: " &&"H*";e=Zlib::
    Inflate.inflate( " ######% .####% :: " &&e).unpack("b*"
    )[0];22.times{|y| " ####% %### " ;w=(Math.sqrt(1-(
    (y*2.0-21)/22)**(; " .###: .#% " ;2))*23).floor;(w*
    2-1).times{|x|u=(e+ " %## " )[y*z=360,z]*2;u=u[
    90*x/w+v+90,90/w];s[( " #. " ;y*80)+120-w+x]=(""<<
    32<<".:%#")[4*u.count(( " . " ;"0"))/u.size]}};;puts\
    s+";_ The Qlobe#{" "*18+ ( "# :#######" ;"Copyright(C).Yusuke End\
    oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010

    View Slide

  103. "௒ઈٕ޼ Ruby ϓϩάϥϛϯά"
    http://
    www.slideshare.net/
    mametter/ruby-esoteric-
    obfuscated-ruby-
    programming

    View Slide

  104. background

    View Slide

  105. Well known idiom using Hash
    def foo(args = {})
    puts "a is #{args[:a]}, b is #{args[:b]}"
    end
    foo a: 1, b: 2
    #=> a is 1, b is 2

    View Slide

  106. Patterns
    Default Values
    Multiple Hashes
    Splat Operator
    Assert Valid Keys

    View Slide

  107. Default Values

    View Slide

  108. Hash#merge
    def foo(args = {})
    values = {a: 1, b: 2}.merge args
    puts "a is #{values[:a]}, b is #{values[:b]}"
    end
    foo b: 4
    #=> a is 1, b is 4

    View Slide

  109. Hash#reverse_merge
    (ActiveSupport)
    def foo(args = {})
    values = args.reverse_merge a: 1, b: 2
    puts "a is #{values[:a]}, b is #{values[:b]}"
    end
    foo b: 4
    #=> a is 1, b is 4

    View Slide

  110. multiple Hashes

    def create(attributes = {}, options = {}, &block)
    AR/associations/collection_association.rb

    def form_tag(url_for_options = {}, options = {},
    &block)
    AV/helpers/form_tag_helper.rb

    def render(options = {}, locals = {}, &block)
    AV/helpers/rendering_helper.rb

    def button_to(name, options = {}, html_options = {})
    AV/helpers/url_helper.rb

    def date_select(method, options = {}, html_options
    = {})
    AV/helpers/date_helper.rb

    View Slide

  111. Passing values into the latter
    keywords Hash
    def button_to(name, options = {}, html_options = {})
    <%= button_to 'New!', action: 'new', method: 'get' %>
    #=> options: {action: 'new', method: 'get'},
    html_options: {}
    <%= button_to 'New!', {action: 'new'}, {method: 'get'} %>
    #=> options: {action: 'new'},
    html_options: {method: 'get'}

    View Slide

  112. Splat Operator
    def define_model_callbacks(*callbacks)
    options = callbacks.extract_options!
    options = {
    :terminator => "result == false",
    :scope => [:kind, :name],
    :only => [:before, :around, :after]
    }.merge(options)
    ...
    AMo/callbacks.rb

    View Slide

  113. extract_options!
    class Array
    def extract_options!
    if last.is_a?(Hash) &&
    last.extractable_options?
    pop
    else
    {}
    end
    end
    end
    AS/core_ext/array/extract_options.rb

    View Slide

  114. assert_valid_keys
    VALID_FIND_OPTIONS =
    [:conditions, :include, :joins, :limit, :offset,
    :extend, :order, :select, :readonly,
    :group, :having, :from, :lock ]
    def apply_finder_options(options)
    ...
    options.assert_valid_keys(VALID_FIND_OPTIONS)
    AR/relation/spawn_methods.rb

    View Slide

  115. Implementation of
    assert_valid_keys
    def assert_valid_keys(*valid_keys)
    valid_keys.flatten!
    each_key do |k|
    raise ArgumentError.new("Unknown key:
    #{k}") unless valid_keys.include?(k)
    end
    end
    AS/core_ext/hash/keys.rb

    View Slide

  116. using assert_valid_keys
    {name: 'amatsuda', job: 'Rubyist'}
    .assert_valid_keys(:name, :age)
    #=> ArgumentError: Unknown key: job

    View Slide

  117. Ruby 2.0 keyword arguments

    View Slide

  118. Defalut Values

    View Slide

  119. No need to merge or
    reverse_merge anymore!
    def foo(a: 1, b: 2)
    puts "a is #{a}, b is #{b}"
    end
    foo()
    #=> a is 1, b is 2
    foo a: 3, b: 2
    #=> a is 3, b is 2

    View Slide

  120. Multiple Hashes &
    Splat Operator

    View Slide

  121. The "rest" argument
    def button_to(name, controller: nil, action: nil,
    **html_options)
    puts "controller: #{controller}"
    puts "action: #{action}"
    puts "html_options: #{html_options}"
    end
    button_to 'a', action: 'new', method: 'get'
    #=> controller: (nil)
    action: new
    html_options: {:method=>"get"}

    View Slide

  122. assert_valid_keys

    View Slide

  123. We don't need
    assert_valid_keys anymore!
    def apply_finder_options(conditions: nil,
    include: nil, joins: nil, limit: nil, offset: nil,
    extend: nil, order: nil, select: nil,
    readonly: nil, group: nil, having: nil,
    from: nil, lock: nil)
    puts "order: #{order}"
    puts "limit: #{limit}"
    end
    apply_finder_options order: 'id', limit: 3, omg: 999
    #=> unknown keyword: omg (ArgumentError)

    View Slide

  124. A bit more about 2.0
    performance
    Encoding

    View Slide

  125. Significant performance
    improvement
    VM
    GC
    `require`

    View Slide

  126. VM: @_ko1

    View Slide

  127. View Slide

  128. GC: @nari_en

    View Slide

  129. View Slide

  130. Encoding

    View Slide

  131. Default scripting Encoding
    1.9.x: US-ASCII
    2.0: UTF-8

    View Slide

  132. Magic comment
    # encoding: utf-8
    puts '͜Μʹͪ͸ɺੈքʂ'

    View Slide

  133. Magic comment
    # encoding: utf-8
    puts '͜Μʹͪ͸ɺੈքʂ'

    View Slide

  134. Why wasn't the Ruby Encoding
    system like this in 1.9?
    (I guess) In order to
    "teach" us the way
    Encoding works

    View Slide

  135. @nalsh

    View Slide

  136. View Slide

  137. ensure

    View Slide

  138. Ruby 2.0 is
    "100% compatible"
    powerful
    fast
    something special

    View Slide

  139. Ruby 2.0 is coming!
    2.months.until 2.0
    The next release would be
    "2.0.0-rc1" within a month
    or so

    View Slide

  140. Give it a try!
    tar.gz
    RVM
    rbenv

    View Slide

  141. try 2.0
    if your_app.ruby_version == 1.9.3
    you.should upgrade {|ruby|
    your_app << ruby.new_features!
    raise Issue.new unless ruby.compatible?
    }
    end

    View Slide

  142. try 2.0
    if your_app.ruby_version == 1.9.3
    you.should upgrade {|ruby|
    your_app << ruby.new_features!
    raise Issue.new unless ruby.compatible?
    }
    else
    die
    end

    View Slide

  143. end

    View Slide