80 lines
1.9 KiB
Ruby
80 lines
1.9 KiB
Ruby
# Template and Mime detection
|
|
require 'tilt'
|
|
require 'rack/mime'
|
|
|
|
require 'middleman-core/contracts'
|
|
|
|
module Middleman
|
|
module Util
|
|
include Contracts
|
|
|
|
module_function
|
|
|
|
# Whether the source file is binary.
|
|
#
|
|
# @param [String] filename The file to check.
|
|
# @return [Boolean]
|
|
Contract Or[String, Pathname] => Bool
|
|
def binary?(filename)
|
|
@binary_cache ||= {}
|
|
|
|
return @binary_cache[filename] if @binary_cache.key?(filename)
|
|
|
|
@binary_cache[filename] = begin
|
|
path = Pathname(filename)
|
|
ext = path.extname
|
|
|
|
# We hardcode detecting of gzipped SVG files
|
|
if ext == '.svgz'
|
|
true
|
|
elsif ::Tilt.registered?(ext.sub('.', ''))
|
|
false
|
|
else
|
|
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?(path.to_s)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
# Is mime type known to be non-binary?
|
|
#
|
|
# @param [String] mime The mimetype to check.
|
|
# @return [Boolean]
|
|
Contract String => Bool
|
|
def nonbinary_mime?(mime)
|
|
case
|
|
when mime.start_with?('text/')
|
|
true
|
|
when mime.include?('xml') && !mime.include?('officedocument')
|
|
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]
|
|
Contract String => Bool
|
|
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]
|
|
s = ::File.read(filename, 4096) || ''
|
|
s.each_byte do |c|
|
|
return true if binary_bytes.include?(c)
|
|
end
|
|
|
|
false
|
|
end
|
|
end
|
|
end
|