moredown 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +52 -0
- data/README.markdown +109 -0
- data/Rakefile +121 -0
- data/VERSION +1 -0
- data/bin/rdiscount +5 -0
- data/ext/Csio.c +49 -0
- data/ext/amalloc.h +29 -0
- data/ext/config.h +9 -0
- data/ext/cstring.h +73 -0
- data/ext/docheader.c +43 -0
- data/ext/dumptree.c +147 -0
- data/ext/extconf.rb +8 -0
- data/ext/generate.c +1389 -0
- data/ext/markdown.c +962 -0
- data/ext/markdown.h +135 -0
- data/ext/mkdio.c +241 -0
- data/ext/mkdio.h +66 -0
- data/ext/rdiscount.c +92 -0
- data/ext/resource.c +169 -0
- data/ext/toc.c +86 -0
- data/lib/markdown.rb +1 -0
- data/lib/moredown.rb +153 -0
- data/lib/rdiscount.rb +72 -0
- data/moredown.gemspec +73 -0
- data/test/benchmark.rb +56 -0
- data/test/benchmark.txt +306 -0
- data/test/markdown_test.rb +119 -0
- data/test/moredown_test.rb +172 -0
- data/test/rdiscount_test.rb +43 -0
- metadata +88 -0
data/ext/resource.c
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
/* markdown: a C implementation of John Gruber's Markdown markup language.
|
2
|
+
*
|
3
|
+
* Copyright (C) 2007 David L Parsons.
|
4
|
+
* The redistribution terms are provided in the COPYRIGHT file that must
|
5
|
+
* be distributed with this source code.
|
6
|
+
*/
|
7
|
+
#include <stdio.h>
|
8
|
+
#include <string.h>
|
9
|
+
#include <stdarg.h>
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include <time.h>
|
12
|
+
#include <ctype.h>
|
13
|
+
|
14
|
+
#include "config.h"
|
15
|
+
|
16
|
+
#include "cstring.h"
|
17
|
+
#include "markdown.h"
|
18
|
+
#include "amalloc.h"
|
19
|
+
|
20
|
+
/* free a (single) line
|
21
|
+
*/
|
22
|
+
void
|
23
|
+
___mkd_freeLine(Line *ptr)
|
24
|
+
{
|
25
|
+
DELETE(ptr->text);
|
26
|
+
free(ptr);
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
/* free a list of lines
|
31
|
+
*/
|
32
|
+
void
|
33
|
+
___mkd_freeLines(Line *p)
|
34
|
+
{
|
35
|
+
if (p->next)
|
36
|
+
___mkd_freeLines(p->next);
|
37
|
+
___mkd_freeLine(p);
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
/* bye bye paragraph.
|
42
|
+
*/
|
43
|
+
void
|
44
|
+
___mkd_freeParagraph(Paragraph *p)
|
45
|
+
{
|
46
|
+
if (p->next)
|
47
|
+
___mkd_freeParagraph(p->next);
|
48
|
+
if (p->down)
|
49
|
+
___mkd_freeParagraph(p->down);
|
50
|
+
if (p->text)
|
51
|
+
___mkd_freeLines(p->text);
|
52
|
+
if (p->ident)
|
53
|
+
free(p->ident);
|
54
|
+
free(p);
|
55
|
+
}
|
56
|
+
|
57
|
+
|
58
|
+
/* bye bye footnotes.
|
59
|
+
*/
|
60
|
+
void
|
61
|
+
___mkd_freefootnotes(MMIOT *f)
|
62
|
+
{
|
63
|
+
int i;
|
64
|
+
|
65
|
+
if ( f->footnotes ) {
|
66
|
+
for (i=0; i < S(*f->footnotes); i++) {
|
67
|
+
DELETE(T(*f->footnotes)[i].tag);
|
68
|
+
DELETE(T(*f->footnotes)[i].link);
|
69
|
+
DELETE(T(*f->footnotes)[i].title);
|
70
|
+
}
|
71
|
+
DELETE(*f->footnotes);
|
72
|
+
free(f->footnotes);
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
|
77
|
+
/* initialize a new MMIOT
|
78
|
+
*/
|
79
|
+
void
|
80
|
+
___mkd_initmmiot(MMIOT *f, void *footnotes)
|
81
|
+
{
|
82
|
+
if ( f ) {
|
83
|
+
memset(f, 0, sizeof *f);
|
84
|
+
CREATE(f->in);
|
85
|
+
CREATE(f->out);
|
86
|
+
CREATE(f->Q);
|
87
|
+
if ( footnotes )
|
88
|
+
f->footnotes = footnotes;
|
89
|
+
else {
|
90
|
+
f->footnotes = malloc(sizeof f->footnotes[0]);
|
91
|
+
CREATE(*f->footnotes);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
|
97
|
+
/* free the contents of a MMIOT, but leave the object alone.
|
98
|
+
*/
|
99
|
+
void
|
100
|
+
___mkd_freemmiot(MMIOT *f, void *footnotes)
|
101
|
+
{
|
102
|
+
if ( f ) {
|
103
|
+
DELETE(f->in);
|
104
|
+
DELETE(f->out);
|
105
|
+
DELETE(f->Q);
|
106
|
+
if ( f->footnotes != footnotes )
|
107
|
+
___mkd_freefootnotes(f);
|
108
|
+
memset(f, 0, sizeof *f);
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
|
113
|
+
/* free lines up to an barrier.
|
114
|
+
*/
|
115
|
+
void
|
116
|
+
___mkd_freeLineRange(Line *anchor, Line *stop)
|
117
|
+
{
|
118
|
+
Line *r = anchor->next;
|
119
|
+
|
120
|
+
if ( r != stop ) {
|
121
|
+
while ( r && (r->next != stop) )
|
122
|
+
r = r->next;
|
123
|
+
if ( r ) r->next = 0;
|
124
|
+
___mkd_freeLines(anchor->next);
|
125
|
+
}
|
126
|
+
anchor->next = 0;
|
127
|
+
}
|
128
|
+
|
129
|
+
|
130
|
+
/* clean up everything allocated in __mkd_compile()
|
131
|
+
*/
|
132
|
+
void
|
133
|
+
mkd_cleanup(Document *doc)
|
134
|
+
{
|
135
|
+
if ( doc ) {
|
136
|
+
if ( doc->ctx ) {
|
137
|
+
___mkd_freemmiot(doc->ctx, 0);
|
138
|
+
free(doc->ctx);
|
139
|
+
}
|
140
|
+
|
141
|
+
if ( doc->code) ___mkd_freeParagraph(doc->code);
|
142
|
+
if ( doc->headers ) ___mkd_freeLines(doc->headers);
|
143
|
+
if ( T(doc->content) ) ___mkd_freeLines(T(doc->content));
|
144
|
+
memset(doc, 0, sizeof doc[0]);
|
145
|
+
free(doc);
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
|
150
|
+
/* write output in XML format
|
151
|
+
*/
|
152
|
+
void
|
153
|
+
___mkd_xml(char *p, int size, FILE *out)
|
154
|
+
{
|
155
|
+
char c;
|
156
|
+
|
157
|
+
while ( size-- > 0 ) {
|
158
|
+
if ( !isascii(c = *p++) )
|
159
|
+
continue;
|
160
|
+
switch (c) {
|
161
|
+
case '<': fputs("<", out); break;
|
162
|
+
case '>': fputs(">", out); break;
|
163
|
+
case '&': fputs("&", out); break;
|
164
|
+
case '"': fputs(""", out); break;
|
165
|
+
case '\'':fputs("'", out); break;
|
166
|
+
default: putc(c,out); break;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
}
|
data/ext/toc.c
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
/*
|
2
|
+
* toc -- spit out a table of contents based on header blocks
|
3
|
+
*
|
4
|
+
* Copyright (C) 2008 Jjgod Jiang, David L Parsons.
|
5
|
+
* The redistribution terms are provided in the COPYRIGHT file that must
|
6
|
+
* be distributed with this source code.
|
7
|
+
*/
|
8
|
+
#include "config.h"
|
9
|
+
#include <stdio.h>
|
10
|
+
#include <stdlib.h>
|
11
|
+
#include <ctype.h>
|
12
|
+
|
13
|
+
#include "cstring.h"
|
14
|
+
#include "markdown.h"
|
15
|
+
#include "amalloc.h"
|
16
|
+
|
17
|
+
/* write an header index
|
18
|
+
*/
|
19
|
+
int
|
20
|
+
mkd_toc(Document *p, char **doc)
|
21
|
+
{
|
22
|
+
Paragraph *pp;
|
23
|
+
int last_hnumber = 0;
|
24
|
+
Cstring res;
|
25
|
+
|
26
|
+
CREATE(res);
|
27
|
+
RESERVE(res, 100);
|
28
|
+
|
29
|
+
*doc = 0;
|
30
|
+
|
31
|
+
if ( !(p && p->ctx) ) return -1;
|
32
|
+
if ( ! (p->ctx->flags & TOC) ) return 0;
|
33
|
+
|
34
|
+
for ( pp = p->code; pp ; pp = pp->next ) {
|
35
|
+
if ( pp->typ == HDR && pp->text ) {
|
36
|
+
|
37
|
+
if ( last_hnumber == pp->hnumber )
|
38
|
+
Csprintf(&res, "%*s</li>\n", pp->hnumber, "");
|
39
|
+
else while ( last_hnumber > pp->hnumber ) {
|
40
|
+
Csprintf(&res, "%*s</li>\n%*s</ul>\n",
|
41
|
+
last_hnumber, "",
|
42
|
+
last_hnumber-1,"");
|
43
|
+
--last_hnumber;
|
44
|
+
}
|
45
|
+
|
46
|
+
while ( pp->hnumber > last_hnumber ) {
|
47
|
+
Csprintf(&res, "\n%*s<ul>\n", pp->hnumber, "");
|
48
|
+
++last_hnumber;
|
49
|
+
}
|
50
|
+
Csprintf(&res, "%*s<li><a href=\"#", pp->hnumber, "");
|
51
|
+
mkd_string_to_anchor(T(pp->text->text), S(pp->text->text), Csputc, &res);
|
52
|
+
Csprintf(&res, "\">");
|
53
|
+
Csreparse(&res, T(pp->text->text), S(pp->text->text), 0);
|
54
|
+
Csprintf(&res, "</a>");
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
while ( last_hnumber > 0 ) {
|
59
|
+
Csprintf(&res, "%*s</li>\n%*s</ul>\n",
|
60
|
+
last_hnumber, "", last_hnumber, "");
|
61
|
+
--last_hnumber;
|
62
|
+
}
|
63
|
+
/* HACK ALERT! HACK ALERT! HACK ALERT! */
|
64
|
+
*doc = T(res); /* we know that a T(Cstring) is a character pointer */
|
65
|
+
/* so we can simply pick it up and carry it away, */
|
66
|
+
return S(res); /* leaving the husk of the Ctring on the stack */
|
67
|
+
/* END HACK ALERT */
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
/* write an header index
|
72
|
+
*/
|
73
|
+
int
|
74
|
+
mkd_generatetoc(Document *p, FILE *out)
|
75
|
+
{
|
76
|
+
char *buf = 0;
|
77
|
+
int sz = mkd_toc(p, &buf);
|
78
|
+
int ret = EOF;
|
79
|
+
|
80
|
+
if ( sz > 0 )
|
81
|
+
ret = fwrite(buf, sz, 1, out);
|
82
|
+
|
83
|
+
if ( buf ) free(buf);
|
84
|
+
|
85
|
+
return ret;
|
86
|
+
}
|
data/lib/markdown.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rdiscount'
|
data/lib/moredown.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
require 'rdiscount'
|
2
|
+
|
3
|
+
class Moredown < RDiscount
|
4
|
+
VERSION = '1.0.4'
|
5
|
+
|
6
|
+
# Don't use inline CSS for styling
|
7
|
+
attr_accessor :has_stylesheet
|
8
|
+
|
9
|
+
# Process emoticons
|
10
|
+
attr_accessor :emotes
|
11
|
+
|
12
|
+
# Map any relative URLs in the text to absolute URLs
|
13
|
+
attr_accessor :base_url
|
14
|
+
|
15
|
+
# Map headings down a few ranks (eg. :map_headings => 2 would convert h1 to h3)
|
16
|
+
attr_accessor :map_headings
|
17
|
+
|
18
|
+
# Use SwfObject2 if available (eg. :swfobject => { :src => 'swfobject.js', :version => '10', :fallback => 'No Flash' })
|
19
|
+
attr_accessor :swfobject
|
20
|
+
|
21
|
+
# Create a Moredown Markdown processor. The +text+ argument
|
22
|
+
# should be a string containing Markdown text. Additional arguments may be
|
23
|
+
# supplied to set various processing options:
|
24
|
+
#
|
25
|
+
# * <tt>:extensions</tt> - Any of the following RDiscount Extensions:
|
26
|
+
# * <tt>:smart</tt> - Enable SmartyPants processing.
|
27
|
+
# * <tt>:filter_styles</tt> - Do not output <tt><style></tt> tags.
|
28
|
+
# * <tt>:filter_html</tt> - Do not output any raw HTML tags included in
|
29
|
+
# the source text.
|
30
|
+
# * <tt>:fold_lines</tt> - RedCloth compatible line folding (not used).
|
31
|
+
# * <tt>:has_stylesheet</tt> - Don't use inline CSS for styling.
|
32
|
+
# * <tt>:emotes</tt> - Process emoticons.
|
33
|
+
# * <tt>:base_url</tt> - Map any relative URLs in the text to absolute URLs.
|
34
|
+
# * <tt>:map_headings</tt> - Map any headings down a few ranks (eg. h1 => h3).
|
35
|
+
# * <tt>:swfobject</tt> - Use SwfObject2 if available (eg. :swfobject => { :src => 'swfobject.js', :version => '10', :fallback => 'No Flash' })
|
36
|
+
#
|
37
|
+
# NOTE: The <tt>:filter_styles</tt> extension is not yet implemented.
|
38
|
+
def initialize text, args = {}
|
39
|
+
@has_stylesheet = args[:has_stylesheet]
|
40
|
+
@emotes = args[:emotes]
|
41
|
+
@base_url = args[:base_url]
|
42
|
+
@map_headings = args[:map_headings] || 0
|
43
|
+
@swfobject = args[:swfobject]
|
44
|
+
|
45
|
+
# each swfobject needs a unique id
|
46
|
+
@next_flash_id = 0
|
47
|
+
|
48
|
+
if args[:extensions]
|
49
|
+
super(text, args[:extensions])
|
50
|
+
else
|
51
|
+
super(text)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_html
|
56
|
+
html = super
|
57
|
+
|
58
|
+
# flash movies (including youtube)
|
59
|
+
html.gsub!(/<img src="(flash|youtube):(.*?)"\s?(?:title="(.*?)")? alt="(.*)" \/>/) do |match|
|
60
|
+
# grab width and height
|
61
|
+
if $3
|
62
|
+
sizes = $3.split(' ')
|
63
|
+
sizes = { :width => sizes[0], :height => sizes[1] }
|
64
|
+
else
|
65
|
+
sizes = {}
|
66
|
+
end
|
67
|
+
|
68
|
+
# check the source
|
69
|
+
if $1.downcase == "youtube"
|
70
|
+
url = "http://www.youtube.com/v/#{$2}"
|
71
|
+
sizes = { :width => 425, :height => 350 }.merge sizes
|
72
|
+
else
|
73
|
+
url = $2
|
74
|
+
end
|
75
|
+
|
76
|
+
flash_tag url, sizes
|
77
|
+
end
|
78
|
+
|
79
|
+
# image alignments
|
80
|
+
if @has_stylesheet
|
81
|
+
html.gsub!(/<img (.*?) \/>:(left|right|center)/) { |match| "<img class=\"#{$2}\" #{$1} />" }
|
82
|
+
else
|
83
|
+
html.gsub!(/<img (.*?) \/>:left/) { |match| "<img style=\"float: left; margin: 0 10px 10px 0;\" #{$1} />" }
|
84
|
+
html.gsub!(/<img (.*?) \/>:right/) { |match| "<img style=\"float: right; margin: 0 0 10px 10px;\" #{$1} />" }
|
85
|
+
html.gsub!(/<img (.*?) \/>:center/) { |match| "<img style=\"display: block; margin: auto;\" #{$1} />" }
|
86
|
+
end
|
87
|
+
|
88
|
+
# code
|
89
|
+
html.gsub!('<pre>', '<pre class="prettyprint">')
|
90
|
+
|
91
|
+
# emoticons
|
92
|
+
if @emotes
|
93
|
+
html.gsub!(':-)', '<img src="/images/emote-smile.png" alt=":-)" width="16" height="16" />')
|
94
|
+
html.gsub!(':-P', '<img src="/images/emote-tongue.png" alt=":-P" width="16" height="16" />')
|
95
|
+
html.gsub!(':-D', '<img src="/images/emote-grin.png" alt=":-D" width="16" height="16" />')
|
96
|
+
html.gsub!(':-(', '<img src="/images/emote-sad.png" alt=":-(" width="16" height="16" />')
|
97
|
+
html.gsub!(':-@', '<img src="/images/emote-angry.png" alt=":-@" width="16" height="16" />')
|
98
|
+
html.gsub!(';-)', '<img src="/images/emote-wink.png" alt=";-)" width="16" height="16" />')
|
99
|
+
end
|
100
|
+
|
101
|
+
# remap relative urls
|
102
|
+
if @base_url
|
103
|
+
html.gsub!('"/images/', "\"#{@base_url}/images/")
|
104
|
+
html.gsub!('<a href="/', "<a href=\"#{@base_url}/")
|
105
|
+
end
|
106
|
+
|
107
|
+
# remap headings down a few notches
|
108
|
+
if @map_headings > 0
|
109
|
+
html.gsub!(/<(\/)?h(\d)>/) { |match| "<#{$1}h#{$2.to_i + @map_headings}>" }
|
110
|
+
end
|
111
|
+
|
112
|
+
# add the js for swfobject
|
113
|
+
if @swfobject
|
114
|
+
swfobjects = []
|
115
|
+
1.upto(@next_flash_id).each do |n|
|
116
|
+
swfobjects << "swfobject.registerObject(\"swf-#{n}\", \"#{@swfobject[:version]}\");\n"
|
117
|
+
end
|
118
|
+
|
119
|
+
# html seems to need to go after the swfobject javascript
|
120
|
+
html = "<script type=\"text/javascript\" src=\"#{@swfobject[:src]}\"></script><script type=\"text/javascript\">\n/*<![CDATA[*/\n#{swfobjects}/*]]>*/\n</script>\n#{html}"
|
121
|
+
end
|
122
|
+
|
123
|
+
html
|
124
|
+
end
|
125
|
+
|
126
|
+
# Process some text in Markdown format
|
127
|
+
def self.text_to_html text, args = {}
|
128
|
+
Moredown.new(text, args).to_html
|
129
|
+
end
|
130
|
+
|
131
|
+
|
132
|
+
protected
|
133
|
+
def flash_tag url, args = {}
|
134
|
+
args = {:width => 400, :height => 300, :fallback => 'Flash is not available.'}.merge args
|
135
|
+
|
136
|
+
if url.include? 'youtube.com'
|
137
|
+
fallback = "<a href=\"#{url}\"><img src=\"http://img.youtube.com/vi/#{url.split('/').last}/default.jpg\" alt=\"\" /></a>"
|
138
|
+
elsif @swfobject
|
139
|
+
fallback = @swfobject[:fallback]
|
140
|
+
else
|
141
|
+
fallback = args[:fallback]
|
142
|
+
end
|
143
|
+
|
144
|
+
return "<object id=\"swf-#{@next_flash_id += 1}\" classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" width=\"#{args[:width]}\" height=\"#{args[:height]}\">" \
|
145
|
+
+"<param name=\"movie\" value=\"#{url}\" />" \
|
146
|
+
+"<!--[if !IE]>-->" \
|
147
|
+
+"<object type=\"application/x-shockwave-flash\" data=\"#{url}\" width=\"#{args[:width]}\" height=\"#{args[:height]}\">" \
|
148
|
+
+"<!--<![endif]-->#{fallback}<!--[if !IE]>-->" \
|
149
|
+
+"</object>" \
|
150
|
+
+"<!--<![endif]-->" \
|
151
|
+
+"</object>"
|
152
|
+
end
|
153
|
+
end
|
data/lib/rdiscount.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Discount is an implementation of John Gruber's Markdown markup
|
2
|
+
# language in C. It implements all of the language as described in
|
3
|
+
# {Markdown Syntax}[http://daringfireball.net/projects/markdown/syntax]
|
4
|
+
# and passes the Markdown 1.0 test suite. The RDiscount extension makes
|
5
|
+
# the Discount processor available via a Ruby C Extension library.
|
6
|
+
#
|
7
|
+
# === Usage
|
8
|
+
#
|
9
|
+
# RDiscount implements the basic protocol popularized by RedCloth and adopted
|
10
|
+
# by BlueCloth:
|
11
|
+
# require 'rdiscount'
|
12
|
+
# markdown = RDiscount.new("Hello World!")
|
13
|
+
# puts markdown.to_html
|
14
|
+
#
|
15
|
+
# === Replacing BlueCloth
|
16
|
+
#
|
17
|
+
# Inject RDiscount into your BlueCloth-using code by replacing your bluecloth
|
18
|
+
# require statements with the following:
|
19
|
+
# begin
|
20
|
+
# require 'rdiscount'
|
21
|
+
# BlueCloth = RDiscount
|
22
|
+
# rescue LoadError
|
23
|
+
# require 'bluecloth'
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
class RDiscount
|
27
|
+
VERSION = '1.3.5'
|
28
|
+
|
29
|
+
# Original Markdown formatted text.
|
30
|
+
attr_reader :text
|
31
|
+
|
32
|
+
# Set true to have smarty-like quote translation performed.
|
33
|
+
attr_accessor :smart
|
34
|
+
|
35
|
+
# Do not output <style> tags included in the source text.
|
36
|
+
attr_accessor :filter_styles
|
37
|
+
|
38
|
+
# Do not output any raw HTML included in the source text.
|
39
|
+
attr_accessor :filter_html
|
40
|
+
|
41
|
+
# RedCloth compatible line folding -- not used for Markdown but
|
42
|
+
# included for compatibility.
|
43
|
+
attr_accessor :fold_lines
|
44
|
+
|
45
|
+
# Enable Table Of Contents generation
|
46
|
+
attr_accessor :generate_toc
|
47
|
+
|
48
|
+
# Create a RDiscount Markdown processor. The +text+ argument
|
49
|
+
# should be a string containing Markdown text. Additional arguments may be
|
50
|
+
# supplied to set various processing options:
|
51
|
+
#
|
52
|
+
# * <tt>:smart</tt> - Enable SmartyPants processing.
|
53
|
+
# * <tt>:filter_styles</tt> - Do not output <tt><style></tt> tags.
|
54
|
+
# * <tt>:filter_html</tt> - Do not output any raw HTML tags included in
|
55
|
+
# the source text.
|
56
|
+
# * <tt>:fold_lines</tt> - RedCloth compatible line folding (not used).
|
57
|
+
#
|
58
|
+
# NOTE: The <tt>:filter_styles</tt> extension is not yet implemented.
|
59
|
+
def initialize(text, *extensions)
|
60
|
+
@text = text
|
61
|
+
@smart = nil
|
62
|
+
@filter_styles = nil
|
63
|
+
@filter_html = nil
|
64
|
+
@fold_lines = nil
|
65
|
+
extensions.each { |e| send("#{e}=", true) }
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
Markdown = RDiscount unless defined? Markdown
|
71
|
+
|
72
|
+
require 'rdiscount.so'
|