exceptron 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/lib/exceptron.rb +38 -0
- data/lib/exceptron/dispatcher.rb +58 -0
- data/lib/exceptron/exception.rb +97 -0
- data/lib/exceptron/exceptions_controller.rb +19 -0
- data/lib/exceptron/helpers.rb +24 -0
- data/lib/exceptron/local_exceptions_controller.rb +17 -0
- data/lib/exceptron/local_helpers.rb +27 -0
- data/lib/exceptron/middleware.rb +27 -0
- data/lib/exceptron/railtie.rb +16 -0
- data/lib/exceptron/version.rb +3 -0
- data/lib/exceptron/views/exceptron/exceptions/internal_server_error.html.erb +26 -0
- data/lib/exceptron/views/exceptron/local_exceptions/_request_and_response.erb +27 -0
- data/lib/exceptron/views/exceptron/local_exceptions/_trace.erb +26 -0
- data/lib/exceptron/views/exceptron/local_exceptions/diagnostics.erb +10 -0
- data/lib/exceptron/views/exceptron/local_exceptions/missing_template.erb +2 -0
- data/lib/exceptron/views/exceptron/local_exceptions/routing_error.erb +10 -0
- data/lib/exceptron/views/exceptron/local_exceptions/template_error.erb +17 -0
- data/lib/exceptron/views/exceptron/local_exceptions/unknown_action.erb +2 -0
- data/lib/exceptron/views/layouts/exceptron/local_exceptions.erb +31 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/controllers/application_controller.rb +4 -0
- data/test/dummy/app/controllers/exceptions_controller.rb +24 -0
- data/test/dummy/app/controllers/home_controller.rb +4 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/app_exceptions/internal_server_error.html.erb +2 -0
- data/test/dummy/app/views/app_exceptions/not_found.html.erb +2 -0
- data/test/dummy/app/views/home/index.erb +1 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/layouts/exceptions.html.erb +12 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +49 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +22 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +25 -0
- data/test/dummy/config/environments/production.rb +49 -0
- data/test/dummy/config/environments/test.rb +35 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +60 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/production.sqlite3 +0 -0
- data/test/dummy/db/schema.rb +15 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/test.log +40506 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/javascripts/application.js +2 -0
- data/test/dummy/public/javascripts/controls.js +965 -0
- data/test/dummy/public/javascripts/dragdrop.js +974 -0
- data/test/dummy/public/javascripts/effects.js +1123 -0
- data/test/dummy/public/javascripts/prototype.js +4874 -0
- data/test/dummy/public/javascripts/rails.js +118 -0
- data/test/dummy/public/stylesheets/exceptions.css +17 -0
- data/test/dummy/script/rails +6 -0
- data/test/exceptron_local_custom_test.rb +173 -0
- data/test/exceptron_local_test.rb +122 -0
- data/test/exceptron_public_custom_test.rb +128 -0
- data/test/exceptron_public_test.rb +72 -0
- data/test/test_helper.rb +48 -0
- data/test/views/exceptions_custom/internal_server_error.da.html.erb +1 -0
- data/test/views/exceptions_custom/internal_server_error.json +1 -0
- data/test/views/exceptions_custom/not_found.html +26 -0
- data/test/views/exceptions_custom/not_found.xml +5 -0
- data/test/views/exceptions_custom/not_implemented.html.erb +26 -0
- data/test/views/layouts/exception_test.html.erb +12 -0
- data/test/views/local_exceptions_custom/diagnostics.da.html.erb +1 -0
- data/test/views/local_exceptions_custom/not_implemented.html.erb +26 -0
- data/test/views/local_exceptions_custom/unknown_action.erb +2 -0
- metadata +197 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2010 JORLHUDA
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/lib/exceptron.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'exceptron/railtie'
|
2
|
+
|
3
|
+
module Exceptron
|
4
|
+
autoload :Dispatcher, 'exceptron/dispatcher'
|
5
|
+
autoload :Exception, 'exceptron/exception'
|
6
|
+
autoload :ExceptionsController, 'exceptron/exceptions_controller'
|
7
|
+
autoload :Helpers, 'exceptron/helpers'
|
8
|
+
autoload :LocalExceptionsController, 'exceptron/local_exceptions_controller'
|
9
|
+
autoload :LocalHelpers, 'exceptron/local_helpers'
|
10
|
+
autoload :Middleware, 'exceptron/middleware'
|
11
|
+
autoload :VERSION, 'exceptron/version'
|
12
|
+
|
13
|
+
|
14
|
+
mattr_reader :rescue_templates
|
15
|
+
@@rescue_templates = Hash.new('diagnostics')
|
16
|
+
@@rescue_templates.update(
|
17
|
+
'ActionView::MissingTemplate' => 'missing_template',
|
18
|
+
'ActionController::RoutingError' => 'routing_error',
|
19
|
+
'AbstractController::ActionNotFound' => 'unknown_action',
|
20
|
+
'ActionView::Template::Error' => 'template_error'
|
21
|
+
)
|
22
|
+
|
23
|
+
def self.enable!
|
24
|
+
@@enabled = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.disable!
|
28
|
+
@@enabled = false
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.enabled?
|
32
|
+
@@enabled
|
33
|
+
end
|
34
|
+
|
35
|
+
class << self
|
36
|
+
attr_accessor :controller, :local_controller
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Exceptron
|
2
|
+
class Dispatcher
|
3
|
+
FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'},
|
4
|
+
["<html><head><title>500 Internal Server Error</title></head>" +
|
5
|
+
"<body><h1>500 Internal Server Error</h1>If you are the administrator of " +
|
6
|
+
"this website, then please read this web application's log file and/or the " +
|
7
|
+
"web server's log file to find out what went wrong.</body></html>"]]
|
8
|
+
|
9
|
+
def initialize(consider_all_requests_local)
|
10
|
+
@consider_all_requests_local = consider_all_requests_local
|
11
|
+
@exception_actions_cache = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def dispatch(env, exception)
|
15
|
+
log_error(exception.wrapped_exception)
|
16
|
+
|
17
|
+
local = @consider_all_requests_local || ActionDispatch::Request.new(env).local?
|
18
|
+
controller = exception_controller(local)
|
19
|
+
action = exception_action(local, controller, exception)
|
20
|
+
|
21
|
+
if action
|
22
|
+
controller.action(action).call(env)
|
23
|
+
else
|
24
|
+
FAILSAFE_RESPONSE
|
25
|
+
end
|
26
|
+
rescue Exception => failsafe_error
|
27
|
+
$stderr.puts "Error during failsafe response: #{failsafe_error}"
|
28
|
+
$stderr.puts failsafe_error.backtrace.join("\n")
|
29
|
+
FAILSAFE_RESPONSE
|
30
|
+
end
|
31
|
+
|
32
|
+
def exception_controller(local)
|
33
|
+
local ? Exceptron.local_controller : Exceptron.controller
|
34
|
+
end
|
35
|
+
|
36
|
+
def exception_action(local, controller_klass, exception)
|
37
|
+
controller = controller_klass.new
|
38
|
+
@exception_actions_cache[controller_klass] ||= {}
|
39
|
+
@exception_actions_cache[controller_klass][exception.original_exception.class] ||=
|
40
|
+
exception.actions.find { |action| controller.available_action?(action) }
|
41
|
+
end
|
42
|
+
|
43
|
+
def log_error(exception)
|
44
|
+
return unless logger
|
45
|
+
|
46
|
+
ActiveSupport::Deprecation.silence do
|
47
|
+
message = "\n#{exception.class} (#{exception.message}):\n"
|
48
|
+
message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
|
49
|
+
message << exception.backtrace.join("\n ")
|
50
|
+
logger.fatal("#{message}\n\n")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def logger
|
55
|
+
defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
class Exceptron::Presenter
|
2
|
+
def initialize(exception)
|
3
|
+
@wrapped_exception = exception
|
4
|
+
end
|
5
|
+
attr_reader :wrapped_exception
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :statuses
|
9
|
+
end
|
10
|
+
self.statuses = {}
|
11
|
+
|
12
|
+
def to_xml(options={})
|
13
|
+
_serialize(:xml, options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_json(options={})
|
17
|
+
_serialize(:json, options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def status_code
|
21
|
+
statuses = self.class.statuses
|
22
|
+
registered_exception = original_exception.class.ancestors.find { |klass| statuses.key? klass }
|
23
|
+
statuses[registered_exception]
|
24
|
+
end
|
25
|
+
|
26
|
+
def status_message
|
27
|
+
status = Rack::Utils::HTTP_STATUS_CODES[status_code]
|
28
|
+
status.to_s if status
|
29
|
+
end
|
30
|
+
|
31
|
+
def actions
|
32
|
+
original_exception.class.ancestors.map do |klass|
|
33
|
+
status_code = self.class.statuses[klass]
|
34
|
+
status = Rack::Utils::HTTP_STATUS_CODES[status_code]
|
35
|
+
status.to_s.downcase.gsub(/\s|-/, '_') if status
|
36
|
+
end.compact
|
37
|
+
end
|
38
|
+
|
39
|
+
def original_exception
|
40
|
+
if wrapped_exception.respond_to?(:original_exception)
|
41
|
+
wrapped_exception.original_exception
|
42
|
+
else
|
43
|
+
wrapped_exception
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def _serialize(serializer, options) #:nodoc:
|
50
|
+
hash = { :status => status_code, :message => status_message }
|
51
|
+
options = { :root => "error" }.merge!(options)
|
52
|
+
hash.send(:"to_#{serializer}", options)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class Exception
|
57
|
+
def self.respond_with(status)
|
58
|
+
Exceptron::Presenter.statuses[self] = status
|
59
|
+
end
|
60
|
+
respond_with 500
|
61
|
+
end
|
62
|
+
|
63
|
+
ActiveSupport.on_load(:action_controller) do
|
64
|
+
class ActionController::RoutingError
|
65
|
+
respond_with 404
|
66
|
+
end
|
67
|
+
|
68
|
+
class AbstractController::ActionNotFound
|
69
|
+
respond_with 404
|
70
|
+
end
|
71
|
+
|
72
|
+
class ActionController::MethodNotAllowed
|
73
|
+
respond_with 405
|
74
|
+
end
|
75
|
+
|
76
|
+
class ActionController::NotImplemented
|
77
|
+
respond_with 501
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
ActiveSupport.on_load(:active_record) do
|
82
|
+
class ActiveRecord::RecordNotFound
|
83
|
+
respond_with 404
|
84
|
+
end
|
85
|
+
|
86
|
+
class ActiveRecord::StaleObjectError
|
87
|
+
respond_with 409
|
88
|
+
end
|
89
|
+
|
90
|
+
class ActiveRecord::RecordInvalid
|
91
|
+
respond_with 422
|
92
|
+
end
|
93
|
+
|
94
|
+
class ActiveRecord::RecordNotSaved
|
95
|
+
respond_with 422
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Exceptron
|
2
|
+
class ExceptionsController < ActionController::Base
|
3
|
+
append_view_path File.expand_path("../views", __FILE__)
|
4
|
+
respond_to :html, :xml, :json
|
5
|
+
|
6
|
+
include Exceptron::Helpers
|
7
|
+
|
8
|
+
def internal_server_error
|
9
|
+
respond_with exception_presenter
|
10
|
+
end
|
11
|
+
alias not_found internal_server_error
|
12
|
+
alias unprocessable_entity internal_server_error
|
13
|
+
|
14
|
+
def self.inherited(subclass)
|
15
|
+
super
|
16
|
+
Exceptron.controller = subclass
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Exceptron
|
2
|
+
module Helpers
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_filter :set_status_code
|
7
|
+
helper_method :exception_presenter, :exception
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
|
12
|
+
def set_status_code
|
13
|
+
self.status = exception_presenter.status_code
|
14
|
+
end
|
15
|
+
|
16
|
+
def exception_presenter
|
17
|
+
@presenter ||= env["exceptron.presenter"]
|
18
|
+
end
|
19
|
+
|
20
|
+
def exception
|
21
|
+
@exception ||= exception_presenter.wrapped_exception
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Exceptron
|
2
|
+
class LocalExceptionsController < ActionController::Base
|
3
|
+
append_view_path File.expand_path("../views", __FILE__)
|
4
|
+
include Exceptron::Helpers
|
5
|
+
|
6
|
+
helper Exceptron::LocalHelpers
|
7
|
+
|
8
|
+
def internal_server_error
|
9
|
+
render :action => Exceptron.rescue_templates[exception_presenter.original_exception.class.name]
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.inherited(subclass)
|
13
|
+
super
|
14
|
+
Exceptron.local_controller = subclass
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Exceptron
|
2
|
+
module LocalHelpers
|
3
|
+
def application_trace
|
4
|
+
clean_backtrace(exception, :silent)
|
5
|
+
end
|
6
|
+
|
7
|
+
def framework_trace
|
8
|
+
clean_backtrace(exception, :noise)
|
9
|
+
end
|
10
|
+
|
11
|
+
def full_trace
|
12
|
+
clean_backtrace(exception, :all)
|
13
|
+
end
|
14
|
+
|
15
|
+
def debug_hash(hash)
|
16
|
+
hash.map { |k, v| "#{k}: #{v.inspect}" }.sort.join("\n")
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def clean_backtrace(exception, *args)
|
22
|
+
Rails.respond_to?(:backtrace_cleaner) && Rails.backtrace_cleaner ?
|
23
|
+
Rails.backtrace_cleaner.clean(exception.backtrace, *args) :
|
24
|
+
exception.backtrace
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Exceptron
|
2
|
+
class Middleware
|
3
|
+
def initialize(app, consider_all_requests_local)
|
4
|
+
@app = app
|
5
|
+
@dispatcher = Dispatcher.new(consider_all_requests_local)
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
begin
|
10
|
+
status, headers, body = @app.call(env)
|
11
|
+
exception = nil
|
12
|
+
|
13
|
+
# Only this middleware cares about RoutingError. So, let's just raise
|
14
|
+
# it here.
|
15
|
+
if headers['X-Cascade'] == 'pass'
|
16
|
+
raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"
|
17
|
+
end
|
18
|
+
rescue Exception => exception
|
19
|
+
raise exception unless Exceptron.enabled?
|
20
|
+
exception = Presenter.new(exception)
|
21
|
+
env["exceptron.presenter"] = exception
|
22
|
+
end
|
23
|
+
|
24
|
+
exception ? @dispatcher.dispatch(env, exception) : [status, headers, body]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Exceptron
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
config.exceptron = Exceptron
|
4
|
+
|
5
|
+
initializer "exceptron.swap_middlewares" do |app|
|
6
|
+
app.middleware.swap "ActionDispatch::ShowExceptions",
|
7
|
+
"Exceptron::Middleware", app.config.consider_all_requests_local
|
8
|
+
end
|
9
|
+
|
10
|
+
config.after_initialize do
|
11
|
+
config.exceptron.enable!
|
12
|
+
config.exceptron.controller ||= Exceptron::ExceptionsController
|
13
|
+
config.exceptron.local_controller ||= Exceptron::LocalExceptionsController
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>We're sorry, but something went wrong (<%= exception_presenter.status_code %>)</title>
|
5
|
+
<style type="text/css">
|
6
|
+
body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
|
7
|
+
div.dialog {
|
8
|
+
width: 25em;
|
9
|
+
padding: 0 4em;
|
10
|
+
margin: 4em auto 0 auto;
|
11
|
+
border: 1px solid #ccc;
|
12
|
+
border-right-color: #999;
|
13
|
+
border-bottom-color: #999;
|
14
|
+
}
|
15
|
+
h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
|
16
|
+
</style>
|
17
|
+
</head>
|
18
|
+
|
19
|
+
<body>
|
20
|
+
<!-- This file lives in public/500.html -->
|
21
|
+
<div class="dialog">
|
22
|
+
<h1>We're sorry, but something went wrong.</h1>
|
23
|
+
<p>We've been notified about this issue and we'll take a look at it shortly.</p>
|
24
|
+
</div>
|
25
|
+
</body>
|
26
|
+
</html>
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<% unless exception.blamed_files.blank? %>
|
2
|
+
<% if (hide = exception.blamed_files.length > 8) %>
|
3
|
+
<a href="#" onclick="document.getElementById('blame_trace').style.display='block'; return false;">Show blamed files</a>
|
4
|
+
<% end %>
|
5
|
+
<pre id="blame_trace" <%='style="display:none"' if hide %>><code><%=h exception.describe_blame %></code></pre>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<%
|
9
|
+
clean_params = request.filtered_parameters.clone
|
10
|
+
clean_params.delete("action")
|
11
|
+
clean_params.delete("controller")
|
12
|
+
|
13
|
+
request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
|
14
|
+
%>
|
15
|
+
|
16
|
+
<h2 style="margin-top: 30px">Request</h2>
|
17
|
+
<p><b>Parameters</b>: <pre><%=h request_dump %></pre></p>
|
18
|
+
|
19
|
+
<p><a href="#" onclick="document.getElementById('session_dump').style.display='block'; return false;">Show session dump</a></p>
|
20
|
+
<div id="session_dump" style="display:none"><pre><%= debug_hash request.session %></pre></div>
|
21
|
+
|
22
|
+
<p><a href="#" onclick="document.getElementById('env_dump').style.display='block'; return false;">Show env dump</a></p>
|
23
|
+
<div id="env_dump" style="display:none"><pre><%= debug_hash request.env.slice(*request.class::ENV_METHODS) %></pre></div>
|
24
|
+
|
25
|
+
|
26
|
+
<h2 style="margin-top: 30px">Response</h2>
|
27
|
+
<p><b>Headers</b>: <pre><%=h defined?(response) ? response.headers.inspect.gsub(',', ",\n") : 'None' %></pre></p>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<%
|
2
|
+
traces = [
|
3
|
+
["Application Trace", application_trace],
|
4
|
+
["Framework Trace", framework_trace],
|
5
|
+
["Full Trace", full_trace]
|
6
|
+
]
|
7
|
+
names = traces.collect {|name, trace| name}
|
8
|
+
%>
|
9
|
+
|
10
|
+
<p><code>Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %></code></p>
|
11
|
+
|
12
|
+
<div id="traces">
|
13
|
+
<% names.each do |name| %>
|
14
|
+
<%
|
15
|
+
show = "document.getElementById('#{name.gsub(/\s/, '-')}').style.display='block';"
|
16
|
+
hide = (names - [name]).collect {|hide_name| "document.getElementById('#{hide_name.gsub(/\s/, '-')}').style.display='none';"}
|
17
|
+
%>
|
18
|
+
<a href="#" onclick="<%= hide.join %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
|
19
|
+
<% end %>
|
20
|
+
|
21
|
+
<% traces.each do |name, trace| %>
|
22
|
+
<div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name == "Application Trace") ? 'block' : 'none' %>;">
|
23
|
+
<pre><code><%=h trace.join "\n" %></code></pre>
|
24
|
+
</div>
|
25
|
+
<% end %>
|
26
|
+
</div>
|