Skip to content
This repository has been archived by the owner on Feb 3, 2018. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
Initial commit.
  • Loading branch information
elijh committed Aug 20, 2009
0 parents commit 27a195a
Show file tree
Hide file tree
Showing 28 changed files with 5,040 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
doc/*
*~

674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

73 changes: 73 additions & 0 deletions README
@@ -0,0 +1,73 @@
= Introduction

GreenCloth is derived from RedCloth, the defacto text to html converter for ruby.

The purpose of GreenCloth is to add a bunch of new features to RedCloth that make
it more suited for wiki markup.

GreenCloth requires that RedCloth version > 4.0 is installed and that prior
versions are NOT installed.

= Changes from RedCloth

New markup:

* Crabgrass style links [my blog post -> meblogpretty.org/2008/4/5]
* Autolinks
* Additional way to specify code blocks
* Markdown blockquotes (>)
* Setext headers (h1 is formed by under line with ====, h2 underline with ----)
* Allow embedded video tags, and sanitize these embeds.
* Tables can use tabs in addition to pipes (|)
* Insert table of contents with [[toc]]
* Add unique clickable anchors to each heading (if to_html is passed option :outline)
* Pass an optional callback block for rendering links (allows for dead link rendering)

= Usage

== Example usage

You can use greencloth like so:

greencloth = GreenCloth.new(body, context_name, [:outline])
greencloth.to_html

Greencloth.new takes three argument:

* The raw greencloth markup text
* The context name for resolving links. The path for links are prefixed with this context.
* an array of greencloth options. useful options include:
* +:outline+ -- turn on the generation of outline data and markup.
* +:lite_mode+ -- disable blocks, only allow some markup.

== Passing a block to to_html()

Greencloth.to_html can take a block. The block is passed data regarding every link
that it encounteres while processing links.

You can use this to do custom rendering of links. For example:

html = GreenCloth.new(test_text,'mygroup').to_html() do |link_data|
process_link(link_data)
end

+process_link+ should return either nil or an <a> tag. If nil, then the greencloth
default is used.

link_date is a hash that might include: url, label, context_name, page_name

= Testing

To run the all the tests:

rake test

Or to test the markup from a specific fixture:

ruby test/markup_test.rb test/fixtures/images.yml


== TODO

sometimes the header detection for editing inline fails.

15 changes: 15 additions & 0 deletions Rakefile
@@ -0,0 +1,15 @@
require 'rake'
require 'rake/testtask'
require 'rake/rdoctask'

desc 'Default: run unit tests.'
task :default => :test

desc 'Test greencloth.'
Rake::TestTask.new(:test) do |t|
#t.libs << File.dirname(__FILE__)
#t.libs << File.dirname(File.dirname(__FILE__))
t.pattern = 'test/**/*_test.rb'
t.verbose = true
end

128 changes: 128 additions & 0 deletions green_tree.rb
@@ -0,0 +1,128 @@
##
## GreenTree -- a nested tree used for building the outline
##
class GreenTree < Array
attr_accessor :heading_level
attr_accessor :tree_level
attr_accessor :text
attr_accessor :name
attr_accessor :markup_index
attr_accessor :type
attr_accessor :parent

def initialize(text=nil, name=nil, heading_level=nil, parent=nil)
tree = super()
tree.text = text
tree.heading_level = heading_level
tree.name = name
tree.parent = parent
tree
end

def inspect
if leaf?
%Q["#{text}"]
else
%Q["#{text||'root'}" -> [#{self.map{|i|i.inspect}.join(', ')}]]
end
end

alias :to_s :inspect
alias :leaf? :empty?
alias :children= :concat
alias :child :slice
def children; self; end

def add_child(txt, name, heading_level)
self << GreenTree.new(txt, name, heading_level, self)
end

# returns the heading text for the one after the 'heading_name'
def successor(heading_name)
children.each_with_index do |node, i|
if node.name == heading_name
next_child = child(i+1)
if self.parent.nil?
return next_child
else
# go up a level to find the next element if we have to
return next_child ? next_child : self.parent.successor(self.name)
end
elsif !node.leaf?
found = node.successor(heading_name)
return found unless found.nil?
end
end
return nil # not found
end

# walks tree, looking for a node that matches
def find(name)
children.each do |node|
if node.name == name
return node
elsif !node.leaf?
node = node.find(name)
return node unless node.nil?
end
end
return nil # not found
end

# get the list of all the available heading names in this tree
# makes no guarantee about ordering
def heading_names
names = []
names << self.name
children.each do |child|
names.concat child.heading_names
end
names.compact
end

# modifies markup
# finds the location for each heading in the markup
def prepare_markup_index!(markup)
if self.text
# find the first occurance of this node in the markup
self.markup_index = markup.index(self.markup_regexp)
if self.markup_index.nil?
puts "GREENCLOTH ERROR: Can't find heading with text: '#{text}' in markup"
else
# modify the markup, so that it will no longer match
# the markup_regexp at this position
markup[self.markup_index] = "\000"
end
else
self.markup_index = 0
end

children.each do |node|
node.prepare_markup_index!(markup)
end
end

# returns a regexp that can be used to find the original markup for
# this node in a body of greencloth text. it is a little iffy.
# the text we have (self.text) has already been transformed by
# greencloth (there is not a good way around this). So, we have
# some transformed text, that we then need to match against original text.
# yep, it is that ugly.
def markup_regexp
# take out carriage returns
heading_text = Regexp.escape(self.text.gsub(/\r\n/, "\n"))

# remove html entities, and let them match any character
heading_text.gsub!(/&(\w{2,6}?|\\#[0-9A-Fa-f]{2,6});/,'.')

# add back carriage returns as optional
heading_text.gsub!('\\n', '\\r?\\n')

Regexp.union(
/^#{heading_text}\s*\r?\n[=-]+\s*?(\r?\n\r?\n?|$)/,
/^h#{heading_level}\. #{heading_text}\s*?(\r?\n\r?\n?|$)/
)
end

end

0 comments on commit 27a195a

Please sign in to comment.