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,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'