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 full-size slide

  2. % ruby -v

    Who here are already using
    Ruby 2.0 in production?

    View full-size slide

  3. % ruby -v

    Who here are still using 1.8?

    View full-size slide

  4. Ruby 2.0 goodness

    Performance

    Stability

    Compatibility

    New features

    View full-size slide

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

    View full-size slide

  6. ※ 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 full-size slide

  7. 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 full-size slide

  8. Stability

    Fact: 2.0.0 was a "stable" release

    View full-size slide

  9. 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 full-size slide

  10. Stability

    2.0.0-p195 was released last
    month by @nagachika

    View full-size slide

  11. Stability

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

    View full-size slide

  12. 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 full-size slide

  13. 1.9.3

    Released by @yugui

    Maintained by @unak (aka. usa)

    Sponsored by Ruby Association

    View full-size slide

  14. 2.0.0

    Released by @mametter (aka.
    mame)

    Maintained by @nagachika

    View full-size slide

  15. 2.1.0

    Would be released by @nalsh
    (aka. naruse)

    Would be released in December
    this year

    View full-size slide

  16. "TRICK 2013" in RubyKaigi

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

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

    View full-size slide

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

    View full-size slide

  18. @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 full-size slide

  19. Compatibility

    View full-size slide

  20. Compatibility

    "100% compatible" (Ruby level)

    magic comment

    View full-size slide

  21. 99.9% compatible

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

    View full-size slide

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

    View full-size slide

  23. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  27. 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 full-size slide

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

    View full-size slide

  29. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  32. Compatibility (GC bug)

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

    View full-size slide

  33. "GC.disable_lazy_sweep"

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

    View full-size slide

  34. New features

    View full-size slide

  35. New Features

    (Re nements)

    Module#prepend

    Keyword arguments

    Enumerable#lazy

    View full-size slide

  36. Module#prepend

    View full-size slide

  37. Module#prepend

    Good for Rails plugins

    You can replace
    alias_method_chain with this

    View full-size slide

  38. 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 full-size slide

  39. 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 full-size slide

  40. Keyword arguments

    View full-size slide

  41. Method#parameters

    since 1.9.1

    View full-size slide

  42. 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 full-size slide

  43. asakusarb/action_args

    View full-size slide

  44. 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 full-size slide

  45. 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 full-size slide

  46. 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 full-size slide

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

    View full-size slide

  48. 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 full-size slide

  49. 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 full-size slide

  50. 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 full-size slide

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

    View full-size slide

  52. 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 full-size slide

  53. 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 full-size slide

  54. 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 full-size slide

  55. 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 full-size slide

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

    View full-size slide

  57. 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 full-size slide

  58. A pitfall I found

    View full-size slide

  59. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  63. kwargs and Rails (:end)

    View full-size slide

  64. 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 full-size slide

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

    View full-size slide

  66. Enumerable#lazy

    View full-size slide

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

    View full-size slide

  68. New Features (internal)

    TracePoint

    DTrace support

    caller_locations

    debug_inspector API

    Memory inspection features

    View full-size slide

  69. debug_inspector API

    View full-size slide

  70. The "debugger" gem

    Works on Ruby 1.9

    Partly supports 2.0

    Own header les

    View full-size slide

  71. We created a new gem

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

    Based on new debugger API

    View full-size slide

  72. Debugger2 gem

    "1.0.0.beta2"

    Still buggy on Rails

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

    View full-size slide

  73. We want debugger!!!

    View full-size slide