byebug 3.2.0 β†’ 3.3.0

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