perc/app.rb
Pranshu Sharma 21c1b5303c Added cache
Only fork markdown tho, can't cache erb.

Now also added a deploy script which runs erb
2025-06-02 16:28:44 +10:00

218 lines
4.7 KiB
Ruby

require 'roda'
require 'erb'
require 'nokogiri'
require 'redcarpet'
require 'tomlib'
$markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, tables: true)
$root = "/home/pranshu/Documents/proj/perc/test"
Dir.chdir $root;
class Config
attr_reader :approved_regex, :layout
def initialize
approved_files = [/\.md$/, /\.e?rb$/]
@approved_regex = Regexp.union(approved_files)
toml = Tomlib.load(File.read "config.toml")
@layout = toml["layout"] || "layout.erb"
# @layout = :layout
end
end
$config = Config.new();
class Sidebar
attr_reader :tree
FileNode = Struct.new(:type, :path, :name, :real)
DirNode = Struct.new(:type, :path, :name, :files, :index, :rb_file)
def initialize
@tree = process_dir "."
end
def show(n=@tree, indent="")
if n.type == :dir
print indent, n.path, "\n"
n.files.each do |r|
show r, " " + indent
end
else
print indent, n.path, "\n"
end
end
def html
return @html if defined?(@html)
builder = Nokogiri::HTML::Builder.new do |doc|
def deal_with_dir (doc, dir, path)
doc.li {
if dir.index
doc.a(:href => "/" + path + "/") {
doc.text dir.path
}
else
doc.text dir.path
end
doc.ul {
dir.files.each do |f|
fpath = File.join(path, f.path)
if f.type == :dir
deal_with_dir doc, f, fpath
else
doc.a(:href => "/#{fpath}") {
doc.li { doc.text f.name }
}
end
end
}
}
end
doc.div {
deal_with_dir doc, @tree, @tree.path
}
end
# colossus hack, but its fine for perf cause we cache
doc = Nokogiri::HTML(builder.to_html())
@html = doc.children[1].child.child.child.children[1].to_s
end
private
def getname(file)
File.basename(file, File.extname(file))
end
def dir_files()
# Remove "." and ".." from file list
Dir.entries(".").filter {|f| f !~ /^\./ }.filter do |f|
if File.file? f
f =~ $config.approved_regex
else
true
end
end
end
def process_dir(dir)
index = false
rb_file = false
dn = DirNode.new
dn.type = :dir
dn.files = []
temp = Dir.chdir(dir) do
ignored = false
if File.file? ".perc.toml"
toml = Tomlib.load(File.read ".perc.toml")
toml["routes"].each do |route|
name = route[0]
url = route[1]
dn.files.push(FileNode.new(:fil, url, name, false))
end
ignored = toml["ignore"] || false
ignored = Regexp.union(ignored)
end
dir_files.map do |f|
if File.file? f
if f =~ /index\.(erb|md)$/
index = f
next nil
elsif f =~ /\.rb$/
rb_file = f
next nil
else
if ignored and f =~ ignored
next nil
end
next FileNode.new(:file, f, getname(f), true)
end
else
next process_dir f
end
end
end
dn.files = temp.collect + dn.files
dn.files = dn.files.compact
dn.path = dir
dn.rb_file = rb_file
dn.name = dn.path
dn.index = index
# Read dir local config
dn
end
end
$sidebar = Sidebar.new
$files_cache = {}
def pview(file)
body = ""
cont = File.read(file) or return "Not found"
if (file =~ /\.erb$/)
# We can't cache erb
tp = ERB.new(cont)
body = tp.result(binding)
elsif (file =~ /\.md$/)
# But we can cache markdown
body = ($files_cache[file] ||= $markdown.render cont)
end
put_in_layout(body)
end
Dir["./**/*.rb"].each { |f| load(f) }
def put_in_layout (str)
body = str
tree = $sidebar.html
ERB.new(File.read($config.layout)).result(binding)
end
class App < Roda
route do |r|
r.root do
pview "main.erb"
end
process_dir r, $sidebar.tree, "."
end
# Now the saga begins,we transform file_tree into a routing tree
def process_dir (r, dir, cdir)
p = Proc.new do
dir.files.each do |f|
dd = File.join(cdir, f.path)
if f.type == :dir
# f is dir
process_dir r, f, dd
elsif f.real == true
# f is a file and is real
r.get f.path do
pview dd
end
end
end
if dir.index
r.is "" do
pview File.join(cdir, dir.index)
end
end
rf = dir.rb_file
if rf
eval "r.run #{File.basename(rf,File.extname(rf)).capitalize}"
end
end
if dir.path == "."
p.call
else
r.on dir.path do
p.call
end
end
end
end