template_streaming 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +4 -0
- data/lib/template_streaming.rb +5 -4
- data/lib/template_streaming/error_recovery.rb +119 -0
- data/lib/template_streaming/version.rb +1 -1
- metadata +4 -3
data/CHANGELOG
CHANGED
data/lib/template_streaming.rb
CHANGED
@@ -232,7 +232,7 @@ module TemplateStreaming
|
|
232
232
|
|
233
233
|
def push(data)
|
234
234
|
if @bytes_to_threshold > 0
|
235
|
-
@push.call(data + padding)
|
235
|
+
@push.call(data + padding(@bytes_to_threshold - data.length))
|
236
236
|
@bytes_to_threshold = 0
|
237
237
|
else
|
238
238
|
@push.call(data)
|
@@ -241,9 +241,10 @@ module TemplateStreaming
|
|
241
241
|
|
242
242
|
private # -------------------------------------------------------
|
243
243
|
|
244
|
-
def padding
|
245
|
-
|
246
|
-
|
244
|
+
def padding(length)
|
245
|
+
return '' if length <= 0
|
246
|
+
content_length = [length - 7, 0].max
|
247
|
+
"<!--#{'+'*content_length}-->"
|
247
248
|
end
|
248
249
|
end
|
249
250
|
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module TemplateStreaming
|
2
|
+
module ErrorRecovery
|
3
|
+
ENV_EXCEPTIONS = 'template_streaming.error_recovery.exceptions'.freeze
|
4
|
+
ENV_SHOW_DETAILS = 'template_streaming.error_recovery.exceptions'.freeze
|
5
|
+
|
6
|
+
module Rendering
|
7
|
+
def uncaught_errors_html(errors)
|
8
|
+
content = errors.map do |error|
|
9
|
+
"<pre>#{uncaught_error_string(error)}</pre>"
|
10
|
+
end.join
|
11
|
+
<<-EOS.gsub(/^ *\|/, '')
|
12
|
+
|<div style='position: absolute; left: 0px; top: 0px; background-color: #fff; z-index: 999'>
|
13
|
+
| <h2 style="margin: 20px; font-weight: bold; border-bottom: 1px solid red">Rails Application Error</h2>
|
14
|
+
| #{content}
|
15
|
+
|</div>
|
16
|
+
EOS
|
17
|
+
end
|
18
|
+
|
19
|
+
def uncaught_error_string(error)
|
20
|
+
details = "#{error.class}: #{error.message}"
|
21
|
+
backtrace = error.backtrace.join("\n").gsub(/^/, ' ')
|
22
|
+
"<span style='font-weight: bold; margin: 20px'>#{h details}</span>\n#{h backtrace}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Controller
|
27
|
+
def self.included(base)
|
28
|
+
base.when_streaming_template :recover_from_errors
|
29
|
+
base.helper Helper
|
30
|
+
base.helper_method :recover_from_errors?
|
31
|
+
end
|
32
|
+
|
33
|
+
def recover_from_errors
|
34
|
+
@recover_from_errors = true
|
35
|
+
end
|
36
|
+
|
37
|
+
def recover_from_errors?
|
38
|
+
@recover_from_errors
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module Helper
|
43
|
+
def render(*)
|
44
|
+
begin
|
45
|
+
super
|
46
|
+
rescue ActionView::MissingTemplate => e
|
47
|
+
# ActionView uses this as a signal to try another template engine.
|
48
|
+
raise e
|
49
|
+
rescue Exception => e
|
50
|
+
raise e if !recover_from_errors?
|
51
|
+
if HoptoadNotifier.configuration[:api_key]
|
52
|
+
Rails.logger.error("#{e.class}: #{e.message}")
|
53
|
+
Rails.logger.error(e.backtrace.join("\n").gsub(/^/, ' '))
|
54
|
+
HoptoadNotifier.notify(e)
|
55
|
+
end
|
56
|
+
|
57
|
+
request.env[ENV_SHOW_DETAILS] = consider_all_requests_local || local_request?
|
58
|
+
|
59
|
+
# TODO: Find a way to make this suck less.
|
60
|
+
is_template_error = e.is_a?(ActionView::TemplateError)
|
61
|
+
if is_template_error && e.file_name =~ %r'\Aapp/views/prelayouts/'
|
62
|
+
# Error in prelayout - no head or body rendered yet.
|
63
|
+
head = "<head><title>Rails Application Error</title></head>"
|
64
|
+
body = "<body>#{uncaught_errors_html([e])}</body>"
|
65
|
+
"<!DOCTYPE html><html>#{head}#{body}</html>"
|
66
|
+
elsif is_template_error && e.file_name =~ %r'\Aapp/views/layouts/'
|
67
|
+
# Error in layout - unclosed head tag has been rendered.
|
68
|
+
head = "<title>Rails Application Error</title></head>"
|
69
|
+
body = "<body>#{uncaught_errors_html([e])}</body>"
|
70
|
+
"#{head}#{body}</html>"
|
71
|
+
else
|
72
|
+
# Body is being rendered - return nothing for this render
|
73
|
+
# call, and render the exception in the middleware.
|
74
|
+
request.env[ENV_EXCEPTIONS] << e
|
75
|
+
''
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
include Rendering
|
81
|
+
end
|
82
|
+
|
83
|
+
class Middleware
|
84
|
+
def initialize(app)
|
85
|
+
@app = app
|
86
|
+
end
|
87
|
+
|
88
|
+
def call(env)
|
89
|
+
@env = env
|
90
|
+
env[ENV_EXCEPTIONS] = []
|
91
|
+
status, headers, @body = *@app.call(env)
|
92
|
+
[status, headers, self]
|
93
|
+
end
|
94
|
+
|
95
|
+
def each
|
96
|
+
# Assume there are no faux occurrences of </body>.
|
97
|
+
@body.each do |chunk|
|
98
|
+
if render_errors? && (chunk =~ %r'</body\b')
|
99
|
+
errors = @env[ENV_EXCEPTIONS]
|
100
|
+
chunk.insert($~.begin(0), uncaught_errors_html(errors))
|
101
|
+
end
|
102
|
+
yield chunk
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
def render_errors?
|
109
|
+
!Rails.env.production? && !@env[ENV_EXCEPTIONS].empty?
|
110
|
+
end
|
111
|
+
|
112
|
+
include Rendering
|
113
|
+
end
|
114
|
+
|
115
|
+
ActionController::Base.send(:include, Controller)
|
116
|
+
ActionView::Base.send(:include, Helper)
|
117
|
+
ActionController::Dispatcher.middleware.insert_after('ActionController::Failsafe', Middleware)
|
118
|
+
end
|
119
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 10
|
9
|
+
version: 0.0.10
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- George Ogata
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-05-05 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -45,6 +45,7 @@ extra_rdoc_files:
|
|
45
45
|
files:
|
46
46
|
- doc/fast-profile.png
|
47
47
|
- doc/slow-profile.png
|
48
|
+
- lib/template_streaming/error_recovery.rb
|
48
49
|
- lib/template_streaming/version.rb
|
49
50
|
- lib/template_streaming.rb
|
50
51
|
- LICENSE
|