ladybug 0.1.1 → 0.1.2
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/README.md +10 -7
- data/lib/ladybug/debugger.rb +30 -10
- data/lib/ladybug/middleware.rb +43 -35
- data/lib/ladybug/object_manager.rb +1 -3
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b73479c1e9523e9a0f5798daed1707ed24baf74c
|
4
|
+
data.tar.gz: d046e7c87d246a2e3a156ad1bf71c23fc256789c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c79d7443d7cebedbb3174fe5a340aa21d2c23d201df2fab87aa6294326c839b3371e187f46eb7d351f4c7c8ad8bf103197882ded9dfb588284f1ae3422eca4ed
|
7
|
+
data.tar.gz: 58f696d4d5dc454c68215c0a3780f9ea2c45d070db1e168f915f2be26bf7ec5e567a02c110439291962f8db88f4e481a4d70978e669f0d7f01c0129c8f8893b4
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ Chrome Devtools as a user interface.
|
|
6
6
|
It aims to provide a rich backend debugging experience in a UI that many
|
7
7
|
web developers are already familiar with for debugging frontend Javascript.
|
8
8
|
|
9
|
-
**This project is currently in
|
9
|
+
**This project is currently in an early experimental phase.** Expect many limitations and bugs. If you try it out, please file
|
10
10
|
Github issues or [email me](mailto:gklitt@gmail.com) to help make this a
|
11
11
|
more useful tool.
|
12
12
|
|
@@ -14,9 +14,9 @@ more useful tool.
|
|
14
14
|
|
15
15
|
## Get started
|
16
16
|
|
17
|
-
1) Install the gem:
|
17
|
+
1) Install the gem, or add it to your Gemfile:
|
18
18
|
|
19
|
-
`gem install
|
19
|
+
`gem install ladybug`
|
20
20
|
|
21
21
|
2) ladybug is implemented as a Rack middleware, so you'll need to add
|
22
22
|
`Ladybug::Middleware` to the Rack middleware stack.
|
@@ -24,7 +24,7 @@ For example, in Rails 5, add
|
|
24
24
|
the following line to `config/application.rb`:
|
25
25
|
|
26
26
|
```
|
27
|
-
config.middleware.
|
27
|
+
config.middleware.use(Ladybug::Middleware)
|
28
28
|
```
|
29
29
|
|
30
30
|
3) Make sure you're using the puma web server, which is currently the
|
@@ -41,7 +41,11 @@ You should see your server program output something like:
|
|
41
41
|
In the Sources tab, you can view your Ruby source code.
|
42
42
|
If you set a breakpoint and then make another request to your server,
|
43
43
|
it should pause on the breakpoint and you'll be able to inspect
|
44
|
-
|
44
|
+
local and instance variables in Devtools.
|
45
|
+
|
46
|
+
6) You can then use the "step over" button to step through your code,
|
47
|
+
or "continue" to continue code execution. "Step into" and "Step out"
|
48
|
+
also work in some contexts.
|
45
49
|
|
46
50
|
**Security warning:** This debugger should only be run in local development.
|
47
51
|
Running it on a server open to the internet could allow anyone to
|
@@ -49,11 +53,10 @@ execute code on your server without authenticating.
|
|
49
53
|
|
50
54
|
## Development status
|
51
55
|
|
52
|
-
* basic pause/continue breakpoint control is supported, but "step over" and "step into" aren't fully supported yet.
|
53
|
-
* inspecting primtive objects like strings and numbers works okay; support for more complex objects is in development.
|
54
56
|
* So far, ladybug has only been tested with simple Rails applications running on
|
55
57
|
Rails 5 with the puma web server. Eventually it aims to support more Rack
|
56
58
|
applications and web servers (and perhaps even non-Rack applications).
|
59
|
+
* inspecting primtive objects like strings and numbers works okay; support for more complex objects is in development.
|
57
60
|
|
58
61
|
## Author
|
59
62
|
|
data/lib/ladybug/debugger.rb
CHANGED
@@ -25,6 +25,8 @@ module Ladybug
|
|
25
25
|
|
26
26
|
@parsed_files = {}
|
27
27
|
|
28
|
+
@break = nil
|
29
|
+
|
28
30
|
# Todo: consider thread safety of mutating this hash
|
29
31
|
Thread.new do
|
30
32
|
preload_paths.each do |preload_path|
|
@@ -41,6 +43,20 @@ module Ladybug
|
|
41
43
|
set_trace_func trace_func
|
42
44
|
end
|
43
45
|
|
46
|
+
def debug
|
47
|
+
RubyVM::InstructionSequence.compile_option = {
|
48
|
+
trace_instruction: true
|
49
|
+
}
|
50
|
+
Thread.current.set_trace_func trace_func
|
51
|
+
|
52
|
+
yield
|
53
|
+
ensure
|
54
|
+
RubyVM::InstructionSequence.compile_option = {
|
55
|
+
trace_instruction: false
|
56
|
+
}
|
57
|
+
Thread.current.set_trace_func nil
|
58
|
+
end
|
59
|
+
|
44
60
|
def on_pause(&block)
|
45
61
|
@on_pause = block
|
46
62
|
end
|
@@ -131,12 +147,12 @@ module Ladybug
|
|
131
147
|
# remove ladybug code from a callstack and prepare it for comparison
|
132
148
|
# this is a hack implemenetation for now, can be made better
|
133
149
|
def clean(callstack)
|
134
|
-
callstack.drop_while { |frame| frame.to_s.include? "ladybug" }
|
150
|
+
callstack.drop_while { |frame| frame.to_s.include? "ladybug/debugger.rb" }
|
135
151
|
end
|
136
152
|
|
137
153
|
# If we're in step over/in/out mode,
|
138
154
|
# detect if we should break even if there's not a breakpoint set here
|
139
|
-
def break_on_step?
|
155
|
+
def break_on_step?(filename:)
|
140
156
|
# This is an important early return;
|
141
157
|
# we don't want to do anything w/ the callstack unless
|
142
158
|
# we're looking for a breakpoint, because
|
@@ -144,22 +160,21 @@ module Ladybug
|
|
144
160
|
# which makes things really slow
|
145
161
|
return false if @break.nil?
|
146
162
|
|
163
|
+
return false if @break == 'step_over' &&
|
164
|
+
@breakpoint_filename != filename
|
165
|
+
|
147
166
|
bp_callstack = clean(@breakpoint_callstack)
|
148
167
|
current_callstack = clean(Thread.current.backtrace_locations)
|
149
168
|
|
150
169
|
if @break == 'step_over'
|
151
|
-
return
|
170
|
+
return current_callstack[1].to_s == bp_callstack[1].to_s
|
152
171
|
elsif @break == 'step_into'
|
153
|
-
return
|
172
|
+
return current_callstack[1].to_s == bp_callstack[0].to_s
|
154
173
|
elsif @break == 'step_out'
|
155
|
-
return
|
174
|
+
return current_callstack[0].to_s == bp_callstack[1].to_s
|
156
175
|
end
|
157
176
|
end
|
158
177
|
|
159
|
-
def stacks_equal?(stack1, stack2)
|
160
|
-
stack1.map(&:to_s) == stack2.map(&:to_s)
|
161
|
-
end
|
162
|
-
|
163
178
|
def trace_func
|
164
179
|
proc { |event, filename, line_number, id, binding, klass, *rest|
|
165
180
|
# This check is called a lot so perhaps worth making faster,
|
@@ -168,12 +183,15 @@ module Ladybug
|
|
168
183
|
bp[:filename] == filename && bp[:line_number] == line_number
|
169
184
|
end
|
170
185
|
|
171
|
-
if breakpoint_hit || break_on_step?
|
186
|
+
if breakpoint_hit || break_on_step?(filename: filename)
|
172
187
|
local_variables =
|
173
188
|
binding.local_variables.each_with_object({}) do |lvar, hash|
|
174
189
|
hash[lvar] = binding.local_variable_get(lvar)
|
175
190
|
end
|
176
191
|
|
192
|
+
# todo: may want to offer classes the ability to
|
193
|
+
# override this and define which instance variables to expose here?
|
194
|
+
|
177
195
|
instance_variables =
|
178
196
|
binding.eval("instance_variables").each_with_object({}) do |ivar, hash|
|
179
197
|
hash[ivar] = binding.eval("instance_variable_get(:#{ivar})")
|
@@ -215,10 +233,12 @@ module Ladybug
|
|
215
233
|
case message[:command]
|
216
234
|
when 'continue'
|
217
235
|
@break = nil
|
236
|
+
@breakpoint_filename = nil
|
218
237
|
break
|
219
238
|
when 'step_over'
|
220
239
|
@break = 'step_over'
|
221
240
|
@breakpoint_callstack = Thread.current.backtrace_locations
|
241
|
+
@breakpoint_filename = filename
|
222
242
|
break
|
223
243
|
when 'step_into'
|
224
244
|
@break = 'step_into'
|
data/lib/ladybug/middleware.rb
CHANGED
@@ -31,7 +31,9 @@ module Ladybug
|
|
31
31
|
# Return async Rack response
|
32
32
|
ws.rack_response
|
33
33
|
else
|
34
|
-
@
|
34
|
+
@debugger.debug do
|
35
|
+
@app.call(env)
|
36
|
+
end
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
@@ -224,42 +226,50 @@ module Ladybug
|
|
224
226
|
|
225
227
|
script = @script_repository.find(absolute_path: info[:filename])
|
226
228
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
229
|
+
# currently we don't support going into functions
|
230
|
+
# that aren't in the path of our current app.
|
231
|
+
if script.nil?
|
232
|
+
puts "Debugger was paused on file outside of app: #{info[:filename]}"
|
233
|
+
puts "ladybug currently only supports pausing in app files."
|
234
|
+
@debugger.resume
|
235
|
+
else
|
236
|
+
location = {
|
237
|
+
scriptId: script.id,
|
238
|
+
lineNumber: info[:line_number] - 1,
|
239
|
+
columnNumber: 0
|
240
|
+
}
|
232
241
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
242
|
+
msg_to_client = {
|
243
|
+
method: "Debugger.paused",
|
244
|
+
params: {
|
245
|
+
callFrames: [
|
246
|
+
{
|
247
|
+
location: location,
|
248
|
+
callFrameId: SecureRandom.uuid,
|
249
|
+
functionName: info[:label],
|
250
|
+
scopeChain: [
|
251
|
+
{
|
252
|
+
type: "local",
|
253
|
+
startLocation: location,
|
254
|
+
endLocation: location,
|
255
|
+
object: {
|
256
|
+
className: "Object",
|
257
|
+
description: "Object",
|
258
|
+
type: "object",
|
259
|
+
objectId: object_id
|
260
|
+
}
|
251
261
|
}
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
262
|
+
],
|
263
|
+
url: script.virtual_url
|
264
|
+
}
|
265
|
+
],
|
266
|
+
hitBreakpoints: info[:breakpoint_id] ? [info[:breakpoint_id]] : [],
|
267
|
+
reason: "other"
|
268
|
+
}
|
259
269
|
}
|
260
|
-
}
|
261
270
|
|
262
|
-
|
271
|
+
ws.send(msg_to_client.to_json)
|
272
|
+
end
|
263
273
|
end
|
264
274
|
|
265
275
|
@debugger.on_resume do
|
@@ -271,8 +281,6 @@ module Ladybug
|
|
271
281
|
ws.send(msg_to_client.to_json)
|
272
282
|
end
|
273
283
|
|
274
|
-
@debugger.start
|
275
|
-
|
276
284
|
ws
|
277
285
|
end
|
278
286
|
end
|
@@ -99,12 +99,10 @@ module Ladybug
|
|
99
99
|
elsif object.is_a? Hash
|
100
100
|
object.
|
101
101
|
map do |key, value|
|
102
|
-
|
102
|
+
{
|
103
103
|
name: key,
|
104
104
|
value: serialize(value)
|
105
105
|
}
|
106
|
-
|
107
|
-
kv
|
108
106
|
end.
|
109
107
|
reject { |property| property[:value].nil? }
|
110
108
|
elsif object.is_a? Array
|