byebug 5.0.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
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