2012-04-04 19:26:07 +02:00
# Used for merging results of metadata callbacks
2013-12-28 01:26:31 +01:00
require 'active_support/core_ext/hash/deep_merge'
2012-10-21 06:19:13 +02:00
require 'monitor'
2012-04-04 19:26:07 +02:00
2014-07-09 02:02:02 +02:00
# Ignores
Middleman :: Extensions . register :sitemap_ignore , auto_activate : :before_configuration do
require 'middleman-core/sitemap/extensions/ignores'
Middleman :: Sitemap :: Extensions :: Ignores
end
# Files on Disk
Middleman :: Extensions . register :sitemap_ondisk , auto_activate : :before_configuration do
require 'middleman-core/sitemap/extensions/on_disk'
Middleman :: Sitemap :: Extensions :: OnDisk
end
# Endpoints
Middleman :: Extensions . register :sitemap_endpoint , auto_activate : :before_configuration do
require 'middleman-core/sitemap/extensions/request_endpoints'
Middleman :: Sitemap :: Extensions :: RequestEndpoints
end
# Proxies
Middleman :: Extensions . register :sitemap_proxies , auto_activate : :before_configuration do
require 'middleman-core/sitemap/extensions/proxies'
Middleman :: Sitemap :: Extensions :: Proxies
end
# Redirects
Middleman :: Extensions . register :sitemap_redirects , auto_activate : :before_configuration do
require 'middleman-core/sitemap/extensions/redirects'
Middleman :: Sitemap :: Extensions :: Redirects
end
2014-01-01 03:21:30 +01:00
2012-05-07 23:41:39 +02:00
module Middleman
# Sitemap namespace
module Sitemap
# The Store class
#
# The Store manages a collection of Resource objects, which represent
# individual items in the sitemap. Resources are indexed by "source path",
# which is the path relative to the source directory, minus any template
# extensions. All "path" parameters used in this class are source paths.
class Store
2014-05-28 08:05:37 +02:00
# @return [Middleman::Application]
attr_reader :app
2012-05-07 23:41:39 +02:00
# Initialize with parent app
# @param [Middleman::Application] app
def initialize ( app )
2013-12-31 23:41:17 +01:00
@app = app
2012-05-07 23:41:39 +02:00
@resources = [ ]
2014-04-28 07:50:19 +02:00
# TODO: Should this be a set or hash?
2012-05-07 23:41:39 +02:00
@resource_list_manipulators = [ ]
2012-09-16 07:24:39 +02:00
@needs_sitemap_rebuild = true
2014-04-29 19:50:21 +02:00
2012-10-21 06:19:13 +02:00
@lock = Monitor . new
2012-09-16 07:24:39 +02:00
reset_lookup_cache!
2012-08-14 00:39:06 +02:00
2014-07-05 20:17:41 +02:00
@app . config_context . class . send :def_delegator , :app , :sitemap
2012-05-07 23:41:39 +02:00
end
2012-02-09 08:00:29 +01:00
2014-05-11 08:47:04 +02:00
# Register an object which can transform the sitemap resource list. Best to register
# these in a `before_configuration` or `after_configuration` hook.
2012-09-16 07:24:39 +02:00
#
2012-05-07 23:41:39 +02:00
# @param [Symbol] name Name of the manipulator for debugging
2014-05-11 08:47:04 +02:00
# @param [#manipulate_resource_list] manipulator Resource list manipulator
2014-05-12 09:00:53 +02:00
# @param [Numeric] priority Sets the order of this resource list manipulator relative to the rest. By default this is 50, and manipulators run in the order they are registered, but if a priority is provided then this will run ahead of or behind other manipulators.
2012-05-07 23:41:39 +02:00
# @return [void]
2014-05-12 09:00:53 +02:00
def register_resource_list_manipulator ( name , manipulator , priority = 50 )
# The third argument used to be a boolean - handle those who still pass one
priority = 50 unless priority . is_a? Numeric
@resource_list_manipulators << [ name , manipulator , priority ]
# The index trick is used so that the sort is stable - manipulators with the same priority
# will always be ordered in the same order as they were registered.
n = 0
@resource_list_manipulators = @resource_list_manipulators . sort_by do | m |
n += 1
[ m [ 2 ] , n ]
end
2012-09-16 07:24:39 +02:00
rebuild_resource_list! ( :registered_new )
2012-04-04 19:26:07 +02:00
end
2012-08-14 00:39:06 +02:00
2012-05-07 23:41:39 +02:00
# Rebuild the list of resources from scratch, using registed manipulators
# @return [void]
2014-05-11 08:47:04 +02:00
def rebuild_resource_list! ( _ = nil )
2012-10-21 06:19:13 +02:00
@lock . synchronize do
@needs_sitemap_rebuild = true
end
2011-11-21 02:05:29 +01:00
end
2012-08-14 00:39:06 +02:00
2012-05-07 23:41:39 +02:00
# Find a resource given its original path
# @param [String] request_path The original path of a resource.
# @return [Middleman::Sitemap::Resource]
def find_resource_by_path ( request_path )
2012-10-21 06:19:13 +02:00
@lock . synchronize do
request_path = :: Middleman :: Util . normalize_path ( request_path )
ensure_resource_list_updated!
@_lookup_by_path [ request_path ]
end
2012-05-07 23:41:39 +02:00
end
2012-08-14 00:39:06 +02:00
2012-05-07 23:41:39 +02:00
# Find a resource given its destination path
# @param [String] request_path The destination (output) path of a resource.
# @return [Middleman::Sitemap::Resource]
def find_resource_by_destination_path ( request_path )
2012-10-21 06:19:13 +02:00
@lock . synchronize do
request_path = :: Middleman :: Util . normalize_path ( request_path )
ensure_resource_list_updated!
@_lookup_by_destination_path [ request_path ]
end
2012-05-07 23:41:39 +02:00
end
2012-08-14 00:39:06 +02:00
2012-05-07 23:41:39 +02:00
# Get the array of all resources
# @param [Boolean] include_ignored Whether to include ignored resources
# @return [Array<Middleman::Sitemap::Resource>]
def resources ( include_ignored = false )
2012-10-21 06:19:13 +02:00
@lock . synchronize do
ensure_resource_list_updated!
if include_ignored
@resources
else
2013-05-23 09:11:09 +02:00
@resources_not_ignored || = @resources . reject ( & :ignored? )
2012-10-21 06:19:13 +02:00
end
2012-05-07 23:41:39 +02:00
end
2012-02-12 20:45:42 +01:00
end
2012-08-14 00:39:06 +02:00
2013-05-23 09:11:09 +02:00
# Invalidate our cached view of resource that are not ingnored. If your extension
# adds ways to ignore files, you should call this to make sure #resources works right.
def invalidate_resources_not_ignored_cache!
@resources_not_ignored = nil
end
2012-05-07 23:41:39 +02:00
# Get the URL path for an on-disk file
# @param [String] file
# @return [String]
def file_to_path ( file )
2012-10-14 07:37:24 +02:00
file = File . join ( @app . root , file )
2012-08-14 00:39:06 +02:00
2013-12-28 01:26:31 +01:00
prefix = @app . source_dir . sub ( / \/ $ / , '' ) + '/'
2012-07-19 10:17:50 +02:00
return false unless file . start_with? ( prefix )
2012-08-14 00:39:06 +02:00
2013-12-28 01:26:31 +01:00
path = file . sub ( prefix , '' )
2012-08-14 00:39:06 +02:00
2012-06-20 05:07:50 +02:00
# Replace a file name containing automatic_directory_matcher with a folder
2012-10-14 07:37:24 +02:00
unless @app . config [ :automatic_directory_matcher ] . nil?
2013-12-28 01:26:31 +01:00
path = path . gsub ( @app . config [ :automatic_directory_matcher ] , '/' )
2012-06-20 05:07:50 +02:00
end
2012-08-14 00:39:06 +02:00
2012-05-07 23:41:39 +02:00
extensionless_path ( path )
end
2012-08-14 00:39:06 +02:00
2012-05-07 23:41:39 +02:00
# Get a path without templating extensions
# @param [String] file
# @return [String]
def extensionless_path ( file )
path = file . dup
2014-03-21 01:03:15 +01:00
remove_templating_extensions ( path )
2012-05-07 23:41:39 +02:00
end
2012-09-16 07:24:39 +02:00
# Actually update the resource list, assuming anything has called
# rebuild_resource_list! since the last time it was run. This is
# very expensive!
def ensure_resource_list_updated!
2012-10-21 06:19:13 +02:00
@lock . synchronize do
return unless @needs_sitemap_rebuild
@needs_sitemap_rebuild = false
2012-09-16 07:24:39 +02:00
2013-12-28 01:26:31 +01:00
@app . logger . debug '== Rebuilding resource list'
2012-09-16 07:24:39 +02:00
2014-05-12 09:00:53 +02:00
@resources = @resource_list_manipulators . reduce ( [ ] ) do | result , ( _ , manipulator , _ ) |
newres = manipulator . manipulate_resource_list ( result )
2012-09-16 07:24:39 +02:00
2012-10-21 06:19:13 +02:00
# Reset lookup cache
reset_lookup_cache!
newres . each do | resource |
@_lookup_by_path [ resource . path ] = resource
@_lookup_by_destination_path [ resource . destination_path ] = resource
end
2012-09-16 07:24:39 +02:00
2012-10-21 06:19:13 +02:00
newres
end
2013-05-23 09:11:09 +02:00
invalidate_resources_not_ignored_cache!
2012-09-16 07:24:39 +02:00
end
end
private
def reset_lookup_cache!
2012-10-21 06:19:13 +02:00
@lock . synchronize {
@_lookup_by_path = { }
@_lookup_by_destination_path = { }
}
2012-09-16 07:24:39 +02:00
end
2013-05-03 06:17:50 +02:00
# Removes the templating extensions, while keeping the others
# @param [String] path
# @return [String]
def remove_templating_extensions ( path )
2013-05-03 07:03:28 +02:00
# Strip templating extensions as long as Tilt knows them
2013-12-28 01:26:31 +01:00
path = path . sub ( File . extname ( path ) , '' ) while :: Tilt [ path ]
2013-05-03 06:17:50 +02:00
path
end
# Remove the locale token from the end of the path
# @param [String] path
# @return [String]
def strip_away_locale ( path )
2014-07-06 01:50:19 +02:00
if @app . extensions [ :i18n ]
2013-05-03 07:03:28 +02:00
path_bits = path . split ( '.' )
lang = path_bits . last
2014-07-06 01:50:19 +02:00
return path_bits [ 0 .. - 2 ] . join ( '.' ) if @app . extensions [ :i18n ] . langs . include? ( lang . to_sym )
2013-05-03 06:17:50 +02:00
end
path
end
2012-04-20 00:47:42 +02:00
end
2011-11-21 02:05:29 +01:00
end
2012-07-11 07:46:18 +02:00
end