redcarpet 2.0.0 → 2.1.1

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
@@ -9,12 +9,9 @@ case since version 2 -- it now has its own API, but retains the old name. Yes,
9
9
  that does mean that Redcarpet 2 is not backwards-compatible with the 1.X
10
10
  versions.
11
11
 
12
- Redcarpet is powered by the Sundown library, which can be found at
13
-
14
- https://www.github.com/tanoku/sundown
15
-
16
- You might want to find out more about Sundown to see what makes this Ruby
17
- library so awesome.
12
+ Redcarpet is powered by the [Sundown](https://www.github.com/tanoku/sundown)
13
+ library. You might want to find out more about Sundown to see what makes this
14
+ Ruby library so awesome.
18
15
 
19
16
  This library is written by people
20
17
  -------------------------------------------------------
@@ -66,7 +63,7 @@ settings, and reused between parses.
66
63
  :tables - parse tables, PHP-Markdown style
67
64
 
68
65
  :fenced_code_blocks - parse fenced code blocks, PHP-Markdown
69
- style .Blocks delimited with 3 or more `~` or backticks
66
+ style. Blocks delimited with 3 or more `~` or backticks
70
67
  will be considered as code, without the need to be
71
68
  indented. An optional language name may be added at the
72
69
  end of the opening fence for the code block
@@ -102,7 +99,7 @@ Rendering with the `Markdown` object is done through `Markdown#render`.
102
99
  Unlike in the RedCloth API, the text to render is passed as an argument
103
100
  and not stored inside the `Markdown` instance, to encourage reusability.
104
101
 
105
- Markdown.render(text)
102
+ Markdown#render(text)
106
103
 
107
104
  Render a Markdown document with the attached renderer
108
105
 
@@ -253,7 +250,10 @@ The following instance methods may be implemented by the renderer:
253
250
  # document before or after the rendering process begins
254
251
  preprocess(full_document)
255
252
  postprocess(full_document)
256
-
253
+
254
+ You can look at
255
+ ["How to extend the Redcarpet 2 Markdown library?"](http://dev.af83.com/2012/02/27/howto-extend-the-redcarpet2-markdown-lib.html)
256
+ for some more explanations.
257
257
 
258
258
  Also, now our Pants are much smarter
259
259
  ------------------------------------
data/bin/redcarpet CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
- # Usage: redcarpet [<file>...]
2
+ # Usage: redcarpet [--parse-<extension>...] [--render-<extension>...] [--smarty] [<file>...]
3
3
  # Convert one or more Markdown files to HTML and write to standard output. With
4
4
  # no <file> or when <file> is '-', read Markdown source text from standard input.
5
+ # With <extension>s, perform additional Markdown processing before writing output.
6
+ # With --smarty, use the SmartyHTML renderer
5
7
  if ARGV.include?('--help')
6
8
  File.read(__FILE__).split("\n").grep(/^# /).each do |line|
7
9
  puts line[2..-1]
@@ -9,5 +11,28 @@ if ARGV.include?('--help')
9
11
  exit 0
10
12
  end
11
13
 
14
+ root = File.expand_path('../../', __FILE__)
15
+ $:.unshift File.expand_path('lib', root)
16
+
12
17
  require 'redcarpet'
13
- STDOUT.write(Redcarpet::Markdown.new(Redcarpet::Render::HTML).render(ARGF.read))
18
+
19
+ render_extensions = {}
20
+ parse_extensions = {}
21
+ renderer = Redcarpet::Render::HTML
22
+
23
+ ARGV.delete_if do |arg|
24
+ if arg =~ /^--render-([\w-]+)$/
25
+ arg = $1.gsub('-', '_')
26
+ render_extensions[arg.to_sym] = true
27
+ elsif arg =~ /^--parse-([\w-]+)$/
28
+ arg = $1.gsub('-', '_')
29
+ parse_extensions[arg.to_sym] = true
30
+ elsif arg == '--smarty'
31
+ renderer = Redcarpet::Render::SmartyHTML
32
+ else
33
+ false
34
+ end
35
+ end
36
+
37
+ render = renderer.new(render_extensions)
38
+ STDOUT.write(Redcarpet::Markdown.new(render, parse_extensions).render(ARGF.read))
@@ -22,6 +22,7 @@
22
22
  #include <stdio.h>
23
23
  #include <stdlib.h>
24
24
  #include <string.h>
25
+ #include <assert.h>
25
26
 
26
27
  /* MSVC compat */
27
28
  #if defined(_MSC_VER)
@@ -34,6 +35,7 @@ int
34
35
  bufprefix(const struct buf *buf, const char *prefix)
35
36
  {
36
37
  size_t i;
38
+ assert(buf && buf->unit);
37
39
 
38
40
  for (i = 0; i < buf->size; ++i) {
39
41
  if (prefix[i] == 0)
@@ -52,7 +54,10 @@ bufgrow(struct buf *buf, size_t neosz)
52
54
  {
53
55
  size_t neoasz;
54
56
  void *neodata;
55
- if (!buf || !buf->unit || neosz > BUFFER_MAX_ALLOC_SIZE)
57
+
58
+ assert(buf && buf->unit);
59
+
60
+ if (neosz > BUFFER_MAX_ALLOC_SIZE)
56
61
  return BUF_ENOMEM;
57
62
 
58
63
  if (buf->asize >= neosz)
@@ -91,8 +96,7 @@ bufnew(size_t unit)
91
96
  const char *
92
97
  bufcstr(struct buf *buf)
93
98
  {
94
- if (!buf || !buf->unit)
95
- return NULL;
99
+ assert(buf && buf->unit);
96
100
 
97
101
  if (buf->size < buf->asize && buf->data[buf->size] == 0)
98
102
  return (char *)buf->data;
@@ -110,12 +114,11 @@ void
110
114
  bufprintf(struct buf *buf, const char *fmt, ...)
111
115
  {
112
116
  va_list ap;
113
- if (!buf || !buf->unit)
114
- return;
115
-
116
117
  int n;
117
118
 
118
- if (buf == 0 || (buf->size >= buf->asize && bufgrow(buf, buf->size + 1)) < 0)
119
+ assert(buf && buf->unit);
120
+
121
+ if (buf->size >= buf->asize && bufgrow(buf, buf->size + 1) < 0)
119
122
  return;
120
123
 
121
124
  va_start(ap, fmt);
@@ -133,6 +136,7 @@ bufprintf(struct buf *buf, const char *fmt, ...)
133
136
  if ((size_t)n >= buf->asize - buf->size) {
134
137
  if (bufgrow(buf, buf->size + n + 1) < 0)
135
138
  return;
139
+
136
140
  va_start(ap, fmt);
137
141
  n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
138
142
  va_end(ap);
@@ -148,8 +152,7 @@ bufprintf(struct buf *buf, const char *fmt, ...)
148
152
  void
149
153
  bufput(struct buf *buf, const void *data, size_t len)
150
154
  {
151
- if (!buf)
152
- return;
155
+ assert(buf && buf->unit);
153
156
 
154
157
  if (buf->size + len > buf->asize && bufgrow(buf, buf->size + len) < 0)
155
158
  return;
@@ -170,8 +173,7 @@ bufputs(struct buf *buf, const char *str)
170
173
  void
171
174
  bufputc(struct buf *buf, int c)
172
175
  {
173
- if (!buf)
174
- return;
176
+ assert(buf && buf->unit);
175
177
 
176
178
  if (buf->size + 1 > buf->asize && bufgrow(buf, buf->size + 1) < 0)
177
179
  return;
@@ -208,8 +210,7 @@ bufreset(struct buf *buf)
208
210
  void
209
211
  bufslurp(struct buf *buf, size_t len)
210
212
  {
211
- if (!buf || !buf->unit || len <= 0)
212
- return;
213
+ assert(buf && buf->unit);
213
214
 
214
215
  if (len >= buf->size) {
215
216
  buf->size = 0;
@@ -220,10 +221,3 @@ bufslurp(struct buf *buf, size_t len)
220
221
  memmove(buf->data, buf->data + len, buf->size);
221
222
  }
222
223
 
223
- /* vbufprintf: stdarg variant of formatted printing into a buffer */
224
- void
225
- vbufprintf(struct buf *buf, const char *fmt, va_list ap)
226
- {
227
-
228
- }
229
-
data/ext/redcarpet/html.c CHANGED
@@ -60,6 +60,16 @@ sdhtml_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname)
60
60
  return HTML_TAG_NONE;
61
61
  }
62
62
 
63
+ static inline void escape_html(struct buf *ob, const uint8_t *source, size_t length)
64
+ {
65
+ houdini_escape_html0(ob, source, length, 0);
66
+ }
67
+
68
+ static inline void escape_href(struct buf *ob, const uint8_t *source, size_t length)
69
+ {
70
+ houdini_escape_href(ob, source, length);
71
+ }
72
+
63
73
  /********************
64
74
  * GENERIC RENDERER *
65
75
  ********************/
@@ -79,7 +89,7 @@ rndr_autolink(struct buf *ob, const struct buf *link, enum mkd_autolink type, vo
79
89
  BUFPUTSL(ob, "<a href=\"");
80
90
  if (type == MKDA_EMAIL)
81
91
  BUFPUTSL(ob, "mailto:");
82
- houdini_escape_href(ob, link->data, link->size);
92
+ escape_href(ob, link->data, link->size);
83
93
 
84
94
  if (options->link_attributes) {
85
95
  bufputc(ob, '\"');
@@ -95,9 +105,9 @@ rndr_autolink(struct buf *ob, const struct buf *link, enum mkd_autolink type, vo
95
105
  * want to print the `mailto:` prefix
96
106
  */
97
107
  if (bufprefix(link, "mailto:") == 0) {
98
- houdini_escape_html(ob, link->data + 7, link->size - 7);
108
+ escape_html(ob, link->data + 7, link->size - 7);
99
109
  } else {
100
- houdini_escape_html(ob, link->data, link->size);
110
+ escape_html(ob, link->data, link->size);
101
111
  }
102
112
 
103
113
  BUFPUTSL(ob, "</a>");
@@ -127,7 +137,7 @@ rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, v
127
137
  org++;
128
138
 
129
139
  if (cls) bufputc(ob, ' ');
130
- houdini_escape_html(ob, lang->data + org, i - org);
140
+ escape_html(ob, lang->data + org, i - org);
131
141
  }
132
142
  }
133
143
 
@@ -136,7 +146,7 @@ rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, v
136
146
  BUFPUTSL(ob, "<pre><code>");
137
147
 
138
148
  if (text)
139
- houdini_escape_html(ob, text->data, text->size);
149
+ escape_html(ob, text->data, text->size);
140
150
 
141
151
  BUFPUTSL(ob, "</code></pre>\n");
142
152
  }
@@ -154,7 +164,7 @@ static int
154
164
  rndr_codespan(struct buf *ob, const struct buf *text, void *opaque)
155
165
  {
156
166
  BUFPUTSL(ob, "<code>");
157
- if (text) houdini_escape_html(ob, text->data, text->size);
167
+ if (text) escape_html(ob, text->data, text->size);
158
168
  BUFPUTSL(ob, "</code>");
159
169
  return 1;
160
170
  }
@@ -230,11 +240,11 @@ rndr_link(struct buf *ob, const struct buf *link, const struct buf *title, const
230
240
  BUFPUTSL(ob, "<a href=\"");
231
241
 
232
242
  if (link && link->size)
233
- houdini_escape_href(ob, link->data, link->size);
243
+ escape_href(ob, link->data, link->size);
234
244
 
235
245
  if (title && title->size) {
236
246
  BUFPUTSL(ob, "\" title=\"");
237
- houdini_escape_html(ob, title->data, title->size);
247
+ escape_html(ob, title->data, title->size);
238
248
  }
239
249
 
240
250
  if (options->link_attributes) {
@@ -322,9 +332,9 @@ rndr_raw_block(struct buf *ob, const struct buf *text, void *opaque)
322
332
  size_t org, sz;
323
333
  if (!text) return;
324
334
  sz = text->size;
325
- while (sz > 0 && text->data[sz - 1] == '\n') sz -= 1;
335
+ while (sz > 0 && text->data[sz - 1] == '\n') sz--;
326
336
  org = 0;
327
- while (org < sz && text->data[org] == '\n') org += 1;
337
+ while (org < sz && text->data[org] == '\n') org++;
328
338
  if (org >= sz) return;
329
339
  if (ob->size) bufputc(ob, '\n');
330
340
  bufput(ob, text->data + org, sz - org);
@@ -356,15 +366,15 @@ rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, cons
356
366
  if (!link || !link->size) return 0;
357
367
 
358
368
  BUFPUTSL(ob, "<img src=\"");
359
- houdini_escape_href(ob, link->data, link->size);
369
+ escape_href(ob, link->data, link->size);
360
370
  BUFPUTSL(ob, "\" alt=\"");
361
371
 
362
372
  if (alt && alt->size)
363
- houdini_escape_html(ob, alt->data, alt->size);
373
+ escape_html(ob, alt->data, alt->size);
364
374
 
365
375
  if (title && title->size) {
366
376
  BUFPUTSL(ob, "\" title=\"");
367
- houdini_escape_html(ob, title->data, title->size); }
377
+ escape_html(ob, title->data, title->size); }
368
378
 
369
379
  bufputs(ob, USE_XHTML(options) ? "\"/>" : "\">");
370
380
  return 1;
@@ -375,6 +385,13 @@ rndr_raw_html(struct buf *ob, const struct buf *text, void *opaque)
375
385
  {
376
386
  struct html_renderopt *options = opaque;
377
387
 
388
+ /* HTML_ESCAPE overrides SKIP_HTML, SKIP_STYLE, SKIP_LINKS and SKIP_IMAGES
389
+ * It doens't see if there are any valid tags, just escape all of them. */
390
+ if((options->flags & HTML_ESCAPE) != 0) {
391
+ escape_html(ob, text->data, text->size);
392
+ return 1;
393
+ }
394
+
378
395
  if ((options->flags & HTML_SKIP_HTML) != 0)
379
396
  return 1;
380
397
 
@@ -466,7 +483,7 @@ static void
466
483
  rndr_normal_text(struct buf *ob, const struct buf *text, void *opaque)
467
484
  {
468
485
  if (text)
469
- houdini_escape_html(ob, text->data, text->size);
486
+ escape_html(ob, text->data, text->size);
470
487
  }
471
488
 
472
489
  static void
@@ -492,10 +509,18 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
492
509
 
493
510
  bufprintf(ob, "<a href=\"#toc_%d\">", options->toc_data.header_count++);
494
511
  if (text)
495
- bufput(ob, text->data, text->size);
512
+ escape_html(ob, text->data, text->size);
496
513
  BUFPUTSL(ob, "</a>\n");
497
514
  }
498
515
 
516
+ static int
517
+ toc_link(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque)
518
+ {
519
+ if (content && content->size)
520
+ bufput(ob, content->data, content->size);
521
+ return 1;
522
+ }
523
+
499
524
  static void
500
525
  toc_finalize(struct buf *ob, void *opaque)
501
526
  {
@@ -529,7 +554,7 @@ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *optio
529
554
  rndr_emphasis,
530
555
  NULL,
531
556
  NULL,
532
- NULL,
557
+ toc_link,
533
558
  NULL,
534
559
  rndr_triple_emphasis,
535
560
  rndr_strikethrough,
@@ -598,6 +623,6 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
598
623
  callbacks->autolink = NULL;
599
624
  }
600
625
 
601
- if (render_flags & HTML_SKIP_HTML)
626
+ if (render_flags & HTML_SKIP_HTML || render_flags & HTML_ESCAPE)
602
627
  callbacks->blockhtml = NULL;
603
628
  }
data/ext/redcarpet/html.h CHANGED
@@ -43,6 +43,7 @@ typedef enum {
43
43
  HTML_TOC = (1 << 6),
44
44
  HTML_HARD_WRAP = (1 << 7),
45
45
  HTML_USE_XHTML = (1 << 8),
46
+ HTML_ESCAPE = (1 << 9),
46
47
  } html_render_mode;
47
48
 
48
49
  typedef enum {
@@ -694,6 +694,8 @@ char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offs
694
694
  rndr->cb.normal_text(ob, &work, rndr->opaque);
695
695
  }
696
696
  else bufputc(ob, data[1]);
697
+ } else if (size == 1) {
698
+ bufputc(ob, data[0]);
697
699
  }
698
700
 
699
701
  return 2;
@@ -886,7 +888,8 @@ char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset
886
888
  /* looking for link end: ' " ) */
887
889
  while (i < size) {
888
890
  if (data[i] == '\\') i += 2;
889
- else if (data[i] == ')' || data[i] == '\'' || data[i] == '"') break;
891
+ else if (data[i] == ')') break;
892
+ else if (i >= 1 && _isspace(data[i-1]) && (data[i] == '\'' || data[i] == '"')) break;
890
893
  else i++;
891
894
  }
892
895
 
@@ -1575,7 +1578,7 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
1575
1578
  struct buf *work = 0, *inter = 0;
1576
1579
  size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
1577
1580
  int in_empty = 0, has_inside_empty = 0;
1578
- int has_next_uli, has_next_oli;
1581
+ size_t has_next_uli, has_next_oli;
1579
1582
 
1580
1583
  /* keeping track of the first indentation prefix */
1581
1584
  while (orgpre < 3 && orgpre < size && data[orgpre] == ' ')
@@ -1627,9 +1630,8 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
1627
1630
 
1628
1631
  /* checking for ul/ol switch */
1629
1632
  if (in_empty && (
1630
- ((*flags & MKD_LIST_ORDERED) && has_next_uli) ||
1631
- (!(*flags & MKD_LIST_ORDERED) && has_next_oli)
1632
- )){
1633
+ ((*flags & MKD_LIST_ORDERED) && has_next_uli) ||
1634
+ (!(*flags & MKD_LIST_ORDERED) && has_next_oli))){
1633
1635
  *flags |= MKD_LI_END;
1634
1636
  break; /* the following item must have same list type */
1635
1637
  }
@@ -1804,7 +1806,7 @@ parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
1804
1806
  i++;
1805
1807
 
1806
1808
  if (i < size)
1807
- curtag = find_block_tag((char *)data + 1, i - 1);
1809
+ curtag = find_block_tag((char *)data + 1, (int)i - 1);
1808
1810
 
1809
1811
  /* handling of special cases */
1810
1812
  if (!curtag) {
@@ -1968,10 +1970,13 @@ parse_table_header(
1968
1970
 
1969
1971
  header_end = i;
1970
1972
 
1973
+ while (header_end > 0 && _isspace(data[header_end - 1]))
1974
+ header_end--;
1975
+
1971
1976
  if (data[0] == '|')
1972
1977
  pipes--;
1973
1978
 
1974
- if (i > 2 && data[i - 1] == '|')
1979
+ if (header_end && data[header_end - 1] == '|')
1975
1980
  pipes--;
1976
1981
 
1977
1982
  *columns = pipes + 1;
@@ -2245,8 +2250,8 @@ is_ref(const uint8_t *data, size_t beg, size_t end, size_t *last, struct link_re
2245
2250
  line_end = title_end;
2246
2251
  title_end = i; } }
2247
2252
 
2248
- if (!line_end)
2249
- return 0; /* garbage after the link */
2253
+ if (!line_end || link_end == link_offset)
2254
+ return 0; /* garbage after the link empty link */
2250
2255
 
2251
2256
  /* a valid ref has been found, filling-in return structures */
2252
2257
  if (last)
@@ -2256,6 +2261,8 @@ is_ref(const uint8_t *data, size_t beg, size_t end, size_t *last, struct link_re
2256
2261
  struct link_ref *ref;
2257
2262
 
2258
2263
  ref = add_link_ref(refs, data + id_offset, id_end - id_offset);
2264
+ if (!ref)
2265
+ return 0;
2259
2266
 
2260
2267
  ref->link = bufnew(link_end - link_offset);
2261
2268
  bufput(ref->link, data + link_offset, link_end - link_offset);
@@ -2361,7 +2368,8 @@ sd_markdown_new(
2361
2368
  void
2362
2369
  sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md)
2363
2370
  {
2364
- static const float MARKDOWN_GROW_FACTOR = 1.4f;
2371
+ #define MARKDOWN_GROW(x) ((x) + ((x) >> 1))
2372
+ static const char UTF8_BOM[] = {0xEF, 0xBB, 0xBF};
2365
2373
 
2366
2374
  struct buf *text;
2367
2375
  size_t beg, end;
@@ -2378,6 +2386,12 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
2378
2386
 
2379
2387
  /* first pass: looking for references, copying everything else */
2380
2388
  beg = 0;
2389
+
2390
+ /* Skip a possible UTF-8 BOM, even though the Unicode standard
2391
+ * discourages having these in UTF-8 documents */
2392
+ if (doc_size >= 3 && memcmp(document, UTF8_BOM, 3) == 0)
2393
+ beg += 3;
2394
+
2381
2395
  while (beg < doc_size) /* iterating over lines */
2382
2396
  if (is_ref(document, beg, doc_size, &end, md->refs))
2383
2397
  beg = end;
@@ -2401,7 +2415,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
2401
2415
  }
2402
2416
 
2403
2417
  /* pre-grow the output buffer to minimize allocations */
2404
- bufgrow(ob, text->size * MARKDOWN_GROW_FACTOR);
2418
+ bufgrow(ob, MARKDOWN_GROW(text->size));
2405
2419
 
2406
2420
  /* second pass: actual rendering */
2407
2421
  if (md->cb.doc_header)
@@ -24,6 +24,8 @@ static void rb_redcarpet_md_flags(VALUE hash, unsigned int *enabled_extensions_p
24
24
  {
25
25
  unsigned int extensions = 0;
26
26
 
27
+ Check_Type(hash, T_HASH);
28
+
27
29
  /**
28
30
  * Markdown extensions -- all disabled by default
29
31
  */
@@ -102,6 +104,16 @@ static VALUE rb_redcarpet_md_render(VALUE self, VALUE text)
102
104
 
103
105
  if (rb_respond_to(rb_rndr, rb_intern("preprocess")))
104
106
  text = rb_funcall(rb_rndr, rb_intern("preprocess"), 1, text);
107
+ if (NIL_P(text))
108
+ return Qnil;
109
+
110
+ #ifdef HAVE_RUBY_ENCODING_H
111
+ {
112
+ struct rb_redcarpet_rndr *renderer;
113
+ Data_Get_Struct(rb_rndr, struct rb_redcarpet_rndr, renderer);
114
+ renderer->options.active_enc = rb_enc_get(text);
115
+ }
116
+ #endif
105
117
 
106
118
  /* initialize buffers */
107
119
  output_buf = bufnew(128);
@@ -114,7 +126,7 @@ static VALUE rb_redcarpet_md_render(VALUE self, VALUE text)
114
126
  markdown);
115
127
 
116
128
  /* build the Ruby string */
117
- text = redcarpet_str_new(output_buf->data, output_buf->size);
129
+ text = redcarpet_str_new(output_buf->data, output_buf->size, rb_enc_get(text));
118
130
 
119
131
  bufrelease(output_buf);
120
132
 
@@ -40,13 +40,11 @@ VALUE rb_cRenderHTML;
40
40
  VALUE rb_cRenderHTML_TOC;
41
41
  VALUE rb_mSmartyPants;
42
42
 
43
- static inline VALUE
44
- buf2str(const struct buf *text)
45
- {
46
- if (!text || !text->size) return Qnil;
47
- return redcarpet_str_new(text->data, text->size);
48
- }
49
-
43
+ #ifdef HAVE_RUBY_ENCODING_H
44
+ #define buf2str(t) ((t) ? redcarpet_str_new((t)->data, (t)->size, opt->active_enc) : Qnil)
45
+ #else
46
+ #define buf2str(t) ((t) ? redcarpet_str_new((t)->data, (t)->size, NULL) : Qnil)
47
+ #endif
50
48
 
51
49
  static void
52
50
  rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque)
@@ -352,6 +350,10 @@ static VALUE rb_redcarpet_html_init(int argc, VALUE *argv, VALUE self)
352
350
  {
353
351
  Check_Type(hash, T_HASH);
354
352
 
353
+ /* escape_html */
354
+ if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue)
355
+ render_flags |= HTML_ESCAPE;
356
+
355
357
  /* filter_html */
356
358
  if (rb_hash_aref(hash, CSTR2SYM("filter_html")) == Qtrue)
357
359
  render_flags |= HTML_SKIP_HTML;
@@ -409,7 +411,7 @@ static VALUE rb_redcarpet_smartypants_render(VALUE self, VALUE text)
409
411
  output_buf = bufnew(128);
410
412
 
411
413
  sdhtml_smartypants(output_buf, RSTRING_PTR(text), RSTRING_LEN(text));
412
- result = redcarpet_str_new(output_buf->data, output_buf->size);
414
+ result = redcarpet_str_new(output_buf->data, output_buf->size, rb_enc_get(text));
413
415
 
414
416
  bufrelease(output_buf);
415
417
  return result;
@@ -7,9 +7,9 @@
7
7
 
8
8
  #ifdef HAVE_RUBY_ENCODING_H
9
9
  # include <ruby/encoding.h>
10
- # define redcarpet_str_new(data, size) rb_enc_str_new(data, size, rb_utf8_encoding())
10
+ # define redcarpet_str_new(data, size, enc) rb_enc_str_new(data, size, enc)
11
11
  #else
12
- # define redcarpet_str_new(data, size) rb_str_new(data, size)
12
+ # define redcarpet_str_new(data, size, enc) rb_str_new(data, size)
13
13
  #endif
14
14
 
15
15
  #include "markdown.h"
@@ -23,6 +23,9 @@ struct redcarpet_renderopt {
23
23
  struct html_renderopt html;
24
24
  VALUE self;
25
25
  VALUE base_class;
26
+ #ifdef HAVE_RUBY_ENCODING_H
27
+ rb_encoding *active_enc;
28
+ #endif
26
29
  };
27
30
 
28
31
  struct rb_redcarpet_rndr {
@@ -0,0 +1,3 @@
1
+ require 'redcarpet'
2
+
3
+ Markdown = RedcarpetCompat unless defined? Markdown
@@ -0,0 +1,33 @@
1
+
2
+ module Redcarpet
3
+ module Render
4
+ # Markdown-stripping renderer. Turns Markdown into plaintext
5
+ # Thanks to @toupeira (Markus Koller)
6
+ class StripDown < Base
7
+ # Methods where the first argument is the text content
8
+ [
9
+ # block-level calls
10
+ :block_code, :block_quote,
11
+ :block_html, :header, :list,
12
+ :list_item, :paragraph,
13
+
14
+ # span-level calls
15
+ :autolink, :codespan, :double_emphasis,
16
+ :emphasis, :raw_html, :triple_emphasis,
17
+ :strikethrough, :superscript,
18
+
19
+ # low level rendering
20
+ :entity, :normal_text
21
+ ].each do |method|
22
+ define_method method do |*args|
23
+ args.first
24
+ end
25
+ end
26
+
27
+ # Other methods where the text content is in another argument
28
+ def link(link, title, content)
29
+ content
30
+ end
31
+ end
32
+ end
33
+ end
data/lib/redcarpet.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'redcarpet.so'
2
2
 
3
3
  module Redcarpet
4
- VERSION = '2.0.0b5'
4
+ VERSION = '2.1.1'
5
5
 
6
6
  class Markdown
7
7
  attr_reader :renderer
@@ -54,20 +54,71 @@ module Redcarpet
54
54
  end
55
55
 
56
56
  # Compatibility class;
57
- # Creates a instance of Redcarpet with the RedCloth
58
- # API. This instance has no extensions enabled whatsoever,
59
- # and no accessors to change this. 100% pure, standard
60
- # Markdown.
57
+ # Creates an instance of Redcarpet with the RedCloth API.
61
58
  class RedcarpetCompat
62
59
  attr_accessor :text
63
60
 
64
- def initialize(text, *_dummy)
61
+ def initialize(text, *exts)
62
+ exts_hash, render_hash = *parse_extensions_and_renderer_options(exts)
65
63
  @text = text
66
- @markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML)
64
+ renderer = Redcarpet::Render::HTML.new(render_hash)
65
+ @markdown = Redcarpet::Markdown.new(renderer, exts_hash)
67
66
  end
68
67
 
69
68
  def to_html(*_dummy)
70
69
  @markdown.render(@text)
71
70
  end
71
+
72
+ private
73
+
74
+ EXTENSION_MAP = {
75
+ # old name => new name
76
+ :autolink => :autolink,
77
+ :fenced_code => :fenced_code_blocks,
78
+ :filter_html => :filter_html,
79
+ :hard_wrap => :hard_wrap,
80
+ :lax_htmlblock => :lax_html_blocks,
81
+ :no_image => :no_images,
82
+ :no_intraemphasis => :no_intra_emphasis,
83
+ :no_links => :no_links,
84
+ :filter_styles => :no_styles,
85
+ :safelink => :safe_links_only,
86
+ :space_header => :space_after_headers,
87
+ :strikethrough => :strikethrough,
88
+ :tables => :tables,
89
+ :generate_toc => :with_toc_data,
90
+ :xhtml => :xhtml,
91
+ # old names with no new mapping
92
+ :gh_blockcode => nil,
93
+ :no_tables => nil,
94
+ :smart => nil,
95
+ :strict => nil
96
+ }
97
+
98
+ RENDERER_OPTIONS = [:filter_html, :no_images, :no_links, :no_styles,
99
+ :safe_links_only, :with_toc_data, :hard_wrap, :xhtml]
100
+
101
+ def rename_extensions(exts)
102
+ exts.map do |old_name|
103
+ if new_name = EXTENSION_MAP[old_name]
104
+ new_name
105
+ else
106
+ old_name
107
+ end
108
+ end.compact
109
+ end
110
+
111
+ # Returns two hashes, the extensions and renderer options
112
+ # given the extension list
113
+ def parse_extensions_and_renderer_options(exts)
114
+ exts = rename_extensions(exts)
115
+ exts.partition {|ext| !RENDERER_OPTIONS.include?(ext) }.
116
+ map {|list| list_to_truthy_hash(list) }
117
+ end
118
+
119
+ # Turns a list of symbols into a hash of <tt>symbol => true</tt>.
120
+ def list_to_truthy_hash(list)
121
+ list.inject({}) {|h, k| h[k] = true; h }
122
+ end
72
123
  end
73
124
 
data/redcarpet.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  Gem::Specification.new do |s|
3
3
  s.name = 'redcarpet'
4
- s.version = '2.0.0'
4
+ s.version = '2.1.1'
5
5
  s.summary = "Markdown that smells nice"
6
6
  s.description = 'A fast, safe and extensible Markdown to (X)HTML parser'
7
7
  s.date = '2011-09-14'
@@ -34,7 +34,9 @@ Gem::Specification.new do |s|
34
34
  ext/redcarpet/stack.c
35
35
  ext/redcarpet/stack.h
36
36
  lib/redcarpet.rb
37
+ lib/redcarpet/compat.rb
37
38
  lib/redcarpet/render_man.rb
39
+ lib/redcarpet/render_strip.rb
38
40
  redcarpet.gemspec
39
41
  sundown
40
42
  test/redcarpet_test.rb
@@ -60,6 +60,8 @@ class HTMLRenderTest < Test::Unit::TestCase
60
60
  :no_images => Redcarpet::Render::HTML.new(:no_images => true),
61
61
  :no_links => Redcarpet::Render::HTML.new(:no_links => true),
62
62
  :safe_links => Redcarpet::Render::HTML.new(:safe_links_only => true),
63
+ :escape_html => Redcarpet::Render::HTML.new(:escape_html => true),
64
+ :hard_wrap => Redcarpet::Render::HTML.new(:hard_wrap => true),
63
65
  }
64
66
  end
65
67
 
@@ -67,6 +69,28 @@ class HTMLRenderTest < Test::Unit::TestCase
67
69
  Redcarpet::Markdown.new(rndr).render(text)
68
70
  end
69
71
 
72
+ # Hint: overrides filter_html, no_images and no_links
73
+ def test_that_escape_html_works
74
+ source = <<EOS
75
+ Through <em>NO</em> <script>DOUBLE NO</script>
76
+
77
+ <script>BAD</script>
78
+
79
+ <img src="/favicon.ico" />
80
+ EOS
81
+ expected = <<EOE
82
+ <p>Through &lt;em&gt;NO&lt;/em&gt; &lt;script&gt;DOUBLE NO&lt;/script&gt;</p>
83
+
84
+ <p>&lt;script&gt;BAD&lt;/script&gt;</p>
85
+
86
+ <p>&lt;img src=&quot;/favicon.ico&quot; /&gt;
87
+
88
+ EOE
89
+
90
+ markdown = render_with(@rndr[:escape_html], source)
91
+ html_equal expected, markdown
92
+ end
93
+
70
94
  def test_that_filter_html_works
71
95
  markdown = render_with(@rndr[:no_html], 'Through <em>NO</em> <script>DOUBLE NO</script>')
72
96
  html_equal "<p>Through NO DOUBLE NO</p>", markdown
@@ -91,6 +115,18 @@ class HTMLRenderTest < Test::Unit::TestCase
91
115
  rd = render_with(@rndr[:safe_links], "[IRC](irc://chat.freenode.org/#freenode)")
92
116
  html_equal "<p>[IRC](irc://chat.freenode.org/#freenode)</p>\n", rd
93
117
  end
118
+
119
+ def test_that_hard_wrap_works
120
+ rd = render_with(@rndr[:hard_wrap], <<EOE)
121
+ Hello world,
122
+ this is just a simple test
123
+
124
+ With hard wraps
125
+ and other *things*.
126
+ EOE
127
+
128
+ assert rd =~ /<br>/
129
+ end
94
130
  end
95
131
 
96
132
  class MarkdownTest < Test::Unit::TestCase
@@ -186,6 +222,18 @@ class MarkdownTest < Test::Unit::TestCase
186
222
  output = @markdown.render(input)
187
223
  assert_equal input.encoding.name, output.encoding.name
188
224
  end
225
+
226
+ def test_should_return_string_in_same_encoding_not_in_utf8
227
+ input = "testing".encode('US-ASCII')
228
+ output = @markdown.render(input)
229
+ assert_equal input.encoding.name, output.encoding.name
230
+ end
231
+
232
+ def test_should_accept_non_utf8_or_ascii
233
+ input = "testing \xAB\xCD".force_encoding('ASCII-8BIT')
234
+ output = @markdown.render(input)
235
+ assert_equal 'ASCII-8BIT', output.encoding.name
236
+ end
189
237
  end
190
238
 
191
239
  def test_that_tags_can_have_dashes_and_underscores
@@ -293,6 +341,54 @@ class CustomRenderTest < Test::Unit::TestCase
293
341
  html_equal "<p>This is <em class=\"cool\">just</em> a test</p>",
294
342
  md.render("This is *just* a test")
295
343
  end
344
+
345
+ class NilPreprocessRenderer < Redcarpet::Render::HTML
346
+ def preprocess(fulldoc)
347
+ nil
348
+ end
349
+ end
350
+
351
+ def test_preprocess_returning_nil
352
+ md = Redcarpet::Markdown.new(NilPreprocessRenderer)
353
+ assert_equal(nil,md.render("Anything"))
354
+ end
355
+
356
+ end
357
+
358
+ class RedcarpetCompatTest < Test::Unit::TestCase
359
+ def test_simple_compat_api
360
+ html = RedcarpetCompat.new("This is_just_a test").to_html
361
+ html_equal "<p>This is<em>just</em>a test</p>", html
362
+ end
363
+
364
+ def test_compat_api_enables_extensions
365
+ html = RedcarpetCompat.new("This is_just_a test", :no_intra_emphasis).to_html
366
+ html_equal "<p>This is_just_a test</p>", html
367
+ end
368
+
369
+ def test_compat_api_knows_fenced_code_extension
370
+ text = "```ruby\nx = 'foo'\n```"
371
+ html = RedcarpetCompat.new(text, :fenced_code).to_html
372
+ html_equal "<pre><code class=\"ruby\">x = 'foo'\n</code></pre>", html
373
+ end
374
+
375
+ def test_compat_api_ignores_gh_blockcode_extension
376
+ text = "```ruby\nx = 'foo'\n```"
377
+ html = RedcarpetCompat.new(text, :fenced_code, :gh_blockcode).to_html
378
+ html_equal "<pre><code class=\"ruby\">x = 'foo'\n</code></pre>", html
379
+ end
380
+
381
+ def test_compat_api_knows_no_intraemphasis_extension
382
+ html = RedcarpetCompat.new("This is_just_a test", :no_intraemphasis).to_html
383
+ html_equal "<p>This is_just_a test</p>", html
384
+ end
385
+
386
+ def test_translate_outdated_extensions
387
+ # these extensions are no longer used
388
+ exts = [:gh_blockcode, :no_tables, :smart, :strict]
389
+ html = RedcarpetCompat.new('"TEST"', *exts).to_html
390
+ html_equal "<p>&quot;TEST&quot;</p>", html
391
+ end
296
392
  end
297
393
 
298
394
  # Disabled by default
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redcarpet
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 9
5
5
  prerelease:
6
6
  segments:
7
7
  - 2
8
- - 0
9
- - 0
10
- version: 2.0.0
8
+ - 1
9
+ - 1
10
+ version: 2.1.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Natacha Port\xC3\xA9"
@@ -65,7 +65,9 @@ files:
65
65
  - ext/redcarpet/stack.c
66
66
  - ext/redcarpet/stack.h
67
67
  - lib/redcarpet.rb
68
+ - lib/redcarpet/compat.rb
68
69
  - lib/redcarpet/render_man.rb
70
+ - lib/redcarpet/render_strip.rb
69
71
  - redcarpet.gemspec
70
72
  - test/redcarpet_test.rb
71
73
  homepage: http://github.com/tanoku/redcarpet
@@ -97,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
97
99
  requirements: []
98
100
 
99
101
  rubyforge_project:
100
- rubygems_version: 1.8.6
102
+ rubygems_version: 1.8.15
101
103
  signing_key:
102
104
  specification_version: 3
103
105
  summary: Markdown that smells nice