hanami-router 2.0.0.alpha2 → 2.0.0.alpha6

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
  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: []