Website/lib/gemsmith.rb

180 lines
4.1 KiB
Ruby

require 'yaml'
require 'redcarpet'
require 'erb'
require 'pipeline.rb'
class Array
def where
clone.delete_if { |i| not yield i }
end
end
module GemSmith
def reset_gemsmith()
$gemsmith = {
active: nil,
in_path: nil,
out_path: nil,
assets: {}
}
end
def load_site(in_path, out_path, out_root)
if File.symlink? in_path then
$stderr.puts "Warning: Skipping symlink #{f}"
[]
elsif File.directory? in_path then
full_out_dir = File.join(out_root, out_path)
directory "#{full_out_dir}" => [File.dirname("#{full_out_dir}")]
Dir["#{in_path}/*"].map do |f|
out_f = File.join(out_path, File.basename(f))
load_site(f, out_f, out_root)
end.flatten(1)
else
[{
modified: File.mtime(in_path),
in_path: in_path,
dependencies: [in_path, File.dirname(File.join(out_root, out_path))],
out_path: File.join(out_root, out_path),
rel_dir: File.dirname(out_path),
stream: Pipeline.new(in_path)
}]
end
end
def for_files(pattern)
tmp = $gemsmith[:active]
$gemsmith[:active] =
$gemsmith[:active].where {|f| pattern =~ File.basename(f[:out_path]) }
yield
$gemsmith[:active] = tmp
end
def site(site_name, params = {})
reset_gemsmith()
in_path = params.fetch(:src, "src")
out_path = params.fetch(:out, File.join("build", site_name.to_s))
$gemsmith[:in_path] = in_path
$gemsmith[:out_path] = out_path
$gemsmith[:active] = load_site(in_path, "", out_path)
directory out_path
task site_name => [ in_path, out_path ]
yield
$gemsmith[:active].each { |f|
file f[:out_path] => f[:dependencies] do
error = nil;
File.open(f[:out_path], "w+") { |out|
begin
f[:stream].pipe_to(out)
rescue => e
error = e
end
}
unless error.nil?
File.unlink(f[:out_path])
raise error
end
end
task site_name => f[:out_path]
}
end
def activate(op)
raise "Using apply outside of a site block" if $gemsmith[:active].nil?
$gemsmith[:active].each { |f| op.call(f) }
end
def extract_headers
lambda { |f|
yaml = ["---\n"]
pos = nil
f[:stream].consume { |fp|
if /^---$/ =~ fp.readline then
l = fp.readline
until /^---$/ =~ l do
yaml.push l
l = fp.readline
end
pos = fp.pos
end
}
unless pos.nil?
begin
f.merge!(YAML.load(yaml.join))
rescue => e
raise "Error parsing YAML ('#{f[:in_path]}'):\n#{e}\n#{yaml.join}---"
end
f[:stream].skip_to(pos)
end
}
end
def render_markdown(renderer = Redcarpet::Render::HTML.new())
markdown = Redcarpet::Markdown.new(renderer)
lambda { |f|
f[:out_path] = File.join(File.dirname(f[:out_path]), "#{File.basename(f[:out_path], ".*")}.html")
f[:stream].transform_all { |body|
markdown.render(body)
}
}
end
def render_erb
lambda { |f|
f[:out_path] = File.join(File.dirname(f[:out_path]), "#{File.basename(f[:out_path], ".*")}.html")
f[:stream].transform_all { |body|
b = binding()
f.each { |k,v| b.local_variable_set(k, v) }
$gemsmith[:now_rendering] = File.join(f[:rel_dir], File.basename(f[:out_path]))
ERB.new(body).result(b)
}
}
end
def apply_template(template)
erb = ERB.new(File.open(template) { |fp| fp.read })
lambda { |f|
f[:dependencies].push(template)
f[:stream].transform_all { |body|
b = binding()
f.each { |k,v| b.local_variable_set(k, v) }
$gemsmith[:now_rendering] = File.join(f[:rel_dir], File.basename(f[:out_path]))
erb.result(b)
}
}
end
def add_dependency(dep)
$gemsmith[:active].each { |f| f[:dependencies].push dep }
end
def add_assets(assets, params = {})
in_dir = params.fetch(:source, "assets")
out_dir = params.fetch(:dir, "assets")
assets.each { |a|
$gemsmith[:active] += load_site(File.join(in_dir, a), File.join(out_dir, a), $gemsmith[:out_path])
$gemsmith[:assets][a] = File.join(out_dir, a)
}
end
def root_path
context = File.split($gemsmith[:now_rendering])
context.pop
File.join( *([".."] * context.length) )
end
def asset_path(asset)
target = $gemsmith[:assets][asset]
return "???" if target.nil?
File.join( root_path, target )
end
end