Road to white mages

Road to white mages

Tama Ruby会議01
白魔術士への道
2019.7.6
https://tama-rb.github.io/tamarubykaigi01/

5ad0bb268dd2605b09165d464308cb7e?s=128

Kuniaki IGARASHI

July 06, 2019
Tweet

Transcript

  1. 9.

    ͳͥTracePoint Λ࢖͏ͱ͋Ϳͳ͍ͷ͔ʁ ॳา͔Βઆ໌͞ΕΔػձ͸͋·Γͳ͍ ͳͥRubyKaigi LTͰʮTracePoint Bomb!ʯͱ͍ ͏λΠτϧ͕ग़͚ͨͩͰΈΜͳരস͢Δͷ͔ ࠇຐज़͸ڧྗ͕ͩҙਤ͠ͳ͍ಈ࡞΋Ҿ͖ى͜͢Մೳੑ͕͋Δ • TracePoint͸ϩʔΧϧม਺Λ্ॻ͖Ͱ͖Δ

    • ͜ͷ্ॻ͖Λ໭͠๨ΕΔϧʔτ͕9ϲ݄ޙ൑໌ • ૝ఆ͠ͳ͍޿͍ൣғͰϩʔΧϧม਺্͕ॻ͖ • ͦͷόά͕ൃݟ͞Εͨͱ͖ͷք۾ͷ༷ࢠ https://speakerdeck.com/koic/the-tracepoint-bumb
  2. 14.

    σόοΨͷ࢖͍ํ ϓϩάϥϜΛ࣮ߦ్தͰҰ࣌ఀࢭͯ͠ϓϩάϥϜΛ࣮ߦ͢Δ • binding.irb Ruby௒ೖ໳ P.62 • pry gem Ruby௒ೖ໳

    P.241 • binding.pry • step ࣮ߦ pry-byebug gem • ιʔεදࣔ pry-doc gem • pry on • $ prying=true rspec spec/a_spec.rb • pry off • $ rspec spec/a_spec.rb ifͰON/OFF͢Δͱָ ؀ڥม਺ͰON/OFF͢Δͱָ
  3. 15.

    ͋ͳͨ͸୭Ͱ͔͢ʁ ΦϒδΣΫτΛ஌Δ • class ϝιου Ruby௒ೖ໳ P.178 • ΦϒδΣΫτͷΫϥεΛ஌Δ •

    object_id ϝιου Ruby௒ೖ໳ P.128, 269 • ΦϒδΣΫτͷࣝผ൪߸Λ஌Δ Integer Float String Hash 2 1.2 "abc" {coffee: 300, caffe_latte: 400}
  4. 18.

    ͋ͳͨ͸Ͳ͔͜Βདྷ·͔ͨ͠ʁ ιʔείʔυฤ • Object#method, Module#instance_method • MethodΦϒδΣΫτऔಘ • MethodΦϒδΣΫτͰ࢖͑Δϝιου •

    source_location: ఆٛ͞Ε͍ͯΔϑΝΠϧ • owner: ఆٛ͞Ε͍ͯΔΫϥε • parameters: Ҿ਺৘ใ method(:pp).source_location #=> ["/Users/igaiga/.rbenv/versions/2.6.2/lib/ruby/2.6.0/pp.rb", 582] method(:pp).owner #=> Kernel require "time" Time.instance_method(:httpdate).source_location #=> ["/Users/igaiga/.rbenv/versions/2.6.2/lib/ruby/2.6.0/time.rb", 691] Time.instance_method(:succ).source_location #=> nil # RubyͰॻ͔Ε͍ͯͳ͍ωΠςΟϒͳϝιου͸nil
  5. 19.

    ͋ͳͨ͸Ͳ͔͜Βདྷ·͔ͨ͠ʁ gemฤ • gemιʔείʔυ͕ஔ͍ͯ͋Δ৔ॴ • gem which • bundle show

    • bundle open • ࢦఆ͞ΕͨΤσΟλͰ։͘ • ؀ڥม਺ EDITOR or BUNDLER_EDITOR Ͱࢦఆ
  6. 20.

    ͋ͳͨ͸Ͳ͔͜Βདྷ·͔ͨ͠ʁ ݺͼग़͠ݩฤ • Kernel#caller • ϝιουݺͼग़͠ཤྺΛදࣔ • Kernel#caller_locations • callerͷ݁ՌΛ

    Thread::Backtrace::LocationͰऔಘ • Exception#backtrace • ͦͷException͕raise͞Εͨͱ͖ͷϝιουݺͼग़͠ཤྺΛදࣔ
  7. 21.

    ΦϒδΣΫτΛมߋ͢Δ ͍͍ͩͨͷ͜ͱ͸Ͱ͖Δ • instance_variables Ruby௒ೖ໳ P.198 • Πϯελϯεม਺ҰཡΛऔಘ • instance_variable_get,

    instance_variable_set • Πϯελϯεม਺Λऔಘɺվ͟Μ • instance_eval, class_eval • ͦͷΦϒδΣΫτʹͳΓ͖࣮ͬͯߦ͢Δ • Πϯελϯεม਺Λ͍͡Δͱ͖ʹ΋ศར • privateϝιουΛݺͼग़͢ͱ͖ʹ΋ศར • sendϝιουΛ࢖͏ख΋͋Δ • bindingΛ࢖͏ͱϩʔΧϧม਺ΛมߋͰ͖Δ • લड़ͷ joker&moris ߨԋࢀর
  8. 22.

    ιʔείʔυͷੈքɺΦϒδΣΫτͷੈք σόοά͕೉͍͠ͷ͸2ͭͷੈքʹִͨΓ͕͋Δ͔Β • ԋܶͰྫ͑Δͱ • ιʔείʔυ͸୆ຊ • ࢲ͕ͨͪॻ͚Δͷ͸୆ຊ • ΦϒδΣΫτͷੈք͸෣୆

    • ࣮ࡍʹϓϩάϥϜ͕ಈ͍͍ͯΔͷ͸͜͜ • ࢲͨͪ͸͜͜Ͱࣗ෼͕ԋ͡Δ͜ͱ΋ɺ؍Δ͜ͱ΋Ͱ͖ͳ͍ ΦϒδΣΫτͷੈք ➡ ιʔείʔυͷੈք ➡ p 1+2 1 + 2
  9. 23.

    ιʔείʔυͷੈքɺΦϒδΣΫτͷੈք ม਺͸ΦϒδΣΫτͷ໊ࡳɺ໊લॏཁ Ruby௒ೖ໳ P.53 ม਺orderʹ "ΧϑΣϥς" ΦϒδΣΫτΛ୅ೖ ʹ "ΧϑΣϥς" ΦϒδΣΫτʹ

    ม਺orderͱ͍͏໊લΛ෇͚Δ "ΧϑΣϥς" PSEFS ʮ໊લʯ͸ιʔείʔυͷੈք͔ΒΦϒδΣΫτͷੈքʹ͍ ΔʮͦͷΦϒδΣΫτʯΛݺͿʢ΄΅ʣ།Ұͷ࢓૊Έ ΦϒδΣΫτͷੈք ➡ ιʔείʔυͷੈք ➡ ༷ʑͳखஈͰΦϒδΣΫτͷੈքʢ෣୆ʣͷ༷ࢠΛ ஌Δํ๏Λ͜ͷ͋ͱઆ໌͍͖ͯ͠·͢ɻ
  10. 26.

    ʮ΍ͭ͸େมͳ΋ͷΛ౪ΜͰ͍͖·ͨ͠ɻ ͋ͳͨͷΠϯελϯεม਺Ͱ͢ɻʯ • ͪͳΈʹάϩʔόϧม਺͸ Kernel#trace_var ͕͋Δ • Πϯελϯεม਺͸ΦϒδΣΫτͰ͸ͳ͍ • ίʔυ:

    https://github.com/igaiga/tmrk01/ ୊ࡐɿʮRailsͷCRUD indexΞΫγϣϯͰɺ@books Πϯε λϯεม਺͕ [] ʹͳ͍ͬͯͯදࣔ಺༰͕ҙਤ௨ΓͰ͸ͳ͍ʯ ਖ਼͍͠ಈ࡞ ʮΠϯελϯεม਺΁ͷ୅ೖΛݕ஌͢Δʯํ๏Λߟ͑Δ ݱঢ়ͷಈ࡞
  11. 29.

    TracePoint TracePointΛ͔͚ͯ͠શͯͷࣜධՁʹॲཧΛڬΉ TracePoint.trace ʹ :line Λ౉͢ͱɺࣜධՁ࣌ʹϒϩοΫ࣮ߦ ϒϩοΫͷม਺tpͰड͚औΔTracePointΦϒδΣΫτ͔Β৘ใऔಘ tp.methods ΍ΔΓ·Ͱ͍࣋ͬͯΔϝιουΛௐ΂Δ P.123

    • event • τϦΨʔ • path • ιʔεύε • lineno • ߦ൪߸ • method_id • ϝιου • defined_class • Ϋϥε ↙ [TP:line] test.rb:3 hi User ⬆ TracePointΦϒδΣΫτͷ৘ใදࣔ ⬅ @hi ΁୅ೖ 3ߦ໨ User#hi ⬇ |tp| TracePointΦϒδΣΫτ
  12. 31.

    TracePoint ࣜͷݩʹͳͬͨιʔείʔυΛಘΔ TracePointΦϒδΣΫτʹ͸ιʔείʔυ৘ใ͕ͳ͍ ධՁ͞Εͨࣜͷ path, lineno ͸෼͔Δ ➡ path, lineno

    ͔ΒιʔείʔυΛऔΕͦ͏ " @hi = \"hi(ŇŋωŋŇ)ϊ\"\n" ιʔείʔυτϨλ ⬆ ιʔεϑΝΠϧ͔Βιʔείʔυऔಘ
  13. 35.

    node.methodsͰ࣋ͬͯΔϝιουΛ୳ͯ͠ௐ΂Δ P.189 node #=> (SCOPE@1:0-1:33 tbl: [] args: nil body:

    (IASGN@1:4-1:33 :@hi (STR@1:10-1:33 "hi(ŇŋωŋŇ)ϊ"))) node.class #=> RubyVM::AbstractSyntaxTree::Node node.type #=> :SCOPE node.children #=> [[], nil, (IASGN@1:4-1:33 :@hi (STR@1:10-1:33 "hi(ŇŋωŋŇ)ϊ"))] node.children.last.class #=> RubyVM::AbstractSyntaxTree::Node node.children.last.type #=> :IASGN RubyVM::AbstractSyntaxTree.parse(" @hi = \"hi(ŇŋωŋŇ)ϊ\"\n") RubyVM::AbstractSyntaxTree AST::NodeΦϒδΣΫτͷߏ଄ RubyVM::AbstractSyntaxTree::NodeΦϒδΣΫτ͕ੵ૚
  14. 36.

    node.children.last #=> (IASGN@1:4-1:33 :@hi (STR@1:10-1:33 "hi(ŇŋωŋŇ)ϊ")) node.children.last.type #=> :IASGN RubyVM::AbstractSyntaxTree.parse("

    @hi = \"hi(ŇŋωŋŇ)ϊ\"\n") RubyVM::AbstractSyntaxTree AST::NodeΦϒδΣΫτͷߏ଄ IASGNΛRubyͷιʔείʔυͳͲͰௐ΂ͯΈΔ IASGN #=> Πϯελϯεม਺΁ͷ୅ೖ RubyVM::AbstractSyntaxTree::Node ৄࡉ - siman https://qiita.com/siman/items/3017ed399ded43229189
  15. 38.

    TracePoint ࢦఆΫϥεͷΠϯελϯεม਺୅ೖΛݕ஌ tp.self : ΠϕϯτΛൃੜͤͨ͞ΦϒδΣΫτ tp.self.is_a?(Ϋϥε) ͰࢦఆΫϥε͔Ͳ͏͔νΣοΫ ↙ Kernel.const_get(target_class_name) "User"

    Λ UserΫϥε΁ ※tp.self͸ʮͲͷΫϥεͰ࣮ߦ͞Ε͍ͯΔॲཧ͔ʯͳͷͰɺincludeͨ͠ModuleͰ୅ೖͯ͠ ͍Δέʔε΋໰୊ͳ͘ಈ͘ɻΫϥε֎ͰΠϯελϯεม਺୅ೖʢՄೳʁʣ͢Δͱμϝ͔΋ɻ ⬅ is_a? ϝιουͰͦͷΫϥε͔൑ఆ
  16. 42.

    RailsΞϓϦͷ४උ • ୊ࡐ: ʮRailsͷڭՊॻʯͰ࡞͍ͬͯΔΞϓϦ • https://tatsu-zine.com/books/rails-textbook • ॻ੶؅ཧΞϓϦ • BookϞσϧ(title,

    memo)ͷCRUD • rails g scaffold book title:string memo:text • https://github.com/igaiga/tmrk01/missing_instance_variables_sample_rails_app • config/initializers ҎԼʹݕ஌ίʔυ഑ஔʢ࣍ϖʔδઆ໌) • /books ΁ΞΫηε(indexΞΫγϣϯ) • app/views/books/index.html.erb • <% @books.each do |book| %> ⬅ ୅ೖݕ஌ର৅ @books • app/controllers/books_controller.rb:7 Ͱ୅ೖ͞Ε͍ͯΔ • @books = Book.all ⬅ @books ୅ೖίʔυ
  17. 43.

    Πϯελϯεม਺୅ೖݕ஌ config/initializers ΁ݕ஌ίʔυ഑ஔ ίϯτϩʔϥͰ୅ೖ͞ΕͯΔ͍Δ৔߹ શͯͷΫϥεͰͷ࣮ߦΛௐ΂ΔͨΊ Ϋϥε໊͸ࢦఆͤͣʹ Πϯελϯεม਺໊͚ͩࢦఆ Started GET "/books"

    for ::1 at 2019-06-08 12:34:50 +0900 Processing by BooksController#index as HTML @books is assigned in /path_to_app/app/controllers/books_controller.rb:7 index BooksController Rendering books/index.html.erb within layouts/application Book Load (6.8ms) SELECT "books".* FROM "books" ↳ app/views/books/index.html.erb:15 Rendered books/index.html.erb within layouts/application (249.2ms) Completed 200 OK in 2933ms (Views: 2800.7ms | ActiveRecord: 6.8ms) /books ΁ΞΫηεͨ͠ϩά ൜ਓ͕͍ͳ͍ૉͷίʔυͰςετ ⬇ίϯτϩʔϥͰͷਖ਼ৗ୅ೖݕ஌੒ޭ @books ୅ೖݕ஌ίʔυ
  18. 44.

    Πϯελϯεม਺୅ೖݕ஌ ίϯτϩʔϥʹ൜ਓ͕͍ͨέʔε Started GET "/books" for ::1 at 2019-06-08 13:02:25

    +0900 Processing by BooksController#index as HTML @books is assigned in /path_to_app/app/controllers/books_controller.rb:7 index BooksController @books is assigned in /path_to_appapp/controllers/books_controller.rb:8 index BooksController Rendering books/index.html.erb within layouts/application Rendered books/index.html.erb within layouts/application (50.2ms) Completed 200 OK in 3146ms (Views: 2867.5ms | ActiveRecord: 0.0ms) /books ΁ΞΫηεͨ͠ϩά ⬆ ݕ஌!! ⬅ books_controller.rb:8 books_controller.rb:7,8 Ͱͷ୅ೖݕ஌͕Ͱ͖ͨ ൜ਓ֬อ!! ⬅ books_controller.rb:7
  19. 45.

    Πϯελϯεม਺୅ೖݕ஌ ݕ஌Ͱ͖ͳ͍έʔε͕͋Δ Started GET "/books" for ::1 at 2019-06-08 12:55:09

    +0900 Processing by BooksController#index as HTML @books is assigned in /path_to_app/app/controllers/books_controller.rb:7 index BooksController Rendering books/index.html.erb within layouts/application Rendered books/index.html.erb within layouts/application (83.2ms) Completed 200 OK in 2881ms (Views: 2742.1ms | ActiveRecord: 0.0ms) /books ΁ΞΫηεͨ͠ϩά ⬇ίϯτϩʔϥͰͷ୅ೖ͸ݕ஌ ⬅ books_controller.rb:7 books_controller.rb:7 Ͱʢਖ਼ৗͳʣ୅ೖݕ஌͸Ͱ͖͍ͯΔ ൜ਓͷݕ஌͸ Ͱ͖͍ͯͳ͍
  20. 46.

    Πϯελϯεม਺୅ೖݕ஌ ͜ͷํ๏Ͱ͸ViewͰͷ୅ೖΛݕ஌Ͱ͖ͳ͔ͬͨ app/view/books/index.html.erb <% @books = [] %> ... <%

    @books.each do |book| %> ⬅ ൜ਓ͕Viewʹ͍Δͱ͖ɺ͜ͷ୅ೖΛݕ஌Ͱ͖ͳ͍ line #=> "<% @books= [] %>\n" erbͳͷͰલޙʹ <% %> ͕෇͍͍ͯΔ ※ݟ౰ҧ͍ͯͯ͠ղܾʹ1ϲ݄͔͔ͬͨ ݪҼ RubyVM::AbstractSyntaxTree.parse(line).children.last #=> SyntaxError
  21. 47.

    Πϯελϯεม਺୅ೖݕ஌ erbରԠ લޙʹ <% %> ͕෇͍͍ͯͨΒ֎͢ ↖ line = match_data.captures.first

    ↙ line.match(/\A\s*<%=*(.*)%>\s*\z/) Ruby௒ೖ໳ P. 271 ਖ਼نදݱ ASTऔಘΑΓޙΖ͸ಉ͡ ਖ਼نදݱதͷ(.*)෦෼औಘ https://docs.ruby-lang.org/ja/latest/class/MatchData.html
  22. 48.

    Πϯελϯεม਺୅ೖݕ஌ erbରԠ Started GET "/books" for ::1 at 2019-06-09 09:55:08

    +0900 (12.4ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC ↳ /Users/igaiga/.rbenv/versions/2.6.3/lib/ruby/gems/2.6.0/gems/activerecord-5.2.3/lib/active_record/ log_subscriber.rb:98 Processing by BooksController#index as HTML @books is assigned in /path_to_app/app/controllers/books_controller.rb:7 index BooksController Rendering books/index.html.erb within layouts/application @books is assigned in /path_to_app/app/views/books/index.html.erb:1 _app_views_books_index_html_erb__4042701126060758541_70158372829520 ActionView::CompiledTemplates Rendered books/index.html.erb within layouts/application (76.8ms) Completed 200 OK in 13765ms (Views: 13457.4ms | ActiveRecord: 0.0ms) ൜ਓ֬อ!! ↖index.html.erb:1 <% @books = [] %>
  23. 49.

    നຐज़ೖ໳ ʮ౪·ΕͨΠϯελϯεม਺ʯ·ͱΊ • Πϯελϯεม਺୅ೖݕ஌खॱͷҰྫ • TracePoint :line ͰϑοΫ • TracePointͷ৘ใ͔ΒιʔεϑΝΠϧऔಘ

    • RubyVM::AbstractSyntaxTree.parseͰղੳ • Πϯελϯεม਺୅ೖ͸IASGN • ͜͜Ͱग़͖ͯͨιʔείʔυ • https://github.com/igaiga/tmrk01 • instance_variable_tracer gem ͱͯ͠ެ։ • https://github.com/igaiga/instance_variable_tracer
  24. 51.

    Tracerඪ४ఴ෇ϥΠϒϥϦ ϩάग़ྗ https://docs.ruby-lang.org/ja/latest/class/Tracer.html தͰ Kernel.#set_trace_func Λར༻ શ࣮ߦߦϩά(ιʔείʔυೖΓ)ΛϑΝΠϧग़ྗͯ͠grepͰௐ΂Δ log.txt ... #1:/path_to_app/app/views/books/index.html.erb:1:ActionView::CompiledTemplates:-:

    <%= @books = [] %> ... Tracer.add_filter do |event, file, line, id, binding, klass| file == "/path_to_app/app/views/books/index.html.erb" end Tracer.on ϑΟϧλʔ͢Δ͜ͱ΋Մೳ ϑΟϧλʔதͰ͸ιʔείʔυΛ௚઀औΕͳ͍ʢ͸ͣʣ = TracePointͱಉ͘͡ඞཁͳΒιʔεϑΝΠϧ͔Βऔಘ
  25. 55.

    station_signage gem with g https://github.com/igaiga/station_signage application_controller.rb before_action { g "#{self.class.name}##{action_name}"

    } gem "g" gem "terminal-notifier" ⬆g gem͕಺෦Ͱར༻͢Δgem ΍ͬͯΔ͜ͱ ϦΫΤετͨ͠ϖʔδͷίϯτϩʔϥ໊ɺΞΫγϣϯ໊Λදࣔ
  26. 56.

    signal & trap ࣌ؒ࣠Ͱσόοά ⬅ infoγάφϧΛड͚औΔͱಈ͘ macͰ͸ ctrl-T Ͱ infoγάφϧΛൃੜ

    ·ͨ͸ $ kill -s info [pid] http://tenderlovemaking.com/2016/02/05/i-am-a-puts-debuggerer.html
  27. 63.
  28. 65.

    ࢀߟࢿྉ • Hijacking Ruby Syntax in Ruby • https://www.youtube.com/watch?v=04HGQEw3A6Y •

    RubyVM::AbstractSyntaxTree::Node ৄࡉ • https://qiita.com/siman/items/3017ed399ded43229189 • I am a puts debugger • http://tenderlovemaking.com/2016/02/05/i-am-a-puts-debuggerer.html • Ruby Debugging Magic Cheat Sheet • https://www.schneems.com/2016/01/25/ruby-debugging-magic-cheat-sheet.html • rubyͰ͍͍͔Μ͡ʹDI͢Δhabuͷ঺հ • https://qiita.com/hanachin_/items/8aa4bd82258bb19b7f91 • †Rubyࠇຐज़ܦయ† • https://speakerdeck.com/joker1007/rubyhei-mo-shu-jing-dian • Railsdm Podcast unasuke.fm #5 Ruby Tendency • https://soundcloud.com/railsdm
  29. 66.

    ँࣙ (ܟশུ) Ғେͳࠇຐज़ࢣͷΈͳ͞Μ joker, moris, koic, hanachin, siman, alitaso ૬ஊʹ৐ͬͯͩͬͨ͘͞Έͳ͞Μ

    ko1, mame, _tad_ ωλΛఏڙͯ͘͠ΕͨΈͳ͞Μ aaron, jugyo Ruby௒ೖ໳νʔϜͷΈͳ͞Μ machu, beco ࢲ͕RubyΛ࢝ΊΔ͖͔͚ͬʹͳͬͨtDiary։ൃνʔϜͷΈͳ͞Μ tdtds, hsbt, machu ࠓ೔ͷ४උΛͯ͘͠ΕͨελοϑͷΈͳ͞Μ
  30. 67.

    ੒Ռ • bugs.ruby-lang ىථ "Tracing instance variable assignment" • https://bugs.ruby-lang.org/issues/15854

    • instance_variable_tracer gem ࡞੒ • https://github.com/igaiga/station_signage • station_signage gem ࡞੒ • https://github.com/igaiga/station_signage • RubyConf୆࿷ CFP ࠾୒ • Rubyͷ஌ࣝ
  31. 68.

    ޒेཛྷ๜໌/igaiga ࣗݾ঺հ ৽͍͠࢓ࣄ͸ืू͍ͯ͠·ͤΜ͕ɺࡳଋͷ͝༻ҙ͕͋Δํ͸͓੠͔͚͍ͩ͘͞ ϑϦʔϥϯεRails/RubyΤϯδχΞ औҾઌ: NaCl͞Μ, ϐΫγϒ͞Μ, OSCR͞Μ, IDCϑϩϯςΟΞ͞Μ, Classi͞Μ,

    αΠόʔηΩϡϦςΟΫϥ΢υ͞Μ, GMOϖύϘ͞Μ ஶॻ: ʮθϩ͔ΒΘ͔ΔRuby௒ೖ໳ʯʮRailsͷڭՊॻʯ ʮRubyͱRailsͷֶशΨΠυʯ https://twitter.com/igaiga555
  32. 69.
  33. 71.