require 'coderay'
class SnippetParser
include Reloadable
def initialize(text)
@text = text.to_s
end
def snippets
build_snippets if @snippets.nil?
@snippets
end
# wraps snippets in
def pre_format
build_snippets do |tag, code|
%(#{code}
)
end
end
def highlight(default_language = :ruby)
build_snippets do |tag, code|
CodeRay.scan(code, (tag && tag['attributes']) || default_language).html
end
end
protected
def build_snippets(&block)
@snippets = []
contents = []
tag = nil
returning [] do |output|
tokenizer = HTML::Tokenizer.new(@text.to_s)
while token = tokenizer.next
node = HTML::Node.parse(nil, 0, 0, token, false)
if node.tag? && node.name == 'code'
if contents.blank? # open tag
tag = node.dup
else # closing tag
output << close_snippet(tag, contents.join, &block)
end
contents.clear
else # inside a code tag
contents << node.to_s
end
end
# get any unfinished code blocks
output << close_snippet(nil, contents.join, &block) unless contents.empty?
end.join
end
def close_snippet(tag, contents, &block)
@snippets << contents
block ? block.call(tag, contents) : %(#{contents})
end
end