byebug 3.5.1 → 4.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 (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,4 +1,5 @@
1
1
  require 'byebug/history'
2
+ require 'byebug/helper'
2
3
 
3
4
  #
4
5
  # Namespace for all of byebug's code
@@ -11,30 +12,109 @@ module Byebug
11
12
  #
12
13
  class Interface
13
14
  attr_accessor :command_queue, :history
15
+ attr_reader :input, :output, :error
14
16
 
15
17
  def initialize
16
18
  @command_queue, @history = [], History.new
17
19
  end
18
20
 
19
21
  #
20
- # Common routine for reporting byebug error messages.
21
- # Derived classes may want to override this to capture output.
22
+ # Pops a command from the input stream.
23
+ #
24
+ def read_command(prompt)
25
+ return command_queue.shift unless command_queue.empty?
26
+
27
+ cmds = read_input(prompt)
28
+ return unless cmds
29
+
30
+ command_queue.concat(cmds)
31
+ command_queue.shift
32
+ end
33
+
34
+ include FileFunctions
35
+ #
36
+ # Pushes lines in +filename+ to the command queue.
37
+ #
38
+ def read_file(filename)
39
+ command_queue.concat(get_lines(filename))
40
+ end
41
+
42
+ #
43
+ # Reads a new line from the interface's input stream.
44
+ #
45
+ def read_input(prompt, save_hist = true)
46
+ line = readline(prompt)
47
+ return unless line
48
+
49
+ history.push(line) if save_hist
50
+
51
+ split_commands(line)
52
+ end
53
+
54
+ #
55
+ # Prints an error message to the error stream.
22
56
  #
23
57
  def errmsg(message)
24
- print("*** #{message}\n")
58
+ error.print("*** #{message}\n")
59
+ end
60
+
61
+ #
62
+ # Prints an output message to the output stream.
63
+ #
64
+ def puts(message)
65
+ output.puts(message)
25
66
  end
26
67
 
27
- protected
68
+ def print(message)
69
+ output.print(message)
70
+ end
28
71
 
29
72
  #
30
- # Stores <cmd> in commands history.
73
+ # Confirms user introduced an affirmative response to the input stream.
31
74
  #
32
- def save_history(cmd)
33
- @history.push(cmd) unless @history.ignore?(cmd)
75
+ def confirm(prompt)
76
+ readline(prompt) == 'y'
34
77
  end
35
- end
36
78
 
37
- require 'byebug/interfaces/local_interface'
38
- require 'byebug/interfaces/script_interface'
39
- require 'byebug/interfaces/remote_interface'
79
+ def close
80
+ end
81
+
82
+ #
83
+ # Saves or clears history according to +autosave+ setting.
84
+ #
85
+ def autosave
86
+ Setting[:autosave] ? history.save : history.clear
87
+ end
88
+
89
+ #
90
+ # Restores history according to +autosave+ setting.
91
+ #
92
+ def autorestore
93
+ history.restore if Setting[:autosave]
94
+ end
95
+
96
+ private
97
+
98
+ #
99
+ # Splits a command line of the form "cmd1 ; cmd2 ; ... ; cmdN" into an
100
+ # array of commands: [cmd1, cmd2, ..., cmdN]
101
+ #
102
+ def split_commands(cmd_line)
103
+ return [''] if cmd_line.empty?
104
+
105
+ cmd_line.split(/;/).each_with_object([]) do |v, m|
106
+ if m.empty? || m.last[-1] != '\\'
107
+ m << v
108
+ next
109
+ end
110
+
111
+ m.last[-1, 1] = ''
112
+ m.last << ';' << v
113
+ end
114
+ end
115
+ end
40
116
  end
117
+
118
+ require 'byebug/interfaces/local_interface'
119
+ require 'byebug/interfaces/script_interface'
120
+ require 'byebug/interfaces/remote_interface'
@@ -3,30 +3,23 @@ module Byebug
3
3
  # Interface class for standard byebug use.
4
4
  #
5
5
  class LocalInterface < Interface
6
- def read_command(prompt)
7
- readline(prompt, true)
6
+ def initialize
7
+ super()
8
+ @input, @output, @error = STDIN, STDOUT, STDERR
8
9
  end
9
10
 
10
- def confirm(prompt)
11
- readline(prompt, false)
12
- end
13
-
14
- def puts(*args)
15
- STDOUT.puts(*args)
16
- end
17
-
18
- def close
19
- end
20
-
21
- private
22
-
23
- def readline(prompt, hist)
24
- line = Readline.readline(prompt, false)
11
+ #
12
+ # Reads a single line of input using Readline. If Ctrl-C is pressed in the
13
+ # middle of input, the line is reset to only the prompt and we ask for input
14
+ # again.
15
+ #
16
+ # @param prompt Prompt to be displayed.
17
+ #
18
+ def readline(prompt)
19
+ Readline.readline(prompt, false)
25
20
  rescue Interrupt
26
21
  puts('^C')
27
22
  retry
28
- ensure
29
- save_history(line) if hist
30
23
  end
31
24
  end
32
25
  end
@@ -7,32 +7,29 @@ module Byebug
7
7
  class RemoteInterface < Interface
8
8
  def initialize(socket)
9
9
  super()
10
- @socket = socket
10
+ @input, @output, @error = socket, socket, socket
11
11
  end
12
12
 
13
- def close
14
- @socket.close
15
- rescue IOError
13
+ def read_command(prompt)
14
+ super("PROMPT #{prompt}")
16
15
  end
17
16
 
18
17
  def confirm(prompt)
19
- send_command "CONFIRM #{prompt}"
18
+ super("CONFIRM #{prompt}")
20
19
  end
21
20
 
22
- def read_command(prompt)
23
- send_command "PROMPT #{prompt}"
24
- end
25
-
26
- def puts(message)
27
- @socket.puts(message)
21
+ def close
22
+ output.close
23
+ rescue IOError
24
+ errmsg('Error closing the interface...')
28
25
  end
29
26
 
30
- private
27
+ def readline(prompt)
28
+ output.puts(prompt)
31
29
 
32
- def send_command(msg)
33
- @socket.puts msg
34
- result = @socket.gets
30
+ result = input.gets
35
31
  fail IOError unless result
32
+
36
33
  result.chomp
37
34
  end
38
35
  end
@@ -3,31 +3,27 @@ module Byebug
3
3
  # Interface class for command execution from script files.
4
4
  #
5
5
  class ScriptInterface < Interface
6
- def initialize(file, out, verbose = false)
6
+ def initialize(file, verbose = false)
7
7
  super()
8
- @file = file.respond_to?(:gets) ? file : open(file)
9
- @out, @verbose = out, verbose
8
+ @input = File.open(file)
9
+ @output = verbose ? STDOUT : StringIO.new
10
+ @error = verbose ? STDERR : StringIO.new
10
11
  end
11
12
 
12
- def read_command(_prompt)
13
- while (result = @file.gets)
14
- puts "# #{result}" if @verbose
15
- next if result =~ /^\s*#/
16
- next if result.strip.empty?
17
- return result.chomp
18
- end
19
- end
20
-
21
- def confirm(_prompt)
22
- 'y'
13
+ def read_command(prompt)
14
+ readline(prompt, false)
23
15
  end
24
16
 
25
- def puts(message)
26
- @out.printf(message)
17
+ def close
18
+ input.close
27
19
  end
28
20
 
29
- def close
30
- @file.close
21
+ def readline(*)
22
+ while (result = input.gets)
23
+ output.puts "+ #{result}"
24
+ next if result =~ /^\s*#/
25
+ return result.chomp
26
+ end
31
27
  end
32
28
  end
33
29
  end
@@ -0,0 +1,54 @@
1
+ module Byebug
2
+ #
3
+ # Custom interface for easier assertions
4
+ #
5
+ class TestInterface < Interface
6
+ attr_accessor :test_block
7
+
8
+ def initialize
9
+ super()
10
+ @input, @output, @error = [], [], []
11
+ end
12
+
13
+ def errmsg(message)
14
+ error.concat(message.to_s.split("\n"))
15
+ end
16
+
17
+ def print(message)
18
+ output.concat(message.to_s.split("\n"))
19
+ end
20
+
21
+ def puts(message)
22
+ output.concat(message.to_s.split("\n"))
23
+ end
24
+
25
+ def read_command(prompt)
26
+ cmd = super(prompt)
27
+
28
+ return cmd unless cmd.nil? && test_block
29
+
30
+ test_block.call
31
+ self.test_block = nil
32
+ end
33
+
34
+ def clear
35
+ @input, @output, @error = [], [], []
36
+ history.clear
37
+ end
38
+
39
+ def inspect
40
+ [
41
+ 'Input:', input.join("\n"),
42
+ 'Output:', output.join("\n"),
43
+ 'Error:', error.join("\n")
44
+ ].join("\n")
45
+ end
46
+
47
+ def readline(prompt)
48
+ puts(prompt)
49
+
50
+ cmd = input.shift
51
+ cmd.is_a?(Proc) ? cmd.call : cmd
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,64 @@
1
+ require 'yaml'
2
+
3
+ module Byebug
4
+ module Printers
5
+ class Base
6
+ class MissedPath < StandardError; end
7
+ class MissedArgument < StandardError; end
8
+
9
+ SEPARATOR = '.'
10
+
11
+ def type
12
+ self.class.name.split('::').last.downcase
13
+ end
14
+
15
+ private
16
+
17
+ def locate(path)
18
+ result = nil
19
+ contents.each do |_, contents|
20
+ result = parts(path).reduce(contents) do |r, part|
21
+ r && r.key?(part) ? r[part] : nil
22
+ end
23
+ break if result
24
+ end
25
+ fail MissedPath, "Can't find part path '#{path}'" unless result
26
+ result
27
+ end
28
+
29
+ def translate(string, args = {})
30
+ # they may contain #{} string interpolation
31
+ string.gsub(/\|\w+$/, '').gsub(/([^#]?){([^}]*)}/) do
32
+ key = Regexp.last_match[2].to_s
33
+ unless args.key?(key.to_sym)
34
+ fail MissedArgument, "Missed argument #{key} for '#{string}'"
35
+ end
36
+
37
+ "#{Regexp.last_match[1]}#{args[key.to_sym]}"
38
+ end
39
+ end
40
+
41
+ def parts(path)
42
+ path.split(SEPARATOR)
43
+ end
44
+
45
+ def contents
46
+ @contents ||= contents_files.each_with_object({}) do |filename, hash|
47
+ hash[filename] = YAML.load_file(filename) || {}
48
+ end
49
+ end
50
+
51
+ def array_of_args(collection, &block)
52
+ collection_with_index = collection.each.with_index
53
+ collection_with_index.each_with_object([]) do |(item, index), array|
54
+ args = block.call(item, index)
55
+ array << args if args
56
+ end
57
+ end
58
+
59
+ def contents_files
60
+ [File.expand_path(File.join('..', 'texts', 'base.yml'), __FILE__)]
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,53 @@
1
+ require 'byebug/printers/base'
2
+
3
+ module Byebug
4
+ module Printers
5
+ class Plain < Base
6
+ include Columnize
7
+
8
+ def print(path, args = {})
9
+ message = translate(locate(path), args)
10
+ tail = parts(path).include?('confirmations') ? ' (y/n) ' : "\n"
11
+ message << tail
12
+ end
13
+
14
+ def print_collection(path, collection, &block)
15
+ modifier = get_modifier(path)
16
+ lines = array_of_args(collection, &block).map do |args|
17
+ print(path, args)
18
+ end
19
+
20
+ if modifier == 'c'
21
+ columnize(lines.map { |l| l.gsub(/\n$/, '') }, Setting[:width])
22
+ else
23
+ lines.join('')
24
+ end
25
+ end
26
+
27
+ def print_variables(variables)
28
+ print_collection('variable.variable', variables) do |(key, value), _|
29
+ value = value.nil? ? 'nil' : value.to_s
30
+ if "#{key} = #{value}".size > Setting[:width]
31
+ key_size = "#{key} = ".size
32
+ value = value[0..Setting[:width] - key_size - 4] + '...'
33
+ end
34
+
35
+ { key: key, value: value }
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def get_modifier(path)
42
+ modifier_regexp = /\|(\w+)$/
43
+ modifier_match = locate(path).match(modifier_regexp)
44
+ modifier_match && modifier_match[1]
45
+ end
46
+
47
+ def contents_files
48
+ [File.expand_path(File.join('..', 'texts', 'plain.yml'), __FILE__)] +
49
+ super
50
+ end
51
+ end
52
+ end
53
+ end
@@ -16,9 +16,28 @@ module Byebug
16
16
  rescue
17
17
  nil
18
18
  end
19
+
20
+ def self.load_commands
21
+ Dir.glob(File.expand_path('../commands/*.rb', __FILE__)).each do |file|
22
+ require file
23
+ end
24
+ end
25
+
26
+ def self.load_settings
27
+ Dir.glob(File.expand_path('../settings/*.rb', __FILE__)).each do |file|
28
+ require file
29
+ end
30
+
31
+ Byebug.constants.grep(/[a-z]Setting/).map do |name|
32
+ setting = Byebug.const_get(name).new
33
+ Byebug::Setting.settings[setting.to_sym] = setting
34
+ end
35
+ end
19
36
  end
37
+
38
+ Processor.load_commands
39
+ Processor.load_settings
20
40
  end
21
41
 
22
- require 'byebug/command'
23
42
  require 'byebug/processors/command_processor'
24
43
  require 'byebug/processors/control_command_processor'