roda 2.6.0 → 2.7.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: 81b5d148505b95423a029a85acb7ab453ad50518
4
- data.tar.gz: 825e0915b23389bb468b335fcadd2c102362f6ab
3
+ metadata.gz: ba4bf20bc11b1e1d4482325c64d4ae439a7665dd
4
+ data.tar.gz: 2f17d46442001a41ba9223db2b71545d11e7ac3e
5
5
  SHA512:
6
- metadata.gz: c2c7ba330521161433166bd7ca685619366459800a28fa06b4a2328232cfced10a796ddd67aa16927a1be44ee3b31c1c8848847b987dd87d506ae501e3acf78c
7
- data.tar.gz: c35370d775528f676f4ad1be2c9cc277f4d0d1082a7750a62418c28ebadc85b6e01056ad4699ea866e55941a8747323f8d3c666faa2b58c265027343685f6ae8
6
+ metadata.gz: 747c00137a2db4494558398d0e85a659c8d247ef330431239787d135cd7213c91ef5cfdb5585c315b76676b8a016a64f33ee4c6d711927e04ed95839e537430e
7
+ data.tar.gz: 930fd61e842f5ca4bbbbf19c9efcfb881e10651f2e2f9f7029388d9c0d84fc27d1cbae5f364e7248aa33edb011d8fbf82518a3a7074844990a58e818fb517fb6
data/CHANGELOG CHANGED
@@ -1,3 +1,17 @@
1
+ = 2.7.0 (2015-10-13)
2
+
3
+ * Add run_handler plugin for modifying rack response arrays when using r.run, and continuing routing for 404 responses (jeremyevans)
4
+
5
+ * Add response_request plugin allowing response object access to request object (jeremyevans)
6
+
7
+ * Add default_status plugin for overriding the default response status (celsworth) (#47)
8
+
9
+ * Make RodaCache synchronize access on MRI (jeremyevans)
10
+
11
+ * Support opts[:host_matcher_captures] = true to make :host=>/regexp/ matcher yield captures in the header_matchers plugin (jeremyevans)
12
+
13
+ * Allow Roda.rewrite_path to take a block in the path_rewriter plugin (Freaky) (#45)
14
+
1
15
  = 2.6.0 (2015-09-14)
2
16
 
3
17
  * Add :params and :params! matchers to param_matchers plugin (jeremyevans)
@@ -0,0 +1,75 @@
1
+ = New Features
2
+
3
+ * A default_status plugin has been added for changing the default
4
+ status for responses. Previously, the default status was hard
5
+ coded to 200, this plugin allows you to change it. The plugin
6
+ takes a block which is instance_evaled in the context of the
7
+ response:
8
+
9
+ plugin :default_status do
10
+ headers['Content-Type'] == 'foo' ? 201 : 200
11
+ end
12
+
13
+ Note that the default status for empty responses (used when no
14
+ route handles the response) is still 404, this just changes the
15
+ default for non-empty responses.
16
+
17
+ * A response_request plugin has been added for giving the response
18
+ instance access to the related request. This can be useful in
19
+ conjunction with the default_status plugin, if you want the
20
+ default status of the response to depend on the request, such as
21
+ using a different status for different request methods:
22
+
23
+ plugin :response_request
24
+ plugin :default_status do
25
+ request.post? ? 201 : 200
26
+ end
27
+
28
+ * A run_handler plugin has been added, for modifying rack response
29
+ arrays before returning them when using r.run. Additionally, it
30
+ allows for continuing with routing if the response returned by
31
+ r.run is a 404 response, using the :not_found=>:pass option:
32
+
33
+ plugin :run_handler
34
+ route do |r|
35
+ # Keep running code if RackAppFoo returns a 404 response
36
+ r.run RackAppFoo, :not_found=>:pass
37
+
38
+ # Change response status codes before returning.
39
+ r.run(RackAppBar) do |response|
40
+ response[0] = 200 if response[0] == 201
41
+ end
42
+ end
43
+
44
+ * Roda.rewite_path in the path_rewriter extension now accepts a block
45
+ to allow for dynamic replacements. The block is yielded a MatchData
46
+ instance:
47
+
48
+ rewrite_path(/\A\/a/(\w+)/){|match| match[1].capitalize}
49
+ # PATH_INFO '/a/moo' => remaining_path '/a/Moo'
50
+
51
+ rewrite_path(/\A\/a/(\w+)/, :path_info => true) do |match|
52
+ match[1].capitalize
53
+ end
54
+ # PATH_INFO '/a/moo' => PATH_INFO '/a/Moo'
55
+
56
+ * The :host matcher in the header_matchers plugin will now yield the
57
+ regexp captures to the block if given a regexp when the
58
+ :host_matcher_captures application option is set. This behavior
59
+ will become the default behavior in Roda 3. This will allow for
60
+ code like:
61
+
62
+ opts[:host_matcher_captures] = true
63
+ route do |r|
64
+ r.on :host=>/\A(\w+).example.com\z/ do |subdomain|
65
+ # ...
66
+ end
67
+ end
68
+
69
+ = Other Improvements
70
+
71
+ * RodaCache now uses a mutex to synchronize access on MRI.
72
+ Previously, it relied on the global interpreter lock, but testing
73
+ has shown that is not reliable in all cases. RodaCache has always
74
+ used a mutex for synchronization on other ruby implementations,
75
+ this just extends that code to MRI as well.
data/lib/roda.rb CHANGED
@@ -9,33 +9,24 @@ class Roda
9
9
  # Error class raised by Roda
10
10
  class RodaError < StandardError; end
11
11
 
12
- if defined?(RUBY_ENGINE) && RUBY_ENGINE != 'ruby'
13
- # :nocov:
14
- # A thread safe cache class, offering only #[] and #[]= methods,
15
- # each protected by a mutex. Used on non-MRI where Hash is not
16
- # thread safe.
17
- class RodaCache
18
- # Create a new thread safe cache.
19
- def initialize
20
- @mutex = Mutex.new
21
- @hash = {}
22
- end
12
+ # A thread safe cache class, offering only #[] and #[]= methods,
13
+ # each protected by a mutex.
14
+ class RodaCache
15
+ # Create a new thread safe cache.
16
+ def initialize
17
+ @mutex = Mutex.new
18
+ @hash = {}
19
+ end
23
20
 
24
- # Make getting value from underlying hash thread safe.
25
- def [](key)
26
- @mutex.synchronize{@hash[key]}
27
- end
21
+ # Make getting value from underlying hash thread safe.
22
+ def [](key)
23
+ @mutex.synchronize{@hash[key]}
24
+ end
28
25
 
29
- # Make setting value in underlying hash thread safe.
30
- def []=(key, value)
31
- @mutex.synchronize{@hash[key] = value}
32
- end
26
+ # Make setting value in underlying hash thread safe.
27
+ def []=(key, value)
28
+ @mutex.synchronize{@hash[key] = value}
33
29
  end
34
- # :nocov:
35
- else
36
- # Hashes are already thread-safe in MRI, due to the GVL, so they
37
- # can safely be used as a cache.
38
- RodaCache = Hash
39
30
  end
40
31
 
41
32
  # Base class used for Roda requests. The instance methods for this
@@ -233,7 +224,7 @@ class Roda
233
224
  # This is the same object yielded by Roda.route.
234
225
  # response :: The instance of the response class related to this request.
235
226
  module InstanceMethods
236
- # Create a request and response of the appopriate class
227
+ # Create a request and response of the appropriate class
237
228
  def initialize(env)
238
229
  klass = self.class
239
230
  @_request = klass::RodaRequest.new(self, env)
@@ -882,9 +873,9 @@ class Roda
882
873
 
883
874
  # Return the rack response array of status, headers, and body
884
875
  # for the current response. If the status has not been set,
885
- # uses a 200 status if the body has been written to, otherwise
886
- # uses a 404 status. Adds the Content-Length header to the
887
- # size of the response body.
876
+ # uses the return value of default_status if the body has
877
+ # been written to, otherwise uses a 404 status.
878
+ # Adds the Content-Length header to the size of the response body.
888
879
  #
889
880
  # Example:
890
881
  #
@@ -894,7 +885,7 @@ class Roda
894
885
  # # []]
895
886
  def finish
896
887
  b = @body
897
- s = (@status ||= b.empty? ? 404 : 200)
888
+ s = (@status ||= b.empty? ? 404 : default_status)
898
889
  set_default_headers
899
890
  h = @headers
900
891
  h[CONTENT_LENGTH] ||= @length.to_s
@@ -907,7 +898,14 @@ class Roda
907
898
  # body.
908
899
  def finish_with_body(body)
909
900
  set_default_headers
910
- [@status || 200, @headers, body]
901
+ [@status || default_status, @headers, body]
902
+ end
903
+
904
+ # Return the default response status to be used when the body
905
+ # has been written to. This is split out to make overriding
906
+ # easier in plugins.
907
+ def default_status
908
+ 200
911
909
  end
912
910
 
913
911
  # Show response class, status code, response headers, and response body
@@ -185,6 +185,18 @@ class Roda
185
185
  # end
186
186
  # end
187
187
  #
188
+ # == External Assets/Assets from Gems
189
+ #
190
+ # The assets plugin only supports loading assets files underneath the assets
191
+ # path. You cannot pass an absolute path to an asset file and have it
192
+ # work. If you would like to reference asset files that are outside the assets
193
+ # path, you have the following options:
194
+ #
195
+ # * Copy, hard link, or symlink the external assets files into the assets path.
196
+ # * Use tilt-indirect or another method of indirection (such as an erb template that loads
197
+ # the external asset file) so that a file inside the assets path can reference files
198
+ # outside the assets path.
199
+ #
188
200
  # == Plugin Options
189
201
  #
190
202
  # :add_suffix :: Whether to append a .css or .js extension to asset routes in non-compiled mode
@@ -0,0 +1,33 @@
1
+ class Roda
2
+ module RodaPlugins
3
+ # The default_status plugin accepts a block which should
4
+ # return a response status integer. This integer will be used as
5
+ # the default response status (usually 200) if the body has been
6
+ # written to, and you have not explicitly set a response status.
7
+ # The block given to the block is instance_execed in the context
8
+ # of the response.
9
+ #
10
+ # Example:
11
+ #
12
+ # # Use 201 default response status for all requests
13
+ # plugin :default_status do
14
+ # 201
15
+ # end
16
+ module DefaultStatus
17
+ def self.configure(app, &block)
18
+ raise RodaError, "default_status plugin requires a block" unless block
19
+ app.opts[:default_status] = block
20
+ end
21
+
22
+ module ResponseMethods
23
+ # instance_exec the default_status plugin block to get the response
24
+ # status.
25
+ def default_status
26
+ instance_exec(&roda_class.opts[:default_status])
27
+ end
28
+ end
29
+ end
30
+
31
+ register_plugin(:default_status, DefaultStatus)
32
+ end
33
+ end
@@ -31,7 +31,13 @@ class Roda
31
31
  # r.halt(403, {'Content-Type'=>'text/csv'}, 'body')
32
32
  # end
33
33
  #
34
- # Note that there is a difference between provide status, headers, and body as separate
34
+ # As supported by default, you can still pass an array which contains a rack response:
35
+ #
36
+ # route do |r|
37
+ # r.halt([403, {'Content-Type'=>'text/csv'}, ['body']])
38
+ # end
39
+ #
40
+ # Note that there is a difference between providing status, headers, and body as separate
35
41
  # arguments and providing them as a single rack response array. With a rack response array,
36
42
  # the values are used directly, while with 3 arguments, the headers given are merged into
37
43
  # the existing headers and the given body is written to the existing response body.
@@ -15,7 +15,14 @@ class Roda
15
15
  #
16
16
  # r.on :host=>'foo.example.com' do
17
17
  # end
18
- # r.on :host=>/\A\w+.example.com/ do
18
+ # r.on :host=>/\A\w+.example.com\z/ do
19
+ # end
20
+ #
21
+ # By default the +:host+ matcher does not yield matchers, but if you use a regexp
22
+ # and set the +:host_matcher_captures+ option for the application, it will
23
+ # yield regexp captures:
24
+ #
25
+ # r.on :host=>/\A(\w+).example.com\z/ do |subdomain|
19
26
  # end
20
27
  #
21
28
  # It adds a +:user_agent+ matcher for matching on a user agent patterns, which
@@ -52,7 +59,13 @@ class Roda
52
59
  # Match if the host of the request is the same as the hostname. +hostname+
53
60
  # can be a regexp or a string.
54
61
  def match_host(hostname)
55
- hostname === host
62
+ if hostname.is_a?(Regexp) && roda_class.opts[:host_matcher_captures]
63
+ if match = hostname.match(host)
64
+ @captures.concat(match.captures)
65
+ end
66
+ else
67
+ hostname === host
68
+ end
56
69
  end
57
70
 
58
71
  # Match the submitted user agent to the given pattern, capturing any
@@ -30,6 +30,14 @@ class Roda
30
30
  # # PATH_INFO '/a' => remaining_path '/b'
31
31
  # # PATH_INFO '/a/c' => remaining_path '/a/c', no change
32
32
  #
33
+ # Patterns can be rewritten dynamically by providing a block accepting a MatchData
34
+ # object and evaluating to the replacement.
35
+ #
36
+ # rewrite_path(/\A\/a/(\w+)/){|match| match[1].capitalize}
37
+ # # PATH_INFO '/a/moo' => remaining_path '/a/Moo'
38
+ # rewrite_path(/\A\/a/(\w+)/, :path_info => true){|match| match[1].capitalize}
39
+ # # PATH_INFO '/a/moo' => PATH_INFO '/a/Moo'
40
+ #
33
41
  # All path rewrites are applied in order, so if a path is rewritten by one rewrite,
34
42
  # it can be rewritten again by a later rewrite. Note that PATH_INFO rewrites are
35
43
  # processed before remaining_path rewrites.
@@ -54,7 +62,18 @@ class Roda
54
62
 
55
63
  # Record a path rewrite from path +was+ to path +is+. Options:
56
64
  # :path_info :: Modify PATH_INFO, not just remaining path.
57
- def rewrite_path(was, is, opts=OPTS)
65
+ def rewrite_path(was, is = nil, opts=OPTS, &block)
66
+ if is.is_a? Hash
67
+ raise RodaError, "cannot provide two hashes to rewrite_path" unless opts.empty?
68
+ opts = is
69
+ is = nil
70
+ end
71
+
72
+ if block
73
+ raise RodaError, "cannot provide both block and string replacement to rewrite_path" if is
74
+ is = block
75
+ end
76
+
58
77
  was = /\A#{Regexp.escape(was)}/ unless was.is_a?(Regexp)
59
78
  array = @opts[opts[:path_info] ? :path_info_rewrites : :remaining_path_rewrites]
60
79
  array << [was, is.dup.freeze].freeze
@@ -65,13 +84,23 @@ class Roda
65
84
  # Rewrite remaining_path and/or PATH_INFO based on the path rewrites.
66
85
  def initialize(scope, env)
67
86
  path_info = env[PATH_INFO]
68
- scope.class.opts[:path_info_rewrites].each do |was, is|
69
- path_info.sub!(was, is)
70
- end
87
+
88
+ rewrite_path(scope.class.opts[:path_info_rewrites], path_info)
71
89
  super
72
90
  remaining_path = @remaining_path = @remaining_path.dup
73
- scope.class.opts[:remaining_path_rewrites].each do |was, is|
74
- remaining_path.sub!(was, is)
91
+ rewrite_path(scope.class.opts[:remaining_path_rewrites], remaining_path)
92
+ end
93
+
94
+ private
95
+
96
+ # Rewrite the given path using the given replacements.
97
+ def rewrite_path(replacements, path)
98
+ replacements.each do |was, is|
99
+ if is.is_a?(Proc)
100
+ path.sub!(was){is.call($~)}
101
+ else
102
+ path.sub!(was, is)
103
+ end
75
104
  end
76
105
  end
77
106
  end
@@ -0,0 +1,26 @@
1
+ class Roda
2
+ module RodaPlugins
3
+ # The response_request plugin gives the response access to the
4
+ # related request instance via the #request method.
5
+ #
6
+ # Example:
7
+ #
8
+ # plugin :response_request
9
+ module ResponseRequest
10
+ module InstanceMethods
11
+ # Set the response's request to the current request.
12
+ def initialize(env)
13
+ super
14
+ @_response.request = @_request
15
+ end
16
+ end
17
+
18
+ module ResponseMethods
19
+ # The request related to this response.
20
+ attr_accessor :request
21
+ end
22
+ end
23
+
24
+ register_plugin(:response_request, ResponseRequest)
25
+ end
26
+ end
@@ -0,0 +1,44 @@
1
+ class Roda
2
+ module RodaPlugins
3
+ # The run_handler plugin allows r.run to take a block, which is yielded
4
+ # the rack response array, before it returns it as a response.
5
+ #
6
+ # Additionally, r.run also takes a options hash, and you can provide a
7
+ # <tt>:not_found=>:pass</tt> option to keep routing normally if the rack
8
+ # app returns a 404 response.
9
+ #
10
+ #
11
+ # plugin :run_handler
12
+ #
13
+ # route do |r|
14
+ # r.on 'a' do
15
+ # # Keep running code if RackAppFoo doesn't return a result
16
+ # r.run RackAppFoo, :not_found=>:pass
17
+ #
18
+ # # Change response status codes before returning.
19
+ # r.run(RackAppBar) do |response|
20
+ # response[0] = 200 if response[0] == 201
21
+ # end
22
+ # end
23
+ # end
24
+ module RunHandler
25
+ OPTS = {}.freeze
26
+
27
+ module RequestMethods
28
+ # If a block is given, yield the rack response array to it. The response can
29
+ # be modified before it is returned by the current app.
30
+ #
31
+ # If the <tt>:not_found=>:pass</tt> option is given, and the rack response
32
+ # returned by the app is a 404 response, do not return the response, continue
33
+ # routing normally.
34
+ def run(app, opts=OPTS)
35
+ res = catch(:halt){super(app)}
36
+ yield res if block_given?
37
+ throw(:halt, res) unless opts[:not_found] == :pass && res[0] == 404
38
+ end
39
+ end
40
+ end
41
+
42
+ register_plugin(:run_handler, RunHandler)
43
+ end
44
+ end
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 = 6
7
+ RodaMinorVersion = 7
8
8
 
9
9
  # The patch version of Roda, updated only for bug fixes from the last
10
10
  # feature release.
@@ -0,0 +1,65 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "default_status plugin" do
4
+ it "sets the default response status to use for the response" do
5
+ app(:bare) do
6
+ plugin :default_status do
7
+ 201
8
+ end
9
+ route do |r|
10
+ r.halt response.finish_with_body([])
11
+ end
12
+ end
13
+
14
+ status.must_equal 201
15
+ end
16
+
17
+ it "should instance_exec the plugin block" do
18
+ app(:bare) do
19
+ plugin :default_status do
20
+ 200 + @body[0].length
21
+ end
22
+ route do |r|
23
+ r.path_info
24
+ end
25
+ end
26
+
27
+ status.must_equal 201
28
+ status('/foo').must_equal 204
29
+ end
30
+
31
+ it "should not override existing response" do
32
+ app(:bare) do
33
+ plugin :default_status do
34
+ 201
35
+ end
36
+
37
+ route do |r|
38
+ response.status = 202
39
+ r.halt response.finish_with_body([])
40
+ end
41
+ end
42
+
43
+ status.must_equal 202
44
+ end
45
+
46
+ it "should work correctly in subclasses" do
47
+ app(:bare) do
48
+ plugin :default_status do
49
+ 201
50
+ end
51
+
52
+ route do |r|
53
+ r.halt response.finish_with_body([])
54
+ end
55
+ end
56
+
57
+ @app = Class.new(@app)
58
+
59
+ status.must_equal 201
60
+ end
61
+
62
+ it "should raise if not given a block" do
63
+ proc{app(:default_status)}.must_raise Roda::RodaError
64
+ end
65
+ end
@@ -69,6 +69,16 @@ describe "halt plugin" do
69
69
  body.must_equal "foo"
70
70
  end
71
71
 
72
+ it "should consider an array as a rack response" do
73
+ app(:halt) do |r|
74
+ r.halt [300, {'a'=>'b'}, ["foo"]]
75
+ end
76
+
77
+ status.must_equal 300
78
+ header('a').must_equal 'b'
79
+ body.must_equal "foo"
80
+ end
81
+
72
82
  it "should handle 3rd of 3 arguments similar to block bodies" do
73
83
  app(:bare) do
74
84
  plugin :halt
@@ -64,7 +64,7 @@ describe "host matcher" do
64
64
  status("HTTP_HOST" => "foo.com").must_equal 404
65
65
  end
66
66
 
67
- it "doesn't yield HOST" do
67
+ it "doesn't yield host" do
68
68
  app(:header_matchers) do |r|
69
69
  r.on :host=>"example.com" do |*args|
70
70
  args.size.to_s
@@ -73,6 +73,30 @@ describe "host matcher" do
73
73
 
74
74
  body("HTTP_HOST" => "example.com").must_equal '0'
75
75
  end
76
+
77
+ it "yields host if passed a regexp and opts[:host_matcher_captures] is set" do
78
+ app(:header_matchers) do |r|
79
+ r.on :host=>/\A(.*)\.example\.com\z/ do |*m|
80
+ m.empty? ? '0' : m[0]
81
+ end
82
+ end
83
+
84
+ body("HTTP_HOST" => "foo.example.com").must_equal '0'
85
+ app.opts[:host_matcher_captures] = true
86
+ body("HTTP_HOST" => "foo.example.com").must_equal 'foo'
87
+ end
88
+
89
+ it "doesn't yields host if passed a string and opts[:host_matcher_captures] is set" do
90
+ app(:header_matchers) do |r|
91
+ r.on :host=>'example.com' do |*m|
92
+ m.empty? ? '0' : m[0]
93
+ end
94
+ end
95
+
96
+ body("HTTP_HOST" => "example.com").must_equal '0'
97
+ app.opts[:host_matcher_captures] = true
98
+ body("HTTP_HOST" => "example.com").must_equal '0'
99
+ end
76
100
  end
77
101
 
78
102
  describe "user_agent matcher" do
@@ -11,6 +11,12 @@ describe "path_rewriter plugin" do
11
11
  rewrite_path '/3', '/h'
12
12
  rewrite_path '/3', '/g', :path_info=>true
13
13
  rewrite_path(/\A\/e\z/, '/f')
14
+ rewrite_path(/\A\/(dynamic1)/){|match| "/#{match[1].capitalize}"}
15
+ rewrite_path(/\A\/(dynamic2)/, :path_info=>true){|match| "/#{match[1].capitalize}"}
16
+ proc{rewrite_path('/a', '/z'){|match| "/x"}}.must_raise(Roda::RodaError)
17
+ proc{rewrite_path('/a', {:path_info=>true}, :path_info=>true)}.must_raise(Roda::RodaError)
18
+ proc{rewrite_path('/a', {:path_info=>true}, :path_info=>true){|match| "/x"}}.must_raise(Roda::RodaError)
19
+
14
20
  route do |r|
15
21
  "#{r.path_info}:#{r.remaining_path}"
16
22
  end
@@ -29,7 +35,9 @@ describe "path_rewriter plugin" do
29
35
  body('/2').must_equal '/1:/b'
30
36
  body('/2/f').must_equal '/1/f:/b/f'
31
37
  body('/3').must_equal '/g:/g'
32
-
38
+ body('/dynamic1').must_equal '/dynamic1:/Dynamic1'
39
+ body('/dynamic2').must_equal '/Dynamic2:/Dynamic2'
40
+
33
41
  app.freeze
34
42
  body('/a').must_equal '/a:/b'
35
43
  proc{app.rewrite_path '/a', '/b'}.must_raise
@@ -0,0 +1,12 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "response_request plugin" do
4
+ it "gives the response access to the request" do
5
+ app(:response_request) do
6
+ response.request.post? ? "b" : "a"
7
+ end
8
+
9
+ body.must_equal "a"
10
+ body('REQUEST_METHOD'=>'POST').must_equal "b"
11
+ end
12
+ end
@@ -0,0 +1,53 @@
1
+ require File.expand_path("spec_helper", File.dirname(File.dirname(__FILE__)))
2
+
3
+ describe "run_handler plugin" do
4
+ it "makes r.run :not_found=>:pass keep going on 404" do
5
+ pr = proc{|env| [(env['PATH_INFO'] == '/a' ? 404 : 201), {}, ['b']]}
6
+ app(:run_handler) do |r|
7
+ r.run pr, :not_found=>:pass
8
+ 'a'
9
+ end
10
+
11
+ status.must_equal 201
12
+ body.must_equal 'b'
13
+ status('/a').must_equal 200
14
+ body('/a').must_equal 'a'
15
+ end
16
+
17
+ it "makes r.run with a block yield rack app to block, and have it be thrown afterward" do
18
+ pr = proc{|env| [(env['PATH_INFO'] == '/a' ? 404 : 201), {}, ['b']]}
19
+ app(:run_handler) do |r|
20
+ r.run(pr){|a| a[0] *= 2}
21
+ 'a'
22
+ end
23
+
24
+ status.must_equal 402
25
+ status('/a').must_equal 808
26
+ end
27
+
28
+ it "works when both :not_found=>:pass and block are given" do
29
+ pr = proc{|env| [(env['PATH_INFO'] == '/a' ? 202 : 201), {}, ['b']]}
30
+ app(:run_handler) do |r|
31
+ r.run(pr, :not_found=>:pass){|a| a[0] *= 2}
32
+ 'a'
33
+ end
34
+
35
+ status.must_equal 402
36
+ body.must_equal 'b'
37
+ status('/a').must_equal 200
38
+ body('/a').must_equal 'a'
39
+ end
40
+
41
+ it "makes r.run work normally if not given an option or block" do
42
+ pr = proc{|env| [(env['PATH_INFO'] == '/a' ? 404 : 201), {}, ['b']]}
43
+ app(:run_handler) do |r|
44
+ r.run pr
45
+ 'a'
46
+ end
47
+
48
+ status.must_equal 201
49
+ body.must_equal 'b'
50
+ status('/a').must_equal 404
51
+ body('/a').must_equal 'b'
52
+ end
53
+ end
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.6.0
4
+ version: 2.7.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: 2015-09-14 00:00:00.000000000 Z
11
+ date: 2015-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -144,6 +144,7 @@ extra_rdoc_files:
144
144
  - doc/release_notes/2.5.0.txt
145
145
  - doc/release_notes/2.5.1.txt
146
146
  - doc/release_notes/2.6.0.txt
147
+ - doc/release_notes/2.7.0.txt
147
148
  files:
148
149
  - CHANGELOG
149
150
  - MIT-LICENSE
@@ -162,6 +163,7 @@ files:
162
163
  - doc/release_notes/2.5.0.txt
163
164
  - doc/release_notes/2.5.1.txt
164
165
  - doc/release_notes/2.6.0.txt
166
+ - doc/release_notes/2.7.0.txt
165
167
  - lib/roda.rb
166
168
  - lib/roda/plugins/_erubis_escaping.rb
167
169
  - lib/roda/plugins/all_verbs.rb
@@ -174,6 +176,7 @@ files:
174
176
  - lib/roda/plugins/cookies.rb
175
177
  - lib/roda/plugins/csrf.rb
176
178
  - lib/roda/plugins/default_headers.rb
179
+ - lib/roda/plugins/default_status.rb
177
180
  - lib/roda/plugins/delay_build.rb
178
181
  - lib/roda/plugins/delegate.rb
179
182
  - lib/roda/plugins/delete_empty_headers.rb
@@ -213,6 +216,8 @@ files:
213
216
  - lib/roda/plugins/precompile_templates.rb
214
217
  - lib/roda/plugins/render.rb
215
218
  - lib/roda/plugins/render_each.rb
219
+ - lib/roda/plugins/response_request.rb
220
+ - lib/roda/plugins/run_handler.rb
216
221
  - lib/roda/plugins/shared_vars.rb
217
222
  - lib/roda/plugins/sinatra_helpers.rb
218
223
  - lib/roda/plugins/slash_path_empty.rb
@@ -247,6 +252,7 @@ files:
247
252
  - spec/plugin/cookies_spec.rb
248
253
  - spec/plugin/csrf_spec.rb
249
254
  - spec/plugin/default_headers_spec.rb
255
+ - spec/plugin/default_status_spec.rb
250
256
  - spec/plugin/delay_build_spec.rb
251
257
  - spec/plugin/delegate_spec.rb
252
258
  - spec/plugin/delete_empty_headers_spec.rb
@@ -286,6 +292,8 @@ files:
286
292
  - spec/plugin/precompile_templates_spec.rb
287
293
  - spec/plugin/render_each_spec.rb
288
294
  - spec/plugin/render_spec.rb
295
+ - spec/plugin/response_request_spec.rb
296
+ - spec/plugin/run_handler_spec.rb
289
297
  - spec/plugin/shared_vars_spec.rb
290
298
  - spec/plugin/sinatra_helpers_spec.rb
291
299
  - spec/plugin/slash_path_empty_spec.rb