lib/yard/server/router.rb in yard-0.6.3 vs lib/yard/server/router.rb in yard-0.6.4
- old
+ new
@@ -1,32 +1,78 @@
module YARD
module Server
+ # A router class implements the logic used to recognize a request for a specific
+ # URL and run specific {Commands::Base commands}.
+ #
+ # == Subclassing Notes
+ # To create a custom router, subclass this class and pass it into the adapter
+ # options through {Adapter#initialize} or by directly modifying {Adapter#router}.
+ #
+ # The most general customization is to change the URL prefixes recognized by
+ # routing, which can be done by overriding {#docs_prefix}, {#list_prefix}
+ # and {#search_prefix}.
+ #
+ # == Implementing Custom Caching
+ # By default, the Router class performs static disk-based caching on all
+ # requests through the +#check_static_cache+. To override this behaviour,
+ # or create your own caching mechanism, mixin your own custom module with
+ # this method implemented as per {StaticCaching#check_static_cache}.
+ #
+ # @example Creating a subclassed router
+ # # Adds 'my' to all routing prefixes
+ # class MyRouter < YARD::Server::Router
+ # def docs_prefix; 'mydocs' end
+ # def list_prefix; 'mylist' end
+ # def search_prefix; 'mysearch' end
+ # end
+ #
+ # # Using it:
+ # WebrickAdapter.new(libraries, :router => MyRouter).start
class Router
include StaticCaching
include Commands
+ # @return [Adapter Dependent] the request data coming in with the routing
attr_accessor :request
+ # @return [Adapter] the adapter used by the router
attr_accessor :adapter
+ # Creates a new router for a specific adapter
+ #
+ # @param [Adapter] adapter the adapter to route requests to
def initialize(adapter)
self.adapter = adapter
end
+ # Perform routing on a specific request, serving the request as a static
+ # file through {Commands::StaticFileCommand} if no route is found.
+ #
+ # @param [Adapter Dependent] request the request object
+ # @return [Array(Number,Hash,Array)] the Rack-style server response data
def call(request)
self.request = request
if result = (check_static_cache || route)
result
else
StaticFileCommand.new(adapter.options).call(request)
end
end
+
+ # @group Route Prefixes
+ # @return [String] the URI prefix for all object documentation requests
def docs_prefix; 'docs' end
+
+ # @return [String] the URI prefix for all class/method/file list requests
def list_prefix; 'list' end
+
+ # @return [String] the URI prefix for all search requests
def search_prefix; 'search' end
+ # @group Routing Methods
+
# @return [Array(LibraryVersion, Array<String>)] the library followed
# by the rest of the path components in the request path. LibraryVersion
# will be nil if no matching library was found.
def parse_library_from_path(paths)
return [adapter.libraries.values.first.first, paths] if adapter.options[:single_library]
@@ -40,12 +86,17 @@
end
end
[library, paths]
end
- private
+ protected
+ # Performs routing algorithm to find which prefix is called, first
+ # parsing out library name/version information.
+ #
+ # @return [Array(Numeric,Hash,Array<String>)] the Rack-style response
+ # @return [nil] if no route is matched
def route
path = request.path.gsub(%r{//+}, '/').gsub(%r{^/|/$}, '')
return route_index if path.empty? || path == docs_prefix
case path
when /^(#{docs_prefix}|#{list_prefix}|#{search_prefix})(\/.*|$)/
@@ -60,10 +111,14 @@
end
end
nil
end
+ # Routes requests from {#docs_prefix} and calls the appropriate command
+ # @param [LibraryVersion] library the library to route for
+ # @param [Array<String>] paths path components (split by '/')
+ # @return (see #route)
def route_docs(library, paths)
return route_index if library.nil?
case paths.first
when "frames"
paths.shift
@@ -76,18 +131,23 @@
end
cmd = cmd.new(final_options(library, paths))
cmd.call(request)
end
+ # Routes for the index of a library / multiple libraries
+ # @return (see #route)
def route_index
if adapter.options[:single_library]
route_docs(adapter.libraries.values.first.first, [])
else
LibraryIndexCommand.new(adapter.options.merge(:path => '')).call(request)
end
end
+ # Routes requests from {#list_prefix} and calls the appropriate command
+ # @param (see #route_docs)
+ # @return (see #route_docs)
def route_list(library, paths)
return if paths.empty?
case paths.shift
when "class"; cmd = ListClassesCommand
when "methods"; cmd = ListMethodsCommand
@@ -95,14 +155,24 @@
else; return
end
cmd.new(final_options(library, paths)).call(request)
end
+ # Routes requests from {#search_prefix} and calls the appropriate command
+ # @param (see #route_docs)
+ # @return (see #route_docs)
def route_search(library, paths)
return unless paths.empty?
SearchCommand.new(final_options(library, paths)).call(request)
end
+ # @group Utility Methods
+
+ # Adds extra :library/:path option keys to the adapter options.
+ # Use this method when passing options to a command.
+ #
+ # @param (see #route_docs)
+ # @return [Hash] finalized options
def final_options(library, paths)
adapter.options.merge(:library => library, :path => paths.join('/'))
end
end
end