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