roda 2.18.0 → 2.19.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +12 -0
- data/doc/release_notes/2.18.0.txt +20 -20
- data/doc/release_notes/2.19.0.txt +30 -0
- data/lib/roda.rb +10 -2
- data/lib/roda/plugins/assets.rb +40 -34
- data/lib/roda/plugins/assets_preloading.rb +1 -1
- data/lib/roda/plugins/h.rb +15 -2
- data/lib/roda/plugins/indifferent_params.rb +72 -30
- data/lib/roda/version.rb +1 -1
- data/spec/plugin/assets_preloading_spec.rb +17 -1
- data/spec/plugin/assets_spec.rb +5 -5
- data/spec/plugin/content_for_spec.rb +32 -26
- data/spec/plugin/h_spec.rb +2 -2
- data/spec/plugin/indifferent_params_spec.rb +1 -0
- data/spec/response_spec.rb +10 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b6466dae7413eb39adad4261800c4a31373bd59
|
4
|
+
data.tar.gz: e03a612cbbcc10f0745c7c5ac90dd60ba42d2608
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eed87278923a1e0c6c02bf903a42e3951bc2d4f3b7107f3a7e7898287abc374185cdb1fa4456392695bd8649cdc132f31764054dd911a4bd3b4cea24652259ac
|
7
|
+
data.tar.gz: 7d79e779afcbd05769a6568920ef5854c5ae9bfdeb9cf5947177efa73a08d1350d63f758ddb747e566991dfccd7df21a1e430b35872d9bae75692b1cd29a027a
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
= 2.19.0 (2016-10-14)
|
2
|
+
|
3
|
+
* Don't add Content-Type/Content-Length headers for 1xx, 204, 205, 304 statuses (celsworth, jeremyevans) (#101, #102)
|
4
|
+
|
5
|
+
* Optimize indifferent_params plugin when using Rack 2 (jeremyevans)
|
6
|
+
|
7
|
+
* Fix assets_paths method in assets plugin when subresource integrity is used (jeremyevans, celsworth)
|
8
|
+
|
9
|
+
* Make assets plugin depend on h plugin, instead of using Rack::Utils.escape_html (jeremyevans)
|
10
|
+
|
11
|
+
* Make h plugin not escape / (celsworth, jeremyevans) (#100)
|
12
|
+
|
1
13
|
= 2.18.0 (2016-09-13)
|
2
14
|
|
3
15
|
* Add assets_preloading plugin, for creating link tags or Link header for preloading assets (celsworth, jeremyevans) (#98)
|
@@ -2,16 +2,16 @@
|
|
2
2
|
|
3
3
|
* A static_routing plugin has been added, which can give a 3-4x
|
4
4
|
increase in performance for large number of static routes, and
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
5
|
+
makes routing O(1) for static routes. Static routes are routes
|
6
|
+
that match full paths, with no placeholders, and are checked before
|
7
|
+
using the normal routing tree.
|
8
|
+
|
9
|
+
Static routes are defined via class-level static_* routing methods.
|
10
|
+
There is a static_* routing method for each HTTP verb (e.g.
|
11
|
+
static_get), as well as a static_route method, which will work
|
12
|
+
for any HTTP verb, with the verb-specific method taking priority.
|
13
|
+
By using static_route, you can get significantly faster performance
|
14
|
+
while retaining some of the benefits of Roda's routing tree design
|
15
15
|
(simple shared logic with verb specific behavior). Example:
|
16
16
|
|
17
17
|
plugin :static_routing
|
@@ -35,25 +35,25 @@
|
|
35
35
|
end
|
36
36
|
|
37
37
|
Because static routing routes on the full path instead of by
|
38
|
-
|
39
|
-
|
38
|
+
path segment, the methods takes the full path as a string,
|
39
|
+
including the leading slash.
|
40
40
|
|
41
41
|
* An assets_preloading plugin has been added, which makes it simple
|
42
42
|
to generate HTML link tags or a Link header value to tell the
|
43
|
-
|
43
|
+
browser to preload assets for performance reasons.
|
44
44
|
|
45
|
-
|
46
|
-
|
45
|
+
# In routes, using the Link header:
|
46
|
+
response.headers['Link'] = preload_assets_link_header(:css)
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
# In templates, using a link tag:
|
49
|
+
<%= preload_assets_link_tags(:css) %>
|
50
50
|
|
51
51
|
= New Features
|
52
52
|
|
53
53
|
* RodaRequest#real_remaining_path has been added. This is designed
|
54
54
|
to be overridden by plugins that modify remaining_path for internal
|
55
|
-
|
56
|
-
|
55
|
+
routing purposes. RodaRequest#run now uses real_remaining_path
|
56
|
+
when passing requests to other rack applications.
|
57
57
|
|
58
58
|
* An assets_paths method has been added to the assets plugin. This
|
59
59
|
is similar to the assets method, but it returns an array of paths
|
@@ -63,7 +63,7 @@
|
|
63
63
|
|
64
64
|
* The public plugin now works correctly when used with the
|
65
65
|
type_routing plugin, for paths ending in extensions that
|
66
|
-
|
66
|
+
type_routing is configured to handle.
|
67
67
|
|
68
68
|
* The head plugin now works with the not_allowed plugin if it is
|
69
69
|
loaded after the not_allowed plugin.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
= Improvements
|
2
|
+
|
3
|
+
* The indifferent_params plugin is now optimized when using Rack 2,
|
4
|
+
using Rack 2's query_parser API, and it no longer needs to do a
|
5
|
+
deep copy of the params.
|
6
|
+
|
7
|
+
* The Content-Type and Content-Length headers are no longer added
|
8
|
+
for 1xx, 204, 205, and 304 responses.
|
9
|
+
|
10
|
+
* The assets_paths method in the assets plugin now works
|
11
|
+
correctly when subresource integrity is enabled.
|
12
|
+
|
13
|
+
* The asset paths are now escaped in tags by the assets and
|
14
|
+
assets_preloading plugins. While it's unlikely a developer
|
15
|
+
would use an asset path that requires escaping, that case is
|
16
|
+
now handled correctly.
|
17
|
+
|
18
|
+
* The h plugin no longer calls Rack::Utils.escape_html, instead
|
19
|
+
implementing it's own html escaping.
|
20
|
+
|
21
|
+
* The assets plugin now uses the h plugin, instead of calling
|
22
|
+
Rack::Utils.escape_html.
|
23
|
+
|
24
|
+
= Backwards Compatibility
|
25
|
+
|
26
|
+
* The h plugin's html escaping no longer escapes "/", which is
|
27
|
+
a behavior change if you are using any recent version of rack.
|
28
|
+
The security arguments made to escape "/" could be applied to
|
29
|
+
many other characters, so if you want to escape "/", you should
|
30
|
+
probably use a separate method that escapes all \W characters.
|
data/lib/roda.rb
CHANGED
@@ -867,6 +867,7 @@ class Roda
|
|
867
867
|
# Instance methods for RodaResponse
|
868
868
|
module ResponseMethods
|
869
869
|
CONTENT_LENGTH = "Content-Length".freeze
|
870
|
+
CONTENT_TYPE = "Content-Type".freeze
|
870
871
|
DEFAULT_HEADERS = {"Content-Type" => "text/html".freeze}.freeze
|
871
872
|
LOCATION = "Location".freeze
|
872
873
|
|
@@ -932,10 +933,17 @@ class Roda
|
|
932
933
|
# # []]
|
933
934
|
def finish
|
934
935
|
b = @body
|
935
|
-
|
936
|
+
empty = b.empty?
|
937
|
+
s = (@status ||= empty ? 404 : default_status)
|
936
938
|
set_default_headers
|
937
939
|
h = @headers
|
938
|
-
|
940
|
+
|
941
|
+
if empty && (s == 304 || s == 204 || s == 205 || (s >= 100 && s <= 199))
|
942
|
+
h.delete(CONTENT_TYPE)
|
943
|
+
else
|
944
|
+
h[CONTENT_LENGTH] ||= @length.to_s
|
945
|
+
end
|
946
|
+
|
939
947
|
[s, h, b]
|
940
948
|
end
|
941
949
|
|
data/lib/roda/plugins/assets.rb
CHANGED
@@ -319,15 +319,17 @@ class Roda
|
|
319
319
|
CONTENT_ENCODING = 'Content-Encoding'.freeze
|
320
320
|
GZIP = 'gzip'.freeze
|
321
321
|
DOTGZ = '.gz'.freeze
|
322
|
+
EMPTY_ATTRS = {}.freeze
|
322
323
|
|
323
324
|
# Internal exception raised when a compressor cannot be found
|
324
325
|
CompressorNotFound = Class.new(RodaError)
|
325
326
|
|
326
|
-
# Load the render and
|
327
|
+
# Load the render, caching, and h plugins, since the assets plugin
|
327
328
|
# depends on them.
|
328
329
|
def self.load_dependencies(app, _opts = nil)
|
329
330
|
app.plugin :render
|
330
331
|
app.plugin :caching
|
332
|
+
app.plugin :h
|
331
333
|
end
|
332
334
|
|
333
335
|
# Setup the options for the plugin. See the Assets module RDoc
|
@@ -605,35 +607,23 @@ class Roda
|
|
605
607
|
# asset group. See the assets function documentation for details.
|
606
608
|
def assets_paths(type)
|
607
609
|
o = self.class.assets_opts
|
608
|
-
|
609
|
-
|
610
|
-
|
610
|
+
if type.is_a?(Array)
|
611
|
+
ltype, *dirs = type
|
612
|
+
else
|
613
|
+
ltype = type
|
614
|
+
end
|
615
|
+
stype = ltype.to_s
|
611
616
|
|
612
617
|
url_prefix = request.script_name if self.class.opts[:add_script_name]
|
613
618
|
|
614
619
|
if compiled = o[:compiled]
|
615
|
-
|
616
|
-
|
617
|
-
key = dirs.join(DOT)
|
618
|
-
ckey = "#{stype}.#{key}"
|
619
|
-
if hash = ukey = compiled[ckey]
|
620
|
-
ukey = "#{key}.#{ukey}"
|
621
|
-
end
|
622
|
-
else
|
623
|
-
hash = ukey = compiled[stype]
|
624
|
-
end
|
625
|
-
|
626
|
-
if ukey
|
627
|
-
if algo = o[:sri]
|
628
|
-
integrity = "\" integrity=\"#{algo}-#{ru.escape_html([[hash].pack('H*')].pack('m').tr("\n", EMPTY_STRING))}"
|
629
|
-
end
|
630
|
-
|
631
|
-
[ "#{asset_host}#{url_prefix}/#{o[:"compiled_#{stype}_prefix"]}.#{ukey}.#{stype}#{integrity}" ]
|
620
|
+
if ukey = _compiled_assets_hash(type, true)
|
621
|
+
["#{o[:compiled_asset_host]}#{url_prefix}/#{o[:"compiled_#{stype}_prefix"]}.#{ukey}.#{stype}"]
|
632
622
|
else
|
633
623
|
[]
|
634
624
|
end
|
635
625
|
else
|
636
|
-
asset_dir = o[
|
626
|
+
asset_dir = o[ltype]
|
637
627
|
if dirs && !dirs.empty?
|
638
628
|
dirs.each{|f| asset_dir = asset_dir[f]}
|
639
629
|
prefix = "#{dirs.join(SLASH)}/" if o[:group_subdirs]
|
@@ -652,19 +642,17 @@ class Roda
|
|
652
642
|
# When the assets are not compiled, this will result in a separate
|
653
643
|
# tag for each asset file. When the assets are compiled, this will
|
654
644
|
# result in a single tag to the compiled asset file.
|
655
|
-
def assets(type, attrs =
|
656
|
-
|
657
|
-
attrs = if attrs
|
658
|
-
attrs.map{|k,v| "#{k}=\"#{ru.escape_html(v.to_s)}\""}.join(SPACE)
|
659
|
-
else
|
660
|
-
EMPTY_STRING
|
661
|
-
end
|
645
|
+
def assets(type, attrs = EMPTY_ATTRS)
|
646
|
+
ltype = type.is_a?(Array) ? type[0] : type
|
662
647
|
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
648
|
+
o = self.class.assets_opts
|
649
|
+
if o[:compiled] && (algo = o[:sri]) && (hash = _compiled_assets_hash(type))
|
650
|
+
attrs = Hash[attrs]
|
651
|
+
attrs[:integrity] = "#{algo}-#{h([[hash].pack('H*')].pack('m').tr("\n", EMPTY_STRING))}"
|
667
652
|
end
|
653
|
+
|
654
|
+
attrs = attrs.map{|k,v| "#{k}=\"#{h(v)}\""}.join(SPACE)
|
655
|
+
|
668
656
|
if ltype == :js
|
669
657
|
tag_start = "<script type=\"text/javascript\" #{attrs} src=\""
|
670
658
|
tag_end = JS_END
|
@@ -673,7 +661,7 @@ class Roda
|
|
673
661
|
tag_end = CSS_END
|
674
662
|
end
|
675
663
|
|
676
|
-
assets_paths(type).map{|p| "#{tag_start}#{p}#{tag_end}"}.join(NEWLINE)
|
664
|
+
assets_paths(type).map{|p| "#{tag_start}#{h(p)}#{tag_end}"}.join(NEWLINE)
|
677
665
|
end
|
678
666
|
|
679
667
|
# Render the asset with the given filename. When assets are compiled,
|
@@ -719,6 +707,24 @@ class Roda
|
|
719
707
|
|
720
708
|
private
|
721
709
|
|
710
|
+
def _compiled_assets_hash(type, return_ukey=false)
|
711
|
+
compiled = self.class.assets_opts[:compiled]
|
712
|
+
type, *dirs = type if type.is_a?(Array)
|
713
|
+
stype = type.to_s
|
714
|
+
|
715
|
+
if dirs && !dirs.empty?
|
716
|
+
key = dirs.join(DOT)
|
717
|
+
ckey = "#{stype}.#{key}"
|
718
|
+
if hash = ukey = compiled[ckey]
|
719
|
+
ukey = "#{key}.#{ukey}"
|
720
|
+
end
|
721
|
+
else
|
722
|
+
hash = ukey = compiled[stype]
|
723
|
+
end
|
724
|
+
|
725
|
+
return_ukey ? ukey : hash
|
726
|
+
end
|
727
|
+
|
722
728
|
# Return when the file was last modified. If the file depends on any
|
723
729
|
# other files, check the modification times of all dependencies and
|
724
730
|
# return the maximum.
|
@@ -61,7 +61,7 @@ class Roda
|
|
61
61
|
# Return a string of <link> tags for the given asset
|
62
62
|
# types/groups.
|
63
63
|
def preload_assets_link_tags(*args)
|
64
|
-
_preload_assets_array(args).map{|path, as| "<link href=\"#{path}\" rel=\"preload\" as=\"#{as}\">"}.join(NEWLINE)
|
64
|
+
_preload_assets_array(args).map{|path, as| "<link href=\"#{h(path)}\" rel=\"preload\" as=\"#{as}\">"}.join(NEWLINE)
|
65
65
|
end
|
66
66
|
|
67
67
|
# Return a string suitable for a Link header for the
|
data/lib/roda/plugins/h.rb
CHANGED
@@ -14,10 +14,23 @@ class Roda
|
|
14
14
|
# h('<foo>')
|
15
15
|
# end
|
16
16
|
module H
|
17
|
+
# A Hash of entities and their escaped equivalents,
|
18
|
+
# to be escaped by h().
|
19
|
+
ESCAPE_HTML = {
|
20
|
+
"&" => "&".freeze,
|
21
|
+
"<" => "<".freeze,
|
22
|
+
">" => ">".freeze,
|
23
|
+
"'" => "'".freeze,
|
24
|
+
'"' => """.freeze,
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
# A Regexp of HTML entities to match for escaping.
|
28
|
+
ESCAPE_HTML_PATTERN = Regexp.union(*ESCAPE_HTML.keys)
|
29
|
+
|
17
30
|
module InstanceMethods
|
18
31
|
# HTML escape the input and return the escaped version.
|
19
|
-
def h(
|
20
|
-
|
32
|
+
def h(string)
|
33
|
+
string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
|
21
34
|
end
|
22
35
|
end
|
23
36
|
end
|
@@ -4,9 +4,9 @@
|
|
4
4
|
class Roda
|
5
5
|
module RodaPlugins
|
6
6
|
# The indifferent_params plugin adds a +params+ instance
|
7
|
-
# method which
|
8
|
-
#
|
9
|
-
# Example:
|
7
|
+
# method which offers indifferent access to the request
|
8
|
+
# params, allowing you to use symbols to lookup values in
|
9
|
+
# a hash where the keys are strings. Example:
|
10
10
|
#
|
11
11
|
# plugin :indifferent_params
|
12
12
|
#
|
@@ -14,39 +14,81 @@ class Roda
|
|
14
14
|
# params[:foo]
|
15
15
|
# end
|
16
16
|
#
|
17
|
-
# The
|
18
|
-
#
|
19
|
-
# the
|
17
|
+
# The exact behavior depends on the version of Rack in use.
|
18
|
+
# If you are using Rack 2, this plugin uses rack's API
|
19
|
+
# to set the query parser for the request to use indifferent
|
20
|
+
# access. Rack 1 doesn't support indifferent access to
|
21
|
+
# params, so if you are using Rack 1, this plugin will make
|
22
|
+
# a deep copy of the request params hash, where each level
|
23
|
+
# uses indifferent access. On Rack 1, The params hash is
|
24
|
+
# initialized lazily, so you only pay the penalty of
|
25
|
+
# copying the request params if you call the +params+ method.
|
20
26
|
#
|
21
27
|
# Note that there is a rack-indifferent gem that
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
28
|
+
# monkey patches rack to always use indifferent params. If
|
29
|
+
# you are using Rack 1, it is recommended to use
|
30
|
+
# rack-indifferent instead of this plugin, as it is faster
|
31
|
+
# and has some other minor advantages, though
|
32
|
+
# it affects all rack applications instead of just the Roda app that
|
26
33
|
# you load the plugin into.
|
27
34
|
module IndifferentParams
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
35
|
+
INDIFFERENT_PROC = lambda{|h,k| h[k.to_s] if k.is_a?(Symbol)}
|
36
|
+
|
37
|
+
if Rack.release > '2'
|
38
|
+
class QueryParser < Rack::QueryParser
|
39
|
+
# Work around for invalid optimization in rack
|
40
|
+
def parse_nested_query(qs, d=nil)
|
41
|
+
return make_params.to_params_hash if qs.nil? || qs.empty?
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
class Params < Rack::QueryParser::Params
|
46
|
+
def initialize(limit = Rack::Utils.key_space_limit)
|
47
|
+
@limit = limit
|
48
|
+
@size = 0
|
49
|
+
@params = Hash.new(&INDIFFERENT_PROC)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
33
53
|
end
|
34
54
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
55
|
+
module RequestMethods
|
56
|
+
QUERY_PARSER = Rack::Utils.default_query_parser = QueryParser.new(QueryParser::Params, 65536, 100)
|
57
|
+
|
58
|
+
def query_parser
|
59
|
+
QUERY_PARSER
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module InstanceMethods
|
64
|
+
def params
|
65
|
+
@_request.params
|
66
|
+
end
|
67
|
+
end
|
68
|
+
else
|
69
|
+
module InstanceMethods
|
70
|
+
# A copy of the request params that will automatically
|
71
|
+
# convert symbols to strings.
|
72
|
+
def params
|
73
|
+
@_params ||= indifferent_params(@_request.params)
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
# Recursively process the request params and convert
|
79
|
+
# hashes to support indifferent access, leaving
|
80
|
+
# other values alone.
|
81
|
+
def indifferent_params(params)
|
82
|
+
case params
|
83
|
+
when Hash
|
84
|
+
hash = Hash.new(&INDIFFERENT_PROC)
|
85
|
+
params.each{|k, v| hash[k] = indifferent_params(v)}
|
86
|
+
hash
|
87
|
+
when Array
|
88
|
+
params.map{|x| indifferent_params(x)}
|
89
|
+
else
|
90
|
+
params
|
91
|
+
end
|
50
92
|
end
|
51
93
|
end
|
52
94
|
end
|
data/lib/roda/version.rb
CHANGED
@@ -1,5 +1,21 @@
|
|
1
1
|
require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
|
2
2
|
|
3
|
+
run_tests = true
|
4
|
+
begin
|
5
|
+
begin
|
6
|
+
require 'tilt/sass'
|
7
|
+
rescue LoadError
|
8
|
+
begin
|
9
|
+
for lib in %w'tilt sass'
|
10
|
+
require lib
|
11
|
+
end
|
12
|
+
rescue LoadError
|
13
|
+
warn "#{lib} not installed, skipping assets_preloading plugin test"
|
14
|
+
run_tests = false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
3
19
|
describe "assets_preloading plugin" do
|
4
20
|
before do
|
5
21
|
app(:bare) do
|
@@ -79,4 +95,4 @@ describe "assets_preloading plugin" do
|
|
79
95
|
html = body('/tags-js')
|
80
96
|
html.scan('as="script"').count.must_equal 1
|
81
97
|
end
|
82
|
-
end
|
98
|
+
end if run_tests
|
data/spec/plugin/assets_spec.rb
CHANGED
@@ -294,20 +294,20 @@ if run_tests
|
|
294
294
|
end
|
295
295
|
|
296
296
|
[[:sha256, 64, 44], [:sha384, 96, 64], [:sha512, 128, 88]].each do |algo, hex_length, base64_length|
|
297
|
-
it
|
297
|
+
it "should handle :sri option for subresource integrity for #{algo} when compiling assets" do
|
298
298
|
app.plugin :assets, :sri=>algo
|
299
299
|
app.compile_assets
|
300
300
|
html = body('/test')
|
301
301
|
html.scan(/<link/).length.must_equal 1
|
302
|
-
html =~ %r|integrity="#{algo}-([^"]+)"
|
303
|
-
css_hash = $1
|
302
|
+
html =~ %r|et" integrity="#{algo}-([^"]+)"|
|
303
|
+
css_hash = $1
|
304
304
|
css_hash.length.must_equal base64_length
|
305
305
|
html =~ %r|href="(/assets/app\.[a-f0-9]{#{hex_length}}\.css)"|
|
306
306
|
css = body($1)
|
307
307
|
[Digest.const_get(algo.to_s.upcase).digest(css)].pack('m').tr("\n", "").must_equal css_hash
|
308
308
|
html.scan(/<script/).length.must_equal 1
|
309
|
-
html =~ %r|integrity="#{algo}-([^"]+)"
|
310
|
-
js_hash = $1
|
309
|
+
html =~ %r|pt" integrity="#{algo}-([^"]+)"|
|
310
|
+
js_hash = $1
|
311
311
|
js_hash.length.must_equal base64_length
|
312
312
|
html =~ %r|src="(/assets/app\.head\.[a-f0-9]{#{hex_length}}\.js)"|
|
313
313
|
js = body($1)
|
@@ -2,9 +2,8 @@ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
|
|
2
2
|
|
3
3
|
begin
|
4
4
|
require 'tilt/erb'
|
5
|
-
require 'tilt/haml'
|
6
5
|
rescue LoadError
|
7
|
-
warn "tilt
|
6
|
+
warn "tilt not installed, skipping content_for plugin test"
|
8
7
|
else
|
9
8
|
describe "content_for plugin with erb" do
|
10
9
|
before do
|
@@ -39,6 +38,37 @@ describe "content_for plugin with erb" do
|
|
39
38
|
end
|
40
39
|
end
|
41
40
|
|
41
|
+
describe "content_for plugin with multiple calls to the same key" do
|
42
|
+
before do
|
43
|
+
app(:bare) do
|
44
|
+
plugin :render, :views => './spec/views'
|
45
|
+
plugin :content_for
|
46
|
+
|
47
|
+
route do |r|
|
48
|
+
r.root do
|
49
|
+
view(:inline => "<% content_for :foo do %>foo<% end %><% content_for :foo do %>baz<% end %>bar", :layout => { :inline => '<%= yield %> <%= content_for(:foo) %>' })
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should replace with multiple calls to the same key by default" do
|
56
|
+
body.strip.must_equal "bar baz"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should append with multiple calls to the same key if :append plugin option is used" do
|
60
|
+
app.plugin :content_for, :append => true
|
61
|
+
body.strip.must_equal "bar foobaz"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
begin
|
67
|
+
require 'tilt/erb'
|
68
|
+
require 'tilt/haml'
|
69
|
+
rescue LoadError
|
70
|
+
warn "tilt or haml not installed, skipping content_for plugin haml tests"
|
71
|
+
else
|
42
72
|
describe "content_for plugin with haml" do
|
43
73
|
before do
|
44
74
|
app(:bare) do
|
@@ -107,28 +137,4 @@ describe "content_for plugin when overriding :engine" do
|
|
107
137
|
body('/a').strip.must_equal "bar\nfoo"
|
108
138
|
end
|
109
139
|
end
|
110
|
-
|
111
|
-
describe "content_for plugin with multiple calls to the same key" do
|
112
|
-
before do
|
113
|
-
app(:bare) do
|
114
|
-
plugin :render, :views => './spec/views'
|
115
|
-
plugin :content_for
|
116
|
-
|
117
|
-
route do |r|
|
118
|
-
r.root do
|
119
|
-
view(:inline => "<% content_for :foo do %>foo<% end %><% content_for :foo do %>baz<% end %>bar", :layout => { :inline => '<%= yield %> <%= content_for(:foo) %>' })
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
it "should replace with multiple calls to the same key by default" do
|
126
|
-
body.strip.must_equal "bar baz"
|
127
|
-
end
|
128
|
-
|
129
|
-
it "should append with multiple calls to the same key if :append plugin option is used" do
|
130
|
-
app.plugin :content_for, :append => true
|
131
|
-
body.strip.must_equal "bar foobaz"
|
132
|
-
end
|
133
|
-
end
|
134
140
|
end
|
data/spec/plugin/h_spec.rb
CHANGED
@@ -3,9 +3,9 @@ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
|
|
3
3
|
describe "h plugin" do
|
4
4
|
it "adds h method for html escaping" do
|
5
5
|
app(:h) do |r|
|
6
|
-
h("<form>") + h(:form)
|
6
|
+
h("<form>") + h(:form) + h("test&<>/'")
|
7
7
|
end
|
8
8
|
|
9
|
-
body.must_equal '<form>
|
9
|
+
body.must_equal '<form>formtest&<>/''
|
10
10
|
end
|
11
11
|
end
|
data/spec/response_spec.rb
CHANGED
@@ -65,6 +65,16 @@ describe "response #finish" do
|
|
65
65
|
header('Content-Length').must_equal '1'
|
66
66
|
end
|
67
67
|
|
68
|
+
it "should not set Content-Type header on a 204 response" do
|
69
|
+
app do |r|
|
70
|
+
response.status = 204
|
71
|
+
throw :halt, response.finish
|
72
|
+
end
|
73
|
+
|
74
|
+
header('Content-Type').must_equal nil
|
75
|
+
header('Content-Length').must_equal nil
|
76
|
+
end
|
77
|
+
|
68
78
|
it "should not overwrite existing status" do
|
69
79
|
app do |r|
|
70
80
|
response.status = 500
|
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: 2.
|
4
|
+
version: 2.19.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: 2016-
|
11
|
+
date: 2016-10-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -184,6 +184,7 @@ extra_rdoc_files:
|
|
184
184
|
- doc/release_notes/2.16.0.txt
|
185
185
|
- doc/release_notes/2.17.0.txt
|
186
186
|
- doc/release_notes/2.18.0.txt
|
187
|
+
- doc/release_notes/2.19.0.txt
|
187
188
|
files:
|
188
189
|
- CHANGELOG
|
189
190
|
- MIT-LICENSE
|
@@ -205,6 +206,7 @@ files:
|
|
205
206
|
- doc/release_notes/2.16.0.txt
|
206
207
|
- doc/release_notes/2.17.0.txt
|
207
208
|
- doc/release_notes/2.18.0.txt
|
209
|
+
- doc/release_notes/2.19.0.txt
|
208
210
|
- doc/release_notes/2.2.0.txt
|
209
211
|
- doc/release_notes/2.3.0.txt
|
210
212
|
- doc/release_notes/2.4.0.txt
|
@@ -420,7 +422,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
420
422
|
version: '0'
|
421
423
|
requirements: []
|
422
424
|
rubyforge_project:
|
423
|
-
rubygems_version: 2.
|
425
|
+
rubygems_version: 2.6.6
|
424
426
|
signing_key:
|
425
427
|
specification_version: 4
|
426
428
|
summary: Routing tree web toolkit
|