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

Ruby 2.0 on Rails in Production

Ruby 2.0 on Rails in Production

Slides for RedDotRubyConf talk "Ruby 2.0 on Rails in Production" http://www.reddotrubyconf.com/schedule#amatsuda

Akira Matsuda

June 08, 2013
Tweet

More Decks by Akira Matsuda

Other Decks in Programming

Transcript

  1. Ruby 2.0 on Rails
    in Production
    Akira
    Matsuda

    View Slide

  2. % ruby -v

    Who here are already using
    Ruby 2.0 in production?

    View Slide

  3. % ruby -v

    Who here are still using 1.8?

    View Slide

  4. View Slide

  5. begin

    View Slide

  6. Ruby 2.0 goodness

    Performance

    Stability

    Compatibility

    New features

    View Slide

  7. Performance

    View Slide

  8. View Slide

  9. ※ taken from @mirakui's slide at RubyKaigi 2013
    https://speakerdeck.com/mirakui/high-performance-rails?slide=7

    View Slide

  10. ※ taken from @mrkn's slide at OedoRubyKaigi 03
    https://speakerdeck.com/mrkn/what-a-hard-work-to-make-the-recipe-
    sharing-service-available-on-ruby-1-dot-9-3?slide=128

    View Slide

  11. rails command boot time
    # ruby 1.9.3p429
    % time rails r '1'
    rails r '1' 7.00s user 1.67s system 99% cpu 8.701 total
    % time rails r '1'
    rails r '1' 7.03s user 1.64s system 99% cpu 8.698 total
    % time rails r '1'
    rails r '1' 7.01s user 1.66s system 99% cpu 8.710 total
    # ruby 2.0.0p195
    % time rails r '1'
    rails r '1' 4.80s user 1.29s system 99% cpu 6.124 total
    % time rails r '1'
    rails r '1' 4.77s user 1.28s system 99% cpu 6.073 total
    % time rails r '1'
    rails r '1' 4.78s user 1.29s system 99% cpu 6.099 total

    View Slide

  12. Stability

    View Slide

  13. Stability

    Fact: 2.0.0 was a "stable" release

    View Slide

  14. 1.9.0 was not

    1.9.0: unstable

    1.9.1: unstable

    1.9.2: stable

    1.9.3: stable

    2.0.0: stable

    2.1.0: stable (?)

    View Slide

  15. Stability

    2.0.0-p195 was released last
    month by @nagachika

    View Slide

  16. View Slide

  17. View Slide

  18. Stability

    2.0.0 is no more p0 and so
    it's ready to use in production

    View Slide

  19. Branch Maintenance Policies

    1.8.7: maintained by @shyouhei, will be dead soon

    1.8.8: no plan

    1.9.0: dead

    1.9.1: dead

    1.9.2: maintained by @yugui, dead (?)

    1.9.3: maintained by @unak

    1.9.4: no plan

    2.0.0: maintained by @nagachika

    2.0.1: no plan

    2.1.0: managed by @naruse

    View Slide

  20. 1.9.3

    Released by @yugui

    Maintained by @unak (aka. usa)

    Sponsored by Ruby Association

    View Slide

  21. View Slide

  22. View Slide

  23. 2.0.0

    Released by @mametter (aka.
    mame)

    Maintained by @nagachika

    View Slide

  24. View Slide

  25. View Slide

  26. 2.1.0

    Would be released by @nalsh
    (aka. naruse)

    Would be released in December
    this year

    View Slide

  27. View Slide

  28. "TRICK 2013" in RubyKaigi

    Results: http://
    www.slideshare.net/mametter/
    trick2013-results

    Winners: https://github.com/tric/
    trick2013

    View Slide

  29. @unak (usa)
    $ruby.is_a?(Object){|oriented| language}

    View Slide

  30. @mametter (mame)
    eval$C=%q(at_exit{
    open("/dev/dsp","wb"){|g|h=[0]*80
    $><<"\s"*18+"eval$C=%q(#$C);S=%:"
    (S<t=0; h.map!{|v|d=?!==l[
    t]?1 :(l[
    t]== ?#)?
    0*v= 6:03
    (v<1 ?[]:
    0..n -1).
    each {|z|
    s[z] +=2*
    M.sin(($*[0] ||1)
    .to_f*M.sin(y= 40*(z+m)*2**
    (t/12E0)/463)+ y)*(v-z*d/n)};
    t+=1;v-d};m+= n;g.flush<<(s.
    pack"C*"); puts(l)}}};M=
    Math);S=%:
    Jesu, Joy of Man's Desiring
    Johann Sebastian Bach
    #
    | #
    | #
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | | #
    # # # #
    | | | #
    | #| #
    # # | #
    | | | #
    | | # #
    # # # #
    | | # |
    | | # #
    # # # #
    | | | #
    | | #
    # # # #
    | | # |
    | # # |
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | | # #
    # # # #
    | | | #
    | # #
    # # #
    | | | #
    | # | #
    # # # #
    | | | |
    | | | |
    | | | |
    | | | |
    | | | |
    | | | |
    | | | |
    | | | |
    | | | |
    | | | |

    View Slide

  31. Compatibility

    View Slide

  32. Compatibility

    "100% compatible" (Ruby level)

    magic comment

    View Slide

  33. View Slide

  34. 99.9% compatible

    Default Ruby source le
    encoding to utf-8 [Feature #6679]

    View Slide

  35. Hello!
    puts '͜Μʹͪ͸ʂ'

    View Slide

  36. Hello...?
    % ruby -v hello_utf8.rb
    ruby 1.8.7 (2012-06-29 patchlevel 370) [i686-darwin12.2.1]
    ͜Μʹͪ͸ʂ
    % ruby -v hello_utf8.rb
    ruby 1.9.3p429 (2013-05-15 revision 40747) [x86_64-darwin12.3.0]
    encoding_utf8.rb:1: invalid multibyte char (US-ASCII)

    View Slide

  37. Magic comment
    # encoding: utf-8
    puts '͜Μʹͪ͸ʂ'

    View Slide

  38. ͜Μʹͪ͸ɺ1.9.3!
    % ruby -v hello_utf8.rb
    ruby 1.9.3p429 (2013-05-15 revision 40747) [x86_64-darwin12.3.0]
    ͜Μʹͪ͸ʂ

    View Slide

  39. Hello!
    puts '͜Μʹͪ͸ʂ'

    View Slide

  40. Hello...?
    % ruby -v hello_utf8.rb
    ruby 1.8.7 (2012-06-29 patchlevel 370) [i686-darwin12.2.1]
    ͜Μʹͪ͸ʂ
    % ruby -v hello_utf8.rb
    ruby 1.9.3p429 (2013-05-15 revision 40747) [x86_64-darwin12.3.0]
    encoding_utf8.rb:1: invalid multibyte char (US-ASCII)
    % ruby -v hello_utf8.rb
    ruby 2.0.0p195 (2013-05-14 revision 40734) [x86_64-darwin12.3.0]
    ͜Μʹͪ͸ʂ

    View Slide

  41. Incompatibility
    s = "\xE3\x81\x82"
    p s, s.size

    View Slide

  42. Incompatibility
    % ruby -v encoding_binary.rb
    ruby 1.9.3p429 (2013-05-15 revision 40747) [x86_64-darwin12.3.0]
    "\xE3\x81\x82"
    3
    % ruby -v encoding_binary.rb
    ruby 2.0.0p195 (2013-05-14 revision 40734) [x86_64-darwin12.3.0]
    "͋"
    1

    View Slide

  43. Tiny Print Debugging Tip
    s = "\xE3\x81\x82"
    # p s, s.size
    p str: s, size: s.size

    View Slide

  44. Tiny Print Debugging Tip
    % ruby encoding_binary.rb
    {:str=>"͋", :size=>1}
    (by @yhara: http://route477.net/d/?date=20130206#p01)

    View Slide

  45. Compatibility (GC bug)

    Ruby 2.0 is so compatible with
    1.9.3 that even known bugs are
    compatible!

    View Slide

  46. "GC.disable_lazy_sweep"

    https://gist.github.com/mrkn/
    5096076

    View Slide

  47. New features

    View Slide

  48. New Features

    (Re nements)

    Module#prepend

    Keyword arguments

    Enumerable#lazy

    View Slide

  49. Re nements

    View Slide

  50. View Slide

  51. Module#prepend

    View Slide

  52. Module#prepend

    Good for Rails plugins

    You can replace
    alias_method_chain with this

    View Slide

  53. 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

  54. 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

  55. Keyword arguments

    View Slide

  56. Method#parameters

    since 1.9.1

    View Slide

  57. Method#parameters
    class C
    def m(a, b = 1, c = nil) end
    end
    C.new.method(:m).parameters
    #=> [[:req, :a], [:opt, :b], [:opt, :c]]

    View Slide

  58. asakusarb/action_args

    View Slide

  59. View Slide

  60. Initial implementation
    module AbstractController
    class Base
    def send_action(method_name, *args)
    return send method_name, *args unless args.blank?
    values =
    method(method_name).parameters.map(&:last).map {|k|
    params[k]}
    send method_name, *values
    end
    end
    end

    View Slide

  61. Test Patterns
    params = {a: '1', b: '2'}
    def m end
    #=> []
    def m(a) end
    #=> ['1']
    def m(a = 'a') end
    #=> ['1']
    def m(c = 'c') end
    #=> expected: ['c'], actual: [nil]

    View Slide

  62. Don't add to the arguments if (type
    == :opt) && !params.has_key?
    params = {a: '1', b: '2'}
    def m(c = 'c') end
    #=> ['c']
    def m(a, b) end
    #=> ['1', '2']
    def m(a, b = 'b') end
    #=> ['1', '2']
    def m(a, c = 'c') end
    #=> ['1', 'c']
    def m(a = 'a', b = 'b') end
    #=> ['1', '2']
    def m(c = 'c', d = 'd') end
    #=> ['c', 'd']
    def m(c = 'c', a) end
    #=> expected: ['c', '1'], actual: ['1']

    View Slide

  63. Default value can't be determined in
    parse / compile phase
    def foo(x = rand(3))

    View Slide

  64. RubyVM::InstructionSequence
    # warning: Do never use this black magic!!
    def foo(x = 'xx', y = :yy, z = 1); end
    ary = RubyVM::InstructionSequence.of(method(:foo)).to_a
    default_args = ary[11][1]
    bytecode = ary[13]
    p default_args
    #=> [:label_0, :label_4, :label_8, :label_11]
    p bytecode
    #=> [:label_0, 2, [:putstring, "xx"],
    [:setlocal_OP__WC__0, 4], :label_4, [:putobject, :yy],
    [:setlocal_OP__WC__0, 3], :label_8,
    [:putobject_OP_INT2FIX_O_1_C_], [:setlocal_OP__WC__0,
    2], :label_11, [:trace, 8], [:putnil], [:trace, 16],
    [:leave]]

    View Slide

  65. method.parameters.reverse_each do |type, key|
    do the same thing
    params = {a: '1', b: '2'}
    def m(c = 'c', a) end
    => ['c', '1']

    View Slide

  66. We needed to do this because,

    Method parameters are just an
    Array

    So the order matters

    It's a pain

    I wish if the method parameter is
    more like a Hash, labeled by the
    de ned method argument names

    View Slide

  67. OK, that's called "Keyword arguments"

    View Slide

  68. Keyword arguments
    # traditional method
    def m(a, b = 'b', c = 'c') end
    m('1', '2', '3')
    # kwargs
    def m(a, b: 'b', c: 'c') end
    m('1', b: '2', c: '3')

    View Slide

  69. Keyword arguments

    Optional parameters can be
    written as a Hash. Order doesn't
    matter

    action_args now supports
    kwargs, so you can use it in your
    controller code

    View Slide

  70. kwargs and Rails

    Rewriting Rails code using kwargs

    More comprehensible API
    def foo(options_with_some_unknown_keys_and_defaults = {})
    def bar(*values_maybe_or_maybe_not_with_options)

    def foo(x: 1, y: 2, z: 2)
    def bar(*values, **options)

    View Slide

  71. kwargs and Rails (AS)
    # AS/lib/active_support/core_ext/class/attribute_accessors.rb
    - def cattr_reader(*syms)
    - options = syms.extract_options!
    + def cattr_reader(*syms, instance_reader: true, instance_accessor:
    true)
    ...
    - unless options[:instance_reader] == false ||
    options[:instance_accessor] == false
    + unless (instance_reader == false) || (instance_accessor ==
    false)

    View Slide

  72. kwargs and Rails (AMo)
    # AMo/lib/active_model/validations/validates.rb
    - def validates(*attributes)
    - defaults = attributes.extract_options!.dup
    + def validates(*attributes, **defaults)

    View Slide

  73. kwargs and Rails (AP)
    # AP/lib/action_view/helpers/text_helper.rb
    - def cycle(first_value, *values)
    - options = values.extract_options!
    - name = options.fetch(:name, 'default')
    -
    + def cycle(first_value, *values, name: 'default')

    View Slide

  74. A pitfall I found

    View Slide

  75. kwargs and Rails (:if, :unless)
    User.validates_presence_of :name, :if => -> { true }
    # AMo/lib/active_model/validations/presence.rb
    - def validates_presence_of(*attr_names)
    + def validates_presence_of(*attr_names, if: true, unless:
    false, on: nil, strict: nil)

    View Slide

  76. :if!?
    def m(if: true)
    end

    View Slide

  77. :if!?
    def m(if: true)
    if if
    ...
    end
    end
    #=> "syntax error, unexpected keyword_end"

    View Slide

  78. :if!?
    def m(if: true)
    p if
    end
    #=> "syntax error, unexpected keyword_end"

    View Slide

  79. kwargs and Rails (:end)

    View Slide

  80. kwargs and Rails (:end)
    # actionpack/lib/action_view/helpers/date_helper.rb
    - def build_options(selected, options = {})
    - options = {
    - leading_zeros: true, ampm: false,
    use_two_digit_numbers: false
    - }.merge!(options)
    -
    - start = options.delete(:start) || 0
    - stop = options.delete(:end) || 59
    - step = options.delete(:step) || 1
    - leading_zeros = options.delete(:leading_zeros)
    + def build_options(selected, start: 0, end: 59, step: 1,
    leading_zeros: true, ampm: false, use_two_digit_numbers: false)

    View Slide

  81. :end!?
    def m(end: 'omg')
    p end
    end
    #=> "syntax error, unexpected keyword_end, expecting end-of-input"

    View Slide

  82. Enumerable#lazy

    View Slide

  83. Enumerable#lazy
    "Enumerable#lazy".topics.lazy.each {|it| I.talk it}

    View Slide

  84. New Features (internal)

    TracePoint

    DTrace support

    caller_locations

    debug_inspector API

    Memory inspection features

    View Slide

  85. View Slide

  86. debug_inspector API

    View Slide

  87. The "debugger" gem

    Works on Ruby 1.9

    Partly supports 2.0

    Own header les

    View Slide

  88. We created a new gem

    Named it "debugger2"
    (ko1 named it. Not me!)

    Based on new debugger API

    View Slide

  89. Debugger2 gem

    "1.0.0.beta2"

    Still buggy on Rails

    We need to do more debugging
    on the debugger...

    View Slide

  90. We want debugger!!!

    View Slide

  91. end

    View Slide