byebug 4.0.4 → 4.0.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/CONTRIBUTING.md +5 -0
- data/GUIDE.md +63 -42
- data/lib/byebug/attacher.rb +5 -5
- data/lib/byebug/commands/break.rb +4 -5
- data/lib/byebug/commands/catch.rb +0 -2
- data/lib/byebug/commands/delete.rb +1 -1
- data/lib/byebug/commands/enable_disable.rb +1 -1
- data/lib/byebug/commands/info.rb +1 -1
- data/lib/byebug/commands/thread.rb +145 -0
- data/lib/byebug/commands/untracevar.rb +1 -1
- data/lib/byebug/context.rb +3 -0
- data/lib/byebug/core.rb +3 -47
- data/lib/byebug/helper.rb +23 -4
- data/lib/byebug/runner.rb +67 -22
- data/lib/byebug/version.rb +1 -1
- metadata +4 -4
- data/lib/byebug/commands/threads.rb +0 -237
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86c24793f077ce32dceea91c8bde07dce922a274
|
4
|
+
data.tar.gz: f166af0f5a9b01024978ebf2ebb5d9b7103d8a7b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19d9a87a1f69496bdb00574437c3913b167d2da92d1b1b35c64412a70adfc8309f2bc78bdac5233bea310bd46543af2966b762453318e450ff6d73092626b16d
|
7
|
+
data.tar.gz: cfe46396685e6cec68816f38b70183317cf7585e1bbec594de6e670962151a5cd1eb4e1eb2483c0aafe43e94d741589c595c8d8e5a4cecb5124200b617c04b05
|
data/CHANGELOG.md
CHANGED
data/CONTRIBUTING.md
CHANGED
@@ -17,6 +17,11 @@ API and a lot of bugs have been recently corrected. Without this fixes,
|
|
17
17
|
`byebug` will fail to work properly, so make sure you have always the last
|
18
18
|
patch level releases of Ruby installed.
|
19
19
|
|
20
|
+
Also, if you are developing on linux, make sure you have the GNU indent utility
|
21
|
+
installed for automatic check of code style in C files. If you're developing in
|
22
|
+
MacOSX, just make sure you keep a consistent style if you edit the C-extension
|
23
|
+
files. Travis CI will do the automatic check anyways.
|
24
|
+
|
20
25
|
|
21
26
|
## Getting started
|
22
27
|
|
data/GUIDE.md
CHANGED
@@ -223,28 +223,28 @@ the output so that it nicely fits our screen.
|
|
223
223
|
(byebug) set width 80
|
224
224
|
Maximum width of byebug's output is 80
|
225
225
|
(byebug) ps private_methods
|
226
|
-
Array default_src_encoding open sleep
|
227
|
-
Complex define_method p spawn
|
228
|
-
Digest eval pp sprintf
|
229
|
-
Float exec print srand
|
230
|
-
Hash exit printf syscall
|
231
|
-
Integer exit! private system
|
232
|
-
Pathname fail proc test
|
233
|
-
Rational fork public throw
|
234
|
-
String format putc timeout
|
235
|
-
URI gem_original_require puts trace_var
|
236
|
-
__callee__ gets raise trap
|
226
|
+
Array default_src_encoding open sleep
|
227
|
+
Complex define_method p spawn
|
228
|
+
Digest eval pp sprintf
|
229
|
+
Float exec print srand
|
230
|
+
Hash exit printf syscall
|
231
|
+
Integer exit! private system
|
232
|
+
Pathname fail proc test
|
233
|
+
Rational fork public throw
|
234
|
+
String format putc timeout
|
235
|
+
URI gem_original_require puts trace_var
|
236
|
+
__callee__ gets raise trap
|
237
237
|
__dir__ global_variables rand untrace_var
|
238
|
-
__method__ include readline using
|
239
|
-
` initialize readlines warn
|
240
|
-
abort initialize_clone require y
|
241
|
-
at_exit initialize_copy require_relative
|
242
|
-
autoload initialize_dup respond_to_missing?
|
243
|
-
autoload? iterator? rubygems_require
|
244
|
-
binding lambda select
|
245
|
-
block_given? load set_trace_func
|
246
|
-
caller local_variables singleton_method_added
|
247
|
-
caller_locations loop singleton_method_removed
|
238
|
+
__method__ include readline using
|
239
|
+
` initialize readlines warn
|
240
|
+
abort initialize_clone require y
|
241
|
+
at_exit initialize_copy require_relative
|
242
|
+
autoload initialize_dup respond_to_missing?
|
243
|
+
autoload? iterator? rubygems_require
|
244
|
+
binding lambda select
|
245
|
+
block_given? load set_trace_func
|
246
|
+
caller local_variables singleton_method_added
|
247
|
+
caller_locations loop singleton_method_removed
|
248
248
|
catch method_missing singleton_method_undefined
|
249
249
|
(byebug)
|
250
250
|
```
|
@@ -500,7 +500,7 @@ Run options: --seed 31679
|
|
500
500
|
|
501
501
|
[2, 11] in test_triangle.rb
|
502
502
|
2: require_relative 'triangle.rb'
|
503
|
-
3:
|
503
|
+
3:
|
504
504
|
4: class TestTriangle < Minitest::Test
|
505
505
|
5: def test_basic
|
506
506
|
6: byebug
|
@@ -1035,7 +1035,7 @@ run a sleeping thread.
|
|
1035
1035
|
|
1036
1036
|
Now we can investigate the problem in the employer's side:
|
1037
1037
|
|
1038
|
-
|
1038
|
+
```bash
|
1039
1039
|
(byebug) s
|
1040
1040
|
[30, 39] in /path/to/company.rb
|
1041
1041
|
30:
|
@@ -1088,7 +1088,7 @@ Now we can investigate the problem in the employer's side:
|
|
1088
1088
|
39: show_off(@results.pop)
|
1089
1089
|
40: end
|
1090
1090
|
(byebug)
|
1091
|
-
|
1091
|
+
```
|
1092
1092
|
|
1093
1093
|
Now we can see the problem, the `@results` variable is always empty! The
|
1094
1094
|
employee forgot to leave the results in his manager's deck. We fix it by
|
@@ -1193,14 +1193,14 @@ get a line trace, `tracer` is most likely faster than `byebug`.
|
|
1193
1193
|
```bash
|
1194
1194
|
$ time byebug --trace --no-stop hanoi.rb > /dev/null
|
1195
1195
|
|
1196
|
-
real
|
1197
|
-
user
|
1198
|
-
sys
|
1196
|
+
real 0m0.743s
|
1197
|
+
user 0m0.668s
|
1198
|
+
sys 0m0.068s
|
1199
1199
|
$ time ruby -rtracer hanoi.rb > /dev/null
|
1200
1200
|
|
1201
|
-
real
|
1202
|
-
user
|
1203
|
-
sys
|
1201
|
+
real 0m0.077s
|
1202
|
+
user 0m0.072s
|
1203
|
+
sys 0m0.004s
|
1204
1204
|
```
|
1205
1205
|
|
1206
1206
|
### Byebug default options
|
@@ -1620,19 +1620,40 @@ will just call pretty-print.
|
|
1620
1620
|
:pretty_inspect,
|
1621
1621
|
:byebug]
|
1622
1622
|
(byebug) putl Kernel.instance_methods
|
1623
|
-
nil?
|
1624
|
-
===
|
1625
|
-
=~
|
1626
|
-
!~
|
1627
|
-
eql?
|
1628
|
-
hash
|
1623
|
+
nil? trust is_a?
|
1624
|
+
=== freeze tap
|
1625
|
+
=~ frozen? send
|
1626
|
+
!~ to_s public_send
|
1627
|
+
eql? inspect respond_to?
|
1628
|
+
hash methods extend
|
1629
|
+
<=> singleton_methods display
|
1630
|
+
class protected_methods method
|
1631
|
+
singleton_class private_methods public_method
|
1632
|
+
clone public_methods singleton_method
|
1633
|
+
dup instance_variables define_singleton_method
|
1634
|
+
itself instance_variable_get object_id
|
1635
|
+
taint instance_variable_set to_enum
|
1636
|
+
tainted? instance_variable_defined? enum_for
|
1637
|
+
untaint remove_instance_variable gem
|
1638
|
+
untrust instance_of? pretty_inspect
|
1639
|
+
untrusted? kind_of?
|
1629
1640
|
(byebug) ps Kernel.instance_methods
|
1630
|
-
!~
|
1631
|
-
<=>
|
1632
|
-
===
|
1633
|
-
=~
|
1634
|
-
|
1635
|
-
|
1641
|
+
!~ instance_of? public_send
|
1642
|
+
<=> instance_variable_defined? remove_instance_variable
|
1643
|
+
=== instance_variable_get respond_to?
|
1644
|
+
=~ instance_variable_set send
|
1645
|
+
class instance_variables singleton_class
|
1646
|
+
clone is_a? singleton_method
|
1647
|
+
define_singleton_method itself singleton_methods
|
1648
|
+
display kind_of? taint
|
1649
|
+
dup method tainted?
|
1650
|
+
enum_for methods tap
|
1651
|
+
eql? nil? to_enum
|
1652
|
+
extend object_id to_s
|
1653
|
+
freeze pretty_inspect trust
|
1654
|
+
frozen? private_methods untaint
|
1655
|
+
gem protected_methods untrust
|
1656
|
+
hash public_method untrusted?
|
1636
1657
|
```
|
1637
1658
|
|
1638
1659
|
Finally, if you need more advanced functionality from REPL's, you can enter
|
data/lib/byebug/attacher.rb
CHANGED
@@ -7,12 +7,12 @@ module Byebug
|
|
7
7
|
# events occur. Before entering byebug the init script is read.
|
8
8
|
#
|
9
9
|
def self.attach
|
10
|
-
|
10
|
+
unless started?
|
11
|
+
self.mode = :attached
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
run_init_script
|
13
|
+
start
|
14
|
+
run_init_script
|
15
|
+
end
|
16
16
|
|
17
17
|
current_context.step_out(2, true)
|
18
18
|
end
|
@@ -15,15 +15,14 @@ module Byebug
|
|
15
15
|
def execute
|
16
16
|
return puts(self.class.help) unless @match[1]
|
17
17
|
|
18
|
-
|
18
|
+
b = line_breakpoint(@match[1]) || method_breakpoint(@match[1])
|
19
|
+
|
19
20
|
if syntax_valid?(@match[2])
|
20
|
-
return puts(
|
21
|
-
pr('break.created', id: brkpt.id, file: brkpt.source, line: brkpt.pos)
|
22
|
-
)
|
21
|
+
return puts(pr('break.created', id: b.id, file: b.source, line: b.pos))
|
23
22
|
end
|
24
23
|
|
25
24
|
errmsg(pr('break.errors.expression', expr: @match[2]))
|
26
|
-
|
25
|
+
b.enabled = false
|
27
26
|
rescue => e
|
28
27
|
errmsg(e.message)
|
29
28
|
end
|
data/lib/byebug/commands/info.rb
CHANGED
@@ -176,7 +176,7 @@ module Byebug
|
|
176
176
|
def execute
|
177
177
|
return puts(self.class.help) unless @match[1]
|
178
178
|
|
179
|
-
args = @match[1].split(/
|
179
|
+
args = @match[1].split(/ +/)
|
180
180
|
param = args.shift
|
181
181
|
subcmd = Command.find(Subcommands, param)
|
182
182
|
return errmsg "Unknown info command #{param}\n" unless subcmd
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'byebug/command'
|
2
|
+
|
3
|
+
module Byebug
|
4
|
+
#
|
5
|
+
# Manipulation of Ruby threads
|
6
|
+
#
|
7
|
+
class ThreadCommand < Command
|
8
|
+
Subcommands = [
|
9
|
+
['current', 1, 'Shows current thread'],
|
10
|
+
['list', 1, 'Lists all threads'],
|
11
|
+
['resume', 1, 'Resumes execution of specified thread number'],
|
12
|
+
['stop', 2, 'Stops execution of specified thread number'],
|
13
|
+
['switch', 2, 'Switches execution to specified thread']
|
14
|
+
].map do |name, min, help|
|
15
|
+
Subcmd.new(name, min, help)
|
16
|
+
end
|
17
|
+
|
18
|
+
def regexp
|
19
|
+
/^\s* th(?:read)? (?:\s+ (.+))? \s*$/x
|
20
|
+
end
|
21
|
+
|
22
|
+
def execute
|
23
|
+
return puts(self.class.help) unless @match[1]
|
24
|
+
|
25
|
+
name, thnum = @match[1].split(/ +/)[0..1]
|
26
|
+
subcmd = Command.find(Subcommands, name)
|
27
|
+
return errmsg("Unknown thread command '#{name}'\n") unless subcmd
|
28
|
+
|
29
|
+
send("thread_#{subcmd.name}", thnum)
|
30
|
+
end
|
31
|
+
|
32
|
+
class << self
|
33
|
+
def names
|
34
|
+
%w(thread)
|
35
|
+
end
|
36
|
+
|
37
|
+
def description
|
38
|
+
prettify <<-EOD
|
39
|
+
Commands to manipulate threads.
|
40
|
+
EOD
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def thread_list(thnum)
|
47
|
+
return errmsg("thread list doesn't need params") unless thnum.nil?
|
48
|
+
|
49
|
+
contexts = Byebug.contexts.sort_by(&:thnum)
|
50
|
+
|
51
|
+
thread_list = prc('thread.context', contexts) do |context, _|
|
52
|
+
thread_arguments(context)
|
53
|
+
end
|
54
|
+
|
55
|
+
print(thread_list)
|
56
|
+
end
|
57
|
+
|
58
|
+
def thread_current(thnum)
|
59
|
+
return errmsg("thread current doesn't need params") unless thnum.nil?
|
60
|
+
|
61
|
+
display_context(@state.context)
|
62
|
+
end
|
63
|
+
|
64
|
+
def thread_stop(thnum)
|
65
|
+
ctx, err = parse_thread_num_for_cmd('thread stop', thnum)
|
66
|
+
return errmsg(err) if err
|
67
|
+
|
68
|
+
ctx.suspend
|
69
|
+
display_context(ctx)
|
70
|
+
end
|
71
|
+
|
72
|
+
def thread_resume(thnum)
|
73
|
+
ctx, err = parse_thread_num_for_cmd('thread resume', thnum)
|
74
|
+
return errmsg(err) if err
|
75
|
+
return errmsg(pr('thread.errors.already_running')) unless ctx.suspended?
|
76
|
+
|
77
|
+
ctx.resume
|
78
|
+
display_context(ctx)
|
79
|
+
end
|
80
|
+
|
81
|
+
def thread_switch(thnum)
|
82
|
+
ctx, err = parse_thread_num_for_cmd('thread switch', thnum)
|
83
|
+
return errmsg(err) if err
|
84
|
+
|
85
|
+
display_context(ctx)
|
86
|
+
|
87
|
+
ctx.switch
|
88
|
+
@state.proceed
|
89
|
+
end
|
90
|
+
|
91
|
+
def display_context(context)
|
92
|
+
puts pr('thread.context', thread_arguments(context))
|
93
|
+
end
|
94
|
+
|
95
|
+
def thread_arguments(context)
|
96
|
+
status_flag = if context.suspended?
|
97
|
+
'$'
|
98
|
+
else
|
99
|
+
context.thread == Thread.current ? '+' : ' '
|
100
|
+
end
|
101
|
+
debug_flag = context.ignored? ? '!' : ' '
|
102
|
+
|
103
|
+
if context == Byebug.current_context
|
104
|
+
file_line = "#{@state.file}:#{@state.line}"
|
105
|
+
else
|
106
|
+
backtrace = context.thread.backtrace_locations
|
107
|
+
if backtrace && backtrace[0]
|
108
|
+
file_line = "#{backtrace[0].path}:#{backtrace[0].lineno}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
{
|
113
|
+
status_flag: status_flag,
|
114
|
+
debug_flag: debug_flag,
|
115
|
+
id: context.thnum,
|
116
|
+
thread: context.thread.inspect,
|
117
|
+
file_line: file_line || ''
|
118
|
+
}
|
119
|
+
end
|
120
|
+
|
121
|
+
def parse_thread_num(subcmd, arg)
|
122
|
+
thnum, err = get_int(arg, subcmd, 1)
|
123
|
+
return [nil, err] unless thnum
|
124
|
+
|
125
|
+
Byebug.contexts.find { |c| c.thnum == thnum }
|
126
|
+
end
|
127
|
+
|
128
|
+
def parse_thread_num_for_cmd(subcmd, arg)
|
129
|
+
c, err = parse_thread_num(subcmd, arg)
|
130
|
+
|
131
|
+
case
|
132
|
+
when err
|
133
|
+
[c, err]
|
134
|
+
when c.nil?
|
135
|
+
[nil, pr('thread.errors.no_thread')]
|
136
|
+
when @state.context == c
|
137
|
+
[c, pr('thread.errors.current_thread')]
|
138
|
+
when c.ignored?
|
139
|
+
[c, pr('thread.errors.wrong_action', subcmd: subcmd, arg: arg)]
|
140
|
+
else
|
141
|
+
[c, nil]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
data/lib/byebug/context.rb
CHANGED
data/lib/byebug/core.rb
CHANGED
@@ -10,12 +10,6 @@ require 'byebug/printers/plain'
|
|
10
10
|
module Byebug
|
11
11
|
extend self
|
12
12
|
|
13
|
-
class NoScript < StandardError
|
14
|
-
end
|
15
|
-
|
16
|
-
class NonExistentScript < StandardError
|
17
|
-
end
|
18
|
-
|
19
13
|
#
|
20
14
|
# Configuration file used for startup commands. Default value is .byebugrc
|
21
15
|
#
|
@@ -27,15 +21,15 @@ module Byebug
|
|
27
21
|
attr_accessor :handler
|
28
22
|
self.handler = CommandProcessor.new
|
29
23
|
|
24
|
+
extend Forwardable
|
25
|
+
def_delegators :handler, :errmsg, :puts
|
26
|
+
|
30
27
|
#
|
31
28
|
# Main debugger's printer
|
32
29
|
#
|
33
30
|
attr_accessor :printer
|
34
31
|
self.printer = Printers::Plain.new
|
35
32
|
|
36
|
-
extend Forwardable
|
37
|
-
def_delegators :handler, :errmsg, :puts
|
38
|
-
|
39
33
|
#
|
40
34
|
# Running mode of the debugger. Can be either:
|
41
35
|
#
|
@@ -61,26 +55,6 @@ module Byebug
|
|
61
55
|
run_script(cwd_rc) if File.exist?(cwd_rc) && cwd_rc != home_rc
|
62
56
|
end
|
63
57
|
|
64
|
-
#
|
65
|
-
# Extracts debugged program from command line args
|
66
|
-
#
|
67
|
-
def setup_cmd_line_args
|
68
|
-
unless $PROGRAM_NAME.include?('bin/byebug')
|
69
|
-
self.mode = :attached
|
70
|
-
return
|
71
|
-
end
|
72
|
-
|
73
|
-
self.mode = :standalone
|
74
|
-
|
75
|
-
fail(NoScript, 'You must specify a program to debug...') if $ARGV.empty?
|
76
|
-
|
77
|
-
program = which($ARGV.shift)
|
78
|
-
program = which($ARGV.shift) if program == which('ruby')
|
79
|
-
fail(NonExistentScript, "The script doesn't exist") unless program
|
80
|
-
|
81
|
-
$PROGRAM_NAME = program
|
82
|
-
end
|
83
|
-
|
84
58
|
private
|
85
59
|
|
86
60
|
#
|
@@ -91,24 +65,6 @@ module Byebug
|
|
91
65
|
processor = ControlCommandProcessor.new(interface)
|
92
66
|
processor.process_commands
|
93
67
|
end
|
94
|
-
|
95
|
-
#
|
96
|
-
# Cross-platform way of finding an executable in the $PATH.
|
97
|
-
# Borrowed from: http://stackoverflow.com/questions/2108727
|
98
|
-
#
|
99
|
-
def which(cmd)
|
100
|
-
return File.expand_path(cmd) if File.exist?(cmd)
|
101
|
-
|
102
|
-
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
103
|
-
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
104
|
-
exts.each do |ext|
|
105
|
-
exe = File.join(path, "#{cmd}#{ext}")
|
106
|
-
return exe if File.executable?(exe) && !File.directory?(exe)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
nil
|
111
|
-
end
|
112
68
|
end
|
113
69
|
|
114
70
|
#
|
data/lib/byebug/helper.rb
CHANGED
@@ -88,12 +88,31 @@ module Byebug
|
|
88
88
|
end
|
89
89
|
|
90
90
|
#
|
91
|
-
# Returns true if code is syntactically correct for Ruby
|
91
|
+
# Returns true if code is syntactically correct for Ruby
|
92
92
|
#
|
93
93
|
def syntax_valid?(code)
|
94
|
-
|
95
|
-
|
96
|
-
|
94
|
+
return true unless code
|
95
|
+
|
96
|
+
without_stderr do
|
97
|
+
begin
|
98
|
+
RubyVM::InstructionSequence.compile(code)
|
99
|
+
true
|
100
|
+
rescue SyntaxError
|
101
|
+
false
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Temporarily disable output to $stderr
|
108
|
+
#
|
109
|
+
def without_stderr
|
110
|
+
stderr = $stderr
|
111
|
+
$stderr.reopen(IO::NULL)
|
112
|
+
|
113
|
+
yield
|
114
|
+
ensure
|
115
|
+
$stderr.reopen(stderr)
|
97
116
|
end
|
98
117
|
|
99
118
|
#
|
data/lib/byebug/runner.rb
CHANGED
@@ -1,12 +1,28 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
require 'English'
|
3
3
|
require 'byebug/core'
|
4
|
+
require 'byebug/helper'
|
4
5
|
|
5
6
|
module Byebug
|
6
7
|
#
|
7
8
|
# Responsible for starting the debugger when started from the command line.
|
8
9
|
#
|
9
10
|
class Runner
|
11
|
+
#
|
12
|
+
# Error class signaling absence of a script to debug
|
13
|
+
#
|
14
|
+
class NoScript < StandardError; end
|
15
|
+
|
16
|
+
#
|
17
|
+
# Error class signaling a non existent script to debug
|
18
|
+
#
|
19
|
+
class NonExistentScript < StandardError; end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Error class signaling a script with invalid Ruby syntax
|
23
|
+
#
|
24
|
+
class InvalidScript < StandardError; end
|
25
|
+
|
10
26
|
#
|
11
27
|
# Special working modes that don't actually start the debugger.
|
12
28
|
#
|
@@ -36,27 +52,6 @@ module Byebug
|
|
36
52
|
EOB
|
37
53
|
end
|
38
54
|
|
39
|
-
#
|
40
|
-
# Debugs a script only if syntax checks okay.
|
41
|
-
#
|
42
|
-
def debug_program
|
43
|
-
check_syntax($PROGRAM_NAME)
|
44
|
-
|
45
|
-
status = Byebug.debug_load($PROGRAM_NAME, @stop)
|
46
|
-
Byebug.puts "#{status}\n#{status.backtrace}" if status
|
47
|
-
end
|
48
|
-
|
49
|
-
#
|
50
|
-
# Exits and outputs error message if syntax of the given program is invalid.
|
51
|
-
#
|
52
|
-
def check_syntax(program_name)
|
53
|
-
output = `ruby -c "#{program_name}" 2>&1`
|
54
|
-
return unless $CHILD_STATUS.exitstatus != 0
|
55
|
-
|
56
|
-
Byebug.errmsg(output)
|
57
|
-
exit($CHILD_STATUS.exitstatus)
|
58
|
-
end
|
59
|
-
|
60
55
|
#
|
61
56
|
# Starts byebug to debug a program
|
62
57
|
#
|
@@ -78,7 +73,7 @@ module Byebug
|
|
78
73
|
return
|
79
74
|
end
|
80
75
|
|
81
|
-
|
76
|
+
setup_cmd_line_args
|
82
77
|
|
83
78
|
loop do
|
84
79
|
debug_program
|
@@ -90,6 +85,11 @@ module Byebug
|
|
90
85
|
end
|
91
86
|
end
|
92
87
|
|
88
|
+
private
|
89
|
+
|
90
|
+
#
|
91
|
+
# Processes options passed from the command line
|
92
|
+
#
|
93
93
|
def prepare_options
|
94
94
|
OptionParser.new(banner, 25) do |opts|
|
95
95
|
opts.banner = banner
|
@@ -139,5 +139,50 @@ module Byebug
|
|
139
139
|
end
|
140
140
|
end
|
141
141
|
end
|
142
|
+
|
143
|
+
#
|
144
|
+
# Extracts debugged program from command line args
|
145
|
+
#
|
146
|
+
def setup_cmd_line_args
|
147
|
+
Byebug.mode = :standalone
|
148
|
+
|
149
|
+
fail(NoScript, 'You must specify a program to debug...') if $ARGV.empty?
|
150
|
+
|
151
|
+
program = which($ARGV.shift)
|
152
|
+
program = which($ARGV.shift) if program == which('ruby')
|
153
|
+
fail(NonExistentScript, "The script doesn't exist") unless program
|
154
|
+
|
155
|
+
$PROGRAM_NAME = program
|
156
|
+
end
|
157
|
+
|
158
|
+
include ParseFunctions
|
159
|
+
#
|
160
|
+
# Debugs a script only if syntax checks okay.
|
161
|
+
#
|
162
|
+
def debug_program
|
163
|
+
ok = syntax_valid?(File.read($PROGRAM_NAME))
|
164
|
+
fail(InvalidScript, 'The script has incorrect syntax') unless ok
|
165
|
+
|
166
|
+
error = Byebug.debug_load($PROGRAM_NAME, @stop)
|
167
|
+
Byebug.puts "#{status}\n#{status.backtrace}" if error
|
168
|
+
end
|
169
|
+
|
170
|
+
#
|
171
|
+
# Cross-platform way of finding an executable in the $PATH.
|
172
|
+
# Borrowed from: http://stackoverflow.com/questions/2108727
|
173
|
+
#
|
174
|
+
def which(cmd)
|
175
|
+
return File.expand_path(cmd) if File.exist?(cmd)
|
176
|
+
|
177
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
178
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
179
|
+
exts.each do |ext|
|
180
|
+
exe = File.join(path, "#{cmd}#{ext}")
|
181
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
nil
|
186
|
+
end
|
142
187
|
end
|
143
188
|
end
|
data/lib/byebug/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: byebug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Rodriguez
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-04-02 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: columnize
|
@@ -102,7 +102,7 @@ files:
|
|
102
102
|
- lib/byebug/commands/show.rb
|
103
103
|
- lib/byebug/commands/source.rb
|
104
104
|
- lib/byebug/commands/stepping.rb
|
105
|
-
- lib/byebug/commands/
|
105
|
+
- lib/byebug/commands/thread.rb
|
106
106
|
- lib/byebug/commands/tracevar.rb
|
107
107
|
- lib/byebug/commands/undisplay.rb
|
108
108
|
- lib/byebug/commands/untracevar.rb
|
@@ -165,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
165
165
|
version: '0'
|
166
166
|
requirements: []
|
167
167
|
rubyforge_project:
|
168
|
-
rubygems_version: 2.4.
|
168
|
+
rubygems_version: 2.4.5
|
169
169
|
signing_key:
|
170
170
|
specification_version: 4
|
171
171
|
summary: Ruby 2.0 fast debugger - base + CLI
|
@@ -1,237 +0,0 @@
|
|
1
|
-
require 'byebug/command'
|
2
|
-
|
3
|
-
#
|
4
|
-
# TODO: Implement thread commands as a single command with subcommands, just
|
5
|
-
# like `info`, `var`, `enable` and `disable`. This allows consistent help
|
6
|
-
# format and we can go back to showing help for a single command in the `help`
|
7
|
-
# command.
|
8
|
-
#
|
9
|
-
module Byebug
|
10
|
-
#
|
11
|
-
# Utilities to assist commands related to threads.
|
12
|
-
#
|
13
|
-
module ThreadFunctions
|
14
|
-
def display_context(context, should_show_top_frame = true)
|
15
|
-
puts pr('thread.context',
|
16
|
-
thread_arguments(context, should_show_top_frame))
|
17
|
-
end
|
18
|
-
|
19
|
-
def thread_arguments(context, should_show_top_frame = true)
|
20
|
-
status_flag = if context.suspended?
|
21
|
-
'$'
|
22
|
-
else
|
23
|
-
context.thread == Thread.current ? '+' : ' '
|
24
|
-
end
|
25
|
-
debug_flag = context.ignored? ? '!' : ' '
|
26
|
-
|
27
|
-
if should_show_top_frame
|
28
|
-
if context == Byebug.current_context
|
29
|
-
file_line = "#{@state.file}:#{@state.line}"
|
30
|
-
else
|
31
|
-
backtrace = context.thread.backtrace_locations
|
32
|
-
if backtrace && backtrace[0]
|
33
|
-
file_line = "#{backtrace[0].path}:#{backtrace[0].lineno}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
{
|
38
|
-
status_flag: status_flag,
|
39
|
-
debug_flag: debug_flag,
|
40
|
-
id: context.thnum,
|
41
|
-
thread: context.thread.inspect,
|
42
|
-
file_line: file_line || ''
|
43
|
-
}
|
44
|
-
end
|
45
|
-
|
46
|
-
def parse_thread_num(subcmd, arg)
|
47
|
-
thnum, err = get_int(arg, subcmd, 1)
|
48
|
-
return [nil, err] unless thnum
|
49
|
-
|
50
|
-
Byebug.contexts.find { |c| c.thnum == thnum }
|
51
|
-
end
|
52
|
-
|
53
|
-
def parse_thread_num_for_cmd(subcmd, arg)
|
54
|
-
c, err = parse_thread_num(subcmd, arg)
|
55
|
-
|
56
|
-
case
|
57
|
-
when err
|
58
|
-
[c, err]
|
59
|
-
when c.nil?
|
60
|
-
[nil, pr('thread.errors.no_thread')]
|
61
|
-
when @state.context == c
|
62
|
-
[c, pr('thread.errors.current_thread')]
|
63
|
-
when c.ignored?
|
64
|
-
[c, pr('thread.errors.wrong_action', subcmd: subcmd, arg: arg)]
|
65
|
-
else
|
66
|
-
[c, nil]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
#
|
72
|
-
# List current threads.
|
73
|
-
#
|
74
|
-
class ThreadListCommand < Command
|
75
|
-
include ThreadFunctions
|
76
|
-
|
77
|
-
self.allow_in_control = true
|
78
|
-
|
79
|
-
def regexp
|
80
|
-
/^\s* th(?:read)? \s+ l(?:ist)? \s*$/x
|
81
|
-
end
|
82
|
-
|
83
|
-
def execute
|
84
|
-
contexts = Byebug.contexts.sort_by(&:thnum)
|
85
|
-
|
86
|
-
thread_list = prc('thread.context', contexts) do |context, _|
|
87
|
-
thread_arguments(context)
|
88
|
-
end
|
89
|
-
|
90
|
-
print(thread_list)
|
91
|
-
end
|
92
|
-
|
93
|
-
class << self
|
94
|
-
def names
|
95
|
-
%w(thread)
|
96
|
-
end
|
97
|
-
|
98
|
-
def description
|
99
|
-
prettify <<-EOD
|
100
|
-
th[read] l[ist] Lists all threads.
|
101
|
-
EOD
|
102
|
-
end
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
#
|
107
|
-
# Show current thread.
|
108
|
-
#
|
109
|
-
class ThreadCurrentCommand < Command
|
110
|
-
include ThreadFunctions
|
111
|
-
|
112
|
-
def regexp
|
113
|
-
/^\s* th(?:read)? \s+ (?:cur(?:rent)?)? \s*$/x
|
114
|
-
end
|
115
|
-
|
116
|
-
def execute
|
117
|
-
display_context(@state.context)
|
118
|
-
end
|
119
|
-
|
120
|
-
class << self
|
121
|
-
def names
|
122
|
-
%w(thread)
|
123
|
-
end
|
124
|
-
|
125
|
-
def description
|
126
|
-
prettify <<-EOD
|
127
|
-
th[read] cur[rent] Shows current thread.
|
128
|
-
EOD
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
#
|
134
|
-
# Stop execution of a thread.
|
135
|
-
#
|
136
|
-
class ThreadStopCommand < Command
|
137
|
-
include ThreadFunctions
|
138
|
-
|
139
|
-
self.allow_in_control = true
|
140
|
-
self.allow_in_post_mortem = false
|
141
|
-
|
142
|
-
def regexp
|
143
|
-
/^\s* th(?:read)? \s+ stop \s* (\S*) \s*$/x
|
144
|
-
end
|
145
|
-
|
146
|
-
def execute
|
147
|
-
c, err = parse_thread_num_for_cmd('thread stop', @match[1])
|
148
|
-
return errmsg(err) if err
|
149
|
-
|
150
|
-
c.suspend
|
151
|
-
display_context(c)
|
152
|
-
end
|
153
|
-
|
154
|
-
class << self
|
155
|
-
def names
|
156
|
-
%w(thread)
|
157
|
-
end
|
158
|
-
|
159
|
-
def description
|
160
|
-
prettify <<-EOD
|
161
|
-
th[read] stop <n> Stops thread <n>.
|
162
|
-
EOD
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
#
|
168
|
-
# Resume execution of a thread.
|
169
|
-
#
|
170
|
-
class ThreadResumeCommand < Command
|
171
|
-
include ThreadFunctions
|
172
|
-
|
173
|
-
self.allow_in_control = true
|
174
|
-
self.allow_in_post_mortem = false
|
175
|
-
|
176
|
-
def regexp
|
177
|
-
/^\s* th(?:read)? \s+ resume \s* (\S*) \s*$/x
|
178
|
-
end
|
179
|
-
|
180
|
-
def execute
|
181
|
-
c, err = parse_thread_num_for_cmd('thread resume', @match[1])
|
182
|
-
return errmsg(err) if err
|
183
|
-
return errmsg pr('thread.errors.already_running') unless c.suspended?
|
184
|
-
|
185
|
-
c.resume
|
186
|
-
display_context(c)
|
187
|
-
end
|
188
|
-
|
189
|
-
class << self
|
190
|
-
def names
|
191
|
-
%w(thread)
|
192
|
-
end
|
193
|
-
|
194
|
-
def description
|
195
|
-
prettify <<-EOD
|
196
|
-
th[read] resume <n> Resumes thread <n>.
|
197
|
-
EOD
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
#
|
203
|
-
# Switch execution to a different thread.
|
204
|
-
#
|
205
|
-
class ThreadSwitchCommand < Command
|
206
|
-
include ThreadFunctions
|
207
|
-
|
208
|
-
self.allow_in_control = true
|
209
|
-
self.allow_in_post_mortem = false
|
210
|
-
|
211
|
-
def regexp
|
212
|
-
/^\s* th(?:read)? \s+ sw(?:itch)? (?:\s+(\S+))? \s*$/x
|
213
|
-
end
|
214
|
-
|
215
|
-
def execute
|
216
|
-
c, err = parse_thread_num_for_cmd('thread switch', @match[1])
|
217
|
-
return errmsg(err) if err
|
218
|
-
|
219
|
-
display_context(c)
|
220
|
-
|
221
|
-
c.switch
|
222
|
-
@state.proceed
|
223
|
-
end
|
224
|
-
|
225
|
-
class << self
|
226
|
-
def names
|
227
|
-
%w(thread)
|
228
|
-
end
|
229
|
-
|
230
|
-
def description
|
231
|
-
prettify <<-EOD
|
232
|
-
th[read] sw[itch] <n> Switches thread context to <n>.
|
233
|
-
EOD
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|
237
|
-
end
|