roda 2.6.0 → 2.7.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 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