hanami-router 2.0.0.beta2 → 2.0.0.rc1

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: 81061c98f91ba599e04ca8e16ac1ae9f8784e8398f3580b552cfa26885218b2e
4
- data.tar.gz: cd776fa30375c022808441897e3849ec76ef5a6d5b452b36a444851c10a4f99c
3
+ metadata.gz: dc0a68636ae47869944fc0c76f262c420356d3fbf10bd12b270692f48d3ea7bb
4
+ data.tar.gz: cb653be9037e33f02a05bcbf2048109d64e561afafaa03c8ed353b4b3183d672
5
5
  SHA512:
6
- metadata.gz: 3cdc82d97486a5d74893d8fdff7bd1f337dc5d64d6ff6407133519aef0b8a287b369231d973b62a4da5fdee7d07ecb766d3d0fd39a8e08aa3cd966a425fff238
7
- data.tar.gz: ccc62d079fba4374b74dde5b008e3de0d4d5eaf630c9608179bca0ad0ff7ba6b0584713bb320977950f7901d0404b601598b2d6c97ffa218be428e8be47b2380
6
+ metadata.gz: 4e50ba3c0279d9c26a1ef882127ef7d02ca39cb5ebab25589799ab7190e4562a40e57d0dcbcfe285b1e9dc7ab312dedc0ebf2553d4da3afc921821a8d23cc233
7
+ data.tar.gz: b6f390eb1750d6e596bb1064573467fbd8d5ceccb3bbf0e34a8ab021dd1162d4fc88a8edee4d36a221d053a8ee3d656114004ac6ebbb9b87fc43636bd8715004
data/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  Rack compatible HTTP router for Ruby
4
4
 
5
+ ## v2.0.0.rc1 - 2022-11-08
6
+
7
+ ### Fixed
8
+
9
+ - [Luca Guidi] During routes inspection, ensure to print path prefixes for nested named routes
10
+
11
+ ### Changed
12
+
13
+ - [Benjamin Klotz] `Hanami::Middleware::BodyParser::Parser#parse` (abstract method) to raise `NoMethodError` instead of `NotImplementedError`
14
+
15
+ ## v2.0.0.beta4 - 2022-10-24
16
+
17
+ ### Changed
18
+
19
+ - [Peter Solnica] `Hanami::Middleware::BodyParser` can be initialized with one or more formats and additional custom mime types per format (`Hanami::Middleware::BodyParser.new(app, [:json, :xml])` or `Hanami::Middleware::BodyParser.new(app, [json: "application/json+scim"])`) (#230)
20
+
5
21
  ## v2.0.0.beta2 - 2022-08-16
6
22
 
7
23
  ### Fixed
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack/builder"
4
+ require_relative "./trie"
5
+
6
+ module Hanami
7
+ module Middleware
8
+ # Hanami Rack middleware stack
9
+
10
+ # @since 2.0.0
11
+ # @api private
12
+ class App
13
+ # @param router [Hanami::Router]
14
+ # @param mapping [Hash]
15
+ #
16
+ # @since 2.0.0
17
+ # @api private
18
+ def initialize(router, mapping)
19
+ @trie = Hanami::Middleware::Trie.new(router)
20
+
21
+ mapping.each do |path, stack|
22
+ builder = Rack::Builder.new
23
+
24
+ stack.each do |middleware, args, blk|
25
+ builder.use(middleware, *args, &blk)
26
+ end
27
+
28
+ builder.run(router)
29
+
30
+ @trie.add(path, builder.to_app.freeze)
31
+ end
32
+
33
+ @trie.freeze
34
+ @inspector = router.inspector.freeze
35
+ end
36
+
37
+ # @since 2.0.0
38
+ # @api private
39
+ def call(env)
40
+ @trie.find(env[::Rack::PATH_INFO]).call(env)
41
+ end
42
+
43
+ # @since 2.0.0
44
+ # @api private
45
+ def to_inspect
46
+ @inspector&.call.to_s
47
+ end
48
+ end
49
+ end
50
+ end
@@ -9,15 +9,38 @@ module Hanami
9
9
  # @api private
10
10
  # @since 1.3.0
11
11
  module ClassInterface
12
+ # Instantiate a new body parser instance and load its parsers
13
+ #
14
+ # @example
15
+ # Hanami::Middleware::BodyParser.new(->(env) { [200, {}, "app"] }, :json)
16
+ #
17
+ # Hanami::Middleware::BodyParser.new(
18
+ # ->(env) { [200, {}, "app"] }, [json: "application/json+scim"]
19
+ # )
20
+ #
21
+ # Hanami::Middleware::BodyParser.new(
22
+ # ->(env) { [200, {}, "app"] }, [json: ["application/json+scim", "application/ld+json"]]
23
+ # )
24
+ #
25
+ # @param app [#call]
26
+ # @param parser_specs [Symbol, Array<Hash>] parser name or name with mime-type(s)
27
+ #
28
+ # @api private
29
+ # @since 2.0.0
30
+ # @return BodyParser
31
+ def new(app, parser_specs)
32
+ super(app, build_parsers(parser_specs))
33
+ end
34
+
12
35
  # @api private
13
36
  # @since 1.3.0
14
- def for(parser)
37
+ def build(parser, **config)
15
38
  parser =
16
39
  case parser
17
40
  when String, Symbol
18
- require_parser(parser)
41
+ build(parser_class(parser), **config)
19
42
  when Class
20
- parser.new
43
+ parser.new(**config)
21
44
  else
22
45
  parser
23
46
  end
@@ -27,32 +50,76 @@ module Hanami
27
50
  parser
28
51
  end
29
52
 
53
+ # @api private
54
+ # @since 2.0.0
55
+ def build_parsers(parser_specs, registry = {})
56
+ return DEFAULT_BODY_PARSERS if parser_specs.empty?
57
+
58
+ parsers = Array(parser_specs).flatten(0)
59
+
60
+ parsers.each_with_object(registry) do |spec, memo|
61
+ if spec.is_a?(Hash) && spec.size > 1
62
+ spec.each do |key, value|
63
+ build_parsers([key => [value]], memo)
64
+ end
65
+ else
66
+ name, *mime_types = Array(*spec).flatten(0)
67
+
68
+ parser = build(name, mime_types: mime_types.flatten)
69
+
70
+ parser.mime_types.each do |mime|
71
+ memo[mime] = parser
72
+ end
73
+ end
74
+ end
75
+ end
76
+
30
77
  private
31
78
 
32
79
  # @api private
33
80
  # @since 1.3.0
34
81
  PARSER_METHODS = %i[mime_types parse].freeze
35
82
 
83
+ # @api private
84
+ # @since 2.0.0
85
+ DEFAULT_BODY_PARSERS = {}.freeze
86
+
36
87
  # @api private
37
88
  # @since 1.3.0
38
89
  def ensure_parser(parser)
39
- raise InvalidParserError.new(parser) unless PARSER_METHODS.all? { |method| parser.respond_to?(method) }
90
+ unless PARSER_METHODS.all? { |method| parser.respond_to?(method) }
91
+ raise InvalidParserError.new(parser)
92
+ end
40
93
  end
41
94
 
42
95
  # @api private
43
96
  # @since 1.3.0
44
- def require_parser(parser)
45
- require "hanami/middleware/body_parser/#{parser}_parser"
97
+ # rubocop:disable Lint/SuppressedException
98
+ def parser_class(parser_name)
99
+ parser = nil
100
+
101
+ begin
102
+ require "hanami/middleware/body_parser/#{parser_name}_parser"
103
+ rescue LoadError; end
104
+
105
+ begin
106
+ parser = load_parser!("#{classify(parser_name)}Parser")
107
+ rescue NameError; end
46
108
 
47
- load_parser!("#{classify(parser)}Parser").new
48
- rescue LoadError, NameError
49
- raise UnknownParserError.new(parser)
109
+ parser
110
+ ensure
111
+ raise UnknownParserError, parser_name unless parser
50
112
  end
113
+ # rubocop:enable Lint/SuppressedException
51
114
 
115
+ # @api private
116
+ # @since 1.3.0
52
117
  def classify(parser)
53
118
  parser.to_s.split(/_/).map(&:capitalize).join
54
119
  end
55
120
 
121
+ # @api private
122
+ # @since 1.3.0
56
123
  def load_parser!(class_name)
57
124
  Hanami::Middleware::BodyParser.const_get(class_name, false)
58
125
  end
@@ -11,7 +11,7 @@ module Hanami
11
11
  class JsonParser < Parser
12
12
  # @since 1.3.0
13
13
  # @api private
14
- def mime_types
14
+ def self.mime_types
15
15
  ["application/json", "application/vnd.api+json"]
16
16
  end
17
17
 
@@ -7,7 +7,9 @@ module Hanami
7
7
  #
8
8
  # @since 2.0.0
9
9
  class Parser
10
- # Declare supported MIME types
10
+ DEFAULT_MIME_TYPES = [].freeze
11
+
12
+ # Return supported mime types
11
13
  #
12
14
  # @return [Array<String>] supported MIME types
13
15
  #
@@ -18,12 +20,15 @@ module Hanami
18
20
  # require "hanami/middleware/body_parser"
19
21
  #
20
22
  # class XMLParser < Hanami::Middleware::BodyParser::Parser
21
- # def mime_types
23
+ # def self.mime_types
22
24
  # ["application/xml", "text/xml"]
23
25
  # end
24
26
  # end
25
- def mime_types
26
- raise NotImplementedError
27
+ attr_reader :mime_types
28
+
29
+ # @api private
30
+ def initialize(mime_types: DEFAULT_MIME_TYPES)
31
+ @mime_types = self.class.mime_types + mime_types
27
32
  end
28
33
 
29
34
  # Parse raw HTTP request body
@@ -49,8 +54,8 @@ module Hanami
49
54
  # raise Hanami::Middleware::BodyParser::BodyParsingError.new(exception.message)
50
55
  # end
51
56
  # end
52
- def parse(body)
53
- raise NotImplementedError
57
+ def parse(body) # rubocop:disable Lint/UnusedMethodArgument
58
+ raise NoMethodError
54
59
  end
55
60
  end
56
61
  end
@@ -37,7 +37,7 @@ module Hanami
37
37
 
38
38
  def initialize(app, parsers)
39
39
  @app = app
40
- @parsers = build_parsers(parsers)
40
+ @parsers = parsers
41
41
  end
42
42
 
43
43
  def call(env)
@@ -56,19 +56,6 @@ module Hanami
56
56
 
57
57
  private
58
58
 
59
- def build_parsers(parser_names)
60
- parser_names = Array(parser_names)
61
- return {} if parser_names.empty?
62
-
63
- parser_names.each_with_object({}) do |name, parsers|
64
- parser = self.class.for(name)
65
-
66
- parser.mime_types.each do |mime|
67
- parsers[mime] = parser
68
- end
69
- end
70
- end
71
-
72
59
  # @api private
73
60
  def _symbolize(body)
74
61
  if body.is_a?(::Hash)
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module Middleware
5
+ # Trie node to register scopes with custom Rack middleware
6
+ #
7
+ # @api private
8
+ # @since 2.0.0
9
+ class Node
10
+ # @api private
11
+ # @since 2.0.0
12
+ attr_reader :app
13
+
14
+ # @api private
15
+ # @since 2.0.0
16
+ def initialize
17
+ @app = nil
18
+ @children = {}
19
+ end
20
+
21
+ # @api private
22
+ # @since 2.0.0
23
+ def freeze
24
+ @children.freeze
25
+ super
26
+ end
27
+
28
+ # @api private
29
+ # @since 2.0.0
30
+ def put(segment)
31
+ @children[segment] ||= self.class.new
32
+ end
33
+
34
+ # @api private
35
+ # @since 2.0.0
36
+ def get(segment)
37
+ @children.fetch(segment) { self if leaf? }
38
+ end
39
+
40
+ # @api private
41
+ # @since 2.0.0
42
+ def app!(app)
43
+ @app = app
44
+ end
45
+
46
+ # @api private
47
+ # @since 2.0.0
48
+ def app?
49
+ !@app.nil?
50
+ end
51
+
52
+ # @api private
53
+ # @since 2.0.0
54
+ def leaf?
55
+ @children.empty?
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "./node"
4
+
5
+ module Hanami
6
+ module Middleware
7
+ # Trie to register scopes with custom Rack middleware
8
+ #
9
+ # @api private
10
+ # @since 2.0.0
11
+ class Trie
12
+ # @api private
13
+ # @since 2.0.0
14
+ def initialize(app)
15
+ @app = app
16
+ @root = Node.new
17
+ end
18
+
19
+ # @api private
20
+ # @since 2.0.0
21
+ def freeze
22
+ @root.freeze
23
+ super
24
+ end
25
+
26
+ # @api private
27
+ # @since 2.0.0
28
+ def add(path, app)
29
+ node = @root
30
+ for_each_segment(path) do |segment|
31
+ node = node.put(segment)
32
+ end
33
+
34
+ node.app!(app)
35
+ end
36
+
37
+ # @api private
38
+ # @since 2.0.0
39
+ def find(path)
40
+ node = @root
41
+
42
+ for_each_segment(path) do |segment|
43
+ break unless node
44
+
45
+ node = node.get(segment)
46
+ end
47
+
48
+ return node.app if node&.app?
49
+
50
+ @root.app || @app
51
+ end
52
+
53
+ # @api private
54
+ # @since 2.0.0
55
+ def empty?
56
+ @root.leaf?
57
+ end
58
+
59
+ private
60
+
61
+ # @api private
62
+ # @since 2.0.0
63
+ def for_each_segment(path, &blk)
64
+ _, *segments = path.split(/\//)
65
+ segments.each(&blk)
66
+ end
67
+ end
68
+ end
69
+ end
@@ -2,63 +2,81 @@
2
2
 
3
3
  module Hanami
4
4
  class Router
5
- # Base error
5
+ # Base class for all Hanami::Router errors.
6
6
  #
7
7
  # @since 0.5.0
8
+ # @api public
8
9
  class Error < StandardError
9
10
  end
10
11
 
11
- # Missing endpoint error. It's raised when the route definition is missing `to:` endpoint and a block.
12
+ # Error raised when no endpoint is specified for a route.
13
+ #
14
+ # Endpoints must be specified by `to:` or a block.
12
15
  #
13
16
  # @since 2.0.0
17
+ # @api public
14
18
  class MissingEndpointError < Error
19
+ # @since 2.0.0
20
+ # @api private
15
21
  def initialize(path)
16
22
  super("missing endpoint for #{path.inspect}")
17
23
  end
18
24
  end
19
25
 
20
- # Invalid route exception. It's raised when the router cannot recognize a route
26
+ # Error raised when a named route could not be found.
27
+ #
28
+ # @see Hanami::Router#path
29
+ # @see Hanami::Router#url
21
30
  #
22
31
  # @since 2.0.0
23
- class InvalidRouteException < Error
32
+ # @api public
33
+ class MissingRouteError < Error
34
+ # @since 2.0.0
35
+ # @api private
24
36
  def initialize(name)
25
- super("No route could be generated for #{name.inspect} - please check given arguments")
37
+ super("No route could be found with name #{name.inspect}")
26
38
  end
27
39
  end
28
40
 
29
- # Invalid route expansion exception. It's raised when the router recognizes
30
- # a route but given variables cannot be expanded into a path/url
31
- #
32
- # @since 2.0.0
41
+ # Error raised when variables given for route cannot be expanded into a full path.
33
42
  #
34
43
  # @see Hanami::Router#path
35
44
  # @see Hanami::Router#url
36
- class InvalidRouteExpansionException < Error
45
+ #
46
+ # @since 2.0.0
47
+ # @api public
48
+ class InvalidRouteExpansionError < Error
49
+ # @since 2.0.0
50
+ # @api private
37
51
  def initialize(name, message)
38
52
  super("No route could be generated for `#{name.inspect}': #{message}")
39
53
  end
40
54
  end
41
55
 
42
- # Handle unknown HTTP status codes
56
+ # Error raised when an unknown HTTP status code is given.
57
+ #
58
+ # @see Hanami::Router#redirect
43
59
  #
44
60
  # @since 2.0.0
61
+ # @api public
45
62
  class UnknownHTTPStatusCodeError < Error
63
+ # @since 2.0.0
64
+ # @api private
46
65
  def initialize(code)
47
66
  super("Unknown HTTP status code: #{code.inspect}")
48
67
  end
49
68
  end
50
69
 
51
- # This error is raised when <tt>#call</tt> is invoked on a non-routable
52
- # recognized route.
53
- #
54
- # @since 0.5.0
70
+ # Error raised when a recognized route is called but has no callable endpoint.
55
71
  #
56
72
  # @see Hanami::Router#recognize
57
- # @see Hanami::Router::RecognizedRoute
58
73
  # @see Hanami::Router::RecognizedRoute#call
59
- # @see Hanami::Router::RecognizedRoute#routable?
74
+ #
75
+ # @since 0.5.0
76
+ # @api public
60
77
  class NotRoutableEndpointError < Error
61
78
  # @since 0.5.0
79
+ # @api private
62
80
  def initialize(env)
63
81
  super %(Cannot find routable endpoint for: #{env[::Rack::REQUEST_METHOD]} #{env[::Rack::PATH_INFO]})
64
82
  end
@@ -4,34 +4,40 @@ require "hanami/router/formatter/human_friendly"
4
4
 
5
5
  module Hanami
6
6
  class Router
7
- # Routes inspector
7
+ # Builds a representation of an array of routes according to a given formatter.
8
8
  #
9
- # Builds a representation of an array of routes according to a given
10
- # formatter.
9
+ # @see Router.new
11
10
  #
12
11
  # @since 2.0.0
12
+ # @api private
13
13
  class Inspector
14
14
  # @param routes [Array<Hanami::Route>]
15
- # @param formatter [#call] Takes the routes as an argument and returns
16
- # whatever representation it creates. Defaults to
17
- # {Hanami::Router::Formatter::HumanFriendly}.
15
+ # @param formatter [#call] routes formatter, taking routes as an argument and returning its
16
+ # own representation (typically a string). Defaults to {Formatter::HumanFriendly}.
17
+ #
18
18
  # @since 2.0.0
19
+ # @api public
19
20
  def initialize(routes: [], formatter: Formatter::HumanFriendly.new)
20
21
  @routes = routes
21
22
  @formatter = formatter
22
23
  end
23
24
 
24
- # @param route [Hash] serialized route
25
+ # Adds a route to be inspected.
26
+ #
27
+ # @param route [Route]
25
28
  #
26
- # @api private
27
29
  # @since 2.0.0
30
+ # @api public
28
31
  def add_route(route)
29
32
  @routes.push(route)
30
33
  end
31
34
 
35
+ # Calls the formatter for all added routes.
36
+ #
32
37
  # @return [Any] Formatted routes
33
38
  #
34
39
  # @since 2.0.0
40
+ # @api public
35
41
  def call(...)
36
42
  @formatter.call(@routes, ...)
37
43
  end
@@ -4,10 +4,13 @@ module Hanami
4
4
  class Router
5
5
  # Represents a result of router path recognition.
6
6
  #
7
- # @since 0.5.0
8
- #
9
7
  # @see Hanami::Router#recognize
8
+ #
9
+ # @since 0.5.0
10
+ # @api public
10
11
  class RecognizedRoute
12
+ # @since 0.5.0
13
+ # @api private
11
14
  def initialize(endpoint, env)
12
15
  @endpoint = endpoint
13
16
  @env = env
@@ -54,12 +57,22 @@ module Hanami
54
57
  @env[::Rack::PATH_INFO]
55
58
  end
56
59
 
60
+ # Returns the route's path params.
61
+ #
62
+ # @return [Hash]
63
+ #
57
64
  # @since 0.7.0
58
65
  # @api public
59
66
  def params
60
67
  @env[Router::PARAMS]
61
68
  end
62
69
 
70
+ # Returns the route's endpoint object.
71
+ #
72
+ # Returns nil if the route is a {#redirect? redirect}.
73
+ #
74
+ # @return [Object, nil]
75
+ #
63
76
  # @since 0.7.0
64
77
  # @api public
65
78
  def endpoint
@@ -68,18 +81,30 @@ module Hanami
68
81
  @endpoint
69
82
  end
70
83
 
84
+ # Returns true if the route has an {#endpoint}.
85
+ #
86
+ # @return [Boolean]
87
+ #
71
88
  # @since 0.7.0
72
89
  # @api public
73
90
  def routable?
74
91
  !@endpoint.nil?
75
92
  end
76
93
 
94
+ # Returns true if the route is a redirect.
95
+ #
96
+ # @return [Boolean]
97
+ #
77
98
  # @since 0.7.0
78
99
  # @api public
79
100
  def redirect?
80
101
  @endpoint.is_a?(Redirect)
81
102
  end
82
103
 
104
+ # Returns the route's redirect path, if it is a redirect, or nil otherwise.
105
+ #
106
+ # @return [String, nil]
107
+ #
83
108
  # @since 0.7.0
84
109
  # @api public
85
110
  def redirection_path
@@ -8,25 +8,57 @@ module Hanami
8
8
  # A route from the router
9
9
  #
10
10
  # @since 2.0.0
11
+ # @api public
11
12
  class Route
12
- # @api private
13
13
  # @since 2.0.0
14
+ # @api private
14
15
  ROUTE_CONSTRAINT_SEPARATOR = ", "
15
16
  private_constant :ROUTE_CONSTRAINT_SEPARATOR
16
17
 
18
+ # Returns the route's HTTP method.
19
+ #
20
+ # @example
21
+ # route.http_method # => "GET"
22
+ #
23
+ # @return [String]
24
+ #
17
25
  # @since 2.0.0
26
+ # @api public
18
27
  attr_reader :http_method
19
28
 
29
+ # Returns the route's path.
30
+ #
31
+ # @example
32
+ # route.path # => "/a/b/c"
33
+ #
34
+ # @return [String]
35
+ #
20
36
  # @since 2.0.0
37
+ # @api public
21
38
  attr_reader :path
22
39
 
40
+ # Returns the route's Rack endpoint, as given to `to:` when the route was defined.
41
+ #
42
+ # @return [Object]
43
+ #
23
44
  # @since 2.0.0
45
+ # @api public
24
46
  attr_reader :to
25
47
 
48
+ # Returns the route's unique name, as given to `as:` when the route was defined.
49
+ #
50
+ # @return [Object]
51
+ #
26
52
  # @since 2.0.0
53
+ # @api public
27
54
  attr_reader :as
28
55
 
56
+ # Returns the route's contraints hash for its path variables.
57
+ #
58
+ # @return [Hash]
59
+ #
29
60
  # @since 2.0.0
61
+ # @api public
30
62
  attr_reader :constraints
31
63
 
32
64
  # @api private
@@ -41,22 +73,48 @@ module Hanami
41
73
  freeze
42
74
  end
43
75
 
76
+ # Returns true if the route is for the HEAD HTTP method.
77
+ #
78
+ # @return [Boolean]
79
+ #
80
+ # @see #http_method
81
+ #
44
82
  # @since 2.0.0
83
+ # @api public
45
84
  def head?
46
85
  http_method == ::Rack::HEAD
47
86
  end
48
87
 
88
+ # Returns true if the route has a name.
89
+ #
90
+ # @return [Boolean]
91
+ #
92
+ # @see #as
93
+ #
49
94
  # @since 2.0.0
95
+ # @api public
50
96
  def as?
51
97
  !as.nil?
52
98
  end
53
99
 
100
+ # Returns true if the route has any constraints.
101
+ #
102
+ # @return [Boolean]
103
+ #
104
+ # @see #constraints
105
+ #
54
106
  # @since 2.0.0
107
+ # @api public
55
108
  def constraints?
56
109
  constraints.any?
57
110
  end
58
111
 
112
+ # Returns a string containing a human-readable representation of the route's {#to} endpoint.
113
+ #
114
+ # @return [String]
115
+ #
59
116
  # @since 2.0.0
117
+ # @api public
60
118
  def inspect_to(value = to)
61
119
  case value
62
120
  when String
@@ -74,14 +132,26 @@ module Hanami
74
132
  end
75
133
  end
76
134
 
135
+ # Returns a string containing a human-readable representation of the route's {#constraints}.
136
+ #
137
+ # @return [String]
138
+ #
77
139
  # @since 2.0.0
140
+ # @api public
78
141
  def inspect_constraints
79
142
  @constraints.map do |key, value|
80
143
  "#{key}: #{value.inspect}"
81
144
  end.join(ROUTE_CONSTRAINT_SEPARATOR)
82
145
  end
83
146
 
147
+ # Returns a string containing a human-readable representation of the route's name.
148
+ #
149
+ # @return [String]
150
+ #
151
+ # @see #as
152
+ #
84
153
  # @since 2.0.0
154
+ # @api public
85
155
  def inspect_as
86
156
  as ? as.inspect : Router::EMPTY_STRING
87
157
  end
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "hanami/router/error"
3
+ require "hanami/router/errors"
4
4
  require "mustermann/error"
5
5
 
6
6
  module Hanami
7
7
  class Router
8
- # URL Helpers
8
+ # @since 2.0.0
9
+ # @api private
9
10
  class UrlHelpers
10
11
  # @since 2.0.0
11
12
  # @api private
@@ -21,17 +22,17 @@ module Hanami
21
22
  end
22
23
 
23
24
  # @since 2.0.0
24
- # @api public
25
+ # @api private
25
26
  def path(name, variables = {})
26
27
  @named.fetch(name.to_sym) do
27
- raise InvalidRouteException.new(name)
28
+ raise MissingRouteError.new(name)
28
29
  end.expand(:append, variables)
29
30
  rescue Mustermann::ExpandError => exception
30
- raise InvalidRouteExpansionException.new(name, exception.message)
31
+ raise InvalidRouteExpansionError.new(name, exception.message)
31
32
  end
32
33
 
33
34
  # @since 2.0.0
34
- # @api public
35
+ # @api private
35
36
  def url(name, variables = {})
36
37
  @base_url + path(name, variables)
37
38
  end
@@ -2,8 +2,11 @@
2
2
 
3
3
  module Hanami
4
4
  class Router
5
- # @since 0.1.0
5
+ # Returns the hanami-router version.
6
+ #
7
+ # @return [String]
8
+ #
6
9
  # @api public
7
- VERSION = "2.0.0.beta2"
10
+ VERSION = "2.0.0.rc1"
8
11
  end
9
12
  end
data/lib/hanami/router.rb CHANGED
@@ -3,13 +3,14 @@
3
3
  require "rack"
4
4
  require "rack/utils"
5
5
 
6
+ # @see Hanami::Router
6
7
  module Hanami
7
8
  # Rack compatible, lightweight and fast HTTP Router.
8
9
  #
9
10
  # @since 0.1.0
10
11
  class Router
11
12
  require "hanami/router/version"
12
- require "hanami/router/error"
13
+ require "hanami/router/errors"
13
14
  require "hanami/router/segment"
14
15
  require "hanami/router/redirect"
15
16
  require "hanami/router/prefix"
@@ -353,6 +354,8 @@ module Hanami
353
354
  # @param as [Symbol] a unique name for the route
354
355
  # @param code [Integer] a HTTP status code to use for the redirect
355
356
  #
357
+ # @raise [Hanami::Router::UnknownHTTPStatusCodeError] when an unknown redirect code is given
358
+ #
356
359
  # @since 0.1.0
357
360
  #
358
361
  # @see #get
@@ -434,7 +437,7 @@ module Hanami
434
437
  #
435
438
  # @return [String]
436
439
  #
437
- # @raise [Hanami::Routing::InvalidRouteException] when the router fails to
440
+ # @raise [Hanami::Router::MissingRouteError] when the router fails to
438
441
  # recognize a route, because of the given arguments.
439
442
  #
440
443
  # @since 0.1.0
@@ -464,7 +467,7 @@ module Hanami
464
467
  #
465
468
  # @return [String]
466
469
  #
467
- # @raise [Hanami::Routing::InvalidRouteException] when the router fails to
470
+ # @raise [Hanami::Router::MissingRouteError] when the router fails to
468
471
  # recognize a route, because of the given arguments.
469
472
  #
470
473
  # @since 0.1.0
@@ -596,12 +599,11 @@ module Hanami
596
599
  # route.params # => {:id=>"1"}
597
600
  def recognize(env, params = {}, options = {})
598
601
  require "hanami/router/recognized_route"
602
+
599
603
  env = env_for(env, params, options)
600
604
  endpoint, params = lookup(env)
601
605
 
602
- RecognizedRoute.new(
603
- endpoint, _params(env, params)
604
- )
606
+ RecognizedRoute.new(endpoint, _params(env, params))
605
607
  end
606
608
 
607
609
  # @since 2.0.0
@@ -686,7 +688,7 @@ module Hanami
686
688
  begin
687
689
  url = path(env, params)
688
690
  return env_for(url, params, options) # rubocop:disable Style/RedundantReturn
689
- rescue Hanami::Router::InvalidRouteException
691
+ rescue Hanami::Router::MissingRouteError
690
692
  {} # Empty Rack env
691
693
  end
692
694
  else
@@ -799,7 +801,10 @@ module Hanami
799
801
  add_fixed_route(http_method, path, endpoint)
800
802
  end
801
803
 
802
- add_named_route(path, as, constraints) if as
804
+ if as
805
+ as = prefixed_name(as)
806
+ add_named_route(path, as, constraints)
807
+ end
803
808
 
804
809
  if inspect?
805
810
  @inspector.add_route(
@@ -843,7 +848,7 @@ module Hanami
843
848
  # @since 2.0.0
844
849
  # @api private
845
850
  def add_named_route(path, as, constraints)
846
- @url_helpers.add(prefixed_name(as), Segment.fabricate(path, **constraints))
851
+ @url_helpers.add(as, Segment.fabricate(path, **constraints))
847
852
  end
848
853
 
849
854
  # @since 2.0.0
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.beta2
4
+ version: 2.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-16 00:00:00.000000000 Z
11
+ date: 2022-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -153,15 +153,18 @@ files:
153
153
  - LICENSE.md
154
154
  - README.md
155
155
  - hanami-router.gemspec
156
+ - lib/hanami/middleware/app.rb
156
157
  - lib/hanami/middleware/body_parser.rb
157
158
  - lib/hanami/middleware/body_parser/class_interface.rb
158
159
  - lib/hanami/middleware/body_parser/errors.rb
159
160
  - lib/hanami/middleware/body_parser/json_parser.rb
160
161
  - lib/hanami/middleware/body_parser/parser.rb
161
162
  - lib/hanami/middleware/error.rb
163
+ - lib/hanami/middleware/node.rb
164
+ - lib/hanami/middleware/trie.rb
162
165
  - lib/hanami/router.rb
163
166
  - lib/hanami/router/block.rb
164
- - lib/hanami/router/error.rb
167
+ - lib/hanami/router/errors.rb
165
168
  - lib/hanami/router/formatter/csv.rb
166
169
  - lib/hanami/router/formatter/human_friendly.rb
167
170
  - lib/hanami/router/inspector.rb
@@ -195,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
195
198
  - !ruby/object:Gem::Version
196
199
  version: 1.3.1
197
200
  requirements: []
198
- rubygems_version: 3.3.7
201
+ rubygems_version: 3.3.3
199
202
  signing_key:
200
203
  specification_version: 4
201
204
  summary: Rack compatible HTTP router for Ruby and Hanami