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:
Tim Riley 2022-11-08 19:49:00 +11:00 committed by GitHub
parent 8364b0c962
commit d4f7a677a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 185 additions and 60 deletions

View File

@ -1,4 +1,2 @@
-
README.md
LICENSE.md
lib/**/*.rb
--markup=markdown
--plugin junk

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -2,6 +2,10 @@
module Hanami
class Router
# Returns the hanami-router version.
#
# @return [String]
#
# @api public
VERSION = "2.0.0.rc1"
end

View File

@ -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

View File

@ -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