wikicloth-0.8.1/ 0000755 0001750 0001750 00000000000 12263013231 013670 5 ustar avtobiff avtobiff wikicloth-0.8.1/init.rb 0000644 0001750 0001750 00000000120 12263013231 015151 0 ustar avtobiff avtobiff require File.join(File.expand_path(File.dirname(__FILE__)), "lib", "wikicloth")
wikicloth-0.8.1/lang/ 0000755 0001750 0001750 00000000000 12263013231 014611 5 ustar avtobiff avtobiff wikicloth-0.8.1/lang/de.yml 0000644 0001750 0001750 00000001056 12263013231 015726 0 ustar avtobiff avtobiff :de:
namespaces:
media: "Medium"
file: "Datei"
category: "Kategorie"
template: "Vorlage"
special: "Spezial"
talk: "Diskussion"
help: "Hilfe"
languages:
en: "Englisch"
de: "Deutsch"
behavior_switches:
notoc: "KEIN_INHALTSVERZEICHNIS"
toc: "INHALTSVERZEICHNIS"
forcetoc: "INHALTSVERZEICHNIS_ERZWINGEN"
noeditsection: "ABSCHNITTE_NICHT_BEARBEITEN"
editsection: "ABSCHNITTE_BEARBEITEN"
table of contents: "Inhaltsverzeichnis"
edit: "Bearbeiten"
edit section: "Abschnitt bearbeiten: %{name}"
wikicloth-0.8.1/lang/en.yml 0000644 0001750 0001750 00000002112 12263013231 015732 0 ustar avtobiff avtobiff en:
namespaces:
media: "Media"
file: "File,Image"
category: "Category"
special: "Special"
template: "Template"
talk: "Talk"
help: "Help"
languages:
en: "English"
de: "German"
behavior_switches:
notoc: "NOTOC"
toc: "TOC"
forcetoc: "FORCETOC"
noeditsection: "NOEDITSECTION"
editsection: "EDITSECTION"
table of contents: "Table of Contents"
edit: "edit"
edit section: "Edit section: %{name}"
template loop detected: "Template loop detected: {{%{tree}}}"
expression error: "Expression error: %{error}"
lang attribute is required: "lang attribute is required"
unknown lang: "unknown lang '%{lang}'"
unable to parse mathml: "Unable to parse MathML: %{error}"
blahtex binary not found: "%{path} binary not found"
unknown function: "unknown function '%{function}'"
lua disabled: "Lua extension not configured"
max lines of code: "Maximum lines of code limit reached"
recursion limit reached: "Recursion limit reached"
unknown error on line: "Unknown error on line %{line} row %{row}: %{tree}"
wikicloth-0.8.1/tasks/ 0000755 0001750 0001750 00000000000 12263013231 015015 5 ustar avtobiff avtobiff wikicloth-0.8.1/tasks/wikicloth_tasks.rake 0000644 0001750 0001750 00000000000 12263013231 021051 0 ustar avtobiff avtobiff wikicloth-0.8.1/sample_documents/ 0000755 0001750 0001750 00000000000 12263013231 017232 5 ustar avtobiff avtobiff wikicloth-0.8.1/sample_documents/lua.wiki 0000644 0001750 0001750 00000002552 12263013231 020704 0 ustar avtobiff avtobiff The
tag allows you to embed Lua code in your templates and wiki documents.
"
for beer = x, 1, -1 do
output = output .. bottle(beer) .. " on the " .. where .. ",\n"
output = output .. bottle(beer) .. ",\n"
output = output .. "Take one down, pass it around,\n"
output = output .. bottle(beer-1) .. " on the " .. where .. ".\n"
output = output .. "\n\n"
end
return output .. "
"
end
"
for beer = x, 1, -1 do
output = output .. bottle(beer) .. " on the " .. where .. ",\n"
output = output .. bottle(beer) .. ",\n"
output = output .. "Take one down, pass it around,\n"
output = output .. bottle(beer-1) .. " on the " .. where .. ".\n"
output = output .. "\n\n"
end
return output .. "
"
end
[[g (factor)|]]
|| [[g (factor)|g]]
|| [[g (factor)|g]]
|-
|| [[Boston, Massachusetts|]]
|| [[Boston, Massachusetts|Boston]]
|| [[Boston, Massachusetts|Boston]]
|-
|| [[The Lord of the Rings: The Fellowship of the Ring (video game)|]]
|| [[The Lord of the Rings: The Fellowship of the Ring (video game)|The Fellowship of the Ring]]
|| [[The Lord of the Rings: The Fellowship of the Ring (video game)|The Fellowship of the Ring]]
|-
! colspan="3" style="text-align: left;" | Redirection
|-
|| [[Bush (43)|]]
|| [[Bush (43)|Bush]]
|| [[Bush (43)|Bush]]
|-
|| [[Bush (41)|]]
|| [[Bush (41)|Bush]]
|| [[Bush (41)|Bush]]
|-
! colspan="3" style="text-align: left;" | Normal titles
|-
|| [[Wikipedia:Help|]]
|| [[Wikipedia:Help|Help]]
|| [[Wikipedia:Help|Help]]
|-
! colspan="3" style="text-align: left;" | Users
|-
|| [[User:Example|]]
|| [[User:Example|Example]]
|| [[User:Example|Example]]
|-
|}
==Where it does not work==
===Cite.php <ref> footnotes===
The trick does not work when enclosing between [[wikipedia:footnotes|"ref" tags]]. [[Roger Taylor (author)|]]
[[Roger Taylor (author)|]] renders in the references list (generated by the /* Edit summaries and the pipe trick */ as tested in [[WP:SAND|]]
renders in the edit history as:
([[#Edit summaries and the pipe trick|→]]Edit summaries and the pipe trick: as tested in [[WP:SAND]])
== Slash trick ==
You can achieve the same effect for subpages by adding a slash: [[/subpage/]]
generates the same output as [[/subpage|subpage]]
. Unlike the pipe trick, though, it will not be transformed in the [[wikitext]].
This trick only works in namespaces where [[/subpage]]
would.
== Reverse pipe trick ==
Typing
, will create the desired effect. So will enclosing all but the first paragraph with ...
For a list with items of more than one paragraph long, adding a blank line between items may be necessary to avoid confusion.
*lists
**ordered lists
**unordered lists
***definition lists
==Continuing a list item after a sub-item==
In HTML, a list item may contain several sublists, not necessarily adjacent; thus there may be parts of the list item not only before the first sublist, but also between sublists, and after the last one; however, in wiki-syntax, sublists follow the same rules as sections of a page: the only possible part of the list item not in sublists is before the first sublist.
In the case of an unnumbered first-level list in wikitext code this limitation can be overcome by splitting the list into multiple lists; indented text between the partial lists may visually serve as part of a list item after a sublist; however, this may give, depending on CSS, a blank line before and after each list, in which case, for uniformity, every first-level list item could be made a separate list.
Numbered lists illustrate that what should look like one list may, for the software, consist of multiple lists; unnumbered lists give a corresponding result, except that the problem of restarting with 1 is not applicable.
{| style="border:1px;border-spacing:1px;background-color:black;" cellpadding="5"
|- style="background-color:white;"
|
#list item A1 ##list item B1 ###list item C1 ##:continuing list item B1 ##list item B2 #list item A2gives #list item A1 ##list item B1 ###list item C1 ##:continuing list item B1 ##list item B2 #list item A2 See also {{tim|List demo}} and [[Help:Section#Subdivisions in general|subdivisions]]. == Changing the list type == The list type (which type of marker appears before the list item) can be changed in CSS by setting the [http://www.w3.org/TR/REC-CSS2/generate.html#lists list-style-type] property: {|border="1" width="79%" !wikitext!!rendering |- |
style="margin-left: 2em"
, causing indentation of the contents. This is '''the most versatile method''', as it allows starting with a number other than 1, see below.
|-
|
start
and value
attributes as used below in HTML 4.01 and XHTML 1.0. But as of 2007, no popular web browsers implement CSS counters, which were to replace these attributes. Wikimedia projects use XHTML Transitional, which contains the deprecated attributes.)
gives
- Amsterdam
- Rotterdam
- The Hague
gives
- Amsterdam
- Rotterdam
- The Hague
{| |- | align=right | 9.||Amsterdam |- | align=right | 10.||Rotterdam |- | align=right | 11.||The Hague |}gives {| |- | align=right | 9.||Amsterdam |- | align=right | 10.||Rotterdam |- | align=right | 11.||The Hague |} This non-automatic numbering has the advantage that if a text refers to the numbers, insertion or deletion of an item does not disturb the correspondence. ==Multi-column bulleted list==
{| | *1 *2 | *3 *4 |}gives: {| | *1 *2 | *3 *4 |} ==Multi-column numbered list== Specifying a starting value is useful for a numbered list with multiple columns, to avoid restarting from one in each column. As mentioned above, this is only possible with HTML-syntax (for the first column either wiki-syntax or HTML-syntax can be used). In combination with the extra indentation explained in the previous section:
{| valign="top" |- |
{{Multi-column numbered list|125|a
{{Multi-column numbered list|lst=lower-alpha|125|a
{{Multi-column numbered list|lst=lower-roman|125|a
{{Multi-column numbered list|lst=disc|125|a
!!
) or start on new lines, each with its own single mark (!
).
|-
|
||
) or start on new lines, each with its own single mark (|
).
|-
|
||
and !!
for optionally adding consecutive cells to a line. However, blank spaces at the beginning of a line are ignored.
*'''XHTML attributes.''' Each mark, except table end, optionally accepts one or more XHTML attributes. Attributes must be on the same line as the mark. Separate attributes from each other with a single space.
**Cells and caption (|
or ||
, !
or !!
, and |+
) hold content. So separate any attributes from content with a single pipe (|
). Cell content may follow on same line or on following lines.
**Table and row marks ({|
and |-
) do not directly hold content. Do ''not'' add pipe (|
) after their optional attributes. If you erroneously add a pipe after attributes for the table mark or row mark the parser will delete it ''and'' your final attribute if it was touching the erroneous pipe!
*'''Content''' may (a) follow its cell mark on the same line after any optional XHTML attributes or (b) on lines below the cell mark. Content that uses wiki markup that itself needs to start on a new line, such as lists, headings, or nested tables, must be on its own new line.
==Basics==
The following table lacks borders and good spacing but shows the simplest wiki markup table structure.
{| cellspacing="0" border="1"
!style="width:50%"|You type
!style="width:50%"|You get
|-
|
{| |Orange |Apple |- |Bread |Pie |- |Butter |Ice cream |}| {| |Orange |Apple |- |Bread |Pie |- |Butter |Ice cream |} |} The cells in the same row can be listed on one line separated by
||
.
Extra spaces within cells in the wiki markup, as in the wiki markup below, do not affect the actual table rendering.
{| cellspacing="0" border="1"
!style="width:50%"|You type
!style="width:50%"|You get
|-
|
{| | Orange || Apple || more |- | Bread || Pie || more |- | Butter || Ice cream || and more |}| {| | Orange || Apple || more |- | Bread || Pie || more |- | Butter || Ice cream || and more |} |} === Table headers === Table headers can be created by using "
!
" instead of "|
". Headers usually show up bold and centered by default.
{| cellspacing="0" border="1"
!style="width:50%"|You type
!style="width:50%"|You get
|-
|
{| ! Item ! Amount ! Cost |- |Orange |10 |7.00 |- |Bread |4 |3.00 |- |Butter |1 |5.00 |- !Total | |15.00 |}| {| ! Item ! Amount ! Cost |- |Orange |10 |7.00 |- |Bread |4 |3.00 |- |Butter |1 |5.00 |- !Total | |15.00 |} |} ===Caption=== A '''table caption''' can be added to the top of any table as follows. {| cellspacing="0" border="1" !style="width:50%"|You type !style="width:50%"|You get |- |
{| |+Food complements |- |Orange |Apple |- |Bread |Pie |- |Butter |Ice cream |}| {| |+ Food complements |- |Orange |Apple |- |Bread |Pie |- |Butter |Ice cream |} |} == XHTML attributes == You can add XHTML attributes to tables. For the authoriative source on these, see [http://www.w3.org/TR/REC-html40/struct/tables.html the W3C's HTML 4.01 Specification page on tables]. === Attributes on tables === Placing attributes after the table start tag (
{|
) applies attributes to the entire table.
{| cellspacing="0" border="1"
!style="width:50%"|You type
!style="width:50%"|You get
|-
|
{| border="1" |Orange |Apple |12,333.00 |- |Bread |Pie |500.00 |- |Butter |Ice cream |1.00 |}| {| border="1" |Orange |Apple |12,333.00 |- |Bread |Pie |500.00 |- |Butter |Ice cream |1.00 |} |} === Attributes on cells === You can put attributes on individual '''cells'''. For example, numbers may look better aligned right. {| cellspacing="0" border="1" !style="width:50%"|You type !style="width:50%"|You get |- |
{| border="1" |Orange |Apple |align="right" | 12,333.00 |- |Bread |Pie |align="right" | 500.00 |- |Butter |Ice cream |align="right" | 1.00 |}| {| border="1" |Orange |Apple |align="right"|12,333.00 |- |Bread |Pie |align="right"|500.00 |- |Butter |Ice cream |align="right"|1.00 |} |} You can also use '''cell''' attributes when you are listing multiple '''cells''' on a single line. Note that the '''cells''' are separated by
||
, and within each '''cell''' the attribute(s) and value are separated by |
.
{| cellspacing="0" border="1"
!style="width:50%"|You type
!style="width:50%"|You get
|-
|
{| border="1" | Orange || Apple || align="right" | 12,333.00 |- | Bread || Pie || align="right" | 500.00 |- | Butter || Ice cream || align="right" | 1.00 |}| {| border="1" | Orange || Apple || align="right" | 12,333.00 |- | Bread || Pie || align="right" | 500.00 |- | Butter || Ice cream || align="right" | 1.00 |} |} ===Attributes on rows=== You can put attributes on individual '''rows''', too. {| cellspacing="0" border="1" !style="width:50%"|You type !style="width:50%"|You get |- |
{| border="1" |Orange |Apple |align="right"|12,333.00 |- |Bread |Pie |align="right"|500.00 |- style="font-style:italic; color:green;" |Butter |Ice cream |align="right"|1.00 |}| {| border="1" |Orange |Apple |align="right"|12,333.00 |- |Bread |Pie |align="right"|500.00 |- style="font-style:italic; color:green;" |Butter |Ice cream |align="right"|1.00 |} |} ===With HTML attributes and CSS styles=== CSS style attributes can be added with or without other HTML attributes. {| cellspacing="0" border="1" !style="width:50%"|You type !style="width:50%"|You get |- |
{| style="color:green; background-color:#ffffcc;" cellpadding="20" cellspacing="0" border="1" |Orange |Apple |- |Bread |Pie |- |Butter |Ice cream |}| {| style="color:green; background-color:#ffffcc;" cellpadding="20" cellspacing="0" border="1" |Orange |Apple |- |Bread |Pie |- |Butter |Ice cream |} |} '''Attributes''' can be added to the caption and headers as follows. {| cellspacing="0" border="1" !style="width:50%"|You type !style="width:50%"|You get |- |
{| border="1" cellpadding="20" cellspacing="0" |+ align="bottom" style="color:#e76700;" |''Food complements'' |- |Orange |Apple |- |Bread |Pie |- |Butter |Ice cream |}| {| border="1" cellpadding="20" cellspacing="0" |+ align="bottom" style="color:#e76700;" |''Food complements'' |- |Orange |Apple |- |Bread |Pie |- |Butter |Ice cream |} |} ==Caveats== ===Negative numbers=== If you start a cell on a new line with a negative number with a minus sign (or a parameter that evaluates to a negative number), your table can get broken, because the characters
|-
will be parsed as the wiki markup for table row, not table cell. To avoid this, insert a space before the value (| -6
) or use in-line cell markup (|| -6
).
===CSS vs Attributes===
Table borders specified through CSS rather then the border attribute will render incorrectly in a small subset of text browsers.
wikicloth-0.8.1/sample_documents/george_washington.wiki 0000644 0001750 0001750 00000231512 12263013231 023634 0 ustar avtobiff avtobiff {{otheruses}}
{{pp-semi-indef|small=yes}}{{pp-move-indef}}
{{Infobox President
|name = George Washington
|nationality = American
|image = Gilbert Stuart Williamstown Portrait of George Washington.jpg
|wh image = Gw1.gif
|order = [[List of Presidents of the United States|1st]] [[President of the United States]]
|term_start = April 30, 1789
|term_end = March 4, 1797
|vicepresident = [[John Adams]]
|successor = [[John Adams]]
|order2 = 1st [[Continental Army|Commander-in-Chief of the Continental Army]]
|term_start2 = June 15, 1775
|term_end2 = December 23, 1783
|appointer2 = [[Continental Congress]]
|successor2 = [[Henry Knox]]{{smallsup|b}}
|order3 = 6th [[Commanding General of the United States Army|United States Army Senior Officer]]
|term_start3 = July 13, 1798
|term_end3 = December 14, 1799
|president3 = [[John Adams]]
|predecessor3 = [[James Wilkinson]]
|successor3 = [[Alexander Hamilton]]
|birth_date = {{birth date|1732|2|22|mf=y}}
|birth_place = [[Westmoreland County, Virginia|Westmoreland County]], [[Colony of Virginia]], [[British America]]
|death_date = {{death date and age|mf=yes|1799|12|14|1732|2|22}}
|death_place = [[Mount Vernon]], [[Virginia]], [[United States]]
|restingplace = Family vault, [[Mount Vernon]], [[Virginia]], [[United States]]
|party = None
|spouse = [[Martha Washington|Martha Dandridge Custis Washington]]
|children = [[John Parke Custis]] (stepson)', '').gsub!('', '') rescue => err error = "#{err.message}" end elsif File.exists?(highlight_path) begin IO.popen("#{highlight_path} #{highlight_options} -f --syntax #{buffer.element_attributes['lang'].downcase}", "r+") do |io| io.puts content io.close_write content = io.read end rescue => err error = "#{err.message}" end else content = content.gsub('<','<').gsub('>','>') end if error.nil? "
#{content}" else error end end end end wikicloth-0.8.1/lib/wikicloth/extensions/lua.rb 0000644 0001750 0001750 00000004511 12263013231 021741 0 ustar avtobiff avtobiff begin require 'rubyluabridge' DISABLE_LUA = false rescue LoadError DISABLE_LUA = true end module WikiCloth class LuaExtension < Extension #
#{I18n.t('table of contents')}
|
".each_char { |c| @buffers[-1].add_char(c) } @indent = @buffers[-1].object_id return true end end if @buffers[-1].run_globals? # new html tag if @check_new_tag == true && current_char =~ /([a-z])/ && !@buffers[-1].skip_html? @buffers[-1].data.chop! parent = @buffers[-1].element_name if @buffers[-1].class == WikiBuffer::HTMLElement @buffers << WikiBuffer::HTMLElement.new("",@options,parent) end @check_new_tag = current_char == '<' ? true : false # global case # start variable when previous_char == '{' && current_char == '{' if @buffers[-1].instance_of?(WikiBuffer::Var) && @buffers[-1].tag_start == true @buffers[-1].tag_size += 1 else @buffers[-1].data.chop! if @buffers[-1].data[-1,1] == '{' @buffers << WikiBuffer::Var.new("",@options) end return true # start link when current_char == '[' && previous_char != '[' && !@buffers[-1].skip_links? @buffers << WikiBuffer::Link.new("",@options) return true # start table when previous_char == '{' && current_char == "|" @buffers[-1].data.chop! @buffers << WikiBuffer::Table.new("",@options) return true end end return false end def add_word(w) self.previous_char = w[-2,1] self.current_char = w[-1,1] @buffers[-1].data += w end def eof() return if @buffers.size == 1 if self.class == WikiBuffer while @buffers.size > 1 @buffers[-1].eof() tmp = @buffers.pop @buffers[-1].data += tmp.send("to_#{@options[:output]}") unless tmp.data.blank? tmp.data.each_char { |x| self.add_char(x) } end end else # default cleanup tasks end end def add_char(c) self.previous_char = self.current_char self.current_char = c if self.check_globals() == false case when @buffers.size == 1 return self.new_char() when @buffers[-1].add_char(c) == false && self.class == WikiBuffer tmp = @buffers.pop @buffers[-1].data += tmp.send("to_#{@options[:output]}") # any data left in the buffer we feed into the parent unless tmp.data.nil? tmp.data.each_char { |x| self.add_char(x) } end end end end protected # only executed in the default state def new_char() case when current_char == "\n" # Underline, and Strikethrough if @options[:extended_markup] == true self.data.gsub!(/---([^-]+)---/,"\\1") self.data.gsub!(/_([^_]+)_/,"\\1") end # Behavior Switches self.data.gsub!(/__([\w]+)__/) { |r| case behavior_switch_key_name($1) when "behavior_switches.toc" @options[:link_handler].toc(@options[:sections], @options[:toc_numbered]) when "behavior_switches.noeditsection" @options[:noedit] = true when "behavior_switches.editsection" @options[:noedit] = false else "" end } # Horizontal Rule self.data.gsub!(/^([-]{4,})/) { |r| "
" } render_bold_italic() # Lists tmp = '' self.data.each_line do |line| if line =~ /^([#\*:;]+)/ # Add current line to list data @list_data << line else # render list if list data was just closed tmp += render_list_data() unless @list_data.empty? tmp += line end end self.data = tmp # Headings is_heading = false self.data.gsub!(/^([=]{1,6})\s*(.*?)\s*(\1)/) { |r| is_heading = true (@paragraph_open ? "" : "") + gen_heading($1.length,$2) } # Paragraphs if is_heading @paragraph_open = false else if self.data =~ /^\s*$/ && @paragraph_open && @list_data.empty? self.data = "#{self.data}" @paragraph_open = false else if self.data !~ /^\s*$/ self.data = "#{self.data}" and @paragraph_open = true unless @paragraph_open end end end self.params << self.data.auto_link self.data = "" else self.data << current_char end return true end def behavior_switch_key_name(name) keys = [:toc,:notoc,:forcetoc,:noeditsection,:editsection] locales = [@options[:locale],I18n.default_locale,:en].uniq values = {} locales.each do |locale| I18n.with_locale(locale) do keys.each do |key| values[I18n.t("behavior_switches.#{key.to_s}")] = "behavior_switches.#{key.to_s}" end end end values[name] end def gen_heading(hnum,title) id = get_id_for(title.gsub(/\s+/,'_')) "
" + (@options[:noedit] == true ? "" : "[ title)}\">#{I18n.t('edit')}] ") + "#{title} \n" end def get_id_for(val) val.gsub!(/[^A-Za-z0-9_]+/,'') @idmap ||= {} @idmap[val] ||= 0 @idmap[val] += 1 @idmap[val] == 1 ? val : "#{val}-#{@idmap[val]}" end def name_current_param() params[-1] = { :value => "", :name => params[-1] } unless params[-1].kind_of?(Hash) || params[-1].nil? end def current_param=(val) unless self.params[-1].nil? || self.params[-1].kind_of?(String) self.params[-1][:value] = val else self.params[-1] = val end end def params=(val) @params = val end def buffer_type=(val) @buffer_type = val end def data=(val) @data = val end def current_char=(val) @current_char = val end def current_char @current_char ||= "" end def previous_char=(val) @previous_char = val end def previous_char @previous_char end def current_line=(val) @current_line = val end def current_line @current_line ||= "" end BOLD_ITALIC_MAP = { 0 => { :bold => [10, ""], :italic => [20, ""], :bold_italic => [40, ""], :four => [10, "'"], :finish => [0, ""] }, 10 => { :bold => [0, ""], :italic => [30, ""], :bold_italic => [20, ""], :four => [0, "'"], :finish => [0, ""] }, 20 => { :bold => [40, ""], :italic => [0, ""], :bold_italic => [10, ""], :four => [40, "'"], :finish => [0, ""] }, 30 => { :bold => [20, ""], :italic => [10, ""], :bold_italic => [0, ""], :four => [20, "'"], :finish => [0, ""] }, 40 => { :bold => [20, ""], :italic => [10, ""], :bold_italic => [0, ""], :four => [20, "'"], :finish => [0, ""] }, } def render_bold_italic() commands = [] self.data.scan(/([\']{2,5})/) do commands << { :len => $1.length, :type => [nil, nil, :italic, :bold, :four, :bold_italic][$1.length], :pos => $~.offset(0).first } end commands << {:type => :finish} state = 0 commands.each do |c| trans = BOLD_ITALIC_MAP[state][c[:type]] c[:output] = trans.last state = trans.first end index = 0 self.data.gsub!(/([\']{2,5})/) do output = commands[index][:output] index += 1 output end self.data << commands.last[:output] end def render_list_data() ret = "" last = "" process_line = Proc.new do |pieces, content| common = 0 (0..last.length - 1).each do |i| if last[i] == pieces[i] common += 1 else break end end close = last[common..-1].reverse open = pieces[common..-1] close.each_char do |e| ret << "#{list_inner_tag_for(e)}>#{list_tag_for(e)}>" end if open == '' && pieces != '' if last != '' ret << "#{list_inner_tag_for(pieces[-1,1])}>" end ret << "<#{list_inner_tag_for(pieces[-1,1])}>" end open.each_char do |e| ret << "<#{list_tag_for(e)}><#{list_inner_tag_for(e)}>" end ret << content last = pieces.clone end (@list_data + ['']).each do |l| if l =~ /^([#\*:;]+)\s*(.*)$/ process_line.call($1, $2) end end process_line.call('', '') @list_data = [] ret + "\n" end def list_tag_for(tag) case tag when "#" then "ol" when "*" then "ul" when ";" then "dl" when ":" then "dl" end end def list_inner_tag_for(tag) case tag when "#" then "li" when "*" then "li" when ";" then "dt" when ":" then "dd" end end end end require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "html_element") require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "table") require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "var") require File.join(File.expand_path(File.dirname(__FILE__)), "wiki_buffer", "link") # load all extensions Dir[File.join(File.expand_path(File.dirname(__FILE__)), "extensions/*.rb")].each { |r| require r } wikicloth-0.8.1/lib/wikicloth/version.rb 0000644 0001750 0001750 00000000117 12263013231 020444 0 ustar avtobiff avtobiff module WikiCloth VERSION = "0.8.1" unless defined?(::WikiCloth::VERSION) end wikicloth-0.8.1/lib/wikicloth/section.rb 0000644 0001750 0001750 00000002773 12263013231 020435 0 ustar avtobiff avtobiff module WikiCloth class Section < String def initialize(title=nil, id=nil) self.title = title @children = [] @id = id @template = nil @auto_toc = nil end def children @children end def id @id end def auto_toc=(val) @auto_toc = val end def template=(val) @template = val end def title=(val) if val =~ /^([=]{1,6})\s*(.*?)\s*(\1)/ @depth = $1.length @clean_title = $2 @title = val else @depth = 1 @clean_title = val @title = val end end def title @clean_title end def depth @depth ||= 1 end def get_section(id) return self.wikitext() if self.id == id @children.each do |child| ret = child.get_section(id) return ret unless ret.nil? end nil end def wikitext(opt={}) options = { :replace => {} }.merge(opt) if options[:replace][self.id].nil? ret = "#{@title}#{self}" ret += @children.collect { |c| c.wikitext(options) }.join ret else options[:replace][self.id] end end def render(opt={}) options = { :noedit => opt[:link_handler].nil? ? true : false }.merge(opt) if self.title.nil? ret = "" else ret = "\n#{@title}\n" end ret += self ret += "__TOC__" if @auto_toc ret += @children.collect { |c| c.render(options) } .join ret end end end wikicloth-0.8.1/lib/wikicloth/parser.rb 0000644 0001750 0001750 00000006046 12263013231 020262 0 ustar avtobiff avtobiff module WikiCloth class Parser < WikiLinkHandler def initialize(options={}) options.each { |k,v| if v.instance_of?(Proc) self.class.send :define_method, k.to_sym do |*args| self.instance_exec(args,&v) end end } @options = { :link_handler => self, :params => {} }.merge(options) @wikicloth = WikiCloth.new(@options) end class << self def url_for(&block) self.send :define_method, 'url_for' do |url| self.instance_exec(url, &block) end end def image_url_for(&block) self.send :define_method, 'image_url_for' do |url| self.instance_exec(url, &block) end end def toc(&block) self.send :define_method, 'toc' do |sections, numbered| self.instance_exec(sections, numbered, &block) end end def function(&block) self.send :define_method, 'function' do |name, params| self.instance_exec(name, params, &block) end end def external_link(&block) self.send :define_method, 'external_link' do |url,text| self.instance_exec(url,text,&block) end end def include_resource(&block) self.send :define_method, 'include_resource' do |resource,options| options ||= [] self.instance_exec(resource,options,&block) end end def template(&block) self.send :define_method, 'template' do |template| self.instance_exec(template,&block) end end def link_for_resource(&block) self.send :define_method, 'link_for_resource' do |prefix,resource,options| options ||= [] self.instance_exec(prefix,resource,options,&block) end end def section_link(&block) self.send :define_method, 'section_link' do |section| self.instance_exec(section,&block) end end def link_for(&block) self.send :define_method, 'link_for' do |page,text| self.instance_exec(page,text,&block) end end def link_attributes_for(&block) self.send :define_method, 'link_attributes_for' do |page| self.instance_exec(page,&block) end end def cache(&block) self.send :define_method, 'cache' do |item| self.instance_exec(item,&block) end end end def method_missing(method, *args) if @wikicloth.respond_to?(method) @wikicloth.send(method, *args) else super(method, *args) end end # Replace a section, along with any sub-section in the document def put_section(id,data) data = @wikicloth.sections.collect { |s| s.wikitext({ :replace => { id => data.last(1) == "\n" ? data : "#{data}\n" } }) }.join @wikicloth = WikiCloth.new(:data => data, :link_handler => self, :params => @options[:params]) end # Get the section, along with any sub-section of the document def get_section(id) @wikicloth.sections.collect { |s| s.get_section(id) }.join end def to_wiki to_wikitext end def to_wikitext @wikicloth.sections.collect { |s| s.wikitext() }.join end end end wikicloth-0.8.1/lib/wikicloth/wiki_buffer/ 0000755 0001750 0001750 00000000000 12263013231 020727 5 ustar avtobiff avtobiff wikicloth-0.8.1/lib/wikicloth/wiki_buffer/var.rb 0000644 0001750 0001750 00000022205 12263013231 022045 0 ustar avtobiff avtobiff require 'expression_parser' require 'digest/md5' require 'uri' module WikiCloth class WikiBuffer::Var < WikiBuffer def initialize(data="",options={}) super(data,options) self.buffer_type = "var" @in_quotes = false @tag_start = true @tag_size = 2 @close_size = 2 @fname = nil end def tag_size @tag_size end def tag_size=(val) @tag_size = val end def skip_links? false end def skip_html? false end def tag_start @tag_start end def tag_start=(val) @tag_start = val end def function_name @fname.nil? ? nil : @fname.strip end def to_html return "" if will_not_be_rendered if self.is_function? if Extension.function_exists?(function_name) return Extension.functions[function_name][:klass].new(@options).instance_exec( params.collect { |p| p.strip }, &Extension.functions[function_name][:block] ).to_s end ret = default_functions(function_name,params.collect { |p| p.strip }) ret ||= @options[:link_handler].function(function_name, params.collect { |p| p.strip }) ret.to_s elsif self.is_param? ret = nil @options[:buffer].buffers.reverse.each do |b| ret = b.get_param(params[0],params[1]) if b.instance_of?(WikiBuffer::HTMLElement) && b.element_name == "template" break unless ret.nil? end ret.to_s else # put template at beginning of buffer template_stack = @options[:buffer].buffers.collect { |b| b.get_param("__name") if b.instance_of?(WikiBuffer::HTMLElement) && b.element_name == "template" }.compact if template_stack.last == params[0] debug_tree = @options[:buffer].buffers.collect { |b| b.debug }.join("-->") "#{I18n.t('template loop detected', :tree => debug_tree)}" else key = params[0].to_s.strip key_options = params[1..-1].collect { |p| p.is_a?(Hash) ? { :name => p[:name].strip, :value => p[:value].strip } : p.strip } key_options ||= [] key_digest = Digest::MD5.hexdigest(key_options.to_a.sort {|x,y| (x.is_a?(Hash) ? x[:name] : x) <=> (y.is_a?(Hash) ? y[:name] : y) }.inspect) return @options[:params][key] if @options[:params].has_key?(key) # if we have a valid cache fragment use it return @options[:cache][key][key_digest] unless @options[:cache].nil? || @options[:cache][key].nil? || @options[:cache][key][key_digest].nil? ret = @options[:link_handler].include_resource(key,key_options).to_s ret.gsub!(//,"") count = 0 tag_attr = key_options.collect { |p| if p.instance_of?(Hash) "#{p[:name]}=\"#{p[:value].gsub(/"/,'"')}\"" else count += 1 "#{count}=\"#{p.gsub(/"/,'"')}\"" end }.join(" ") self.data = ret.blank? ? "" : "#{ret}" "" end end end def will_not_be_rendered @options[:buffer].buffers.reverse.each do |buffer| if buffer.instance_of?(WikiBuffer::Var) && buffer.is_function? return true if buffer.function_name == "#if" && buffer.params.size == 2 && buffer.params[0].strip.blank? return true if buffer.function_name == "#if" && buffer.params.size == 3 && !buffer.params[0].strip.blank? end end false end def default_functions(name,params) case name when "#if" params.first.blank? ? params[2] : params[1] when "#switch" match = params.first default = nil for p in params[1..-1] temp = p.split("=") if p !~ /=/ && temp.length == 1 && p == params.last return p elsif temp.instance_of?(Array) && temp.length > 0 test = temp.first.strip default = temp[1..-1].join("=").strip if test == "#default" return temp[1..-1].join("=").strip if test == match || (test == "none" && match.blank?) end end default.nil? ? "" : default when "#expr" begin ExpressionParser::Parser.new.parse(params.first) rescue RuntimeError I18n.t('expression error', :error => $!) end when "#ifexpr" val = false begin val = ExpressionParser::Parser.new.parse(params.first) rescue RuntimeError end if val params[1] else params[2] end when "#ifeq" if params[0] =~ /^[0-9A-Fa-f]+$/ && params[1] =~ /^[0-9A-Fa-f]+$/ params[0].to_i == params[1].to_i ? params[2] : params[3] else params[0] == params[1] ? params[2] : params[3] end when "#len" params.first.length when "#sub" params.first[params[1].to_i,params[2].to_i] when "#pad" case params[3] when "right" params[0].ljust(params[1].to_i,params[2]) when "center" params[0].center(params[1].to_i,params[2]) else params[0].rjust(params[1].to_i,params[2]) end when "#iferror" params.first =~ /error/ ? params[1] : params[2] when "#capture" @options[:params][params.first] = params[1] "" when "urlencode" URI.escape(params.first, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")) when "lc" params.first.downcase when "uc" params.first.upcase when "ucfirst" params.first.capitalize when "lcfirst" params.first[0,1].downcase + params.first[1..-1] when "anchorencode" params.first.gsub(/\s+/,'_') when "plural" begin expr_value = ExpressionParser::Parser.new.parse(params.first) expr_value.to_i == 1 ? params[1] : params[2] rescue RuntimeError I18n.t('expression error', :error => $!) end when "ns" values = { "" => "", "0" => "", "1" => localise_ns("Talk"), "talk" => localise_ns("Talk"), "6" => localise_ns("File"), "file" => localise_ns("File"), "image" => localise_ns("File"), "10" => localise_ns("Template"), "template" => localise_ns("Template"), "14" => localise_ns("Category"), "category" => localise_ns("Category"), "-1" => localise_ns("Special"), "special" => localise_ns("Special"), "12" => localise_ns("Help"), "help" => localise_ns("Help"), "-2" => localise_ns("Media"), "media" => localise_ns("Media") } values[localise_ns(params.first,:en).gsub(/\s+/,'_').downcase] when "#language" WikiNamespaces.language_name(params.first) when "#tag" return "" if params.empty? elem = Builder::XmlMarkup.new return elem.tag!(params.first) if params.length == 1 return elem.tag!(params.first) { |e| e << params.last } if params.length == 2 tag_attrs = {} params[1..-2].each do |attr| tag_attrs[$1] = $2 if attr =~ /^\s*([\w]+)\s*=\s*"(.*)"\s*$/ end elem.tag!(params.first,tag_attrs) { |e| e << params.last } when "debug" ret = nil case params.first when "param" @options[:buffer].buffers.reverse.each do |b| if b.instance_of?(WikiBuffer::HTMLElement) && b.element_name == "template" ret = b.get_param(params[1]) end end ret when "buffer" ret = "" buffer = @options[:buffer].buffers buffer.each do |b| ret += " --- #{b.class}" ret += b.instance_of?(WikiBuffer::HTMLElement) ? " -- #{b.element_name}\n" : " -- #{b.data}\n" end "#{ret}" end end end def localise_ns(name,lang=nil) WikiNamespaces.localise_ns(name,lang) end def is_param? @tag_size == 3 ? true : false end def is_function? self.function_name.nil? || self.function_name.blank? ? false : true end protected def function_name=(val) @fname = val end def new_char() case when current_char == '|' && @in_quotes == false self.current_param = self.data self.data = "" self.params << "" # Start of either a function or a namespace change when current_char == ':' && @in_quotes == false && self.params.size <= 1 if self.data.blank? || self.data.include?(":") self.data << current_char else self.function_name = self.data self.data = "" end # Dealing with variable names within functions # and variables when current_char == '=' && @in_quotes == false && !is_function? self.current_param = self.data self.data = "" self.name_current_param() # End of a template, variable, or function when current_char == '}' && previous_char == '}' if @close_size == @tag_size self.data.chop! self.current_param = self.data self.data = "" return false else @close_size += 1 end else self.data << current_char if @tag_start # FIXME: template params and templates colliding if @tag_size > 3 if @tag_size == 5 @options[:buffer].buffers << WikiBuffer::Var.new(self.data,@options) @options[:buffer].buffers[-1].tag_start = false self.data = "" @tag_size = 3 return true end end @tag_start = false end end return true end end end wikicloth-0.8.1/lib/wikicloth/wiki_buffer/link.rb 0000644 0001750 0001750 00000005007 12263013231 022213 0 ustar avtobiff avtobiff module WikiCloth class WikiBuffer::Link < WikiBuffer def initialize(data="",options={}) super(data,options) @in_quotes = false @checktrailing = false end def internal_link @internal_link ||= false end def to_html link_handler = @options[:link_handler] unless self.internal_link || params[0].strip !~ /^\s*((([a-z]+):\/\/|mailto:)|[\?\/])(.*)/ if $1.downcase == "mailto:" return link_handler.external_link("#{params[0]}".strip, $4) elsif params.length > 1 return link_handler.external_link("#{params[0]}".strip, params.last.strip) else return link_handler.external_link("#{params[0]}".strip) end else case when !self.internal_link return "[#{params[0]}]" when params[0] =~ /^:(.*)/ return link_handler.link_for(params[0],params[1]) when params[0] =~ /^\s*([^\]\s:]+)\s*:(.*)$/ return link_handler.link_for_resource($1,$2,params[1..-1]) else return "" if params[0].blank? && params[1].blank? return link_handler.link_for(params[0],params[1]) end end end def eof() self.current_param = self.data end protected def internal_link=(val) @internal_link = (val == true ? true : false) end def new_char() case when @checktrailing && current_char !~ /\w/ self.current_param = self.data self.data = current_char == '{' ? "" : current_char return false # check if this link is internal or external when previous_char.blank? && current_char == '[' self.internal_link = true # Marks the beginning of another paramater for # the current object when current_char == '|' && self.internal_link == true && @in_quotes == false self.current_param = self.data self.data = "" self.params << "" # URL label when current_char == ' ' && self.internal_link == false && params[1].nil? && !self.data.blank? self.current_param = self.data self.data = "" self.params << "" # end of link when current_char == ']' && ((previous_char == ']' && self.internal_link == true) || self.internal_link == false) && @in_quotes == false self.current_param = self.data if self.internal_link == true self.data.chop!.rstrip! self.params << "" unless self.params.size > 1 @checktrailing = true else self.data = "" return false end else self.data += current_char unless current_char == ' ' && self.data.blank? end return true end end end wikicloth-0.8.1/lib/wikicloth/wiki_buffer/html_element.rb 0000644 0001750 0001750 00000017631 12263013231 023741 0 ustar avtobiff avtobiff require 'rexml/document' module WikiCloth class WikiBuffer::HTMLElement < WikiBuffer ALLOWED_ELEMENTS = ['a','b','i','img','div','span','sup','sub','strike','s','u','font','big','ref','tt','del', 'small','blockquote','strong','pre','code','references','ol','li','ul','dd','dt','dl','center', 'h1','h2','h3','h4','h5','h6','p','table','tr','td','th','tbody','thead','tfoot','abbr','del','ins','em'] ALLOWED_ATTRIBUTES = ['src','id','name','style','class','href','start','value','colspan','align','border', 'cellpadding','cellspacing','name','valign','color','rowspan','nowrap','title','rel','for'] ESCAPED_TAGS = [ 'nowiki','pre','code' ] SHORT_TAGS = [ 'meta','br','hr'] NO_NEED_TO_CLOSE = ['li','p'] + SHORT_TAGS DISABLE_GLOBALS_FOR = ESCAPED_TAGS def initialize(d="",options={},check=nil) super("",options) self.buffer_type = "Element" @in_quotes = false @in_single_quotes = false @start_tag = 1 @tag_check = check end def debug case self.element_name when "template" self.get_param("__name") else ret = self.class.to_s + "[" ret += self.element_name tmp = self.get_param("id") ret += tmp.nil? ? "" : "##{tmp}" ret + "]" end end def skip_html? return Extension.skip_html?(self.element_name) if Extension.element_exists?(self.element_name) DISABLE_GLOBALS_FOR.include?(self.element_name) ? true : false end def run_globals? return false if self.in_template? && self.element_name == "noinclude" return false if !self.in_template? && self.element_name == "includeonly" return Extension.run_globals?(self.element_name) if Extension.element_exists?(self.element_name) return DISABLE_GLOBALS_FOR.include?(self.element_name) ? false : true end def to_html if NO_NEED_TO_CLOSE.include?(self.element_name) return "<#{self.element_name} />" if SHORT_TAGS.include?(self.element_name) return "#{self.element_name}><#{self.element_name}>" if @tag_check == self.element_name end if ESCAPED_TAGS.include?(self.element_name) # remove empty first line self.element_content = $1 if self.element_content =~ /^\s*\n(.*)$/m # escape all html inside this element self.element_content = self.element_content.gsub('<','<').gsub('>','>') # hack to fix
nested mess self.element_content = self.element_content.gsub(/<[\/]*\s*nowiki\s*>/,'') end case self.element_name when "template" @options[:link_handler].cache({ :name => self.element_attributes["__name"], :content => self.element_content, :md5 => self.element_attributes["__hash"] }) return self.element_content when "noinclude" return self.in_template? ? "" : self.element_content when "includeonly" return self.in_template? ? self.element_content : "" when "nowiki" return self.element_content when "a" if self.element_attributes['href'] =~ /:\/\// return @options[:link_handler].external_link(self.element_attributes['href'], self.element_content) elsif self.element_attributes['href'].nil? || self.element_attributes['href'] =~ /^\s*([\?\/])/ # if a element has no href attribute, or href starts with / or ? return elem.tag!(self.element_name, self.element_attributes) { |x| x << self.element_content } end else if Extension.element_exists?(self.element_name) return Extension.html_elements[self.element_name][:klass].new(@options).instance_exec( self, &Extension.html_elements[self.element_name][:block] ).to_s end end tmp = elem.tag!(self.element_name, self.element_attributes) { |x| x << self.element_content } unless ALLOWED_ELEMENTS.include?(self.element_name) tmp.gsub!(/[\-!\|&"\{\}\[\]]/) { |r| self.escape_char(r) } return tmp.gsub('<', '<').gsub('>', '>') end tmp end def get_attribute_by_name(name) params.each { |p| return p[:value] if p.kind_of?(Hash) && p[:name] == name } nil end def element_attributes attr = {} params.each { |p| attr[p[:name]] = p[:value] if p.kind_of?(Hash) } if ALLOWED_ELEMENTS.include?(self.element_name.strip.downcase) attr.delete_if { |key,value| !ALLOWED_ATTRIBUTES.include?(key.strip) } end return attr end def element_name @ename ||= "" end def element_content @econtent ||= "" end protected def escape_char(c) c = case c when '-' then '-' when '!' then '!' when '|' then '|' when '&' then '&' when '"' then '"' when '{' then '{' when '}' then '}' when '[' then '[' when ']' then ']' when '*' then '*' when '#' then '#' when ':' then ':' when ';' then ';' when "'" then ''' when '=' then '=' else c end return c end def elem Builder::XmlMarkup.new end def element_name=(val) @ename = val end def element_content=(val) @econtent = val end def in_quotes? @in_quotes || @in_single_quotes ? true : false end def new_char() case # tag name when @start_tag == 1 && current_char == ' ' self.element_name = self.data.strip.downcase self.data = "" @start_tag = 2 # tag is closed no attributes when @start_tag == 1 && previous_char == '/' && current_char == '>' self.data.chop! self.element_name = self.data.strip.downcase self.data = "" @start_tag = 0 return false # open tag when @start_tag == 1 && previous_char != '/' && current_char == '>' self.element_name = self.data.strip.downcase self.data = "" @start_tag = 0 return false if SHORT_TAGS.include?(self.element_name) return false if self.element_name == @tag_check && NO_NEED_TO_CLOSE.include?(self.element_name) # new tag attr when @start_tag == 2 && current_char == ' ' && self.in_quotes? == false self.current_param = self.data self.data = "" self.params << "" # tag attribute name when @start_tag == 2 && current_char == '=' && self.in_quotes? == false self.current_param = self.data self.data = "" self.name_current_param() # tag is now open when @start_tag == 2 && previous_char != '/' && current_char == '>' self.current_param = self.data self.data = "" @start_tag = 0 return false if SHORT_TAGS.include?(self.element_name) return false if self.element_name == @tag_check && NO_NEED_TO_CLOSE.include?(self.element_name) # tag is closed when @start_tag == 2 && previous_char == '/' && current_char == '>' self.current_param = self.data.chop self.data = "" @start_tag = 0 return false # in quotes when @start_tag == 2 && current_char == "'" && previous_char != '\\' && !@in_quotes @in_single_quotes = !@in_single_quotes # in quotes when @start_tag == 2 && current_char == '"' && previous_char != '\\' && !@in_single_quotes @in_quotes = !@in_quotes # start of a closing tag when @start_tag == 0 && previous_char == '<' && current_char == '/' self.element_content += self.data.chop self.data = "" @start_tag = 5 when @start_tag == 5 && (current_char == '>' || current_char == ' ') && !self.data.blank? self.data = self.data.strip.downcase if self.data == self.element_name self.data = "" return false else if @tag_check == self.data && NO_NEED_TO_CLOSE.include?(self.element_name) self.data = "#{self.data}>" return false else self.element_content += skip_html? ? "#{self.data}>" : "</#{self.data}>" @start_tag = 0 self.data = "" end end else if @start_tag == 0 && ESCAPED_TAGS.include?(self.element_name) self.data << self.escape_char(current_char) else self.data << current_char end end return true end end end wikicloth-0.8.1/lib/wikicloth/wiki_buffer/table.rb 0000644 0001750 0001750 00000012552 12263013231 022350 0 ustar avtobiff avtobiff module WikiCloth class WikiBuffer::Table < WikiBuffer def initialize(data="",options={}) super(data,options) self.buffer_type = "table" @start_table = true @start_row = false @start_caption = false @in_quotes = false end def table_caption @caption ||= "" return @caption.kind_of?(Hash) ? @caption[:value] : @caption end def table_caption_attributes @caption.kind_of?(Hash) ? @caption[:style] : "" end def rows @rows ||= [ [] ] end def to_html row_count = 0 ret = " " ret += "
" end protected def parse_attributes(data) attribute_name = nil in_quotes = false quote_type = nil ret = {} d = "" prev_char = nil for char in data.each_char case when char == "=" && attribute_name.nil? && in_quotes == false attribute_name = d.strip d = "" when (char == '"' || char == "'") && in_quotes == false && !attribute_name.nil? in_quotes = true quote_type = char when (char == quote_type && in_quotes == true && prev_char != '\\') || (char == ' ' && in_quotes == false && !d.blank?) ret[attribute_name] = d if WikiBuffer::HTMLElement::ALLOWED_ATTRIBUTES.include?(attribute_name) attribute_name = nil in_quotes = false d = "" else prev_char = char d += char end end ret end def rows=(val) @rows = val end def table_caption_attributes=(val) @caption = { :style => val, :value => self.table_caption } unless @caption.kind_of?(Hash) @caption[:style] = val if @caption.kind_of?(Hash) end def table_caption=(val) @caption = val unless @caption.kind_of?(Hash) @caption[:value] = val if @caption.kind_of?(Hash) end def next_row() self.params << "" self.rows << [] end def next_cell(type="td") if self.rows[-1].size == 0 self.rows[-1] = [ { :type => type, :value => "", :style => "" } ] else self.rows[-1][-1][:value] = self.data self.rows[-1] << { :type => type, :value => "", :style => "" } end end def new_char() if @check_cell_data == 1 case when current_char != '|' && @start_caption == false && (self.rows[-1][-1].nil? || self.rows[-1][-1][:style].blank?) self.next_cell() if self.rows[-1][-1].nil? self.rows[-1][-1][:style] = self.data self.data = "" when current_char != '|' && @start_caption == true && self.table_caption_attributes.blank? self.table_caption_attributes = self.data self.data = "" end @check_cell_data = 0 end case # Next table cell in row (TD) when current_char == "|" && (previous_char == "\n" || previous_char == "|") && @in_quotes == false self.data.chop! if self.data[-1,1] == "|" self.next_cell() unless self.data.blank? && previous_char == "|" self.data = "" # Next table cell in row (TH) when current_char == "!" && (previous_char == "\n" || previous_char == "!") && @in_quotes == false self.data.chop! self.next_cell('th') self.data = "" # End of a table when current_char == '}' && previous_char == '|' self.data = "" self.rows[-1].pop return false # Start table caption when current_char == '+' && previous_char == '|' && @in_quotes == false self.data = "" self.rows[-1].pop @start_caption = true # Table cell might have attributes when current_char == '|' && previous_char != "\n" && @in_quotes == false @check_cell_data = 1 unless @start_table # End table caption when current_char == "\n" && @start_caption == true && @in_quotes == false @start_caption = false self.table_caption = self.data self.data = "" # in quotes when current_char == '"' && previous_char != '\\' @in_quotes = !@in_quotes self.data += '"' # Table params when current_char == "\n" && @start_table == true && @in_quotes == false @start_table = false unless self.data.blank? self.current_param = self.data self.params << "" end self.data = "" # Table row params when current_char == "\n" && @start_row == true && @in_quotes == false @start_row = false unless self.data.blank? self.current_param = self.data end self.data = "" # Start new table row when current_char == '-' && previous_char == '|' && @in_quotes == false self.data.chop! self.rows[-1].pop self.next_row() @start_row = true else self.data << current_char end return true end end end wikicloth-0.8.1/lib/wikicloth/extension.rb 0000644 0001750 0001750 00000002315 12263013231 020775 0 ustar avtobiff avtobiff module WikiCloth class Extension def initialize(options={}) @options = options end class << self def html_elements @@html_elements ||= {} end def functions @@functions ||= {} end def element(*args,&block) options = args.last.is_a?(Hash) ? args.pop : {} key = args.shift html_elements[key] = { :klass => self, :block => block, :options => { :skip_html => false, :run_globals => true }.merge(options) } end def skip_html?(elem) return true if !element_exists?(elem) html_elements[elem][:options][:skip_html] end def run_globals?(elem) return false if !element_exists?(elem) html_elements[elem][:options][:run_globals] end def element_exists?(elem) html_elements.has_key?(elem) end def function(name,&block) functions[name] = { :klass => self, :block => block } end def function_exists?(name) functions.has_key?(name) end protected def html_elements=(val) @@html_elements = val end def functions=(val) @@functions = val end end end end wikicloth-0.8.1/lib/wikicloth/i18n.rb 0000644 0001750 0001750 00000004636 12263013231 017550 0 ustar avtobiff avtobiff require 'yaml' module I18n class << self def default_locale :en end def locale @@locale ||= default_locale end def locale=(val) @@locale = val end def t(*args) options = args.last.is_a?(Hash) ? args.pop : {} key = args.shift load_translations use_locale = @@translations[locale].nil? || @@translations[locale].empty? ? default_locale : locale if !@@translations[use_locale].nil? && @@translations[use_locale].has_key?(key) add_vars(@@translations[use_locale][key], options) elsif use_locale != default_locale && @@translations[default_locale].has_key?(key) add_vars(@@translations[default_locale][key], options) else "translation missing: #{locale}, #{key}" end end def available_locales load_translations @@available_locales end def load_path @@load_paths ||= [] end def load_path=(val) @@load_paths = val end def load_translations return if initialized? @@available_locales = [] @@translations = {} load_path.each do |path| Dir[path].each do |file| begin data = YAML::load(File.read(file)) data.each do |key,value| @@available_locales << key.to_sym unless @@available_locales.include?(key.to_sym) @@translations[key.to_sym] ||= {} import_values(key.to_sym,value) end rescue ArgumentError => err puts "error in #{file}: #{err.message}" end end end initialized! end def initialized? @@initialized ||= false end def initialized! @@initialized = true end # Executes block with given I18n.locale set. def with_locale(tmp_locale = nil) if tmp_locale current_locale = self.locale self.locale = tmp_locale end yield ensure self.locale = current_locale if tmp_locale end private def import_values(key,values,prefix=[]) values.each do |k,value| if value.is_a?(Hash) import_values(key,value,prefix+[k]) else @@translations[key.to_sym][(prefix+[k]).join(".")] = value end end end def add_vars(string, options) options.each do |key,value| string.gsub!(/(%\{#{key}\})/, value.to_s) end string end end end wikicloth-0.8.1/lib/wikicloth/core_ext.rb 0000644 0001750 0001750 00000003122 12263013231 020566 0 ustar avtobiff avtobiff require 'rinku' if RUBY_VERSION < '1.9' READ_MODE = "r" class Object module InstanceExecHelper; end include InstanceExecHelper def instance_exec(*args, &block) begin old_critical, Thread.critical = Thread.critical, true n = 0 n += 1 while respond_to?(mname="__instance_exec#{n}") InstanceExecHelper.module_eval{ define_method(mname, &block) } ensure Thread.critical = old_critical end begin ret = send(mname, *args) ensure InstanceExecHelper.module_eval{ remove_method(mname) } rescue nil end ret end end else READ_MODE = "r:UTF-8" end module Math def self.eval(expression) allowed_characters = Regexp.escape('+-*/.() ') safe_expression = expression.match(/[\d#{allowed_characters}]*/).to_s Kernel.eval(safe_expression) end end module ExtendedString def blank? respond_to?(:empty?) ? empty? : !self end def addslashes self.gsub(/['"\\\x0]/,'\\\\\0'); end def to_slug self.gsub(/\W+/, '-').gsub(/^-+/,'').gsub(/-+$/,'').downcase end def auto_link Rinku.auto_link(to_s) end def last(n) self[-n,n] end def dump() ret = to_s delete!(to_s) ret end def smart_split(char) ret = [] tmp = "" inside = 0 to_s.each_char do |x| if x == char && inside == 0 ret << tmp tmp = "" else inside += 1 if x == "[" || x == "{" || x == "<" inside -= 1 if x == "]" || x == "}" || x == ">" tmp += x end end ret << tmp unless tmp.empty? ret end end wikicloth-0.8.1/lib/wikicloth.rb 0000644 0001750 0001750 00000011306 12263013231 016761 0 ustar avtobiff avtobiff require 'rubygems' if RUBY_VERSION < '1.9' require 'jcode' if RUBY_VERSION < '1.9' require 'builder' # if i18n gem loaded use it instead require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "i18n") unless defined?(I18n) I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) if defined?(I18n::Backend::Simple) I18n.load_path += Dir[File.join(File.expand_path(File.dirname(__FILE__)), "../lang/*.yml")].collect { |f| f } require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "version") require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "core_ext") require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "namespaces") require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "extension") require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "section") require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "wiki_buffer") require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "wiki_link_handler") require File.join(File.expand_path(File.dirname(__FILE__)), "wikicloth", "parser") String.send(:include, ExtendedString) module WikiCloth class WikiCloth def initialize(opt={}) self.options.merge!(opt) self.options[:extensions] ||= [] self.options[:link_handler] = opt[:link_handler] unless opt[:link_handler].nil? self.load(opt[:data],opt[:params]) unless opt[:data].nil? @current_line = 1 @current_row = 0 end def load(data,p={}) depth = 1 count = 0 root = [self.sections] # parse wiki document into sections data.each_line do |line| if line =~ /^([=]{1,6})\s*(.*?)\s*(\1)/ root << root.last[-1].children if $1.length > depth root.pop if $1.length < depth depth = $1.length root.last << Section.new(line, get_id_for($2.gsub(/\s+/,'_'))) count += 1 else root.last[-1] << line end end # if we find template variables assume document is # a template self.sections.first.template = true if data =~ /\{\{\{\s*([A-Za-z0-9]+)\s*\}\}\}/ # If there are more than four sections enable automatic # table of contents self.sections.first.auto_toc = true unless count < 4 || data =~ /__(NO|)TOC__/ self.params = p end def render(opt={}) self.options = { :noedit => false, :locale => I18n.default_locale, :fast => true, :output => :html, :link_handler => self.link_handler, :params => self.params, :sections => self.sections }.merge(self.options).merge(opt) self.options[:link_handler].params = options[:params] I18n.locale = self.options[:locale] data = self.sections.collect { |s| s.render(self.options) }.join data.gsub!(//,"") data << "\n" if data.last(1) != "\n" data << "garbage" buffer = WikiBuffer.new("",options) begin if self.options[:fast] until data.empty? case data when /\A\w+/ data = $' @current_row += $&.length buffer.add_word($&) when /\A[^\w]+(\w|)/m data = $' $&.each_char { |c| add_current_char(buffer,c) } end end else data.each_char { |c| add_current_char(buffer,c) } end rescue => err debug_tree = buffer.buffers.collect { |b| b.debug }.join("-->") puts I18n.t("unknown error on line", :line => @current_line, :row => @current_row, :tree => debug_tree) raise err end buffer.eof() buffer.send("to_#{self.options[:output]}") end def sections @sections ||= [Section.new] end def to_html(opt={}) self.render(opt.merge(:output => :html)) end def link_handler self.options[:link_handler] ||= WikiLinkHandler.new end def params @page_params ||= {} end def options @options ||= {} end def method_missing(method, *args) if self.link_handler.respond_to?(method) self.link_handler.send(method, *args) else super(method, *args) end end protected def add_current_char(buffer,c) if c == "\n" @current_line += 1 @current_row = 1 else @current_row += 1 end buffer.add_char(c) end def sections=(val) @sections = val end def get_id_for(val) val.gsub!(/[^A-Za-z0-9_]+/,'') @idmap ||= {} @idmap[val] ||= 0 @idmap[val] += 1 @idmap[val] == 1 ? val : "#{val}-#{@idmap[val]}" end def options=(val) @options = val end def params=(val) @page_params = val end end end wikicloth-0.8.1/README.textile 0000644 0001750 0001750 00000004043 12263013231 016226 0 ustar avtobiff avtobiff h1. WikiCloth "!https://api.travis-ci.org/nricciar/wikicloth.png!":https://travis-ci.org/nricciar/wikicloth Ruby implementation of the MediaWiki markup language. h2. Supports * Variables, Templates {{ ... }} * Links ** External Links [ ... ] ** Internal Links, Images [[ ... ]] * Markup ** == Headings == ** Lists (*#;:) ** bold (#{table_caption.strip} " unless self.table_caption.blank? for row in rows row_count += 1 unless row.empty? ret += "" for cell in row cell_attributes = cell[:style].blank? ? "" : parse_attributes(cell[:style].strip).collect { |k,v| "#{k}=\"#{v}\"" }.join(" ") cell_attributes = cell_attributes.blank? ? "" : " #{cell_attributes}" ret += "<#{cell[:type]}#{cell_attributes}>\n#{cell[:value].strip}\n#{cell[:type]}>" end ret += " " end end ret += "'''
), italic (''
) or both ('''''
) ** Horizontal rule (----) ** "Tables":https://github.com/nricciar/wikicloth/wiki/Tables ** Table of Contents [__NOTOC__, __FORCETOC__, __TOC__
] *
,
(disable wiki markup) *, and
support * "html sanitization":https://github.com/nricciar/wikicloth/wiki/Html-Sanitization For more information about the MediaWiki markup see "https://www.mediawiki.org/wiki/Markup_spec":https://www.mediawiki.org/wiki/Markup_spec h2. Install
git clone git://github.com/nricciar/wikicloth.git cd wikicloth/ rake installh2. Usage@wiki = WikiCloth::Parser.new({ :data => "h2. Advanced Usage Most features of WikiCloth can be overriden as needed...{{test}} ''Hello {{test}}!''\n", :params => { "test" => "World" } }) @wiki.to_html => "{{test}} Hello World!
"class WikiParser < WikiCloth::Parser url_for do |page| "javascript:alert('You clicked on: #{page}');" end link_attributes_for do |page| { :href => url_for(page) } end template do |template| "Hello {{{1}}}" if template == "hello" end external_link do |url,text| "#{text.blank? ? url : text}" end end @wiki = WikiParser.new({ :params => { "PAGENAME" => "Testing123" }, :data => "{{hello|world}} From {{ PAGENAME }} -- [www.google.com]"; }) @wiki.to_html =>wikicloth-0.8.1/examples/ 0000755 0001750 0001750 00000000000 12263013231 015506 5 ustar avtobiff avtobiff wikicloth-0.8.1/examples/print.rb 0000644 0001750 0001750 00000001134 12263013231 017166 0 ustar avtobiff avtobiff require File.join(File.dirname(__FILE__),'../init.rb') if ARGV[0] && File.exists?(ARGV[0]) data = File.read(ARGV[0]) else data = "[[ this ]] is a [[ link ]] and another [http://www.google.com Google] but they should be disabled" end # Disables all links in the document for printing class PrettyPrint < WikiCloth::Parser external_link do |url,text| text.nil? ? url : "#{text} (#{url})" end link_for do |page,text| text.nil? ? page : text end end # load file into custom parser and render without # section edit links puts PrettyPrint.new(:data => data).to_html(:noedit => true) wikicloth-0.8.1/examples/template_extractor.rb 0000644 0001750 0001750 00000003025 12263013231 021741 0 ustar avtobiff avtobiff # encoding: utf-8 # # Take a wiki document and extract the template options of the specified template # # {{Infobox person # |name = Casanova # |image = Casanova_self_portrait.jpg # |caption = A self portrait of Casanova # |website = # }} # # and returns the template data in json... # # {"name":"Casanova","caption":"A self portrait of Casanova","website":"","image":"Casanova_self_portrait.jpg"} # # This file takes two arguments: filename, and template name # ex: ./template_extractor test.wiki "Infobox person" # require File.join(File.dirname(__FILE__),'../init.rb') require 'json' class TemplateExtractor < WikiCloth::Parser def initialize(args = {}) @templates = [] super(args) to_html # parse the document end def extract(name) ret = [] @templates.each do |template| ret << template[:data] if template[:name] == name end ret.length == 1 ? ret.first : ret end link_for do |url,text| text.blank? ? url : text end include_resource do |resource,options| data = {} options.each do |opt| data[opt[:name]] = opt[:value] end @templates << { :name => resource, :data => data } "" end end wiki_data = "" if ARGV[0] && File.exists?(ARGV[0]) wiki_data = File.read(ARGV[0]) else wiki_data = <Hello world From Testing123 -- http://www.google.com
wiki_data) puts @wiki.extract(ARGV[1] ? ARGV[1] : "Infobox person").to_json wikicloth-0.8.1/examples/info.rb 0000644 0001750 0001750 00000001246 12263013231 016771 0 ustar avtobiff avtobiff require File.join(File.dirname(__FILE__),'../init.rb') if ARGV[0] && File.exists?(ARGV[0]) data = File.read(ARGV[0]) else data = "[[ this ]] is a [[ link ]] and another [http://www.google.com Google]. This is a reference, but this is a [[Category:Test]]. This is in another [[de:Sprache]]" end wiki = WikiCloth::Parser.new(:data => data) wiki.to_html puts "Internal Links: #{wiki.internal_links.size}" puts "External Links: #{wiki.external_links.size}" puts "References: #{wiki.references.size}" puts "Categories: #{wiki.categories.size} [#{wiki.categories.join(",")}]" puts "Languages: #{wiki.languages.size} [#{wiki.languages.keys.join(",")}]" wikicloth-0.8.1/Gemfile 0000644 0001750 0001750 00000000031 12263013231 015155 0 ustar avtobiff avtobiff source :rubygems gemspec wikicloth-0.8.1/Rakefile 0000644 0001750 0001750 00000001521 12263013231 015334 0 ustar avtobiff avtobiff require 'rubygems' require 'rake' require File.join(File.dirname(__FILE__),'init') require 'bundler' Bundler::GemHelper.install_tasks require 'rake/testtask' Rake::TestTask.new(:test) do |test| test.pattern = 'test/*_test.rb' test.verbose = true end if RUBY_VERSION =~ /^1\.9/ require 'simplecov' desc "Code coverage detail" task :simplecov do ENV['COVERAGE'] = "true" Rake::Task['spec'].execute end else require 'rcov/rcovtask' Rcov::RcovTask.new do |test| test.libs << 'test' test.pattern = 'test/**/test_*.rb' test.verbose = true end end task :default => :test require 'rdoc/task' RDoc::Task.new do |rdoc| rdoc.rdoc_dir = 'rdoc' rdoc.title = "wikicloth #{WikiCloth::VERSION}" rdoc.rdoc_files.include('README*') rdoc.rdoc_files.include('MIT-LICENSE') rdoc.rdoc_files.include('lib/**/*.rb') end wikicloth-0.8.1/run_tests.rb 0000644 0001750 0001750 00000002764 12263013231 016254 0 ustar avtobiff avtobiff require File.join(File.dirname(__FILE__),'init') include WikiCloth class WikiParser < WikiCloth::Parser include_resource do |resource,options| case resource when "date" Time.now.to_s else params[resource].nil? ? "" : params[resource] end end url_for do |page| "javascript:alert('You clicked on: #{page}');" end link_attributes_for do |page| { :href => url_for(page) } end end @wiki = WikiCloth::Parser.new({ :data => "\n {{test}}\n\n {{test}} ''Hello {{test}}!''\n", :params => { "test" => "World" } }) puts @wiki.to_html @wiki = WikiParser.new({ :params => { "PAGENAME" => "Testing123" }, :data => "[[Hello World]] From {{ PAGENAME }} on {{ date }}" }) puts @wiki.to_html Dir.glob("sample_documents/*.wiki").each do |x| start_time = Time.now out_name = "#{x}.html" data = File.open(x, READ_MODE) { |x| x.read } tmp = WikiCloth::Parser.new({ :data => data, :params => { "PAGENAME" => "HelloWorld" } }) out = tmp.to_html out = "#{out}" File.open(out_name, "w") { |x| x.write(out) } end_time = Time.now puts "#{out_name}: Completed (#{end_time - start_time} sec) | External Links: #{tmp.external_links.size} -- References: #{tmp.references.size}" end wikicloth-0.8.1/test/ 0000755 0001750 0001750 00000000000 12263013231 014647 5 ustar avtobiff avtobiff wikicloth-0.8.1/test/locales.yml 0000644 0001750 0001750 00000005646 12263013231 017027 0 ustar avtobiff avtobiff :af: hello: "world" :am: hello: "world" :ang: hello: "world" :ar: hello: "world" :arc: hello: "world" :ast: hello: "world" :az: hello: "world" :bn: hello: "world" :zh_min_nan: hello: "world" :ba: hello: "world" :be: hello: "world" :be_x_old: hello: "world" :bar: hello: "world" :bs: hello: "world" :br: hello: "world" :bg: hello: "world" :ca: hello: "world" :ceb: hello: "world" :cs: hello: "world" :co: hello: "world" :cy: hello: "world" :da: hello: "world" :de: hello: "world" :dv: hello: "world" :et: hello: "world" :el: hello: "world" :es: hello: "world" :eo: hello: "world" :eu: hello: "world" :fa: hello: "world" :fo: hello: "world" :fr: hello: "world" :fy: hello: "world" :ga: hello: "world" :gd: hello: "world" :gl: hello: "world" :gan: hello: "world" :ko: hello: "world" :hy: hello: "world" :hi: hello: "world" :hr: hello: "world" :io: hello: "world" :id: hello: "world" :is: hello: "world" :it: hello: "world" :he: hello: "world" :jv: hello: "world" :kn: hello: "world" :pam: hello: "world" :ka: hello: "world" :sw: hello: "world" :ku: hello: "world" :la: hello: "world" :lv: hello: "world" :lb: hello: "world" :lt: hello: "world" :hu: hello: "world" :mk: hello: "world" :mg: hello: "world" :ml: hello: "world" :mr: hello: "world" :arz: hello: "world" :ms: hello: "world" :nah: hello: "world" :nl: hello: "world" :ja: hello: "world" :no: hello: "world" :nn: hello: "world" :oc: hello: "world" :uz: hello: "world" :pap: hello: "world" :nds: hello: "world" :pl: hello: "world" :pt: hello: "world" :ksh: hello: "world" :ro: hello: "world" :qu: hello: "world" :ru: hello: "world" :sa: hello: "world" :sco: hello: "world" :sq: hello: "world" :scn: hello: "world" :simple: hello: "world" :sk: hello: "world" :sl: hello: "world" :sr: hello: "world" :sh: hello: "world" :fi: hello: "world" :sv: hello: "world" :tl: hello: "world" :ta: hello: "world" :th: hello: "world" :tg: hello: "world" :tr: hello: "world" :uk: hello: "world" :ur: hello: "world" :vi: hello: "world" :zh_classical: hello: "world" :yi: hello: "world" :bat_smg: hello: "world" :zh: hello: "world" :lo: hello: "world" :en: hello: "world" :gn: hello: "world" :map_bms: hello: "world" :pdc: hello: "world" :eml: hello: "world" :ki: hello: "world" :hak: hello: "world" :ia: hello: "world" :ky: hello: "world" :lad: hello: "world" :nds_nl: hello: "world" :ne: hello: "world" :nrm: hello: "world" :nov: hello: "world" :sm: hello: "world" :si: hello: "world" :su: hello: "world" :kab: hello: "world" :te: hello: "world" :vec: hello: "world" :fiu_vro: hello: "world" :wa: hello: "world" :war: hello: "world" :wuu: hello: "world" :zh_yue: hello: "world" :diq: hello: "world" :als: hello: "world" :bjn: hello: "world" :ce: hello: "world" :ht: hello: "world" wikicloth-0.8.1/test/wiki_cloth_test.rb 0000644 0001750 0001750 00000036057 12263013231 020402 0 ustar avtobiff avtobiff # encoding: utf-8 require File.expand_path(File.join(File.dirname(__FILE__),'test_helper')) class WikiParser < WikiCloth::Parser url_for do |page| page end image_url_for do |url| File.join("/images/", url) end template do |template| case template when "noinclude" "hello world testing " when "test" "busted" when "nowiki" "hello world" when "testparams" "{{{def|hello world}}} {{{1}}} {{{test}}} {{{nested|{{{2}}}}}}" when "moreparamtest" "{{{{{test|bla}}|wtf}}}" when "loop" "{{loop}}" when "tablebegin" "" when "tablemid" "
" end end external_link do |url,text| "#{text.blank? ? url : text}" end end class WikiClothTest < ActiveSupport::TestCase test "a url should be automaticly linked" do wiki = WikiCloth::Parser.new(:data => "\n\n\nhttp://www.google.com/") data = wiki.to_html assert data.include?('') wiki = WikiCloth::Parser.new(:data => "hello http://www.google.com/ world") data = wiki.to_html assert data.include?('') wiki = WikiCloth::Parser.new(:data => "http://www.google.com/") data = wiki.to_html assert data.include?('') wiki = WikiCloth::Parser.new(:data => "[https://github.com/repo/README.md README]") data = wiki.to_html assert data.include?('https://github.com/repo/README.md') assert data =~ /\>\s*README\s*\ end test "image url override" do wiki = WikiCloth::Parser.new(:data => "[[Image:test.jpg]]") data = wiki.to_html assert !data.include?("/images/test.jpg") assert data.include?("\"test.jpg\"") wiki = WikiParser.new(:data => "[[Image:test.jpg]]") data = wiki.to_html assert data.include?("/images/test.jpg") end test "wiki table attributes without quotes" do wiki = WikiParser.new(:data => "{| width=\"95%\" !colspan=2 style=\"background-color:#ffebac;\"|Heading |- |hello||world |}") data = wiki.to_html assert data.include?("" when "tableend" " test