implement redirect support
This commit is contained in:
parent
912b33929f
commit
d86dffa7c6
8 changed files with 271 additions and 127 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
3.1.2
|
||||||
|
===
|
||||||
|
|
||||||
|
* Added `redirect` command for generating meta refreshes
|
||||||
|
|
||||||
3.1.1
|
3.1.1
|
||||||
===
|
===
|
||||||
|
|
||||||
|
|
60
middleman-core/features/redirects.feature
Normal file
60
middleman-core/features/redirects.feature
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
Feature: Meta redirects
|
||||||
|
|
||||||
|
Scenario: Redirect to unknown file
|
||||||
|
Given a fixture app "large-build-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
redirect "hello.html", :to => "world.html"
|
||||||
|
"""
|
||||||
|
And the Server is running at "large-build-app"
|
||||||
|
When I go to "/hello.html"
|
||||||
|
Then I should see '<meta http-equiv=refresh content="0; url=world.html"'
|
||||||
|
|
||||||
|
Scenario: Redirect to external site
|
||||||
|
Given a fixture app "large-build-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
redirect "hello.html", :to => "http://example.com"
|
||||||
|
"""
|
||||||
|
And the Server is running at "large-build-app"
|
||||||
|
When I go to "/hello.html"
|
||||||
|
Then I should see '<meta http-equiv=refresh content="0; url=http://example.com"'
|
||||||
|
|
||||||
|
Scenario: Redirect to a resource
|
||||||
|
Given a fixture app "large-build-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
ready do
|
||||||
|
r = sitemap.find_resource_by_path("static.html")
|
||||||
|
redirect "hello.html", :to => r
|
||||||
|
end
|
||||||
|
"""
|
||||||
|
And the Server is running at "large-build-app"
|
||||||
|
When I go to "/hello.html"
|
||||||
|
Then I should see '<meta http-equiv=refresh content="0; url=/static.html"'
|
||||||
|
|
||||||
|
Scenario: Redirect to a path with directory index
|
||||||
|
Given a fixture app "large-build-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
activate :directory_indexes
|
||||||
|
redirect "hello.html", :to => "link_test.html"
|
||||||
|
redirect "hello2.html", :to => "services/index.html"
|
||||||
|
"""
|
||||||
|
And the Server is running at "large-build-app"
|
||||||
|
When I go to "/hello/index.html"
|
||||||
|
Then I should see '<meta http-equiv=refresh content="0; url=/link_test/"'
|
||||||
|
When I go to "/hello2/index.html"
|
||||||
|
Then I should see '<meta http-equiv=refresh content="0; url=/services/"'
|
||||||
|
|
||||||
|
Scenario: Redirect with custom html
|
||||||
|
Given a fixture app "large-build-app"
|
||||||
|
And a file named "config.rb" with:
|
||||||
|
"""
|
||||||
|
redirect "hello.html", :to => "world.html" do |from, to|
|
||||||
|
"#{from} to #{to}"
|
||||||
|
end
|
||||||
|
"""
|
||||||
|
And the Server is running at "large-build-app"
|
||||||
|
When I go to "/hello.html"
|
||||||
|
Then I should see 'hello.html to world.html'
|
|
@ -2,6 +2,7 @@ require "middleman-core/sitemap/store"
|
||||||
require "middleman-core/sitemap/resource"
|
require "middleman-core/sitemap/resource"
|
||||||
|
|
||||||
require "middleman-core/sitemap/extensions/on_disk"
|
require "middleman-core/sitemap/extensions/on_disk"
|
||||||
|
require "middleman-core/sitemap/extensions/redirects"
|
||||||
require "middleman-core/sitemap/extensions/request_endpoints"
|
require "middleman-core/sitemap/extensions/request_endpoints"
|
||||||
require "middleman-core/sitemap/extensions/proxies"
|
require "middleman-core/sitemap/extensions/proxies"
|
||||||
require "middleman-core/sitemap/extensions/ignores"
|
require "middleman-core/sitemap/extensions/ignores"
|
||||||
|
@ -20,6 +21,7 @@ module Middleman
|
||||||
app.register Middleman::Sitemap::Extensions::RequestEndpoints
|
app.register Middleman::Sitemap::Extensions::RequestEndpoints
|
||||||
app.register Middleman::Sitemap::Extensions::Proxies
|
app.register Middleman::Sitemap::Extensions::Proxies
|
||||||
app.register Middleman::Sitemap::Extensions::Ignores
|
app.register Middleman::Sitemap::Extensions::Ignores
|
||||||
|
app.register Middleman::Sitemap::Extensions::Redirects
|
||||||
|
|
||||||
# Set to automatically convert some characters into a directory
|
# Set to automatically convert some characters into a directory
|
||||||
app.config.define_setting :automatic_directory_matcher, nil, 'Set to automatically convert some characters into a directory'
|
app.config.define_setting :automatic_directory_matcher, nil, 'Set to automatically convert some characters into a directory'
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
module Middleman
|
||||||
|
|
||||||
|
module Sitemap
|
||||||
|
|
||||||
|
module Extensions
|
||||||
|
|
||||||
|
module Redirects
|
||||||
|
|
||||||
|
# Setup extension
|
||||||
|
class << self
|
||||||
|
|
||||||
|
# Once registered
|
||||||
|
def registered(app)
|
||||||
|
# Include methods
|
||||||
|
app.send :include, InstanceMethods
|
||||||
|
end
|
||||||
|
|
||||||
|
alias :included :registered
|
||||||
|
end
|
||||||
|
|
||||||
|
module InstanceMethods
|
||||||
|
def redirect_manager
|
||||||
|
@_redirect_manager ||= RedirectManager.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
def redirect(*args, &block)
|
||||||
|
redirect_manager.create_redirect(*args, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Manages the list of proxy configurations and manipulates the sitemap
|
||||||
|
# to include new resources based on those configurations
|
||||||
|
class RedirectManager
|
||||||
|
def initialize(app)
|
||||||
|
@app = app
|
||||||
|
@redirects = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
# Setup a redirect from a path to a target
|
||||||
|
# @param [String] path
|
||||||
|
# @param [Hash] The :to value gives a target path
|
||||||
|
# @return [void]
|
||||||
|
def create_redirect(path, opts={}, &block)
|
||||||
|
if block_given?
|
||||||
|
opts[:template] = block
|
||||||
|
end
|
||||||
|
|
||||||
|
@redirects[path] = opts
|
||||||
|
|
||||||
|
@app.sitemap.rebuild_resource_list!(:added_redirect)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Update the main sitemap resource list
|
||||||
|
# @return [void]
|
||||||
|
def manipulate_resource_list(resources)
|
||||||
|
resources + @redirects.map do |path, opts|
|
||||||
|
r = RedirectResource.new(
|
||||||
|
@app.sitemap,
|
||||||
|
path,
|
||||||
|
opts[:to]
|
||||||
|
)
|
||||||
|
r.output = opts[:template] if opts[:template]
|
||||||
|
r
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class RedirectResource < ::Middleman::Sitemap::Resource
|
||||||
|
attr_accessor :output
|
||||||
|
|
||||||
|
def initialize(store, path, target)
|
||||||
|
@request_path = target
|
||||||
|
|
||||||
|
super(store, path)
|
||||||
|
end
|
||||||
|
|
||||||
|
def template?
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def render(*args, &block)
|
||||||
|
url = ::Middleman::Util.url_for(store.app, @request_path, :relative => false, :find_resource => true)
|
||||||
|
|
||||||
|
if output
|
||||||
|
output.call(path, url)
|
||||||
|
else
|
||||||
|
<<-END
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv=refresh content="0; url=#{url}" />
|
||||||
|
<meta name="robots" content="noindex,follow" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
END
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# def request_path
|
||||||
|
# @request_path
|
||||||
|
# end
|
||||||
|
|
||||||
|
def binary?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def raw_data
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
|
||||||
|
def ignored?
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def metadata
|
||||||
|
@local_metadata.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,8 +11,6 @@ module Middleman
|
||||||
|
|
||||||
# Once registered
|
# Once registered
|
||||||
def registered(app)
|
def registered(app)
|
||||||
# ::Middleman::Sitemap::Resource.send :include, ResourceInstanceMethods
|
|
||||||
|
|
||||||
# Include methods
|
# Include methods
|
||||||
app.send :include, InstanceMethods
|
app.send :include, InstanceMethods
|
||||||
end
|
end
|
||||||
|
@ -20,65 +18,6 @@ module Middleman
|
||||||
alias :included :registered
|
alias :included :registered
|
||||||
end
|
end
|
||||||
|
|
||||||
# module ResourceInstanceMethods
|
|
||||||
# # Whether this page is a proxy
|
|
||||||
# # @return [Boolean]
|
|
||||||
# def proxy?
|
|
||||||
# !!@proxied_to
|
|
||||||
# end
|
|
||||||
|
|
||||||
# # Set this page to proxy to a target path
|
|
||||||
# # @param [String] target
|
|
||||||
# # @return [void]
|
|
||||||
# def proxy_to(target)
|
|
||||||
# target = ::Middleman::Util.normalize_path(target)
|
|
||||||
# raise "You can't proxy #{path} to itself!" if target == path
|
|
||||||
# @proxied_to = target
|
|
||||||
# end
|
|
||||||
|
|
||||||
# # The path of the page this page is proxied to, or nil if it's not proxied.
|
|
||||||
# # @return [String]
|
|
||||||
# def proxied_to
|
|
||||||
# @proxied_to
|
|
||||||
# end
|
|
||||||
|
|
||||||
# # The resource for the page this page is proxied to. Throws an exception
|
|
||||||
# # if there is no resource.
|
|
||||||
# # @return [Sitemap::Resource]
|
|
||||||
# def proxied_to_resource
|
|
||||||
# proxy_resource = store.find_resource_by_path(proxied_to)
|
|
||||||
|
|
||||||
# unless proxy_resource
|
|
||||||
# raise "Path #{path} proxies to unknown file #{proxied_to}:#{store.resources.map(&:path)}"
|
|
||||||
# end
|
|
||||||
|
|
||||||
# if proxy_resource.proxy?
|
|
||||||
# raise "You can't proxy #{path} to #{proxied_to} which is itself a proxy."
|
|
||||||
# end
|
|
||||||
|
|
||||||
# proxy_resource
|
|
||||||
# end
|
|
||||||
|
|
||||||
# def get_source_file
|
|
||||||
# if proxy?
|
|
||||||
# proxied_to_resource.source_file
|
|
||||||
# else
|
|
||||||
# super
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|
||||||
# def content_type
|
|
||||||
# mime_type = super
|
|
||||||
# return mime_type if mime_type
|
|
||||||
|
|
||||||
# if proxy?
|
|
||||||
# proxied_to_resource.content_type
|
|
||||||
# else
|
|
||||||
# nil
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
|
|
||||||
module InstanceMethods
|
module InstanceMethods
|
||||||
def endpoint_manager
|
def endpoint_manager
|
||||||
@_endpoint_manager ||= EndpointManager.new(self)
|
@_endpoint_manager ||= EndpointManager.new(self)
|
||||||
|
|
|
@ -41,6 +41,9 @@ module Middleman
|
||||||
|
|
||||||
# Proxies
|
# Proxies
|
||||||
register_resource_list_manipulator(:proxies, @app.proxy_manager)
|
register_resource_list_manipulator(:proxies, @app.proxy_manager)
|
||||||
|
|
||||||
|
# Redirects
|
||||||
|
register_resource_list_manipulator(:redirects, @app.redirect_manager)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Register a klass which can manipulate the main site map list. Best to register
|
# Register a klass which can manipulate the main site map list. Best to register
|
||||||
|
|
|
@ -146,5 +146,81 @@ module Middleman
|
||||||
end
|
end
|
||||||
end.flatten.compact
|
end.flatten.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Given a source path (referenced either absolutely or relatively)
|
||||||
|
# or a Resource, this will produce the nice URL configured for that
|
||||||
|
# path, respecting :relative_links, directory indexes, etc.
|
||||||
|
def self.url_for(app, path_or_resource, options={})
|
||||||
|
# Handle Resources and other things which define their own url method
|
||||||
|
url = path_or_resource.respond_to?(:url) ? path_or_resource.url : path_or_resource
|
||||||
|
|
||||||
|
begin
|
||||||
|
uri = URI(url)
|
||||||
|
rescue URI::InvalidURIError
|
||||||
|
# Nothing we can do with it, it's not really a URI
|
||||||
|
return url
|
||||||
|
end
|
||||||
|
|
||||||
|
relative = options.delete(:relative)
|
||||||
|
raise "Can't use the relative option with an external URL" if relative && uri.host
|
||||||
|
|
||||||
|
# Allow people to turn on relative paths for all links with
|
||||||
|
# set :relative_links, true
|
||||||
|
# but still override on a case by case basis with the :relative parameter.
|
||||||
|
effective_relative = relative || false
|
||||||
|
effective_relative = true if relative.nil? && app.config[:relative_links]
|
||||||
|
|
||||||
|
# Try to find a sitemap resource corresponding to the desired path
|
||||||
|
this_resource = app.current_resource # store in a local var to save work
|
||||||
|
|
||||||
|
if path_or_resource.is_a?(::Middleman::Sitemap::Resource)
|
||||||
|
resource = path_or_resource
|
||||||
|
resource_url = url
|
||||||
|
elsif this_resource && uri.path
|
||||||
|
# Handle relative urls
|
||||||
|
url_path = Pathname(uri.path)
|
||||||
|
current_source_dir = Pathname('/' + this_resource.path).dirname
|
||||||
|
url_path = current_source_dir.join(url_path) if url_path.relative?
|
||||||
|
resource = app.sitemap.find_resource_by_path(url_path.to_s)
|
||||||
|
resource_url = resource.url if resource
|
||||||
|
elsif options[:find_resource] && uri.path
|
||||||
|
resource = app.sitemap.find_resource_by_path(uri.path)
|
||||||
|
resource_url = resource.url if resource
|
||||||
|
end
|
||||||
|
|
||||||
|
if resource
|
||||||
|
# Switch to the relative path between this_resource and the given resource
|
||||||
|
# if we've been asked to.
|
||||||
|
if effective_relative
|
||||||
|
# Output urls relative to the destination path, not the source path
|
||||||
|
current_dir = Pathname('/' + this_resource.destination_path).dirname
|
||||||
|
relative_path = Pathname(resource_url).relative_path_from(current_dir).to_s
|
||||||
|
|
||||||
|
# Put back the trailing slash to avoid unnecessary Apache redirects
|
||||||
|
if resource_url.end_with?('/') && !relative_path.end_with?('/')
|
||||||
|
relative_path << '/'
|
||||||
|
end
|
||||||
|
|
||||||
|
uri.path = relative_path
|
||||||
|
else
|
||||||
|
uri.path = resource_url
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# If they explicitly asked for relative links but we can't find a resource...
|
||||||
|
raise "No resource exists at #{url}" if relative
|
||||||
|
end
|
||||||
|
|
||||||
|
# Support a :query option that can be a string or hash
|
||||||
|
if query = options.delete(:query)
|
||||||
|
uri.query = query.respond_to?(:to_param) ? query.to_param : query.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
# Support a :fragment or :anchor option just like Padrino
|
||||||
|
fragment = options.delete(:anchor) || options.delete(:fragment)
|
||||||
|
uri.fragment = fragment.to_s if fragment
|
||||||
|
|
||||||
|
# Finally make the URL back into a string
|
||||||
|
uri.to_s
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -189,72 +189,7 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
|
||||||
# or a Resource, this will produce the nice URL configured for that
|
# or a Resource, this will produce the nice URL configured for that
|
||||||
# path, respecting :relative_links, directory indexes, etc.
|
# path, respecting :relative_links, directory indexes, etc.
|
||||||
def url_for(path_or_resource, options={})
|
def url_for(path_or_resource, options={})
|
||||||
# Handle Resources and other things which define their own url method
|
::Middleman::Util.url_for(self, path_or_resource, options)
|
||||||
url = path_or_resource.respond_to?(:url) ? path_or_resource.url : path_or_resource
|
|
||||||
|
|
||||||
begin
|
|
||||||
uri = URI(url)
|
|
||||||
rescue URI::InvalidURIError
|
|
||||||
# Nothing we can do with it, it's not really a URI
|
|
||||||
return url
|
|
||||||
end
|
|
||||||
|
|
||||||
relative = options.delete(:relative)
|
|
||||||
raise "Can't use the relative option with an external URL" if relative && uri.host
|
|
||||||
|
|
||||||
# Allow people to turn on relative paths for all links with
|
|
||||||
# set :relative_links, true
|
|
||||||
# but still override on a case by case basis with the :relative parameter.
|
|
||||||
effective_relative = relative || false
|
|
||||||
effective_relative = true if relative.nil? && config[:relative_links]
|
|
||||||
|
|
||||||
# Try to find a sitemap resource corresponding to the desired path
|
|
||||||
this_resource = current_resource # store in a local var to save work
|
|
||||||
if path_or_resource.is_a?(::Middleman::Sitemap::Resource)
|
|
||||||
resource = path_or_resource
|
|
||||||
resource_url = url
|
|
||||||
elsif this_resource && uri.path
|
|
||||||
# Handle relative urls
|
|
||||||
url_path = Pathname(uri.path)
|
|
||||||
current_source_dir = Pathname('/' + this_resource.path).dirname
|
|
||||||
url_path = current_source_dir.join(url_path) if url_path.relative?
|
|
||||||
resource = sitemap.find_resource_by_path(url_path.to_s)
|
|
||||||
resource_url = resource.url if resource
|
|
||||||
end
|
|
||||||
|
|
||||||
if resource
|
|
||||||
# Switch to the relative path between this_resource and the given resource
|
|
||||||
# if we've been asked to.
|
|
||||||
if effective_relative
|
|
||||||
# Output urls relative to the destination path, not the source path
|
|
||||||
current_dir = Pathname('/' + this_resource.destination_path).dirname
|
|
||||||
relative_path = Pathname(resource_url).relative_path_from(current_dir).to_s
|
|
||||||
|
|
||||||
# Put back the trailing slash to avoid unnecessary Apache redirects
|
|
||||||
if resource_url.end_with?('/') && !relative_path.end_with?('/')
|
|
||||||
relative_path << '/'
|
|
||||||
end
|
|
||||||
|
|
||||||
uri.path = relative_path
|
|
||||||
else
|
|
||||||
uri.path = resource_url
|
|
||||||
end
|
|
||||||
else
|
|
||||||
# If they explicitly asked for relative links but we can't find a resource...
|
|
||||||
raise "No resource exists at #{url}" if relative
|
|
||||||
end
|
|
||||||
|
|
||||||
# Support a :query option that can be a string or hash
|
|
||||||
if query = options.delete(:query)
|
|
||||||
uri.query = query.respond_to?(:to_param) ? query.to_param : query.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
# Support a :fragment or :anchor option just like Padrino
|
|
||||||
fragment = options.delete(:anchor) || options.delete(:fragment)
|
|
||||||
uri.fragment = fragment.to_s if fragment
|
|
||||||
|
|
||||||
# Finally make the URL back into a string
|
|
||||||
uri.to_s
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Overload the regular link_to to be sitemap-aware - if you
|
# Overload the regular link_to to be sitemap-aware - if you
|
||||||
|
|
Loading…
Reference in a new issue