spring cleaning util and discovery of nasty variable mutating in url_for
This commit is contained in:
parent
3cc74aae7e
commit
2e2415612a
|
@ -16,6 +16,9 @@ require 'active_support/core_ext/float/rounding'
|
||||||
# Simple callback library
|
# Simple callback library
|
||||||
require 'vendored-middleman-deps/hooks-0.2.0/lib/hooks'
|
require 'vendored-middleman-deps/hooks-0.2.0/lib/hooks'
|
||||||
|
|
||||||
|
# Our custom logger
|
||||||
|
require 'middleman-core/logger'
|
||||||
|
|
||||||
require 'middleman-core/sitemap'
|
require 'middleman-core/sitemap'
|
||||||
|
|
||||||
require 'middleman-core/configuration'
|
require 'middleman-core/configuration'
|
||||||
|
@ -156,8 +159,12 @@ module Middleman
|
||||||
# with_layout and page routing
|
# with_layout and page routing
|
||||||
include Middleman::CoreExtensions::Routing
|
include Middleman::CoreExtensions::Routing
|
||||||
|
|
||||||
|
attr_reader :logger
|
||||||
|
|
||||||
# Initialize the Middleman project
|
# Initialize the Middleman project
|
||||||
def initialize(&block)
|
def initialize(&block)
|
||||||
|
@logger = ::Middleman::Logger.singleton
|
||||||
|
|
||||||
# Clear the static class cache
|
# Clear the static class cache
|
||||||
cache.clear
|
cache.clear
|
||||||
|
|
||||||
|
@ -188,11 +195,15 @@ module Middleman
|
||||||
|
|
||||||
# Whether we're in development mode
|
# Whether we're in development mode
|
||||||
# @return [Boolean] If we're in dev mode
|
# @return [Boolean] If we're in dev mode
|
||||||
def development?; config[:environment] == :development; end
|
def development?
|
||||||
|
config[:environment] == :development
|
||||||
|
end
|
||||||
|
|
||||||
# Whether we're in build mode
|
# Whether we're in build mode
|
||||||
# @return [Boolean] If we're in build mode
|
# @return [Boolean] If we're in build mode
|
||||||
def build?; config[:environment] == :build; end
|
def build?
|
||||||
|
config[:environment] == :build
|
||||||
|
end
|
||||||
|
|
||||||
# The full path to the source directory
|
# The full path to the source directory
|
||||||
#
|
#
|
||||||
|
@ -201,7 +212,7 @@ module Middleman
|
||||||
File.join(root, config[:source])
|
File.join(root, config[:source])
|
||||||
end
|
end
|
||||||
|
|
||||||
delegate :logger, :instrument, :to => ::Middleman::Util
|
delegate :instrument, :to => ::Middleman::Util
|
||||||
|
|
||||||
# Work around this bug: http://bugs.ruby-lang.org/issues/4521
|
# Work around this bug: http://bugs.ruby-lang.org/issues/4521
|
||||||
# where Ruby will call to_s/inspect while printing exception
|
# where Ruby will call to_s/inspect while printing exception
|
||||||
|
@ -212,27 +223,6 @@ module Middleman
|
||||||
end
|
end
|
||||||
alias :inspect :to_s # Ruby 2.0 calls inspect for NoMethodError instead of to_s
|
alias :inspect :to_s # Ruby 2.0 calls inspect for NoMethodError instead of to_s
|
||||||
|
|
||||||
# Expand a path to include the index file if it's a directory
|
|
||||||
#
|
|
||||||
# @private
|
|
||||||
# @param [String] path Request path
|
|
||||||
# @return [String] Path with index file if necessary
|
|
||||||
def full_path(path)
|
|
||||||
resource = sitemap.find_resource_by_destination_path(path)
|
|
||||||
|
|
||||||
if !resource
|
|
||||||
# Try it with /index.html at the end
|
|
||||||
indexed_path = File.join(path.sub(%r{/$}, ''), config[:index_file])
|
|
||||||
resource = sitemap.find_resource_by_destination_path(indexed_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
if resource
|
|
||||||
'/' + resource.destination_path
|
|
||||||
else
|
|
||||||
'/' + Middleman::Util.normalize_path(path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
require 'middleman-core'
|
require 'middleman-core'
|
||||||
|
require 'middleman-core/logger'
|
||||||
|
|
||||||
require 'fileutils'
|
require 'fileutils'
|
||||||
require 'set'
|
require 'set'
|
||||||
|
|
||||||
|
@ -90,7 +92,7 @@ module Middleman::Cli
|
||||||
def shared_instance(verbose=false, instrument=false)
|
def shared_instance(verbose=false, instrument=false)
|
||||||
@_shared_instance ||= ::Middleman::Application.server.inst do
|
@_shared_instance ||= ::Middleman::Application.server.inst do
|
||||||
config[:environment] = :build
|
config[:environment] = :build
|
||||||
logger(verbose ? 0 : 1, instrument)
|
::Middleman::Logger.singleton(verbose ? 0 : 1, instrument)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,8 @@ require 'rack/file'
|
||||||
require 'rack/lint'
|
require 'rack/lint'
|
||||||
require 'rack/head'
|
require 'rack/head'
|
||||||
|
|
||||||
|
require 'middleman-core/util'
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
module CoreExtensions
|
module CoreExtensions
|
||||||
|
|
||||||
|
@ -231,7 +233,7 @@ module Middleman
|
||||||
if request_path.respond_to? :force_encoding
|
if request_path.respond_to? :force_encoding
|
||||||
request_path.force_encoding('UTF-8')
|
request_path.force_encoding('UTF-8')
|
||||||
end
|
end
|
||||||
request_path = full_path(request_path)
|
request_path = ::Middleman::Util.full_path(request_path, self)
|
||||||
|
|
||||||
# Run before callbacks
|
# Run before callbacks
|
||||||
run_hook :before
|
run_hook :before
|
||||||
|
|
|
@ -7,6 +7,18 @@ module Middleman
|
||||||
|
|
||||||
# The Middleman Logger
|
# The Middleman Logger
|
||||||
class Logger < ActiveSupport::BufferedLogger
|
class Logger < ActiveSupport::BufferedLogger
|
||||||
|
|
||||||
|
def self.singleton(*args)
|
||||||
|
if !@_logger || args.length > 0
|
||||||
|
if args.length == 1 && (args.first.is_a?(::String) || args.first.respond_to?(:write))
|
||||||
|
args = [0, false, args.first]
|
||||||
|
end
|
||||||
|
@_logger = new(*args)
|
||||||
|
end
|
||||||
|
|
||||||
|
@_logger
|
||||||
|
end
|
||||||
|
|
||||||
def initialize(log_level=1, is_instrumenting=false, target=$stdout)
|
def initialize(log_level=1, is_instrumenting=false, target=$stdout)
|
||||||
super(target)
|
super(target)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
require 'webrick'
|
require 'webrick'
|
||||||
require 'middleman-core/meta_pages'
|
require 'middleman-core/meta_pages'
|
||||||
|
require 'middleman-core/logger'
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
module PreviewServer
|
module PreviewServer
|
||||||
|
@ -90,7 +91,7 @@ module Middleman
|
||||||
|
|
||||||
private
|
private
|
||||||
def new_app
|
def new_app
|
||||||
opts = @options
|
opts = @options.dup
|
||||||
server = ::Middleman::Application.server
|
server = ::Middleman::Application.server
|
||||||
|
|
||||||
# Add in the meta pages application
|
# Add in the meta pages application
|
||||||
|
@ -100,11 +101,14 @@ module Middleman
|
||||||
end
|
end
|
||||||
|
|
||||||
@app = server.inst do
|
@app = server.inst do
|
||||||
|
::Middleman::Logger.singleton(
|
||||||
|
opts[:debug] ? 0 : 1,
|
||||||
|
opts[:instrumenting] || false
|
||||||
|
)
|
||||||
|
|
||||||
if opts[:environment]
|
if opts[:environment]
|
||||||
config[:environment] = opts[:environment].to_sym
|
config[:environment] = opts[:environment].to_sym
|
||||||
end
|
end
|
||||||
|
|
||||||
logger(opts[:debug] ? 0 : 1, opts[:instrumenting] || false)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,10 @@ module Middleman
|
||||||
end
|
end
|
||||||
|
|
||||||
def render(*args, &block)
|
def render(*args, &block)
|
||||||
url = ::Middleman::Util.url_for(store.app, @request_path, :relative => false, :find_resource => true)
|
url = ::Middleman::Util.url_for(store.app, @request_path, {
|
||||||
|
:relative => false,
|
||||||
|
:find_resource => true
|
||||||
|
})
|
||||||
|
|
||||||
if output
|
if output
|
||||||
output.call(path, url)
|
output.call(path, url)
|
||||||
|
|
|
@ -24,7 +24,7 @@ module Middleman
|
||||||
# Initialize with parent app
|
# Initialize with parent app
|
||||||
# @param [Middleman::Application] app
|
# @param [Middleman::Application] app
|
||||||
def initialize(app)
|
def initialize(app)
|
||||||
@app = app
|
@app = app
|
||||||
@resources = []
|
@resources = []
|
||||||
@_cached_metadata = {}
|
@_cached_metadata = {}
|
||||||
@resource_list_manipulators = []
|
@resource_list_manipulators = []
|
||||||
|
@ -252,10 +252,10 @@ module Middleman
|
||||||
# @param [String] path
|
# @param [String] path
|
||||||
# @return [String]
|
# @return [String]
|
||||||
def strip_away_locale(path)
|
def strip_away_locale(path)
|
||||||
if app.respond_to? :langs
|
if @app.respond_to? :langs
|
||||||
path_bits = path.split('.')
|
path_bits = path.split('.')
|
||||||
lang = path_bits.last
|
lang = path_bits.last
|
||||||
if app.langs.include?(lang.to_sym)
|
if @app.langs.include?(lang.to_sym)
|
||||||
return path_bits[0..-2].join('.')
|
return path_bits[0..-2].join('.')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
# Our custom logger
|
|
||||||
require 'middleman-core/logger'
|
|
||||||
|
|
||||||
# For instrumenting
|
# For instrumenting
|
||||||
require 'active_support/notifications'
|
require 'active_support/notifications'
|
||||||
|
|
||||||
|
@ -10,193 +7,263 @@ require 'thor'
|
||||||
# Core Pathname library used for traversal
|
# Core Pathname library used for traversal
|
||||||
require 'pathname'
|
require 'pathname'
|
||||||
|
|
||||||
|
# Template and Mime detection
|
||||||
require 'tilt'
|
require 'tilt'
|
||||||
require 'rack/mime'
|
require 'rack/mime'
|
||||||
|
|
||||||
module Middleman
|
module Middleman
|
||||||
|
|
||||||
module Util
|
module Util
|
||||||
|
class << self
|
||||||
|
|
||||||
# Whether the source file is binary.
|
# Whether the source file is binary.
|
||||||
#
|
#
|
||||||
# @param [String] filename The file to check.
|
# @param [String] filename The file to check.
|
||||||
# @return [Boolean]
|
# @return [Boolean]
|
||||||
def self.binary?(filename)
|
def binary?(filename)
|
||||||
ext = File.extname(filename)
|
ext = File.extname(filename)
|
||||||
return true if ext == '.svgz'
|
|
||||||
return false if Tilt.registered?(ext.sub('.',''))
|
|
||||||
|
|
||||||
ext = ".#{ext}" unless ext.to_s[0] == ?.
|
# We hardcode detecting of gzipped SVG files
|
||||||
mime = ::Rack::Mime.mime_type(ext, nil)
|
return true if ext == '.svgz'
|
||||||
unless mime
|
|
||||||
|
return false if Tilt.registered?(ext.sub('.', ''))
|
||||||
|
|
||||||
|
dot_ext = (ext.to_s[0] == ?.) ? ext.dup : ".#{ext}"
|
||||||
|
|
||||||
|
if mime = ::Rack::Mime.mime_type(dot_ext, nil)
|
||||||
|
!nonbinary_mime?(mime)
|
||||||
|
else
|
||||||
|
file_contents_include_binary_bytes?(filename)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Facade for ActiveSupport/Notification
|
||||||
|
def instrument(name, payload={}, &block)
|
||||||
|
suffixed_name = (name =~ /\.middleman$/) ? name.dup : "#{name}.middleman"
|
||||||
|
::ActiveSupport::Notifications.instrument(suffixed_name, payload, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Recursively convert a normal Hash into a HashWithIndifferentAccess
|
||||||
|
#
|
||||||
|
# @private
|
||||||
|
# @param [Hash] data Normal hash
|
||||||
|
# @return [Thor::CoreExt::HashWithIndifferentAccess]
|
||||||
|
def recursively_enhance(data)
|
||||||
|
if data.is_a? Hash
|
||||||
|
data = ::Thor::CoreExt::HashWithIndifferentAccess.new(data)
|
||||||
|
data.each do |key, val|
|
||||||
|
data[key] = recursively_enhance(val)
|
||||||
|
end
|
||||||
|
data
|
||||||
|
elsif data.is_a? Array
|
||||||
|
data.each_with_index do |val, i|
|
||||||
|
data[i] = recursively_enhance(val)
|
||||||
|
end
|
||||||
|
data
|
||||||
|
else
|
||||||
|
data
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Normalize a path to not include a leading slash
|
||||||
|
# @param [String] path
|
||||||
|
# @return [String]
|
||||||
|
def normalize_path(path)
|
||||||
|
# The tr call works around a bug in Ruby's Unicode handling
|
||||||
|
path.sub(%r{^/}, '').tr('','')
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is a separate method from normalize_path in case we
|
||||||
|
# change how we normalize paths
|
||||||
|
def strip_leading_slash(path)
|
||||||
|
path.sub(%r{^/}, '')
|
||||||
|
end
|
||||||
|
|
||||||
|
# Extract the text of a Rack response as a string.
|
||||||
|
# Useful for extensions implemented as Rack middleware.
|
||||||
|
# @param response The response from #call
|
||||||
|
# @return [String] The whole response as a string.
|
||||||
|
def extract_response_text(response)
|
||||||
|
# The rack spec states all response bodies must respond to each
|
||||||
|
result = ''
|
||||||
|
response.each do |part, s|
|
||||||
|
result << part
|
||||||
|
end
|
||||||
|
result
|
||||||
|
end
|
||||||
|
|
||||||
|
# Takes a matcher, which can be a literal string
|
||||||
|
# or a string containing glob expressions, or a
|
||||||
|
# regexp, or a proc, or anything else that responds
|
||||||
|
# to #match or #call, and returns whether or not the
|
||||||
|
# given path matches that matcher.
|
||||||
|
#
|
||||||
|
# @param matcher A matcher string/regexp/proc/etc
|
||||||
|
# @param path A path as a string
|
||||||
|
# @return [Boolean] Whether the path matches the matcher
|
||||||
|
def path_match(matcher, path)
|
||||||
|
case
|
||||||
|
when matcher.is_a?(String)
|
||||||
|
path.match(matcher)
|
||||||
|
when matcher.respond_to?(:match)
|
||||||
|
matcher.match(path)
|
||||||
|
when matcher.respond_to?(:call)
|
||||||
|
matcher.call(path)
|
||||||
|
else
|
||||||
|
File.fnmatch(matcher.to_s, path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get a recusive list of files inside a set of paths.
|
||||||
|
# Works with symlinks.
|
||||||
|
#
|
||||||
|
# @param paths Some paths string or Pathname
|
||||||
|
# @return [Array] An array of filenames
|
||||||
|
def all_files_under(*paths)
|
||||||
|
paths.flat_map do |p|
|
||||||
|
path = Pathname(p)
|
||||||
|
|
||||||
|
if path.directory?
|
||||||
|
all_files_under(*path.children)
|
||||||
|
elsif path.file?
|
||||||
|
path
|
||||||
|
end
|
||||||
|
end.compact
|
||||||
|
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 url_for(app, path_or_resource, options={})
|
||||||
|
# Handle Resources and other things which define their own url method
|
||||||
|
url = if path_or_resource.respond_to?(:url)
|
||||||
|
path_or_resource.url
|
||||||
|
else
|
||||||
|
path_or_resource.dup
|
||||||
|
end.gsub(' ', '%20')
|
||||||
|
|
||||||
|
# Try to parse URL
|
||||||
|
begin
|
||||||
|
uri = URI(url)
|
||||||
|
rescue URI::InvalidURIError
|
||||||
|
# Nothing we can do with it, it's not really a URI
|
||||||
|
return url
|
||||||
|
end
|
||||||
|
|
||||||
|
relative = options[: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 = options[:current_resource]
|
||||||
|
|
||||||
|
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
|
||||||
|
uri.path = relative_path_from_resource(this_resource, resource_url, effective_relative)
|
||||||
|
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[: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[:anchor] || options[:fragment]
|
||||||
|
uri.fragment = fragment.to_s if fragment
|
||||||
|
|
||||||
|
# Finally make the URL back into a string
|
||||||
|
uri.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
# Expand a path to include the index file if it's a directory
|
||||||
|
#
|
||||||
|
# @param [String] path Request path/
|
||||||
|
# @param [Middleman::Application] app The requesting app.
|
||||||
|
# @return [String] Path with index file if necessary.
|
||||||
|
def full_path(path, app)
|
||||||
|
resource = app.sitemap.find_resource_by_destination_path(path)
|
||||||
|
|
||||||
|
if !resource
|
||||||
|
# Try it with /index.html at the end
|
||||||
|
indexed_path = File.join(path.sub(%r{/$}, ''), app.config[:index_file])
|
||||||
|
resource = app.sitemap.find_resource_by_destination_path(indexed_path)
|
||||||
|
end
|
||||||
|
|
||||||
|
if resource
|
||||||
|
'/' + resource.destination_path
|
||||||
|
else
|
||||||
|
'/' + normalize_path(path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Is mime type known to be non-binary?
|
||||||
|
#
|
||||||
|
# @param [String] mime The mimetype to check.
|
||||||
|
# @return [Boolean]
|
||||||
|
def nonbinary_mime?(mime)
|
||||||
|
case
|
||||||
|
when mime.start_with?('text/')
|
||||||
|
true
|
||||||
|
when mime.include?('xml')
|
||||||
|
true
|
||||||
|
when mime.include?('json')
|
||||||
|
true
|
||||||
|
when mime.include?('javascript')
|
||||||
|
true
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Read a few bytes from the file and see if they are binary.
|
||||||
|
#
|
||||||
|
# @param [String] filename The file to check.
|
||||||
|
# @return [Boolean]
|
||||||
|
def file_contents_include_binary_bytes?(filename)
|
||||||
binary_bytes = [0, 1, 2, 3, 4, 5, 6, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31]
|
binary_bytes = [0, 1, 2, 3, 4, 5, 6, 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31]
|
||||||
s = File.read(filename, 4096) || ''
|
s = File.read(filename, 4096) || ''
|
||||||
s.each_byte do |c|
|
s.each_byte do |c|
|
||||||
return true if binary_bytes.include?(c)
|
return true if binary_bytes.include?(c)
|
||||||
end
|
end
|
||||||
return false
|
|
||||||
end
|
|
||||||
return false if mime.start_with?('text/')
|
|
||||||
return false if mime.include?('xml')
|
|
||||||
return false if mime.include?('json')
|
|
||||||
return false if mime.include?('javascript')
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
# The logger
|
false
|
||||||
#
|
|
||||||
# @return [Middleman::Logger] The logger
|
|
||||||
def self.logger(*args)
|
|
||||||
if !@_logger || args.length > 0
|
|
||||||
if args.length == 1 && (args.first.is_a?(::String) || args.first.respond_to?(:write))
|
|
||||||
args = [0, false, args.first]
|
|
||||||
end
|
|
||||||
@_logger = ::Middleman::Logger.new(*args)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@_logger
|
# Get a relative path to a resource.
|
||||||
end
|
#
|
||||||
|
# @param [Middleman::Sitemap::Resource] curr_resource The resource.
|
||||||
# Facade for ActiveSupport/Notification
|
# @param [String] resource_url The target url.
|
||||||
def self.instrument(name, payload={}, &block)
|
# @param [Boolean] relative If the path should be relative.
|
||||||
name << '.middleman' unless name =~ /\.middleman$/
|
# @return [String]
|
||||||
::ActiveSupport::Notifications.instrument(name, payload, &block)
|
def relative_path_from_resource(curr_resource, resource_url, relative)
|
||||||
end
|
# Switch to the relative path between resource and the given resource
|
||||||
|
|
||||||
# Recursively convert a normal Hash into a HashWithIndifferentAccess
|
|
||||||
#
|
|
||||||
# @private
|
|
||||||
# @param [Hash] data Normal hash
|
|
||||||
# @return [Thor::CoreExt::HashWithIndifferentAccess]
|
|
||||||
def self.recursively_enhance(data)
|
|
||||||
if data.is_a? Hash
|
|
||||||
data = ::Thor::CoreExt::HashWithIndifferentAccess.new(data)
|
|
||||||
data.each do |key, val|
|
|
||||||
data[key] = recursively_enhance(val)
|
|
||||||
end
|
|
||||||
data
|
|
||||||
elsif data.is_a? Array
|
|
||||||
data.each_with_index do |val, i|
|
|
||||||
data[i] = recursively_enhance(val)
|
|
||||||
end
|
|
||||||
data
|
|
||||||
else
|
|
||||||
data
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Normalize a path to not include a leading slash
|
|
||||||
# @param [String] path
|
|
||||||
# @return [String]
|
|
||||||
def self.normalize_path(path)
|
|
||||||
# The tr call works around a bug in Ruby's Unicode handling
|
|
||||||
path.sub(%r{^/}, '').tr('','')
|
|
||||||
end
|
|
||||||
|
|
||||||
# This is a separate method from normalize_path in case we
|
|
||||||
# change how we normalize paths
|
|
||||||
def self.strip_leading_slash(path)
|
|
||||||
path.sub(%r{^/}, '')
|
|
||||||
end
|
|
||||||
|
|
||||||
# Extract the text of a Rack response as a string.
|
|
||||||
# Useful for extensions implemented as Rack middleware.
|
|
||||||
# @param response The response from #call
|
|
||||||
# @return [String] The whole response as a string.
|
|
||||||
def self.extract_response_text(response)
|
|
||||||
# The rack spec states all response bodies must respond to each
|
|
||||||
result = ''
|
|
||||||
response.each do |part, s|
|
|
||||||
result << part
|
|
||||||
end
|
|
||||||
result
|
|
||||||
end
|
|
||||||
|
|
||||||
# Takes a matcher, which can be a literal string
|
|
||||||
# or a string containing glob expressions, or a
|
|
||||||
# regexp, or a proc, or anything else that responds
|
|
||||||
# to #match or #call, and returns whether or not the
|
|
||||||
# given path matches that matcher.
|
|
||||||
#
|
|
||||||
# @param matcher A matcher string/regexp/proc/etc
|
|
||||||
# @param path A path as a string
|
|
||||||
# @return [Boolean] Whether the path matches the matcher
|
|
||||||
def self.path_match(matcher, path)
|
|
||||||
if matcher.is_a? String
|
|
||||||
path.match matcher
|
|
||||||
elsif matcher.respond_to? :match
|
|
||||||
matcher.match path
|
|
||||||
elsif matcher.respond_to? :call
|
|
||||||
matcher.call path
|
|
||||||
else
|
|
||||||
File.fnmatch(matcher.to_s, path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get a recusive list of files inside a set of paths.
|
|
||||||
# Works with symlinks.
|
|
||||||
#
|
|
||||||
# @param paths Some paths string or Pathname
|
|
||||||
# @return [Array] An array of filenames
|
|
||||||
def self.all_files_under(*paths)
|
|
||||||
paths.flat_map do |p|
|
|
||||||
path = Pathname(p)
|
|
||||||
if path.directory?
|
|
||||||
all_files_under(*path.children)
|
|
||||||
elsif path.file?
|
|
||||||
path
|
|
||||||
end
|
|
||||||
end.compact
|
|
||||||
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
|
|
||||||
url = url.gsub(' ', '%20')
|
|
||||||
|
|
||||||
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 we've been asked to.
|
||||||
if effective_relative
|
if relative && curr_resource
|
||||||
# Output urls relative to the destination path, not the source path
|
# Output urls relative to the destination path, not the source path
|
||||||
current_dir = Pathname('/' + this_resource.destination_path).dirname
|
current_dir = Pathname('/' + curr_resource.destination_path).dirname
|
||||||
relative_path = Pathname(resource_url).relative_path_from(current_dir).to_s
|
relative_path = Pathname(resource_url).relative_path_from(current_dir).to_s
|
||||||
|
|
||||||
# Put back the trailing slash to avoid unnecessary Apache redirects
|
# Put back the trailing slash to avoid unnecessary Apache redirects
|
||||||
|
@ -204,26 +271,11 @@ module Middleman
|
||||||
relative_path << '/'
|
relative_path << '/'
|
||||||
end
|
end
|
||||||
|
|
||||||
uri.path = relative_path
|
relative_path
|
||||||
else
|
else
|
||||||
uri.path = resource_url
|
resource_url
|
||||||
end
|
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
|
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
|
end
|
|
@ -194,7 +194,10 @@ 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={})
|
||||||
::Middleman::Util.url_for(self, path_or_resource, options)
|
options_with_resource = options.dup
|
||||||
|
options_with_resource[:current_resource] ||= current_resource
|
||||||
|
|
||||||
|
::Middleman::Util.url_for(self, path_or_resource, options_with_resource)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Overload the regular link_to to be sitemap-aware - if you
|
# Overload the regular link_to to be sitemap-aware - if you
|
||||||
|
@ -224,6 +227,14 @@ class Middleman::CoreExtensions::DefaultHelpers < ::Middleman::Extension
|
||||||
|
|
||||||
# Transform the url through our magic url_for method
|
# Transform the url through our magic url_for method
|
||||||
args[url_arg_index] = url_for(url, options)
|
args[url_arg_index] = url_for(url, options)
|
||||||
|
|
||||||
|
# Cleanup before passing to Padrino
|
||||||
|
options.delete(:relative)
|
||||||
|
options.delete(:current_resource)
|
||||||
|
options.delete(:find_resource)
|
||||||
|
options.delete(:query)
|
||||||
|
options.delete(:anchor)
|
||||||
|
options.delete(:fragment)
|
||||||
end
|
end
|
||||||
|
|
||||||
super(*args, &block)
|
super(*args, &block)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
require 'middleman-core/util'
|
||||||
|
|
||||||
class Middleman::Extensions::AssetHash < ::Middleman::Extension
|
class Middleman::Extensions::AssetHash < ::Middleman::Extension
|
||||||
option :exts, %w(.jpg .jpeg .png .gif .js .css .otf .woff .eot .ttf .svg), 'List of extensions that get asset hashes appended to them.'
|
option :exts, %w(.jpg .jpeg .png .gif .js .css .otf .woff .eot .ttf .svg), 'List of extensions that get asset hashes appended to them.'
|
||||||
option :ignore, [], 'Regexes of filenames to skip adding asset hashes to'
|
option :ignore, [], 'Regexes of filenames to skip adding asset hashes to'
|
||||||
|
@ -70,7 +72,7 @@ class Middleman::Extensions::AssetHash < ::Middleman::Extension
|
||||||
# We don't want to use this middleware when rendering files to figure out their hash!
|
# We don't want to use this middleware when rendering files to figure out their hash!
|
||||||
return [status, headers, response] if env['bypass_asset_hash'] == 'true'
|
return [status, headers, response] if env['bypass_asset_hash'] == 'true'
|
||||||
|
|
||||||
path = @middleman_app.full_path(env['PATH_INFO'])
|
path = ::Middleman::Util.full_path(env['PATH_INFO'], @middleman_app)
|
||||||
|
|
||||||
if path =~ /(^\/$)|(\.(htm|html|php|css|js)$)/
|
if path =~ /(^\/$)|(\.(htm|html|php|css|js)$)/
|
||||||
body = ::Middleman::Util.extract_response_text(response)
|
body = ::Middleman::Util.extract_response_text(response)
|
||||||
|
|
Loading…
Reference in a new issue