haveapi 0.19.3 → 0.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Rakefile +6 -6
  4. data/haveapi.gemspec +13 -13
  5. data/lib/haveapi/action.rb +140 -158
  6. data/lib/haveapi/action_state.rb +2 -6
  7. data/lib/haveapi/actions/default.rb +8 -10
  8. data/lib/haveapi/api.rb +2 -1
  9. data/lib/haveapi/authentication/base.rb +5 -8
  10. data/lib/haveapi/authentication/basic/provider.rb +4 -5
  11. data/lib/haveapi/authentication/chain.rb +19 -17
  12. data/lib/haveapi/authentication/oauth2/config.rb +12 -32
  13. data/lib/haveapi/authentication/oauth2/provider.rb +20 -30
  14. data/lib/haveapi/authentication/oauth2/revoke_endpoint.rb +1 -2
  15. data/lib/haveapi/authentication/token/action_config.rb +5 -3
  16. data/lib/haveapi/authentication/token/config.rb +5 -5
  17. data/lib/haveapi/authentication/token/provider.rb +33 -37
  18. data/lib/haveapi/authorization.rb +5 -4
  19. data/lib/haveapi/client_example.rb +11 -14
  20. data/lib/haveapi/client_examples/curl.rb +37 -37
  21. data/lib/haveapi/client_examples/fs_client.rb +29 -31
  22. data/lib/haveapi/client_examples/http.rb +35 -36
  23. data/lib/haveapi/client_examples/js_client.rb +62 -63
  24. data/lib/haveapi/client_examples/php_client.rb +77 -76
  25. data/lib/haveapi/client_examples/ruby_cli.rb +30 -30
  26. data/lib/haveapi/client_examples/ruby_client.rb +26 -26
  27. data/lib/haveapi/common.rb +3 -4
  28. data/lib/haveapi/context.rb +11 -10
  29. data/lib/haveapi/example.rb +9 -4
  30. data/lib/haveapi/example_list.rb +2 -2
  31. data/lib/haveapi/exceptions.rb +1 -1
  32. data/lib/haveapi/extensions/action_exceptions.rb +2 -2
  33. data/lib/haveapi/extensions/base.rb +1 -3
  34. data/lib/haveapi/extensions/exception_mailer.rb +260 -257
  35. data/lib/haveapi/hooks.rb +40 -39
  36. data/lib/haveapi/metadata.rb +1 -1
  37. data/lib/haveapi/model_adapter.rb +16 -27
  38. data/lib/haveapi/model_adapters/active_record.rb +59 -69
  39. data/lib/haveapi/output_formatter.rb +7 -7
  40. data/lib/haveapi/output_formatters/base.rb +2 -4
  41. data/lib/haveapi/parameters/resource.rb +7 -7
  42. data/lib/haveapi/parameters/typed.rb +6 -9
  43. data/lib/haveapi/params.rb +38 -45
  44. data/lib/haveapi/resource.rb +8 -8
  45. data/lib/haveapi/resources/action_state.rb +11 -19
  46. data/lib/haveapi/server.rb +105 -108
  47. data/lib/haveapi/spec/api_response.rb +1 -1
  48. data/lib/haveapi/spec/helpers.rb +1 -1
  49. data/lib/haveapi/spec/mock_action.rb +11 -10
  50. data/lib/haveapi/spec/spec_methods.rb +9 -8
  51. data/lib/haveapi/tasks/yard.rb +2 -2
  52. data/lib/haveapi/types.rb +5 -6
  53. data/lib/haveapi/validator.rb +6 -3
  54. data/lib/haveapi/validator_chain.rb +9 -8
  55. data/lib/haveapi/validators/acceptance.rb +6 -6
  56. data/lib/haveapi/validators/confirmation.rb +2 -3
  57. data/lib/haveapi/validators/exclusion.rb +1 -1
  58. data/lib/haveapi/validators/format.rb +1 -1
  59. data/lib/haveapi/validators/inclusion.rb +1 -1
  60. data/lib/haveapi/validators/length.rb +12 -11
  61. data/lib/haveapi/validators/numericality.rb +14 -13
  62. data/lib/haveapi/validators/presence.rb +4 -3
  63. data/lib/haveapi/version.rb +2 -2
  64. data/lib/haveapi.rb +2 -3
  65. data/spec/.rubocop.yml +4 -0
  66. data/spec/action/dsl_spec.rb +18 -18
  67. data/spec/authorization_spec.rb +8 -8
  68. data/spec/common_spec.rb +2 -1
  69. data/spec/documentation_spec.rb +2 -9
  70. data/spec/envelope_spec.rb +2 -2
  71. data/spec/hooks_spec.rb +12 -12
  72. data/spec/parameters/typed_spec.rb +6 -6
  73. data/spec/params_spec.rb +22 -24
  74. data/spec/resource_spec.rb +5 -7
  75. data/spec/spec_helper.rb +0 -1
  76. data/spec/validators/acceptance_spec.rb +1 -1
  77. data/spec/validators/confirmation_spec.rb +5 -5
  78. data/spec/validators/exclusion_spec.rb +3 -3
  79. data/spec/validators/format_spec.rb +2 -2
  80. data/spec/validators/inclusion_spec.rb +4 -4
  81. data/spec/validators/length_spec.rb +23 -23
  82. data/spec/validators/numericality_spec.rb +13 -13
  83. data/spec/validators/presence_spec.rb +3 -3
  84. metadata +49 -48
@@ -10,12 +10,15 @@ module HaveAPI::Extensions
10
10
  # functions are removed, since e-mail doesn't support it. HaveAPI-specific content
11
11
  # is added. Some helper methods are taken either from Sinatra or Rack.
12
12
  class ExceptionMailer < Base
13
+ Frame = Struct.new(:filename, :lineno, :function, :context_line)
14
+
13
15
  # @param opts [Hash] options
14
16
  # @option opts to [String] recipient address
15
17
  # @option opts from [String] sender address
16
18
  # @option opts subject [String] '%s' is replaced by the error message
17
19
  # @option opts smtp [Hash, falsy] smtp options, sendmail is used if not provided
18
20
  def initialize(opts)
21
+ super()
19
22
  @opts = opts
20
23
  end
21
24
 
@@ -33,28 +36,27 @@ module HaveAPI::Extensions
33
36
 
34
37
  def log(context, exception)
35
38
  req = context.request.request
36
- path = (req.script_name + req.path_info).squeeze("/")
39
+ path = (req.script_name + req.path_info).squeeze('/')
37
40
 
38
- frames = exception.backtrace.map { |line|
39
- frame = OpenStruct.new
41
+ frames = exception.backtrace.map do |line|
42
+ frame = Frame.new
40
43
 
41
- if line =~ /(.*?):(\d+)(:in `(.*)')?/
42
- frame.filename = $1
43
- frame.lineno = $2.to_i
44
- frame.function = $4
44
+ next unless line =~ /(.*?):(\d+)(:in `(.*)')?/
45
45
 
46
- begin
47
- lineno = frame.lineno-1
48
- lines = ::File.readlines(frame.filename)
49
- frame.context_line = lines[lineno].chomp
50
- rescue
51
- end
46
+ frame.filename = ::Regexp.last_match(1)
47
+ frame.lineno = ::Regexp.last_match(2).to_i
48
+ frame.function = ::Regexp.last_match(4)
52
49
 
53
- frame
54
- else
55
- nil
50
+ begin
51
+ lineno = frame.lineno - 1
52
+ lines = ::File.readlines(frame.filename)
53
+ frame.context_line = lines[lineno].chomp
54
+ rescue StandardError
55
+ # ignore
56
56
  end
57
- }.compact
57
+
58
+ frame
59
+ end.compact
58
60
 
59
61
  env = context.request.env
60
62
 
@@ -72,9 +74,9 @@ module HaveAPI::Extensions
72
74
  mail = ::Mail.new({
73
75
  from: @opts[:from],
74
76
  to: @opts[:to],
75
- subject: @opts[:subject] % [exception.to_s],
76
- body: body,
77
- content_type: 'text/html; charset=UTF-8',
77
+ subject: format(@opts[:subject], exception.to_s),
78
+ body:,
79
+ content_type: 'text/html; charset=UTF-8'
78
80
  })
79
81
 
80
82
  if @opts[:smtp]
@@ -89,15 +91,16 @@ module HaveAPI::Extensions
89
91
  end
90
92
 
91
93
  protected
94
+
92
95
  # From {Sinatra::ShowExceptions}
93
96
  def frame_class(frame)
94
- if frame.filename =~ /lib\/sinatra.*\.rb/
95
- "framework"
97
+ if frame.filename =~ %r{lib/sinatra.*\.rb}
98
+ 'framework'
96
99
  elsif (defined?(Gem) && frame.filename.include?(Gem.dir)) ||
97
- frame.filename =~ /\/bin\/(\w+)$/
98
- "system"
100
+ frame.filename =~ %r{/bin/(\w+)$}
101
+ 'system'
99
102
  else
100
- "app"
103
+ 'app'
101
104
  end
102
105
  end
103
106
 
@@ -111,237 +114,237 @@ module HaveAPI::Extensions
111
114
  end
112
115
  end
113
116
 
114
- TEMPLATE = ERB.new(<<END
115
- <!DOCTYPE html>
116
- <html>
117
- <head>
118
- <meta charset="utf-8">
119
- <title><%=h exception.class %> at <%=h path %></title>
120
- <style type="text/css">
121
- * {margin: 0; padding: 0; border: 0; outline: 0;}
122
- div.clear {clear: both;}
123
- body {background: #EEEEEE; margin: 0; padding: 0;
124
- font-family: 'Lucida Grande', 'Lucida Sans Unicode',
125
- 'Garuda';}
126
- code {font-family: 'Lucida Console', monospace;
127
- font-size: 12px;}
128
- li {height: 18px;}
129
- ul {list-style: none; margin: 0; padding: 0;}
130
- ol:hover {cursor: pointer;}
131
- ol li {white-space: pre;}
132
- #explanation {font-size: 12px; color: #666666;
133
- margin: 20px 0 0 100px;}
134
- /* WRAP */
135
- #wrap {width: 1000px; background: #FFFFFF; margin: 0 auto;
136
- padding: 30px 5px 20px 5px;
137
- border-left: 1px solid #DDDDDD;
138
- border-right: 1px solid #DDDDDD;}
139
- /* HEADER */
140
- #header {margin: 0 auto 25px auto;}
141
- #header #summary {margin: 12px 0 0 20px;
142
- font-family: 'Lucida Grande', 'Lucida Sans Unicode';}
143
- h1 {margin: 0; font-size: 36px; color: #981919;}
144
- h2 {margin: 0; font-size: 22px; color: #333333;}
145
- #header ul {margin: 0; font-size: 12px; color: #666666;}
146
- #header ul li strong{color: #444444;}
147
- #header ul li {display: inline; padding: 0 10px;}
148
- #header ul li.first {padding-left: 0;}
149
- #header ul li.last {border: 0; padding-right: 0;}
150
- /* BODY */
151
- #backtrace,
152
- #get,
153
- #post,
154
- #cookies,
155
- #rack, #context {width: 980px; margin: 0 auto 10px auto;}
156
- p#nav {float: right; font-size: 14px;}
157
- /* BACKTRACE */
158
- h3 {float: left; width: 100px; margin-bottom: 10px;
159
- color: #981919; font-size: 14px; font-weight: bold;}
160
- #nav a {color: #666666; text-decoration: none; padding: 0 5px;}
161
- #backtrace li.frame-info {background: #f7f7f7; padding-left: 10px;
162
- font-size: 12px; color: #333333;}
163
- #backtrace ul {list-style-position: outside; border: 1px solid #E9E9E9;
164
- border-bottom: 0;}
165
- #backtrace ol {width: 920px; margin-left: 50px;
166
- font: 10px 'Lucida Console', monospace; color: #666666;}
167
- #backtrace ol li {border: 0; border-left: 1px solid #E9E9E9;
168
- padding: 2px 0;}
169
- #backtrace ol code {font-size: 10px; color: #555555; padding-left: 5px;}
170
- #backtrace-ul li {border-bottom: 1px solid #E9E9E9; height: auto;
171
- padding: 3px 0;}
172
- #backtrace-ul .code {padding: 6px 0 4px 0;}
173
- /* REQUEST DATA */
174
- p.no-data {padding-top: 2px; font-size: 12px; color: #666666;}
175
- table.req {width: 980px; text-align: left; font-size: 12px;
176
- color: #666666; padding: 0; border-spacing: 0;
177
- border: 1px solid #EEEEEE; border-bottom: 0;
178
- border-left: 0;
179
- clear:both}
180
- table.req tr th {padding: 2px 10px; font-weight: bold;
181
- background: #F7F7F7; border-bottom: 1px solid #EEEEEE;
182
- border-left: 1px solid #EEEEEE;}
183
- table.req tr td {padding: 2px 20px 2px 10px;
184
- border-bottom: 1px solid #EEEEEE;
185
- border-left: 1px solid #EEEEEE;}
186
- /* HIDE PRE/POST CODE AT START */
187
- .pre-context,
188
- .post-context {display: none;}
189
- table td.code {width:750px}
190
- table td.code div {width:750px;overflow:hidden}
191
- </style>
192
- </head>
193
- <body>
194
- <div id="wrap">
195
- <div id="header">
196
- <div id="summary">
197
- <h1><strong><%=h exception.class %></strong> at <strong><%=h path %>
198
- </strong></h1>
199
- <h2><%=h exception.message %></h2>
200
- <ul>
201
- <li class="first"><strong>file:</strong> <code>
202
- <%=h frames.first.filename.split("/").last %></code></li>
203
- <li><strong>location:</strong> <code><%=h frames.first.function %>
204
- </code></li>
205
- <li class="last"><strong>line:
206
- </strong> <%=h frames.first.lineno %></li>
207
- </ul>
208
- </div>
209
- <div class="clear"></div>
210
- </div>
211
- <div id="context">
212
- <h3>Context</h3>
213
- <table class="req">
214
- <tr>
215
- <th>API version</th>
216
- <td><%=h context.version %></td>
217
- </tr>
218
- <tr>
219
- <th>Action</th>
220
- <td><%= h(context.action && context.action.to_s) %></td>
221
- </tr>
222
- <tr>
223
- <th>Arguments</th>
224
- <td><%=h context.args %></td>
225
- </tr>
226
- <tr>
227
- <th>Parameters</th>
228
- <td><%=h context.params %></td>
229
- </tr>
230
- <tr>
231
- <th>User</th>
232
- <td><%=h user %></td>
233
- </tr>
234
- </table>
235
- <div class="clear"></div>
236
- </div>
237
- <div id="backtrace">
238
- <h3>BACKTRACE</h3>
239
- <p id="nav"><strong>JUMP TO:</strong>
240
- <a href="#get-info">GET</a>
241
- <a href="#post-info">POST</a>
242
- <a href="#cookie-info">COOKIES</a>
243
- <a href="#env-info">ENV</a>
244
- </p>
245
- <div class="clear"></div>
246
- <ul id="backtrace-ul">
247
- <% frames.each do |frame| %>
248
- <li class="frame-info <%= frame_class(frame) %>">
249
- <code><%=h frame.filename %></code> in
250
- <code><strong><%=h frame.function %></strong></code>
251
- </li>
252
- <li class="code <%= frame_class(frame) %>">
253
- <ol start="<%= frame.lineno %>" class="context">
254
- <li class="context-line">
255
- <code><%=h frame.context_line %></code>
256
- </li>
257
- </ol>
258
- <div class="clear"></div>
259
- </li>
260
- <% end %>
261
- </ul>
262
- </div> <!-- /BACKTRACE -->
263
- <div id="get">
264
- <h3 id="get-info">GET</h3>
265
- <% if req.GET and not req.GET.empty? %>
266
- <table class="req">
267
- <tr>
268
- <th>Variable</th>
269
- <th>Value</th>
270
- </tr>
271
- <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %>
272
- <tr>
273
- <td><%=h key %></td>
274
- <td class="code"><div><%=h val.inspect %></div></td>
275
- </tr>
276
- <% } %>
277
- </table>
278
- <% else %>
279
- <p class="no-data">No GET data.</p>
280
- <% end %>
281
- <div class="clear"></div>
282
- </div> <!-- /GET -->
283
- <div id="post">
284
- <h3 id="post-info">POST</h3>
285
- <% if req.POST and not req.POST.empty? %>
286
- <table class="req">
287
- <tr>
288
- <th>Variable</th>
289
- <th>Value</th>
290
- </tr>
291
- <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %>
292
- <tr>
293
- <td><%=h key %></td>
294
- <td class="code"><div><%=h val.inspect %></div></td>
295
- </tr>
296
- <% } %>
297
- </table>
298
- <% else %>
299
- <p class="no-data">No POST data.</p>
300
- <% end %>
301
- <div class="clear"></div>
302
- </div> <!-- /POST -->
303
- <div id="cookies">
304
- <h3 id="cookie-info">COOKIES</h3>
305
- <% unless req.cookies.empty? %>
306
- <table class="req">
307
- <tr>
308
- <th>Variable</th>
309
- <th>Value</th>
310
- </tr>
311
- <% req.cookies.each { |key, val| %>
312
- <tr>
313
- <td><%=h key %></td>
314
- <td class="code"><div><%=h val.inspect %></div></td>
315
- </tr>
316
- <% } %>
317
- </table>
318
- <% else %>
319
- <p class="no-data">No cookie data.</p>
320
- <% end %>
321
- <div class="clear"></div>
322
- </div> <!-- /COOKIES -->
323
- <div id="rack">
324
- <h3 id="env-info">Rack ENV</h3>
325
- <table class="req">
326
- <tr>
327
- <th>Variable</th>
328
- <th>Value</th>
329
- </tr>
330
- <% env.sort_by { |k, v| k.to_s }.each { |key, val| %>
331
- <tr>
332
- <td><%=h key %></td>
333
- <td class="code"><div><%=h val %></div></td>
334
- </tr>
335
- <% } %>
336
- </table>
337
- <div class="clear"></div>
338
- </div> <!-- /RACK ENV -->
339
- <p id="explanation">You're seeing this error because you have
340
- enabled HaveAPI Extension <code>HaveAPI::Extensions::ExceptionMailer</code>.</p>
341
- </div> <!-- /WRAP -->
342
- </body>
343
- </html>
344
- END
345
- )
117
+ TEMPLATE = ERB.new(<<~END
118
+ <!DOCTYPE html>
119
+ <html>
120
+ <head>
121
+ <meta charset="utf-8">
122
+ <title><%=h exception.class %> at <%=h path %></title>
123
+ <style type="text/css">
124
+ * {margin: 0; padding: 0; border: 0; outline: 0;}
125
+ div.clear {clear: both;}
126
+ body {background: #EEEEEE; margin: 0; padding: 0;
127
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode',
128
+ 'Garuda';}
129
+ code {font-family: 'Lucida Console', monospace;
130
+ font-size: 12px;}
131
+ li {height: 18px;}
132
+ ul {list-style: none; margin: 0; padding: 0;}
133
+ ol:hover {cursor: pointer;}
134
+ ol li {white-space: pre;}
135
+ #explanation {font-size: 12px; color: #666666;
136
+ margin: 20px 0 0 100px;}
137
+ /* WRAP */
138
+ #wrap {width: 1000px; background: #FFFFFF; margin: 0 auto;
139
+ padding: 30px 5px 20px 5px;
140
+ border-left: 1px solid #DDDDDD;
141
+ border-right: 1px solid #DDDDDD;}
142
+ /* HEADER */
143
+ #header {margin: 0 auto 25px auto;}
144
+ #header #summary {margin: 12px 0 0 20px;
145
+ font-family: 'Lucida Grande', 'Lucida Sans Unicode';}
146
+ h1 {margin: 0; font-size: 36px; color: #981919;}
147
+ h2 {margin: 0; font-size: 22px; color: #333333;}
148
+ #header ul {margin: 0; font-size: 12px; color: #666666;}
149
+ #header ul li strong{color: #444444;}
150
+ #header ul li {display: inline; padding: 0 10px;}
151
+ #header ul li.first {padding-left: 0;}
152
+ #header ul li.last {border: 0; padding-right: 0;}
153
+ /* BODY */
154
+ #backtrace,
155
+ #get,
156
+ #post,
157
+ #cookies,
158
+ #rack, #context {width: 980px; margin: 0 auto 10px auto;}
159
+ p#nav {float: right; font-size: 14px;}
160
+ /* BACKTRACE */
161
+ h3 {float: left; width: 100px; margin-bottom: 10px;
162
+ color: #981919; font-size: 14px; font-weight: bold;}
163
+ #nav a {color: #666666; text-decoration: none; padding: 0 5px;}
164
+ #backtrace li.frame-info {background: #f7f7f7; padding-left: 10px;
165
+ font-size: 12px; color: #333333;}
166
+ #backtrace ul {list-style-position: outside; border: 1px solid #E9E9E9;
167
+ border-bottom: 0;}
168
+ #backtrace ol {width: 920px; margin-left: 50px;
169
+ font: 10px 'Lucida Console', monospace; color: #666666;}
170
+ #backtrace ol li {border: 0; border-left: 1px solid #E9E9E9;
171
+ padding: 2px 0;}
172
+ #backtrace ol code {font-size: 10px; color: #555555; padding-left: 5px;}
173
+ #backtrace-ul li {border-bottom: 1px solid #E9E9E9; height: auto;
174
+ padding: 3px 0;}
175
+ #backtrace-ul .code {padding: 6px 0 4px 0;}
176
+ /* REQUEST DATA */
177
+ p.no-data {padding-top: 2px; font-size: 12px; color: #666666;}
178
+ table.req {width: 980px; text-align: left; font-size: 12px;
179
+ color: #666666; padding: 0; border-spacing: 0;
180
+ border: 1px solid #EEEEEE; border-bottom: 0;
181
+ border-left: 0;
182
+ clear:both}
183
+ table.req tr th {padding: 2px 10px; font-weight: bold;
184
+ background: #F7F7F7; border-bottom: 1px solid #EEEEEE;
185
+ border-left: 1px solid #EEEEEE;}
186
+ table.req tr td {padding: 2px 20px 2px 10px;
187
+ border-bottom: 1px solid #EEEEEE;
188
+ border-left: 1px solid #EEEEEE;}
189
+ /* HIDE PRE/POST CODE AT START */
190
+ .pre-context,
191
+ .post-context {display: none;}
192
+ table td.code {width:750px}
193
+ table td.code div {width:750px;overflow:hidden}
194
+ </style>
195
+ </head>
196
+ <body>
197
+ <div id="wrap">
198
+ <div id="header">
199
+ <div id="summary">
200
+ <h1><strong><%=h exception.class %></strong> at <strong><%=h path %>
201
+ </strong></h1>
202
+ <h2><%=h exception.message %></h2>
203
+ <ul>
204
+ <li class="first"><strong>file:</strong> <code>
205
+ <%=h frames.first.filename.split("/").last %></code></li>
206
+ <li><strong>location:</strong> <code><%=h frames.first.function %>
207
+ </code></li>
208
+ <li class="last"><strong>line:
209
+ </strong> <%=h frames.first.lineno %></li>
210
+ </ul>
211
+ </div>
212
+ <div class="clear"></div>
213
+ </div>
214
+ <div id="context">
215
+ <h3>Context</h3>
216
+ <table class="req">
217
+ <tr>
218
+ <th>API version</th>
219
+ <td><%=h context.version %></td>
220
+ </tr>
221
+ <tr>
222
+ <th>Action</th>
223
+ <td><%= h(context.action && context.action.to_s) %></td>
224
+ </tr>
225
+ <tr>
226
+ <th>Arguments</th>
227
+ <td><%=h context.args %></td>
228
+ </tr>
229
+ <tr>
230
+ <th>Parameters</th>
231
+ <td><%=h context.params %></td>
232
+ </tr>
233
+ <tr>
234
+ <th>User</th>
235
+ <td><%=h user %></td>
236
+ </tr>
237
+ </table>
238
+ <div class="clear"></div>
239
+ </div>
240
+ <div id="backtrace">
241
+ <h3>BACKTRACE</h3>
242
+ <p id="nav"><strong>JUMP TO:</strong>
243
+ <a href="#get-info">GET</a>
244
+ <a href="#post-info">POST</a>
245
+ <a href="#cookie-info">COOKIES</a>
246
+ <a href="#env-info">ENV</a>
247
+ </p>
248
+ <div class="clear"></div>
249
+ <ul id="backtrace-ul">
250
+ <% frames.each do |frame| %>
251
+ <li class="frame-info <%= frame_class(frame) %>">
252
+ <code><%=h frame.filename %></code> in
253
+ <code><strong><%=h frame.function %></strong></code>
254
+ </li>
255
+ <li class="code <%= frame_class(frame) %>">
256
+ <ol start="<%= frame.lineno %>" class="context">
257
+ <li class="context-line">
258
+ <code><%=h frame.context_line %></code>
259
+ </li>
260
+ </ol>
261
+ <div class="clear"></div>
262
+ </li>
263
+ <% end %>
264
+ </ul>
265
+ </div> <!-- /BACKTRACE -->
266
+ <div id="get">
267
+ <h3 id="get-info">GET</h3>
268
+ <% if req.GET and not req.GET.empty? %>
269
+ <table class="req">
270
+ <tr>
271
+ <th>Variable</th>
272
+ <th>Value</th>
273
+ </tr>
274
+ <% req.GET.sort_by { |k, v| k.to_s }.each { |key, val| %>
275
+ <tr>
276
+ <td><%=h key %></td>
277
+ <td class="code"><div><%=h val.inspect %></div></td>
278
+ </tr>
279
+ <% } %>
280
+ </table>
281
+ <% else %>
282
+ <p class="no-data">No GET data.</p>
283
+ <% end %>
284
+ <div class="clear"></div>
285
+ </div> <!-- /GET -->
286
+ <div id="post">
287
+ <h3 id="post-info">POST</h3>
288
+ <% if req.POST and not req.POST.empty? %>
289
+ <table class="req">
290
+ <tr>
291
+ <th>Variable</th>
292
+ <th>Value</th>
293
+ </tr>
294
+ <% req.POST.sort_by { |k, v| k.to_s }.each { |key, val| %>
295
+ <tr>
296
+ <td><%=h key %></td>
297
+ <td class="code"><div><%=h val.inspect %></div></td>
298
+ </tr>
299
+ <% } %>
300
+ </table>
301
+ <% else %>
302
+ <p class="no-data">No POST data.</p>
303
+ <% end %>
304
+ <div class="clear"></div>
305
+ </div> <!-- /POST -->
306
+ <div id="cookies">
307
+ <h3 id="cookie-info">COOKIES</h3>
308
+ <% unless req.cookies.empty? %>
309
+ <table class="req">
310
+ <tr>
311
+ <th>Variable</th>
312
+ <th>Value</th>
313
+ </tr>
314
+ <% req.cookies.each { |key, val| %>
315
+ <tr>
316
+ <td><%=h key %></td>
317
+ <td class="code"><div><%=h val.inspect %></div></td>
318
+ </tr>
319
+ <% } %>
320
+ </table>
321
+ <% else %>
322
+ <p class="no-data">No cookie data.</p>
323
+ <% end %>
324
+ <div class="clear"></div>
325
+ </div> <!-- /COOKIES -->
326
+ <div id="rack">
327
+ <h3 id="env-info">Rack ENV</h3>
328
+ <table class="req">
329
+ <tr>
330
+ <th>Variable</th>
331
+ <th>Value</th>
332
+ </tr>
333
+ <% env.sort_by { |k, v| k.to_s }.each { |key, val| %>
334
+ <tr>
335
+ <td><%=h key %></td>
336
+ <td class="code"><div><%=h val %></div></td>
337
+ </tr>
338
+ <% } %>
339
+ </table>
340
+ <div class="clear"></div>
341
+ </div> <!-- /RACK ENV -->
342
+ <p id="explanation">You're seeing this error because you have
343
+ enabled HaveAPI Extension <code>HaveAPI::Extensions::ExceptionMailer</code>.</p>
344
+ </div> <!-- /WRAP -->
345
+ </body>
346
+ </html>
347
+ END
348
+ )
346
349
  end
347
350
  end