byebug 11.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +897 -0
  3. data/CONTRIBUTING.md +58 -0
  4. data/GUIDE.md +1806 -0
  5. data/LICENSE +23 -0
  6. data/README.md +199 -0
  7. data/exe/byebug +6 -0
  8. data/ext/byebug/breakpoint.c +517 -0
  9. data/ext/byebug/byebug.c +905 -0
  10. data/ext/byebug/byebug.h +143 -0
  11. data/ext/byebug/context.c +673 -0
  12. data/ext/byebug/extconf.rb +12 -0
  13. data/ext/byebug/locker.c +96 -0
  14. data/ext/byebug/threads.c +230 -0
  15. data/lib/byebug.rb +3 -0
  16. data/lib/byebug/attacher.rb +48 -0
  17. data/lib/byebug/breakpoint.rb +111 -0
  18. data/lib/byebug/command.rb +111 -0
  19. data/lib/byebug/command_list.rb +34 -0
  20. data/lib/byebug/commands.rb +40 -0
  21. data/lib/byebug/commands/break.rb +112 -0
  22. data/lib/byebug/commands/catch.rb +78 -0
  23. data/lib/byebug/commands/condition.rb +55 -0
  24. data/lib/byebug/commands/continue.rb +68 -0
  25. data/lib/byebug/commands/debug.rb +38 -0
  26. data/lib/byebug/commands/delete.rb +55 -0
  27. data/lib/byebug/commands/disable.rb +33 -0
  28. data/lib/byebug/commands/disable/breakpoints.rb +42 -0
  29. data/lib/byebug/commands/disable/display.rb +43 -0
  30. data/lib/byebug/commands/display.rb +66 -0
  31. data/lib/byebug/commands/down.rb +45 -0
  32. data/lib/byebug/commands/edit.rb +69 -0
  33. data/lib/byebug/commands/enable.rb +33 -0
  34. data/lib/byebug/commands/enable/breakpoints.rb +42 -0
  35. data/lib/byebug/commands/enable/display.rb +43 -0
  36. data/lib/byebug/commands/finish.rb +57 -0
  37. data/lib/byebug/commands/frame.rb +57 -0
  38. data/lib/byebug/commands/help.rb +64 -0
  39. data/lib/byebug/commands/history.rb +39 -0
  40. data/lib/byebug/commands/info.rb +37 -0
  41. data/lib/byebug/commands/info/breakpoints.rb +65 -0
  42. data/lib/byebug/commands/info/display.rb +49 -0
  43. data/lib/byebug/commands/info/file.rb +80 -0
  44. data/lib/byebug/commands/info/line.rb +35 -0
  45. data/lib/byebug/commands/info/program.rb +49 -0
  46. data/lib/byebug/commands/interrupt.rb +34 -0
  47. data/lib/byebug/commands/irb.rb +50 -0
  48. data/lib/byebug/commands/kill.rb +45 -0
  49. data/lib/byebug/commands/list.rb +159 -0
  50. data/lib/byebug/commands/method.rb +53 -0
  51. data/lib/byebug/commands/next.rb +40 -0
  52. data/lib/byebug/commands/pry.rb +41 -0
  53. data/lib/byebug/commands/quit.rb +42 -0
  54. data/lib/byebug/commands/restart.rb +64 -0
  55. data/lib/byebug/commands/save.rb +72 -0
  56. data/lib/byebug/commands/set.rb +79 -0
  57. data/lib/byebug/commands/show.rb +45 -0
  58. data/lib/byebug/commands/skip.rb +85 -0
  59. data/lib/byebug/commands/source.rb +40 -0
  60. data/lib/byebug/commands/step.rb +40 -0
  61. data/lib/byebug/commands/thread.rb +34 -0
  62. data/lib/byebug/commands/thread/current.rb +37 -0
  63. data/lib/byebug/commands/thread/list.rb +43 -0
  64. data/lib/byebug/commands/thread/resume.rb +45 -0
  65. data/lib/byebug/commands/thread/stop.rb +43 -0
  66. data/lib/byebug/commands/thread/switch.rb +46 -0
  67. data/lib/byebug/commands/tracevar.rb +54 -0
  68. data/lib/byebug/commands/undisplay.rb +51 -0
  69. data/lib/byebug/commands/untracevar.rb +36 -0
  70. data/lib/byebug/commands/up.rb +45 -0
  71. data/lib/byebug/commands/var.rb +37 -0
  72. data/lib/byebug/commands/var/all.rb +41 -0
  73. data/lib/byebug/commands/var/args.rb +39 -0
  74. data/lib/byebug/commands/var/const.rb +49 -0
  75. data/lib/byebug/commands/var/global.rb +37 -0
  76. data/lib/byebug/commands/var/instance.rb +39 -0
  77. data/lib/byebug/commands/var/local.rb +39 -0
  78. data/lib/byebug/commands/where.rb +53 -0
  79. data/lib/byebug/context.rb +157 -0
  80. data/lib/byebug/core.rb +115 -0
  81. data/lib/byebug/errors.rb +29 -0
  82. data/lib/byebug/frame.rb +185 -0
  83. data/lib/byebug/helpers/bin.rb +47 -0
  84. data/lib/byebug/helpers/eval.rb +126 -0
  85. data/lib/byebug/helpers/file.rb +63 -0
  86. data/lib/byebug/helpers/frame.rb +75 -0
  87. data/lib/byebug/helpers/parse.rb +75 -0
  88. data/lib/byebug/helpers/path.rb +40 -0
  89. data/lib/byebug/helpers/reflection.rb +19 -0
  90. data/lib/byebug/helpers/string.rb +33 -0
  91. data/lib/byebug/helpers/thread.rb +67 -0
  92. data/lib/byebug/helpers/toggle.rb +62 -0
  93. data/lib/byebug/helpers/var.rb +54 -0
  94. data/lib/byebug/history.rb +130 -0
  95. data/lib/byebug/interface.rb +146 -0
  96. data/lib/byebug/interfaces/local_interface.rb +44 -0
  97. data/lib/byebug/interfaces/remote_interface.rb +50 -0
  98. data/lib/byebug/interfaces/script_interface.rb +33 -0
  99. data/lib/byebug/interfaces/test_interface.rb +67 -0
  100. data/lib/byebug/option_setter.rb +95 -0
  101. data/lib/byebug/printers/base.rb +68 -0
  102. data/lib/byebug/printers/plain.rb +44 -0
  103. data/lib/byebug/printers/texts/base.yml +115 -0
  104. data/lib/byebug/printers/texts/plain.yml +33 -0
  105. data/lib/byebug/processors/command_processor.rb +173 -0
  106. data/lib/byebug/processors/control_processor.rb +24 -0
  107. data/lib/byebug/processors/post_mortem_processor.rb +18 -0
  108. data/lib/byebug/processors/script_processor.rb +49 -0
  109. data/lib/byebug/remote.rb +85 -0
  110. data/lib/byebug/remote/client.rb +57 -0
  111. data/lib/byebug/remote/server.rb +47 -0
  112. data/lib/byebug/runner.rb +198 -0
  113. data/lib/byebug/setting.rb +79 -0
  114. data/lib/byebug/settings/autoirb.rb +29 -0
  115. data/lib/byebug/settings/autolist.rb +29 -0
  116. data/lib/byebug/settings/autopry.rb +29 -0
  117. data/lib/byebug/settings/autosave.rb +17 -0
  118. data/lib/byebug/settings/basename.rb +16 -0
  119. data/lib/byebug/settings/callstyle.rb +20 -0
  120. data/lib/byebug/settings/fullpath.rb +16 -0
  121. data/lib/byebug/settings/histfile.rb +20 -0
  122. data/lib/byebug/settings/histsize.rb +20 -0
  123. data/lib/byebug/settings/linetrace.rb +22 -0
  124. data/lib/byebug/settings/listsize.rb +21 -0
  125. data/lib/byebug/settings/post_mortem.rb +27 -0
  126. data/lib/byebug/settings/savefile.rb +20 -0
  127. data/lib/byebug/settings/stack_on_error.rb +15 -0
  128. data/lib/byebug/settings/width.rb +20 -0
  129. data/lib/byebug/source_file_formatter.rb +71 -0
  130. data/lib/byebug/subcommands.rb +54 -0
  131. data/lib/byebug/version.rb +8 -0
  132. metadata +199 -0
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+ require "byebug/helpers/string"
5
+
6
+ module Byebug
7
+ #
8
+ # Parent class of all byebug commands.
9
+ #
10
+ # Subclass it and name the subclass ending with the word Command to implement
11
+ # your own custom command.
12
+ #
13
+ # @example Define a custom command
14
+ #
15
+ # class MyCustomCommand < Command
16
+ # def self.regexp
17
+ # /custom_regexp/
18
+ # end
19
+ #
20
+ # def self.description
21
+ # "Custom long desc"
22
+ # end
23
+ #
24
+ # def.short_description
25
+ # "Custom short desc"
26
+ # end
27
+ #
28
+ # def execute
29
+ # # My command's implementation
30
+ # end
31
+ # end
32
+ #
33
+ class Command
34
+ extend Forwardable
35
+
36
+ attr_reader :processor
37
+
38
+ def initialize(processor, input = self.class.to_s)
39
+ @processor = processor
40
+ @match = match(input)
41
+ end
42
+
43
+ def context
44
+ @context ||= processor.context
45
+ end
46
+
47
+ def frame
48
+ @frame ||= context.frame
49
+ end
50
+
51
+ def arguments
52
+ @match[0].split(" ").drop(1).join(" ")
53
+ end
54
+
55
+ def_delegators "self.class", :help, :match
56
+
57
+ def_delegator "processor.printer", :print, :pr
58
+ def_delegator "processor.printer", :print_collection, :prc
59
+ def_delegator "processor.printer", :print_variables, :prv
60
+
61
+ def_delegators "processor.interface", :errmsg, :puts, :print, :confirm
62
+
63
+ class << self
64
+ include Helpers::StringHelper
65
+
66
+ #
67
+ # Special methods to allow command filtering in processors
68
+ #
69
+ attr_accessor :allow_in_control, :allow_in_post_mortem
70
+
71
+ attr_writer :always_run
72
+
73
+ def always_run
74
+ @always_run ||= 0
75
+ end
76
+
77
+ #
78
+ # Name of the command, as executed by the user.
79
+ #
80
+ def to_s
81
+ name
82
+ .split("::")
83
+ .map { |n| n.gsub(/Command$/, "").downcase if n =~ /Command$/ }
84
+ .compact
85
+ .join(" ")
86
+ end
87
+
88
+ def columnize(width)
89
+ format(
90
+ " %-<name>#{width}s -- %<description>s\n",
91
+ name: to_s,
92
+ description: short_description
93
+ )
94
+ end
95
+
96
+ #
97
+ # Default help text for a command.
98
+ #
99
+ def help
100
+ prettify(description)
101
+ end
102
+
103
+ #
104
+ # Command's regexp match against an input
105
+ #
106
+ def match(input)
107
+ regexp.match(input)
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "byebug/errors"
4
+
5
+ module Byebug
6
+ #
7
+ # Holds an array of subcommands for a command
8
+ #
9
+ class CommandList
10
+ include Enumerable
11
+
12
+ def initialize(commands)
13
+ @commands = commands.sort_by(&:to_s)
14
+ end
15
+
16
+ def match(input)
17
+ find { |cmd| cmd.match(input) }
18
+ end
19
+
20
+ def each
21
+ @commands.each { |cmd| yield(cmd) }
22
+ end
23
+
24
+ def to_s
25
+ "\n" + map { |cmd| cmd.columnize(width) }.join + "\n"
26
+ end
27
+
28
+ private
29
+
30
+ def width
31
+ @width ||= map(&:to_s).max_by(&:size).size
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "byebug/commands/break"
4
+ require "byebug/commands/catch"
5
+ require "byebug/commands/condition"
6
+ require "byebug/commands/continue"
7
+ require "byebug/commands/debug"
8
+ require "byebug/commands/delete"
9
+ require "byebug/commands/disable"
10
+ require "byebug/commands/display"
11
+ require "byebug/commands/down"
12
+ require "byebug/commands/edit"
13
+ require "byebug/commands/enable"
14
+ require "byebug/commands/finish"
15
+ require "byebug/commands/frame"
16
+ require "byebug/commands/help"
17
+ require "byebug/commands/history"
18
+ require "byebug/commands/info"
19
+ require "byebug/commands/interrupt"
20
+ require "byebug/commands/irb"
21
+ require "byebug/commands/kill"
22
+ require "byebug/commands/list"
23
+ require "byebug/commands/method"
24
+ require "byebug/commands/next"
25
+ require "byebug/commands/pry"
26
+ require "byebug/commands/quit"
27
+ require "byebug/commands/restart"
28
+ require "byebug/commands/save"
29
+ require "byebug/commands/set"
30
+ require "byebug/commands/show"
31
+ require "byebug/commands/skip"
32
+ require "byebug/commands/source"
33
+ require "byebug/commands/step"
34
+ require "byebug/commands/thread"
35
+ require "byebug/commands/tracevar"
36
+ require "byebug/commands/undisplay"
37
+ require "byebug/commands/untracevar"
38
+ require "byebug/commands/up"
39
+ require "byebug/commands/var"
40
+ require "byebug/commands/where"
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "byebug/command"
4
+ require "byebug/helpers/eval"
5
+ require "byebug/helpers/file"
6
+ require "byebug/helpers/parse"
7
+ require "byebug/source_file_formatter"
8
+
9
+ module Byebug
10
+ #
11
+ # Implements breakpoint functionality
12
+ #
13
+ class BreakCommand < Command
14
+ include Helpers::EvalHelper
15
+ include Helpers::FileHelper
16
+ include Helpers::ParseHelper
17
+
18
+ self.allow_in_control = true
19
+
20
+ def self.regexp
21
+ /^\s* b(?:reak)? (?:\s+ (.+?))? (?:\s+ if \s+(.+))? \s*$/x
22
+ end
23
+
24
+ def self.description
25
+ <<-DESCRIPTION
26
+ b[reak] [<file>:]<line> [if <expr>]
27
+ b[reak] [<module>::...]<class>(.|#)<method> [if <expr>]
28
+
29
+ They can be specified by line or method and an expression can be added
30
+ for conditionally enabled breakpoints.
31
+
32
+ #{short_description}
33
+ DESCRIPTION
34
+ end
35
+
36
+ def self.short_description
37
+ "Sets breakpoints in the source code"
38
+ end
39
+
40
+ def execute
41
+ return puts(help) unless @match[1]
42
+
43
+ b = line_breakpoint(@match[1]) || method_breakpoint(@match[1])
44
+ return errmsg(pr("break.errors.location")) unless b
45
+
46
+ return puts(pr("break.created", id: b.id, file: b.source, line: b.pos)) if syntax_valid?(@match[2])
47
+
48
+ errmsg(pr("break.errors.expression", expr: @match[2]))
49
+ b.enabled = false
50
+ end
51
+
52
+ private
53
+
54
+ def line_breakpoint(location)
55
+ line_match = location.match(/^(\d+)$/)
56
+ file_line_match = location.match(/^(.+):(\d+)$/)
57
+ return unless line_match || file_line_match
58
+
59
+ file = line_match ? frame.file : file_line_match[1]
60
+ line = line_match ? line_match[1].to_i : file_line_match[2].to_i
61
+
62
+ add_line_breakpoint(file, line)
63
+ end
64
+
65
+ def method_breakpoint(location)
66
+ location.match(/([^.#]+)[.#](.+)/) do |match|
67
+ klass = target_object(match[1])
68
+ method = match[2].intern
69
+
70
+ Breakpoint.add(klass, method, @match[2])
71
+ end
72
+ end
73
+
74
+ def target_object(str)
75
+ k = error_eval(str)
76
+
77
+ k&.is_a?(Module) ? k.name : str
78
+ rescue StandardError
79
+ errmsg("Warning: breakpoint source is not yet defined")
80
+ str
81
+ end
82
+
83
+ def add_line_breakpoint(file, line)
84
+ raise(pr("break.errors.source", file: file)) unless File.exist?(file)
85
+
86
+ fullpath = File.realpath(file)
87
+
88
+ raise(pr("break.errors.far_line", lines: n_lines(file), file: fullpath)) if line > n_lines(file)
89
+
90
+ unless Breakpoint.potential_line?(fullpath, line)
91
+ msg = pr(
92
+ "break.errors.line",
93
+ file: fullpath,
94
+ line: line,
95
+ valid_breakpoints: valid_breakpoints_for(fullpath, line)
96
+ )
97
+
98
+ raise(msg)
99
+ end
100
+
101
+ Breakpoint.add(fullpath, line, @match[2])
102
+ end
103
+
104
+ def valid_breakpoints_for(path, line)
105
+ potential_lines = Breakpoint.potential_lines(path)
106
+ annotator = ->(n) { potential_lines.include?(n) ? "[B]" : " " }
107
+ source_file_formatter = SourceFileFormatter.new(path, annotator)
108
+
109
+ source_file_formatter.lines_around(line).join.chomp
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "byebug/command"
4
+ require "byebug/helpers/eval"
5
+
6
+ module Byebug
7
+ #
8
+ # Implements exception catching.
9
+ #
10
+ # Enables the user to catch unhandled assertion when they happen.
11
+ #
12
+ class CatchCommand < Command
13
+ include Helpers::EvalHelper
14
+
15
+ self.allow_in_post_mortem = true
16
+
17
+ def self.regexp
18
+ /^\s* cat(?:ch)? (?:\s+(\S+))? (?:\s+(off))? \s*$/x
19
+ end
20
+
21
+ def self.description
22
+ <<-DESCRIPTION
23
+ cat[ch][ (off|<exception>[ off])]
24
+
25
+ #{short_description}
26
+
27
+ catch -- lists catchpoints
28
+ catch off -- deletes all catchpoints
29
+ catch <exception> -- enables handling <exception>
30
+ catch <exception> off -- disables handling <exception>
31
+ DESCRIPTION
32
+ end
33
+
34
+ def self.short_description
35
+ "Handles exception catchpoints"
36
+ end
37
+
38
+ def execute
39
+ return info unless @match[1]
40
+
41
+ return @match[1] == "off" ? clear : add(@match[1]) unless @match[2]
42
+
43
+ return errmsg pr("catch.errors.off", off: cmd) unless @match[2] == "off"
44
+
45
+ remove(@match[1])
46
+ end
47
+
48
+ private
49
+
50
+ def remove(exception)
51
+ return errmsg pr("catch.errors.not_found", exception: exception) unless Byebug.catchpoints.member?(exception)
52
+
53
+ puts pr("catch.removed", exception: exception)
54
+ Byebug.catchpoints.delete(exception)
55
+ end
56
+
57
+ def add(exception)
58
+ errmsg pr("catch.errors.not_class", class: exception) if warning_eval(exception.is_a?(Class).to_s)
59
+
60
+ puts pr("catch.added", exception: exception)
61
+ Byebug.add_catchpoint(exception)
62
+ end
63
+
64
+ def clear
65
+ Byebug.catchpoints.clear if confirm(pr("catch.confirmations.delete_all"))
66
+ end
67
+
68
+ def info
69
+ if Byebug.catchpoints && !Byebug.catchpoints.empty?
70
+ Byebug.catchpoints.each_key do |exception|
71
+ puts("#{exception}: #{exception.is_a?(Class)}")
72
+ end
73
+ else
74
+ puts "No exceptions set to be caught."
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "byebug/command"
4
+ require "byebug/helpers/parse"
5
+
6
+ module Byebug
7
+ #
8
+ # Implements conditions on breakpoints.
9
+ #
10
+ # Adds the ability to stop on breakpoints only under certain conditions.
11
+ #
12
+ class ConditionCommand < Command
13
+ include Helpers::ParseHelper
14
+
15
+ self.allow_in_post_mortem = true
16
+
17
+ def self.regexp
18
+ /^\s* cond(?:ition)? (?:\s+(\d+)(?:\s+(.*))?)? \s*$/x
19
+ end
20
+
21
+ def self.description
22
+ <<-DESCRIPTION
23
+ cond[ition] <n>[ expr]
24
+
25
+ #{short_description}
26
+
27
+ Specify breakpoint number <n> to break only if <expr> is true. <n> is
28
+ an integer and <expr> is an expression to be evaluated whenever
29
+ breakpoint <n> is reached. If no expression is specified, the condition
30
+ is removed.
31
+ DESCRIPTION
32
+ end
33
+
34
+ def self.short_description
35
+ "Sets conditions on breakpoints"
36
+ end
37
+
38
+ def execute
39
+ return puts(help) unless @match[1]
40
+
41
+ breakpoints = Byebug.breakpoints.sort_by(&:id)
42
+ return errmsg(pr("condition.errors.no_breakpoints")) if breakpoints.empty?
43
+
44
+ pos, err = get_int(@match[1], "Condition", 1)
45
+ return errmsg(err) if err
46
+
47
+ breakpoint = breakpoints.find { |b| b.id == pos }
48
+ return errmsg(pr("break.errors.no_breakpoint")) unless breakpoint
49
+
50
+ return errmsg(pr("break.errors.not_changed", expr: @match[2])) unless syntax_valid?(@match[2])
51
+
52
+ breakpoint.expr = @match[2]
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "byebug/command"
4
+ require "byebug/helpers/parse"
5
+
6
+ module Byebug
7
+ #
8
+ # Implements the continue command.
9
+ #
10
+ # Allows the user to continue execution until the next stopping point, a
11
+ # specific line number or until program termination.
12
+ #
13
+ class ContinueCommand < Command
14
+ include Helpers::ParseHelper
15
+
16
+ def self.regexp
17
+ /^\s* c(?:ont(?:inue)?)? (?:(!|\s+unconditionally|\s+\S+))? \s*$/x
18
+ end
19
+
20
+ def self.description
21
+ <<-DESCRIPTION
22
+ c[ont[inue]][ <line_number>]
23
+
24
+ #{short_description}
25
+
26
+ Normally the program stops at the next breakpoint. However, if the
27
+ parameter "unconditionally" is given or the command is suffixed with
28
+ "!", the program will run until the end regardless of any enabled
29
+ breakpoints.
30
+ DESCRIPTION
31
+ end
32
+
33
+ def self.short_description
34
+ "Runs until program ends, hits a breakpoint or reaches a line"
35
+ end
36
+
37
+ def execute
38
+ if until_line?
39
+ num, err = get_int(modifier, "Continue", 0, nil)
40
+ return errmsg(err) unless num
41
+
42
+ filename = File.expand_path(frame.file)
43
+ return errmsg(pr("continue.errors.unstopped_line", line: num)) unless Breakpoint.potential_line?(filename, num)
44
+
45
+ Breakpoint.add(filename, num)
46
+ end
47
+
48
+ processor.proceed!
49
+
50
+ Byebug.mode = :off if unconditionally?
51
+ Byebug.stop if unconditionally? || Byebug.stoppable?
52
+ end
53
+
54
+ private
55
+
56
+ def until_line?
57
+ @match[1] && !["!", "unconditionally"].include?(modifier)
58
+ end
59
+
60
+ def unconditionally?
61
+ @match[1] && ["!", "unconditionally"].include?(modifier)
62
+ end
63
+
64
+ def modifier
65
+ @match[1].lstrip
66
+ end
67
+ end
68
+ end