middleman/middleman-core/lib/middleman-core/sitemap/resource.rb

216 lines
6.8 KiB
Ruby
Raw Normal View History

require 'rack/mime'
require 'middleman-core/sitemap/extensions/traversal'
require 'middleman-core/file_renderer'
require 'middleman-core/template_renderer'
2014-07-03 04:04:34 +02:00
require 'middleman-core/contracts'
module Middleman
# Sitemap namespace
module Sitemap
# Sitemap Resource class
class Resource
2014-07-03 04:04:34 +02:00
include Contracts
include Middleman::Sitemap::Extensions::Traversal
# The source path of this resource (relative to the source directory,
# without template extensions)
# @return [String]
attr_reader :path
# The output path in the build directory for this resource
# @return [String]
attr_accessor :destination_path
2014-05-31 07:46:15 +02:00
2014-07-08 07:12:44 +02:00
# The on-disk source file for this resource, if there is one
# @return [String]
2015-04-24 19:26:42 +02:00
Contract Maybe[IsA['Middleman::SourceFile']]
attr_reader :file_descriptor
2014-07-08 07:12:44 +02:00
2014-05-31 07:46:15 +02:00
# The path to use when requesting this resource. Normally it's
# the same as {#destination_path} but it can be overridden in subclasses.
# @return [String]
2016-01-14 20:21:42 +01:00
alias request_path destination_path
2016-01-14 20:21:42 +01:00
METADATA_HASH = { options: Maybe[Hash], locals: Maybe[Hash], page: Maybe[Hash] }.freeze
2014-07-10 21:35:47 +02:00
2014-07-03 04:04:34 +02:00
# The metadata for this resource
# @return [Hash]
2015-04-24 19:26:42 +02:00
Contract METADATA_HASH
2014-07-03 04:04:34 +02:00
attr_reader :metadata
attr_accessor :ignored
# Initialize resource with parent store and URL
# @param [Middleman::Sitemap::Store] store
# @param [String] path
# @param [String] source
2014-12-23 23:54:21 +01:00
Contract IsA['Middleman::Sitemap::Store'], String, Maybe[Or[IsA['Middleman::SourceFile'], String]] => Any
def initialize(store, path, source=nil)
@store = store
@app = @store.app
@path = path
@ignored = false
2014-12-23 23:54:21 +01:00
2015-09-17 18:41:17 +02:00
source = Pathname(source) if source && source.is_a?(String)
2014-12-23 23:54:21 +01:00
2016-01-14 20:21:42 +01:00
@file_descriptor = if source && source.is_a?(Pathname)
::Middleman::SourceFile.new(source.relative_path_from(@app.source_dir), source, @app.source_dir, Set.new([:source]))
2014-12-23 23:54:21 +01:00
else
2016-01-14 20:21:42 +01:00
source
2014-12-23 23:54:21 +01:00
end
@destination_path = @path
# Options are generally rendering/sitemap options
# Locals are local variables for rendering this resource's template
# Page are data that is exposed through this resource's data member.
# Note: It is named 'page' for backwards compatibility with older MM.
2014-05-28 09:00:36 +02:00
@metadata = { options: {}, locals: {}, page: {} }
end
# Whether this resource has a template file
# @return [Boolean]
2015-04-24 19:26:42 +02:00
Contract Bool
def template?
return false if file_descriptor.nil?
!::Tilt[file_descriptor[:full_path].to_s].nil?
end
# Backwards compatible method for turning descriptor into a string.
# @return [String]
Contract String
def source_file
file_descriptor && file_descriptor[:full_path].to_s
end
2014-04-28 08:21:12 +02:00
# Merge in new metadata specific to this resource.
# @param [Hash] meta A metadata block with keys :options, :locals, :page.
# Options are generally rendering/sitemap options
# Locals are local variables for rendering this resource's template
# Page are data that is exposed through this resource's data member.
# Note: It is named 'page' for backwards compatibility with older MM.
2014-07-10 21:35:47 +02:00
Contract METADATA_HASH => METADATA_HASH
2014-04-28 08:21:12 +02:00
def add_metadata(meta={})
2014-05-28 09:00:36 +02:00
@metadata.deep_merge!(meta)
2014-04-28 08:21:12 +02:00
end
# Data about this resource, populated from frontmatter or extensions.
# @return [Hash]
Contract RespondTo[:indifferent_access?]
def data
2014-07-14 22:19:34 +02:00
::Middleman::Util.recursively_enhance(metadata[:page])
end
2014-04-28 08:21:12 +02:00
# Options about how this resource is rendered, such as its :layout,
# :renderer_options, and whether or not to use :directory_indexes.
# @return [Hash]
2015-04-24 19:26:42 +02:00
Contract Hash
2014-04-28 08:21:12 +02:00
def options
metadata[:options]
end
# Local variable mappings that are used when rendering the template for this resource.
# @return [Hash]
2015-04-24 19:26:42 +02:00
Contract Hash
2014-04-28 08:21:12 +02:00
def locals
metadata[:locals]
end
# Extension of the path (i.e. '.js')
# @return [String]
2015-04-24 19:26:42 +02:00
Contract String
def ext
File.extname(path)
end
# Render this resource
# @return [String]
2014-07-03 04:04:34 +02:00
Contract Hash, Hash => String
def render(opts={}, locs={})
return ::Middleman::FileRenderer.new(@app, file_descriptor[:full_path].to_s).template_data_for_file unless template?
2012-04-04 19:26:07 +02:00
2016-01-14 02:16:36 +01:00
# ::Middleman::Util.instrument 'render.resource', path: file_descriptor[:full_path].to_s, destination_path: destination_path do
2016-01-14 20:21:42 +01:00
md = metadata
opts = md[:options].deep_merge(opts)
locs = md[:locals].deep_merge(locs)
locs[:current_path] ||= destination_path
2013-06-24 22:39:14 +02:00
2016-01-14 20:21:42 +01:00
# Certain output file types don't use layouts
opts[:layout] = false if !opts.key?(:layout) && ext != '.html'
2013-06-24 22:39:14 +02:00
2016-01-14 20:21:42 +01:00
renderer = ::Middleman::TemplateRenderer.new(@app, file_descriptor[:full_path].to_s)
renderer.render(locs, opts)
2016-01-14 02:16:36 +01:00
# end
end
# A path without the directory index - so foo/index.html becomes
# just foo. Best for linking.
# @return [String]
2015-04-24 19:26:42 +02:00
Contract String
def url
url_path = destination_path
if @app.config[:strip_index_file]
url_path = url_path.sub(/(^|\/)#{Regexp.escape(@app.config[:index_file])}$/,
@app.config[:trailing_slash] ? '/' : '')
end
File.join(@app.config[:http_prefix], url_path)
end
# Whether the source file is binary.
#
# @return [Boolean]
2015-04-24 19:26:42 +02:00
Contract Bool
def binary?
!file_descriptor.nil? && ::Middleman::Util.binary?(file_descriptor[:full_path].to_s)
end
# Ignore a resource directly, without going through the whole
# ignore filter stuff.
# @return [void]
2015-04-24 19:26:42 +02:00
Contract Any
def ignore!
@ignored = true
end
# Whether the Resource is ignored
# @return [Boolean]
2015-04-24 19:26:42 +02:00
Contract Bool
def ignored?
@ignored
end
# The preferred MIME content type for this resource based on extension or metadata
# @return [String] MIME type for this resource
2015-04-24 19:26:42 +02:00
Contract Maybe[String]
def content_type
2014-07-08 07:12:44 +02:00
options[:content_type] || ::Rack::Mime.mime_type(ext, nil)
end
2014-06-29 00:07:43 +02:00
def to_s
2015-10-01 22:54:54 +02:00
"#<#{self.class} path=#{@path}>"
2014-06-29 00:07:43 +02:00
end
2016-01-14 20:21:42 +01:00
alias inspect to_s # Ruby 2.0 calls inspect for NoMethodError instead of to_s
2014-06-29 00:07:43 +02:00
end
class StringResource < Resource
def initialize(store, path, contents=nil, &block)
@request_path = path
@contents = block_given? ? block : contents
super(store, path)
end
def template?
true
end
def render(*)
@contents.respond_to?(:call) ? @contents.call : @contents
end
def binary?
false
end
2012-04-04 19:26:07 +02:00
end
end
end