Files
homebrew-tap/scripts/build_site.rb

156 lines
3.9 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# typed: strict
# frozen_string_literal: true
require "json"
require "fileutils"
require "erb"
require "pathname"
require "time"
require "terser"
require "cssminify2"
require_relative "array_extensions"
require_relative "time_formatter"
require_relative "asset_processor"
# Static site generator for homebrew tap documentation
class SiteBuilder
include ERB::Util
include TimeFormatter
include AssetProcessor
# Context class for rendering ERB partials with access to builder methods and local variables
class PartialContext
include ERB::Util
def initialize(builder, locals)
@builder = builder
locals.each do |key, value|
define_singleton_method(key) { value }
end
end
def render_partial(name, locals = {})
@builder.render_partial(name, locals)
end
def format_relative_time(timestamp)
@builder.format_relative_time(timestamp)
end
def format_date(timestamp)
@builder.format_date(timestamp)
end
def binding_context
binding
end
end
DOCS_DIR = File.expand_path("../docs", __dir__).freeze
DATA_DIR = File.join(DOCS_DIR, "_data").freeze
OUTPUT_DIR = DOCS_DIR
THEME_SOURCE_DIR = File.expand_path("../theme", __dir__).freeze
TEMPLATES_DIR = THEME_SOURCE_DIR
def self.build
new.generate_site
end
def generate_site
puts "🏗️ Building static site..."
setup_directories
load_data
generate_assets
generate_pages
puts "✅ Site built successfully in #{OUTPUT_DIR}"
puts "🌐 Open #{File.join(OUTPUT_DIR, "index.html")} in your browser"
end
def render_partial(name, locals = {})
partial_path = File.join(TEMPLATES_DIR, "_#{name}.html.erb")
raise ArgumentError, "Partial not found: #{partial_path}" unless File.exist?(partial_path)
context = PartialContext.new(self, locals)
ERB.new(File.read(partial_path)).result(context.binding_context)
end
private
def setup_directories
FileUtils.mkdir_p(File.join(OUTPUT_DIR, "formula"))
return if templates_exist?
puts "⚠️ Templates not found in #{TEMPLATES_DIR}. Please ensure theme/*.html.erb files exist."
exit 1
end
def load_data
formulae_file = File.join(DATA_DIR, "formulae.json")
@data = File.exist?(formulae_file) ? JSON.parse(File.read(formulae_file)) : default_data
end
def generate_assets
copy_assets
generate_css
minify_js
end
def generate_pages
generate_index_page
generate_formulae_pages
end
def generate_index_page
template = load_template("index.html.erb")
content = template.result(binding)
File.write(File.join(OUTPUT_DIR, "index.html"), content)
end
def generate_formulae_pages
@data["formulae"].each do |formula|
generate_formula_page(formula)
end
# Generate formulae index
template = load_template("formulae.html.erb")
content = template.result(binding)
File.write(File.join(OUTPUT_DIR, "formulae.html"), content)
end
def generate_formula_page(formula)
@formula = formula
template = load_template("formula.html.erb")
content = template.result(binding)
formula_dir = File.join(OUTPUT_DIR, "formula")
FileUtils.mkdir_p(formula_dir)
File.write(File.join(formula_dir, "#{formula["name"]}.html"), content)
end
def load_template(name)
template_path = File.join(TEMPLATES_DIR, name)
template_content = File.read(template_path)
ERB.new(template_content)
end
def templates_exist?
%w[index.html.erb formulae.html.erb formula.html.erb].all? do |template|
File.exist?(File.join(TEMPLATES_DIR, template))
end
end
def default_data
{
"tap_name" => "ivuorinen/homebrew-tap",
"generated_at" => Time.now.strftime("%Y-%m-%dT%H:%M:%S%z"),
"formulae_count" => 0,
"formulae" => [],
}
end
end
# Allow running this script directly
SiteBuilder.build if __FILE__ == $PROGRAM_NAME