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

如何使用 byebug 來除錯 Ruby 程式

Johnlin
August 02, 2020

如何使用 byebug 來除錯 Ruby 程式

Johnlin

August 02, 2020
Tweet

More Decks by Johnlin

Other Decks in Programming

Transcript

  1. ᮫ԙզ • John Lin • Twitter: @johnlinvc • Senior Solution

    Architect, DevOps 
 @ West Pharmaceutical Service (୆ᖯҖ๏෰຿)
  2. ྖંၢ݊ coupon.rb def get_coupon(user_id, history) if history[user_id] = true return

    0 end history[user_id] = true 3000 end puts get_coupon(1, {}) Ṝछศᑍࢴཫ౎ੋఔࣜᛰ
  3. ྖંၢ݊ coupon.rb $ ruby coupon.rb 0 def get_coupon(user_id, history) if

    history[user_id] = true return 0 end history[user_id] = true 3000 end puts get_coupon(1, {}) Ṝछศᑍࢴཫ౎ੋఔࣜᛰ →৭ᐽཫੋbash/byebug ࿨༬ظෆಉɼጯ֘ཁ༌ग़ 3000
  4. ༻ puts ֬ೝఔࣜ။ෆ။ඃࣥߦ౸ def get_coupon(user_id, history) if history[user_id] = true

    return 0 end puts "here" history[user_id] = true 3000 end puts get_coupon(1, {}) ೗Ռ༗ࣥߦ౸Ṝཫब။༌ग़ here
  5. ༻ puts ֬ೝఔࣜ။ෆ။ඃࣥߦ౸ $ ruby coupon_here.rb 0 def get_coupon(user_id, history)

    if history[user_id] = true return 0 end puts "here" history[user_id] = true 3000 end puts get_coupon(1, {}) ೗Ռ༗ࣥߦ౸Ṝཫब။༌ग़ here ᔒ༗ hereɼ
 ॴҎᔒ༗ࣥߦ౸ਖ਼֬తҐஔ
  6. byebug • ໋ྩྻత Ruby আࡨثɻ • ࢖༻ TracePoint API ိሣ

    Ruby ఔࣜআࡨɻ • ࢧԉ MRI Ruby 2.4.0 Ҏ্ɻ ෆࢧԉ jruby, rubinius ౳ଖଞ Ruby ௚ᩄثɻ
  7. ࢖༻ byebug root@coscup:/app# byebug coupon.rb [1, 9] in /app/coupon.rb =>

    1: def get_coupon(user_id, history) 2: if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug)
  8. ᙘ໘ղ㘸 root@coscup:/app# byebug coupon.rb [1, 9] in /app/coupon.rb => 1:

    def get_coupon(user_id, history) 2: if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) 䈕໊᪑ߦᏐൣᅴ
  9. ᙘ໘ղ㘸 root@coscup:/app# byebug coupon.rb [1, 9] in /app/coupon.rb => 1:

    def get_coupon(user_id, history) 2: if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) ఔࣜᛰ࿨ߦᥒ
  10. ᙘ໘ղ㘸 root@coscup:/app# byebug coupon.rb [1, 9] in /app/coupon.rb => 1:

    def get_coupon(user_id, history) 2: if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) ඪࣔ໨લ
 ఀࢭҐஔ
  11. ᙘ໘ղ㘸 root@coscup:/app# byebug coupon.rb [1, 9] in /app/coupon.rb => 1:

    def get_coupon(user_id, history) 2: if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) prompt ɼඪࣔ䬟زߦੋզ၇༌ೖతࢦྩ
  12. ཭։ byebug [1, 9] in /app/coupon.rb => 1: def get_coupon(user_id,

    history) 2: if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) quit Really quit? (y/n) y root@coscup:/app#
  13. help (byebug) help break -- Sets breakpoints in the source

    code catch -- Handles exception catchpoints condition -- Sets conditions on breakpoints continue -- Runs until program ends, hits a breakpoint or reaches a line debug -- Spawns a subdebugger delete -- Deletes breakpoints disable -- Disables breakpoints or displays display -- Evaluates expressions every time the debugger stops down -- Moves to a lower frame in the stack trace edit -- Edits source files enable -- Enables breakpoints or displays finish -- Runs the program until frame returns frame -- Moves to a frame in the call stack help -- Helps you using byebug history -- Shows byebug's history of commands info -- Shows several informations about the program being debugged interrupt -- Interrupts the program irb -- Starts an IRB session kill -- Sends a signal to the current process list -- Lists lines of source code method -- Shows methods of an object, class or module next -- Runs one or more lines of code pry -- Starts a Pry session quit -- Exits byebug restart -- Restarts the debugged program save -- Saves current byebug session to a file set -- Modifies byebug settings show -- Shows byebug settings skip -- Runs until the next breakpoint as long as it is different from the current one source -- Restores a previously saved byebug session step -- Steps into blocks or methods one or more times thread -- Commands to manipulate threads
  14. help • byebug ༗㚎ݐ㘸໌ࢦྩɻ • ࡏ prompt ༌ೖ help बՄҎ؃౸ࢦྩྻදɻ

    • ࡏ prompt ༌ೖ help <ࢦྩ> बՄҎ؃౸ࢦྩత㘸໌ɻ (byebug) help (byebug) help help
  15. h[elp] (byebug) help help h[elp][ <cmd>[ <subcmd>]] Helps you using

    byebug help -- prints a summary of all commands help <cmd> -- prints help on command <cmd> help <cmd> <subcmd> -- prints help on <cmd>'s subcommand <subcmd> [ ] 㚎త෦෼ੋબᎩੑతɼॴҎ໵ՄҎ୞ଧ h
  16. l[ist] • ؃ݱࡏࣥߦ౸䬟Ұߦࢦྩɻ။༌ग़ෟۙతزߦɻ (byebug) list [1, 9] in /app/coupon.rb =>

    1: def get_coupon(user_id, history) 2: if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {})
  17. b[reak] • ཁٻ byebug ࡏࣥߦ౸ࢦఆߦᏐલఀԼိɻఀԼိతҐஔɼ ላ໊ڣ၏ ”தᏗᴍ“
 • ໵ՄҎ༻؆ሜ b


    (byebug) break 2 Created breakpoint 1 at /app/coupon.rb:2 (byebug) b 3 Created breakpoint 3 at /app/coupon.rb:3
  18. ༻ byebug ֬ೝఔࣜ။ෆ။ඃࣥߦ౸ [1, 9] in /app/coupon.rb => 1: def

    get_coupon(user_id, history) 2: if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) break 5 Created breakpoint 1 at /app/coupon.rb:5 (byebug) ૝֬ఆ။ࣥߦୈ 5 ߦ
  19. ༻ byebug ֬ೝఔࣜ။ෆ။ඃࣥߦ౸ [1, 9] in /app/coupon.rb => 1: def

    get_coupon(user_id, history) 2: if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) break 5 Created breakpoint 1 at /app/coupon.rb:5 (byebug) ཁٻࡏࣥߦୈ 5 ߦ࣌ఀԼိ
  20. ༻ byebug ֬ೝఔࣜ။ෆ။ඃࣥߦ౸ [1, 9] in /app/coupon.rb => 1: def

    get_coupon(user_id, history) 2: if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) break 5 Created breakpoint 1 at /app/coupon.rb:5 (byebug) continue ཁٻ៺᠃ࣥߦ
  21. ༻ byebug ֬ೝఔࣜ။ෆ။ඃࣥߦ౸ [1, 9] in /app/coupon.rb => 1: def

    get_coupon(user_id, history) 2: if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) break 5 Created breakpoint 1 at /app/coupon.rb:5 (byebug) continue 0 root@coscup:/app# ᔒ༗ఀԼိब݁ଋྃɼॴҎୈ 5 ߦੋᔒ༗ࣥߦ౸తɻ
  22. [1, 9] in /app/coupon.rb 1: def get_coupon(user_id, history) => 2:

    if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) next [1, 9] in /app/coupon.rb 1: def get_coupon(user_id, history) 2: if history[user_id] = true => 3: return 0 4: end ݱࡏࣥߦ౸ୈ 2 ߦ
  23. [1, 9] in /app/coupon.rb 1: def get_coupon(user_id, history) => 2:

    if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) next [1, 9] in /app/coupon.rb 1: def get_coupon(user_id, history) 2: if history[user_id] = true => 3: return 0 4: end ࣥߦԼҰߦ
  24. [1, 9] in /app/coupon.rb 1: def get_coupon(user_id, history) => 2:

    if history[user_id] = true 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) next [1, 9] in /app/coupon.rb 1: def get_coupon(user_id, history) 2: if history[user_id] = true => 3: return 0 4: end ݱࡏࣥߦ౸ྃୈࡾߦ
  25. ෆੋ㑌ݸ஍ํ౎ೳதᏗ • ༗Ұࠣᔒ༗ࣥߦҙٛత஍ํੋෆೳதᏗతɻ૾ੋۭߦɼ end, {, }ɻ (byebug) break /app/coupon.rb:4 ***

    Line 4 is not a valid breakpoint in file /app/coupon.rb. Valid break points are: [B] 1: def get_coupon(user_id, history) [B] 2: if history[user_id] = true [B] 3: return 0 4: end ᔒ༗ඪ [B] తߦᏐແ๏தᏗ
  26. ࡏಛఆ৘گԼ break • ՄҎ୞༗ࡏಛఆత৘گԼ break • break [file:]line [if <expr>]


    (byebug) break 3 if history[user_id] Created breakpoint 5 at /app/coupon.rb:3
  27. ࡏ rails server ༻ byebug • rails 4.2 ೭ޙब༬ઃࡏ։ᚙ໛ࣜ҆᧋ byebug

    • ࡏ code ཫ࢖༻ byebug method ိࡏࣥߦఔࣜత࣌ީఀࡏ byebug ႔ɻ • ඇ rails తఔࣜ require 'byebug' ޙ໵Մ༻ byebug methodɻ • ෆա byebug method ෆࢉੋதᏗᴍɻ
  28. ࡏ rails ཫ࢖༻ byebug Started GET "/posts" for 127.0.0.1 at

    2020-08-01 12:18:37 +0000 Processing by PostsController#index as */* [3, 12] in /app/rails_example/app/controllers/ posts_controller.rb 3: 4: # GET /posts 5: # GET /posts.json 6: def index 7: byebug => 8: @posts = Post.all 9: end 10: 11: # GET /posts/1 12: # GET /posts/1.json (byebug) ။ఀࡏ byebug తԼҰߦ
  29. ࡏඇ rails ཫ࢖༻ byebug $ ruby coupon_byebug.rb [1, 10] in

    /app/coupon_byebug.rb 1: require 'byebug' 2: def get_coupon(user_id, history) 3: byebug => 4: if history[user_id] = true 5: return 0 6: end 7: history[user_id] = true 8: 3000 9: end 10: (byebug) ઌ require ࠽ೳ࢖༻ byebug
  30. ᑍ݅ࣜ byebug • code ཫత byebug बੋҰൠత ruby methodɻՄҎ์ࡏ೚ Կ஍ํɼ໵ՄҎ༻

    if ိઃఆᑍ݅ ɻ
 $ ruby coupon_byebug_cond.rb [1, 10] in /app/coupon_byebug_cond.rb 1: require 'byebug' 2: def get_coupon(user_id, history) 3: byebug if user_id == 1 => 4: if history[user_id] = true 5: return 0 ୞༗ᑍ݅ූ߹࣌࠽தᏗ
  31. ༻ puts ֬ೝᏓᏐతᆴ def get_coupon(user_id, history) if history[user_id] = true

    puts user_id puts history return 0 end history[user_id] = true 3000 end puts get_coupon(1, {}) $ ruby coupon_puts_val.rb 1 {1=>true} 0
  32. ༻ byebug ֬ೝᏓᏐతᆴ [1, 9] in /app/coupon.rb 1: def get_coupon(user_id,

    history) 2: if history[user_id] = true => 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) user_id 1
  33. [1, 9] in /app/coupon.rb 1: def get_coupon(user_id, history) 2: if

    history[user_id] = true => 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) history 1 help 2 help help 3 list
  34. [1, 9] in /app/coupon.rb 1: def get_coupon(user_id, history) 2: if

    history[user_id] = true => 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) history 1 help 2 help help 3 list
  35. ᙛ࿨㚎ݐࢦྩিಥ࣌ɼ ࢖༻ eval [1, 9] in /app/coupon.rb 1: def get_coupon(user_id,

    history) 2: if history[user_id] = true => 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) eval('history') {1=>true}
  36. v[ar] • v[ar] args ɿྻग़ method తჩᏐɻ • v[ar] c[onst]

    ɿྻग़ݱࡏ scope 㚎త constantɻ • v[ar] i[nstance] [object] ɿྻग़ object ҃ੋ self త ivarɻ • v[ar] l[ocal]ɿྻग़ॴ༗ local ᏓᏐɻ • v[ar] a[ll]ɿྻग़ local, global, instance ᏓᏐɻ
  37. [1, 9] in /app/coupon.rb 1: def get_coupon(user_id, history) 2: if

    history[user_id] = true => 3: return 0 4: end 5: history[user_id] = true 6: 3000 7: end 8: 9: puts get_coupon(1, {}) (byebug) var local history = {1=>true} user_id = 1
  38. ෆ୞᧺࡯ɼؐՄҎհೖ [1, 2] in /app/modify_var.rb => 1: a = 1

    2: puts "a is: #{a}" (byebug) n [1, 2] in /app/modify_var.rb 1: a = 1 => 2: puts "a is: #{a}" (byebug) a = 56 56 (byebug) c a is: 56 a = 1 puts "a is: #{a}"
  39. ༻ puts ፙᏓᏐඃमվతҐஔ def get_coupon(user_id, history) puts history if history[user_id]

    = true puts history return 0 end history[user_id] = true 3000 end puts get_coupon(1, {}) $ ruby coupon_puts_find.rb {} {1=>true} 0
  40. ༻ byebug ፙᏓᏐඃमվతҐஔ (byebug) display history 1: history = (undefined)

    (byebug) set linetrace linetrace is on (byebug) continue Tracing: /app/coupon.rb:9 puts get_coupon(1, {}) 1: history = (undefined) Tracing: /app/coupon.rb:2 if history[user_id] = true 1: history = {} Tracing: /app/coupon.rb:3 return 0 1: history = {1=>true}
  41. ༻ byebug ፙᏓᏐඃमվతҐஔ (byebug) display history 1: history = (undefined)

    (byebug) set linetrace linetrace is on (byebug) continue Tracing: /app/coupon.rb:9 puts get_coupon(1, {}) 1: history = (undefined) Tracing: /app/coupon.rb:2 if history[user_id] = true 1: history = {} Tracing: /app/coupon.rb:3 return 0 1: history = {1=>true}
  42. ༻ byebug ፙᏓᏐඃमվతҐஔ (byebug) display history 1: history = (undefined)

    (byebug) set linetrace linetrace is on (byebug) continue Tracing: /app/coupon.rb:9 puts get_coupon(1, {}) 1: history = (undefined) Tracing: /app/coupon.rb:2 if history[user_id] = true 1: history = {} Tracing: /app/coupon.rb:3 return 0 1: history = {1=>true}
  43. ༻ byebug ፙᏓᏐඃमվతҐஔ (byebug) display history 1: history = (undefined)

    (byebug) set linetrace linetrace is on (byebug) continue Tracing: /app/coupon.rb:9 puts get_coupon(1, {}) 1: history = (undefined) Tracing: /app/coupon.rb:2 if history[user_id] = true 1: history = {} Tracing: /app/coupon.rb:3 return 0 1: history = {1=>true}
  44. ༻ byebug ፙᏓᏐඃमվతҐஔ (byebug) display history 1: history = (undefined)

    (byebug) set linetrace linetrace is on (byebug) continue Tracing: /app/coupon.rb:9 puts get_coupon(1, {}) 1: history = (undefined) Tracing: /app/coupon.rb:2 if history[user_id] = true 1: history = {} Tracing: /app/coupon.rb:3 return 0 1: history = {1=>true}
  45. ౸ఈݺڣྃ䬟Ұஈఔࣜ? require_relative 'hidden_lib.rb' puts HiddenLib.new.hello("world") $ grep 'hello' hidden_lib.rb $

    ፙෆ౸ hello Ṝݸࣈ۲ʁʁ $ ruby method_caller.rb called hello with args: ["world"]
  46. ౸ఈݺڣྃ䬟Ұஈఔࣜ? # method_caller.rb require_relative 'hidden_lib.rb' puts HiddenLib.new.hello("world") $ grep 'hello'

    hidden_lib.rb $ ፙෆ౸ hello Ṝݸࣈ۲ʁʁ $ ruby method_caller.rb called hello with args: ["world"]
  47. class HiddenLib # hidden_lib.rb def method_missing(name, *args) "called #{name} with

    args: #{args.map(&:to_s)}" end end ౸ఈݺڣྃ䬟Ұஈఔࣜ? # method_caller.rb require_relative 'hidden_lib.rb' puts HiddenLib.new.hello("world") ׬શᔒ༗ hello Ṝݸࣈ۲ʂʂ $ ruby method_caller.rb called hello with args: ["world"]
  48. "ஶ໊"త method_missing • method_missing ੋᙛ object ඃݺڣෆଘࡏత method ɼब ။վҝݺڣṜݸ

    methodɻඃݺڣత method ໊᜝࿨ሏతჩ Ꮠ౎။ੋ method_missing తჩᏐɻ Ruby on Rails ࢖༻ྃ ෆগత method_missingɻ • obj.foo(a,b) => obj.method_missing(:foo, [a,b])
  49. class HiddenLib # hidden_lib.rb def method_missing(name, *args) "called #{name} with

    args: #{args.map(&:to_s)}" end end ༻ puts ፙඃݺڣతఔࣜ # method_caller.rb require_relative 'hidden_lib.rb' puts HiddenLib.new.hello("world")
  50. ༻ byebug ፙඃݺڣతఔࣜ [1, 3] in /app/method_caller.rb 1: require_relative 'hidden_lib.rb'

    2: => 3: puts HiddenLib.new.hello("world") (byebug) step [1, 5] in /app/hidden_lib.rb 1: class HiddenLib 2: def method_missing(name, *args) => 3: "called #{name} with args: #{args.map(&:to_s)}" 4: end 5: end (byebug)
  51. s[tep] [1, 3] in /app/method_caller.rb 1: require_relative 'hidden_lib.rb' 2: =>

    3: puts HiddenLib.new.hello("world") (byebug) step [1, 5] in /app/hidden_lib.rb 1: class HiddenLib 2: def method_missing(name, *args) => 3: "called #{name} with args: #{args.map(&:to_s)}" 4: end 5: end (byebug) • ᄸ㑊ࣥߦਐೖඃݺڣత methodɻ
  52. ༻ puts ፙݺڣ႔ $ ./framework (eval):1:in `<main>' ./framework:4:in `eval' ./framework:4:in

    `<main>' hello # my_code.rb def my_method puts caller_locations "hello" end
  53. ༻ byebug ፙݺڣ႔ ./framework [1, 5] in /app/my_code.rb 1: require

    'byebug' 2: def my_method 3: byebug => 4: "hello" 5: end (byebug) where
  54. ༻ byebug ፙݺڣ႔ ./framework [1, 5] in /app/my_code.rb 1: require

    'byebug' 2: def my_method 3: byebug => 4: "hello" 5: end (byebug) where
  55. ༻ byebug ፙݺڣ႔ ./framework [1, 5] in /app/my_code.rb 1: require

    'byebug' 2: def my_method 3: byebug => 4: "hello" 5: end (byebug) where
  56. w[here] • ᰖࣔ໨લత call stack ɼ0 ੋ໨લඃݺڣత methodɻᏐࣈ େతݺڣᏐࣈখతɻ ex:

    1 ݺڣ 0ɻ (byebug) where --> #0 Object.my_method at /app/my_code.rb:4 #1 <main> at /app/(eval):1 ͱ-- #2 Kernel.eval at /app/framework:4 #3 <main> at /app/framework:4
  57. bye ࢦྩখঞ • h[elp] [cmd] • q[uit] • l[ist] •

    b[reak] [file:]line [if expr] • c[ontinue] • n[ext] • v[ar] l[ocal] • s[tep] • disp[lay] expr • set linetrace • w[here]