byebug 5.0.0 → 6.0.0

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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -1
  3. data/CONTRIBUTING.md +35 -13
  4. data/GUIDE.md +256 -198
  5. data/README.md +5 -11
  6. data/ext/byebug/byebug.c +5 -43
  7. data/ext/byebug/byebug.h +6 -1
  8. data/ext/byebug/context.c +4 -5
  9. data/lib/byebug/command.rb +64 -64
  10. data/lib/byebug/command_list.rb +32 -0
  11. data/lib/byebug/commands.rb +37 -0
  12. data/lib/byebug/commands/break.rb +45 -37
  13. data/lib/byebug/commands/catch.rb +52 -28
  14. data/lib/byebug/commands/condition.rb +19 -13
  15. data/lib/byebug/commands/continue.rb +15 -11
  16. data/lib/byebug/commands/delete.rb +18 -12
  17. data/lib/byebug/commands/disable.rb +9 -10
  18. data/lib/byebug/commands/disable/breakpoints.rb +13 -11
  19. data/lib/byebug/commands/disable/display.rb +13 -11
  20. data/lib/byebug/commands/display.rb +32 -24
  21. data/lib/byebug/commands/down.rb +18 -14
  22. data/lib/byebug/commands/edit.rb +42 -26
  23. data/lib/byebug/commands/enable.rb +9 -3
  24. data/lib/byebug/commands/enable/breakpoints.rb +13 -11
  25. data/lib/byebug/commands/enable/display.rb +13 -11
  26. data/lib/byebug/commands/finish.rb +23 -14
  27. data/lib/byebug/commands/frame.rb +21 -18
  28. data/lib/byebug/commands/help.rb +39 -16
  29. data/lib/byebug/commands/history.rb +16 -10
  30. data/lib/byebug/commands/info.rb +8 -5
  31. data/lib/byebug/commands/info/breakpoints.rb +16 -14
  32. data/lib/byebug/commands/info/display.rb +18 -18
  33. data/lib/byebug/commands/info/file.rb +22 -22
  34. data/lib/byebug/commands/info/line.rb +13 -11
  35. data/lib/byebug/commands/info/program.rb +13 -17
  36. data/lib/byebug/commands/interrupt.rb +13 -11
  37. data/lib/byebug/commands/irb.rb +16 -10
  38. data/lib/byebug/commands/kill.rb +19 -13
  39. data/lib/byebug/commands/list.rb +35 -24
  40. data/lib/byebug/commands/method.rb +25 -15
  41. data/lib/byebug/commands/next.rb +15 -13
  42. data/lib/byebug/commands/pry.rb +18 -11
  43. data/lib/byebug/commands/ps.rb +21 -23
  44. data/lib/byebug/commands/quit.rb +17 -11
  45. data/lib/byebug/commands/restart.rb +28 -24
  46. data/lib/byebug/commands/save.rb +23 -15
  47. data/lib/byebug/commands/set.rb +26 -19
  48. data/lib/byebug/commands/show.rb +20 -14
  49. data/lib/byebug/commands/source.rb +15 -14
  50. data/lib/byebug/commands/step.rb +15 -13
  51. data/lib/byebug/commands/thread.rb +8 -4
  52. data/lib/byebug/commands/thread/current.rb +11 -11
  53. data/lib/byebug/commands/thread/list.rb +14 -14
  54. data/lib/byebug/commands/thread/resume.rb +14 -14
  55. data/lib/byebug/commands/thread/stop.rb +14 -14
  56. data/lib/byebug/commands/thread/switch.rb +15 -14
  57. data/lib/byebug/commands/tracevar.rb +20 -16
  58. data/lib/byebug/commands/undisplay.rb +22 -18
  59. data/lib/byebug/commands/untracevar.rb +13 -11
  60. data/lib/byebug/commands/up.rb +18 -14
  61. data/lib/byebug/commands/var.rb +10 -3
  62. data/lib/byebug/commands/var/all.rb +15 -13
  63. data/lib/byebug/commands/var/args.rb +37 -0
  64. data/lib/byebug/commands/var/const.rb +25 -14
  65. data/lib/byebug/commands/var/global.rb +13 -11
  66. data/lib/byebug/commands/var/instance.rb +13 -11
  67. data/lib/byebug/commands/var/local.rb +13 -11
  68. data/lib/byebug/commands/where.rb +15 -11
  69. data/lib/byebug/context.rb +71 -73
  70. data/lib/byebug/core.rb +45 -26
  71. data/lib/byebug/errors.rb +27 -0
  72. data/lib/byebug/frame.rb +181 -0
  73. data/lib/byebug/helpers/eval.rb +67 -26
  74. data/lib/byebug/helpers/file.rb +18 -3
  75. data/lib/byebug/helpers/frame.rb +36 -39
  76. data/lib/byebug/helpers/parse.rb +15 -13
  77. data/lib/byebug/helpers/path.rb +21 -0
  78. data/lib/byebug/helpers/reflection.rb +17 -0
  79. data/lib/byebug/helpers/thread.rb +20 -14
  80. data/lib/byebug/helpers/toggle.rb +10 -5
  81. data/lib/byebug/helpers/var.rb +36 -15
  82. data/lib/byebug/interface.rb +27 -9
  83. data/lib/byebug/option_setter.rb +93 -0
  84. data/lib/byebug/printers/base.rb +3 -0
  85. data/lib/byebug/printers/plain.rb +4 -14
  86. data/lib/byebug/printers/texts/base.yml +2 -7
  87. data/lib/byebug/processors/command_processor.rb +101 -102
  88. data/lib/byebug/processors/control_processor.rb +20 -0
  89. data/lib/byebug/processors/post_mortem_processor.rb +16 -0
  90. data/lib/byebug/processors/script_processor.rb +49 -0
  91. data/lib/byebug/remote.rb +13 -7
  92. data/lib/byebug/runner.rb +39 -65
  93. data/lib/byebug/setting.rb +4 -1
  94. data/lib/byebug/settings/post_mortem.rb +0 -16
  95. data/lib/byebug/settings/savefile.rb +1 -4
  96. data/lib/byebug/subcommands.rb +27 -29
  97. data/lib/byebug/version.rb +4 -1
  98. metadata +14 -29
  99. data/lib/byebug/commands/eval.rb +0 -43
  100. data/lib/byebug/commands/info/args.rb +0 -39
  101. data/lib/byebug/commands/info/catch.rb +0 -39
  102. data/lib/byebug/commands/pp.rb +0 -41
  103. data/lib/byebug/commands/putl.rb +0 -43
  104. data/lib/byebug/processor.rb +0 -43
  105. data/lib/byebug/processors/control_command_processor.rb +0 -48
  106. data/lib/byebug/settings/verbose.rb +0 -20
  107. data/lib/byebug/state.rb +0 -12
  108. data/lib/byebug/states/control_state.rb +0 -26
  109. data/lib/byebug/states/regular_state.rb +0 -187
  110. data/lib/byebug/subcommand_list.rb +0 -33
@@ -0,0 +1,20 @@
1
+ module Byebug
2
+ #
3
+ # Processes commands when there's not program running
4
+ #
5
+ class ControlProcessor < CommandProcessor
6
+ #
7
+ # Available commands
8
+ #
9
+ def commands
10
+ super.select(&:allow_in_control)
11
+ end
12
+
13
+ #
14
+ # Prompt shown before reading a command.
15
+ #
16
+ def prompt
17
+ '(byebug:ctrl) '
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ require 'byebug/processors/command_processor'
2
+
3
+ module Byebug
4
+ #
5
+ # Processes commands in post_mortem mode
6
+ #
7
+ class PostMortemProcessor < CommandProcessor
8
+ def commands
9
+ super.select(&:allow_in_post_mortem)
10
+ end
11
+
12
+ def prompt
13
+ '(byebug:post_mortem) '
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,49 @@
1
+ module Byebug
2
+ #
3
+ # Processes commands from a file
4
+ #
5
+ class ScriptProcessor < CommandProcessor
6
+ #
7
+ # Available commands
8
+ #
9
+ def commands
10
+ super.select(&:allow_in_control)
11
+ end
12
+
13
+ def process_commands
14
+ while (input = interface.read_command(prompt))
15
+ command = command_list.match(input)
16
+
17
+ if command
18
+ command.new(self).execute
19
+ else
20
+ errmsg('Unknown command')
21
+ end
22
+ end
23
+
24
+ interface.close
25
+ rescue IOError, SystemCallError
26
+ interface.close
27
+ rescue
28
+ without_exceptions do
29
+ puts "INTERNAL ERROR!!! #{$ERROR_INFO}"
30
+ puts $ERROR_INFO.backtrace.map { |l| "\t#{l}" }.join("\n")
31
+ end
32
+ end
33
+
34
+ #
35
+ # Prompt shown before reading a command.
36
+ #
37
+ def prompt
38
+ '(byebug:ctrl) '
39
+ end
40
+
41
+ private
42
+
43
+ def without_exceptions
44
+ yield
45
+ rescue
46
+ nil
47
+ end
48
+ end
49
+ end
@@ -1,5 +1,10 @@
1
1
  require 'socket'
2
2
 
3
+ #
4
+ # Remote debugging functionality.
5
+ #
6
+ # TODO: Refactor & add tests
7
+ #
3
8
  module Byebug
4
9
  # Port number used for remote debugging
5
10
  PORT = 8989 unless defined?(PORT)
@@ -25,7 +30,7 @@ module Byebug
25
30
  def start_server(host = nil, port = PORT)
26
31
  return if @thread
27
32
 
28
- handler.interface = nil
33
+ Context.interface = nil
29
34
  start
30
35
 
31
36
  start_control(host, port == 0 ? 0 : port + 1)
@@ -40,7 +45,7 @@ module Byebug
40
45
 
41
46
  @thread = DebugThread.new do
42
47
  while (session = server.accept)
43
- handler.interface = RemoteInterface.new(session)
48
+ Context.interface = RemoteInterface.new(session)
44
49
  mutex.synchronize { proceed.signal } if wait_connection
45
50
  end
46
51
  end
@@ -55,8 +60,9 @@ module Byebug
55
60
 
56
61
  @control_thread = DebugThread.new do
57
62
  while (session = server.accept)
58
- handler.interface = RemoteInterface.new(session)
59
- ControlCommandProcessor.new(handler.interface).process_commands
63
+ Context.interface = RemoteInterface.new(session)
64
+
65
+ ControlCommandProcessor.new(Byebug.current_context).process_commands
60
66
  end
61
67
  end
62
68
 
@@ -67,7 +73,7 @@ module Byebug
67
73
  # Connects to the remote byebug
68
74
  #
69
75
  def start_client(host = 'localhost', port = PORT)
70
- handler.interface = LocalInterface.new
76
+ Context.interface = LocalInterface.new
71
77
  puts 'Connecting to byebug server...'
72
78
  socket = TCPSocket.new(host, port)
73
79
  puts 'Connected.'
@@ -76,11 +82,11 @@ module Byebug
76
82
  while (line = socket.gets)
77
83
  case line
78
84
  when /^PROMPT (.*)$/
79
- input = handler.interface.read_command(Regexp.last_match[1])
85
+ input = Context.interface.read_command(Regexp.last_match[1])
80
86
  throw :exit unless input
81
87
  socket.puts input
82
88
  when /^CONFIRM (.*)$/
83
- input = handler.interface.confirm(Regexp.last_match[1])
89
+ input = Context.interface.confirm(Regexp.last_match[1])
84
90
  throw :exit unless input
85
91
  socket.puts input
86
92
  else
@@ -1,7 +1,10 @@
1
1
  require 'optparse'
2
2
  require 'English'
3
3
  require 'byebug/core'
4
+ require 'byebug/version'
4
5
  require 'byebug/helpers/parse'
6
+ require 'byebug/option_setter'
7
+ require 'byebug/processors/control_processor'
5
8
 
6
9
  module Byebug
7
10
  #
@@ -11,24 +14,29 @@ module Byebug
11
14
  include Helpers::ParseHelper
12
15
 
13
16
  #
14
- # Error class signaling absence of a script to debug
17
+ # Error class signaling absence of a script to debug.
15
18
  #
16
19
  class NoScript < StandardError; end
17
20
 
18
21
  #
19
- # Error class signaling a non existent script to debug
22
+ # Error class signaling a non existent script to debug.
20
23
  #
21
24
  class NonExistentScript < StandardError; end
22
25
 
23
26
  #
24
- # Error class signaling a script with invalid Ruby syntax
27
+ # Error class signaling a script with invalid Ruby syntax.
25
28
  #
26
29
  class InvalidScript < StandardError; end
27
30
 
28
31
  #
29
32
  # Special working modes that don't actually start the debugger.
30
33
  #
31
- attr_accessor :help, :version, :remote
34
+ attr_reader :help, :version, :remote
35
+
36
+ #
37
+ # Signals that we should exit after the debugged program is finished.
38
+ #
39
+ attr_accessor :quit
32
40
 
33
41
  #
34
42
  # @param stop [Boolean] Whether the runner should stop right before
@@ -42,6 +50,22 @@ module Byebug
42
50
  @quit = quit
43
51
  end
44
52
 
53
+ def help=(text)
54
+ @help ||= text
55
+
56
+ interface.puts("\n#{text}\n")
57
+ end
58
+
59
+ def version=(number)
60
+ @version ||= number
61
+
62
+ interface.puts("\n Running byebug #{number}\n")
63
+ end
64
+
65
+ def remote=(host_and_port)
66
+ @remote ||= Byebug.parse_host_and_port(host_and_port)
67
+ end
68
+
45
69
  #
46
70
  # Usage banner.
47
71
  #
@@ -56,20 +80,11 @@ module Byebug
56
80
  end
57
81
 
58
82
  #
59
- # Starts byebug to debug a program
83
+ # Starts byebug to debug a program.
60
84
  #
61
85
  def run
62
86
  prepare_options.order!($ARGV)
63
-
64
- if version
65
- Byebug.puts("\n Running byebug #{version}\n")
66
- return
67
- end
68
-
69
- if help
70
- Byebug.puts("#{help}\n")
71
- return
72
- end
87
+ return if version || help
73
88
 
74
89
  if remote
75
90
  Byebug.start_client(*remote)
@@ -81,70 +96,29 @@ module Byebug
81
96
  loop do
82
97
  debug_program
83
98
 
84
- break if @quit
99
+ break if quit
85
100
 
86
- processor = Byebug::ControlCommandProcessor.new
87
- processor.process_commands
101
+ ControlProcessor.new.process_commands
88
102
  end
89
103
  end
90
104
 
91
- private
105
+ def interface
106
+ @interface ||= LocalInterface.new
107
+ end
92
108
 
93
109
  #
94
- # Processes options passed from the command line
110
+ # Processes options passed from the command line.
95
111
  #
96
112
  def prepare_options
97
113
  OptionParser.new(banner, 25) do |opts|
98
114
  opts.banner = banner
99
115
 
100
- opts.on '-d', '--debug', 'Set $DEBUG=true' do
101
- $DEBUG = true
102
- end
103
-
104
- opts.on('-I', '--include list', 'Add to paths to $LOAD_PATH') do |list|
105
- $LOAD_PATH.push(list.split(':')).flatten!
106
- end
107
-
108
- opts.on '-m', '--[no-]post-mortem', 'Use post-mortem mode' do |v|
109
- Setting[:post_mortem] = v
110
- end
111
-
112
- opts.on '-q', '--[no-]quit', 'Quit when script finishes' do |v|
113
- @quit = v
114
- end
115
-
116
- opts.on '-x', '--[no-]rc', 'Run byebug initialization file' do |v|
117
- Byebug.run_init_script if v
118
- end
119
-
120
- opts.on '-s', '--[no-]stop', 'Stop when script is loaded' do |v|
121
- @stop = v
122
- end
123
-
124
- opts.on '-r', '--require file', 'Require library before script' do |lib|
125
- require lib
126
- end
127
-
128
- opts.on '-R', '--remote [host:]port', 'Remote debug [host:]port' do |p|
129
- self.remote = Byebug.parse_host_and_port(p)
130
- end
131
-
132
- opts.on '-t', '--[no-]trace', 'Turn on line tracing' do |v|
133
- Setting[:linetrace] = v
134
- end
135
-
136
- opts.on '-v', '--version', 'Print program version' do
137
- self.version = VERSION
138
- end
139
-
140
- opts.on('-h', '--help', 'Display this message') do
141
- self.help = opts.help
142
- end
116
+ OptionSetter.new(self, opts).setup
143
117
  end
144
118
  end
145
119
 
146
120
  #
147
- # Extracts debugged program from command line args
121
+ # Extracts debugged program from command line args.
148
122
  #
149
123
  def setup_cmd_line_args
150
124
  Byebug.mode = :standalone
@@ -166,7 +140,7 @@ module Byebug
166
140
  fail(InvalidScript, 'The script has incorrect syntax') unless ok
167
141
 
168
142
  error = Byebug.debug_load($PROGRAM_NAME, @stop)
169
- Byebug.puts "#{status}\n#{status.backtrace}" if error
143
+ puts "#{error}\n#{error.backtrace}" if error
170
144
  end
171
145
 
172
146
  #
@@ -57,8 +57,11 @@ module Byebug
57
57
  matches.size == 1 ? matches.values.first : nil
58
58
  end
59
59
 
60
+ #
61
+ # TODO: DRY this up. Very similar code exists in the CommandList class
62
+ #
60
63
  def help_all
61
- output = " List of settings supported in byebug:\n --\n"
64
+ output = " List of supported settings:\n\n"
62
65
  width = settings.keys.max_by(&:size).size
63
66
  settings.values.each do |sett|
64
67
  output << format(" %-#{width}s -- %s\n", sett.to_sym, sett.banner)
@@ -22,20 +22,4 @@ module Byebug
22
22
  Byebug.post_mortem?
23
23
  end
24
24
  end
25
-
26
- #
27
- # Saves information about the unhandled exception and gives a byebug
28
- # prompt back to the user before program termination.
29
- #
30
- def self.handle_post_mortem
31
- return unless Byebug.raised_exception
32
-
33
- context = Byebug.raised_exception.__bb_context
34
- file = Byebug.raised_exception.__bb_file
35
- line = Byebug.raised_exception.__bb_line
36
-
37
- Byebug.handler.at_line(context, file, line)
38
- end
39
-
40
- at_exit { Byebug.handle_post_mortem if Byebug.post_mortem? }
41
25
  end
@@ -8,10 +8,7 @@ module Byebug
8
8
  DEFAULT = File.expand_path("#{ENV['HOME'] || '.'}/.byebug_save")
9
9
 
10
10
  def banner
11
- <<-EOB
12
- File where save commands saves current settings to. Default:
13
- ~/.byebug_save
14
- EOB
11
+ 'File where settings are saved to. Default: ~/.byebug_save'
15
12
  end
16
13
 
17
14
  def to_s
@@ -1,53 +1,51 @@
1
- require 'byebug/command'
2
- require 'byebug/subcommand_list'
1
+ require 'forwardable'
2
+
3
+ require 'byebug/helpers/reflection'
4
+ require 'byebug/command_list'
3
5
 
4
6
  module Byebug
5
7
  #
6
8
  # Subcommand additions.
7
9
  #
8
10
  module Subcommands
9
- #
10
- # Summarized description of a subcommand
11
- #
12
- def short_description
13
- fail(NotImplementedError, 'Your custom subcommand needs to define this')
11
+ def self.included(command)
12
+ command.extend(ClassMethods)
14
13
  end
15
14
 
15
+ extend Forwardable
16
+ def_delegators :'self.class', :subcommand_list
17
+
16
18
  #
17
19
  # Delegates to subcommands or prints help if no subcommand specified.
18
20
  #
19
21
  def execute
20
22
  return puts(help) unless @match[1]
21
23
 
22
- subcmd = subcommands.find(@match[1])
23
- return errmsg("Unknown subcommand '#{@match[1]}'\n") unless subcmd
24
+ subcmd = subcommand_list.match(@match[1])
25
+ fail CommandNotFound.new(@match[1], self.class) unless subcmd
24
26
 
25
- subcmd.execute
27
+ subcmd.new(processor, arguments).execute
26
28
  end
27
29
 
28
30
  #
29
- # Default help text for a command with subcommands
31
+ # Class methods added to subcommands
30
32
  #
31
- def help
32
- prettify <<-EOH
33
- #{description}
34
-
35
- List of "#{to_name}" subcommands:
33
+ module ClassMethods
34
+ include Helpers::ReflectionHelper
36
35
 
37
- --
38
- #{subcommands}
39
- EOH
40
- end
41
-
42
- #
43
- # Command's subcommands.
44
- #
45
- def subcommands
46
- subcmd_klasses = self.class.subcommands
47
- return nil unless subcmd_klasses.any?
36
+ #
37
+ # Default help text for a command with subcommands
38
+ #
39
+ def help
40
+ super + subcommand_list.to_s
41
+ end
48
42
 
49
- subcmd_list = subcmd_klasses.map { |cmd| cmd.new(@state) }
50
- SubcommandList.new(subcmd_list, self.class.name)
43
+ #
44
+ # Command's subcommands.
45
+ #
46
+ def subcommand_list
47
+ @subcommand_list ||= CommandList.new(commands)
48
+ end
51
49
  end
52
50
  end
53
51
  end