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