goliath 0.9.1 → 0.9.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of goliath might be problematic. Click here for more details.

Files changed (94) hide show
  1. data/.gitignore +1 -0
  2. data/HISTORY +50 -0
  3. data/README.md +2 -0
  4. data/examples/activerecord/srv.rb +1 -3
  5. data/examples/async_aroundware_demo.rb +81 -0
  6. data/examples/async_upload.rb +1 -2
  7. data/examples/auth_and_rate_limit.rb +143 -0
  8. data/examples/chunked_streaming.rb +37 -0
  9. data/examples/conf_test.rb +1 -3
  10. data/examples/config/auth_and_rate_limit.rb +30 -0
  11. data/examples/config/template.rb +8 -0
  12. data/examples/content_stream.rb +1 -3
  13. data/examples/echo.rb +8 -6
  14. data/examples/env_use_statements.rb +17 -0
  15. data/examples/gziped.rb +1 -3
  16. data/examples/public/stylesheets/style.css +296 -0
  17. data/examples/rack_routes.rb +65 -3
  18. data/examples/rasterize/rasterize.js +15 -0
  19. data/examples/rasterize/rasterize.rb +36 -0
  20. data/examples/rasterize/rasterize_and_shorten.rb +37 -0
  21. data/examples/stream.rb +2 -2
  22. data/examples/template.rb +48 -0
  23. data/examples/test_rig.rb +125 -0
  24. data/examples/valid.rb +4 -2
  25. data/examples/views/debug.haml +4 -0
  26. data/examples/views/joke.markdown +13 -0
  27. data/examples/views/layout.erb +12 -0
  28. data/examples/views/layout.haml +39 -0
  29. data/examples/views/root.haml +28 -0
  30. data/goliath.gemspec +10 -3
  31. data/lib/goliath.rb +0 -36
  32. data/lib/goliath/api.rb +137 -26
  33. data/lib/goliath/application.rb +71 -21
  34. data/lib/goliath/connection.rb +4 -2
  35. data/lib/goliath/constants.rb +1 -0
  36. data/lib/goliath/env.rb +40 -1
  37. data/lib/goliath/goliath.rb +30 -15
  38. data/lib/goliath/headers.rb +2 -2
  39. data/lib/goliath/plugins/latency.rb +8 -2
  40. data/lib/goliath/rack.rb +18 -0
  41. data/lib/goliath/rack/async_aroundware.rb +56 -0
  42. data/lib/goliath/rack/async_middleware.rb +93 -0
  43. data/lib/goliath/rack/builder.rb +42 -0
  44. data/lib/goliath/rack/default_response_format.rb +3 -15
  45. data/lib/goliath/rack/formatters.rb +11 -0
  46. data/lib/goliath/rack/formatters/html.rb +2 -18
  47. data/lib/goliath/rack/formatters/json.rb +2 -17
  48. data/lib/goliath/rack/formatters/plist.rb +32 -0
  49. data/lib/goliath/rack/formatters/xml.rb +23 -31
  50. data/lib/goliath/rack/formatters/yaml.rb +27 -0
  51. data/lib/goliath/rack/jsonp.rb +1 -13
  52. data/lib/goliath/rack/params.rb +55 -27
  53. data/lib/goliath/rack/render.rb +13 -22
  54. data/lib/goliath/rack/templates.rb +357 -0
  55. data/lib/goliath/rack/tracer.rb +11 -12
  56. data/lib/goliath/rack/validation.rb +12 -0
  57. data/lib/goliath/rack/validation/default_params.rb +0 -2
  58. data/lib/goliath/rack/validation/numeric_range.rb +11 -2
  59. data/lib/goliath/rack/validation/request_method.rb +3 -2
  60. data/lib/goliath/rack/validation/required_param.rb +13 -11
  61. data/lib/goliath/rack/validation/required_value.rb +11 -15
  62. data/lib/goliath/rack/validator.rb +51 -0
  63. data/lib/goliath/request.rb +34 -20
  64. data/lib/goliath/response.rb +3 -2
  65. data/lib/goliath/runner.rb +5 -11
  66. data/lib/goliath/server.rb +2 -1
  67. data/lib/goliath/synchrony/mongo_receiver.rb +64 -0
  68. data/lib/goliath/synchrony/response_receiver.rb +64 -0
  69. data/lib/goliath/test_helper.rb +39 -21
  70. data/lib/goliath/validation.rb +2 -0
  71. data/lib/goliath/{rack/validation_error.rb → validation/error.rb} +0 -16
  72. data/lib/goliath/validation/standard_http_errors.rb +31 -0
  73. data/lib/goliath/version.rb +1 -1
  74. data/spec/integration/http_log_spec.rb +16 -16
  75. data/spec/integration/rack_routes_spec.rb +144 -0
  76. data/spec/integration/reloader_spec.rb +4 -4
  77. data/spec/integration/template_spec.rb +54 -0
  78. data/spec/integration/trace_spec.rb +23 -0
  79. data/spec/integration/valid_spec.rb +21 -0
  80. data/spec/spec_helper.rb +3 -1
  81. data/spec/unit/api_spec.rb +30 -0
  82. data/spec/unit/rack/builder_spec.rb +40 -0
  83. data/spec/unit/rack/formatters/plist_spec.rb +51 -0
  84. data/spec/unit/rack/formatters/yaml_spec.rb +53 -0
  85. data/spec/unit/rack/params_spec.rb +22 -0
  86. data/spec/unit/rack/render_spec.rb +10 -5
  87. data/spec/unit/rack/validation/numeric_range_spec.rb +8 -1
  88. data/spec/unit/rack/validation/request_method_spec.rb +8 -8
  89. data/spec/unit/rack/validation/required_param_spec.rb +19 -15
  90. data/spec/unit/rack/validation/required_value_spec.rb +10 -13
  91. data/spec/unit/server_spec.rb +4 -4
  92. data/spec/unit/validation/standard_http_errors_spec.rb +21 -0
  93. metadata +177 -35
  94. data/spec/unit/rack/validation_error_spec.rb +0 -40
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ $:<< '../lib' << 'lib'
3
+
4
+ require 'goliath'
5
+ require 'yajl'
6
+
7
+ class EnvUseStatements < Goliath::API
8
+ if Goliath.dev?
9
+ use Goliath::Rack::Render, 'json'
10
+ elsif Goliath.prod?
11
+ use Goliath::Rack::Render, 'xml'
12
+ end
13
+
14
+ def response(env)
15
+ [200, {}, {'Test' => 'Response'}]
16
+ end
17
+ end
@@ -27,9 +27,7 @@ class Gziped < Goliath::API
27
27
  end
28
28
 
29
29
  use Goliath::Rack::Params # parse & merge query and body parameters
30
- use Goliath::Rack::Formatters::JSON # JSON output formatter
31
- use Goliath::Rack::Render # auto-negotiate response format
32
- use Goliath::Rack::ValidationError # catch and render validation errors
30
+ use Goliath::Rack::Render, 'json' # auto-negotiate response format
33
31
 
34
32
  use Goliath::Rack::Validation::RequestMethod, %w(GET) # allow GET requests only
35
33
  use Goliath::Rack::Validation::RequiredParam, {:key => 'echo'} # must provide ?echo= query or body param
@@ -0,0 +1,296 @@
1
+
2
+ /* ==== Scroll down to find where to put your styles :) ==== */
3
+
4
+ /* HTML5 - Boilerplate */
5
+
6
+ html, body, div, span, object, iframe,
7
+ h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8
+ abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
9
+ small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
10
+ fieldset, form, label, legend,
11
+ table, caption, tbody, tfoot, thead, tr, th, td,
12
+ article, aside, canvas, details, figcaption, figure,
13
+ footer, header, hgroup, menu, nav, section, summary,
14
+ time, mark, audio, video {
15
+ margin: 0;
16
+ padding: 0;
17
+ border: 0;
18
+ font-size: 100%;
19
+ font: inherit;
20
+ vertical-align: baseline;
21
+ }
22
+
23
+ article, aside, details, figcaption, figure,
24
+ footer, header, hgroup, menu, nav, section {
25
+ display: block;
26
+ }
27
+
28
+ blockquote, q { quotes: none; }
29
+ blockquote:before, blockquote:after,
30
+ q:before, q:after { content: ''; content: none; }
31
+ ins { background-color: #ff9; color: #000; text-decoration: none; }
32
+ mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
33
+ del { text-decoration: line-through; }
34
+ abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; }
35
+ table { border-collapse: collapse; border-spacing: 0; }
36
+ hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; }
37
+ input, select { vertical-align: middle; }
38
+
39
+ body { font:13px/1.231 sans-serif; *font-size:small; }
40
+ select, input, textarea, button { font:99% sans-serif; }
41
+ pre, code, kbd, samp { font-family: monospace, sans-serif; }
42
+
43
+ html { overflow-y: scroll; }
44
+ a:hover, a:active { outline: none; }
45
+ ul, ol { margin-left: 2em; }
46
+ ol { list-style-type: decimal; }
47
+ nav ul, nav li { margin: 0; list-style:none; list-style-image: none; }
48
+ small { font-size: 85%; }
49
+ strong, th { font-weight: bold; }
50
+ td { vertical-align: top; }
51
+
52
+ sub, sup { font-size: 75%; line-height: 0; position: relative; }
53
+ sup { top: -0.5em; }
54
+ sub { bottom: -0.25em; }
55
+
56
+ pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; padding: 15px; }
57
+ textarea { overflow: auto; }
58
+ .ie6 legend, .ie7 legend { margin-left: -7px; }
59
+ input[type="radio"] { vertical-align: text-bottom; }
60
+ input[type="checkbox"] { vertical-align: bottom; }
61
+ .ie7 input[type="checkbox"] { vertical-align: baseline; }
62
+ .ie6 input { vertical-align: text-bottom; }
63
+ label, input[type="button"], input[type="submit"], input[type="image"], button { cursor: pointer; }
64
+ button, input, select, textarea { margin: 0; }
65
+ input:valid, textarea:valid { }
66
+ input:invalid, textarea:invalid { border-radius: 1px; -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red; box-shadow: 0px 0px 5px red; }
67
+ .no-boxshadow input:invalid, .no-boxshadow textarea:invalid { background-color: #f0dddd; }
68
+
69
+ ::-moz-selection{ background: #eFdEe9; color:#fff; text-shadow: none; }
70
+ ::selection { background:#eFdEe9; color:#fff; text-shadow: none; }
71
+ a:link { -webkit-tap-highlight-color: #eFdEe9; }
72
+
73
+ button { width: auto; overflow: visible; }
74
+ .ie7 img { -ms-interpolation-mode: bicubic; }
75
+
76
+ body, select, input, textarea { color: #444; }
77
+ h1, h2, h3, h4, h5, h6 { font-weight: bold; }
78
+ a, a:active, a:visited { color: #607890; }
79
+ a:hover { color: #036; }
80
+
81
+ /*
82
+ // ========================================== \\
83
+ || ||
84
+ || Your styles ! ||
85
+ || ||
86
+ \\ ========================================== //
87
+ */
88
+
89
+
90
+ body{
91
+ font-family:Helvetica, Helvetica Neue, Arial, sans-serif;
92
+ }
93
+
94
+ .wrapper{
95
+ margin:auto;
96
+ width:960px;
97
+ }
98
+
99
+ #logo {
100
+ float: left;
101
+ margin-top: 10px;
102
+ margin-right: 20px;
103
+ }
104
+
105
+ #header-container{
106
+ background-color:#e4edf6;
107
+ height:80px;
108
+ border-bottom:20px solid #f1e5d9;
109
+ margin-bottom:50px;
110
+ }
111
+
112
+ #title{
113
+ font-weight:normal;
114
+ font-size: 50px;
115
+ color:white;
116
+ padding: 15px 5px 10px 0;
117
+ float:left;
118
+ clear: none;
119
+ }
120
+ #title a{ text-decoration: none }
121
+
122
+ h1 { font-size: 185%; padding-top: 14px; padding-bottom: 5px; }
123
+ h2 { font-size: 154%; padding-top: 20px; padding-bottom: 4px; }
124
+ h3 { font-size: 139%; padding-top: 6px; padding-bottom: 4px; }
125
+ h4 { font-size: 116%; padding-top: 4px; padding-bottom: 2px; }
126
+
127
+ nav{
128
+ float:right;
129
+ margin-top:10px;
130
+ }
131
+
132
+ nav ul, nav ul li{
133
+ display:inline;
134
+ }
135
+
136
+ nav a, nav a:visited, nav a:active{
137
+ padding:10px 20px;
138
+ color:#666;
139
+ text-decoration:none;
140
+ background-color:#d4dde6;
141
+ }
142
+
143
+ aside{
144
+ color:#444;
145
+ padding:20px;
146
+ float:right;
147
+ height:500px;
148
+ width:200px;
149
+ background-color:#e4edf6;
150
+ border-bottom:20px solid #e44d26;
151
+ margin-bottom:50px;
152
+ }
153
+
154
+ #main {
155
+ min-height: 550px;
156
+ }
157
+
158
+ #main p{
159
+ font:16px/26px Helvetica, Helvetica Neue, Arial;
160
+ width:620px;
161
+ text-shadow:none;
162
+ }
163
+
164
+ #main header h2{
165
+ padding-bottom:30px;
166
+ }
167
+
168
+ article header{
169
+ margin-bottom:50px;
170
+ padding-bottom:30px;
171
+ width:700px;
172
+ }
173
+
174
+ #footer-container{
175
+ background-color:#e4edf6;
176
+ height:240px;
177
+ border-top:40px solid #e4edf6;
178
+ margin-top:50px;
179
+ }
180
+
181
+ #footer-container footer{
182
+ color:#888;
183
+ text-align:right;
184
+ }
185
+ #footer-container footer a, #footer-container footer a:active, #footer-container footer a:visited { color: #88a; }
186
+
187
+ .info{
188
+ position:absolute;
189
+ top:5px;
190
+ background-color:white;
191
+ padding:10px;
192
+ }
193
+
194
+ #jquery-test{
195
+ top:45px;
196
+ }
197
+
198
+ .ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; }
199
+ .hidden { display: none; visibility: hidden; }
200
+ .visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
201
+ .visuallyhidden.focusable:active,
202
+ .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; }
203
+ .invisible { visibility: hidden; }
204
+ .clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; }
205
+ .clearfix:after { clear: both; }
206
+ .clearfix { zoom: 1; }
207
+
208
+
209
+ .meter {
210
+ margin: 3em;
211
+ background-color: #eee;
212
+ padding: 2em;
213
+ font-size: 154%;
214
+ }
215
+
216
+
217
+ /* Nice table styling for greater dashboard justice */
218
+ table {
219
+ text-align: left;
220
+ }
221
+ table th, table td {
222
+ text-align: left;
223
+ }
224
+ table th {
225
+ font-weight: bold;
226
+ }
227
+ table th, table td {
228
+ min-width: 30px;
229
+ padding: 4px 0 4px 10px;
230
+ }
231
+ table th:first-child, table td:first-child {
232
+ padding-left: 0;
233
+ }
234
+ table tbody tr:hover {
235
+ background-color: #e8f0ff;
236
+ }
237
+
238
+ table.full {
239
+ width: 960px;
240
+ }
241
+ table.horizontal th {
242
+ border-bottom: 2px solid #6678b1;
243
+ }
244
+ table.horizontal th, table.horizontal td {
245
+ min-width: 70px;
246
+ }
247
+
248
+ table.vertical {
249
+ margin: 16px 0;
250
+ }
251
+ table.vertical th {
252
+ width: 180px;
253
+ padding: 4px 5px 3px 5px;
254
+ border-bottom: 1px solid #51ded8;
255
+ }
256
+ table.vertical td {
257
+ padding: 4px 0 3px 10px;
258
+ border-bottom: 1px solid #f1eee8;
259
+ }
260
+ table.vertical th:first-child {
261
+ white-space: nowrap;
262
+ }
263
+ table.vertical tr:last-child {
264
+ border: none;
265
+ }
266
+
267
+
268
+
269
+ @media all and (orientation:portrait) {
270
+
271
+ }
272
+
273
+ @media all and (orientation:landscape) {
274
+
275
+ }
276
+
277
+ @media screen and (max-device-width: 480px) {
278
+
279
+ /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */
280
+ }
281
+
282
+
283
+ @media print {
284
+ * { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important;
285
+ -ms-filter: none !important; }
286
+ a, a:visited { color: #444 !important; text-decoration: underline; }
287
+ a[href]:after { content: " (" attr(href) ")"; }
288
+ abbr[title]:after { content: " (" attr(title) ")"; }
289
+ .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; }
290
+ pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
291
+ thead { display: table-header-group; }
292
+ tr, img { page-break-inside: avoid; }
293
+ @page { margin: 0.5cm; }
294
+ p, h2, h3 { orphans: 3; widows: 3; }
295
+ h2, h3{ page-break-after: avoid; }
296
+ }
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # encoding: utf-8
2
3
  $:<< '../lib' << 'lib'
3
4
 
4
5
  require 'goliath'
@@ -19,18 +20,59 @@ class HelloWorld < Goliath::API
19
20
  end
20
21
  end
21
22
 
23
+ class PostHelloWorld < Goliath::API
24
+ def response(env)
25
+ [200, {}, "hello post world!"]
26
+ end
27
+ end
28
+
29
+ class HelloNumber < Goliath::API
30
+ use Goliath::Rack::Params
31
+ def response(env)
32
+ [200, {}, "number #{params[:number]}!"]
33
+ end
34
+ end
35
+
36
+ class BigNumber < Goliath::API
37
+ use Goliath::Rack::Params
38
+ def response(env)
39
+ [200, {}, "big number #{params[:number]}!"]
40
+ end
41
+ end
42
+
22
43
  class Bonjour < Goliath::API
23
44
  def response(env)
24
45
  [200, {}, "bonjour!"]
25
46
  end
26
47
  end
27
48
 
49
+ class Hola < Goliath::API
50
+ use Goliath::Rack::Params
51
+ use Goliath::Rack::Validation::RequiredParam, {:key => "foo"}
52
+
53
+ def response(env)
54
+ [200, {}, "hola!"]
55
+ end
56
+ end
57
+
58
+ class Aloha < Goliath::API
59
+ use Goliath::Rack::Validation::RequestMethod, %w(GET)
60
+
61
+ def response(env)
62
+ [200, {}, "Aloha"]
63
+ end
64
+ end
65
+
28
66
  class RackRoutes < Goliath::API
29
67
  map '/version' do
30
68
  run Proc.new { |env| [200, {"Content-Type" => "text/html"}, ["Version 0.1"]] }
31
69
  end
32
70
 
33
- map "/hello_world" do
71
+ post "/hello_world" do
72
+ run PostHelloWorld.new
73
+ end
74
+
75
+ get "/hello_world" do
34
76
  run HelloWorld.new
35
77
  end
36
78
 
@@ -38,7 +80,27 @@ class RackRoutes < Goliath::API
38
80
  run Bonjour.new
39
81
  end
40
82
 
41
- map '/' do
42
- run Proc.new { |env| [404, {"Content-Type" => "text/html"}, ["Try /version /hello_world or /bonjour"]] }
83
+ map "/hola" do
84
+ use Goliath::Rack::Validation::RequestMethod, %w(GET)
85
+ run Hola.new
86
+ end
87
+
88
+ map "/aloha", Aloha
89
+
90
+ map "/:number", :number => /\d+/ do
91
+ if params[:number].to_i > 100
92
+ run BigNumber.new
93
+ else
94
+ run HelloNumber.new
95
+ end
96
+ end
97
+
98
+ not_found('/') do
99
+ run Proc.new { |env| [404, {"Content-Type" => "text/html"}, ["Try /version /hello_world, /bonjour, or /hola"]] }
100
+ end
101
+
102
+ # You must use either maps or response, but never both!
103
+ def response(env)
104
+ raise RuntimeException.new("#response is ignored when using maps, so this exception won't raise. See spec/integration/rack_routes_spec.")
43
105
  end
44
106
  end
@@ -0,0 +1,15 @@
1
+ if (phantom.state.length === 0) {
2
+ if (phantom.args.length !== 2) {
3
+ console.log('Usage: rasterize.js URL filename');
4
+ phantom.exit();
5
+ } else {
6
+ var address = phantom.args[0];
7
+ phantom.state = 'rasterize';
8
+ phantom.viewportSize = { width: 800, height: 600 };
9
+ phantom.open(address);
10
+ }
11
+ } else {
12
+ var output = phantom.args[1];
13
+ phantom.render(output);
14
+ phantom.exit();
15
+ }
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.dirname(__FILE__)+'/../../lib'
3
+ require 'goliath'
4
+ require 'postrank-uri'
5
+
6
+ # Install phantomjs: http://code.google.com/p/phantomjs/wiki/QuickStart
7
+ # $> ruby rasterize.rb -sv
8
+ # $> curl http://localhost:9000/?url=http://www.google.com (or rather, visit in the browser!)
9
+
10
+ class Rasterize < Goliath::API
11
+ use Goliath::Rack::Params
12
+
13
+ use Goliath::Rack::Validation::RequestMethod, %w(GET)
14
+ use Goliath::Rack::Validation::RequiredParam, {:key => 'url'}
15
+
16
+ def response(env)
17
+ url = PostRank::URI.clean(params['url'])
18
+ hash = PostRank::URI.hash(url, :clean => false)
19
+
20
+ if !File.exists? filename(hash)
21
+ fiber = Fiber.current
22
+ EM.system('phantomjs rasterize.js ' + url.to_s + ' ' + filename(hash)) do |output, status|
23
+ env.logger.info "Phantom exit status: #{status}"
24
+ fiber.resume
25
+ end
26
+
27
+ Fiber.yield
28
+ end
29
+
30
+ [202, {'X-Phantom' => 'Goliath'}, IO.read(filename(hash))]
31
+ end
32
+
33
+ def filename(hash)
34
+ "thumb/#{hash}.png"
35
+ end
36
+ end