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

Re: Power Assert in Ruby

k_tsj
November 08, 2015

Re: Power Assert in Ruby

k_tsj

November 08, 2015
Tweet

More Decks by k_tsj

Other Decks in Programming

Transcript

  1. RE: POWER ASSERT
    IN RUBY
    Kazuki Tsujimoto

    View Slide

  2. ࣗݾ঺հ
    • “VM Bug Hunter”
    • ॳAsakusa.rb

    View Slide

  3. • Ξαʔγϣϯϝιου/Ϛονϟͷ࢖͍෼͚ʹ೰·ͣʹ
    ςετΛॻ͚ΔΑ͏ʹ͢ΔͨΊpower_assertΛ࡞ͬͨ
    • assert {expr}͚͍֮ͩ͑ͯΕ͹Α͍
    • 1==3ͷ໭Γ஋͕දࣔ͞Ε͍ͯͳ͍ͱ͍͏໰୊͕͋Δ
    $ ruby test_example.rb
    assert { [0, 1, 2].find {|i| i.odd? } == 3 }
    |
    1
    POWER ASSERT IN RUBY

    View Slide

  4. • ࣮૷ʹ࢖͍ͬͯΔTracePointͷ੍໿
    • ϝιουݺͼग़͠ͷ࠷దԽʹΑͬͯɺΠϕϯτ͕ىಈ
    ͞Εͳ͘ͳ͍ͬͯΔ
    • ࣄલʹpower_assertΛrequireͯ͠࠷దԽΛແޮԽ͢Ε
    ͹Α͍͕ɺ͜Ε͸खؒ
    $ ruby -rpoewr_assert test_example.rb
    assert { [0, 1, 2].find {|i| i.odd? } == 3 }
    | |
    | false
    1
    POWER ASSERT IN RUBY

    View Slide

  5. • akr͞Μ͔Β࠷దԽର৅ͱͳΔϝιουΛʮ͜
    ͱ͝ͱ͘࠶ఆٛͯ͠ݩʹ໭ͯ͠͠·ʯ͑͹Α
    ͍ͷͰ͸ͳ͍͔ͱͷࢦఠ
    • ࣄલrequireΛෆཁʹ͢Δ͜ͱ͸Ͱ͖Δͷ͔
    POWER ASSERT IN RUBY

    View Slide

  6. ໰୊
    • 1 == 3ͷ==ϝιουݺͼग़͠ͷΠϕϯτ͕र
    ͑ͳ͍
    trace = TracePoint.new(:return, :c_return) {|tp|
    p tp.method_id
    }
    trace.enable {
    1 == 3
    }

    View Slide

  7. ݪҼ
    • Fixnum#==ͳͲͷجຊతͳϝιου͸ಛघ
    έʔεѻ͍Ͱ؆ུԽͨ͠ॲཧΛ͍ͯ͠ΔͨΊ
    if (FIXNUM_2_P(recv, obj) &&
    BASIC_OP_UNREDEFINED_P(BOP_EQ, FIXNUM_REDEFINED_OP_FLAG)) {
    return (recv == obj) ? Qtrue : Qfalse;
    }
    else if(...) {
    ...
    }
    ...
    CALL_SIMPLE_METHOD(recv);
    ಛघέʔε(1)
    ಛघέʔε(..N)
    Ұൠέʔεɹ

    View Slide

  8. ରࡦ
    • ૉ௚ͳΞϓϩʔν(࠶ఆٛͰϑϥάΛཱͯΔ)
    • Fixnum.method_addedΛϢʔβ͕ఆٛͯ͠
    ͍Δ৔߹ͳͲʹӨڹ͕ग़Δ
    class Fixnum
    alias eq_orig ==
    def ==(other)
    eq_orig(other)
    end
    alias == eq_orig
    end

    View Slide

  9. ରࡦ
    • ࠾༻ͨ͠Ξϓϩʔν(࠶ఆٛҎ֎ͰϑϥάΛཱͯΔ)
    • ՄࢹੑΛ໌ࣔతʹઃఆ͢Δ(Ruby 2.0ʙ2.2)
    • refine͢Δ(Ruby 2.0ʙ2.3dev)
    class Fixnum
    public :==
    end
    module M
    refine Fixnum do
    def ==; end
    end
    end

    View Slide

  10. ଓɾ໰୊
    • C.new == C.newͷ==ϝιουݺͼग़͠ͷΠ
    ϕϯτ͕र͑ͳ͍
    trace = TracePoint.new(:return, :c_return) {|tp|
    p tp.method_id
    }
    class C; end
    trace.enable {
    C.new == C.new
    }

    View Slide

  11. ଓɾݪҼ
    • ϝιουͷ࣮ମ͕ಛఆͷCؔ਺(rb_obj_equal)
    ͩͬͨͱ͖͸ಛघέʔεѻ͍Ͱ؆ུԽͨ͠ॲ
    ཧΛ͍ͯ͠ΔͨΊ
    ...
    vm_search_method(ci, cc, recv);
    if (check_cfunc(cc->me, rb_obj_equal)) {
    return recv == obj ? Qtrue : Qfalse;
    }
    ...
    CALL_SIMPLE_METHOD(recv);

    View Slide

  12. ଓɾରࡦ
    • ૉ௚ͳΞϓϩʔν
    • ϝιουΛ࠶ఆٛͯ͠ݩʹ໭͞ͳ͍
    • BasicObject.method_added(ུ)
    • ϞϯΩʔύον͕ద༻͞Εͨঢ়ଶͰϢʔβίʔυ͕࣮ߦ͞
    Εͯ͠·͏
    class BasicObject
    alias eq_orig ==
    def ==(other); eq_orig(other); end
    alias == eq_orig
    end

    View Slide

  13. ଓɾରࡦ
    • ࠾༻ͨ͠Ξϓϩʔν
    • refine͢Δ(refine͞Ε͍ͯΔ͜ͱΛࣔ͢ಛघͳϝιου
    ΤϯτϦΛrb_obj_equalͷલʹૠೖ͢Δ)
    • ͲͪΒͷΞϓϩʔνͰ΋Rubyͷඪ४Ϋϥεʹ͍ͭͯ͸ࣄલʹ
    ରԠ͓ͯ͘͜͠ͱ͕Մೳ͕ͩɺC֦ுͰ࡞੒ͨ͠Ϣʔβఆٛ
    Ϋϥε·Ͱ͸ٹ͑ͳ͍ͱ͍͏՝୊͸࢒Δ
    module M
    refine BasicObject do
    def ==; end
    end
    end

    View Slide

  14. ଓʑɾ໰୊
    • C.new == C.newͷ==ϝιουݺͼग़͠ͷΠ
    ϕϯτ͕1ճ͔͠र͑ͳ͍
    trace = TracePoint.new(:return, :c_return) {|tp|
    p tp.method_id
    }
    class C; end
    trace.enable {
    loop {
    C.new == C.new
    }
    }

    View Slide

  15. ଓʑɾݪҼ
    • 1ճ໨ͷݺͼग़࣌͠ʹʮ࠷ऴతʹrb_obj_equalΛݺͿʯ
    ͱ͍͏৘ใΛΠϯϥΠϯΩϟογϡʹ࣋ͬͯ͠·͏ͨΊ
    Lightweight Method Dispatch on MRI(Koichi Sasada)͔ΒҾ༻

    View Slide

  16. ଓʑɾରࡦ
    • దٓΩϟογϡΛΫϦΞ͢Ε͹Α͍
    • power_assertͰ͸assertʹ౉͞ΕͨϒϩοΫΛݺ
    ͼग़͢λΠϛϯάͰΫϦΞ
    • ΩϟογϡͷΫϦΞʹ΋RefinementsΛར༻
    • ۭϞδϡʔϧΛusing

    View Slide

  17. ·ͱΊ
    • power_assertͷࣄલrequire͸΄΅ෆཁʹ
    • ׬શͰ͸ͳ͍͕௨ৗͷϢʔεέʔε͸Χόʔ
    • Rubyͷ಺෦࣮૷ʹڧ͘ґଘ͓ͯ͠Γࠓޙ΋ಈ࡞
    ͢Δ͔͸ෆಁ໌
    • Ҿ͖ଓ͖ࣄલrequireΛਪ঑

    View Slide