roda 2.14.0 → 2.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cde8be71334a4d1be45b77656f9314fbac254bd1
4
- data.tar.gz: 6c100351e8af6103d141f64967971c3e56dec13d
3
+ metadata.gz: 625daaffa474b5553308633c41d20b76fa3096d8
4
+ data.tar.gz: 4bcfc8c8c1258f6860e8ac430ba59679b2c62c69
5
5
  SHA512:
6
- metadata.gz: 9084568d409627ac84c60d16049a6d2c545bdd9ac6cd6ba4dc312720474ccebc4e859dcc559d7e82390b66e04f31b06ee63ba32a288df57a832ea36ed18fd2ef
7
- data.tar.gz: 74b8305898e306b49179ccb05349d4cf25a8fd4f7d481baec071728626a6c1eec99f40fd04faa6d85321e256154db6bf9a74717dbee50a50edad22f552152086
6
+ metadata.gz: 2331dd19bd5efb8c3187df90917c4a23f814d52ec205b553ac1131fb39a787fffc83930ce697011cda5ac6926ab7cf31a209033dfc5589342b9410ff09b6a743
7
+ data.tar.gz: 0abd741f20b87dbe497eba823357ce323aa1d82f7a8048895afe4d5b47eefeb340e50fdf9c71daa8c9cb2c064a5e4f30cda800aa751a345f84f57d2424a6a617
data/CHANGELOG CHANGED
@@ -1,3 +1,13 @@
1
+ = 2.15.0 (2016-06-13)
2
+
3
+ * Add public plugin for r.public method for serving all files in the public directory (jeremyevans)
4
+
5
+ * Make send_file in sinatra_helpers plugin work with Rack 2 (jeremyevans)
6
+
7
+ * Make :header matcher prefixes the env key with HTTP_ if application :header_matcher_prefix option is set (timothypage, jeremyevans) (#69)
8
+
9
+ * Add content_for plugin :append option to support appending to the existing content (evanleck, jeremyevans) (#66)
10
+
1
11
  = 2.14.0 (2016-05-13)
2
12
 
3
13
  * Add symbol_status plugin for using symbols as status codes (Papierkorb) (#65)
data/Rakefile CHANGED
@@ -68,7 +68,7 @@ end
68
68
 
69
69
  spec = proc do |env|
70
70
  env.each{|k,v| ENV[k] = v}
71
- sh "#{FileUtils::RUBY} -rubygems -I lib -e 'ARGV.each{|f| require f}' ./spec/*_spec.rb ./spec/plugin/*_spec.rb"
71
+ sh "#{FileUtils::RUBY} spec/all.rb"
72
72
  env.each{|k,v| ENV.delete(k)}
73
73
  end
74
74
 
@@ -0,0 +1,53 @@
1
+ = New Features
2
+
3
+ * A public plugin has been added. This adds an r.public method
4
+ for serving all files in the public directory. The public
5
+ plugin can replace usage of the static plugin, and is more
6
+ flexible. You can place r.public at any point in the routing
7
+ tree, and it will use the remaining path to lookup the file
8
+ in the public directory. You can also pass the :gzip option
9
+ when loading the plugin, and it will serve already gzipped
10
+ files to the client if the client supports gzipped transfer
11
+ encoding and the file exists with a .gz extension. Example:
12
+
13
+ plugin :public
14
+ route do |r|
15
+ # Serve public files before routing
16
+ r.public
17
+
18
+ # ...
19
+ end
20
+
21
+ * The :header matcher added by the header_matchers plugin now
22
+ automatically prefixes the key with HTTP_ when looking it up in
23
+ the environment, if the :header_matcher_prefix application
24
+ option is set. This behavior will probably be the default in
25
+ Roda 3.
26
+
27
+ # Before
28
+ r.on :header => 'http_accept'
29
+
30
+ # Now, with :header_matcher_prefix=>true application option
31
+ r.on :header => 'accept'
32
+
33
+ * The content_for plugin now accepts an :append=>true option to
34
+ support appending to the existing content instead of overwriting
35
+ the existing content if called multiple times. This behavior
36
+ will probably be the default in Roda 3.
37
+
38
+ # Before
39
+ content_for(:form, 'a')
40
+ content_for(:form, 'b')
41
+ content_for(:form) # => 'b'
42
+
43
+ # Now, with :append=>true option
44
+ content_for(:form, 'a')
45
+ content_for(:form, 'b')
46
+ content_for(:form) # => 'ab'
47
+
48
+ = Other Improvements
49
+
50
+ * The r.send_file method in the sinatra_helpers plugin now works
51
+ correctly when using rack 2.
52
+
53
+ * The specs now run correctly on Windows.
@@ -10,7 +10,7 @@ class Roda
10
10
  # This uses the render plugin for rendering the assets, and the render
11
11
  # plugin uses tilt internally, so you can use any template engine
12
12
  # supported by tilt for your assets. Tilt ships with support for
13
- # the following asset template engines, assuming the necessary libaries
13
+ # the following asset template engines, assuming the necessary libraries
14
14
  # are installed:
15
15
  #
16
16
  # css :: Less, Sass, Scss
@@ -77,7 +77,7 @@ class Roda
77
77
  # assets/css/frontend/some_frontend_file.scss
78
78
  # assets/css/backend/some_backend_file.scss
79
79
  #
80
- # If you want do not want to force that directory structure when using
80
+ # If you do not want to force that directory structure when using
81
81
  # asset groups, you can use the <tt>:group_subdirs => false</tt> option.
82
82
  #
83
83
  # In your view code use an array argument in your call to assets:
@@ -86,7 +86,7 @@ class Roda
86
86
  #
87
87
  # === Nesting
88
88
  #
89
- # Asset groups also supporting nesting, though that should only be needed
89
+ # Asset groups also support nesting, though that should only be needed
90
90
  # in fairly large applications. You can use a nested hash when loading
91
91
  # the plugin:
92
92
  #
@@ -221,7 +221,7 @@ class Roda
221
221
  # :compiled_js_route :: Route under :prefix for compiled javscript assets (default: :compiled_js_dir)
222
222
  # :compiled_name :: Compiled file name prefix (default: 'app')
223
223
  # :compiled_path:: Path inside public folder in which compiled files are stored (default: :prefix)
224
- # :concat_only :: Whether to just concatenate instead of concatentating
224
+ # :concat_only :: Whether to just concatenate instead of concatenating
225
225
  # and compressing files (default: false)
226
226
  # :css_compressor :: Compressor to use for compressing CSS, either :yui, :none, or nil (the default, which will try
227
227
  # :yui if available, but not fail if it is not available)
@@ -26,34 +26,59 @@ class Roda
26
26
  # call content_for without the block:
27
27
  #
28
28
  # <%= content_for :foo %>
29
+ #
30
+ # If content_for is used multiple times with the same key,
31
+ # by default, the last call will override previous calls.
32
+ # If you want to append to the content, pass the :append
33
+ # option when loading the plugin:
34
+ #
35
+ # plugin :content_for, :append=>true
29
36
  module ContentFor
30
37
  # Depend on the render plugin, since this plugin only makes
31
38
  # sense when the render plugin is used.
32
- def self.load_dependencies(app)
39
+ def self.load_dependencies(app, _opts = {})
33
40
  app.plugin :render
34
41
  end
35
42
 
43
+ # Configure whether to append or overwrite if content_for
44
+ # is called multiple times to set data. Overwrite is default, use
45
+ # the :append option to append.
46
+ def self.configure(app, opts = {})
47
+ app.opts[:append_content_for] = opts.fetch(:append, false)
48
+ end
49
+
36
50
  module InstanceMethods
37
51
  # If called with a block, store content enclosed by block
38
52
  # under the given key. If called without a block, retrieve
39
53
  # stored content with the given key, or return nil if there
40
54
  # is no content stored with that key.
41
55
  def content_for(key, value=nil, &block)
42
- if block
43
- outvar = render_opts[:template_opts][:outvar]
44
- buf_was = instance_variable_get(outvar)
45
- # clean the output buffer for ERB-based rendering systems
46
- instance_variable_set(outvar, String.new)
56
+ append = opts[:append_content_for]
47
57
 
48
- @_content_for ||= {}
49
- @_content_for[key] = Tilt[render_opts[:engine]].new(&block).render
58
+ if block || value
59
+ if block
60
+ outvar = render_opts[:template_opts][:outvar]
61
+ buf_was = instance_variable_get(outvar)
62
+
63
+ # Use temporary output buffer for ERB-based rendering systems
64
+ instance_variable_set(outvar, String.new)
65
+ value = Tilt[render_opts[:engine]].new(&block).render
66
+ instance_variable_set(outvar, buf_was)
67
+ end
50
68
 
51
- instance_variable_set(outvar, buf_was)
52
- elsif value
53
69
  @_content_for ||= {}
54
- @_content_for[key] = value
55
- elsif @_content_for
56
- @_content_for[key]
70
+
71
+ if append
72
+ (@_content_for[key] ||= []) << value
73
+ else
74
+ @_content_for[key] = value
75
+ end
76
+ elsif @_content_for && (value = @_content_for[key])
77
+ if append
78
+ value = value.join
79
+ end
80
+
81
+ value
57
82
  end
58
83
  end
59
84
  end
@@ -11,7 +11,16 @@ class Roda
11
11
  # It adds a +:header+ matcher for matching on arbitrary headers, which matches
12
12
  # if the header is present:
13
13
  #
14
+ # r.on :header=>'HTTP-X-App-Token' do |header_value|
15
+ # # Looks for env['HTTP_X_APP_TOKEN']
16
+ # end
17
+ #
18
+ # For backwards compatibility, the header value is not automatically prefixed
19
+ # with HTTP_. You can set the +:header_matcher_prefix+ option for the application,
20
+ # which will automatically prefix the header with HTTP_:
21
+ #
14
22
  # r.on :header=>'X-App-Token' do |header_value|
23
+ # # Looks for env['HTTP_X_APP_TOKEN']
15
24
  # end
16
25
  #
17
26
  # It adds a +:host+ matcher for matching by the host of the request:
@@ -54,7 +63,13 @@ class Roda
54
63
 
55
64
  # Match if the given uppercase key is present inside the environment.
56
65
  def match_header(key)
57
- if v = @env[key.upcase.tr("-","_")]
66
+ key = key.upcase.tr("-","_")
67
+
68
+ if roda_class.opts[:header_matcher_prefix]
69
+ key = "HTTP_#{key}"
70
+ end
71
+
72
+ if v = @env[key]
58
73
  @captures << v
59
74
  end
60
75
  end
@@ -0,0 +1,114 @@
1
+ # frozen-string-literal: true
2
+
3
+ require 'uri'
4
+
5
+ #
6
+ class Roda
7
+ module RodaPlugins
8
+ # The public plugin adds a +r.public+ routing method to serve static files
9
+ # from a directory.
10
+ #
11
+ # The public plugin recognizes the application's :root option, and defaults to
12
+ # using the +public+ subfolder of the application's +:root+ option. If the application's
13
+ # :root option is not set, it defaults to the the +public+ folder in the working
14
+ # directory. Additionally, if a relative path is provided as the :root
15
+ # option to the plugin, it will be considered relative to the application's
16
+ # +:root+ option.
17
+ #
18
+ # Examples:
19
+ #
20
+ # opts[:root] = '/path/to/app'
21
+ # plugin :public
22
+ # plugin :public, :root=>'static'
23
+ module Public
24
+ NULL_BYTE = "\0".freeze
25
+ SPLIT = Regexp.union(*[File::SEPARATOR, File::ALT_SEPARATOR].compact)
26
+ PARSER = RUBY_VERSION >= '1.9' ? URI::DEFAULT_PARSER : URI
27
+
28
+ # Use options given to setup a Rack::File instance for serving files. Options:
29
+ # :default_mime :: The default mime type to use if the mime type is not recognized.
30
+ # :gzip :: Whether to serve already gzipped files with a .gz extension for clients
31
+ # supporting gzipped transfer encoding.
32
+ # :headers :: A hash of headers to use for statically served files
33
+ # :root :: Use this option for the root of the public directory (default: "public")
34
+ def self.configure(app, opts={})
35
+ root = File.expand_path(opts[:root]||"public", app.opts[:root])
36
+ app.opts[:public_server] = ::Rack::File.new(root, opts[:headers]||{}, opts[:default_mime] || 'text/plain')
37
+ app.opts[:public_gzip] = opts[:gzip]
38
+ end
39
+
40
+ module RequestMethods
41
+ # Serve files from the public directory if the file exists and this is a GET request.
42
+ def public
43
+ if is_get?
44
+ path = PARSER.unescape(remaining_path)
45
+ return if path.include?(NULL_BYTE)
46
+
47
+ roda_opts = roda_class.opts
48
+ server = roda_opts[:public_server]
49
+ path = ::File.join(server.root, *public_path_segments(path))
50
+
51
+ if roda_opts[:public_gzip] && env['HTTP_ACCEPT_ENCODING'] =~ /\bgzip\b/
52
+ gzip_path = path + '.gz'
53
+
54
+ if public_file_readable?(gzip_path)
55
+ res = public_serve(server, gzip_path)
56
+ headers = res[1]
57
+
58
+ if mime_type = ::Rack::Mime.mime_type(::File.extname(path), 'text/plain')
59
+ headers['Content-Type'] = mime_type
60
+ end
61
+ headers['Content-Encoding'] = 'gzip'
62
+
63
+ halt res
64
+ end
65
+ end
66
+
67
+ if public_file_readable?(path)
68
+ halt public_serve(server, path)
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+
75
+ # Return an array of segments for the given path, handling ..
76
+ # and . components
77
+ def public_path_segments(path)
78
+ segments = []
79
+
80
+ path.split(SPLIT).each do |seg|
81
+ next if seg.empty? || seg == '.'
82
+ seg == '..' ? segments.pop : segments << seg
83
+ end
84
+
85
+ segments
86
+ end
87
+
88
+ # Return whether the given path is a readable regular file.
89
+ def public_file_readable?(path)
90
+ ::File.file?(path) && ::File.readable?(path)
91
+ rescue SystemCallError
92
+ false
93
+ end
94
+
95
+ if ::Rack.release > '2'
96
+ # :nocov:
97
+ def public_serve(server, path)
98
+ server.serving(self, path)
99
+ end
100
+ # :nocov:
101
+ else
102
+ # Serve the given path using the given Rack::File server.
103
+ def public_serve(server, path)
104
+ server = server.dup
105
+ server.path = path
106
+ server.serving(env)
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ register_plugin(:public, Public)
113
+ end
114
+ end
@@ -339,9 +339,15 @@ class Roda
339
339
  last_modified(lm)
340
340
  end
341
341
 
342
- file = ::Rack::File.new nil
343
- file.path = path
344
- s, h, b = file.serving(@env)
342
+ file = ::Rack::File.new nil
343
+ s, h, b = if Rack.release > '2'
344
+ # :nocov:
345
+ file.serving(self, path)
346
+ # :nocov:
347
+ else
348
+ file.path = path
349
+ file.serving(@env)
350
+ end
345
351
 
346
352
  res.status = opts[:status] || s
347
353
  headers.delete(CONTENT_LENGTH)
@@ -15,6 +15,8 @@ class Roda
15
15
  #
16
16
  # Since the :urls option for Rack::Static is always required, the static plugin
17
17
  # uses a separate option for it.
18
+ #
19
+ # Users of this plugin may want to consider using the public plugin instead.
18
20
  #
19
21
  # Examples:
20
22
  #
data/lib/roda/version.rb CHANGED
@@ -4,7 +4,7 @@ class Roda
4
4
  RodaMajorVersion = 2
5
5
 
6
6
  # The minor version of Roda, updated for new feature releases of Roda.
7
- RodaMinorVersion = 14
7
+ RodaMinorVersion = 15
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
data/spec/all.rb ADDED
@@ -0,0 +1,3 @@
1
+ $:.unshift(File.expand_path("../lib", File.dirname(__FILE__)))
2
+ require 'rubygems'
3
+ (Dir['./spec/*_spec.rb'] + Dir['./spec/plugin/*_spec.rb']).each{|f| require f}
@@ -2,12 +2,18 @@ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
2
 
3
3
  begin
4
4
  require 'erubis'
5
+ require 'tilt'
5
6
  require 'tilt/erb'
6
7
  begin
7
8
  require 'tilt/erubis'
8
9
  rescue LoadError
9
10
  # Tilt 1 support
10
11
  end
12
+
13
+ if defined?(Tilt::ErubisTemplate) && ::Tilt['erb'] != Tilt::ErubisTemplate
14
+ # Work around error where erubis isn't set as erb template handler
15
+ Tilt.register(Tilt::ErubisTemplate, 'erb')
16
+ end
11
17
  rescue LoadError
12
18
  warn "tilt or erubis not installed, skipping _erubis_escaping plugin test"
13
19
  else
@@ -564,15 +564,16 @@ if run_tests
564
564
 
565
565
  app.opts[:root] = '/foo'
566
566
  app.plugin :assets
567
- app.assets_opts[:path].must_equal '/foo/assets'
568
- app.assets_opts[:js_path].must_equal '/foo/assets/js/'
569
- app.assets_opts[:css_path].must_equal '/foo/assets/css/'
567
+ # Work around for Windows
568
+ app.assets_opts[:path].sub(/\A\w:/, '').must_equal '/foo/assets'
569
+ app.assets_opts[:js_path].sub(/\A\w:/, '').must_equal '/foo/assets/js/'
570
+ app.assets_opts[:css_path].sub(/\A\w:/, '').must_equal '/foo/assets/css/'
570
571
 
571
572
  app.opts[:root] = '/foo/bar'
572
573
  app.plugin :assets
573
- app.assets_opts[:path].must_equal '/foo/bar/assets'
574
- app.assets_opts[:js_path].must_equal '/foo/bar/assets/js/'
575
- app.assets_opts[:css_path].must_equal '/foo/bar/assets/css/'
574
+ app.assets_opts[:path].sub(/\A\w:/, '').must_equal '/foo/bar/assets'
575
+ app.assets_opts[:js_path].sub(/\A\w:/, '').must_equal '/foo/bar/assets/js/'
576
+ app.assets_opts[:css_path].sub(/\A\w:/, '').must_equal '/foo/bar/assets/css/'
576
577
 
577
578
  app.opts[:root] = nil
578
579
  app.plugin :assets
@@ -107,4 +107,28 @@ describe "content_for plugin when overriding :engine" do
107
107
  body('/a').strip.must_equal "bar\nfoo"
108
108
  end
109
109
  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
110
134
  end
@@ -22,22 +22,34 @@ describe "header matcher" do
22
22
  end
23
23
 
24
24
  body("HTTP_ACCEPT" => "application/xml").must_equal "bar"
25
+ status("HTTP_HTTP_ACCEPT" => "application/xml").must_equal 404
25
26
  status.must_equal 404
26
27
  end
27
28
 
28
- it "should yield the header value if :match_header_yield option is present" do
29
+ it "should yield the header value" do
30
+ app(:header_matchers) do |r|
31
+ r.on :header=>"http-accept" do |v|
32
+ "bar-#{v}"
33
+ end
34
+ end
35
+
36
+ body("HTTP_ACCEPT" => "application/xml").must_equal "bar-application/xml"
37
+ status.must_equal 404
38
+ end
39
+
40
+ it "should automatically use HTTP prefix for headers if :header_matcher_prefix is set" do
29
41
  app(:bare) do
30
42
  plugin :header_matchers
31
- opts[:match_header_yield] = true
43
+ opts[:header_matcher_prefix] = true
32
44
  route do |r|
33
- r.on :header=>"http-accept" do |v|
45
+ r.on :header=>"accept" do |v|
34
46
  "bar-#{v}"
35
47
  end
36
48
  end
37
49
  end
38
50
 
39
51
  body("HTTP_ACCEPT" => "application/xml").must_equal "bar-application/xml"
40
- status.must_equal 404
52
+ status("ACCEPT"=>"application/xml").must_equal 404
41
53
  end
42
54
  end
43
55
 
@@ -0,0 +1,62 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "public plugin" do
4
+ it "adds r.public for serving static files from public folder" do
5
+ app(:bare) do
6
+ plugin :public, :root=>'spec/views'
7
+
8
+ route do |r|
9
+ r.public
10
+
11
+ r.on 'static' do
12
+ r.public
13
+ end
14
+ end
15
+ end
16
+
17
+ status("/about/_test.erb\0").must_equal 404
18
+ body('/about/_test.erb').must_equal File.read('spec/views/about/_test.erb')
19
+ body('/static/about/_test.erb').must_equal File.read('spec/views/about/_test.erb')
20
+ body('/foo/.././/about/_test.erb').must_equal File.read('spec/views/about/_test.erb')
21
+ end
22
+
23
+ it "respects the application's :root option" do
24
+ app(:bare) do
25
+ opts[:root] = File.expand_path('../../', __FILE__)
26
+ plugin :public, :root=>'views'
27
+
28
+ route do |r|
29
+ r.public
30
+ end
31
+ end
32
+
33
+ body('/about/_test.erb').must_equal File.read('spec/views/about/_test.erb')
34
+ end
35
+
36
+ it "handles serving gzip files in gzip mode if client supports gzip" do
37
+ app(:bare) do
38
+ plugin :public, :root=>'spec/views', :gzip=>true
39
+
40
+ route do |r|
41
+ r.public
42
+ end
43
+ end
44
+
45
+ body('/about/_test.erb').must_equal File.read('spec/views/about/_test.erb')
46
+ header('Content-Encoding', '/about/_test.erb').must_equal nil
47
+
48
+ body('/about.erb').must_equal File.read('spec/views/about.erb')
49
+ header('Content-Encoding', '/about.erb').must_equal nil
50
+
51
+ meth = RUBY_VERSION >= '1.9' ? :binread : :read
52
+ body('/about/_test.erb', 'HTTP_ACCEPT_ENCODING'=>'deflate, gzip').must_equal File.send(meth, 'spec/views/about/_test.erb.gz')
53
+ h = req('/about/_test.erb', 'HTTP_ACCEPT_ENCODING'=>'deflate, gzip')[1]
54
+ h['Content-Encoding'].must_equal 'gzip'
55
+ h['Content-Type'].must_equal 'text/plain'
56
+
57
+ body('/about/_test.css', 'HTTP_ACCEPT_ENCODING'=>'deflate, gzip').must_equal File.send(meth, 'spec/views/about/_test.css.gz')
58
+ h = req('/about/_test.css', 'HTTP_ACCEPT_ENCODING'=>'deflate, gzip')[1]
59
+ h['Content-Encoding'].must_equal 'gzip'
60
+ h['Content-Type'].must_equal 'text/css'
61
+ end
62
+ end
@@ -189,11 +189,12 @@ describe "render plugin" do
189
189
 
190
190
  app.opts[:root] = '/foo'
191
191
  app.plugin :render
192
- app.render_opts[:views].must_equal '/foo/views'
192
+ # Work around for Windows
193
+ app.render_opts[:views].sub(/\A\w:/, '').must_equal '/foo/views'
193
194
 
194
195
  app.opts[:root] = '/foo/bar'
195
196
  app.plugin :render
196
- app.render_opts[:views].must_equal '/foo/bar/views'
197
+ app.render_opts[:views].sub(/\A\w:/, '').must_equal '/foo/bar/views'
197
198
 
198
199
  app.opts[:root] = nil
199
200
  app.plugin :render
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.14.0
4
+ version: 2.15.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-05-13 00:00:00.000000000 Z
11
+ date: 2016-06-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -180,6 +180,7 @@ extra_rdoc_files:
180
180
  - doc/release_notes/2.12.0.txt
181
181
  - doc/release_notes/2.13.0.txt
182
182
  - doc/release_notes/2.14.0.txt
183
+ - doc/release_notes/2.15.0.txt
183
184
  files:
184
185
  - CHANGELOG
185
186
  - MIT-LICENSE
@@ -197,6 +198,7 @@ files:
197
198
  - doc/release_notes/2.12.0.txt
198
199
  - doc/release_notes/2.13.0.txt
199
200
  - doc/release_notes/2.14.0.txt
201
+ - doc/release_notes/2.15.0.txt
200
202
  - doc/release_notes/2.2.0.txt
201
203
  - doc/release_notes/2.3.0.txt
202
204
  - doc/release_notes/2.4.0.txt
@@ -259,6 +261,7 @@ files:
259
261
  - lib/roda/plugins/path_rewriter.rb
260
262
  - lib/roda/plugins/per_thread_caching.rb
261
263
  - lib/roda/plugins/precompile_templates.rb
264
+ - lib/roda/plugins/public.rb
262
265
  - lib/roda/plugins/render.rb
263
266
  - lib/roda/plugins/render_each.rb
264
267
  - lib/roda/plugins/response_request.rb
@@ -277,6 +280,7 @@ files:
277
280
  - lib/roda/plugins/view_subdirs.rb
278
281
  - lib/roda/plugins/websockets.rb
279
282
  - lib/roda/version.rb
283
+ - spec/all.rb
280
284
  - spec/assets/css/app.scss
281
285
  - spec/assets/css/no_access.css
282
286
  - spec/assets/css/raw.css
@@ -339,6 +343,7 @@ files:
339
343
  - spec/plugin/path_spec.rb
340
344
  - spec/plugin/per_thread_caching_spec.rb
341
345
  - spec/plugin/precompile_templates_spec.rb
346
+ - spec/plugin/public_spec.rb
342
347
  - spec/plugin/render_each_spec.rb
343
348
  - spec/plugin/render_spec.rb
344
349
  - spec/plugin/response_request_spec.rb