roda 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +8 -0
- data/doc/release_notes/3.6.0.txt +21 -0
- data/lib/roda/plugins/assets.rb +12 -1
- data/lib/roda/plugins/early_hints.rb +26 -0
- data/lib/roda/plugins/json_parser.rb +21 -1
- data/lib/roda/version.rb +1 -1
- data/spec/plugin/assets_spec.rb +21 -0
- data/spec/plugin/early_hints_spec.rb +19 -0
- data/spec/plugin/json_parser_spec.rb +45 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f461d51ffcff3abee852c79773a13d87f2ffc5fea2c6a27346bfb2755b318e1e
|
4
|
+
data.tar.gz: c30fafc14125ef2b100bce74762193cb0f09776805732c284b7d7cd0472f07c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 428d1c607d27a5f90b4c5c992e8f8f3ea33cf8dd7c49e2a0920e49e4b97de34532eb9177aae04ad1efa9a229d747a6e5a744334ae803edbaf60e1e51cf154552
|
7
|
+
data.tar.gz: dd85d32aedb8b2c09fc757bd1cbc0f92dce99849841e4ab2e78f47589de8670c87023eb9d6a144efd1c7ff06f08f705589e2510cb7c4383cba13b40020b2d489
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
= 3.6.0 (2018-03-26)
|
2
|
+
|
3
|
+
* Add :wrap option to json_parser plugin, for whether/how to wrap the uploaded JSON object (jeremyevans) (#142)
|
4
|
+
|
5
|
+
* Add :early_hints option to the assets plugin, for supporting sending early hints for calls to assets (jeremyevans)
|
6
|
+
|
7
|
+
* Add early_hints plugin for sending 103 Early Hint responses, currently only working on puma (jeremyevans)
|
8
|
+
|
1
9
|
= 3.5.0 (2018-02-14)
|
2
10
|
|
3
11
|
* Add request_aref plugin for configuring behavior of request [] and []= methods (jeremyevans)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
= New Features
|
2
|
+
|
3
|
+
* An early_hints plugin has been added for senting 103 Early Hint
|
4
|
+
responses. This is currently only supported on puma 3.11+, and
|
5
|
+
can allow for improved performance by letting the requestor know
|
6
|
+
which related files will be needed by the request.
|
7
|
+
|
8
|
+
* An :early_hints option has been added to the assets plugin. If
|
9
|
+
given, calling the assets method will also issue an early hint
|
10
|
+
for the related assets.
|
11
|
+
|
12
|
+
* A :wrap option has been added to the json_parser plugin. If set
|
13
|
+
to :always, all uploaded json data will be stored using a hash
|
14
|
+
with a "_json" key. If set to :unless_hash, uploaded json data
|
15
|
+
will only be wrapped in such a matter if it is not already a hash.
|
16
|
+
|
17
|
+
Using the :wrap option can fix problems when using r.params when
|
18
|
+
the uploaded JSON data is an array and not a hash. However, it
|
19
|
+
does change the behavior of r.POST. It is possible to handle
|
20
|
+
uploaded JSON array data without the :wrap option by using r.GET
|
21
|
+
and r.POST directly instead of using r.params.
|
data/lib/roda/plugins/assets.rb
CHANGED
@@ -267,6 +267,7 @@ class Roda
|
|
267
267
|
# :dependencies :: A hash of dependencies for your asset files. Keys should be paths to asset files,
|
268
268
|
# values should be arrays of paths your asset files depends on. This is used to
|
269
269
|
# detect changes in your asset files.
|
270
|
+
# :early_hints :: Automatically send early hints for all assets. Requires the early_hints plugin.
|
270
271
|
# :group_subdirs :: Whether a hash used in :css and :js options requires the assets for the
|
271
272
|
# related group are contained in a subdirectory with the same name (default: true)
|
272
273
|
# :gzip :: Store gzipped compiled assets files, and serve those to clients who accept gzip encoding.
|
@@ -307,6 +308,7 @@ class Roda
|
|
307
308
|
:concat_only => false,
|
308
309
|
:compiled => false,
|
309
310
|
:add_suffix => false,
|
311
|
+
:early_hints => false,
|
310
312
|
:timestamp_paths => false,
|
311
313
|
:group_subdirs => true,
|
312
314
|
:compiled_css_dir => nil,
|
@@ -369,6 +371,10 @@ class Roda
|
|
369
371
|
opts[:compiled] = ::JSON.parse(::File.read(opts[:precompiled]))
|
370
372
|
end
|
371
373
|
|
374
|
+
if opts[:early_hints]
|
375
|
+
app.plugin :early_hints
|
376
|
+
end
|
377
|
+
|
372
378
|
DEFAULTS.each do |k, v|
|
373
379
|
opts[k] = v unless opts.has_key?(k)
|
374
380
|
end
|
@@ -661,7 +667,12 @@ class Roda
|
|
661
667
|
tag_end = "\" />"
|
662
668
|
end
|
663
669
|
|
664
|
-
assets_paths(type)
|
670
|
+
paths = assets_paths(type)
|
671
|
+
if o[:early_hints]
|
672
|
+
early_hint_as = ltype == :js ? 'script' : 'style'
|
673
|
+
send_early_hints('Link'=>paths.map{|p| "<#{p}>; rel=preload; as=#{early_hint_as}"}.join("\n"))
|
674
|
+
end
|
675
|
+
paths.map{|p| "#{tag_start}#{h(p)}#{tag_end}"}.join("\n")
|
665
676
|
end
|
666
677
|
|
667
678
|
# Render the asset with the given filename. When assets are compiled,
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
class Roda
|
5
|
+
module RodaPlugins
|
6
|
+
# The early_hints plugin allows sending 103 Early Hints responses
|
7
|
+
# using the rack.early_hints environment variable. Currently, this
|
8
|
+
# is only supported by puma 3.11+, and on other servers this is a no-op.
|
9
|
+
# Early hints allow clients to preload necessary files before receiving
|
10
|
+
# the response.
|
11
|
+
module EarlyHints
|
12
|
+
module InstanceMethods
|
13
|
+
# Send given hash of Early Hints using the rack.early_hints environment variable,
|
14
|
+
# currenly only supported by puma. hash given should generally have the single
|
15
|
+
# key 'Link', and a string or array of strings for each of the early hints.
|
16
|
+
def send_early_hints(hash)
|
17
|
+
if eh_proc = env['rack.early_hints']
|
18
|
+
eh_proc.call(hash)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
register_plugin(:early_hints, EarlyHints)
|
25
|
+
end
|
26
|
+
end
|
@@ -25,10 +25,24 @@ class Roda
|
|
25
25
|
# :include_request :: If true, the parser will be called with the request
|
26
26
|
# object as the second argument, so the parser needs
|
27
27
|
# to respond to +call(str, request)+.
|
28
|
+
# :wrap :: Whether to wrap uploaded JSON data in a hash with a "_json"
|
29
|
+
# key. Without this, calls to r.params will fail if a non-Hash
|
30
|
+
# (such as an array) is uploaded in JSON format. A value of
|
31
|
+
# :always will wrap all values, and a value of :unless_hash will
|
32
|
+
# only wrap values that are not already hashes.
|
28
33
|
def self.configure(app, opts=OPTS)
|
29
34
|
app.opts[:json_parser_error_handler] = opts[:error_handler] || app.opts[:json_parser_error_handler] || DEFAULT_ERROR_HANDLER
|
30
35
|
app.opts[:json_parser_parser] = opts[:parser] || app.opts[:json_parser_parser] || DEFAULT_PARSER
|
31
36
|
app.opts[:json_parser_include_request] = opts[:include_request] if opts.has_key?(:include_request)
|
37
|
+
|
38
|
+
case opts[:wrap]
|
39
|
+
when :unless_hash, :always
|
40
|
+
app.opts[:json_parser_wrap] = opts[:wrap]
|
41
|
+
when nil
|
42
|
+
# Nothing
|
43
|
+
else
|
44
|
+
raise RodaError, "unsupported option value for json_parser plugin :wrap option: #{opts[:wrap].inspect} (should be :unless_hash or :always)"
|
45
|
+
end
|
32
46
|
end
|
33
47
|
|
34
48
|
module RequestMethods
|
@@ -43,10 +57,16 @@ class Roda
|
|
43
57
|
input.rewind
|
44
58
|
return super if str.empty?
|
45
59
|
begin
|
46
|
-
json_params =
|
60
|
+
json_params = parse_json(str)
|
47
61
|
rescue
|
48
62
|
roda_class.opts[:json_parser_error_handler].call(self)
|
49
63
|
end
|
64
|
+
|
65
|
+
wrap = roda_class.opts[:json_parser_wrap]
|
66
|
+
if wrap == :always || (wrap == :unless_hash && !json_params.is_a?(Hash))
|
67
|
+
json_params = {"_json"=>json_params}
|
68
|
+
end
|
69
|
+
env["roda.json_params"] = json_params
|
50
70
|
env["rack.request.form_input"] = input
|
51
71
|
json_params
|
52
72
|
else
|
data/lib/roda/version.rb
CHANGED
data/spec/plugin/assets_spec.rb
CHANGED
@@ -196,6 +196,27 @@ if run_tests
|
|
196
196
|
js.must_include('console.log')
|
197
197
|
end
|
198
198
|
|
199
|
+
it 'should handle early hints if the :early_hints option is used' do
|
200
|
+
app.plugin :assets, :early_hints=>true
|
201
|
+
eh = []
|
202
|
+
html = body('/test', 'rack.early_hints'=>proc{|h| eh << h})
|
203
|
+
eh.must_equal [
|
204
|
+
{"Link"=>"</assets/css/app.scss>; rel=preload; as=style\n</assets/css/raw.css>; rel=preload; as=style"},
|
205
|
+
{"Link"=>"</assets/js/head/app.js>; rel=preload; as=script"}
|
206
|
+
]
|
207
|
+
html.scan(/<link/).length.must_equal 2
|
208
|
+
html =~ %r{href="(/assets/css/app\.scss)"}
|
209
|
+
css = body($1)
|
210
|
+
html =~ %r{href="(/assets/css/raw\.css)"}
|
211
|
+
css2 = body($1)
|
212
|
+
html.scan(/<script/).length.must_equal 1
|
213
|
+
html =~ %r{src="(/assets/js/head/app\.js)"}
|
214
|
+
js = body($1)
|
215
|
+
css.must_match(/color: red;/)
|
216
|
+
css2.must_match(/color: blue;/)
|
217
|
+
js.must_include('console.log')
|
218
|
+
end
|
219
|
+
|
199
220
|
it 'should handle rendering assets, linking to them, and accepting requests for them when :add_script_name app option is used' do
|
200
221
|
app.opts[:add_script_name] = true
|
201
222
|
app.plugin :assets
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
|
3
|
+
describe "early_hints plugin" do
|
4
|
+
it "allows sending early hints to rack.early_hints" do
|
5
|
+
queue = []
|
6
|
+
app(:early_hints) do |r|
|
7
|
+
send_early_hints('Link'=>'</foo.js>; rel=preload; as=script')
|
8
|
+
queue << 'OK'
|
9
|
+
'OK'
|
10
|
+
end
|
11
|
+
|
12
|
+
body.must_equal 'OK'
|
13
|
+
queue.must_equal ['OK']
|
14
|
+
|
15
|
+
queue = []
|
16
|
+
body('rack.early_hints'=>proc{|h| queue << h}).must_equal 'OK'
|
17
|
+
queue.must_equal [{'Link'=>'</foo.js>; rel=preload; as=script'}, 'OK']
|
18
|
+
end
|
19
|
+
end
|
@@ -18,6 +18,12 @@ describe "json_parser plugin" do
|
|
18
18
|
it "returns 400 for invalid json" do
|
19
19
|
req('rack.input'=>StringIO.new('{"a":{"b":1}'), 'CONTENT_TYPE'=>'text/json', 'REQUEST_METHOD'=>'POST').must_equal [400, {}, []]
|
20
20
|
end
|
21
|
+
|
22
|
+
it "raises by default if r.params is called and a non-hash is submitted" do
|
23
|
+
proc do
|
24
|
+
req('rack.input'=>StringIO.new('[1]'), 'CONTENT_TYPE'=>'text/json', 'REQUEST_METHOD'=>'POST')
|
25
|
+
end.must_raise
|
26
|
+
end
|
21
27
|
end
|
22
28
|
|
23
29
|
describe "json_parser plugin" do
|
@@ -28,6 +34,45 @@ describe "json_parser plugin" do
|
|
28
34
|
body('rack.input'=>StringIO.new(''), 'CONTENT_TYPE'=>'text/json', 'REQUEST_METHOD'=>'POST').must_equal '0'
|
29
35
|
end
|
30
36
|
|
37
|
+
it "handles arrays and other non-hash values using r.POST" do
|
38
|
+
app(:json_parser) do |r|
|
39
|
+
r.POST.inspect
|
40
|
+
end
|
41
|
+
body('rack.input'=>StringIO.new('[ 1 ]'), 'CONTENT_TYPE'=>'text/json', 'REQUEST_METHOD'=>'POST').must_equal '[1]'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "supports :wrap=>:always option" do
|
45
|
+
app(:bare) do
|
46
|
+
plugin(:json_parser, :wrap=>:always)
|
47
|
+
route do |r|
|
48
|
+
r.post 'a' do r.params['_json']['a']['b'].to_s end
|
49
|
+
r.params['_json'][1].to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
body('/a', 'rack.input'=>StringIO.new('{"a":{"b":1}}'), 'CONTENT_TYPE'=>'text/json', 'REQUEST_METHOD'=>'POST').must_equal '1'
|
53
|
+
body('rack.input'=>StringIO.new('[true, 2]'), 'CONTENT_TYPE'=>'text/json', 'REQUEST_METHOD'=>'POST').must_equal '2'
|
54
|
+
end
|
55
|
+
|
56
|
+
it "supports :wrap=>:unless_hash option" do
|
57
|
+
app(:bare) do
|
58
|
+
plugin(:json_parser, :wrap=>:unless_hash)
|
59
|
+
route do |r|
|
60
|
+
r.post 'a' do r.params['a']['b'].to_s end
|
61
|
+
r.params['_json'][1].to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
body('/a', 'rack.input'=>StringIO.new('{"a":{"b":1}}'), 'CONTENT_TYPE'=>'text/json', 'REQUEST_METHOD'=>'POST').must_equal '1'
|
65
|
+
body('rack.input'=>StringIO.new('[true, 2]'), 'CONTENT_TYPE'=>'text/json', 'REQUEST_METHOD'=>'POST').must_equal '2'
|
66
|
+
end
|
67
|
+
|
68
|
+
it "raises for unsupported :wrap option" do
|
69
|
+
proc do
|
70
|
+
app(:bare) do
|
71
|
+
plugin(:json_parser, :wrap=>:foo)
|
72
|
+
end
|
73
|
+
end.must_raise Roda::RodaError
|
74
|
+
end
|
75
|
+
|
31
76
|
it "supports :error_handler option" do
|
32
77
|
app(:bare) do
|
33
78
|
plugin(:json_parser, :error_handler=>proc{|r| r.halt [401, {}, ['bad']]})
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roda
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -201,6 +201,7 @@ extra_rdoc_files:
|
|
201
201
|
- doc/release_notes/3.3.0.txt
|
202
202
|
- doc/release_notes/3.4.0.txt
|
203
203
|
- doc/release_notes/3.5.0.txt
|
204
|
+
- doc/release_notes/3.6.0.txt
|
204
205
|
files:
|
205
206
|
- CHANGELOG
|
206
207
|
- MIT-LICENSE
|
@@ -248,6 +249,7 @@ files:
|
|
248
249
|
- doc/release_notes/3.3.0.txt
|
249
250
|
- doc/release_notes/3.4.0.txt
|
250
251
|
- doc/release_notes/3.5.0.txt
|
252
|
+
- doc/release_notes/3.6.0.txt
|
251
253
|
- lib/roda.rb
|
252
254
|
- lib/roda/plugins/_symbol_regexp_matchers.rb
|
253
255
|
- lib/roda/plugins/all_verbs.rb
|
@@ -269,6 +271,7 @@ files:
|
|
269
271
|
- lib/roda/plugins/delete_empty_headers.rb
|
270
272
|
- lib/roda/plugins/disallow_file_uploads.rb
|
271
273
|
- lib/roda/plugins/drop_body.rb
|
274
|
+
- lib/roda/plugins/early_hints.rb
|
272
275
|
- lib/roda/plugins/empty_root.rb
|
273
276
|
- lib/roda/plugins/environments.rb
|
274
277
|
- lib/roda/plugins/error_email.rb
|
@@ -364,6 +367,7 @@ files:
|
|
364
367
|
- spec/plugin/delete_empty_headers_spec.rb
|
365
368
|
- spec/plugin/disallow_file_uploads_spec.rb
|
366
369
|
- spec/plugin/drop_body_spec.rb
|
370
|
+
- spec/plugin/early_hints_spec.rb
|
367
371
|
- spec/plugin/empty_root_spec.rb
|
368
372
|
- spec/plugin/environments_spec.rb
|
369
373
|
- spec/plugin/error_email_spec.rb
|