Skip to content

Instantly share code, notes, and snippets.

@maxlapshin
Created August 1, 2011 16:19
Show Gist options
  • Save maxlapshin/1118447 to your computer and use it in GitHub Desktop.
Save maxlapshin/1118447 to your computer and use it in GitHub Desktop.
class Page
def self.repo
@repo ||= Grit::Repo.new(Erlyhub.doc_path)
end
def self.lookup_path(path, lang = nil)
dirname = File.dirname(path)
dirname = nil if dirname == "."
tree = dirname ? (repo.tree / dirname) : repo.tree
return if !tree
list = tree.contents
name = File.basename(path)
list.each do |entry|
return full_name(dirname, entry.name) if File.basename(entry.name, File.extname(entry.name)) == name
return full_name(dirname, entry.name) if lang && File.basename(entry.name, File.extname(entry.name)) == "#{name}.#{lang}"
return full_name(dirname, entry.name) if entry.name == name
end
nil
end
def self.find(path, lang = nil)
if path = lookup_path(path, lang)
disk_path = File.join(Erlyhub.doc_path, path)
contents = if File.exists?(disk_path)
File.read(disk_path)
else
(repo.tree / path).data.force_encoding("utf-8")
end
page = Page.new(path, contents)
page.language = lang ? lang.to_s : lang
page.path = path
page
end
end
def self.full_name(dirname, path)
dirname ? File.join(dirname, path) : path
end
attr_reader :contents, :extname
attr_accessor :path
def text_format?
[:md, :html, :txt].include?(format)
end
def mime_type
MIME::Types.of(extname).first.to_s
end
def initialize(path, contents)
@extname = File.extname(path).gsub(/^\./,'')
@contents = contents
end
def format
@extname.to_sym
end
def body
postformat(htmlize(preformat(contents)))
end
def postformat(page)
i = 0
data = page.gsub(/\<h2\>/) do
i += 1
"<a name=\"s#{i}\"></a>\n<h2>"
end
process_code(data)
end
def htmlize(text)
case format
when :md
Markdown.new(text).to_html
when :html
text
end
end
attr_writer :position, :title
def language=(value)
@language = value.to_s
end
def language
text_data unless @language
@language
end
def position
@position ||= contents[/\[position (\d+)\]/,1].to_i
end
def title
if !@title
@title = contents.split(/\n/).map {|l| l[/^\#[\s+](.+)$/, 1]}.select {|l| l}.map{|l| l.force_encoding("utf-8")}.first
end
@title
end
def preformat(text)
acc = []
lang = nil
text.split(/(\[\w+ [^\]]+\])/).each do |part|
if part =~ /\[(\w+) ([^\]]+)\]/
command = $1
value = $2
case command
when "lang"
lang = value
@language = lang if !@language
when "position"
@position = value.to_i
when "href"
acc << "<a name=\"#{value}\"/>"
when "title"
@title = value if lang == @language || !lang
else
acc << part
end
else
if lang == @language || !lang
acc << part
end
end
end
data = acc.join("").split(/\n/).reject do |line|
if line =~ /^\#\s+(.+)$/
@title = $1
true
end
end.join("\n")
extract_code(data)
end
#########################################################################
#
# Code
#
#########################################################################
# Extract all code blocks into the codemap and replace with placeholders.
#
# data - The raw String data.
#
# Returns the placeholder'd String data.
def extract_code(data)
@codemap ||= {}
data.gsub!(/^``` ?([^\r\n]+)?\r?\n(.+?)\r?\n```\r?$/m) do
id = Digest::SHA1.hexdigest($2)
cached = check_cache(:code, id)
@codemap[id] = cached ?
{ :output => cached } :
{ :lang => $1, :code => $2 }
id
end
data
end
# Process all code from the codemap and replace the placeholders with the
# final HTML.
#
# data - The String data (with placeholders).
#
# Returns the marked up String data.
def process_code(data)
return data if data.nil? || data.size.zero? || @codemap.size.zero?
blocks = []
@codemap.each do |id, spec|
next if spec[:output] # cached
code = spec[:code]
if code.lines.all? { |line| line =~ /\A\r?\n\Z/ || line =~ /^( |\t)/ }
code.gsub!(/^( |\t)/m, '')
end
blocks << [spec[:lang], code]
end
highlighted = begin
blocks.size.zero? ? [] : Gollum::Albino.colorize(blocks)
rescue ::Albino::ShellArgumentError, ::Albino::TimeoutExceeded,
::Albino::MaximumOutputExceeded
[]
end
@codemap.each do |id, spec|
body = spec[:output] || begin
if (body = highlighted.shift.to_s).size > 0
update_cache(:code, id, body)
body
else
"<pre><code>#{CGI.escapeHTML(spec[:code])}</code></pre>"
end
end
data.gsub!(id, body)
end
data
end
def check_cache(type, id)
end
def update_cache(type, id, data)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment