byebug 3.5.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/.rubocop.yml +18 -1
  4. data/.travis.yml +21 -1
  5. data/CHANGELOG.md +356 -308
  6. data/CONTRIBUTING.md +31 -15
  7. data/GUIDE.md +859 -475
  8. data/Gemfile +8 -10
  9. data/LICENSE +1 -1
  10. data/README.md +41 -45
  11. data/Rakefile +30 -28
  12. data/byebug.gemspec +18 -18
  13. data/ext/byebug/breakpoint.c +88 -75
  14. data/ext/byebug/byebug.c +253 -252
  15. data/ext/byebug/byebug.h +53 -53
  16. data/ext/byebug/context.c +188 -159
  17. data/ext/byebug/extconf.rb +9 -6
  18. data/ext/byebug/locker.c +53 -11
  19. data/ext/byebug/threads.c +137 -39
  20. data/lib/byebug/attacher.rb +7 -2
  21. data/lib/byebug/breakpoint.rb +30 -0
  22. data/lib/byebug/command.rb +36 -32
  23. data/lib/byebug/commands/break.rb +49 -48
  24. data/lib/byebug/commands/catch.rb +64 -0
  25. data/lib/byebug/commands/condition.rb +13 -9
  26. data/lib/byebug/commands/continue.rb +8 -4
  27. data/lib/byebug/commands/delete.rb +10 -4
  28. data/lib/byebug/commands/display.rb +33 -25
  29. data/lib/byebug/commands/edit.rb +18 -13
  30. data/lib/byebug/commands/enable_disable.rb +26 -24
  31. data/lib/byebug/commands/eval.rb +77 -35
  32. data/lib/byebug/commands/finish.rb +9 -5
  33. data/lib/byebug/commands/frame.rb +66 -125
  34. data/lib/byebug/commands/help.rb +14 -21
  35. data/lib/byebug/commands/history.rb +5 -1
  36. data/lib/byebug/commands/info.rb +41 -106
  37. data/lib/byebug/commands/interrupt.rb +6 -2
  38. data/lib/byebug/commands/irb.rb +5 -2
  39. data/lib/byebug/commands/kill.rb +6 -2
  40. data/lib/byebug/commands/list.rb +21 -14
  41. data/lib/byebug/commands/method.rb +17 -9
  42. data/lib/byebug/commands/pry.rb +13 -3
  43. data/lib/byebug/commands/quit.rb +10 -5
  44. data/lib/byebug/commands/restart.rb +12 -19
  45. data/lib/byebug/commands/save.rb +10 -6
  46. data/lib/byebug/commands/set.rb +15 -14
  47. data/lib/byebug/commands/show.rb +8 -8
  48. data/lib/byebug/commands/source.rb +14 -8
  49. data/lib/byebug/commands/stepping.rb +15 -29
  50. data/lib/byebug/commands/threads.rb +73 -49
  51. data/lib/byebug/commands/tracevar.rb +56 -0
  52. data/lib/byebug/commands/undisplay.rb +8 -4
  53. data/lib/byebug/commands/untracevar.rb +38 -0
  54. data/lib/byebug/commands/var.rb +107 -0
  55. data/lib/byebug/context.rb +78 -42
  56. data/lib/byebug/core.rb +78 -40
  57. data/lib/byebug/helper.rb +58 -42
  58. data/lib/byebug/history.rb +12 -1
  59. data/lib/byebug/interface.rb +91 -11
  60. data/lib/byebug/interfaces/local_interface.rb +12 -19
  61. data/lib/byebug/interfaces/remote_interface.rb +12 -15
  62. data/lib/byebug/interfaces/script_interface.rb +14 -18
  63. data/lib/byebug/interfaces/test_interface.rb +54 -0
  64. data/lib/byebug/printers/base.rb +64 -0
  65. data/lib/byebug/printers/plain.rb +53 -0
  66. data/lib/byebug/processor.rb +20 -1
  67. data/lib/byebug/processors/command_processor.rb +57 -172
  68. data/lib/byebug/processors/control_command_processor.rb +16 -43
  69. data/lib/byebug/remote.rb +13 -7
  70. data/lib/byebug/runner.rb +102 -54
  71. data/lib/byebug/setting.rb +45 -68
  72. data/lib/byebug/settings/autoeval.rb +2 -0
  73. data/lib/byebug/settings/autoirb.rb +3 -0
  74. data/lib/byebug/settings/autolist.rb +3 -0
  75. data/lib/byebug/settings/autosave.rb +2 -0
  76. data/lib/byebug/settings/basename.rb +2 -0
  77. data/lib/byebug/settings/callstyle.rb +2 -0
  78. data/lib/byebug/settings/fullpath.rb +2 -0
  79. data/lib/byebug/settings/histfile.rb +2 -0
  80. data/lib/byebug/settings/histsize.rb +2 -0
  81. data/lib/byebug/settings/linetrace.rb +2 -0
  82. data/lib/byebug/settings/listsize.rb +2 -0
  83. data/lib/byebug/settings/post_mortem.rb +7 -2
  84. data/lib/byebug/settings/stack_on_error.rb +2 -0
  85. data/lib/byebug/settings/verbose.rb +2 -0
  86. data/lib/byebug/settings/width.rb +2 -0
  87. data/lib/byebug/state.rb +12 -0
  88. data/lib/byebug/states/control_state.rb +26 -0
  89. data/lib/byebug/states/regular_state.rb +178 -0
  90. data/lib/byebug/version.rb +1 -1
  91. metadata +24 -109
  92. data/lib/byebug/commands/catchpoint.rb +0 -53
  93. data/lib/byebug/commands/reload.rb +0 -29
  94. data/lib/byebug/commands/trace.rb +0 -50
  95. data/lib/byebug/commands/variables.rb +0 -206
  96. data/lib/byebug/options.rb +0 -46
  97. data/lib/byebug/settings/autoreload.rb +0 -12
  98. data/lib/byebug/settings/forcestep.rb +0 -14
  99. data/lib/byebug/settings/testing.rb +0 -12
  100. data/lib/byebug/settings/tracing_plus.rb +0 -11
  101. data/test/commands/break_test.rb +0 -364
  102. data/test/commands/condition_test.rb +0 -85
  103. data/test/commands/continue_test.rb +0 -47
  104. data/test/commands/delete_test.rb +0 -26
  105. data/test/commands/display_test.rb +0 -37
  106. data/test/commands/edit_test.rb +0 -52
  107. data/test/commands/eval_test.rb +0 -89
  108. data/test/commands/finish_test.rb +0 -74
  109. data/test/commands/frame_test.rb +0 -223
  110. data/test/commands/help_test.rb +0 -66
  111. data/test/commands/history_test.rb +0 -61
  112. data/test/commands/info_test.rb +0 -238
  113. data/test/commands/interrupt_test.rb +0 -45
  114. data/test/commands/irb_test.rb +0 -28
  115. data/test/commands/kill_test.rb +0 -50
  116. data/test/commands/list_test.rb +0 -174
  117. data/test/commands/method_test.rb +0 -52
  118. data/test/commands/post_mortem_test.rb +0 -71
  119. data/test/commands/pry_test.rb +0 -26
  120. data/test/commands/quit_test.rb +0 -53
  121. data/test/commands/reload_test.rb +0 -39
  122. data/test/commands/restart_test.rb +0 -46
  123. data/test/commands/save_test.rb +0 -67
  124. data/test/commands/set_test.rb +0 -140
  125. data/test/commands/show_test.rb +0 -76
  126. data/test/commands/source_test.rb +0 -46
  127. data/test/commands/stepping_test.rb +0 -192
  128. data/test/commands/thread_test.rb +0 -164
  129. data/test/commands/trace_test.rb +0 -71
  130. data/test/commands/undisplay_test.rb +0 -75
  131. data/test/commands/variables_test.rb +0 -105
  132. data/test/debugger_alias_test.rb +0 -7
  133. data/test/runner_test.rb +0 -150
  134. data/test/support/matchers.rb +0 -65
  135. data/test/support/test_interface.rb +0 -59
  136. data/test/support/utils.rb +0 -122
  137. data/test/test_helper.rb +0 -58
@@ -1,3 +1,5 @@
1
+ require 'byebug/command'
2
+
1
3
  module Byebug
2
4
  #
3
5
  # Implements breakpoint functionality
@@ -6,78 +8,77 @@ module Byebug
6
8
  self.allow_in_post_mortem = false
7
9
  self.allow_in_control = true
8
10
 
9
- POSITION_REGEXP = '(?:(\d+)|(.+?)[:.#]([^.:\s]+))'
10
-
11
11
  def regexp
12
- /^\s* b(?:reak)? (?:\s+ #{POSITION_REGEXP})? (?:\s+(.+))? \s*$/x
12
+ /^\s* b(?:reak)? (?:\s+ (\S+))? (?:\s+ if \s+(.+))? \s*$/x
13
13
  end
14
14
 
15
15
  def execute
16
- return puts(self.class.help) if self.class.names.include?(@match[0])
16
+ return puts(self.class.help) unless @match[1]
17
17
 
18
- if @match[1]
19
- line, _, _, expr = @match.captures
20
- else
21
- _, file, line, expr = @match.captures
18
+ brkpt = line_breakpoint(@match[1]) || method_breakpoint(@match[1])
19
+ if syntax_valid?(@match[2])
20
+ return puts(
21
+ pr('break.created', id: brkpt.id, file: brkpt.source, line: brkpt.pos)
22
+ )
22
23
  end
23
24
 
24
- if expr && file.nil? && line.nil?
25
- return errmsg("Invalid breakpoint location: #{expr}")
26
- elsif expr && expr !~ /^\s*if\s+(.+)/
27
- return errmsg("Expecting \"if\" in breakpoint condition, got: #{expr}")
28
- else
29
- expr = $1
25
+ errmsg(pr('break.errors.expression', expr: @match[2]))
26
+ brkpt.enabled = false
27
+ rescue => e
28
+ errmsg(e.message)
29
+ end
30
+
31
+ class << self
32
+ def names
33
+ %w(break)
30
34
  end
31
35
 
32
- if file.nil? && !@state.context
33
- return errmsg('We are not in a state that has an associated file')
36
+ def description
37
+ prettify <<-EOD
38
+ b[reak] [file:]line [if expr]
39
+ b[reak] [module::...]class(.|#)method [if expr]
40
+
41
+ Set breakpoint to some position, (optionally) if expr == true
42
+ EOD
34
43
  end
44
+ end
35
45
 
36
- file = @state.file if file.nil?
37
- line = @state.line.to_s if line.nil?
46
+ private
38
47
 
39
- if line =~ /^\d+$/
40
- path = CommandProcessor.canonic_file(file)
41
- return errmsg("No file named #{path}") unless File.exist?(file)
48
+ def line_breakpoint(loc)
49
+ line, file_line = loc.match(/^(\d+)$/), loc.match(/^([^:]+):(\d+)$/)
50
+ return nil unless line || file_line
42
51
 
43
- l, n = line.to_i, File.foreach(file).count
44
- return errmsg("There are only #{n} lines in file #{path}") if l > n
52
+ f, l = line ? [@state.file, line[1]] : [file_line[1], file_line[2]]
45
53
 
46
- autoreload = Setting[:autoreload]
47
- possible_lines = LineCache.trace_line_numbers(file, autoreload)
48
- unless possible_lines.member?(l)
49
- return errmsg("Line #{l} is not a valid breakpoint in file #{path}")
50
- end
54
+ check_errors(f, l.to_i)
51
55
 
52
- b = Breakpoint.add(file, l, expr)
53
- puts "Created breakpoint #{b.id} at #{path}:#{l}"
56
+ Breakpoint.add(File.expand_path(f), l.to_i, @match[2])
57
+ end
54
58
 
55
- unless syntax_valid?(expr)
56
- errmsg("Incorrect expression \"#{expr}\"; breakpoint disabled.")
57
- b.enabled = false
58
- end
59
+ def method_breakpoint(location)
60
+ location.match(/([^.#]+)[.#](.+)/) do |match|
61
+ k, m = bb_warning_eval(match[1]), match[2]
59
62
 
60
- else
61
- kl = bb_warning_eval(file)
62
- return errmsg("Unknown class #{file}") unless kl && kl.is_a?(Module)
63
+ klass = k && k.is_a?(Module) ? k.name : match[1]
64
+ method = m.intern
63
65
 
64
- class_name, method = kl.name, line.intern
65
- b = Breakpoint.add(class_name, method, expr)
66
- puts "Created breakpoint #{b.id} at #{class_name}::#{method}"
66
+ Breakpoint.add(klass, method, @match[2])
67
67
  end
68
68
  end
69
69
 
70
- class << self
71
- def names
72
- %w(break)
73
- end
70
+ def check_errors(file, line)
71
+ path, deco_path = File.expand_path(file), normalize(file)
74
72
 
75
- def description
76
- %{b[reak] file:line [if expr]
77
- b[reak] class(.|#)method [if expr]
73
+ fail(pr('break.errors.source', file: deco_path)) unless File.exist?(path)
78
74
 
79
- Set breakpoint to some position, (optionally) if expr == true}
75
+ if line > n_lines(file)
76
+ fail(pr('break.errors.far_line', lines: n_lines(file), file: deco_path))
80
77
  end
78
+
79
+ return if Breakpoint.potential_line?(path, line)
80
+
81
+ fail(pr('break.errors.line', file: deco_path, line: line))
81
82
  end
82
83
  end
83
84
  end
@@ -0,0 +1,64 @@
1
+ require 'byebug/command'
2
+
3
+ module Byebug
4
+ #
5
+ # Implements exception catching.
6
+ #
7
+ # Enables the user to catch unhandled assertion when they happen.
8
+ #
9
+ class CatchCommand < Command
10
+ self.allow_in_control = false
11
+
12
+ def regexp
13
+ /^\s* cat(?:ch)? (?:\s+(\S+))? (?:\s+(off))? \s*$/x
14
+ end
15
+
16
+ def execute
17
+ ex = @match[1]
18
+ return info_catch unless ex
19
+
20
+ cmd = @match[2]
21
+ unless cmd
22
+ if 'off' == ex
23
+ Byebug.catchpoints.clear if
24
+ confirm(pr('catch.confirmations.delete_all'))
25
+
26
+ return
27
+ end
28
+
29
+ is_class = bb_eval("#{ex.is_a?(Class)}")
30
+ puts pr('catch.errors.not_class', class: ex) unless is_class
31
+
32
+ Byebug.add_catchpoint(ex)
33
+ return puts pr('catch.catching', exception: ex)
34
+ end
35
+
36
+ if cmd == 'off'
37
+ exists = Byebug.catchpoints.member?(ex)
38
+ return errmsg pr('catch.errors.not_found', exception: ex) unless exists
39
+
40
+ Byebug.catchpoints.delete(ex)
41
+ return errmsg pr('catch.errors.removed', exception: ex)
42
+ end
43
+
44
+ errmsg pr('catch.errors.off', off: cmd)
45
+ end
46
+
47
+ class << self
48
+ def names
49
+ %w(catch)
50
+ end
51
+
52
+ def description
53
+ prettify <<-EOD
54
+ cat[ch][ (off|<exception>[ off])]
55
+
56
+ "catch" lists catchpoints.
57
+ "catch off" deletes all catchpoints.
58
+ "catch <exception>" enables handling <exception>.
59
+ "catch <exception> off" disables handling <exception>.
60
+ EOD
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,3 +1,5 @@
1
+ require 'byebug/command'
2
+
1
3
  module Byebug
2
4
  #
3
5
  # Implements conditions on breakpoints.
@@ -12,20 +14,20 @@ module Byebug
12
14
  end
13
15
 
14
16
  def execute
15
- return puts(ConditionCommand.help) unless @match[1]
17
+ return puts(self.class.help) unless @match[1]
16
18
 
17
- breakpoints = Byebug.breakpoints.sort_by { |b| b.id }
18
- return errmsg('No breakpoints have been set') unless breakpoints.any?
19
+ breakpoints = Byebug.breakpoints.sort_by(&:id)
20
+ return errmsg(pr('condition.errors.no_breakpoints')) if breakpoints.empty?
19
21
 
20
22
  pos, err = get_int(@match[1], 'Condition', 1)
21
23
  return errmsg(err) if err
22
24
 
23
25
  breakpoint = breakpoints.find { |b| b.id == pos }
24
- return errmsg('Invalid breakpoint id. Use "info breakpoint" to find ' \
25
- 'out the correct id') unless breakpoint
26
+ return errmsg(pr('break.errors.no_breakpoint')) unless breakpoint
26
27
 
27
- return errmsg("Incorrect expression \"#{@match[2]}\", " \
28
- 'breakpoint not changed') unless syntax_valid?(@match[2])
28
+ unless syntax_valid?(@match[2])
29
+ return errmsg(pr('break.errors.not_changed', expr: @match[2]))
30
+ end
29
31
 
30
32
  breakpoint.expr = @match[2]
31
33
  end
@@ -36,12 +38,14 @@ module Byebug
36
38
  end
37
39
 
38
40
  def description
39
- %(cond[ition] <n>[ expr]
41
+ prettify <<-EOD
42
+ cond[ition] <n>[ expr]
40
43
 
41
44
  Specify breakpoint number <n> to break only if <expr> is true. <n> is
42
45
  an integer and <expr> is an expression to be evaluated whenever
43
46
  breakpoint <n> is reached. If no expression is specified, the
44
- condition is removed.)
47
+ condition is removed.
48
+ EOD
45
49
  end
46
50
  end
47
51
  end
@@ -1,3 +1,5 @@
1
+ require 'byebug/command'
2
+
1
3
  module Byebug
2
4
  #
3
5
  # Implements the continue command.
@@ -16,8 +18,8 @@ module Byebug
16
18
  return errmsg(err) unless num
17
19
 
18
20
  filename = File.expand_path(@state.file)
19
- unless LineCache.trace_line_numbers(filename).member?(num)
20
- return errmsg("Line #{num} is not a valid stopping point in file")
21
+ unless Breakpoint.potential_line?(filename, num)
22
+ return errmsg(pr('continue.errors.unstopped_line', line: num))
21
23
  end
22
24
 
23
25
  Breakpoint.add(filename, num)
@@ -32,9 +34,11 @@ module Byebug
32
34
  end
33
35
 
34
36
  def description
35
- %(c[ont[inue]][ <n>]
37
+ prettify <<-EOD
38
+ c[ont[inue]][ <n>]
36
39
 
37
- Run until program ends, hits a breakpoint or reaches line <n>.)
40
+ Run until program ends, hits a breakpoint or reaches line <n>.
41
+ EOD
38
42
  end
39
43
  end
40
44
  end
@@ -1,3 +1,5 @@
1
+ require 'byebug/command'
2
+
1
3
  module Byebug
2
4
  #
3
5
  # Implements breakpoint deletion.
@@ -12,7 +14,9 @@ module Byebug
12
14
 
13
15
  def execute
14
16
  unless @match[1]
15
- Byebug.breakpoints.clear if confirm('Delete all breakpoints? (y/n) ')
17
+ if confirm(pr('break.confirmations.delete_all'))
18
+ Byebug.breakpoints.clear
19
+ end
16
20
 
17
21
  return nil
18
22
  end
@@ -23,7 +27,7 @@ module Byebug
23
27
  return errmsg(err) unless pos
24
28
 
25
29
  unless Breakpoint.remove(pos)
26
- return errmsg("No breakpoint number #{pos}")
30
+ return errmsg(pr('break.errors.no_breakpoint_delete', pos: pos))
27
31
  end
28
32
  end
29
33
  end
@@ -34,10 +38,12 @@ module Byebug
34
38
  end
35
39
 
36
40
  def description
37
- %(del[ete][ nnn...]
41
+ prettify <<-EOD
42
+ del[ete][ nnn...]
38
43
 
39
44
  Without and argument, deletes all breakpoints. With integer
40
- arguments, it deletes specific breakpoints.)
45
+ arguments, it deletes specific breakpoints.
46
+ EOD
41
47
  end
42
48
  end
43
49
  end
@@ -1,25 +1,6 @@
1
- module Byebug
2
- #
3
- # Custom display utilities.
4
- #
5
- module DisplayFunctions
6
- def display_expression(exp)
7
- "#{exp} = #{bb_warning_eval(exp).inspect}"
8
- end
9
-
10
- def active_display_expressions?
11
- @state.display.select { |d| d[0] }.size > 0
12
- end
13
-
14
- def print_display_expressions
15
- n = 1
16
- @state.display.each do |d|
17
- puts "#{n}: #{display_expression(d[1])}" if d[0]
18
- n += 1
19
- end
20
- end
21
- end
1
+ require 'byebug/command'
22
2
 
3
+ module Byebug
23
4
  #
24
5
  # Implements the functionality of adding custom expressions to be displayed
25
6
  # every time the debugger stops.
@@ -34,7 +15,7 @@ module Byebug
34
15
  def execute
35
16
  exp = @match[1]
36
17
  @state.display.push [true, exp]
37
- puts "#{@state.display.size}: #{display_expression(exp)}"
18
+ display_expression(exp)
38
19
  end
39
20
 
40
21
  class << self
@@ -43,11 +24,22 @@ module Byebug
43
24
  end
44
25
 
45
26
  def description
46
- %(disp[lay] <expression>
27
+ prettify <<-EOD
28
+ disp[lay] <expression>
47
29
 
48
- Add <expression> into display expression list.)
30
+ Add <expression> into display expression list.
31
+ EOD
49
32
  end
50
33
  end
34
+
35
+ private
36
+
37
+ def display_expression(exp)
38
+ print pr('display.result',
39
+ n: @state.display.size,
40
+ exp: exp,
41
+ result: bb_warning_eval(exp).inspect)
42
+ end
51
43
  end
52
44
 
53
45
  #
@@ -74,8 +66,24 @@ module Byebug
74
66
  end
75
67
 
76
68
  def description
77
- %(disp[lay] Display expression list.)
69
+ prettify <<-EOD
70
+ disp[lay] Display expression list.
71
+ EOD
72
+ end
73
+ end
74
+
75
+ private
76
+
77
+ def print_display_expressions
78
+ result = prc('display.result', @state.display) do |item, index|
79
+ is_active, expression = item
80
+ if is_active
81
+ { n: index + 1,
82
+ exp: expression,
83
+ result: bb_warning_eval(expression).inspect }
84
+ end
78
85
  end
86
+ print result
79
87
  end
80
88
  end
81
89
  end
@@ -1,3 +1,5 @@
1
+ require 'byebug/command'
2
+
1
3
  module Byebug
2
4
  #
3
5
  # Edit a file from byebug's prompt.
@@ -11,27 +13,28 @@ module Byebug
11
13
 
12
14
  def execute
13
15
  if !@match[1]
14
- unless @state.file
15
- return errmsg "We are not in a state that has an associated file.\n"
16
- end
16
+ return errmsg(pr('edit.errors.state')) unless @state.file
17
17
  file = @state.file
18
18
  line = @state.line if @state.line
19
19
  elsif (@pos_match = /([^:]+)[:]([0-9]+)/.match(@match[1]))
20
20
  file, line = @pos_match.captures
21
- elsif File.exist?(@match[1])
22
- file = @match[1]
23
21
  else
24
- return errmsg "Invalid file[:line] number specification: #{@match[1]}\n"
22
+ file = @match[1]
25
23
  end
26
24
 
27
25
  editor = ENV['EDITOR'] || 'vim'
26
+ file = File.expand_path(file)
28
27
 
29
- if File.readable?(file)
30
- system("#{editor} +#{line} #{file}") if line
31
- system("#{editor} #{file}") unless line
32
- else
33
- errmsg "File \"#{file}\" is not readable.\n"
28
+ unless File.exist?(file)
29
+ return errmsg(pr('edit.errors.not_exist', file: file))
34
30
  end
31
+ unless File.readable?(file)
32
+ return errmsg(pr('edit.errors.not_readable', file: file))
33
+ end
34
+
35
+ cmd = line ? "#{editor} +#{line} #{file}" : "#{editor} #{file}"
36
+
37
+ system(cmd)
35
38
  end
36
39
 
37
40
  class << self
@@ -40,11 +43,13 @@ module Byebug
40
43
  end
41
44
 
42
45
  def description
43
- %(edit[ file:lineno] Edit specified files.
46
+ prettify <<-EOD
47
+ edit[ file:lineno] Edit specified files.
44
48
 
45
49
  With no argument, edits file containing most recent line listed.
46
50
  Editing targets can also be specified to start editing at a specific
47
- line in a specific file.)
51
+ line in a specific file.
52
+ EOD
48
53
  end
49
54
  end
50
55
  end