Skip to content

Commit 783a91e

Browse files
authored
Merge pull request #203 from gsamokovarov/exception-mapper
Map bindings to traces based on the trace __FILE__ and __LINE__
2 parents 47523ac + 3a27cc9 commit 783a91e

File tree

7 files changed

+86
-22
lines changed

7 files changed

+86
-22
lines changed

lib/web_console.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module WebConsole
77

88
autoload :View
99
autoload :Evaluator
10+
autoload :ExceptionMapper
1011
autoload :Session
1112
autoload :Response
1213
autoload :Request

lib/web_console/exception_mapper.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module WebConsole
2+
class ExceptionMapper
3+
def initialize(exception)
4+
@backtrace = exception.backtrace
5+
@bindings = exception.bindings
6+
end
7+
8+
def first
9+
guess_the_first_application_binding || @bindings.first
10+
end
11+
12+
def [](index)
13+
guess_binding_for_index(index) || @bindings[index]
14+
end
15+
16+
private
17+
18+
def guess_binding_for_index(index)
19+
file, line = @backtrace[index].to_s.split(':')
20+
line = line.to_i
21+
22+
@bindings.find do |binding|
23+
binding.eval('__FILE__') == file && binding.eval('__LINE__') == line
24+
end
25+
end
26+
27+
def guess_the_first_application_binding
28+
@bindings.find do |binding|
29+
binding.eval('__FILE__').to_s.start_with?(Rails.root.to_s)
30+
end
31+
end
32+
end
33+
end

lib/web_console/session.rb

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ def find(id)
3030
# storage.
3131
def from(storage)
3232
if exc = storage[:__web_console_exception]
33-
new(exc.bindings)
33+
new(ExceptionMapper.new(exc))
3434
elsif binding = storage[:__web_console_binding]
35-
new(binding)
35+
new([binding])
3636
end
3737
end
3838
end
@@ -42,8 +42,8 @@ def from(storage)
4242

4343
def initialize(bindings)
4444
@id = SecureRandom.hex(16)
45-
@bindings = Array(bindings)
46-
@evaluator = Evaluator.new(application_binding || @bindings.first)
45+
@bindings = bindings
46+
@evaluator = Evaluator.new(bindings.first)
4747

4848
store_into_memory
4949
end
@@ -64,10 +64,6 @@ def switch_binding_to(index)
6464

6565
private
6666

67-
def application_binding
68-
@bindings.find { |b| b.eval('__FILE__').to_s.start_with?(Rails.root.to_s) }
69-
end
70-
7167
def store_into_memory
7268
inmemory_storage[id] = self
7369
end
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
<% @ok = 42 %>
2-
<% raise %>
2+
<% params.fetch(:bad_key) %>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
require 'test_helper'
2+
3+
module WebConsole
4+
class ExcetionMapperTest < ActiveSupport::TestCase
5+
test '#first tries to find the first application binding' do
6+
Rails.stubs(:root).returns Pathname(__FILE__).parent
7+
8+
mapper = ExceptionMapper.new(External.exception)
9+
10+
assert_equal __FILE__, mapper.first.eval('__FILE__')
11+
end
12+
13+
test '.[] tries match the binding for trace index' do
14+
exception = External.exception
15+
mapper = ExceptionMapper.new(exception)
16+
17+
last_index = exception.backtrace.count - 1
18+
file, line = exception.backtrace.last.split(':')
19+
20+
assert_equal file, mapper[last_index].eval('__FILE__')
21+
assert_equal line.to_i, mapper[last_index].eval('__LINE__')
22+
end
23+
24+
test '.[] fall backs to index if no trace can be found' do
25+
exception = External.exception
26+
mapper = ExceptionMapper.new(exception)
27+
28+
unbound_index = exception.backtrace.count
29+
30+
assert_nil mapper[unbound_index]
31+
end
32+
end
33+
end

test/web_console/middleware_test.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def body
124124
end
125125

126126
test 'can evaluate code and return it as a JSON' do
127-
session, line = Session.new(binding), __LINE__
127+
session, line = Session.new([binding]), __LINE__
128128

129129
Session.stubs(:from).returns(session)
130130

@@ -148,7 +148,7 @@ def body
148148
test 'can be changed mount point' do
149149
Middleware.mount_point = '/customized/path'
150150

151-
session, line = Session.new(binding), __LINE__
151+
session, line = Session.new([binding]), __LINE__
152152
put "/customized/path/repl_sessions/#{session.id}", params: { input: '__LINE__' }, xhr: true
153153

154154
assert_equal({ output: "=> #{line}\n" }.to_json, response.body)

test/web_console/session_test.rb

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,8 @@ def initialize(line)
1717
end
1818

1919
setup do
20-
Rails.stubs(:root).returns Pathname(__FILE__).parent
2120
Session.inmemory_storage.clear
22-
@session = Session.new(binding)
21+
@session = Session.new([binding])
2322
end
2423

2524
test 'returns nil when a session is not found' do
@@ -34,17 +33,19 @@ def initialize(line)
3433
assert_equal "=> 42\n", @session.eval('40 + 2')
3534
end
3635

37-
test 'find first binding of the rails app' do
38-
session = Session.new(External.exception.bindings)
39-
assert_equal session.eval('__FILE__'), "=> \"#{__FILE__}\"\n"
40-
end
41-
4236
test 'use first binding if no application bindings' do
43-
binding = Object.new
44-
binding.expects(:eval).with('__FILE__').returns 'framework'
45-
binding.expects(:eval).with('called?').returns 'yes'
37+
binding = Object.new.instance_eval do
38+
def eval(string)
39+
case string
40+
when '__FILE__' then framework
41+
when 'called?' then 'yes'
42+
end
43+
end
44+
45+
self
46+
end
4647

47-
session = Session.new(binding)
48+
session = Session.new([binding])
4849
assert_equal session.eval('called?'), "=> \"yes\"\n"
4950
end
5051

0 commit comments

Comments
 (0)