rinku 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/ext/rinku/rinku.c ADDED
@@ -0,0 +1,86 @@
1
+ #include <stdio.h>
2
+ #include "ruby.h"
3
+
4
+ #include "autolink.h"
5
+ #include "buffer.h"
6
+
7
+ static VALUE rb_cRinku;
8
+
9
+ extern void
10
+ upshtml_autolink(
11
+ struct buf *ob,
12
+ struct buf *text,
13
+ unsigned int flags,
14
+ const char *link_attr,
15
+ void (*link_text_cb)(struct buf *ob, const struct buf *link, void *payload),
16
+ void *payload);
17
+
18
+ static void
19
+ autolink_callback(struct buf *link_text, const struct buf *link, void *block)
20
+ {
21
+ VALUE rb_link, rb_link_text;
22
+ rb_link = rb_str_new(link->data, link->size);
23
+ rb_link_text = rb_funcall((VALUE)block, rb_intern("call"), 1, rb_link);
24
+ Check_Type(rb_link_text, T_STRING);
25
+ bufput(link_text, RSTRING_PTR(rb_link_text), RSTRING_LEN(rb_link_text));
26
+ }
27
+
28
+ static VALUE
29
+ rb_rinku_autolink(int argc, VALUE *argv, VALUE self)
30
+ {
31
+ VALUE result, rb_text, rb_mode, rb_html, rb_block;
32
+ struct buf input_buf = {0, 0, 0, 0, 0}, *output_buf;
33
+ int link_mode;
34
+ const char *link_attr = NULL;
35
+ ID mode_sym;
36
+
37
+ rb_scan_args(argc, argv, "3&", &rb_text, &rb_mode, &rb_html, &rb_block);
38
+
39
+ Check_Type(rb_text, T_STRING);
40
+ Check_Type(rb_mode, T_SYMBOL);
41
+
42
+ if (!NIL_P(rb_html)) {
43
+ Check_Type(rb_html, T_STRING);
44
+ link_attr = RSTRING_PTR(rb_html);
45
+ }
46
+
47
+ input_buf.data = RSTRING_PTR(rb_text);
48
+ input_buf.size = RSTRING_LEN(rb_text);
49
+ output_buf = bufnew(128);
50
+
51
+ mode_sym = SYM2ID(rb_mode);
52
+
53
+ if (mode_sym == rb_intern("all"))
54
+ link_mode = AUTOLINK_ALL;
55
+ else if (mode_sym == rb_intern("email_addresses"))
56
+ link_mode = AUTOLINK_EMAILS;
57
+ else if (mode_sym == rb_intern("urls"))
58
+ link_mode = AUTOLINK_URLS;
59
+ else
60
+ rb_raise(rb_eTypeError,
61
+ "Invalid linking mode (possible values are :all, :urls, :email_addresses)");
62
+
63
+ if (RTEST(rb_block))
64
+ upshtml_autolink(output_buf, &input_buf, AUTOLINK_ALL, link_attr, &autolink_callback, (void*)rb_block);
65
+ else
66
+ upshtml_autolink(output_buf, &input_buf, AUTOLINK_ALL, link_attr, NULL, NULL);
67
+
68
+ result = rb_str_new(output_buf->data, output_buf->size);
69
+ bufrelease(output_buf);
70
+
71
+ /* force the input encoding */
72
+ if (rb_respond_to(rb_text, rb_intern("encoding"))) {
73
+ VALUE encoding = rb_funcall(rb_text, rb_intern("encoding"), 0);
74
+ rb_funcall(result, rb_intern("force_encoding"), 1, encoding);
75
+ }
76
+
77
+ return result;
78
+ }
79
+
80
+ void Init_rinku()
81
+ {
82
+ rb_cRinku = rb_define_class("Rinku", rb_cObject);
83
+ rb_define_singleton_method(rb_cRinku, "_auto_link", rb_rinku_autolink, -1);
84
+ }
85
+
86
+
data/lib/rinku.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'set'
2
+ require 'cgi'
3
+
4
+ class Rinku
5
+ def self.auto_link(text, *args, &block)
6
+ return '' if text.strip.empty?
7
+
8
+ options = args.size == 2 ? {} : (args.last.is_a?(::Hash) ? args.pop : {})
9
+ unless args.empty?
10
+ options[:link] = args[0] || :all
11
+ options[:html] = args[1] || {}
12
+ end
13
+
14
+ _auto_link(text, options[:link] || :all, tag_options(options[:html] || {}), &block)
15
+ end
16
+
17
+ private
18
+ BOOLEAN_ATTRIBUTES = %w(disabled readonly multiple checked autobuffer
19
+ autoplay controls loop selected hidden scoped async
20
+ defer reversed ismap seemless muted required
21
+ autofocus novalidate formnovalidate open).to_set
22
+
23
+ def self.tag_options(options, escape = true)
24
+ unless options.empty?
25
+ attrs = []
26
+ options.each_pair do |key, value|
27
+ key = key.to_s
28
+ if BOOLEAN_ATTRIBUTES.include?(key)
29
+ attrs << %(#{key}="#{key}") if value
30
+ elsif !value.nil?
31
+ final_value = value.is_a?(Array) ? value.join(" ") : value
32
+ final_value = CGI.escapeHTML(final_value) if escape
33
+ attrs << %(#{key}="#{final_value}")
34
+ end
35
+ end
36
+ " #{attrs.sort * ' '}" unless attrs.empty?
37
+ end
38
+ end
39
+ end
40
+
41
+ require 'rinku.so'
data/rinku.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'rinku'
3
+ s.version = File.open('VERSION').read.strip
4
+ s.summary = "Mostly autolinking"
5
+ s.description = <<-EOF
6
+ A fast and very smart autolinking library that
7
+ acts as a drop-in replacement for Rails `auto_link`
8
+ EOF
9
+ s.email = 'vicent@github.com'
10
+ s.homepage = 'http://github.com/tanoku/rinku'
11
+ s.authors = ["Vicent Martí"]
12
+ # = MANIFEST =
13
+ s.files = %w[
14
+ COPYING
15
+ VERSION
16
+ README.markdown
17
+ Rakefile
18
+ ext/rinku/rinku.c
19
+ ext/rinku/autolink.c
20
+ ext/rinku/autolink.h
21
+ ext/rinku/buffer.c
22
+ ext/rinku/buffer.h
23
+ ext/rinku/html_autolink.c
24
+ ext/rinku/extconf.rb
25
+ lib/rinku.rb
26
+ rinku.gemspec
27
+ test/autolink_test.rb
28
+ ]
29
+ # = MANIFEST =
30
+ s.test_files = ["test/autolink_test.rb"]
31
+ s.extra_rdoc_files = ["COPYING"]
32
+ s.extensions = ["ext/rinku/extconf.rb"]
33
+ s.require_paths = ["lib"]
34
+ end
@@ -0,0 +1,135 @@
1
+ # encoding: utf-8
2
+ rootdir = File.dirname(File.dirname(__FILE__))
3
+ $LOAD_PATH.unshift "#{rootdir}/lib"
4
+
5
+ require 'test/unit'
6
+ require 'cgi'
7
+ require 'rinku'
8
+
9
+ class RedcarpetAutolinkTest < Test::Unit::TestCase
10
+ def assert_linked(expected, url)
11
+ assert_equal expected, Rinku.auto_link(url)
12
+ end
13
+
14
+ def test_block
15
+ link = Rinku.auto_link("Find ur favorite pokeman @ http://www.pokemon.com") do |url|
16
+ assert_equal url, "http://www.pokemon.com"
17
+ "POKEMAN WEBSITE"
18
+ end
19
+
20
+ assert_equal link, "Find ur favorite pokeman @ <a href=\"http://www.pokemon.com\">POKEMAN WEBSITE</a>"
21
+ end
22
+
23
+ def test_link_attributes
24
+ assert_equal Rinku.auto_link("http://www.bash.org", :html => {:target => "_blank"}),
25
+ "<a target=\"_blank\" href=\"http://www.bash.org\">http://www.bash.org</a>"
26
+ end
27
+
28
+ def test_autolink_works
29
+ url = "http://example.com/"
30
+ assert_linked "<a href=\"#{url}\">#{url}</a>", url
31
+ end
32
+
33
+ def test_not_autolink_www
34
+ assert_linked "Awww... man", "Awww... man"
35
+ end
36
+
37
+ def test_does_not_terminate_on_dash
38
+ url = "http://example.com/Notification_Center-GitHub-20101108-140050.jpg"
39
+ assert_linked "<a href=\"#{url}\">#{url}</a>", url
40
+ end
41
+
42
+ def test_does_not_include_trailing_gt
43
+ url = "http://example.com"
44
+ assert_linked "&lt;<a href=\"#{url}\">#{url}</a>&gt;", "&lt;#{url}&gt;"
45
+ end
46
+
47
+ def test_links_with_anchors
48
+ url = "https://github.com/github/hubot/blob/master/scripts/cream.js#L20-20"
49
+ assert_linked "<a href=\"#{url}\">#{url}</a>", url
50
+ end
51
+
52
+ def test_links_like_rails
53
+ urls = %w(http://www.rubyonrails.com
54
+ http://www.rubyonrails.com:80
55
+ http://www.rubyonrails.com/~minam
56
+ https://www.rubyonrails.com/~minam
57
+ http://www.rubyonrails.com/~minam/url%20with%20spaces
58
+ http://www.rubyonrails.com/foo.cgi?something=here
59
+ http://www.rubyonrails.com/foo.cgi?something=here&and=here
60
+ http://www.rubyonrails.com/contact;new
61
+ http://www.rubyonrails.com/contact;new%20with%20spaces
62
+ http://www.rubyonrails.com/contact;new?with=query&string=params
63
+ http://www.rubyonrails.com/~minam/contact;new?with=query&string=params
64
+ http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007
65
+ http://www.mail-archive.com/rails@lists.rubyonrails.org/
66
+ http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1
67
+ http://en.wikipedia.org/wiki/Sprite_(computer_graphics)
68
+ http://en.wikipedia.org/wiki/Texas_hold'em
69
+ https://www.google.com/doku.php?id=gps:resource:scs:start
70
+ )
71
+
72
+ urls.each do |url|
73
+ assert_linked %(<a href="#{url}">#{CGI.escapeHTML(url)}</a>), url
74
+ end
75
+ end
76
+
77
+ def test_links_like_autolink_rails
78
+ email_raw = 'david@loudthinking.com'
79
+ email_result = %{<a href="mailto:#{email_raw}">#{email_raw}</a>}
80
+ email2_raw = '+david@loudthinking.com'
81
+ email2_result = %{<a href="mailto:#{email2_raw}">#{email2_raw}</a>}
82
+ link_raw = 'http://www.rubyonrails.com'
83
+ link_result = %{<a href="#{link_raw}">#{link_raw}</a>}
84
+ link_result_with_options = %{<a href="#{link_raw}" target="_blank">#{link_raw}</a>}
85
+ link2_raw = 'www.rubyonrails.com'
86
+ link2_result = %{<a href="http://#{link2_raw}">#{link2_raw}</a>}
87
+ link3_raw = 'http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281'
88
+ link3_result = %{<a href="#{link3_raw}">#{link3_raw}</a>}
89
+ link4_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor123'
90
+ link4_result = %{<a href="#{link4_raw}">#{CGI.escapeHTML(link4_raw)}</a>}
91
+ link5_raw = 'http://foo.example.com:3000/controller/action'
92
+ link5_result = %{<a href="#{link5_raw}">#{link5_raw}</a>}
93
+ link6_raw = 'http://foo.example.com:3000/controller/action+pack'
94
+ link6_result = %{<a href="#{link6_raw}">#{link6_raw}</a>}
95
+ link7_raw = 'http://foo.example.com/controller/action?parm=value&p2=v2#anchor-123'
96
+ link7_result = %{<a href="#{link7_raw}">#{CGI.escapeHTML(link7_raw)}</a>}
97
+ link8_raw = 'http://foo.example.com:3000/controller/action.html'
98
+ link8_result = %{<a href="#{link8_raw}">#{link8_raw}</a>}
99
+ link9_raw = 'http://business.timesonline.co.uk/article/0,,9065-2473189,00.html'
100
+ link9_result = %{<a href="#{link9_raw}">#{link9_raw}</a>}
101
+ link10_raw = 'http://www.mail-archive.com/ruby-talk@ruby-lang.org/'
102
+ link10_result = %{<a href="#{link10_raw}">#{link10_raw}</a>}
103
+
104
+ assert_linked %(Go to #{link_result} and say hello to #{email_result}), "Go to #{link_raw} and say hello to #{email_raw}"
105
+ assert_linked %(<p>Link #{link_result}</p>), "<p>Link #{link_raw}</p>"
106
+ assert_linked %(<p>#{link_result} Link</p>), "<p>#{link_raw} Link</p>"
107
+ assert_linked %(Go to #{link_result}.), %(Go to #{link_raw}.)
108
+ assert_linked %(<p>Go to #{link_result}, then say hello to #{email_result}.</p>), %(<p>Go to #{link_raw}, then say hello to #{email_raw}.</p>)
109
+ assert_linked %(<p>Link #{link2_result}</p>), "<p>Link #{link2_raw}</p>"
110
+ assert_linked %(<p>#{link2_result} Link</p>), "<p>#{link2_raw} Link</p>"
111
+ assert_linked %(Go to #{link2_result}.), %(Go to #{link2_raw}.)
112
+ assert_linked %(<p>Say hello to #{email_result}, then go to #{link2_result},</p>), %(<p>Say hello to #{email_raw}, then go to #{link2_raw},</p>)
113
+ assert_linked %(<p>Link #{link3_result}</p>), "<p>Link #{link3_raw}</p>"
114
+ assert_linked %(<p>#{link3_result} Link</p>), "<p>#{link3_raw} Link</p>"
115
+ assert_linked %(Go to #{link3_result}.), %(Go to #{link3_raw}.)
116
+ assert_linked %(<p>Go to #{link3_result}. seriously, #{link3_result}? i think I'll say hello to #{email_result}. instead.</p>), %(<p>Go to #{link3_raw}. seriously, #{link3_raw}? i think I'll say hello to #{email_raw}. instead.</p>)
117
+ assert_linked %(<p>Link #{link4_result}</p>), "<p>Link #{link4_raw}</p>"
118
+ assert_linked %(<p>#{link4_result} Link</p>), "<p>#{link4_raw} Link</p>"
119
+ assert_linked %(<p>#{link5_result} Link</p>), "<p>#{link5_raw} Link</p>"
120
+ assert_linked %(<p>#{link6_result} Link</p>), "<p>#{link6_raw} Link</p>"
121
+ assert_linked %(<p>#{link7_result} Link</p>), "<p>#{link7_raw} Link</p>"
122
+ assert_linked %(<p>Link #{link8_result}</p>), "<p>Link #{link8_raw}</p>"
123
+ assert_linked %(<p>#{link8_result} Link</p>), "<p>#{link8_raw} Link</p>"
124
+ assert_linked %(Go to #{link8_result}.), %(Go to #{link8_raw}.)
125
+ assert_linked %(<p>Go to #{link8_result}. seriously, #{link8_result}? i think I'll say hello to #{email_result}. instead.</p>), %(<p>Go to #{link8_raw}. seriously, #{link8_raw}? i think I'll say hello to #{email_raw}. instead.</p>)
126
+ assert_linked %(<p>Link #{link9_result}</p>), "<p>Link #{link9_raw}</p>"
127
+ assert_linked %(<p>#{link9_result} Link</p>), "<p>#{link9_raw} Link</p>"
128
+ assert_linked %(Go to #{link9_result}.), %(Go to #{link9_raw}.)
129
+ assert_linked %(<p>Go to #{link9_result}. seriously, #{link9_result}? i think I'll say hello to #{email_result}. instead.</p>), %(<p>Go to #{link9_raw}. seriously, #{link9_raw}? i think I'll say hello to #{email_raw}. instead.</p>)
130
+ assert_linked %(<p>#{link10_result} Link</p>), "<p>#{link10_raw} Link</p>"
131
+ assert_linked email2_result, email2_raw
132
+ assert_linked "#{link_result} #{link_result} #{link_result}", "#{link_raw} #{link_raw} #{link_raw}"
133
+ assert_linked '<a href="http://www.rubyonrails.com">Ruby On Rails</a>', '<a href="http://www.rubyonrails.com">Ruby On Rails</a>'
134
+ end
135
+ end
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rinku
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - "Vicent Mart\xC3\xAD"
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-06-09 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: " A fast and very smart autolinking library that\n acts as a drop-in replacement for Rails `auto_link`\n"
23
+ email: vicent@github.com
24
+ executables: []
25
+
26
+ extensions:
27
+ - ext/rinku/extconf.rb
28
+ extra_rdoc_files:
29
+ - COPYING
30
+ files:
31
+ - COPYING
32
+ - VERSION
33
+ - README.markdown
34
+ - Rakefile
35
+ - ext/rinku/rinku.c
36
+ - ext/rinku/autolink.c
37
+ - ext/rinku/autolink.h
38
+ - ext/rinku/buffer.c
39
+ - ext/rinku/buffer.h
40
+ - ext/rinku/html_autolink.c
41
+ - ext/rinku/extconf.rb
42
+ - lib/rinku.rb
43
+ - rinku.gemspec
44
+ - test/autolink_test.rb
45
+ has_rdoc: true
46
+ homepage: http://github.com/tanoku/rinku
47
+ licenses: []
48
+
49
+ post_install_message:
50
+ rdoc_options: []
51
+
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ hash: 3
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.7
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Mostly autolinking
79
+ test_files:
80
+ - test/autolink_test.rb