hanami-router 2.0.0.alpha2 → 2.0.0.alpha6

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
  SHA256:
3
- metadata.gz: '078b6fde8c274fe1d60ae480f8b9aec21e3c765daf8ba58f10b1b30a2d0c2135'
4
- data.tar.gz: 941ad1968db99f130f18ef37ba12798e882e80b84aeb9974780edeabd446dcfb
3
+ metadata.gz: 8d4b765c647ddf0aa30e30b516bc8e449a9734d6de8f8466c5e9ae96051b8b2b
4
+ data.tar.gz: 6b6728d2cb184ac2924fad9b36e0d61396b9dde66c95894a694c831291e113b5
5
5
  SHA512:
6
- metadata.gz: 9091771edcea709bf395654175c7a4f8c1f961d85d66f553db6591d7e1c6675cea38cfdc393e5438e219edb75c75965d4a37727e2da69cdbe1d57ce6756523b7
7
- data.tar.gz: 130e577dd27732b4b74acc147a9fbaa444b682546092acd6ed849347c94edcbd779193917b66f4444dd4faf1d7f35ae5dc6755eada2b783ba5d62aa0b7d9c004
6
+ metadata.gz: e2553b5cae230e21181467afce6950bd3df79e17e6351bc8f9b92bf4577ccaf4f7b773d11d67d88e3fe9fa789fcefd5211dd721ea1e723c16414e2d2670594d3
7
+ data.tar.gz: 247718a876404665267bdeb523944a73b55d9f7e846b11888e022f0fcfac39c8514f2dca60b030e8820ac3958bc666f766229793a04f992bca328cbd0c3e2919
data/CHANGELOG.md CHANGED
@@ -1,6 +1,30 @@
1
1
  # Hanami::Router
2
2
  Rack compatible HTTP router for Ruby
3
3
 
4
+ ## v2.0.0.alpha6 - 2022-02-10
5
+ ### Added
6
+ - [Luca Guidi] Official support for MRI 3.1
7
+ - [Luca Guidi] Parse non-GET request body and make it available in Rack env under the `router.params` key. For JSON requests, please use `Hanami:::Middleware::JsonParser`
8
+
9
+ ### Changed
10
+ - [Luca Guidi] Drop support for Ruby: MRI 2.6, and 2.7.
11
+
12
+ ## v2.0.0.alpha5 - 2021-05-04
13
+ ### Added
14
+ - [Luca Guidi] Introduced `Hanami::Router#to_inspect` which returns a string blob with all the routes formatted for human readability
15
+
16
+ ## v2.0.0.alpha4 - 2021-01-16
17
+ ### Added
18
+ - [Luca Guidi] Official support for MRI 3.0
19
+ - [Luca Guidi] Introduced `Hanami::Middleware::BodyParser::Parser` as superclass for body parsers
20
+ - [Paweł Świątkowski] Added `not_found:` option to `Hanami::Router#initialize` to customize HTTP 404 status
21
+
22
+ ## v2.0.0.alpha3 - 2020-05-20
23
+ ### Fixed
24
+ - [Luca Guidi] `Hanami::Router#initialize` do not yield block if not given
25
+ - [Luca Guidi] Ensure to not accidentally cache response headers for HTTP 404 and 405
26
+ - [Luca Guidi] Ensure scoped root to not be added as trailing slash
27
+
4
28
  ## v2.0.0.alpha2 - 2020-02-19
5
29
  ### Added
6
30
  - [Luca Guidi] Block syntax. Routes definition accept a block which returning value is the body of the Rack response.
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2014-2017 Luca Guidi
1
+ Copyright © 2014-2021 Luca Guidi
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -2,12 +2,15 @@
2
2
 
3
3
  Rack compatible, lightweight and fast HTTP Router for Ruby and [Hanami](http://hanamirb.org).
4
4
 
5
+ ## Version
6
+
7
+ **This branch contains the code for `hanami-router` 2.x.**
8
+
5
9
  ## Status
6
10
 
7
11
  [![Gem Version](https://badge.fury.io/rb/hanami-router.svg)](https://badge.fury.io/rb/hanami-router)
8
- [![Build Status](https://ci.hanamirb.org/api/badges/hanami/router/status.svg)](https://ci.hanamirb.org/hanami/router)
9
- [![CircleCI](https://circleci.com/gh/hanami/router/tree/master.svg?style=svg)](https://circleci.com/gh/hanami/router/tree/master)
10
- [![Test Coverage](https://codecov.io/gh/hanami/router/branch/master/graph/badge.svg)](https://codecov.io/gh/hanami/router)
12
+ [![CI](https://github.com/hanami/router/workflows/ci/badge.svg?branch=main)](https://github.com/hanami/router/actions?query=workflow%3Aci+branch%3Amain)
13
+ [![Test Coverage](https://codecov.io/gh/hanami/router/branch/main/graph/badge.svg)](https://codecov.io/gh/hanami/router)
11
14
  [![Depfu](https://badges.depfu.com/badges/5f6b8e8fa3b0d082539f0b0f84d55960/overview.svg)](https://depfu.com/github/hanami/router?project=Bundler)
12
15
  [![Inline Docs](http://inch-ci.org/github/hanami/router.svg)](http://inch-ci.org/github/hanami/router)
13
16
 
@@ -22,7 +25,7 @@ Rack compatible, lightweight and fast HTTP Router for Ruby and [Hanami](http://h
22
25
 
23
26
  ## Rubies
24
27
 
25
- __Hanami::Router__ supports Ruby (MRI) 2.5+
28
+ __Hanami::Router__ supports Ruby (MRI) 3.0+
26
29
 
27
30
 
28
31
  ## Installation
@@ -225,6 +228,13 @@ router = Hanami::Router.new
225
228
  router.call(Rack::MockRequest.env_for("/unknown")).status # => 404
226
229
  ```
227
230
 
231
+ ### Explicit Not Found:
232
+
233
+ ```ruby
234
+ router = Hanami::Router.new(not_found: ->(_) { [499, {}, []]})
235
+ router.call(Rack::MockRequest.env_for("/unknown")).status # => 499
236
+ ```
237
+
228
238
  ### Body Parsers
229
239
 
230
240
  Rack ignores request bodies unless they come from a form submission.
@@ -355,6 +365,4 @@ __Hanami::Router__ uses [Semantic Versioning 2.0.0](http://semver.org)
355
365
 
356
366
  ## Copyright
357
367
 
358
- Copyright © 2014-2020 Luca Guidi – Released under MIT License
359
-
360
- This project was formerly known as Lotus (`lotus-router`).
368
+ Copyright © 2014-2022 Hanami Team – Released under MIT License
@@ -14,11 +14,12 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = "http://hanamirb.org"
15
15
  spec.license = "MIT"
16
16
 
17
- spec.files = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md hanami-router.gemspec`.split($INPUT_RECORD_SEPARATOR)
17
+ spec.files = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md hanami-router.gemspec`.split($/)
18
18
  spec.executables = []
19
19
  spec.test_files = spec.files.grep(%r{^(test)/})
20
20
  spec.require_paths = ["lib"]
21
- spec.required_ruby_version = ">= 2.5.0"
21
+ spec.metadata["rubygems_mfa_required"] = "true"
22
+ spec.required_ruby_version = ">= 3.0"
22
23
 
23
24
  spec.add_dependency "rack", "~> 2.0"
24
25
  spec.add_dependency "mustermann", "~> 1.0"
@@ -28,4 +29,7 @@ Gem::Specification.new do |spec|
28
29
  spec.add_development_dependency "rake", "~> 13"
29
30
  spec.add_development_dependency "rack-test", "~> 1.0"
30
31
  spec.add_development_dependency "rspec", "~> 3.8"
32
+
33
+ spec.add_development_dependency "rubocop", "~> 1.0"
34
+ spec.add_development_dependency "rubocop-performance", "~> 1.0"
31
35
  end
@@ -11,7 +11,7 @@ module Hanami
11
11
  module ClassInterface
12
12
  # @api private
13
13
  # @since 1.3.0
14
- def for(parser) # rubocop:disable Metrics/MethodLength
14
+ def for(parser)
15
15
  parser =
16
16
  case parser
17
17
  when String, Symbol
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "json"
4
- require_relative "errors"
4
+ require_relative "parser"
5
5
 
6
6
  module Hanami
7
7
  module Middleware
8
8
  class BodyParser
9
9
  # @since 1.3.0
10
10
  # @api private
11
- class JsonParser
11
+ class JsonParser < Parser
12
12
  # @since 1.3.0
13
13
  # @api private
14
14
  def mime_types
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module Middleware
5
+ class BodyParser
6
+ # Body parser abstract class
7
+ #
8
+ # @since 2.0.0
9
+ class Parser
10
+ # Declare supported MIME types
11
+ #
12
+ # @return [Array<String>] supported MIME types
13
+ #
14
+ # @abstract
15
+ # @since 2.0.0
16
+ #
17
+ # @example
18
+ # require "hanami/middleware/body_parser"
19
+ #
20
+ # class XMLParser < Hanami::Middleware::BodyParser::Parser
21
+ # def mime_types
22
+ # ["application/xml", "text/xml"]
23
+ # end
24
+ # end
25
+ def mime_types
26
+ raise NotImplementedError
27
+ end
28
+
29
+ # Parse raw HTTP request body
30
+ #
31
+ # @param body [String] HTTP request body
32
+ #
33
+ # @return [Hash] the result of the parsing
34
+ #
35
+ # @raise [Hanami::Middleware::BodyParser::BodyParsingError] the error
36
+ # that must be raised if the parsing cannot be accomplished
37
+ #
38
+ # @abstract
39
+ # @since 2.0.0
40
+ #
41
+ # @example
42
+ # require "hanami/middleware/body_parser"
43
+ #
44
+ # class XMLParser < Hanami::Middleware::BodyParser::Parser
45
+ # def parse(body)
46
+ # # XML parsing
47
+ # # ...
48
+ # rescue => exception
49
+ # raise Hanami::Middleware::BodyParser::BodyParsingError.new(exception.message)
50
+ # end
51
+ # end
52
+ def parse(body)
53
+ raise NotImplementedError
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -2,20 +2,22 @@
2
2
 
3
3
  require "hanami/router/params"
4
4
  require "hanami/middleware/error"
5
- require_relative "body_parser/class_interface"
6
5
 
7
6
  module Hanami
8
7
  module Middleware
9
8
  # @since 1.3.0
10
9
  # @api private
11
10
  class BodyParser
11
+ require_relative "body_parser/class_interface"
12
+ require_relative "body_parser/parser"
13
+
12
14
  # @since 1.3.0
13
15
  # @api private
14
16
  CONTENT_TYPE = "CONTENT_TYPE"
15
17
 
16
18
  # @since 1.3.0
17
19
  # @api private
18
- MEDIA_TYPE_MATCHER = /\s*[;,]\s*/.freeze
20
+ MEDIA_TYPE_MATCHER = /\s*[;,]\s*/
19
21
 
20
22
  # @since 1.3.0
21
23
  # @api private
@@ -72,7 +74,7 @@ module Hanami
72
74
  if body.is_a?(::Hash)
73
75
  Router::Params.deep_symbolize(body)
74
76
  else
75
- { FALLBACK_KEY => body }
77
+ {FALLBACK_KEY => body}
76
78
  end
77
79
  end
78
80
 
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ class Router
5
+ # Routes inspector
6
+ #
7
+ # @api private
8
+ # @since 2.0.0
9
+ class Inspector
10
+ # @api private
11
+ # @since 2.0.0
12
+ def initialize(routes: [])
13
+ @routes = routes
14
+ end
15
+
16
+ # @param route [Hash] serialized route
17
+ #
18
+ # @api private
19
+ # @since 2.0.0
20
+ def add_route(route)
21
+ @routes.push(route)
22
+ end
23
+
24
+ # @return [String] The inspected routes
25
+ #
26
+ # @api private
27
+ # @since 2.0.0
28
+ def call(*)
29
+ @routes.map(&:to_inspect).join(NEW_LINE)
30
+ end
31
+
32
+ # @api private
33
+ # @since 2.0.0
34
+ NEW_LINE = $/
35
+ private_constant :NEW_LINE
36
+ end
37
+ end
38
+ end
@@ -36,8 +36,7 @@ module Hanami
36
36
  # @api private
37
37
  # @since 2.0.0
38
38
  #
39
- # rubocop:disable Metrics/MethodLength
40
- def get(segment)
39
+ def get(segment) # rubocop:disable Metrics/PerceivedComplexity
41
40
  return unless @variable || @fixed
42
41
 
43
42
  found = nil
@@ -55,7 +54,6 @@ module Hanami
55
54
 
56
55
  [found, captured&.named_captures]
57
56
  end
58
- # rubocop:enable Metrics/MethodLength
59
57
 
60
58
  # @api private
61
59
  # @since 2.0.0
@@ -15,7 +15,7 @@ module Hanami
15
15
  #
16
16
  # @api private
17
17
  # @since 2.0.0
18
- def self.deep_symbolize(params) # rubocop:disable Metrics/MethodLength
18
+ def self.deep_symbolize(params)
19
19
  params.each_with_object({}) do |(key, value), output|
20
20
  output[key.to_sym] =
21
21
  case value
@@ -25,7 +25,7 @@ module Hanami
25
25
  # @api private
26
26
  def relative_join(path, separator = DEFAULT_SEPARATOR)
27
27
  _join(path.to_s)
28
- .gsub(DEFAULT_SEPARATOR_REGEXP, separator)[1..-1]
28
+ .gsub(DEFAULT_SEPARATOR_REGEXP, separator)[1..]
29
29
  end
30
30
 
31
31
  # @since 2.0.0
@@ -48,15 +48,17 @@ module Hanami
48
48
 
49
49
  # @since 2.0.0
50
50
  # @api private
51
- DEFAULT_SEPARATOR_REGEXP = /\//.freeze
51
+ DEFAULT_SEPARATOR_REGEXP = /\//
52
52
 
53
53
  # @since 2.0.0
54
54
  # @api private
55
- DOUBLE_DEFAULT_SEPARATOR_REGEXP = /[\/]{2,}/.freeze
55
+ DOUBLE_DEFAULT_SEPARATOR_REGEXP = /\/{2,}/
56
56
 
57
57
  # @since 2.0.0
58
58
  # @api private
59
59
  def _join(path)
60
+ return @prefix if path == DEFAULT_SEPARATOR
61
+
60
62
  (@prefix + DEFAULT_SEPARATOR + path)
61
63
  .gsub(DOUBLE_DEFAULT_SEPARATOR_REGEXP, DEFAULT_SEPARATOR)
62
64
  end
@@ -27,7 +27,7 @@ module Hanami
27
27
  # @see Hanami::Router::RecognizedRoute#routable?
28
28
  # @see Hanami::Router::NotRoutableEndpointError
29
29
  def call(env)
30
- if routable? # rubocop:disable Style/GuardClause
30
+ if routable?
31
31
  @endpoint.call(env)
32
32
  else
33
33
  raise NotRoutableEndpointError.new(@env)
@@ -13,8 +13,13 @@ module Hanami
13
13
 
14
14
  # @since 2.0.0
15
15
  # @api private
16
- def initialize(destination, endpoint)
16
+ attr_reader :code
17
+
18
+ # @since 2.0.0
19
+ # @api private
20
+ def initialize(destination, code, endpoint)
17
21
  @destination = destination
22
+ @code = code
18
23
  @endpoint = endpoint
19
24
  end
20
25
 
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/router/redirect"
4
+ require "hanami/router/block"
5
+
6
+ module Hanami
7
+ class Router
8
+ class Route
9
+ # @api private
10
+ # @since 2.0.0
11
+ attr_reader :http_method
12
+
13
+ # @api private
14
+ # @since 2.0.0
15
+ attr_reader :path
16
+
17
+ # @api private
18
+ # @since 2.0.0
19
+ attr_reader :to
20
+
21
+ # @api private
22
+ # @since 2.0.0
23
+ attr_reader :as
24
+
25
+ # @api private
26
+ # @since 2.0.0
27
+ attr_reader :constraints
28
+
29
+ # @api private
30
+ # @since 2.0.0
31
+ def initialize(http_method:, path:, to:, as: nil, constraints: {}, blk: nil) # rubocop:disable Metrics/ParameterLists
32
+ @http_method = http_method
33
+ @path = path
34
+ @to = to
35
+ @as = as
36
+ @constraints = constraints
37
+ @blk = blk
38
+ freeze
39
+ end
40
+
41
+ # @api private
42
+ # @since 2.0.0
43
+ def to_inspect
44
+ return EMPTY_ROUTE if head?
45
+
46
+ result = http_method.to_s.ljust(SMALL_STRING_JUSTIFY_AMOUNT)
47
+ result += path.ljust(LARGE_STRING_JUSTIFY_AMOUNT)
48
+ result += inspect_to(to).ljust(LARGE_STRING_JUSTIFY_AMOUNT)
49
+ result += "as #{as.inspect}".ljust(MEDIUM_STRING_JUSTIFY_AMOUNT) if as
50
+
51
+ if constraints?
52
+ result += "(#{inspect_constraints(constraints)})".ljust(EXTRA_LARGE_STRING_JUSTIFY_AMOUNT)
53
+ end
54
+
55
+ result
56
+ end
57
+
58
+ private
59
+
60
+ # @api private
61
+ # @since 2.0.0
62
+ EMPTY_ROUTE = ""
63
+ private_constant :EMPTY_ROUTE
64
+
65
+ # @api private
66
+ # @since 2.0.0
67
+ ROUTE_CONSTRAINT_SEPARATOR = ", "
68
+ private_constant :ROUTE_CONSTRAINT_SEPARATOR
69
+
70
+ # @api private
71
+ # @since 2.0.0
72
+ SMALL_STRING_JUSTIFY_AMOUNT = 8
73
+ private_constant :SMALL_STRING_JUSTIFY_AMOUNT
74
+
75
+ # @api private
76
+ # @since 2.0.0
77
+ MEDIUM_STRING_JUSTIFY_AMOUNT = 20
78
+ private_constant :MEDIUM_STRING_JUSTIFY_AMOUNT
79
+
80
+ # @api private
81
+ # @since 2.0.0
82
+ LARGE_STRING_JUSTIFY_AMOUNT = 30
83
+ private_constant :LARGE_STRING_JUSTIFY_AMOUNT
84
+
85
+ # @api private
86
+ # @since 2.0.0
87
+ EXTRA_LARGE_STRING_JUSTIFY_AMOUNT = 40
88
+ private_constant :EXTRA_LARGE_STRING_JUSTIFY_AMOUNT
89
+
90
+ # @api private
91
+ # @since 2.0.0
92
+ def head?
93
+ http_method == "HEAD"
94
+ end
95
+
96
+ # @api private
97
+ # @since 2.0.0
98
+ def constraints?
99
+ constraints.any?
100
+ end
101
+
102
+ # @api private
103
+ # @since 2.0.0
104
+ def inspect_to(to)
105
+ case to
106
+ when String
107
+ to
108
+ when Proc
109
+ "(proc)"
110
+ when Class
111
+ to.name || "(class)"
112
+ when Block
113
+ "(block)"
114
+ when Redirect
115
+ "#{to.destination} (HTTP #{to.code})"
116
+ else
117
+ inspect_to(to.class)
118
+ end
119
+ end
120
+
121
+ # @api private
122
+ # @since 2.0.0
123
+ def inspect_constraints(constraints)
124
+ constraints.map do |key, value|
125
+ "#{key}: #{value.inspect}"
126
+ end.join(ROUTE_CONSTRAINT_SEPARATOR)
127
+ end
128
+ end
129
+ end
130
+ end
@@ -4,6 +4,6 @@ module Hanami
4
4
  class Router
5
5
  # @since 0.1.0
6
6
  # @api public
7
- VERSION = "2.0.0.alpha2"
7
+ VERSION = "2.0.0.alpha6"
8
8
  end
9
9
  end
data/lib/hanami/router.rb CHANGED
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "rack"
3
4
  require "rack/utils"
4
5
 
5
6
  module Hanami
6
7
  # Rack compatible, lightweight and fast HTTP Router.
7
8
  #
8
9
  # @since 0.1.0
9
- class Router # rubocop:disable Metrics/ClassLength
10
+ class Router
10
11
  require "hanami/router/version"
11
12
  require "hanami/router/error"
12
13
  require "hanami/router/segment"
@@ -15,6 +16,7 @@ module Hanami
15
16
  require "hanami/router/params"
16
17
  require "hanami/router/trie"
17
18
  require "hanami/router/block"
19
+ require "hanami/router/route"
18
20
  require "hanami/router/url_helpers"
19
21
 
20
22
  # URL helpers for other Hanami integrations
@@ -23,6 +25,12 @@ module Hanami
23
25
  # @since 2.0.0
24
26
  attr_reader :url_helpers
25
27
 
28
+ # Routes for inspection
29
+ #
30
+ # @api private
31
+ # @since 2.0.0
32
+ attr_reader :routes
33
+
26
34
  # Returns the given block as it is.
27
35
  #
28
36
  # @param blk [Proc] a set of route definitions
@@ -48,6 +56,7 @@ module Hanami
48
56
  # is deployed
49
57
  # @param resolver [#call(path, to)] a resolver for route entpoints
50
58
  # @param block_context [Hanami::Router::Block::Context)
59
+ # @param not_found [#call(env)] default handler when route is not matched
51
60
  # @param blk [Proc] the route definitions
52
61
  #
53
62
  # @since 0.1.0
@@ -60,18 +69,22 @@ module Hanami
60
69
  # Hanami::Router.new do
61
70
  # get "/", to: ->(*) { [200, {}, ["OK"]] }
62
71
  # end
63
- def initialize(base_url: DEFAULT_BASE_URL, prefix: DEFAULT_PREFIX, resolver: DEFAULT_RESOLVER, block_context: nil, &blk)
72
+ def initialize(base_url: DEFAULT_BASE_URL, prefix: DEFAULT_PREFIX, resolver: DEFAULT_RESOLVER, not_found: NOT_FOUND, block_context: nil, inspector: nil, &blk) # rubocop:disable Layout/LineLength
64
73
  # TODO: verify if Prefix can handle both name and path prefix
65
74
  @path_prefix = Prefix.new(prefix)
66
75
  @name_prefix = Prefix.new("")
67
76
  @url_helpers = UrlHelpers.new(base_url)
77
+ @base_url = base_url
68
78
  @resolver = resolver
79
+ @not_found = not_found
69
80
  @block_context = block_context
70
81
  @fixed = {}
71
82
  @variable = {}
72
83
  @globbed = {}
73
84
  @mounted = {}
74
- instance_eval(&blk)
85
+ @blk = blk
86
+ @inspector = inspector
87
+ instance_eval(&blk) if blk
75
88
  end
76
89
 
77
90
  # Resolve the given Rack env to a registered endpoint and invokes it.
@@ -86,7 +99,7 @@ module Hanami
86
99
 
87
100
  unless endpoint
88
101
  return not_allowed(env) ||
89
- not_found
102
+ not_found(env)
90
103
  end
91
104
 
92
105
  endpoint.call(
@@ -405,7 +418,11 @@ module Hanami
405
418
  def mount(app, at:, **constraints)
406
419
  path = prefixed_path(at)
407
420
  prefix = Segment.fabricate(path, **constraints)
421
+
408
422
  @mounted[prefix] = @resolver.call(path, app)
423
+ if inspect?
424
+ @inspector.add_route(Route.new(http_method: "*", path: at, to: app, constraints: constraints))
425
+ end
409
426
  end
410
427
 
411
428
  # Generate an relative URL for a specified named route.
@@ -586,6 +603,21 @@ module Hanami
586
603
  )
587
604
  end
588
605
 
606
+ # Returns formatted routes
607
+ #
608
+ # @return [String] formatted routes
609
+ #
610
+ # @since 2.0.0
611
+ # @api private
612
+ def to_inspect
613
+ require "hanami/router/inspector"
614
+
615
+ inspector = Inspector.new
616
+ with(inspector: inspector)
617
+
618
+ inspector.call
619
+ end
620
+
589
621
  # @since 2.0.0
590
622
  # @api private
591
623
  def fixed(env)
@@ -631,13 +663,14 @@ module Hanami
631
663
  # @since 2.0.0
632
664
  # @api private
633
665
  def not_allowed(env)
634
- (_not_allowed_fixed(env) || _not_allowed_variable(env)) and return NOT_ALLOWED
666
+ (_not_allowed_fixed(env) ||
667
+ _not_allowed_variable(env)) and return [405, {"Content-Length" => "11"}, ["Not Allowed"]]
635
668
  end
636
669
 
637
670
  # @since 2.0.0
638
671
  # @api private
639
- def not_found
640
- NOT_FOUND
672
+ def not_found(env)
673
+ @not_found.call(env)
641
674
  end
642
675
 
643
676
  protected
@@ -655,7 +688,7 @@ module Hanami
655
688
  #
656
689
  # @see Hanami::Router#recognize
657
690
  # @see http://www.rubydoc.info/github/rack/rack/Rack%2FMockRequest.env_for
658
- def env_for(env, params = {}, options = {}) # rubocop:disable Metrics/MethodLength
691
+ def env_for(env, params = {}, options = {})
659
692
  require "rack/mock"
660
693
 
661
694
  case env
@@ -666,7 +699,7 @@ module Hanami
666
699
  url = path(env, params)
667
700
  return env_for(url, params, options) # rubocop:disable Style/RedundantReturn
668
701
  rescue Hanami::Router::InvalidRouteException
669
- EMPTY_RACK_ENV.dup
702
+ {} # Empty Rack env
670
703
  end
671
704
  else
672
705
  env
@@ -691,31 +724,21 @@ module Hanami
691
724
  # @api private
692
725
  DEFAULT_REDIRECT_CODE = 301
693
726
 
694
- # @since 2.0.0
695
- # @api private
696
- NOT_FOUND = [404, { "Content-Length" => "9" }, ["Not Found"]].freeze
697
-
698
- # @since 2.0.0
699
- # @api private
700
- NOT_ALLOWED = [405, { "Content-Length" => "11" }, ["Not Allowed"]].freeze
701
-
702
727
  # @since 2.0.0
703
728
  # @api private
704
729
  PARAMS = "router.params"
705
730
 
706
- # @since 2.0.0
731
+ # Default response when no route was matched
732
+ #
707
733
  # @api private
708
- EMPTY_PARAMS = {}.freeze
709
-
710
734
  # @since 2.0.0
711
- # @api private
712
- EMPTY_RACK_ENV = {}.freeze
735
+ NOT_FOUND = ->(*) { [404, {"Content-Length" => "9"}, ["Not Found"]] }.freeze
713
736
 
714
737
  # @since 2.0.0
715
738
  # @api private
716
739
  def lookup(env)
717
740
  endpoint = fixed(env)
718
- return [endpoint, EMPTY_PARAMS] if endpoint
741
+ return [endpoint, {}] if endpoint
719
742
 
720
743
  variable(env) || globbed(env) || mounted(env)
721
744
  end
@@ -735,6 +758,12 @@ module Hanami
735
758
  end
736
759
 
737
760
  add_named_route(path, as, constraints) if as
761
+
762
+ if inspect?
763
+ @inspector.add_route(
764
+ Route.new(http_method: http_method, path: path, to: to, as: as, constraints: constraints, blk: blk)
765
+ )
766
+ end
738
767
  end
739
768
 
740
769
  # @since 2.0.0
@@ -785,6 +814,12 @@ module Hanami
785
814
  /\*/.match?(path)
786
815
  end
787
816
 
817
+ # @since 2.0.0
818
+ # @api private
819
+ def inspect?
820
+ !@inspector.nil?
821
+ end
822
+
788
823
  # @since 2.0.0
789
824
  # @api private
790
825
  def prefixed_path(path)
@@ -797,6 +832,27 @@ module Hanami
797
832
  @name_prefix.relative_join(name, "_").to_sym
798
833
  end
799
834
 
835
+ # Returns a new instance of Hanami::Router with the modified options.
836
+ #
837
+ # @return [Hanami::Route] a new instance of Hanami::Router
838
+ #
839
+ # @see Hanami::Router#initialize
840
+ #
841
+ # @since 2.0.0
842
+ # @api private
843
+ def with(**new_options, &blk)
844
+ options = {
845
+ base_url: @base_url,
846
+ prefix: @path_prefix.to_s,
847
+ resolver: @resolver,
848
+ not_found: @not_found,
849
+ block_context: @block_context,
850
+ inspector: @inspector
851
+ }
852
+
853
+ self.class.new(**options.merge(new_options), &(blk || @blk))
854
+ end
855
+
800
856
  # @since 2.0.0
801
857
  # @api private
802
858
  def _redirect(to, code)
@@ -805,7 +861,7 @@ module Hanami
805
861
  end
806
862
 
807
863
  destination = prefixed_path(to)
808
- Redirect.new(destination, ->(*) { [code, { "Location" => destination }, [body]] })
864
+ Redirect.new(destination, code, ->(*) { [code, {"Location" => destination}, [body]] })
809
865
  end
810
866
 
811
867
  # @since 2.0.0
@@ -813,7 +869,13 @@ module Hanami
813
869
  def _params(env, params)
814
870
  params ||= {}
815
871
  env[PARAMS] ||= {}
816
- env[PARAMS].merge!(Rack::Utils.parse_nested_query(env["QUERY_STRING"]))
872
+
873
+ if (input = env[Rack::RACK_INPUT]) and input.rewind
874
+ env[PARAMS].merge!(Rack::Utils.parse_nested_query(input.read))
875
+ input.rewind
876
+ end
877
+
878
+ env[PARAMS].merge!(Rack::Utils.parse_nested_query(env[Rack::QUERY_STRING]))
817
879
  env[PARAMS].merge!(params)
818
880
  env[PARAMS] = Params.deep_symbolize(env[PARAMS])
819
881
  env
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-router
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.alpha2
4
+ version: 2.0.0.alpha6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-19 00:00:00.000000000 Z
11
+ date: 2022-02-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -114,6 +114,34 @@ dependencies:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
116
  version: '3.8'
117
+ - !ruby/object:Gem::Dependency
118
+ name: rubocop
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: '1.0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '1.0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: rubocop-performance
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '1.0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '1.0'
117
145
  description: Rack compatible HTTP router for Ruby
118
146
  email:
119
147
  - me@lucaguidi.com
@@ -129,15 +157,18 @@ files:
129
157
  - lib/hanami/middleware/body_parser/class_interface.rb
130
158
  - lib/hanami/middleware/body_parser/errors.rb
131
159
  - lib/hanami/middleware/body_parser/json_parser.rb
160
+ - lib/hanami/middleware/body_parser/parser.rb
132
161
  - lib/hanami/middleware/error.rb
133
162
  - lib/hanami/router.rb
134
163
  - lib/hanami/router/block.rb
135
164
  - lib/hanami/router/error.rb
165
+ - lib/hanami/router/inspector.rb
136
166
  - lib/hanami/router/node.rb
137
167
  - lib/hanami/router/params.rb
138
168
  - lib/hanami/router/prefix.rb
139
169
  - lib/hanami/router/recognized_route.rb
140
170
  - lib/hanami/router/redirect.rb
171
+ - lib/hanami/router/route.rb
141
172
  - lib/hanami/router/segment.rb
142
173
  - lib/hanami/router/trie.rb
143
174
  - lib/hanami/router/url_helpers.rb
@@ -145,8 +176,9 @@ files:
145
176
  homepage: http://hanamirb.org
146
177
  licenses:
147
178
  - MIT
148
- metadata: {}
149
- post_install_message:
179
+ metadata:
180
+ rubygems_mfa_required: 'true'
181
+ post_install_message:
150
182
  rdoc_options: []
151
183
  require_paths:
152
184
  - lib
@@ -154,15 +186,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
154
186
  requirements:
155
187
  - - ">="
156
188
  - !ruby/object:Gem::Version
157
- version: 2.5.0
189
+ version: '3.0'
158
190
  required_rubygems_version: !ruby/object:Gem::Requirement
159
191
  requirements:
160
192
  - - ">"
161
193
  - !ruby/object:Gem::Version
162
194
  version: 1.3.1
163
195
  requirements: []
164
- rubygems_version: 3.1.2
165
- signing_key:
196
+ rubygems_version: 3.3.3
197
+ signing_key:
166
198
  specification_version: 4
167
199
  summary: Rack compatible HTTP router for Ruby and Hanami
168
200
  test_files: []