redcarpet 1.17.2 → 2.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/README.markdown CHANGED
@@ -1,61 +1,318 @@
1
- Ruby + Upskirt = Markdown that doesn't suck
2
- ===========================================
1
+ Redcarpet 2 is written with sugar, spice and everything nice
2
+ ============================================================
3
3
 
4
- Redcarpet is a Ruby wrapper for Upskirt. It is mostly based on Ryan
5
- Tomayko's RDiscount wrapper, and inspired by Rick Astley wearing a kilt.
4
+ Redcarpet is Ruby library for Markdown processing that smells like
5
+ butterflies and popcorn.
6
6
 
7
- Redcarpet is powered by the Upskirt library, which can be found at
7
+ Redcarpet used to be a drop-in replacement for Redcloth. This is no longer the
8
+ case since version 2 -- it now has its own API, but retains the old name. Yes,
9
+ that does mean that Redcarpet 2 is not backwards-compatible with the 1.X
10
+ versions.
8
11
 
9
- https://www.github.com/tanoku/upskirt
12
+ Redcarpet is powered by the Sundown library, which can be found at
10
13
 
11
- You might want to find out more about Upskirt to see what makes these Ruby
12
- bindings so awesome.
14
+ https://www.github.com/tanoku/sundown
13
15
 
14
- Credits
15
- -------
16
+ You might want to find out more about Sundown to see what makes this Ruby
17
+ library so awesome.
16
18
 
17
- * Natacha Porté, lady of Markdown
18
- * Vicent Martí, wannabe
19
- * With special thanks to Ryan Tomayko
19
+ This library is written by people
20
+ -------------------------------------------------------
20
21
 
21
- Install
22
- -------
22
+ Redcarpet 2 has been rewritten from scratch by Vicent Martí (@tanoku). Why
23
+ are you not following me on Twitter?
23
24
 
24
- Redcarpet is readily available as a Ruby gem:
25
+ Redcarpet would not be possible without the Sundown library and its authors
26
+ (Natacha Porté, Vicent Martí, and its many awesome contributors).
27
+
28
+ You can totally install it as a Gem
29
+ -----------------------------------
30
+
31
+ Redcarpet is readily available as a Ruby gem. It will build some native
32
+ extensions, but the parser is standalone and requires no installed libraries.
25
33
 
26
34
  $ [sudo] gem install redcarpet
27
35
 
28
- The Redcarpet source (including Upskirt as a submodule) is available at GitHub:
36
+ The Redcarpet source (including Sundown as a submodule) is available at GitHub:
29
37
 
30
38
  $ git clone git://github.com/tanoku/redcarpet.git
31
39
 
32
- Usage
33
- -----
40
+ And it's like *really* simple to use
41
+ ------------------------------------
42
+
43
+ The core of the Redcarpet library is the `Redcarpet::Markdown` class. Each
44
+ instance of the class is attached to a `Renderer` object; the Markdown class
45
+ performs parsing of a document and uses the attached renderer to generate
46
+ output.
47
+
48
+ The `Markdown` object is encouraged to be instantiated once with the required
49
+ settings, and reused between parses.
50
+
51
+ Markdown.new(renderer, extensions={})
52
+
53
+ Initializes a Markdown parser
54
+
55
+ renderer - a renderer object, inheriting from Redcarpet::Render::Base.
56
+ If the given object has not been instantiated, the library
57
+ will do it with default arguments.
58
+
59
+ extensions - a hash containing the Markdown extensions which the parser
60
+ will identify. The following extensions are accepted:
61
+
62
+ :no_intra_emphasis - do not parse emphasis inside of words.
63
+ Strings such as `foo_bar_baz` will not generate `<em>`
64
+ tags.
65
+
66
+ :tables - parse tables, PHP-Markdown style
67
+
68
+ :fenced_code_blocks - parse fenced code blocks, PHP-Markdown
69
+ style .Blocks delimited with 3 or more `~` or backticks
70
+ will be considered as code, without the need to be
71
+ indented. An optional language name may be added at the
72
+ end of the opening fence for the code block
73
+
74
+ :autolink - parse links even when they are not enclosed in
75
+ `<>` characters. Autolinks for the http, https and ftp
76
+ protocols will be automatically detected. Email addresses
77
+ are also handled, and http links without protocol, but
78
+ starting with `www.`
79
+
80
+ :strikethrough - parse strikethrough, PHP-Markdown style
81
+ Two `~` characters mark the start of a strikethrough,
82
+ e.g. `this is ~~good~~ bad`
83
+
84
+ :lax_html_blocks - HTML blocks do not require to be surrounded
85
+ by an empty line as in the Markdown standard.
86
+
87
+ :space_after_headers - A space is always required between the
88
+ hash at the beginning of a header and its name, e.g.
89
+ `#this is my header` would not be a valid header.
90
+
91
+ :superscript - parse superscripts after the `^` character;
92
+ contiguous superscripts are nested together, and complex
93
+ values can be enclosed in parenthesis,
94
+ e.g. `this is the 2^(nd) time`
95
+
96
+ Example:
97
+
98
+ markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML,
99
+ :autolink => true, :space_after_headers => true)
100
+
101
+ Rendering with the `Markdown` object is done through `Markdown#render`.
102
+ Unlike in the RedCloth API, the text to render is passed as an argument
103
+ and not stored inside the `Markdown` instance, to encourage reusability.
104
+
105
+ Markdown.render(text)
106
+
107
+ Render a Markdown document with the attached renderer
108
+
109
+ text - a Markdown document
110
+
111
+ Example:
112
+
113
+ markdown.render("This is *bongos*, indeed.")
114
+ #=> "<p>This is <em>bongos</em>, indeed</p>"
115
+
116
+
117
+ Darling, I packed you a couple renderers for lunch
118
+ --------------------------------------------------
119
+
120
+ Redcarpet comes with two built-in renderers, `Redcarpet::Render::HTML` and
121
+ `Redcarpet::Render::XHTML`, which output HTML and XHTML, respectively. These
122
+ renderers are actually implemented in C, and hence offer a brilliant
123
+ performance, several degrees of magnitude faster than other Ruby Markdown
124
+ solutions.
125
+
126
+ All the rendering flags that previously applied only to HTML output have
127
+ now been moved to the `Render::HTML` class, and may be enabled when
128
+ instantiating the renderer:
129
+
130
+ Render::HTML.new(render_options={})
131
+
132
+ Initializes an HTML renderer. The following flags are available:
133
+
134
+ :filter_html - do not allow any user-inputted HTML in the output
135
+
136
+ :no_images - do not generate any `<img>` tags
137
+
138
+ :no_links - do not generate any `<a>` tags
139
+
140
+ :no_styles - do not generate any `<style>` tags
141
+
142
+ :safe_links_only - only generate links for protocols which are considered safe
143
+
144
+ :with_toc_data - add HTML anchors to each header in the output HTML,
145
+ to allow linking to each section.
146
+
147
+ :hard_wrap - insert HTML `<br>` tags inside on paragraphs where the origin
148
+ Markdown document had newlines (by default, Markdown ignores these
149
+ newlines).
150
+
151
+ :xhtml - output XHTML-conformant tags. This option is always enabled in the
152
+ `Render::XHTML` renderer.
153
+
154
+
155
+ Example:
156
+
157
+ rndr = Redcarpet::Render::HTML.new(:no_links => true, :hard_wrap => true)
158
+
159
+
160
+ The `HTML` renderer has an alternate version, `Redcarpet::Render::HTML_TOC`,
161
+ which will output a table of contents in HTML based on the headers of the
162
+ Markdown document.
163
+
164
+ Furthermore, the abstract base class `Redcarpet::Render::Base` can be used
165
+ to write a custom renderer purely in Ruby, or extending an existing renderer.
166
+ See the following section for more information.
167
+
168
+
169
+ And you can even cook your own
170
+ ------------------------------
171
+
172
+ Custom renderers are created by inheriting from an existing renderer. The
173
+ built-in renderers, `HTML` and `XHTML` may be extended as such:
174
+
175
+ ~~~~~ ruby
176
+ # create a custom renderer that allows highlighting of code blocks
177
+ class HTMLwithAlbino < Redcarpet::Render::HTML
178
+ def block_code(code, language)
179
+ Albino.safe_colorize(code, language)
180
+ end
181
+ end
182
+
183
+ markdown = Redcarpet::Markdown.new(HTMLwithAlbino, :fenced_code_blocks => true)
184
+ ~~~~~
185
+
186
+ But new renderers can also be created from scratch (see `lib/render_man.rb` for
187
+ an example implementation of a Manpage renderer)
188
+
189
+ ~~~~~~ ruby
190
+ class ManPage < Redcarpet::Render::Base
191
+ # you get the drill -- keep going from here
192
+ end
193
+ ~~~~~
194
+
195
+ The following instance methods may be implemented by the renderer:
196
+
197
+ # Block-level calls
198
+ # If the return value of the method is `nil`, the block
199
+ # will be skipped.
200
+ # If the method for a document element is not implemented,
201
+ # the block will be skipped.
202
+ #
203
+ # Example:
204
+ #
205
+ # class RenderWithoutCode < Redcarpet::Render::HTML
206
+ # def block_code(code, language)
207
+ # nil
208
+ # end
209
+ # end
210
+ #
211
+ block_code(code, language)
212
+ block_quote(quote)
213
+ block_html(raw_html)
214
+ header(text, header_level)
215
+ hrule()
216
+ list(contents, list_type)
217
+ list_item(text, list_type)
218
+ paragraph(text)
219
+ table(header, body)
220
+ table_row(content)
221
+ table_cell(content, alignment)
222
+
223
+ # Span-level calls
224
+ # A return value of `nil` will not output any data
225
+ # If the method for a document element is not implemented,
226
+ # the contents of the span will be copied verbatim
227
+ autolink(link, link_type)
228
+ codespan(code)
229
+ double_emphasis(text)
230
+ emphasis(text)
231
+ image(link, title, alt_text)
232
+ linebreak()
233
+ link(link, title, content)
234
+ raw_html(raw_html)
235
+ triple_emphasis(text)
236
+ strikethrough(text)
237
+ superscript(text)
238
+
239
+ # Low level rendering
240
+ entity(text)
241
+ normal_text(text)
242
+
243
+ # Header of the document
244
+ # Rendered before any another elements
245
+ doc_header()
246
+
247
+ # Footer of the document
248
+ # Rendered after all the other elements
249
+ doc_footer()
250
+
251
+ # Pre/post-process
252
+ # Special callback: preprocess or postprocess the whole
253
+ # document before or after the rendering process begins
254
+ preprocess(full_document)
255
+ postprocess(full_document)
256
+
257
+
258
+ Also, now our Pants are much smarter
259
+ ------------------------------------
260
+
261
+ Redcarpet 2 comes with a standalone [SmartyPants](
262
+ http://daringfireball.net/projects/smartypants/) implementation. It is fully
263
+ compliant with the original implementation. It is the fastest SmartyPants
264
+ parser there is, with a difference of several orders of magnitude.
265
+
266
+ The SmartyPants parser can be found in `Redcarpet::Render::SmartyPants`. It has
267
+ been implemented as a module, so it can be used standalone or as a mixin.
268
+
269
+ When mixed with a Renderer class, it will override the `postprocess` method
270
+ to perform SmartyPants replacements once the rendering is complete
271
+
272
+ ~~~~ ruby
273
+ # Mixin
274
+ class HTMLWithPants < Redcarpet::Render::HTML
275
+ include Redcarpet::Render::SmartyPants
276
+ end
277
+
278
+ # Standalone
279
+ Redcarpet::Render::SmartyPants.render("<p>Oh SmartyPants, you're so crazy...</p>")
280
+ ~~~~~
281
+
282
+ SmartyPants works on top of already-rendered HTML, and will ignore replacements
283
+ inside the content of HTML tags and inside specific HTML blocks such as
284
+ `<code>` or `<pre>`.
285
+
286
+ What? You really want to mix Markdown renderers?
287
+ ------------------------------------------------
288
+
289
+ What a terrible idea! Markdown is already ill-specified enough; if you create
290
+ software that is renderer-independent, the results will be completely unreliable!
291
+
292
+ Each renderer has its own API and its own set of extensions: you should choose one
293
+ (it doesn't have to be Redcarpet, though that would be great!), write your
294
+ software accordingly, and force your users to install it. That's the
295
+ only way to have reliable and predictable Markdown output on your program.
34
296
 
35
- Redcarpet implements the basic protocol popularized by RedCloth:
297
+ Still, if major forces (let's say, tornadoes or other natural disasters) force you
298
+ to keep a Markdown-compatibility later, Redcarpet also supports this:
36
299
 
37
- ~~~~~~ {ruby}
38
- require 'redcarpet'
39
- markdown = Redcarpet.new("Hello World!")
40
- puts markdown.to_html
41
- ~~~~~~
300
+ require 'redcarpet/compat'
42
301
 
43
- [Additional processing options](http://rdoc.info/github/tanoku/redcarpet/master/Redcarpet#autolink-instance_method) can be turned on when creating the
44
- Redcarpet object:
302
+ Requiring the compatibility library will declare a `Markdown` class with the
303
+ classical RedCloth API, e.g.
45
304
 
46
- ~~~~~~ {ruby}
47
- markdown = Redcarpet.new("Hello World!", :smart, :filter_html)
48
- ~~~~~~
305
+ Markdown.new('this is my text').to_html
49
306
 
50
- Note that by default, Redcarpet parses standard Markdown (with no extensions)
51
- and offers a sane subset of parse options which allow you to modify the rendering
52
- output and to enable MD extensions on a per-case basis.
307
+ This class renders 100% standards compliant Markdown with 0 extensions. Nada.
308
+ Don't even try to enable extensions with a compatibility layer, because
309
+ that's a maintance nightmare and won't work.
53
310
 
54
- Redcarpet also offers a wrapper class, `RedcarpetCompat` with the same flags
55
- and behavior as the RDiscount library, which acts as a drop-in replacement.
311
+ On a related topic: if your Markdown gem has a `lib/markdown.rb` file that
312
+ monkeypatches the Markdown class, you're a terrible human being. Just saying.
56
313
 
57
- License
58
- -------
314
+ Boring legal stuff
315
+ ------------------
59
316
 
60
317
  Copyright (c) 2011, Vicent Martí
61
318
 
data/Rakefile CHANGED
@@ -70,9 +70,6 @@ task :install => package('.gem') do
70
70
  sh "gem install #{package('.gem')}"
71
71
  end
72
72
 
73
- desc 'Update the gemspec'
74
- task :update_gem => file('redcarpet.gemspec')
75
-
76
73
  directory 'pkg/'
77
74
 
78
75
  file package('.gem') => %w[pkg/ redcarpet.gemspec] + $spec.files do |f|
@@ -91,9 +88,10 @@ def source_version
91
88
  line.match(/.*VERSION = '(.*)'/)[1]
92
89
  end
93
90
 
94
- file 'redcarpet.gemspec' => FileList['Rakefile','lib/redcarpet.rb'] do |f|
91
+ task :update_gem do
95
92
  # read spec file and split out manifest section
96
- spec = File.read(f.name)
93
+ GEMFILE = 'redcarpet.gemspec'
94
+ spec = File.read(GEMFILE)
97
95
  head, manifest, tail = spec.split(" # = MANIFEST =\n")
98
96
  head.sub!(/\.version = '.*'/, ".version = '#{source_version}'")
99
97
  head.sub!(/\.date = '.*'/, ".date = '#{Date.today.to_s}'")
@@ -107,26 +105,26 @@ file 'redcarpet.gemspec' => FileList['Rakefile','lib/redcarpet.rb'] do |f|
107
105
  # piece file back together and write...
108
106
  manifest = " s.files = %w[\n#{files}\n ]\n"
109
107
  spec = [head,manifest,tail].join(" # = MANIFEST =\n")
110
- File.open(f.name, 'w') { |io| io.write(spec) }
111
- puts "updated #{f.name}"
108
+ File.open(GEMFILE, 'w') { |io| io.write(spec) }
109
+ puts "updated #{GEMFILE}"
112
110
  end
113
111
 
114
- desc 'Gather required Upskirt sources into extension directory'
115
- task :gather => 'upskirt/src/markdown.h' do |t|
112
+ desc 'Gather required Sundown sources into extension directory'
113
+ task :gather => 'sundown/src/markdown.h' do |t|
116
114
  files =
117
115
  FileList[
118
- 'upskirt/src/{markdown,buffer,array,autolink}.h',
119
- 'upskirt/src/{markdown,buffer,array,autolink}.c',
120
- 'upskirt/html/{html,html_smartypants}.c',
121
- 'upskirt/html/html.h',
116
+ 'sundown/src/{markdown,buffer,stack,autolink,html_blocks}.h',
117
+ 'sundown/src/{markdown,buffer,stack,autolink}.c',
118
+ 'sundown/html/{html,html_smartypants,houdini_html_e,houdini_href_e}.c',
119
+ 'sundown/html/{html,houdini}.h',
122
120
  ]
123
121
  cp files, 'ext/redcarpet/',
124
122
  :preserve => true,
125
123
  :verbose => true
126
124
  end
127
125
 
128
- file 'upskirt/src/markdown.h' do |t|
129
- abort "The Upskirt submodule is required."
126
+ file 'sundown/src/markdown.h' do |t|
127
+ abort "The Sundown submodule is required."
130
128
  end
131
129
 
132
130
 
data/bin/redcarpet CHANGED
@@ -10,4 +10,4 @@ if ARGV.include?('--help')
10
10
  end
11
11
 
12
12
  require 'redcarpet'
13
- STDOUT.write(Redcarpet.new(ARGF.read).to_html)
13
+ STDOUT.write(Redcarpet::Markdown.new(Redcarpet::Render::HTML).render(ARGF.read))
@@ -22,11 +22,11 @@
22
22
  #include <ctype.h>
23
23
 
24
24
  int
25
- is_safe_link(const char *link, size_t link_len)
25
+ sd_autolink_issafe(const uint8_t *link, size_t link_len)
26
26
  {
27
- static const size_t valid_uris_count = 4;
27
+ static const size_t valid_uris_count = 5;
28
28
  static const char *valid_uris[] = {
29
- "http://", "https://", "ftp://", "mailto://"
29
+ "/", "http://", "https://", "ftp://", "mailto:"
30
30
  };
31
31
 
32
32
  size_t i;
@@ -35,7 +35,7 @@ is_safe_link(const char *link, size_t link_len)
35
35
  size_t len = strlen(valid_uris[i]);
36
36
 
37
37
  if (link_len > len &&
38
- strncasecmp(link, valid_uris[i], len) == 0 &&
38
+ strncasecmp((char *)link, valid_uris[i], len) == 0 &&
39
39
  isalnum(link[len]))
40
40
  return 1;
41
41
  }
@@ -44,9 +44,9 @@ is_safe_link(const char *link, size_t link_len)
44
44
  }
45
45
 
46
46
  static size_t
47
- autolink_delim(char *data, size_t link_end, size_t offset, size_t size)
47
+ autolink_delim(uint8_t *data, size_t link_end, size_t offset, size_t size)
48
48
  {
49
- char cclose, copen = 0;
49
+ uint8_t cclose, copen = 0;
50
50
  size_t i;
51
51
 
52
52
  for (i = 0; i < link_end; ++i)
@@ -128,7 +128,7 @@ autolink_delim(char *data, size_t link_end, size_t offset, size_t size)
128
128
  }
129
129
 
130
130
  static size_t
131
- check_domain(char *data, size_t size)
131
+ check_domain(uint8_t *data, size_t size)
132
132
  {
133
133
  size_t i, np = 0;
134
134
 
@@ -140,21 +140,20 @@ check_domain(char *data, size_t size)
140
140
  else if (!isalnum(data[i]) && data[i] != '-') break;
141
141
  }
142
142
 
143
- if (!isalnum(data[i - 1]) || np == 0)
144
- return 0;
145
-
146
- return i;
143
+ /* a valid domain needs to have at least a dot.
144
+ * that's as far as we get */
145
+ return np ? i : 0;
147
146
  }
148
147
 
149
148
  size_t
150
- ups_autolink__www(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size)
149
+ sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
151
150
  {
152
151
  size_t link_end;
153
152
 
154
153
  if (offset > 0 && !ispunct(data[-1]) && !isspace(data[-1]))
155
154
  return 0;
156
155
 
157
- if (size < 4 || memcmp(data, "www.", STRLEN("www.")) != 0)
156
+ if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0)
158
157
  return 0;
159
158
 
160
159
  link_end = check_domain(data, size);
@@ -177,13 +176,13 @@ ups_autolink__www(size_t *rewind_p, struct buf *link, char *data, size_t offset,
177
176
  }
178
177
 
179
178
  size_t
180
- ups_autolink__email(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size)
179
+ sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
181
180
  {
182
181
  size_t link_end, rewind;
183
182
  int nb = 0, np = 0;
184
183
 
185
184
  for (rewind = 0; rewind < offset; ++rewind) {
186
- char c = data[-rewind - 1];
185
+ uint8_t c = data[-rewind - 1];
187
186
 
188
187
  if (isalnum(c))
189
188
  continue;
@@ -198,7 +197,7 @@ ups_autolink__email(size_t *rewind_p, struct buf *link, char *data, size_t offse
198
197
  return 0;
199
198
 
200
199
  for (link_end = 0; link_end < size; ++link_end) {
201
- char c = data[link_end];
200
+ uint8_t c = data[link_end];
202
201
 
203
202
  if (isalnum(c))
204
203
  continue;
@@ -226,7 +225,7 @@ ups_autolink__email(size_t *rewind_p, struct buf *link, char *data, size_t offse
226
225
  }
227
226
 
228
227
  size_t
229
- ups_autolink__url(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size)
228
+ sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size)
230
229
  {
231
230
  size_t link_end, rewind = 0, domain_len;
232
231
 
@@ -236,9 +235,9 @@ ups_autolink__url(size_t *rewind_p, struct buf *link, char *data, size_t offset,
236
235
  while (rewind < offset && isalpha(data[-rewind - 1]))
237
236
  rewind++;
238
237
 
239
- if (!is_safe_link(data - rewind, size + rewind))
238
+ if (!sd_autolink_issafe(data - rewind, size + rewind))
240
239
  return 0;
241
- link_end = STRLEN("://");
240
+ link_end = strlen("://");
242
241
 
243
242
  domain_len = check_domain(data + link_end, size - link_end);
244
243
  if (domain_len == 0)
@@ -15,18 +15,21 @@
15
15
  */
16
16
 
17
17
  #ifndef UPSKIRT_AUTOLINK_H
18
- #define UPSKIRT_AUTOLINK_H_H
18
+ #define UPSKIRT_AUTOLINK_H
19
19
 
20
20
  #include "buffer.h"
21
21
 
22
+ extern int
23
+ sd_autolink_issafe(const uint8_t *link, size_t link_len);
24
+
22
25
  extern size_t
23
- ups_autolink__www(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size);
26
+ sd_autolink__www(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);
24
27
 
25
28
  extern size_t
26
- ups_autolink__email(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size);
29
+ sd_autolink__email(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);
27
30
 
28
31
  extern size_t
29
- ups_autolink__url(size_t *rewind_p, struct buf *link, char *data, size_t offset, size_t size);
32
+ sd_autolink__url(size_t *rewind_p, struct buf *link, uint8_t *data, size_t offset, size_t size);
30
33
 
31
34
  #endif
32
35