middleman-template/lib/fonts4web.rb

152 lines
3.9 KiB
Ruby

require 'json'
require 'active_support/all'
require 'fileutils'
require 'shellwords'
class ::Metadata2FontsCss < ::Middleman::Extension
def initialize app, **options_hash, &block
super
@additional_extentions = %w[woff]
end
def included() true end
alias registered included
class <<self
def included() true end
alias registered included
end
FontFace = <<EOF.gsub( /^\s*(.*?)\s*$/, '\1').gsub /\n/m, ''
@font-face {
font-family: "%<name>s";
font-weight: %<weight>i;
font-style: %<style>s;
src:
local("%<fullName>s"),
local("%<postScriptName>s"),
url("%<woff>s") format("woff"),
url("%<ttf>s") format("truetype");
}
EOF
def manipulate_resource_list resources
fonts_css = StringIO.new
resources.lazy.
select {|res| Pathname.new( res.path).basename.to_s == 'METADATA.json' }.
map do |res|
JSON.parse( File.read( f))['fonts'].each do |font|
font = font.symbolize_keys
font[:ttf] = "/assets/fonts/#{font[:filename]}"
font[:woff] = "/assets/fonts/#{font[:filename].gsub /\.[ot]tf\Z/, '.woff'}"
fonts_css.printf FontFace, font
end
end
resources.delete_if do |res|
path = Pathname.new res.path
if 'assets' == path.descend.first.to_s
case path.basename.to_s
when 'METADATA.pb' then true
when 'METADATA.json' then true
when 'DESCRIPTION.en_us.html' then true
when 'OFL.txt' then true
else false
end
else false
end
end
resources << ::Middleman::Sitemap::StringResource.new(
self.app.sitemap,
'assets/styles/fonts.css',
fonts_css.string)
resources
end
end
::Middleman::Extensions.register :fonts_css, ::Metadata2FontsCss
class ::Fonts4Web < ::Middleman::Extension
def initialize app, **options_hash, &block
super
@converter = 'sfnt2woff-zopfli'
@cachepath = Pathname.new '.fonts_cache'
end
def included() true end
alias registered included
class <<self
def included() true end
alias registered included
end
def spawn *a, **options
a = a.map &:to_s
if options[:verbose]
pre = ''
pre = "cd #{Shellwords.escape options[:chdir]}; " if options.has_key? :chdir
STDERR.puts "$ #{pre}#{a.shelljoin}"
end
options.delete :verbose
options[:chdir] &&= options[:chdir].to_s
pid = Process.spawn *a, **options
_, status = Process.wait2 pid
status
end
def convert builder, src, dest = nil
# files:
f = src.basename
d = Pathname.new "#{src.basename src.extname}.woff"
# files in cache:
symlink = @cachepath + f
cache_dest = @cachepath + d
relsrc = src.expand_path.relative_path_from @cachepath.expand_path
dest = dest ? Pathname.new( dest) : cache_dest
@cachepath.mkpath
# dest is not older than src, we can use the cache
if dest.exist? and dest.lstat >= src.lstat
builder.trigger :identical, "#{dest}"
return dest
end
# cache_dest is older than source
unless cache_dest.exist? and cache_dest.lstat >= src.lstat
# prepare cache-files:
symlink.unlink if begin symlink.lstat; rescue Errno::ENOENT; false; end
symlink.make_symlink relsrc
# convert:
status = spawn @converter, symlink.basename, chdir: symlink.dirname
raise "Convertion #{src} failed!" unless 0 == status.exitstatus
raise "Convertion #{src} failed!" unless cache_dest.exist?
end
# deliver dest:
unless cache_dest == dest
FileUtils.copy cache_dest, dest, verbose: false
end
builder.trigger :created, "#{dest}"
dest
end
def after_build builder
paths = ::Middleman::Util.all_files_under( app.config[:build_dir])
paths.each do |path|
path = Pathname.new path
if 'assets' == path.relative_path_from( Pathname.new(@app.config[:build_dir])).descend.first.to_s
case path.extname
when '.otf', '.ttf'
new = path.dirname + "#{path.basename path.extname}.woff"
woff = convert builder, path, path.dirname + "#{path.basename path.extname}.woff"
end
end
end
end
end
::Middleman::Extensions.register :fonts4web, ::Fonts4Web