Internal routes representation.

Introduced classes

class AppGlobRoute

popcorn :: AppGlobRoute

Route with glob.
class AppParamRoute

popcorn :: AppParamRoute

Parameterizable routes.
class AppRoute

popcorn :: AppRoute

AppRoute provide services for path and uri manipulation and matching..
private class UriParam

popcorn :: UriParam

An uri parameter string like :id.
private interface UriPart

popcorn :: UriPart

A String that compose an URI.
private class UriString

popcorn :: UriString

A static uri string like users.

All class definitions

class AppGlobRoute

popcorn $ AppGlobRoute

Route with glob.
class AppParamRoute

popcorn $ AppParamRoute

Parameterizable routes.
class AppRoute

popcorn $ AppRoute

AppRoute provide services for path and uri manipulation and matching..
private class UriParam

popcorn $ UriParam

An uri parameter string like :id.
private interface UriPart

popcorn $ UriPart

A String that compose an URI.
private class UriString

popcorn $ UriString

A static uri string like users.
package_diagram popcorn::pop_routes pop_routes nitcorn nitcorn popcorn::pop_routes->nitcorn ...nitcorn ... ...nitcorn->nitcorn popcorn::pop_handlers pop_handlers popcorn::pop_handlers->popcorn::pop_routes popcorn::pop_logging pop_logging popcorn::pop_logging->popcorn::pop_handlers popcorn::pop_json pop_json popcorn::pop_json->popcorn::pop_handlers popcorn::pop_sessions pop_sessions popcorn::pop_sessions->popcorn::pop_handlers popcorn::pop_tasks pop_tasks popcorn::pop_tasks->popcorn::pop_handlers popcorn::pop_logging... ... popcorn::pop_logging...->popcorn::pop_logging popcorn::pop_json... ... popcorn::pop_json...->popcorn::pop_json popcorn::pop_sessions... ... popcorn::pop_sessions...->popcorn::pop_sessions popcorn::pop_tasks... ... popcorn::pop_tasks...->popcorn::pop_tasks

Ancestors

module abstract_collection

core :: abstract_collection

Abstract collection classes and services.
module abstract_text

core :: abstract_text

Abstract class for manipulation of sequences of characters
module array

core :: array

This module introduces the standard array structure.
module base64

base64 :: base64

Offers the base 64 encoding and decoding algorithms
module bitset

core :: bitset

Services to handle BitSet
module bytes

core :: bytes

Services for byte streams and arrays
module caching

serialization :: caching

Services for caching serialization engines
module circular_array

core :: circular_array

Efficient data structure to access both end of the sequence.
module codec_base

core :: codec_base

Base for codecs to use with streams
module codecs

core :: codecs

Group module for all codec-related manipulations
module collection

core :: collection

This module define several collection classes.
module core

core :: core

Standard classes and methods used by default by Nit programs and libraries.
module engine_tools

serialization :: engine_tools

Advanced services for serialization engines
module environ

core :: environ

Access to the environment variables of the process
module error

core :: error

Standard error-management infrastructure.
module exec

core :: exec

Invocation and management of operating system sub-processes.
module file

core :: file

File manipulations (create, read, write, etc.)
module file_server

nitcorn :: file_server

Provides the FileServer action, which is a standard and minimal file server
module fixed_ints

core :: fixed_ints

Basic integers of fixed-precision
module fixed_ints_text

core :: fixed_ints_text

Text services to complement fixed_ints
module flat

core :: flat

All the array-based text representations
module gc

core :: gc

Access to the Nit internal garbage collection mechanism
module hash_collection

core :: hash_collection

Introduce HashMap and HashSet.
module http_errors

nitcorn :: http_errors

Offers ErrorTemplate to display error pages
module http_request

nitcorn :: http_request

Provides the HttpRequest class and services to create it
module http_request_buffer

nitcorn :: http_request_buffer

Http request parsing for buffered inputs.
module http_response

nitcorn :: http_response

Provides the HttpResponse class and http_status_codes
module inspect

serialization :: inspect

Refine Serializable::inspect to show more useful information
module iso8859_1

core :: iso8859_1

Codec for ISO8859-1 I/O
module kernel

core :: kernel

Most basic classes and methods.
module libevent

libevent :: libevent

Low-level wrapper around the libevent library to manage events on file descriptors
module list

core :: list

This module handle double linked lists
module math

core :: math

Mathematical operations
module md5

md5 :: md5

Native MD5 digest implementation as Text::md5
module media_types

nitcorn :: media_types

Services to identify Internet media types (or MIME types, Content-types)
module meta

meta :: meta

Simple user-defined meta-level to manipulate types of instances as object.
module more_collections

more_collections :: more_collections

Highly specific, but useful, collections-related classes.
module native

core :: native

Native structures for text and bytes
module numeric

core :: numeric

Advanced services for Numeric types
module poset

poset :: poset

Pre order sets and partial order set (ie hierarchies)
module protocol

core :: protocol

module queue

core :: queue

Queuing data structures and wrappers
module range

core :: range

Module for range of discrete objects.
module re

core :: re

Regular expression support for all services based on Pattern
module reactor

nitcorn :: reactor

Core of the nitcorn project, provides HttpFactory and Action
module ropes

core :: ropes

Tree-based representation of a String.
module serialization

serialization :: serialization

General serialization services
module serialization_core

serialization :: serialization_core

Abstract services to serialize Nit objects to different formats
module server_config

nitcorn :: server_config

Classes and services to configure the server
module sessions

nitcorn :: sessions

Automated session management
module signal_handler

nitcorn :: signal_handler

Handle SIGINT and SIGTERM to close the server after all active events
module sorter

core :: sorter

This module contains classes used to compare things and sorts arrays.
module stream

core :: stream

Input and output streams of characters
module template

template :: template

Basic template system
module text

core :: text

All the classes and methods related to the manipulation of text entities
module time

core :: time

Management of time and dates
module token

nitcorn :: token

Simple generate_token service, independent of the rest of the nitcorn framework
module union_find

core :: union_find

union–find algorithm using an efficient disjoint-set data structure
module utf8

core :: utf8

Codec for UTF-8 I/O
module vararg_routes

nitcorn :: vararg_routes

Routes with parameters.

Parents

module nitcorn

nitcorn :: nitcorn

The nitcorn Web server framework creates server-side Web apps in Nit

Children

module pop_handlers

popcorn :: pop_handlers

Route handlers.

Descendants

module a_star-m

a_star-m

module api

nitc :: api

Components required to build a web server about the nit model.
module api_auth

nitc :: api_auth

module api_base

nitc :: api_base

Base classes used by nitweb.
module api_docdown

nitc :: api_docdown

Nitdoc specific Markdown format handling for Nitweb
module api_feedback

nitc :: api_feedback

Feedback related features
module api_light

nitc :: api_light

Highlight and collect messages from a piece of code
module api_model

nitc :: api_model

module example_angular

popcorn :: example_angular

This is an example of how to use angular.js with popcorn
module loader

github :: loader

module nitweb

nitc :: nitweb

Runs a webserver based on nitcorn that render things from model.
module pop_auth

popcorn :: pop_auth

Authentification handlers.
module pop_json

popcorn :: pop_json

Introduce useful services for JSON REST API handlers.
module pop_sessions

popcorn :: pop_sessions

Session handlers
module pop_tasks

popcorn :: pop_tasks

Popcorn threaded tasks
module pop_templates

popcorn :: pop_templates

Template rendering for popcorn
module pop_tests

popcorn :: pop_tests

Popcorn testing services
module popcorn

popcorn :: popcorn

Application server abstraction on top of nitcorn.
# Internal routes representation.
module pop_routes

import nitcorn

# AppRoute provide services for path and uri manipulation and matching..
#
# Default strict routes like `/` or `/user` match the same URI string.
# An exception is done for the trailing `/`, which is always omitted during the
# parsing.
#
# ~~~
# var route = new AppRoute("/")
# assert route.match("")
# assert route.match("/")
# assert not route.match("/user")
# assert not route.match("user")
#
# route = new AppRoute("/user")
# assert not route.match("/")
# assert route.match("/user")
# assert route.match("/user/")
# assert not route.match("/user/10")
# assert not route.match("/foo")
# assert not route.match("user")
# assert not route.match("/username")
# ~~~
class AppRoute

	# Route relative path from server root.
	var path: String

	# Does self match the `req`?
	fun match(uri: String): Bool do
		uri = uri.simplify_path
		var path = resolve_path(uri)
		if uri.is_empty and path == "/" then return true
		return uri == path
	end

	# Replace path parameters with concrete values from the `uri`.
	#
	# For strict routes, it returns the path unchanged:
	# ~~~
	# var route = new AppRoute("/")
	# assert route.resolve_path("/user/10/profile") == "/"
	#
	# route = new AppRoute("/user")
	# assert route.resolve_path("/user/10/profile") == "/user"
	# ~~~
	fun resolve_path(uri: String): String do return path.simplify_path

	# Remove `resolved_path` prefix from `uri`.
	#
	# Mainly used to resolve and match mountable routes.
	#
	# ~~~
	# var route = new AppRoute("/")
	# assert route.uri_root("/user/10/profile") == "/user/10/profile"
	#
	# route = new AppRoute("/user")
	# assert route.uri_root("/user/10/profile") == "/10/profile"
	# ~~~
	fun uri_root(uri: String): String do
		var path = resolve_path(uri)
		if path == "/" then return uri
		return uri.substring(path.length, uri.length).simplify_path
	end
end

# Parameterizable routes.
#
# Routes that can contains variables parts that will be resolved during the
# matching process.
#
# Route parameters are marked with a colon `:`
# ~~~
# var route = new AppParamRoute("/:id")
# assert not route.match("/")
# assert route.match("/user")
# assert route.match("/user/")
# assert not route.match("/user/10")
# ~~~
#
# It is possible to use more than one parameter in the same route:
# ~~~
# route = new AppParamRoute("/user/:userId/items/:itemId")
# assert not route.match("/user/10/items/")
# assert route.match("/user/10/items/e895346")
# assert route.match("/user/USER/items/0/")
# assert not route.match("/user/10/items/10/profile")
# ~~~
class AppParamRoute
	super AppRoute

	init do parse_path_parameters(path)

	# Cut `path` into `UriParts`.
	fun parse_path_parameters(path: String) do
		for part in path.split("/") do
			if not part.is_empty and part.first == ':' then
				# is an uri param
				path_parts.add new UriParam(part.substring(1, part.length))
			else
				# is a standard string
				path_parts.add new UriString(part)
			end
		end
	end

	# For parameterized routes, parameter names are replaced by their value in the URI.
	# ~~~
	# var route = new AppParamRoute("/user/:id")
	# assert route.resolve_path("/user/10/profile") == "/user/10"
	#
	# route = new AppParamRoute("/user/:userId/items/:itemId")
	# assert route.resolve_path("/user/Morriar/items/i156/desc") == "/user/Morriar/items/i156"
	# ~~~
	redef fun resolve_path(uri) do
		var uri_params = parse_uri_parameters(uri)
		var path = "/"
		for part in path_parts do
			if part isa UriString then
				path /= part.string
			else if part isa UriParam then
				path /= uri_params.get_or_default(part.name, part.name)
			end
		end
		return path.simplify_path
	end

	# Extract parameter values from `uri`.
	# ~~~
	# var route = new AppParamRoute("/user/:userId/items/:itemId")
	# var params = route.parse_uri_parameters("/user/10/items/i125/desc")
	# assert params["userId"] == "10"
	# assert params["itemId"] == "i125"
	# assert params.length == 2
	#
	# params = route.parse_uri_parameters("/")
	# assert params.is_empty
	# ~~~
	fun parse_uri_parameters(uri: String): Map[String, String] do
		var res = new HashMap[String, String]
		if path_parts.is_empty then return res
		var parts = uri.split("/")
		for i in [0 .. path_parts.length[ do
			if i >= parts.length then return res
			var ppart = path_parts[i]
			var part = parts[i]
			if not ppart.match(part) then return res
			if ppart isa UriParam then
				res[ppart.name] = part
			end
		end
		return res
	end

	private var path_parts = new Array[UriPart]
end

# Route with glob.
#
# Route variable part is suffixed with a star `*`:
# ~~~
# var route = new AppGlobRoute("/*")
# assert route.match("/")
# assert route.match("/user")
# assert route.match("/user/10")
# ~~~
#
# Glob routes can be combined with parameters:
# ~~~
# route = new AppGlobRoute("/user/:id/*")
# assert not route.match("/user")
# assert route.match("/user/10")
# assert route.match("/user/10/profile")
# ~~~
#
# Note that the star can be used directly on the end of an URI part:
# ~~~
# route = new AppGlobRoute("/user*")
# assert route.match("/user")
# assert route.match("/username")
# assert route.match("/user/10/profile")
# assert not route.match("/foo")
# ~~~
#
# For now, stars cannot be used inside a route, use URI parameters instead.
class AppGlobRoute
	super AppParamRoute

	# Path without the trailing `*`.
	# ~~~
	# var route = new AppGlobRoute("/user/:id/*")
	# assert route.resolve_path("/user/10/profile") == "/user/10"
	#
	# route = new AppGlobRoute("/user/:userId/items/:itemId*")
	# assert route.resolve_path("/user/Morriar/items/i156/desc") == "/user/Morriar/items/i156"
	# ~~~
	redef fun resolve_path(uri) do
		var path = super
		if path.has_suffix("*") then
			return path.substring(0, path.length - 1).simplify_path
		end
		return path.simplify_path
	end

	redef fun match(uri) do
		var path = resolve_path(uri)
		return uri.has_prefix(path.substring(0, path.length - 1))
	end
end

# A String that compose an URI.
#
# In practice, UriPart can be parameters or static strings.
private interface UriPart
	# Does `self` matches a part of the uri?
	fun match(uri_part: String): Bool is abstract
end

# An uri parameter string like `:id`.
private class UriParam
	super UriPart

	# Param `name` in the route uri.
	var name: String

	# Parameters match everything.
	redef fun match(part) do return not part.is_empty

	redef fun to_s do return name
end

# A static uri string like `users`.
private class UriString
	super UriPart

	# Uri part string.
	var string: String

	# Empty strings match everything otherwise matching is based on string equality.
	redef fun match(part) do return string.is_empty or string == part

	redef fun to_s do return string
end
lib/popcorn/pop_routes.nit:17,1--263,3