Update API docs for 2.0 (#236)
Updated API docs for 2.0; now nothing public is left undocumented. Key changes: - Rename `InvalidRouteException` to `MissingRouteError` - Rename `InvalidRouteExpansionException` to `InvalidRouteExpansionError` - Rename `hanami/router/error.rb` to `errors.rb` for consistency with our other codebases - Make `UrlHelpers` private. This is an internal class and its behaviour is exposed by already-public methods on router. I think this one must have been mislabeled as public in the first place. - Keep `Inspector` as public, and document `Route` as public to go along with it.
This commit is contained in:
parent
8364b0c962
commit
d4f7a677a3
|
@ -1,4 +1,2 @@
|
|||
-
|
||||
README.md
|
||||
LICENSE.md
|
||||
lib/**/*.rb
|
||||
--markup=markdown
|
||||
--plugin junk
|
||||
|
|
9
Gemfile
9
Gemfile
|
@ -4,9 +4,10 @@ source "https://rubygems.org"
|
|||
gemspec
|
||||
|
||||
unless ENV["CI"]
|
||||
gem "byebug", require: false, platforms: :mri
|
||||
gem "yard", require: false
|
||||
gem "byebug", platforms: :mri
|
||||
gem "yard"
|
||||
gem "yard-junk"
|
||||
end
|
||||
|
||||
gem "hanami-utils", "~> 2.0.beta", require: false, git: "https://github.com/hanami/utils.git", branch: "main"
|
||||
gem "hanami-devtools", require: false, git: "https://github.com/hanami/devtools.git", branch: "main"
|
||||
gem "hanami-utils", "~> 2.0.beta", git: "https://github.com/hanami/utils.git", branch: "main"
|
||||
gem "hanami-devtools", git: "https://github.com/hanami/devtools.git", branch: "main"
|
||||
|
|
|
@ -54,7 +54,7 @@ module Hanami
|
|||
# raise Hanami::Middleware::BodyParser::BodyParsingError.new(exception.message)
|
||||
# end
|
||||
# end
|
||||
def parse(_body)
|
||||
def parse(body) # rubocop:disable Lint/UnusedMethodArgument
|
||||
raise NoMethodError
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,13 +3,14 @@
|
|||
require "rack"
|
||||
require "rack/utils"
|
||||
|
||||
# @see Hanami::Router
|
||||
module Hanami
|
||||
# Rack compatible, lightweight and fast HTTP Router.
|
||||
#
|
||||
# @since 0.1.0
|
||||
class Router
|
||||
require "hanami/router/version"
|
||||
require "hanami/router/error"
|
||||
require "hanami/router/errors"
|
||||
require "hanami/router/segment"
|
||||
require "hanami/router/redirect"
|
||||
require "hanami/router/prefix"
|
||||
|
@ -353,6 +354,8 @@ module Hanami
|
|||
# @param as [Symbol] a unique name for the route
|
||||
# @param code [Integer] a HTTP status code to use for the redirect
|
||||
#
|
||||
# @raise [Hanami::Router::UnknownHTTPStatusCodeError] when an unknown redirect code is given
|
||||
#
|
||||
# @since 0.1.0
|
||||
#
|
||||
# @see #get
|
||||
|
@ -434,7 +437,7 @@ module Hanami
|
|||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @raise [Hanami::Routing::InvalidRouteException] when the router fails to
|
||||
# @raise [Hanami::Router::MissingRouteError] when the router fails to
|
||||
# recognize a route, because of the given arguments.
|
||||
#
|
||||
# @since 0.1.0
|
||||
|
@ -464,7 +467,7 @@ module Hanami
|
|||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @raise [Hanami::Routing::InvalidRouteException] when the router fails to
|
||||
# @raise [Hanami::Router::MissingRouteError] when the router fails to
|
||||
# recognize a route, because of the given arguments.
|
||||
#
|
||||
# @since 0.1.0
|
||||
|
@ -596,12 +599,11 @@ module Hanami
|
|||
# route.params # => {:id=>"1"}
|
||||
def recognize(env, params = {}, options = {})
|
||||
require "hanami/router/recognized_route"
|
||||
|
||||
env = env_for(env, params, options)
|
||||
endpoint, params = lookup(env)
|
||||
|
||||
RecognizedRoute.new(
|
||||
endpoint, _params(env, params)
|
||||
)
|
||||
RecognizedRoute.new(endpoint, _params(env, params))
|
||||
end
|
||||
|
||||
# @since 2.0.0
|
||||
|
@ -686,7 +688,7 @@ module Hanami
|
|||
begin
|
||||
url = path(env, params)
|
||||
return env_for(url, params, options) # rubocop:disable Style/RedundantReturn
|
||||
rescue Hanami::Router::InvalidRouteException
|
||||
rescue Hanami::Router::MissingRouteError
|
||||
{} # Empty Rack env
|
||||
end
|
||||
else
|
||||
|
|
|
@ -2,63 +2,81 @@
|
|||
|
||||
module Hanami
|
||||
class Router
|
||||
# Base error
|
||||
# Base class for all Hanami::Router errors.
|
||||
#
|
||||
# @since 0.5.0
|
||||
# @api public
|
||||
class Error < StandardError
|
||||
end
|
||||
|
||||
# Missing endpoint error. It's raised when the route definition is missing `to:` endpoint and a block.
|
||||
# Error raised when no endpoint is specified for a route.
|
||||
#
|
||||
# Endpoints must be specified by `to:` or a block.
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
class MissingEndpointError < Error
|
||||
# @since 2.0.0
|
||||
# @api private
|
||||
def initialize(path)
|
||||
super("missing endpoint for #{path.inspect}")
|
||||
end
|
||||
end
|
||||
|
||||
# Invalid route exception. It's raised when the router cannot recognize a route
|
||||
#
|
||||
# @since 2.0.0
|
||||
class InvalidRouteException < Error
|
||||
def initialize(name)
|
||||
super("No route could be generated for #{name.inspect} - please check given arguments")
|
||||
end
|
||||
end
|
||||
|
||||
# Invalid route expansion exception. It's raised when the router recognizes
|
||||
# a route but given variables cannot be expanded into a path/url
|
||||
#
|
||||
# @since 2.0.0
|
||||
# Error raised when a named route could not be found.
|
||||
#
|
||||
# @see Hanami::Router#path
|
||||
# @see Hanami::Router#url
|
||||
class InvalidRouteExpansionException < Error
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
class MissingRouteError < Error
|
||||
# @since 2.0.0
|
||||
# @api private
|
||||
def initialize(name)
|
||||
super("No route could be found with name #{name.inspect}")
|
||||
end
|
||||
end
|
||||
|
||||
# Error raised when variables given for route cannot be expanded into a full path.
|
||||
#
|
||||
# @see Hanami::Router#path
|
||||
# @see Hanami::Router#url
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
class InvalidRouteExpansionError < Error
|
||||
# @since 2.0.0
|
||||
# @api private
|
||||
def initialize(name, message)
|
||||
super("No route could be generated for `#{name.inspect}': #{message}")
|
||||
end
|
||||
end
|
||||
|
||||
# Handle unknown HTTP status codes
|
||||
# Error raised when an unknown HTTP status code is given.
|
||||
#
|
||||
# @see Hanami::Router#redirect
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
class UnknownHTTPStatusCodeError < Error
|
||||
# @since 2.0.0
|
||||
# @api private
|
||||
def initialize(code)
|
||||
super("Unknown HTTP status code: #{code.inspect}")
|
||||
end
|
||||
end
|
||||
|
||||
# This error is raised when <tt>#call</tt> is invoked on a non-routable
|
||||
# recognized route.
|
||||
#
|
||||
# @since 0.5.0
|
||||
# Error raised when a recognized route is called but has no callable endpoint.
|
||||
#
|
||||
# @see Hanami::Router#recognize
|
||||
# @see Hanami::Router::RecognizedRoute
|
||||
# @see Hanami::Router::RecognizedRoute#call
|
||||
# @see Hanami::Router::RecognizedRoute#routable?
|
||||
#
|
||||
# @since 0.5.0
|
||||
# @api public
|
||||
class NotRoutableEndpointError < Error
|
||||
# @since 0.5.0
|
||||
# @api private
|
||||
def initialize(env)
|
||||
super %(Cannot find routable endpoint for: #{env[::Rack::REQUEST_METHOD]} #{env[::Rack::PATH_INFO]})
|
||||
end
|
|
@ -4,34 +4,40 @@ require "hanami/router/formatter/human_friendly"
|
|||
|
||||
module Hanami
|
||||
class Router
|
||||
# Routes inspector
|
||||
# Builds a representation of an array of routes according to a given formatter.
|
||||
#
|
||||
# Builds a representation of an array of routes according to a given
|
||||
# formatter.
|
||||
# @see Router.new
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api private
|
||||
class Inspector
|
||||
# @param routes [Array<Hanami::Route>]
|
||||
# @param formatter [#call] Takes the routes as an argument and returns
|
||||
# whatever representation it creates. Defaults to
|
||||
# {Hanami::Router::Formatter::HumanFriendly}.
|
||||
# @param formatter [#call] routes formatter, taking routes as an argument and returning its
|
||||
# own representation (typically a string). Defaults to {Formatter::HumanFriendly}.
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
def initialize(routes: [], formatter: Formatter::HumanFriendly.new)
|
||||
@routes = routes
|
||||
@formatter = formatter
|
||||
end
|
||||
|
||||
# @param route [Hash] serialized route
|
||||
# Adds a route to be inspected.
|
||||
#
|
||||
# @param route [Route]
|
||||
#
|
||||
# @api private
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
def add_route(route)
|
||||
@routes.push(route)
|
||||
end
|
||||
|
||||
# Calls the formatter for all added routes.
|
||||
#
|
||||
# @return [Any] Formatted routes
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
def call(...)
|
||||
@formatter.call(@routes, ...)
|
||||
end
|
||||
|
|
|
@ -4,10 +4,13 @@ module Hanami
|
|||
class Router
|
||||
# Represents a result of router path recognition.
|
||||
#
|
||||
# @since 0.5.0
|
||||
#
|
||||
# @see Hanami::Router#recognize
|
||||
#
|
||||
# @since 0.5.0
|
||||
# @api public
|
||||
class RecognizedRoute
|
||||
# @since 0.5.0
|
||||
# @api private
|
||||
def initialize(endpoint, env)
|
||||
@endpoint = endpoint
|
||||
@env = env
|
||||
|
@ -54,12 +57,22 @@ module Hanami
|
|||
@env[::Rack::PATH_INFO]
|
||||
end
|
||||
|
||||
# Returns the route's path params.
|
||||
#
|
||||
# @return [Hash]
|
||||
#
|
||||
# @since 0.7.0
|
||||
# @api public
|
||||
def params
|
||||
@env[Router::PARAMS]
|
||||
end
|
||||
|
||||
# Returns the route's endpoint object.
|
||||
#
|
||||
# Returns nil if the route is a {#redirect? redirect}.
|
||||
#
|
||||
# @return [Object, nil]
|
||||
#
|
||||
# @since 0.7.0
|
||||
# @api public
|
||||
def endpoint
|
||||
|
@ -68,18 +81,30 @@ module Hanami
|
|||
@endpoint
|
||||
end
|
||||
|
||||
# Returns true if the route has an {#endpoint}.
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @since 0.7.0
|
||||
# @api public
|
||||
def routable?
|
||||
!@endpoint.nil?
|
||||
end
|
||||
|
||||
# Returns true if the route is a redirect.
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @since 0.7.0
|
||||
# @api public
|
||||
def redirect?
|
||||
@endpoint.is_a?(Redirect)
|
||||
end
|
||||
|
||||
# Returns the route's redirect path, if it is a redirect, or nil otherwise.
|
||||
#
|
||||
# @return [String, nil]
|
||||
#
|
||||
# @since 0.7.0
|
||||
# @api public
|
||||
def redirection_path
|
||||
|
|
|
@ -8,25 +8,57 @@ module Hanami
|
|||
# A route from the router
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
class Route
|
||||
# @api private
|
||||
# @since 2.0.0
|
||||
# @api private
|
||||
ROUTE_CONSTRAINT_SEPARATOR = ", "
|
||||
private_constant :ROUTE_CONSTRAINT_SEPARATOR
|
||||
|
||||
# Returns the route's HTTP method.
|
||||
#
|
||||
# @example
|
||||
# route.http_method # => "GET"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
attr_reader :http_method
|
||||
|
||||
# Returns the route's path.
|
||||
#
|
||||
# @example
|
||||
# route.path # => "/a/b/c"
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
attr_reader :path
|
||||
|
||||
# Returns the route's Rack endpoint, as given to `to:` when the route was defined.
|
||||
#
|
||||
# @return [Object]
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
attr_reader :to
|
||||
|
||||
# Returns the route's unique name, as given to `as:` when the route was defined.
|
||||
#
|
||||
# @return [Object]
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
attr_reader :as
|
||||
|
||||
# Returns the route's contraints hash for its path variables.
|
||||
#
|
||||
# @return [Hash]
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
attr_reader :constraints
|
||||
|
||||
# @api private
|
||||
|
@ -41,22 +73,48 @@ module Hanami
|
|||
freeze
|
||||
end
|
||||
|
||||
# Returns true if the route is for the HEAD HTTP method.
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @see #http_method
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
def head?
|
||||
http_method == ::Rack::HEAD
|
||||
end
|
||||
|
||||
# Returns true if the route has a name.
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @see #as
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
def as?
|
||||
!as.nil?
|
||||
end
|
||||
|
||||
# Returns true if the route has any constraints.
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @see #constraints
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
def constraints?
|
||||
constraints.any?
|
||||
end
|
||||
|
||||
# Returns a string containing a human-readable representation of the route's {#to} endpoint.
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
def inspect_to(value = to)
|
||||
case value
|
||||
when String
|
||||
|
@ -74,14 +132,26 @@ module Hanami
|
|||
end
|
||||
end
|
||||
|
||||
# Returns a string containing a human-readable representation of the route's {#constraints}.
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
def inspect_constraints
|
||||
@constraints.map do |key, value|
|
||||
"#{key}: #{value.inspect}"
|
||||
end.join(ROUTE_CONSTRAINT_SEPARATOR)
|
||||
end
|
||||
|
||||
# Returns a string containing a human-readable representation of the route's name.
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @see #as
|
||||
#
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
def inspect_as
|
||||
as ? as.inspect : Router::EMPTY_STRING
|
||||
end
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "hanami/router/error"
|
||||
require "hanami/router/errors"
|
||||
require "mustermann/error"
|
||||
|
||||
module Hanami
|
||||
class Router
|
||||
# URL Helpers
|
||||
# @since 2.0.0
|
||||
# @api private
|
||||
class UrlHelpers
|
||||
# @since 2.0.0
|
||||
# @api private
|
||||
|
@ -21,17 +22,17 @@ module Hanami
|
|||
end
|
||||
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
# @api private
|
||||
def path(name, variables = {})
|
||||
@named.fetch(name.to_sym) do
|
||||
raise InvalidRouteException.new(name)
|
||||
raise MissingRouteError.new(name)
|
||||
end.expand(:append, variables)
|
||||
rescue Mustermann::ExpandError => exception
|
||||
raise InvalidRouteExpansionException.new(name, exception.message)
|
||||
raise InvalidRouteExpansionError.new(name, exception.message)
|
||||
end
|
||||
|
||||
# @since 2.0.0
|
||||
# @api public
|
||||
# @api private
|
||||
def url(name, variables = {})
|
||||
@base_url + path(name, variables)
|
||||
end
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
module Hanami
|
||||
class Router
|
||||
# Returns the hanami-router version.
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api public
|
||||
VERSION = "2.0.0.rc1"
|
||||
end
|
||||
|
|
|
@ -24,7 +24,7 @@ RSpec.describe Hanami::Router do
|
|||
end
|
||||
|
||||
it "raises error when variables aren't satisfied" do
|
||||
expect { router.path(:variables) }.to raise_error(Hanami::Router::InvalidRouteExpansionException, "No route could be generated for `:variables': cannot expand with keys [], possible expansions: [:id]")
|
||||
expect { router.path(:variables) }.to raise_error(Hanami::Router::InvalidRouteExpansionError, "No route could be generated for `:variables': cannot expand with keys [], possible expansions: [:id]")
|
||||
end
|
||||
|
||||
it "recognizes string with variables and constraints" do
|
||||
|
@ -48,7 +48,7 @@ RSpec.describe Hanami::Router do
|
|||
|
||||
# FIXME: shall we keep this behavior?
|
||||
xit "raises error when insufficient params are passed" do
|
||||
expect { router.path(nil) }.to raise_error(Hanami::Router::InvalidRouteExpansionException, "No route could be generated for nil - please check given arguments")
|
||||
expect { router.path(nil) }.to raise_error(Hanami::Router::InvalidRouteExpansionError, "No route could be generated for nil - please check given arguments")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,7 +25,7 @@ RSpec.describe Hanami::Router do
|
|||
end
|
||||
|
||||
it "raises error when variables aren't satisfied" do
|
||||
expect { router.url(:variables) }.to raise_error(Hanami::Router::InvalidRouteExpansionException, "No route could be generated for `:variables': cannot expand with keys [], possible expansions: [:id]")
|
||||
expect { router.url(:variables) }.to raise_error(Hanami::Router::InvalidRouteExpansionError, "No route could be generated for `:variables': cannot expand with keys [], possible expansions: [:id]")
|
||||
end
|
||||
|
||||
it "recognizes string with variables and constraints" do
|
||||
|
@ -49,7 +49,7 @@ RSpec.describe Hanami::Router do
|
|||
|
||||
# FIXME: should preserve this behavior?
|
||||
xit "raises error when insufficient params are passed" do
|
||||
expect { router.url(nil) }.to raise_error(Hanami::Router::InvalidRouteExpansionException, "No route could be generated for nil - please check given arguments")
|
||||
expect { router.url(nil) }.to raise_error(Hanami::Router::InvalidRouteExpansionError, "No route could be generated for nil - please check given arguments")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue