RedCloth 4.1.1 → 4.1.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of RedCloth might be problematic. Click here for more details.

Files changed (41) hide show
  1. data/CHANGELOG +36 -0
  2. data/COPYING +1 -1
  3. data/README +32 -17
  4. data/Rakefile +1 -0
  5. data/RedCloth.gemspec +4 -7
  6. data/ext/redcloth_scan/redcloth.h +53 -22
  7. data/ext/redcloth_scan/redcloth_attributes.c +176 -172
  8. data/ext/redcloth_scan/redcloth_attributes.c.rl +2 -3
  9. data/ext/redcloth_scan/redcloth_attributes.java.rl +5 -6
  10. data/ext/redcloth_scan/redcloth_attributes.rl +2 -2
  11. data/ext/redcloth_scan/redcloth_common.rl +5 -1
  12. data/ext/redcloth_scan/redcloth_inline.c +14485 -7298
  13. data/ext/redcloth_scan/redcloth_inline.c.rl +48 -14
  14. data/ext/redcloth_scan/redcloth_inline.java.rl +36 -4
  15. data/ext/redcloth_scan/redcloth_inline.rl +11 -12
  16. data/ext/redcloth_scan/redcloth_scan.c +6436 -6228
  17. data/ext/redcloth_scan/redcloth_scan.c.rl +12 -14
  18. data/ext/redcloth_scan/redcloth_scan.java.rl +25 -3
  19. data/ext/redcloth_scan/redcloth_scan.rl +7 -12
  20. data/lib/redcloth/formatters/base.rb +26 -20
  21. data/lib/redcloth/formatters/html.rb +22 -30
  22. data/lib/redcloth/formatters/latex.rb +45 -17
  23. data/lib/redcloth/textile_doc.rb +1 -3
  24. data/lib/redcloth/version.rb +1 -1
  25. data/test/basic.yml +16 -2
  26. data/test/code.yml +6 -7
  27. data/test/html.yml +15 -1
  28. data/test/images.yml +23 -0
  29. data/test/links.yml +27 -1
  30. data/test/lists.yml +19 -1
  31. data/test/table.yml +73 -4
  32. data/test/test_custom_tags.rb +13 -1
  33. data/test/test_erb.rb +1 -1
  34. data/test/test_extensions.rb +1 -1
  35. data/test/test_formatters.rb +1 -1
  36. data/test/test_parser.rb +1 -1
  37. data/test/test_restrictions.rb +1 -1
  38. data/test/textism.yml +1 -1
  39. data/test/threshold.yml +1 -3
  40. data/test/validate_fixtures.rb +2 -1
  41. metadata +6 -15
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * redcloth_scan.c.rl
3
3
  *
4
- * Copyright (C) 2008 Jason Garber
4
+ * Copyright (C) 2009 Jason Garber
5
5
  */
6
6
  #define redcloth_scan_c
7
7
 
@@ -31,11 +31,11 @@ redcloth_transform(self, p, pe, refs)
31
31
  VALUE refs;
32
32
  {
33
33
  char *orig_p = p, *orig_pe = pe;
34
- int cs, act, nest;
34
+ int cs, act, nest = 0;
35
35
  char *ts = NULL, *te = NULL, *reg = NULL, *bck = NULL, *eof = NULL;
36
- VALUE html = rb_str_new2("");
37
- VALUE table = rb_str_new2("");
38
- VALUE block = rb_str_new2("");
36
+ VALUE html = STR_NEW2("");
37
+ VALUE table = STR_NEW2("");
38
+ VALUE block = STR_NEW2("");
39
39
  VALUE regs; CLEAR_REGS()
40
40
 
41
41
 
@@ -84,7 +84,7 @@ redcloth_html_esc(int argc, VALUE* argv, VALUE self) //(self, str, level)
84
84
 
85
85
  rb_scan_args(argc, argv, "11", &str, &level);
86
86
 
87
- VALUE new_str = rb_str_new2("");
87
+ VALUE new_str = STR_NEW2("");
88
88
  if (str == Qnil)
89
89
  return new_str;
90
90
 
@@ -95,7 +95,7 @@ redcloth_html_esc(int argc, VALUE* argv, VALUE self) //(self, str, level)
95
95
 
96
96
  char *ts = RSTRING_PTR(str), *te = RSTRING_PTR(str) + RSTRING_LEN(str);
97
97
  char *t = ts, *t2 = ts, *ch = NULL;
98
- if (te <= ts) return;
98
+ if (te <= ts) return Qnil;
99
99
 
100
100
  while (t2 < te) {
101
101
  ch = NULL;
@@ -142,7 +142,7 @@ redcloth_html_esc(int argc, VALUE* argv, VALUE self) //(self, str, level)
142
142
  static VALUE
143
143
  redcloth_latex_esc(VALUE self, VALUE str)
144
144
  {
145
- VALUE new_str = rb_str_new2("");
145
+ VALUE new_str = STR_NEW2("");
146
146
 
147
147
  if (str == Qnil)
148
148
  return new_str;
@@ -154,7 +154,7 @@ redcloth_latex_esc(VALUE self, VALUE str)
154
154
 
155
155
  char *ts = RSTRING_PTR(str), *te = RSTRING_PTR(str) + RSTRING_LEN(str);
156
156
  char *t = ts, *t2 = ts, *ch = NULL;
157
- if (te <= ts) return;
157
+ if (te <= ts) return Qnil;
158
158
 
159
159
  while (t2 < te) {
160
160
  ch = NULL;
@@ -181,7 +181,7 @@ redcloth_latex_esc(VALUE self, VALUE str)
181
181
  if (t2 > t)
182
182
  rb_str_cat(new_str, t, t2-t);
183
183
  VALUE opts = rb_hash_new();
184
- rb_hash_aset(opts, ID2SYM(rb_intern("text")), rb_str_new2(ch));
184
+ rb_hash_aset(opts, ID2SYM(rb_intern("text")), STR_NEW2(ch));
185
185
  rb_str_concat(new_str, rb_funcall(self, rb_intern("entity"), 1, opts));
186
186
  t = t2 + 1;
187
187
  }
@@ -201,12 +201,10 @@ static VALUE
201
201
  redcloth_to(self, formatter)
202
202
  VALUE self, formatter;
203
203
  {
204
- char *pe, *p;
205
- int len = 0;
206
-
207
- rb_funcall(self, rb_intern("delete!"), 1, rb_str_new2("\r"));
204
+ rb_funcall(self, rb_intern("delete!"), 1, STR_NEW2("\r"));
208
205
  VALUE working_copy = rb_obj_clone(self);
209
206
  rb_extend_object(working_copy, formatter);
207
+
210
208
  if (rb_funcall(working_copy, rb_intern("lite_mode"), 0) == Qtrue) {
211
209
  return redcloth_inline2(working_copy, self, rb_hash_new());
212
210
  } else {
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * redcloth_scan.java.rl
3
3
  *
4
- * Copyright (C) 2008 Jason Garber
4
+ * Copyright (C) 2009 Jason Garber
5
5
  */
6
6
  import java.io.IOException;
7
7
 
@@ -108,8 +108,20 @@ public class RedclothScanService implements BasicLibraryService {
108
108
  boolean punct = true;
109
109
  while(p > reg && punct) {
110
110
  switch(data[p - 1]) {
111
+ case ')':
112
+ int tempP = p - 1;
113
+ int level = -1;
114
+ while(tempP > reg) {
115
+ switch(data[tempP - 1]) {
116
+ case '(': ++level; break;
117
+ case ')': --level; break;
118
+ }
119
+ --tempP;
120
+ }
121
+ if (level == 0) { punct = false; } else { --p; }
122
+ break;
111
123
  case '!': case '"': case '#': case '$': case '%': case ']': case '[': case '&': case '\'':
112
- case '*': case '+': case ',': case '-': case '.': case ')': case '(': case ':':
124
+ case '*': case '+': case ',': case '-': case '.': case '(': case ':':
113
125
  case ';': case '=': case '?': case '@': case '\\': case '^': case '_':
114
126
  case '`': case '|': case '~': p--; break;
115
127
  default: punct = false;
@@ -160,7 +172,8 @@ public class RedclothScanService implements BasicLibraryService {
160
172
  ((RubyHash)regs).aset(sym_text, inline2(self, block, refs));
161
173
  }
162
174
 
163
- if(self.respondsTo(method.asJavaString())) {
175
+ IRubyObject formatterMethods = ((RubyObject)self).callMethod(runtime.getCurrentContext(), "formatter_methods");
176
+ if( ((RubyArray)formatterMethods).includes(runtime.getCurrentContext(), method) ) {
164
177
  block = self.callMethod(runtime.getCurrentContext(), method.asJavaString(), regs);
165
178
  } else {
166
179
  IRubyObject fallback = ((RubyHash)regs).aref(runtime.newSymbol("fallback"));
@@ -229,6 +242,10 @@ public class RedclothScanService implements BasicLibraryService {
229
242
  ((RubyString)H).append(self.callMethod(runtime.getCurrentContext(), T, regs));
230
243
  }
231
244
 
245
+ public void RSTRIP_BANG(IRubyObject H) {
246
+ ((RubyString)H).callMethod(runtime.getCurrentContext(), "rstrip!");
247
+ }
248
+
232
249
  public void DONE(IRubyObject H) {
233
250
  ((RubyString)html).append(H);
234
251
  CLEAR(H);
@@ -403,6 +420,11 @@ public class RedclothScanService implements BasicLibraryService {
403
420
 
404
421
  ((RubyObject)workingCopy).extend(new IRubyObject[]{formatter});
405
422
 
423
+ IRubyObject workingCopyMethods = workingCopy.callMethod(runtime.getCurrentContext(), "methods");
424
+ IRubyObject classInstanceMethods = workingCopy.getType().callMethod(runtime.getCurrentContext(), "instance_methods");
425
+ IRubyObject customTags = workingCopyMethods.callMethod(runtime.getCurrentContext(), "-", classInstanceMethods);
426
+ ((RubyObject)workingCopy).setInstanceVariable("@custom_tags", customTags);
427
+
406
428
  if(workingCopy.callMethod(runtime.getCurrentContext(), "lite_mode").isTrue()) {
407
429
  return inline2(workingCopy, self, RubyHash.newHash(runtime));
408
430
  } else {
@@ -1,19 +1,18 @@
1
1
  /*
2
2
  * redcloth_scan.rl
3
3
  *
4
- * Copyright (C) 2008 Jason Garber
4
+ * Copyright (C) 2009 Jason Garber
5
5
  */
6
6
  %%{
7
7
 
8
8
  machine redcloth_scan;
9
9
 
10
10
  # blocks
11
- notextile_tag_start = "<notextile>" ;
12
- notextile_tag_end = "</notextile>" LF? ;
11
+ notextile_tag = notextile (LF | EOF) ;
13
12
  noparagraph_line_start = " "+ ;
14
13
  notextile_block_start = ( "notextile" >A %{ STORE("type"); } A C :> "." ( "." %extend | "" ) " "+ ) ;
15
- pre_tag_start = "<pre" [^>]* ">" (space* "<code>")? ;
16
- pre_tag_end = ("</code>" space*)? "</pre>" LF? ;
14
+ pre_tag_start = "<pre" [^>]* ">" (space* code_tag_start)? ;
15
+ pre_tag_end = (code_tag_end space*)? "</pre>" LF? ;
17
16
  pre_block_start = ( "pre" >A %{ STORE("type"); } A C :> "." ( "." %extend | "" ) " "+ ) ;
18
17
  bc_start = ( "bc" >A %{ STORE("type"); } A C :> "." ( "." %extend | "" ) " "+ ) ;
19
18
  bq_start = ( "bq" >A %{ STORE("type"); } A C :> "." ( "." %extend | "" ) ( ":" %A uri %{ STORE("cite"); } )? " "+ ) ;
@@ -30,7 +29,7 @@
30
29
  ol = "#" %{nest++; list_type = "ol";};
31
30
  ul_start = ( ul | ol )* ul A C :> " "+ ;
32
31
  ol_start = ( ul | ol )* ol N A C :> " "+ ;
33
- list_start = ( ul_start | ol_start ) >{nest = 0;} ;
32
+ list_start = " "* ( ul_start | ol_start ) >{nest = 0;} ;
34
33
  dt_start = "-" . " "+ ;
35
34
  dd_start = ":=" ;
36
35
  long_dd = dd_start " "* LF %{ ADD_BLOCK(); ASET("type", "dd"); } any+ >A %{ TRANSFORM("text"); } :>> "=:" ;
@@ -109,11 +108,6 @@
109
108
  LF { ADD_BLOCK(); fgoto main; };
110
109
  default => cat;
111
110
  *|;
112
-
113
- notextile_tag := |*
114
- notextile_tag_end { ADD_BLOCK(); fgoto main; };
115
- default => cat;
116
- *|;
117
111
 
118
112
  notextile_block := |*
119
113
  EOF {
@@ -178,6 +172,7 @@
178
172
  } else {
179
173
  ADD_EXTENDED_BLOCKCODE();
180
174
  CAT(html);
175
+ RSTRIP_BANG(html);
181
176
  INLINE(html, "bc_close");
182
177
  SET_PLAIN_BLOCK("p");
183
178
  END_EXTENDED();
@@ -293,7 +288,7 @@
293
288
 
294
289
  main := |*
295
290
  noparagraph_line_start { ASET("type", "ignored_line"); fgoto noparagraph_line; };
296
- notextile_tag_start { ASET("type", "notextile"); fgoto notextile_tag; };
291
+ notextile_tag { INLINE(block, "notextile"); };
297
292
  notextile_block_start { ASET("type", "notextile"); fgoto notextile_block; };
298
293
  script_tag_start { CAT(block); fgoto script_tag; };
299
294
  pre_tag_start { ASET("type", "notextile"); CAT(block); fgoto pre_tag; };
@@ -1,26 +1,6 @@
1
1
  module RedCloth::Formatters
2
2
  module Base
3
3
 
4
- def pba(opts)
5
- opts.delete(:style) if filter_styles
6
- opts.delete(:class) if filter_classes
7
- opts.delete(:id) if filter_ids
8
-
9
- atts = ''
10
- opts[:"text-align"] = opts.delete(:align)
11
- opts[:style] += ';' if opts[:style] && (opts[:style][-1..-1] != ';')
12
- [:float, :"text-align", :"vertical-align"].each do |a|
13
- opts[:style] = "#{a}:#{opts[a]};#{opts[:style]}" if opts[a]
14
- end
15
- [:"padding-right", :"padding-left"].each do |a|
16
- opts[:style] = "#{a}:#{opts[a]}em;#{opts[:style]}" if opts[a]
17
- end
18
- [:style, :class, :lang, :id, :colspan, :rowspan, :title, :start, :align].each do |a|
19
- atts << " #{a}=\"#{ html_esc(opts[a].to_s, :html_escape_attributes) }\"" if opts[a]
20
- end
21
- atts
22
- end
23
-
24
4
  def ignore(opts)
25
5
  opts[:text]
26
6
  end
@@ -41,6 +21,28 @@ module RedCloth::Formatters
41
21
  end
42
22
  end
43
23
 
24
+ private
25
+
26
+ def pba(opts)
27
+ opts.delete(:style) if filter_styles
28
+ opts.delete(:class) if filter_classes
29
+ opts.delete(:id) if filter_ids
30
+
31
+ atts = ''
32
+ opts[:"text-align"] = opts.delete(:align)
33
+ opts[:style] += ';' if opts[:style] && (opts[:style][-1..-1] != ';')
34
+ [:float, :"text-align", :"vertical-align"].each do |a|
35
+ opts[:style] = "#{a}:#{opts[a]};#{opts[:style]}" if opts[a]
36
+ end
37
+ [:"padding-right", :"padding-left"].each do |a|
38
+ opts[:style] = "#{a}:#{opts[a]}em;#{opts[:style]}" if opts[a]
39
+ end
40
+ [:style, :class, :lang, :id, :colspan, :rowspan, :title, :start, :align].each do |a|
41
+ atts << " #{a}=\"#{ html_esc(opts[a].to_s, :html_escape_attributes) }\"" if opts[a]
42
+ end
43
+ atts
44
+ end
45
+
44
46
  def method_missing(method, opts)
45
47
  opts[:text] || ""
46
48
  end
@@ -52,6 +54,10 @@ module RedCloth::Formatters
52
54
  def after_transform(text)
53
55
 
54
56
  end
57
+
58
+ def formatter_methods
59
+ singleton_methods.map! {|method| method.to_sym }
60
+ end
55
61
 
56
62
  end
57
63
  end
@@ -1,25 +1,6 @@
1
1
  module RedCloth::Formatters::HTML
2
2
  include RedCloth::Formatters::Base
3
3
 
4
- # escapement for regular HTML (not in PRE tag)
5
- def escape(text)
6
- html_esc(text)
7
- end
8
-
9
- # escapement for HTML in a PRE tag
10
- def escape_pre(text)
11
- html_esc(text, :html_escape_preformatted)
12
- end
13
-
14
- # escaping for HTML attributes
15
- def escape_attribute(text)
16
- html_esc(text, :html_escape_attributes)
17
- end
18
-
19
- def after_transform(text)
20
- text.chomp!
21
- end
22
-
23
4
  [:h1, :h2, :h3, :h4, :h5, :h6, :p, :pre, :div].each do |m|
24
5
  define_method(m) do |opts|
25
6
  "<#{m}#{pba(opts)}>#{opts[:text]}</#{m}>\n"
@@ -129,18 +110,7 @@ module RedCloth::Formatters::HTML
129
110
  "</blockquote>\n"
130
111
  end
131
112
 
132
- LINK_TEXT_WITH_TITLE_RE = /
133
- ([^"]+?) # $text
134
- \s?
135
- \(([^)]+?)\) # $title
136
- $
137
- /x
138
113
  def link(opts)
139
- if opts[:name] =~ LINK_TEXT_WITH_TITLE_RE
140
- md = LINK_TEXT_WITH_TITLE_RE.match(opts[:name])
141
- opts[:name] = md[1]
142
- opts[:title] = md[2]
143
- end
144
114
  "<a href=\"#{escape_attribute opts[:href]}\"#{pba(opts)}>#{opts[:name]}</a>"
145
115
  end
146
116
 
@@ -281,6 +251,28 @@ module RedCloth::Formatters::HTML
281
251
  opts[:text] + "\n"
282
252
  end
283
253
 
254
+ private
255
+
256
+ # escapement for regular HTML (not in PRE tag)
257
+ def escape(text)
258
+ html_esc(text)
259
+ end
260
+
261
+ # escapement for HTML in a PRE tag
262
+ def escape_pre(text)
263
+ html_esc(text, :html_escape_preformatted)
264
+ end
265
+
266
+ # escaping for HTML attributes
267
+ def escape_attribute(text)
268
+ html_esc(text, :html_escape_attributes)
269
+ end
270
+
271
+ def after_transform(text)
272
+ text.chomp!
273
+ end
274
+
275
+
284
276
  def before_transform(text)
285
277
  clean_html(text) if sanitize_html
286
278
  end
@@ -14,14 +14,6 @@ module RedCloth::Formatters::LATEX
14
14
 
15
15
  RedCloth::TextileDoc.send(:include, Settings)
16
16
 
17
- def escape(text)
18
- latex_esc(text)
19
- end
20
-
21
- def escape_pre(text)
22
- text
23
- end
24
-
25
17
  # headers
26
18
  { :h1 => 'section*',
27
19
  :h2 => 'subsection*',
@@ -38,7 +30,7 @@ module RedCloth::Formatters::LATEX
38
30
  # commands
39
31
  { :strong => 'textbf',
40
32
  :em => 'emph',
41
- :i => 'emph',
33
+ :i => 'textit',
42
34
  :b => 'textbf',
43
35
  :ins => 'underline',
44
36
  :del => 'sout',
@@ -102,24 +94,50 @@ module RedCloth::Formatters::LATEX
102
94
  end
103
95
 
104
96
  def td(opts)
105
- "\t\t\t#{opts[:text]} &\n"
97
+ column = @table_row.size
98
+ if opts[:colspan]
99
+ opts[:text] = "\\multicolumn{#{opts[:colspan]}}{ #{"l " * opts[:colspan].to_i}}{#{opts[:text]}}"
100
+ end
101
+ if opts[:rowspan]
102
+ @table_multirow_next[column] = opts[:rowspan].to_i - 1
103
+ opts[:text] = "\\multirow{#{opts[:rowspan]}}{*}{#{opts[:text]}}"
104
+ end
105
+ @table_row.push(opts[:text])
106
+ return ""
106
107
  end
107
108
 
108
109
  def tr_open(opts)
109
- "\t\t"
110
+ @table_row = []
111
+ return ""
110
112
  end
111
113
 
112
114
  def tr_close(opts)
113
- "\t\t\\\\\n"
115
+ multirow_columns = @table_multirow.find_all {|c,n| n > 0}
116
+ multirow_columns.each do |c,n|
117
+ @table_row.insert(c,"")
118
+ @table_multirow[c] -= 1
119
+ end
120
+ @table_multirow.merge!(@table_multirow_next)
121
+ @table_multirow_next = {}
122
+ @table.push(@table_row)
123
+ return ""
114
124
  end
115
125
 
116
- # FIXME: we need to know the column count before opening tabular context.
126
+ # We need to know the column count before opening tabular context.
117
127
  def table_open(opts)
118
- "\\begin{align*}\n"
128
+ @table = []
129
+ @table_multirow = {}
130
+ @table_multirow_next = {}
131
+ return ""
119
132
  end
120
133
 
121
134
  def table_close(opts)
122
- "\t\\end{align*}\n"
135
+ output = "\\begin{tabular}{ #{"l " * @table[0].size }}\n"
136
+ @table.each do |row|
137
+ output << " #{row.join(" & ")} \\\\\n"
138
+ end
139
+ output << "\\end{tabular}\n"
140
+ output
123
141
  end
124
142
 
125
143
  def bc_open(opts)
@@ -222,12 +240,22 @@ module RedCloth::Formatters::LATEX
222
240
  end
223
241
 
224
242
  def dim(opts)
225
- space = opts[:space] ? " " : ''
226
- "#{opts[:text]}#{space}\\texttimes{}#{space}"
243
+ opts[:text].gsub!('x', '\times')
244
+ opts[:text].gsub!('"', "''")
245
+ period = opts[:text].slice!(/\.$/)
246
+ "$#{opts[:text]}$#{period}"
227
247
  end
228
248
 
229
249
  private
230
250
 
251
+ def escape(text)
252
+ latex_esc(text)
253
+ end
254
+
255
+ def escape_pre(text)
256
+ text
257
+ end
258
+
231
259
  # Use this for block level commands that use \begin
232
260
  def begin_chunk(type)
233
261
  chunk_counter[type] += 1