Skip to content

Instantly share code, notes, and snippets.

@shibulijack-fd
Created November 17, 2015 09:45
Show Gist options
  • Save shibulijack-fd/c6243a444f5e798e7c68 to your computer and use it in GitHub Desktop.
Save shibulijack-fd/c6243a444f5e798e7c68 to your computer and use it in GitHub Desktop.
Middleman Helper Method Utility [UPDATED]
# Our custom logger
require "middleman-core/logger"
# For instrumenting
require "active_support/notifications"
# Using Thor's indifferent hash access
require "thor"
# Core Pathname library used for traversal
require "pathname"
require "tilt"
require "rack/mime"
module Middleman
module Util
# Whether the source file is binary.
#
# @param [String] filename The file to check.
# @return [Boolean]
def self.binary?(filename)
ext = File.extname(filename)
return true if ext == '.svgz'
return false if Tilt.registered?(ext.sub('.',''))
ext = ".#{ext}" unless ext.to_s[0] == ?.
mime = ::Rack::Mime.mime_type(ext, nil)
unless mime
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.each_byte do |c|
return true if binary_bytes.include?(c)
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
#
# @return [Middleman::Logger] The logger
def self.logger(*args)
if !@_logger || args.length > 0
@_logger = ::Middleman::Logger.new(*args)
end
@_logger
end
# Facade for ActiveSupport/Notification
def self.instrument(name, payload={}, &block)
name << ".middleman" unless name =~ /\.middleman$/
::ActiveSupport::Notifications.instrument(name, payload, &block)
end
# 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)
# when we drop 1.8, replace this with flat_map
paths.map do |p|
path = Pathname(p)
if path.directory?
all_files_under(*path.children)
elsif path.file?
path
end
end.flatten.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
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)
puts "Resource path: #{this_resource.path}"
current_source_dir_split = this_resource.path.split('/')
if current_source_dir_split.length > 1
current_source_dir = Pathname.new('/'+current_source_dir_split[0]+'/')
else
current_source_dir = Pathname('/' + this_resource.path).dirname
end
url_path = current_source_dir.join(url_path) if url_path.relative?
puts "URL : #{url_path}"
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment