debug 1.6.2 → 1.7.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.
- checksums.yaml +4 -4
- data/CONTRIBUTING.md +20 -8
- data/Gemfile +0 -0
- data/LICENSE.txt +0 -0
- data/README.md +39 -16
- data/Rakefile +0 -0
- data/TODO.md +0 -0
- data/debug.gemspec +1 -1
- data/exe/rdbg +17 -2
- data/ext/debug/debug.c +15 -1
- data/ext/debug/extconf.rb +0 -0
- data/ext/debug/iseq_collector.c +0 -0
- data/lib/debug/abbrev_command.rb +77 -0
- data/lib/debug/breakpoint.rb +17 -11
- data/lib/debug/client.rb +27 -10
- data/lib/debug/color.rb +0 -0
- data/lib/debug/config.rb +34 -16
- data/lib/debug/console.rb +0 -0
- data/lib/debug/frame_info.rb +0 -0
- data/lib/debug/local.rb +16 -10
- data/lib/debug/open.rb +0 -0
- data/lib/debug/open_nonstop.rb +0 -0
- data/lib/debug/prelude.rb +0 -0
- data/lib/debug/server.rb +25 -21
- data/lib/debug/server_cdp.rb +282 -81
- data/lib/debug/server_dap.rb +110 -38
- data/lib/debug/session.rb +390 -208
- data/lib/debug/source_repository.rb +39 -19
- data/lib/debug/start.rb +1 -1
- data/lib/debug/thread_client.rb +187 -61
- data/lib/debug/tracer.rb +0 -0
- data/lib/debug/version.rb +1 -1
- data/lib/debug.rb +7 -3
- data/misc/README.md.erb +11 -5
- metadata +5 -4
data/lib/debug/server_cdp.rb
CHANGED
|
@@ -7,13 +7,18 @@ require 'securerandom'
|
|
|
7
7
|
require 'stringio'
|
|
8
8
|
require 'open3'
|
|
9
9
|
require 'tmpdir'
|
|
10
|
+
require 'tempfile'
|
|
11
|
+
require 'timeout'
|
|
10
12
|
|
|
11
13
|
module DEBUGGER__
|
|
12
14
|
module UI_CDP
|
|
13
15
|
SHOW_PROTOCOL = ENV['RUBY_DEBUG_CDP_SHOW_PROTOCOL'] == '1'
|
|
14
16
|
|
|
17
|
+
class UnsupportedError < StandardError; end
|
|
18
|
+
class NotFoundChromeEndpointError < StandardError; end
|
|
19
|
+
|
|
15
20
|
class << self
|
|
16
|
-
def setup_chrome addr
|
|
21
|
+
def setup_chrome addr, uuid
|
|
17
22
|
return if CONFIG[:chrome_path] == ''
|
|
18
23
|
|
|
19
24
|
port, path, pid = run_new_chrome
|
|
@@ -39,6 +44,8 @@ module DEBUGGER__
|
|
|
39
44
|
}
|
|
40
45
|
when res['id'] == 2
|
|
41
46
|
s_id = res.dig('result', 'sessionId')
|
|
47
|
+
# TODO: change id
|
|
48
|
+
ws_client.send sessionId: s_id, id: 100, method: 'Network.enable'
|
|
42
49
|
ws_client.send sessionId: s_id, id: 3,
|
|
43
50
|
method: 'Page.enable'
|
|
44
51
|
when res['id'] == 3
|
|
@@ -51,57 +58,191 @@ module DEBUGGER__
|
|
|
51
58
|
ws_client.send sessionId: s_id, id: 5,
|
|
52
59
|
method: 'Page.navigate',
|
|
53
60
|
params: {
|
|
54
|
-
url: "devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{addr}/#{
|
|
61
|
+
url: "devtools://devtools/bundled/inspector.html?v8only=true&panel=sources&ws=#{addr}/#{uuid}",
|
|
55
62
|
frameId: f_id
|
|
56
63
|
}
|
|
57
|
-
when res['method'] == '
|
|
64
|
+
when res['method'] == 'Network.webSocketWillSendHandshakeRequest'
|
|
65
|
+
s_id = res['sessionId']
|
|
66
|
+
# Display the console by entering ESC key
|
|
67
|
+
ws_client.send sessionId: s_id, id: 101, # TODO: change id
|
|
68
|
+
method:"Input.dispatchKeyEvent",
|
|
69
|
+
params: {
|
|
70
|
+
type:"keyDown",
|
|
71
|
+
windowsVirtualKeyCode:27 # ESC key
|
|
72
|
+
}
|
|
73
|
+
when res['id'] == 101
|
|
58
74
|
break
|
|
59
75
|
end
|
|
60
76
|
end
|
|
61
77
|
pid
|
|
62
|
-
rescue Errno::ENOENT
|
|
78
|
+
rescue Errno::ENOENT, UnsupportedError, NotFoundChromeEndpointError
|
|
63
79
|
nil
|
|
64
80
|
end
|
|
65
81
|
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
TIMEOUT_SEC = 5
|
|
83
|
+
|
|
84
|
+
def run_new_chrome
|
|
85
|
+
path = CONFIG[:chrome_path]
|
|
86
|
+
|
|
87
|
+
data = nil
|
|
88
|
+
port = nil
|
|
89
|
+
wait_thr = nil
|
|
68
90
|
|
|
69
91
|
# The process to check OS is based on `selenium` project.
|
|
70
92
|
case RbConfig::CONFIG['host_os']
|
|
71
93
|
when /mswin|msys|mingw|cygwin|emc/
|
|
72
|
-
|
|
94
|
+
if path.nil?
|
|
95
|
+
candidates = ['C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe', 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe']
|
|
96
|
+
path = get_chrome_path candidates
|
|
97
|
+
end
|
|
98
|
+
uuid = SecureRandom.uuid
|
|
99
|
+
# The path is based on https://github.com/sindresorhus/open/blob/v8.4.0/index.js#L128.
|
|
100
|
+
stdin, stdout, stderr, wait_thr = *Open3.popen3("#{ENV['SystemRoot']}\\System32\\WindowsPowerShell\\v1.0\\powershell")
|
|
101
|
+
tf = Tempfile.create(['debug-', '.txt'])
|
|
102
|
+
|
|
103
|
+
stdin.puts("Start-process '#{path}' -Argumentlist '--remote-debugging-port=0', '--no-first-run', '--no-default-browser-check', '--user-data-dir=C:\\temp' -Wait -RedirectStandardError #{tf.path}")
|
|
104
|
+
stdin.close
|
|
105
|
+
stdout.close
|
|
106
|
+
stderr.close
|
|
107
|
+
port, path = get_devtools_endpoint(tf.path)
|
|
108
|
+
|
|
109
|
+
at_exit{
|
|
110
|
+
DEBUGGER__.skip_all
|
|
111
|
+
|
|
112
|
+
stdin, stdout, stderr, wait_thr = *Open3.popen3("#{ENV['SystemRoot']}\\System32\\WindowsPowerShell\\v1.0\\powershell")
|
|
113
|
+
stdin.puts("Stop-process -Name chrome")
|
|
114
|
+
stdin.close
|
|
115
|
+
stdout.close
|
|
116
|
+
stderr.close
|
|
117
|
+
tf.close
|
|
118
|
+
begin
|
|
119
|
+
File.unlink(tf)
|
|
120
|
+
rescue Errno::EACCES
|
|
121
|
+
end
|
|
122
|
+
}
|
|
73
123
|
when /darwin|mac os/
|
|
74
|
-
'/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome'
|
|
124
|
+
path = path || '/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome'
|
|
125
|
+
dir = Dir.mktmpdir
|
|
126
|
+
# The command line flags are based on: https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging/Chrome_Desktop#connecting.
|
|
127
|
+
stdin, stdout, stderr, wait_thr = *Open3.popen3("#{path} --remote-debugging-port=0 --no-first-run --no-default-browser-check --user-data-dir=#{dir}")
|
|
128
|
+
stdin.close
|
|
129
|
+
stdout.close
|
|
130
|
+
data = stderr.readpartial 4096
|
|
131
|
+
stderr.close
|
|
132
|
+
if data.match /DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/
|
|
133
|
+
port = $1
|
|
134
|
+
path = $2
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
at_exit{
|
|
138
|
+
DEBUGGER__.skip_all
|
|
139
|
+
FileUtils.rm_rf dir
|
|
140
|
+
}
|
|
75
141
|
when /linux/
|
|
76
|
-
'google-chrome'
|
|
142
|
+
path = path || 'google-chrome'
|
|
143
|
+
dir = Dir.mktmpdir
|
|
144
|
+
# The command line flags are based on: https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging/Chrome_Desktop#connecting.
|
|
145
|
+
stdin, stdout, stderr, wait_thr = *Open3.popen3("#{path} --remote-debugging-port=0 --no-first-run --no-default-browser-check --user-data-dir=#{dir}")
|
|
146
|
+
stdin.close
|
|
147
|
+
stdout.close
|
|
148
|
+
data = ''
|
|
149
|
+
begin
|
|
150
|
+
Timeout.timeout(TIMEOUT_SEC) do
|
|
151
|
+
until data.match?(/DevTools listening on ws:\/\/127.0.0.1:\d+.*/)
|
|
152
|
+
data = stderr.readpartial 4096
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
rescue Exception
|
|
156
|
+
raise NotFoundChromeEndpointError
|
|
157
|
+
end
|
|
158
|
+
stderr.close
|
|
159
|
+
if data.match /DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/
|
|
160
|
+
port = $1
|
|
161
|
+
path = $2
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
at_exit{
|
|
165
|
+
DEBUGGER__.skip_all
|
|
166
|
+
FileUtils.rm_rf dir
|
|
167
|
+
}
|
|
77
168
|
else
|
|
78
|
-
raise
|
|
169
|
+
raise UnsupportedError
|
|
79
170
|
end
|
|
171
|
+
|
|
172
|
+
[port, path, wait_thr.pid]
|
|
80
173
|
end
|
|
81
174
|
|
|
82
|
-
def
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
175
|
+
def get_chrome_path candidates
|
|
176
|
+
candidates.each{|c|
|
|
177
|
+
if File.exist? c
|
|
178
|
+
return c
|
|
179
|
+
end
|
|
180
|
+
}
|
|
181
|
+
raise UnsupportedError
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
ITERATIONS = 50
|
|
185
|
+
|
|
186
|
+
def get_devtools_endpoint tf
|
|
187
|
+
i = 1
|
|
188
|
+
while i < ITERATIONS
|
|
189
|
+
i += 1
|
|
190
|
+
if File.exist?(tf) && data = File.read(tf)
|
|
191
|
+
if data.match /DevTools listening on ws:\/\/127.0.0.1:(\d+)(.*)/
|
|
192
|
+
port = $1
|
|
193
|
+
path = $2
|
|
194
|
+
return [port, path]
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
sleep 0.1
|
|
93
198
|
end
|
|
94
|
-
|
|
199
|
+
raise NotFoundChromeEndpointError
|
|
200
|
+
end
|
|
201
|
+
end
|
|
95
202
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
203
|
+
def send_chrome_response req
|
|
204
|
+
@repl = false
|
|
205
|
+
case req
|
|
206
|
+
when /^GET\s\/json\/version\sHTTP\/1.1/
|
|
207
|
+
body = {
|
|
208
|
+
Browser: "ruby/v#{RUBY_VERSION}",
|
|
209
|
+
'Protocol-Version': "1.1"
|
|
99
210
|
}
|
|
100
|
-
|
|
101
|
-
|
|
211
|
+
send_http_res body
|
|
212
|
+
raise UI_ServerBase::RetryConnection
|
|
213
|
+
|
|
214
|
+
when /^GET\s\/json\sHTTP\/1.1/
|
|
215
|
+
@uuid = @uuid || SecureRandom.uuid
|
|
216
|
+
addr = @local_addr.inspect_sockaddr
|
|
217
|
+
body = [{
|
|
218
|
+
description: "ruby instance",
|
|
219
|
+
devtoolsFrontendUrl: "devtools://devtools/bundled/inspector.html?experiments=true&v8only=true&ws=#{addr}/#{@uuid}",
|
|
220
|
+
id: @uuid,
|
|
221
|
+
title: $0,
|
|
222
|
+
type: "node",
|
|
223
|
+
url: "file://#{File.absolute_path($0)}",
|
|
224
|
+
webSocketDebuggerUrl: "ws://#{addr}/#{@uuid}"
|
|
225
|
+
}]
|
|
226
|
+
send_http_res body
|
|
227
|
+
raise UI_ServerBase::RetryConnection
|
|
228
|
+
|
|
229
|
+
when /^GET\s\/(\w{8}-\w{4}-\w{4}-\w{4}-\w{12})\sHTTP\/1.1/
|
|
230
|
+
raise 'Incorrect uuid' unless $1 == @uuid
|
|
231
|
+
|
|
232
|
+
@need_pause_at_first = false
|
|
233
|
+
CONFIG.set_config no_color: true
|
|
234
|
+
|
|
235
|
+
@ws_server = WebSocketServer.new(@sock)
|
|
236
|
+
@ws_server.handshake
|
|
102
237
|
end
|
|
103
238
|
end
|
|
104
239
|
|
|
240
|
+
def send_http_res body
|
|
241
|
+
json = JSON.generate body
|
|
242
|
+
header = "HTTP/1.0 200 OK\r\nContent-Type: application/json; charset=UTF-8\r\nCache-Control: no-cache\r\nContent-Length: #{json.bytesize}\r\n\r\n"
|
|
243
|
+
@sock.puts "#{header}#{json}"
|
|
244
|
+
end
|
|
245
|
+
|
|
105
246
|
module WebSocketUtils
|
|
106
247
|
class Frame
|
|
107
248
|
attr_reader :b
|
|
@@ -528,12 +669,6 @@ module DEBUGGER__
|
|
|
528
669
|
|
|
529
670
|
## Called by the SESSION thread
|
|
530
671
|
|
|
531
|
-
def readline prompt
|
|
532
|
-
return 'c' unless @q_msg
|
|
533
|
-
|
|
534
|
-
@q_msg.pop || 'kill!'
|
|
535
|
-
end
|
|
536
|
-
|
|
537
672
|
def respond req, **result
|
|
538
673
|
send_response req, **result
|
|
539
674
|
end
|
|
@@ -561,6 +696,28 @@ module DEBUGGER__
|
|
|
561
696
|
end
|
|
562
697
|
|
|
563
698
|
class Session
|
|
699
|
+
# FIXME: unify this method with ThreadClient#propertyDescriptor.
|
|
700
|
+
def get_type obj
|
|
701
|
+
case obj
|
|
702
|
+
when Array
|
|
703
|
+
['object', 'array']
|
|
704
|
+
when Hash
|
|
705
|
+
['object', 'map']
|
|
706
|
+
when String
|
|
707
|
+
['string']
|
|
708
|
+
when TrueClass, FalseClass
|
|
709
|
+
['boolean']
|
|
710
|
+
when Symbol
|
|
711
|
+
['symbol']
|
|
712
|
+
when Integer, Float
|
|
713
|
+
['number']
|
|
714
|
+
when Exception
|
|
715
|
+
['object', 'error']
|
|
716
|
+
else
|
|
717
|
+
['object']
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
|
|
564
721
|
def fail_response req, **result
|
|
565
722
|
@ui.respond_fail req, **result
|
|
566
723
|
return :retry
|
|
@@ -584,17 +741,38 @@ module DEBUGGER__
|
|
|
584
741
|
code: INVALID_PARAMS,
|
|
585
742
|
message: "'callFrameId' is an invalid"
|
|
586
743
|
end
|
|
587
|
-
when 'Runtime.getProperties'
|
|
588
|
-
oid = req.dig('params', 'objectId')
|
|
744
|
+
when 'Runtime.getProperties', 'Runtime.getExceptionDetails'
|
|
745
|
+
oid = req.dig('params', 'objectId') || req.dig('params', 'errorObjectId')
|
|
589
746
|
if ref = @obj_map[oid]
|
|
590
747
|
case ref[0]
|
|
591
748
|
when 'local'
|
|
592
749
|
frame_id = ref[1]
|
|
593
750
|
fid = @frame_map[frame_id]
|
|
594
751
|
request_tc [:cdp, :scope, req, fid]
|
|
752
|
+
when 'global'
|
|
753
|
+
vars = global_variables.sort.map do |name|
|
|
754
|
+
gv = eval(name.to_s)
|
|
755
|
+
prop = {
|
|
756
|
+
name: name,
|
|
757
|
+
value: {
|
|
758
|
+
description: gv.inspect
|
|
759
|
+
},
|
|
760
|
+
configurable: true,
|
|
761
|
+
enumerable: true
|
|
762
|
+
}
|
|
763
|
+
type, subtype = get_type(gv)
|
|
764
|
+
prop[:value][:type] = type
|
|
765
|
+
prop[:value][:subtype] = subtype if subtype
|
|
766
|
+
prop
|
|
767
|
+
end
|
|
768
|
+
|
|
769
|
+
@ui.respond req, result: vars
|
|
770
|
+
return :retry
|
|
595
771
|
when 'properties'
|
|
596
772
|
request_tc [:cdp, :properties, req, oid]
|
|
597
|
-
when '
|
|
773
|
+
when 'exception'
|
|
774
|
+
request_tc [:cdp, :exception, req, oid]
|
|
775
|
+
when 'script'
|
|
598
776
|
# TODO: Support script and global types
|
|
599
777
|
@ui.respond req, result: []
|
|
600
778
|
return :retry
|
|
@@ -730,6 +908,9 @@ module DEBUGGER__
|
|
|
730
908
|
frame[:scriptId] = s_id
|
|
731
909
|
end
|
|
732
910
|
}
|
|
911
|
+
if oid = exc[:exception][:objectId]
|
|
912
|
+
@obj_map[oid] = ['exception']
|
|
913
|
+
end
|
|
733
914
|
end
|
|
734
915
|
rs = result.dig(:response, :result)
|
|
735
916
|
[rs].each{|obj|
|
|
@@ -767,6 +948,8 @@ module DEBUGGER__
|
|
|
767
948
|
}
|
|
768
949
|
}
|
|
769
950
|
@ui.respond req, **result
|
|
951
|
+
when :exception
|
|
952
|
+
@ui.respond req, **result
|
|
770
953
|
end
|
|
771
954
|
end
|
|
772
955
|
end
|
|
@@ -872,8 +1055,8 @@ module DEBUGGER__
|
|
|
872
1055
|
result = b.local_variable_get(expr)
|
|
873
1056
|
rescue NameError
|
|
874
1057
|
# try to check method
|
|
875
|
-
if b.receiver
|
|
876
|
-
result = b.receiver
|
|
1058
|
+
if M_RESPOND_TO_P.bind_call(b.receiver, expr, include_all: true)
|
|
1059
|
+
result = M_METHOD.bind_call(b.receiver, expr)
|
|
877
1060
|
else
|
|
878
1061
|
message = "Error: Can not evaluate: #{expr.inspect}"
|
|
879
1062
|
end
|
|
@@ -886,35 +1069,7 @@ module DEBUGGER__
|
|
|
886
1069
|
result = current_frame.binding.eval(expr.to_s, '(DEBUG CONSOLE)')
|
|
887
1070
|
rescue Exception => e
|
|
888
1071
|
result = e
|
|
889
|
-
|
|
890
|
-
frames = [
|
|
891
|
-
{
|
|
892
|
-
columnNumber: 0,
|
|
893
|
-
functionName: 'eval',
|
|
894
|
-
lineNumber: 0,
|
|
895
|
-
url: ''
|
|
896
|
-
}
|
|
897
|
-
]
|
|
898
|
-
e.backtrace_locations&.each do |loc|
|
|
899
|
-
break if loc.path == __FILE__
|
|
900
|
-
path = loc.absolute_path || loc.path
|
|
901
|
-
frames << {
|
|
902
|
-
columnNumber: 0,
|
|
903
|
-
functionName: loc.base_label,
|
|
904
|
-
lineNumber: loc.lineno - 1,
|
|
905
|
-
url: path
|
|
906
|
-
}
|
|
907
|
-
end
|
|
908
|
-
res[:exceptionDetails] = {
|
|
909
|
-
exceptionId: 1,
|
|
910
|
-
text: 'Uncaught',
|
|
911
|
-
lineNumber: 0,
|
|
912
|
-
columnNumber: 0,
|
|
913
|
-
exception: evaluate_result(result),
|
|
914
|
-
stackTrace: {
|
|
915
|
-
callFrames: frames
|
|
916
|
-
}
|
|
917
|
-
}
|
|
1072
|
+
res[:exceptionDetails] = exceptionDetails(e, 'Uncaught')
|
|
918
1073
|
ensure
|
|
919
1074
|
output = $stdout.string
|
|
920
1075
|
$stdout = orig_stdout
|
|
@@ -987,21 +1142,63 @@ module DEBUGGER__
|
|
|
987
1142
|
]
|
|
988
1143
|
end
|
|
989
1144
|
|
|
990
|
-
result += obj.
|
|
991
|
-
variable(iv,
|
|
1145
|
+
result += M_INSTANCE_VARIABLES.bind_call(obj).map{|iv|
|
|
1146
|
+
variable(iv, M_INSTANCE_VARIABLE_GET.bind_call(obj, iv))
|
|
992
1147
|
}
|
|
993
|
-
prop += [internalProperty('#class', obj
|
|
1148
|
+
prop += [internalProperty('#class', M_CLASS.bind_call(obj))]
|
|
994
1149
|
end
|
|
995
1150
|
event! :cdp_result, :properties, req, result: result, internalProperties: prop
|
|
1151
|
+
when :exception
|
|
1152
|
+
oid = args.shift
|
|
1153
|
+
exc = nil
|
|
1154
|
+
if obj = @obj_map[oid]
|
|
1155
|
+
exc = exceptionDetails obj, obj.to_s
|
|
1156
|
+
end
|
|
1157
|
+
event! :cdp_result, :exception, req, exceptionDetails: exc
|
|
1158
|
+
end
|
|
1159
|
+
end
|
|
1160
|
+
|
|
1161
|
+
def exceptionDetails exc, text
|
|
1162
|
+
frames = [
|
|
1163
|
+
{
|
|
1164
|
+
columnNumber: 0,
|
|
1165
|
+
functionName: 'eval',
|
|
1166
|
+
lineNumber: 0,
|
|
1167
|
+
url: ''
|
|
1168
|
+
}
|
|
1169
|
+
]
|
|
1170
|
+
exc.backtrace_locations&.each do |loc|
|
|
1171
|
+
break if loc.path == __FILE__
|
|
1172
|
+
path = loc.absolute_path || loc.path
|
|
1173
|
+
frames << {
|
|
1174
|
+
columnNumber: 0,
|
|
1175
|
+
functionName: loc.base_label,
|
|
1176
|
+
lineNumber: loc.lineno - 1,
|
|
1177
|
+
url: path
|
|
1178
|
+
}
|
|
996
1179
|
end
|
|
1180
|
+
{
|
|
1181
|
+
exceptionId: 1,
|
|
1182
|
+
text: text,
|
|
1183
|
+
lineNumber: 0,
|
|
1184
|
+
columnNumber: 0,
|
|
1185
|
+
exception: evaluate_result(exc),
|
|
1186
|
+
stackTrace: {
|
|
1187
|
+
callFrames: frames
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
997
1190
|
end
|
|
998
1191
|
|
|
999
1192
|
def search_const b, expr
|
|
1000
1193
|
cs = expr.delete_prefix('::').split('::')
|
|
1001
|
-
[Object, *b.eval('Module.nesting')].reverse_each{|mod|
|
|
1194
|
+
[Object, *b.eval('::Module.nesting')].reverse_each{|mod|
|
|
1002
1195
|
if cs.all?{|c|
|
|
1003
1196
|
if mod.const_defined?(c)
|
|
1004
|
-
|
|
1197
|
+
begin
|
|
1198
|
+
mod = mod.const_get(c)
|
|
1199
|
+
rescue Exception
|
|
1200
|
+
false
|
|
1201
|
+
end
|
|
1005
1202
|
else
|
|
1006
1203
|
false
|
|
1007
1204
|
end
|
|
@@ -1045,25 +1242,29 @@ module DEBUGGER__
|
|
|
1045
1242
|
v = prop[:value]
|
|
1046
1243
|
v.delete :value
|
|
1047
1244
|
v[:subtype] = subtype if subtype
|
|
1048
|
-
v[:className] = obj.
|
|
1245
|
+
v[:className] = (klass = M_CLASS.bind_call(obj)).name || klass.to_s
|
|
1049
1246
|
end
|
|
1050
1247
|
prop
|
|
1051
1248
|
end
|
|
1052
1249
|
|
|
1053
1250
|
def preview_ value, hash, overflow
|
|
1251
|
+
# The reason for not using "map" method is to prevent the object overriding it from causing bugs.
|
|
1252
|
+
# https://github.com/ruby/debug/issues/781
|
|
1253
|
+
props = []
|
|
1254
|
+
hash.each{|k, v|
|
|
1255
|
+
pd = propertyDescriptor k, v
|
|
1256
|
+
props << {
|
|
1257
|
+
name: pd[:name],
|
|
1258
|
+
type: pd[:value][:type],
|
|
1259
|
+
value: pd[:value][:description]
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1054
1262
|
{
|
|
1055
1263
|
type: value[:type],
|
|
1056
1264
|
subtype: value[:subtype],
|
|
1057
1265
|
description: value[:description],
|
|
1058
1266
|
overflow: overflow,
|
|
1059
|
-
properties:
|
|
1060
|
-
pd = propertyDescriptor k, v
|
|
1061
|
-
{
|
|
1062
|
-
name: pd[:name],
|
|
1063
|
-
type: pd[:value][:type],
|
|
1064
|
-
value: pd[:value][:description]
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1267
|
+
properties: props
|
|
1067
1268
|
}
|
|
1068
1269
|
end
|
|
1069
1270
|
|