rinku 1.2.2 → 1.3.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/ext/rinku/rinku.c CHANGED
@@ -34,13 +34,20 @@
34
34
 
35
35
  static VALUE rb_mRinku;
36
36
 
37
+ typedef enum {
38
+ HTML_TAG_NONE = 0,
39
+ HTML_TAG_OPEN,
40
+ HTML_TAG_CLOSE,
41
+ } html_tag;
42
+
37
43
  typedef enum {
38
44
  AUTOLINK_URLS = (1 << 0),
39
45
  AUTOLINK_EMAILS = (1 << 1),
46
+ AUTOLINK_IN_CODE = (1 << 2),
40
47
  AUTOLINK_ALL = AUTOLINK_URLS|AUTOLINK_EMAILS
41
48
  } autolink_mode;
42
49
 
43
- typedef size_t (*autolink_parse_cb)(size_t *rewind, struct buf *, char *, size_t, size_t);
50
+ typedef size_t (*autolink_parse_cb)(size_t *rewind, struct buf *, uint8_t *, size_t, size_t);
44
51
 
45
52
  typedef enum {
46
53
  AUTOLINK_ACTION_NONE = 0,
@@ -52,9 +59,9 @@ typedef enum {
52
59
 
53
60
  static autolink_parse_cb g_callbacks[] = {
54
61
  NULL,
55
- ups_autolink__www, /* 1 */
56
- ups_autolink__email,/* 2 */
57
- ups_autolink__url, /* 3 */
62
+ sd_autolink__www, /* 1 */
63
+ sd_autolink__email,/* 2 */
64
+ sd_autolink__url, /* 3 */
58
65
  };
59
66
 
60
67
  static const char *g_hrefs[] = {
@@ -65,93 +72,94 @@ static const char *g_hrefs[] = {
65
72
  };
66
73
 
67
74
  static void
68
- autolink_escape_cb(struct buf *ob, const struct buf *text, void *unused)
75
+ autolink__html_escape(struct buf *ob, const struct buf *link, void *payload)
69
76
  {
70
- size_t i = 0, org;
71
-
72
- while (i < text->size) {
73
- org = i;
74
-
75
- while (i < text->size &&
76
- text->data[i] != '<' &&
77
- text->data[i] != '>' &&
78
- text->data[i] != '&' &&
79
- text->data[i] != '"')
80
- i++;
81
-
82
- if (i > org)
83
- bufput(ob, text->data + org, i - org);
84
-
85
- if (i >= text->size)
86
- break;
87
-
88
- switch (text->data[i]) {
89
- case '<': BUFPUTSL(ob, "&lt;"); break;
90
- case '>': BUFPUTSL(ob, "&gt;"); break;
91
- case '&': BUFPUTSL(ob, "&amp;"); break;
92
- case '"': BUFPUTSL(ob, "&quot;"); break;
93
- default: bufputc(ob, text->data[i]); break;
94
- }
95
-
96
- i++;
97
- }
77
+ houdini_escape_html0(ob, link->data, link->size, 0);
98
78
  }
99
79
 
100
- static inline int
101
- is_closing_a(const char *tag, size_t size)
80
+ /* From sundown/html/html.c */
81
+ static int
82
+ html_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname)
102
83
  {
103
84
  size_t i;
85
+ int closed = 0;
104
86
 
105
- if (tag[0] != '<' || size < STRLEN("</a>") || tag[1] != '/')
106
- return 0;
87
+ if (tag_size < 3 || tag_data[0] != '<')
88
+ return HTML_TAG_NONE;
107
89
 
108
- i = 2;
90
+ i = 1;
109
91
 
110
- while (i < size && isspace(tag[i]))
92
+ if (tag_data[i] == '/') {
93
+ closed = 1;
111
94
  i++;
95
+ }
112
96
 
113
- if (i == size || tag[i] != 'a')
114
- return 0;
97
+ for (; i < tag_size; ++i, ++tagname) {
98
+ if (*tagname == 0)
99
+ break;
115
100
 
116
- i++;
101
+ if (tag_data[i] != *tagname)
102
+ return HTML_TAG_NONE;
103
+ }
117
104
 
118
- while (i < size && isspace(tag[i]))
119
- i++;
105
+ if (i == tag_size)
106
+ return HTML_TAG_NONE;
120
107
 
121
- if (i == size || tag[i] != '>')
122
- return 0;
108
+ if (isspace(tag_data[i]) || tag_data[i] == '>')
109
+ return closed ? HTML_TAG_CLOSE : HTML_TAG_OPEN;
123
110
 
124
- return i;
111
+ return HTML_TAG_NONE;
125
112
  }
126
113
 
127
114
  static size_t
128
- autolink__skip_tag(struct buf *ob, char *text, size_t size)
115
+ autolink__skip_tag(
116
+ struct buf *ob,
117
+ const uint8_t *text,
118
+ size_t size,
119
+ const char **skip_tags,
120
+ size_t skip_tags_count)
129
121
  {
130
- size_t i = 0;
122
+ size_t tag, i = 0;
131
123
 
132
124
  while (i < size && text[i] != '>')
133
125
  i++;
134
126
 
135
- if (size > 3 && text[1] == 'a' && isspace(text[2])) {
136
- while (i < size) {
137
- size_t tag_len = is_closing_a(text + i, size - i);
138
- if (tag_len) {
139
- i += tag_len;
127
+ for (tag = 0; tag < skip_tags_count; ++tag) {
128
+ if (html_is_tag(text, size, skip_tags[tag]) == HTML_TAG_OPEN)
129
+ break;
130
+ }
131
+
132
+ if (tag < skip_tags_count) {
133
+ for (;;) {
134
+ while (i < size && text[i] != '<')
135
+ i++;
136
+
137
+ if (i == size)
140
138
  break;
141
- }
139
+
140
+ if (html_is_tag(text + i, size - i, skip_tags[tag]) == HTML_TAG_CLOSE)
141
+ break;
142
+
142
143
  i++;
143
144
  }
145
+
146
+ while (i < size && text[i] != '>')
147
+ i++;
144
148
  }
145
149
 
146
- return i + 1;
150
+ // bufput(ob, text, i + 1);
151
+ return i;
147
152
  }
148
153
 
149
154
  int
150
155
  rinku_autolink(
151
156
  struct buf *ob,
152
- struct buf *text,
157
+ const uint8_t *text,
158
+ size_t size,
153
159
  unsigned int flags,
154
160
  const char *link_attr,
161
+ const char **skip_tags,
162
+ size_t skip_tags_count,
155
163
  void (*link_text_cb)(struct buf *ob, const struct buf *link, void *payload),
156
164
  void *payload)
157
165
  {
@@ -161,7 +169,7 @@ rinku_autolink(
161
169
  void (*link_url_cb)(struct buf *, const struct buf *, void *);
162
170
  int link_count = 0;
163
171
 
164
- if (!text || text->size == 0)
172
+ if (!text || size == 0)
165
173
  return;
166
174
 
167
175
  memset(active_chars, 0x0, sizeof(active_chars));
@@ -178,44 +186,48 @@ rinku_autolink(
178
186
  }
179
187
 
180
188
  if (link_text_cb == NULL)
181
- link_text_cb = &autolink_escape_cb;
189
+ link_text_cb = &autolink__html_escape;
182
190
 
183
191
  if (link_attr != NULL) {
184
192
  while (isspace(*link_attr))
185
193
  link_attr++;
186
194
  }
187
195
 
188
- bufgrow(ob, text->size);
196
+ bufgrow(ob, size);
189
197
 
190
198
  i = end = 0;
191
199
 
192
- while (i < text->size) {
200
+ while (i < size) {
193
201
  size_t rewind, link_end;
194
202
  char action;
195
203
 
196
- while (end < text->size && (action = active_chars[text->data[end] & 0xFF]) == 0)
204
+ while (end < size && (action = active_chars[text[end]]) == 0)
197
205
  end++;
198
206
 
199
- if (end == text->size) {
207
+ if (end == size) {
200
208
  if (link_count > 0)
201
- bufput(ob, text->data + i, end - i);
209
+ bufput(ob, text + i, end - i);
202
210
  break;
203
211
  }
204
212
 
205
213
  if (action == AUTOLINK_ACTION_SKIP_TAG) {
206
- end += autolink__skip_tag(ob, text->data + end, text->size - end);
214
+ end += autolink__skip_tag(ob,
215
+ text + end, size - end,
216
+ skip_tags, skip_tags_count);
217
+
207
218
  continue;
208
219
  }
209
220
 
210
221
  link->size = 0;
211
- link_end = g_callbacks[(int)action](&rewind, link, text->data + end, end, text->size - end);
222
+ link_end = g_callbacks[(int)action](
223
+ &rewind, link, (uint8_t *)text + end, end, size - end);
212
224
 
213
225
  /* print the link */
214
226
  if (link_end > 0) {
215
- bufput(ob, text->data + i, end - i - rewind);
227
+ bufput(ob, text + i, end - i - rewind);
216
228
 
217
229
  bufputs(ob, g_hrefs[(int)action]);
218
- autolink_escape_cb(ob, link, NULL);
230
+ houdini_escape_href(ob, link->data, link->size);
219
231
 
220
232
  if (link_attr) {
221
233
  BUFPUTSL(ob, "\" ");
@@ -258,8 +270,8 @@ autolink_callback(struct buf *link_text, const struct buf *link, void *block)
258
270
  * Document-method: auto_link
259
271
  *
260
272
  * call-seq:
261
- * auto_link(text, mode=:all, link_attr=nil)
262
- * auto_link(text, mode=:all, link_attr=nil) { |link_text| ... }
273
+ * auto_link(text, mode=:all, link_attr=nil, skip_tags=nil)
274
+ * auto_link(text, mode=:all, link_attr=nil, skip_tags=nil) { |link_text| ... }
263
275
  *
264
276
  * Parses a block of text looking for "safe" urls or email addresses,
265
277
  * and turns them into HTML links with the given attributes.
@@ -277,8 +289,9 @@ autolink_callback(struct buf *link_text, const struct buf *link, void *block)
277
289
  * HTML, Rinku is smart enough to skip the links that are already enclosed in <a>
278
290
  * tags.
279
291
  *
280
- * +mode+ is a symbol, either :all, :urls or :email_addresses, which specifies which
281
- * kind of links will be auto-linked.
292
+ * +mode+ is a symbol, either :all, :in_code, :urls or :email_addresses,
293
+ * which specifies which kind of links will be auto-linked. The :in_code symbol
294
+ * will autolink e
282
295
  *
283
296
  * +link_attr+ is a string containing the link attributes for each link that
284
297
  * will be generated. These attributes are not sanitized and will be include as-is
@@ -289,6 +302,9 @@ autolink_callback(struct buf *link_text, const struct buf *link, void *block)
289
302
  *
290
303
  * This string can be autogenerated from a hash using the Rails `tag_options` helper.
291
304
  *
305
+ * +skip_tags+ is a list of strings with the names of HTML tags that will be skipped
306
+ * when autolinking. If nil, this defaults to ["a", "pre", "code", "kbd", "script"].
307
+ *
292
308
  * +block+ The method takes an optional block argument. If a block is passed, it will
293
309
  * be yielded for each found link in the text, and its return value will be used instead
294
310
  * of the name of the link. E.g.
@@ -301,13 +317,17 @@ autolink_callback(struct buf *link_text, const struct buf *link, void *block)
301
317
  static VALUE
302
318
  rb_rinku_autolink(int argc, VALUE *argv, VALUE self)
303
319
  {
304
- VALUE result, rb_text, rb_mode, rb_html, rb_block;
305
- struct buf input_buf = {0, 0, 0, 0, 0}, *output_buf;
320
+ static const char *SKIP_TAGS[] = {"a", "pre", "code", "kbd", "script"};
321
+
322
+ VALUE result, rb_text, rb_mode, rb_html, rb_skip, rb_block;
323
+ struct buf *output_buf;
306
324
  int link_mode, count;
307
325
  const char *link_attr = NULL;
326
+ const char **skip_tags = NULL;
327
+ size_t skip_tags_count;
308
328
  ID mode_sym;
309
329
 
310
- rb_scan_args(argc, argv, "12&", &rb_text, &rb_mode, &rb_html, &rb_block);
330
+ rb_scan_args(argc, argv, "13&", &rb_text, &rb_mode, &rb_html, &rb_skip, &rb_block);
311
331
 
312
332
  Check_Type(rb_text, T_STRING);
313
333
 
@@ -323,8 +343,27 @@ rb_rinku_autolink(int argc, VALUE *argv, VALUE self)
323
343
  link_attr = RSTRING_PTR(rb_html);
324
344
  }
325
345
 
326
- input_buf.data = RSTRING_PTR(rb_text);
327
- input_buf.size = RSTRING_LEN(rb_text);
346
+ if (!NIL_P(rb_skip)) {
347
+ long i;
348
+
349
+ Check_Type(rb_skip, T_ARRAY);
350
+
351
+ skip_tags_count = RARRAY_LEN(rb_skip);
352
+ skip_tags = malloc(sizeof(void *) * skip_tags_count);
353
+ if (!skip_tags)
354
+ rb_raise(rb_eNoMemError, "Out of memory");
355
+
356
+ for (i = 0; i < skip_tags_count; ++i) {
357
+ VALUE tag = rb_ary_entry(rb_skip, i);
358
+ Check_Type(tag, T_STRING);
359
+
360
+ skip_tags[i] = StringValueCStr(tag);
361
+ }
362
+ } else {
363
+ skip_tags = SKIP_TAGS;
364
+ skip_tags_count = sizeof(SKIP_TAGS) / sizeof(SKIP_TAGS[0]);
365
+ }
366
+
328
367
  output_buf = bufnew(32);
329
368
 
330
369
  if (mode_sym == rb_intern("all"))
@@ -339,9 +378,12 @@ rb_rinku_autolink(int argc, VALUE *argv, VALUE self)
339
378
 
340
379
  count = rinku_autolink(
341
380
  output_buf,
342
- &input_buf,
381
+ RSTRING_PTR(rb_text),
382
+ RSTRING_LEN(rb_text),
343
383
  link_mode,
344
384
  link_attr,
385
+ skip_tags,
386
+ skip_tags_count,
345
387
  RTEST(rb_block) ? &autolink_callback : NULL,
346
388
  (void*)rb_block);
347
389
 
@@ -352,6 +394,9 @@ rb_rinku_autolink(int argc, VALUE *argv, VALUE self)
352
394
  rb_enc_copy(result, rb_text);
353
395
  }
354
396
 
397
+ if (skip_tags != SKIP_TAGS)
398
+ free(skip_tags);
399
+
355
400
  bufrelease(output_buf);
356
401
  return result;
357
402
  }
data/lib/rails_rinku.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'rinku'
2
2
 
3
3
  module RailsRinku
4
- def auto_link(text, *args, &block)
4
+ def rinku_auto_link(text, *args, &block)
5
5
  return '' if text.blank?
6
6
 
7
7
  options = args.size == 2 ? {} : args.extract_options!
@@ -10,7 +10,6 @@ module RailsRinku
10
10
  options[:html] = args[1] || {}
11
11
  end
12
12
  options.reverse_merge!(:link => :all, :html => {})
13
- text = sanitize(text) unless options[:sanitize] == false
14
13
 
15
14
  Rinku.auto_link(text, options[:link], tag_options(options[:html]), &block)
16
15
  end
@@ -18,4 +17,5 @@ end
18
17
 
19
18
  module ActionView::Helpers::TextHelper
20
19
  include RailsRinku
20
+ alias_method :auto_link, :rinku_auto_link
21
21
  end
data/rinku.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rinku'
3
- s.version = '1.2.2'
3
+ s.version = '1.3.0'
4
4
  s.summary = "Mostly autolinking"
5
5
  s.description = <<-EOF
6
6
  A fast and very smart autolinking library that
@@ -20,6 +20,9 @@ Gem::Specification.new do |s|
20
20
  ext/rinku/buffer.c
21
21
  ext/rinku/buffer.h
22
22
  ext/rinku/extconf.rb
23
+ ext/rinku/houdini.h
24
+ ext/rinku/houdini_href_e.c
25
+ ext/rinku/houdini_html_e.c
23
26
  lib/rinku.rb
24
27
  lib/rails_rinku.rb
25
28
  rinku.gemspec
@@ -4,13 +4,46 @@ $LOAD_PATH.unshift "#{rootdir}/lib"
4
4
 
5
5
  require 'test/unit'
6
6
  require 'cgi'
7
+ require 'uri'
7
8
  require 'rinku'
8
9
 
9
10
  class RedcarpetAutolinkTest < Test::Unit::TestCase
11
+
12
+ SAFE_CHARS = "{}[]~'"
13
+
10
14
  def assert_linked(expected, url)
11
15
  assert_equal expected, Rinku.auto_link(url)
12
16
  end
13
17
 
18
+ def test_does_not_segfault
19
+ assert_linked "< this is just a test", "< this is just a test"
20
+ end
21
+
22
+ def test_skips_tags
23
+ html = <<-html
24
+ This is just a test. http://www.pokemon.com
25
+ <div>
26
+ More test
27
+ http://www.amd.com
28
+ </div>
29
+ <pre>
30
+ CODE www.less.es
31
+ </pre>
32
+ html
33
+
34
+ result = <<-result
35
+ This is just a test. <a href="http://www.pokemon.com">http://www.pokemon.com</a>
36
+ <div>
37
+ More test
38
+ http://www.amd.com
39
+ </div>
40
+ <pre>
41
+ CODE <a href="http://www.less.es">www.less.es</a>
42
+ </pre>
43
+ result
44
+ assert_equal result, Rinku.auto_link(html, :all, nil, ["div", "a"])
45
+ end
46
+
14
47
  def test_auto_link_with_brackets
15
48
  link1_raw = 'http://en.wikipedia.org/wiki/Sprite_(computer_graphics)'
16
49
  link1_result = generate_result(link1_raw)
@@ -128,12 +161,12 @@ class RedcarpetAutolinkTest < Test::Unit::TestCase
128
161
  http://www.mail-archive.com/rails@lists.rubyonrails.org/
129
162
  http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1
130
163
  http://en.wikipedia.org/wiki/Sprite_(computer_graphics)
131
- http://en.wikipedia.org/wiki/Texas_hold'em
164
+ http://en.wikipedia.org/wiki/Texas_hold%27em
132
165
  https://www.google.com/doku.php?id=gps:resource:scs:start
133
166
  )
134
167
 
135
168
  urls.each do |url|
136
- assert_linked %(<a href="#{CGI.escapeHTML url}">#{CGI.escapeHTML url}</a>), url
169
+ assert_linked %(<a href="#{CGI.escapeHTML URI.escape(url, SAFE_CHARS)}">#{CGI.escapeHTML url}</a>), url
137
170
  end
138
171
  end
139
172
 
@@ -212,7 +245,7 @@ class RedcarpetAutolinkTest < Test::Unit::TestCase
212
245
 
213
246
  def generate_result(link_text, href = nil)
214
247
  href ||= link_text
215
- %{<a href="#{CGI::escapeHTML href}">#{CGI::escapeHTML link_text}</a>}
248
+ %{<a href="#{CGI::escapeHTML URI.escape(href, SAFE_CHARS)}">#{CGI::escapeHTML link_text}</a>}
216
249
  end
217
250
 
218
251
  end
metadata CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
- - 2
9
- - 2
10
- version: 1.2.2
8
+ - 3
9
+ - 0
10
+ version: 1.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - "Vicent Mart\xC3\xAD"
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-19 00:00:00 +02:00
19
- default_executable:
18
+ date: 2011-11-08 00:00:00 Z
20
19
  dependencies: []
21
20
 
22
21
  description: " A fast and very smart autolinking library that\n acts as a drop-in replacement for Rails `auto_link`\n"
@@ -37,11 +36,13 @@ files:
37
36
  - ext/rinku/buffer.c
38
37
  - ext/rinku/buffer.h
39
38
  - ext/rinku/extconf.rb
39
+ - ext/rinku/houdini.h
40
+ - ext/rinku/houdini_href_e.c
41
+ - ext/rinku/houdini_html_e.c
40
42
  - lib/rinku.rb
41
43
  - lib/rails_rinku.rb
42
44
  - rinku.gemspec
43
45
  - test/autolink_test.rb
44
- has_rdoc: true
45
46
  homepage: http://github.com/tanoku/rinku
46
47
  licenses: []
47
48
 
@@ -71,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
72
  requirements: []
72
73
 
73
74
  rubyforge_project:
74
- rubygems_version: 1.6.2
75
+ rubygems_version: 1.8.6
75
76
  signing_key:
76
77
  specification_version: 3
77
78
  summary: Mostly autolinking