byebug 3.2.0 → 3.3.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 (127) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +125 -99
  4. data/CONTRIBUTING.md +4 -6
  5. data/GUIDE.md +42 -20
  6. data/Gemfile +5 -3
  7. data/README.md +2 -3
  8. data/Rakefile +11 -7
  9. data/bin/byebug +2 -252
  10. data/byebug.gemspec +7 -4
  11. data/ext/byebug/byebug.c +17 -18
  12. data/ext/byebug/byebug.h +4 -5
  13. data/ext/byebug/context.c +37 -39
  14. data/ext/byebug/threads.c +39 -18
  15. data/lib/byebug.rb +2 -110
  16. data/lib/byebug/attacher.rb +23 -0
  17. data/lib/byebug/breakpoint.rb +60 -0
  18. data/lib/byebug/command.rb +62 -70
  19. data/lib/byebug/commands/break.rb +24 -24
  20. data/lib/byebug/commands/catchpoint.rb +18 -10
  21. data/lib/byebug/commands/condition.rb +18 -17
  22. data/lib/byebug/commands/continue.rb +17 -9
  23. data/lib/byebug/commands/delete.rb +19 -13
  24. data/lib/byebug/commands/display.rb +19 -53
  25. data/lib/byebug/commands/edit.rb +7 -4
  26. data/lib/byebug/commands/enable_disable.rb +130 -0
  27. data/lib/byebug/commands/eval.rb +40 -22
  28. data/lib/byebug/commands/finish.rb +13 -4
  29. data/lib/byebug/commands/frame.rb +65 -45
  30. data/lib/byebug/commands/help.rb +17 -18
  31. data/lib/byebug/commands/history.rb +14 -8
  32. data/lib/byebug/commands/info.rb +160 -182
  33. data/lib/byebug/commands/interrupt.rb +4 -1
  34. data/lib/byebug/commands/irb.rb +30 -0
  35. data/lib/byebug/commands/kill.rb +7 -8
  36. data/lib/byebug/commands/list.rb +71 -66
  37. data/lib/byebug/commands/method.rb +14 -6
  38. data/lib/byebug/commands/pry.rb +35 -0
  39. data/lib/byebug/commands/quit.rb +9 -6
  40. data/lib/byebug/commands/reload.rb +5 -2
  41. data/lib/byebug/commands/restart.rb +13 -9
  42. data/lib/byebug/commands/save.rb +17 -17
  43. data/lib/byebug/commands/set.rb +16 -15
  44. data/lib/byebug/commands/show.rb +10 -11
  45. data/lib/byebug/commands/source.rb +11 -5
  46. data/lib/byebug/commands/stepping.rb +38 -24
  47. data/lib/byebug/commands/threads.rb +45 -31
  48. data/lib/byebug/commands/trace.rb +22 -9
  49. data/lib/byebug/commands/undisplay.rb +45 -0
  50. data/lib/byebug/commands/variables.rb +83 -27
  51. data/lib/byebug/context.rb +25 -22
  52. data/lib/byebug/core.rb +82 -0
  53. data/lib/byebug/helper.rb +37 -28
  54. data/lib/byebug/history.rb +8 -4
  55. data/lib/byebug/interface.rb +12 -17
  56. data/lib/byebug/interfaces/local_interface.rb +11 -8
  57. data/lib/byebug/interfaces/remote_interface.rb +11 -8
  58. data/lib/byebug/interfaces/script_interface.rb +9 -6
  59. data/lib/byebug/options.rb +46 -0
  60. data/lib/byebug/processor.rb +7 -1
  61. data/lib/byebug/processors/command_processor.rb +135 -125
  62. data/lib/byebug/processors/control_command_processor.rb +23 -23
  63. data/lib/byebug/remote.rb +17 -26
  64. data/lib/byebug/runner.rb +100 -0
  65. data/lib/byebug/setting.rb +33 -8
  66. data/lib/byebug/settings/autoeval.rb +5 -15
  67. data/lib/byebug/settings/autoirb.rb +4 -1
  68. data/lib/byebug/settings/autolist.rb +5 -2
  69. data/lib/byebug/settings/autoreload.rb +5 -2
  70. data/lib/byebug/settings/autosave.rb +6 -2
  71. data/lib/byebug/settings/basename.rb +7 -2
  72. data/lib/byebug/settings/callstyle.rb +4 -1
  73. data/lib/byebug/settings/forcestep.rb +6 -3
  74. data/lib/byebug/settings/fullpath.rb +5 -2
  75. data/lib/byebug/settings/histfile.rb +5 -3
  76. data/lib/byebug/settings/histsize.rb +5 -3
  77. data/lib/byebug/settings/linetrace.rb +4 -1
  78. data/lib/byebug/settings/listsize.rb +5 -1
  79. data/lib/byebug/settings/post_mortem.rb +21 -13
  80. data/lib/byebug/settings/stack_on_error.rb +6 -2
  81. data/lib/byebug/settings/testing.rb +6 -1
  82. data/lib/byebug/settings/tracing_plus.rb +5 -1
  83. data/lib/byebug/settings/verbose.rb +13 -2
  84. data/lib/byebug/settings/width.rb +4 -1
  85. data/lib/byebug/version.rb +1 -1
  86. data/test/{break_test.rb → commands/break_test.rb} +41 -53
  87. data/test/{condition_test.rb → commands/condition_test.rb} +14 -14
  88. data/test/{continue_test.rb → commands/continue_test.rb} +0 -0
  89. data/test/{delete_test.rb → commands/delete_test.rb} +2 -2
  90. data/test/commands/display_test.rb +37 -0
  91. data/test/{edit_test.rb → commands/edit_test.rb} +0 -0
  92. data/test/{eval_test.rb → commands/eval_test.rb} +1 -0
  93. data/test/{finish_test.rb → commands/finish_test.rb} +11 -1
  94. data/test/{frame_test.rb → commands/frame_test.rb} +12 -16
  95. data/test/{help_test.rb → commands/help_test.rb} +21 -4
  96. data/test/{history_test.rb → commands/history_test.rb} +0 -0
  97. data/test/{info_test.rb → commands/info_test.rb} +5 -55
  98. data/test/{interrupt_test.rb → commands/interrupt_test.rb} +0 -0
  99. data/test/commands/irb_test.rb +28 -0
  100. data/test/{kill_test.rb → commands/kill_test.rb} +1 -1
  101. data/test/{list_test.rb → commands/list_test.rb} +1 -1
  102. data/test/{method_test.rb → commands/method_test.rb} +0 -0
  103. data/test/{post_mortem_test.rb → commands/post_mortem_test.rb} +6 -10
  104. data/test/{pry_test.rb → commands/pry_test.rb} +4 -13
  105. data/test/{quit_test.rb → commands/quit_test.rb} +4 -4
  106. data/test/{reload_test.rb → commands/reload_test.rb} +0 -0
  107. data/test/{restart_test.rb → commands/restart_test.rb} +6 -0
  108. data/test/{save_test.rb → commands/save_test.rb} +2 -2
  109. data/test/{set_test.rb → commands/set_test.rb} +9 -2
  110. data/test/{show_test.rb → commands/show_test.rb} +1 -1
  111. data/test/{source_test.rb → commands/source_test.rb} +3 -3
  112. data/test/{stepping_test.rb → commands/stepping_test.rb} +44 -35
  113. data/test/{thread_test.rb → commands/thread_test.rb} +0 -0
  114. data/test/{trace_test.rb → commands/trace_test.rb} +0 -0
  115. data/test/{display_test.rb → commands/undisplay_test.rb} +7 -45
  116. data/test/{variables_test.rb → commands/variables_test.rb} +10 -1
  117. data/test/debugger_alias_test.rb +2 -2
  118. data/test/runner_test.rb +127 -0
  119. data/test/support/matchers.rb +27 -25
  120. data/test/support/test_interface.rb +9 -5
  121. data/test/support/utils.rb +96 -101
  122. data/test/test_helper.rb +32 -20
  123. metadata +93 -68
  124. data/lib/byebug/commands/enable.rb +0 -154
  125. data/lib/byebug/commands/repl.rb +0 -126
  126. data/test/irb_test.rb +0 -47
  127. data/test/support/breakpoint.rb +0 -13
@@ -1,37 +1,39 @@
1
1
  module Byebug
2
-
2
+ #
3
+ # Processes commands in 'control' mode, when there's no program running
4
+ #
3
5
  class ControlCommandProcessor < Processor
4
- def initialize(interface)
6
+ def initialize(interface = LocalInterface.new)
5
7
  super(interface)
6
8
  @context_was_dead = false # Assume we haven't started.
7
9
  end
8
10
 
9
- def process_commands(verbose=false)
11
+ def process_commands(verbose = false)
10
12
  control_cmds = Command.commands.select do |cmd|
11
13
  cmd.allow_in_control
12
14
  end
13
15
  state = State.new(@interface, control_cmds)
14
- commands = control_cmds.map{|cmd| cmd.new(state) }
16
+ commands = control_cmds.map { |cmd| cmd.new(state) }
15
17
 
16
18
  if @context_was_dead
17
- print "The program finished.\n"
19
+ puts 'The program finished.'
18
20
  @context_was_dead = false
19
21
  end
20
22
 
21
- while input = @interface.read_command(prompt(nil))
22
- print "+#{input}" if verbose
23
- catch(:debug_error) do
24
- if cmd = commands.find{|c| c.match(input) }
25
- cmd.execute
26
- else
27
- errmsg "Unknown command\n"
28
- end
29
- end
23
+ while (input = @interface.read_command(prompt(nil)))
24
+ puts("+#{input}") if verbose
25
+
26
+ cmd = commands.find { |c| c.match(input) }
27
+ return errmsg('Unknown command') unless cmd
28
+
29
+ cmd.execute
30
30
  end
31
31
  rescue IOError, SystemCallError
32
32
  rescue
33
- print "INTERNAL ERROR!!! #{$!}\n" rescue nil
34
- print $!.backtrace.map{|l| "\t#{l}"}.join("\n") rescue nil
33
+ without_exceptions do
34
+ puts "INTERNAL ERROR!!! #{$ERROR_INFO}"
35
+ puts $ERROR_INFO.backtrace.map { |l| "\t#{l}" }.join("\n")
36
+ end
35
37
  ensure
36
38
  @interface.close
37
39
  end
@@ -39,8 +41,8 @@ module Byebug
39
41
  #
40
42
  # Prompt shown before reading a command.
41
43
  #
42
- def prompt(context)
43
- return '(byebug:ctrl) '
44
+ def prompt(_context)
45
+ '(byebug:ctrl) '
44
46
  end
45
47
 
46
48
  class State
@@ -55,9 +57,9 @@ module Byebug
55
57
  end
56
58
 
57
59
  extend Forwardable
58
- def_delegators :@interface, :errmsg, :print
60
+ def_delegators :@interface, :errmsg, :puts
59
61
 
60
- def confirm(*args)
62
+ def confirm(*_args)
61
63
  'y'
62
64
  end
63
65
 
@@ -66,10 +68,8 @@ module Byebug
66
68
  end
67
69
 
68
70
  def file
69
- errmsg "No filename given.\n"
70
- throw :debug_error
71
+ errmsg 'No filename given.'
71
72
  end
72
73
  end
73
74
  end
74
-
75
75
  end
@@ -1,12 +1,10 @@
1
1
  require 'socket'
2
2
 
3
3
  module Byebug
4
-
5
4
  # Port number used for remote debugging
6
5
  PORT = 8989 unless defined?(PORT)
7
6
 
8
7
  class << self
9
-
10
8
  # If in remote mode, wait for the remote connection
11
9
  attr_accessor :wait_connection
12
10
 
@@ -42,31 +40,24 @@ module Byebug
42
40
  @thread = DebugThread.new do
43
41
  while (session = server.accept)
44
42
  self.interface = RemoteInterface.new(session)
45
- if wait_connection
46
- mutex.synchronize do
47
- proceed.signal
48
- end
49
- end
50
- end
51
- end
52
- if wait_connection
53
- mutex.synchronize do
54
- proceed.wait(mutex)
43
+ mutex.synchronize { proceed.signal } if wait_connection
55
44
  end
56
45
  end
46
+
47
+ mutex.synchronize { proceed.wait(mutex) } if wait_connection
57
48
  end
58
49
 
59
50
  def start_control(host = nil, ctrl_port = PORT + 1)
60
- return @actual_control_port if @control_thread
61
- server = TCPServer.new(host, ctrl_port)
62
- @actual_control_port = server.addr[1]
63
- @control_thread = DebugThread.new do
64
- while (session = server.accept)
65
- interface = RemoteInterface.new(session)
66
- ControlCommandProcessor.new(interface).process_commands
67
- end
68
- end
69
- @actual_control_port
51
+ return @actual_control_port if @control_thread
52
+ server = TCPServer.new(host, ctrl_port)
53
+ @actual_control_port = server.addr[1]
54
+ @control_thread = DebugThread.new do
55
+ while (session = server.accept)
56
+ interface = RemoteInterface.new(session)
57
+ ControlCommandProcessor.new(interface).process_commands
58
+ end
59
+ end
60
+ @actual_control_port
70
61
  end
71
62
 
72
63
  #
@@ -75,21 +66,21 @@ module Byebug
75
66
  def start_client(host = 'localhost', port = PORT)
76
67
  interface = LocalInterface.new
77
68
  socket = TCPSocket.new(host, port)
78
- puts "Connected."
69
+ puts 'Connected.'
79
70
 
80
71
  catch(:exit) do
81
72
  while (line = socket.gets)
82
73
  case line
83
74
  when /^PROMPT (.*)$/
84
- input = interface.read_command($1)
75
+ input = interface.read_command(Regexp.last_match[1])
85
76
  throw :exit unless input
86
77
  socket.puts input
87
78
  when /^CONFIRM (.*)$/
88
- input = interface.confirm($1)
79
+ input = interface.confirm(Regexp.last_match[1])
89
80
  throw :exit unless input
90
81
  socket.puts input
91
82
  else
92
- print line
83
+ puts line
93
84
  end
94
85
  end
95
86
  end
@@ -0,0 +1,100 @@
1
+ require 'slop'
2
+ require 'ostruct'
3
+ require 'English'
4
+ require 'byebug/core'
5
+ require 'byebug/options'
6
+
7
+ module Byebug
8
+ #
9
+ # Responsible for starting the debugger when started from the command line.
10
+ #
11
+ class Runner
12
+ BYEBUG_SCRIPT = File.expand_path('../../../../bin/byebug')
13
+ IGNORED_FILES << BYEBUG_SCRIPT
14
+
15
+ #
16
+ # Debug a script only if syntax checks okay.
17
+ #
18
+ def debug_program(options)
19
+ output = `ruby -c "#{Byebug::PROG_SCRIPT}" 2>&1`
20
+ if $CHILD_STATUS.exitstatus != 0
21
+ Byebug.puts output
22
+ exit $CHILD_STATUS.exitstatus
23
+ end
24
+
25
+ status = Byebug.debug_load(Byebug::PROG_SCRIPT, options[:stop])
26
+ Byebug.puts "#{status}\n#{status.backtrace}" if status
27
+ end
28
+
29
+ #
30
+ # Do a shell-like path lookup for prog_script and return the results. If we
31
+ # can't find anything return prog_script.
32
+ #
33
+ def whence_file(prog_script)
34
+ if prog_script.index(File::SEPARATOR)
35
+ # Don't search since this name has path separator components
36
+ return prog_script
37
+ end
38
+
39
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |dirname|
40
+ prog_script_try = File.join(dirname, prog_script)
41
+ return prog_script_try if File.exist?(prog_script_try)
42
+ end
43
+
44
+ # Failure
45
+ prog_script
46
+ end
47
+
48
+ #
49
+ # Starts byebug to debug a program
50
+ #
51
+ def run
52
+ opts = Byebug::Options.parse
53
+
54
+ return Byebug.puts("\n Running byebug #{VERSION}\n") if opts[:version]
55
+ return Byebug.puts("#{opts.help}\n") if opts[:help]
56
+
57
+ if opts[:remote]
58
+ port, host = opts[:remote].pop.to_i, opts[:remote].pop || 'localhost'
59
+ Byebug.puts "Connecting to byebug server #{host}:#{port}..."
60
+ Byebug.start_client(host, port)
61
+ return
62
+ end
63
+
64
+ if ARGV.empty?
65
+ Byebug.puts 'You must specify a program to debug...'
66
+ abort
67
+ end
68
+
69
+ # Save debugged program
70
+ prog_script = ARGV.pop
71
+ prog_script = whence_file(prog_script) unless File.exist?(prog_script)
72
+
73
+ if Byebug.const_defined?('PROG_SCRIPT')
74
+ Byebug.send(:remove_const, 'PROG_SCRIPT')
75
+ end
76
+ Byebug.const_set('PROG_SCRIPT', File.expand_path(prog_script))
77
+
78
+ # Set up trace hook for byebug
79
+ Byebug.start
80
+
81
+ # load initrc script (e.g. .byebugrc)
82
+ Byebug.run_init_script(StringIO.new) if opts[:rc]
83
+
84
+ # Post Mortem mode status
85
+ Byebug::Setting[:post_mortem] = opts[:'post-mortem']
86
+
87
+ # Line Tracing Status
88
+ Byebug::Setting[:linetrace] = opts[:trace]
89
+
90
+ loop do
91
+ debug_program(opts)
92
+
93
+ break if opts[:quit]
94
+
95
+ processor = Byebug::ControlCommandProcessor.new
96
+ processor.process_commands
97
+ end
98
+ end
99
+ end
100
+ end
@@ -1,4 +1,7 @@
1
1
  module Byebug
2
+ #
3
+ # Parent class for all byebug settings.
4
+ #
2
5
  class Setting
3
6
  attr_accessor :value
4
7
 
@@ -34,8 +37,9 @@ module Byebug
34
37
  end
35
38
 
36
39
  def integer?
37
- integer = Integer(value) rescue nil
38
- integer ? true : false
40
+ Integer(value) ? true : false
41
+ rescue ArgumentError
42
+ false
39
43
  end
40
44
 
41
45
  def self.exists?(name)
@@ -61,18 +65,39 @@ module Byebug
61
65
  matches.size == 1 ? matches.keys.first : nil
62
66
  end
63
67
 
64
- def self.format()
65
- output = "List of settings supported in byebug:\n"
68
+ def self.help_all
69
+ output = " List of settings supported in byebug:\n --\n"
66
70
  width = settings.keys.max_by(&:size).size
67
- settings.values.each do |setting|
68
- output << sprintf("%-#{width}s -- %s\n", setting.to_sym, setting.help)
71
+ settings.values.each do |sett|
72
+ output << format(" %-#{width}s -- %s\n", sett.to_sym, sett.banner)
69
73
  end
70
- output
74
+ output + "\n"
75
+ end
76
+
77
+ def self.help(cmd, subcmd)
78
+ if subcmd
79
+ camelized = subcmd.split('_').map { |w| w.capitalize }.join
80
+ setting = Byebug.const_get("#{camelized}Setting").new
81
+ <<-EOH.gsub(/^ {8}/, '')
82
+
83
+ #{cmd} #{setting.to_sym} <value>
84
+
85
+ #{setting.banner}.
86
+
87
+ EOH
88
+ else
89
+ command = Byebug.const_get("#{cmd.capitalize}Command")
90
+ command.description + help_all
91
+ end
92
+ end
93
+
94
+ def help
95
+ "\n #{banner}.\n\n"
71
96
  end
72
97
 
73
98
  def to_sym
74
99
  name = self.class.name.gsub(/^Byebug::/, '').gsub(/Setting$/, '')
75
- name.gsub(/(.)([A-Z])/,'\1_\2').downcase.to_sym
100
+ name.gsub(/(.)([A-Z])/, '\1_\2').downcase.to_sym
76
101
  end
77
102
 
78
103
  def to_s
@@ -1,22 +1,12 @@
1
1
  module Byebug
2
+ #
3
+ # Setting for automatic evaluation of unknown commands.
4
+ #
2
5
  class AutoevalSetting < Setting
3
6
  DEFAULT = true
4
7
 
5
- def initialize
6
- EvalCommand.unknown = DEFAULT
7
- end
8
-
9
- def help
10
- 'If true, byebug will evaluate every unrecognized command. If false, ' \
11
- 'need to use the `eval` command to evaluate stuff'
12
- end
13
-
14
- def value=(v)
15
- EvalCommand.unknown = v
16
- end
17
-
18
- def value
19
- EvalCommand.unknown
8
+ def banner
9
+ 'Automatically evaluate unrecognized commands'
20
10
  end
21
11
  end
22
12
  end
@@ -1,4 +1,7 @@
1
1
  module Byebug
2
+ #
3
+ # Setting for automatically invoking IRB on every stop.
4
+ #
2
5
  class AutoirbSetting < Setting
3
6
  DEFAULT = 0
4
7
 
@@ -6,7 +9,7 @@ module Byebug
6
9
  IrbCommand.always_run = DEFAULT
7
10
  end
8
11
 
9
- def help
12
+ def banner
10
13
  'Invoke IRB on every stop'
11
14
  end
12
15
 
@@ -1,4 +1,7 @@
1
1
  module Byebug
2
+ #
3
+ # Setting for automatically listing source code on every stop.
4
+ #
2
5
  class AutolistSetting < Setting
3
6
  DEFAULT = 1
4
7
 
@@ -6,8 +9,8 @@ module Byebug
6
9
  ListCommand.always_run = DEFAULT
7
10
  end
8
11
 
9
- def help
10
- 'If true, `list` command is run everytime byebug stops'
12
+ def banner
13
+ 'Invoke list command on every stop'
11
14
  end
12
15
 
13
16
  def value=(v)
@@ -1,9 +1,12 @@
1
1
  module Byebug
2
+ #
3
+ # Setting for automatically reloading source code when it is changed.
4
+ #
2
5
  class AutoreloadSetting < Setting
3
6
  DEFAULT = true
4
7
 
5
- def help
6
- 'Reload source code when changed'
8
+ def banner
9
+ 'Automatically reload source code when it is changed'
7
10
  end
8
11
  end
9
12
  end
@@ -1,9 +1,13 @@
1
1
  module Byebug
2
+ #
3
+ # Setting for automatically saving previously entered commands to history
4
+ # when exiting the debugger.
5
+ #
2
6
  class AutosaveSetting < Setting
3
7
  DEFAULT = true
4
8
 
5
- def help
6
- 'If true, command history record is saved on exit'
9
+ def banner
10
+ 'Automatically save command history record on exit'
7
11
  end
8
12
  end
9
13
  end
@@ -1,7 +1,12 @@
1
1
  module Byebug
2
+ #
3
+ # Command to display short paths in file names.
4
+ #
5
+ # For example, when displaying source code information.
6
+ #
2
7
  class BasenameSetting < Setting
3
- def help
4
- 'Filename display style.'
8
+ def banner
9
+ '<file>:<line> information after every stop uses short paths'
5
10
  end
6
11
  end
7
12
  end