breakout_parser 0.0.23 → 0.0.31
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/ChangeLog +19 -0
- data/README +23 -11
- data/ext/breakout_parser/extconf.rb +10 -5
- data/ext/breakout_parser/parser.h +27 -0
- data/ext/breakout_parser/parser.l +22 -6
- data/ext/breakout_parser/parser.y +294 -126
- data/ext/breakout_parser/ruby_ext.c +51 -22
- data/ext/breakout_parser/ruby_ext.h +2 -0
- data/spec/links_only_parser_spec.rb +916 -0
- data/spec/obj_proxy.rb +22 -0
- data/spec/parser_examples_spec.rb +115 -0
- data/spec/parser_spec.rb +146 -34
- data/spec/spec_helper.rb +1 -0
- metadata +89 -62
- data/ext/breakout_parser/lex.yy.c +0 -2996
- data/ext/breakout_parser/parser.tab.c +0 -2482
- data/ext/breakout_parser/parser.tab.h +0 -113
@@ -1,6 +1,13 @@
|
|
1
1
|
#ifdef RUBY_VERSION
|
2
2
|
|
3
3
|
#include "ruby.h"
|
4
|
+
#include "ruby_ext.h"
|
5
|
+
|
6
|
+
#ifdef RUBY_19
|
7
|
+
#include "ruby/st.h"
|
8
|
+
#else
|
9
|
+
#include "st.h"
|
10
|
+
#endif
|
4
11
|
|
5
12
|
void Init_breakout_parser();
|
6
13
|
VALUE method_parse(int, VALUE*, VALUE);
|
@@ -20,55 +27,78 @@ extern const char *space_name;
|
|
20
27
|
extern size_t in_buf_len, bufsize, space_name_len;
|
21
28
|
|
22
29
|
extern const char *site_url;
|
30
|
+
extern const char *large_files_url;
|
23
31
|
extern size_t site_url_len;
|
32
|
+
extern size_t large_files_url_len;
|
33
|
+
|
34
|
+
extern VALUE meta_attributes;
|
24
35
|
|
25
36
|
VALUE vcs_url;
|
26
37
|
|
38
|
+
char **temp_names, **temp_values;
|
39
|
+
|
27
40
|
extern int parse_links_only, absolute_urls;
|
28
41
|
|
29
42
|
VALUE do_parse(int argc, VALUE *argv, VALUE self) {
|
30
43
|
VALUE s, text, r_space_name;
|
31
44
|
char *p;
|
32
45
|
|
33
|
-
if(
|
34
|
-
rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..
|
35
|
-
return rb_str_new("",0); // unreachable code, but for double safety
|
46
|
+
if (argc < 2 || argc > 7) {
|
47
|
+
rb_raise(rb_eArgError, "wrong number of arguments (%d for 2..7)", argc);
|
36
48
|
}
|
37
49
|
|
38
50
|
text = argv[0];
|
39
51
|
r_space_name = argv[1];
|
40
52
|
|
41
53
|
site_url = NULL; site_url_len = 0;
|
42
|
-
if(
|
54
|
+
if (argc > 2 && RTEST(argv[2])){
|
43
55
|
site_url = StringValueCStr(argv[2]);
|
44
56
|
site_url_len = site_url ? strlen(site_url) : 0;
|
45
57
|
while( site_url && site_url_len > 0 && site_url[site_url_len-1] == '/' ) {
|
46
58
|
// skip trailing slashes
|
47
|
-
site_url_len--;
|
59
|
+
site_url_len--;
|
48
60
|
}
|
49
61
|
}
|
50
62
|
|
51
|
-
vcs_url =
|
52
|
-
if(
|
63
|
+
vcs_url = rb_str_new2("");
|
64
|
+
if (argc > 3 && RTEST(argv[3])) {
|
53
65
|
vcs_url = argv[3];
|
54
66
|
}
|
55
67
|
|
56
68
|
absolute_urls = 0;
|
57
|
-
if(
|
69
|
+
if (argc > 4 && RTEST(argv[4])) {
|
58
70
|
absolute_urls = 1;
|
59
71
|
}
|
60
72
|
|
61
|
-
|
62
|
-
|
63
|
-
|
73
|
+
large_files_url = NULL; large_files_url_len = 0;
|
74
|
+
if (argc > 5 && RTEST(argv[5])) {
|
75
|
+
large_files_url = StringValueCStr(argv[5]);
|
76
|
+
large_files_url_len = large_files_url ? strlen(large_files_url) : 0;
|
64
77
|
}
|
65
78
|
|
66
|
-
|
67
|
-
|
79
|
+
meta_attributes = rb_hash_new();
|
80
|
+
if (argc > 6 && RTEST(argv[6])) {
|
81
|
+
// More information about object types may be found in ruby.h
|
82
|
+
if (TYPE(argv[6]) != T_HASH) {
|
83
|
+
rb_raise(rb_eTypeError, "wrong type of meta attributes values; expected Hash, given %d", TYPE(argv[6]));
|
84
|
+
}
|
85
|
+
|
86
|
+
if (RHASH_SIZE(argv[6]) > 0) {
|
87
|
+
meta_attributes = argv[6];
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
if(!text || !(RTEST(text))){
|
92
|
+
// empty input string
|
93
|
+
return rb_str_new2("");
|
94
|
+
}
|
95
|
+
|
96
|
+
p = RSTRING_PTR(text);
|
97
|
+
in_buf_len = RSTRING_LEN(text);
|
68
98
|
|
69
99
|
if(!p || in_buf_len <= 0){
|
70
100
|
// empty input string
|
71
|
-
return
|
101
|
+
return rb_str_new2("");
|
72
102
|
}
|
73
103
|
|
74
104
|
while( in_buf_len > 0 && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')){
|
@@ -84,25 +114,24 @@ VALUE do_parse(int argc, VALUE *argv, VALUE self) {
|
|
84
114
|
bufsize = 1 + in_buf_len + in_buf_len/3; // reserve 30% of in_buf size
|
85
115
|
if(bufsize<0x100) bufsize = 0x100;
|
86
116
|
|
87
|
-
buf = ALLOC_N(char, bufsize);
|
117
|
+
buf = ALLOC_N(char, bufsize);
|
88
118
|
bufptr = buf;
|
89
119
|
|
90
|
-
// protect buf from GC (theoretically)
|
91
|
-
rb_iv_set(self,"@obj",Data_Wrap_Struct(rb_cData,NULL,NULL,buf));
|
92
|
-
|
93
120
|
yyparse();
|
94
121
|
yylex_destroy();
|
95
|
-
//
|
122
|
+
// printf("[.] yyparse() ended\n");
|
96
123
|
|
97
124
|
// make ruby string from our char[] data
|
98
|
-
s = rb_str_new(buf,bufptr-buf);
|
125
|
+
s = rb_str_new(buf, bufptr-buf);
|
99
126
|
|
100
|
-
// cleanup
|
101
|
-
rb_iv_set(self,"@obj",Qnil);
|
102
127
|
xfree(buf);
|
103
128
|
buf = bufptr = NULL;
|
104
129
|
bufsize = 0;
|
105
130
|
|
131
|
+
#ifdef RUBY_19
|
132
|
+
s = rb_funcall(s, rb_intern("force_encoding"), 1, rb_str_new2("UTF-8")); // encode string to UTF-8
|
133
|
+
#endif
|
134
|
+
|
106
135
|
return s;
|
107
136
|
}
|
108
137
|
|
@@ -0,0 +1,916 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'spec_helper'
|
3
|
+
require File.dirname(__FILE__) + '/obj_proxy'
|
4
|
+
|
5
|
+
describe 'BreakoutParser' do
|
6
|
+
def self.hex_string s
|
7
|
+
## sexier, but not runs on ruby 1.8.6 patchlevel 383 i386-mingw32:
|
8
|
+
#s.each_byte.to_a.map{ |c| "%02x" % c }.join
|
9
|
+
r = ''
|
10
|
+
s.each_byte{ |c| r << "%02x" % c }
|
11
|
+
r
|
12
|
+
end
|
13
|
+
def hex_string s; self.class.hex_string(s); end
|
14
|
+
|
15
|
+
it 'accepts from 2 to 7 arguments' do
|
16
|
+
expect { BreakoutParser.parse }.to raise_error(ArgumentError, "wrong number of arguments (0 for 2..7)")
|
17
|
+
expect { BreakoutParser.parse('a') }.to raise_error(ArgumentError, "wrong number of arguments (1 for 2..7)")
|
18
|
+
[9, 10].each do |argc|
|
19
|
+
expect { BreakoutParser.parse(*(['a'] * (argc - 1) + [{}])) }.to raise_error(ArgumentError, "wrong number of arguments (#{argc} for 2..7)")
|
20
|
+
end
|
21
|
+
(2..6).each do |argc|
|
22
|
+
expect { BreakoutParser.parse(*(['a'] * argc)) }.to_not raise_error(ArgumentError)
|
23
|
+
end
|
24
|
+
expect { BreakoutParser.parse(*(['a'] * 6 + [{}])) }.to_not raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'converts \n to <br />' do
|
28
|
+
parse("aaa\nbbb").should match(%r"aaa ?<br /> ?bbb")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "parses 1M file #1" do
|
32
|
+
s = 'a' * 1024 * 1024
|
33
|
+
parse(s).size.should == s.size
|
34
|
+
end
|
35
|
+
|
36
|
+
it "parses 1M file #2" do
|
37
|
+
s = 'a' + (' ' * 1024 * 1024) + 'b'
|
38
|
+
parse(s).should == 'a b'
|
39
|
+
end
|
40
|
+
|
41
|
+
it "parses 1M file #3" do
|
42
|
+
s = 'a ' * 1024 * 512
|
43
|
+
parse(s).size.should == s.strip.size
|
44
|
+
end
|
45
|
+
|
46
|
+
it "handles nil & false text well" do
|
47
|
+
parse(false).should == ""
|
48
|
+
parse(false, :space_name => false).should == ""
|
49
|
+
parse("", :space_name => false).should == ""
|
50
|
+
parse(nil).should == ""
|
51
|
+
parse(nil, :space_name => nil).should == ""
|
52
|
+
parse("", :space_name => nil).should == ""
|
53
|
+
end
|
54
|
+
|
55
|
+
it "handles nil space_name well" do
|
56
|
+
lambda{
|
57
|
+
parse("#123", :space_name => nil)
|
58
|
+
}.should raise_error(TypeError)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "handles false space_name well" do
|
62
|
+
lambda{
|
63
|
+
parse("#123", :space_name => false)
|
64
|
+
}.should raise_error(TypeError)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "strips tailing spaces and newlines" do
|
68
|
+
parse("aaa ").should == "aaa"
|
69
|
+
parse("aaa\t\t\t\t\t\t").should == "aaa"
|
70
|
+
parse("aaa\r\r\r\r\r").should == "aaa"
|
71
|
+
parse("aaa\n\n\n\n\n").should == "aaa"
|
72
|
+
parse("aaa\r\n\r\n\r\n\r\n").should == "aaa"
|
73
|
+
parse("aaa\r\n\t \t \n \r \n \t \t\n\r ").should == "aaa"
|
74
|
+
end
|
75
|
+
|
76
|
+
it "strips leading spaces and newlines" do
|
77
|
+
parse(" aaa").should == "aaa"
|
78
|
+
parse("\t\t\t\t\t\taaa").should == "aaa"
|
79
|
+
parse("\r\r\r\r\raaa").should == "aaa"
|
80
|
+
parse("\n\n\n\n\naaa").should == "aaa"
|
81
|
+
parse("\r\n\r\n\r\n\r\naaa").should == "aaa"
|
82
|
+
parse("\r\n\t \t \n \r \n \t \t\n\r aaa").should == "aaa"
|
83
|
+
end
|
84
|
+
|
85
|
+
it "converts each newline to <br />" do
|
86
|
+
parse("aaa\n\nbbb").should == "aaa<br /><br />bbb"
|
87
|
+
parse("aaa\n \nbbb").should == "aaa<br /><br />bbb"
|
88
|
+
parse("aaa\n\n\nbbb").should == "aaa<br /><br /><br />bbb"
|
89
|
+
parse("aaa\n \n \nbbb").should == "aaa<br /><br /><br />bbb"
|
90
|
+
parse("aaa\r\n \r\n \r\nbbb").should == "aaa<br /><br /><br />bbb"
|
91
|
+
parse("aaa\n \n\n \nbbb").should == "aaa<br /><br /><br /><br />bbb"
|
92
|
+
parse("aaa\n \n\n\n \nbbb").should == "aaa" + "<br />"*5 + "bbb"
|
93
|
+
parse("aaa\n\n\n\n\n\n\nbbb").should == "aaa" + "<br />"*7 + "bbb"
|
94
|
+
parse("aaa\r\n\r\n\r\nbbb").should == "aaa" + "<br />"*3 + "bbb"
|
95
|
+
end
|
96
|
+
|
97
|
+
###############################################################################
|
98
|
+
|
99
|
+
describe "@code@" do
|
100
|
+
it "only" do
|
101
|
+
parse("@smth@").should == '@smth@'
|
102
|
+
end
|
103
|
+
it "at beginning" do
|
104
|
+
parse("@smth@\nxxx").should == '@smth@<br />xxx'
|
105
|
+
end
|
106
|
+
it "in the middle of text" do
|
107
|
+
parse("xxx @smth@ yyy").should == 'xxx @smth@ yyy'
|
108
|
+
end
|
109
|
+
it "parses @multiline\\nsmth@" do
|
110
|
+
parse("@multiline\nsmth@").should == "@multiline<br />smth@"
|
111
|
+
end
|
112
|
+
it "not confuses" do
|
113
|
+
parse("look at @this code@ and mail me at xxx@yyy.com").should ==
|
114
|
+
'look at @this code@ and mail me at <a href="mailto:xxx@yyy.com">xxx@yyy.com</a>'
|
115
|
+
end
|
116
|
+
it "w/o closing tag" do
|
117
|
+
parse("@smth").should == '@smth'
|
118
|
+
end
|
119
|
+
it "nesting1 w/o closing tags" do
|
120
|
+
parse("@smth1 @smth2").should == '@smth1 @smth2'
|
121
|
+
end
|
122
|
+
it "nesting2 w/o closing tags" do
|
123
|
+
parse("@smth1 @smth2").should == '@smth1 @smth2'
|
124
|
+
end
|
125
|
+
it "two times" do
|
126
|
+
parse("@code1@ @code2@").should == "@code1@ @code2@"
|
127
|
+
parse("@code1@ @code2@").should == "@code1@ @code2@"
|
128
|
+
parse(" @code1@ @code2@ ").should == "@code1@ @code2@"
|
129
|
+
parse(" @code1@ xxx @code2@ ").should == "@code1@ xxx @code2@"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
###############################################################################
|
134
|
+
|
135
|
+
describe "*bold*" do
|
136
|
+
it "only" do
|
137
|
+
parse("*bold*").should == '*bold*'
|
138
|
+
end
|
139
|
+
it "at beginning" do
|
140
|
+
parse("*bold*\nxxx").should == "*bold*<br />xxx"
|
141
|
+
end
|
142
|
+
it "in the middle of text" do
|
143
|
+
parse("xxx *bold* yyy").should == "xxx *bold* yyy"
|
144
|
+
end
|
145
|
+
it "parses *multiline\\nbold*" do
|
146
|
+
parse("*multiline\nbold*").should == "*multiline<br />bold*"
|
147
|
+
end
|
148
|
+
it "skips lone star inside bold block" do
|
149
|
+
parse("*aaa * bbb*").should == "*aaa * bbb*"
|
150
|
+
end
|
151
|
+
it "skips lone star" do
|
152
|
+
parse("aaa * bbb").should == 'aaa * bbb'
|
153
|
+
end
|
154
|
+
it "w/o closing tag" do
|
155
|
+
parse("*bold").should == '*bold'
|
156
|
+
end
|
157
|
+
it "nesting1 w/o closing tags" do
|
158
|
+
parse("*bold1 *bold2").should == "*bold1 *bold2"
|
159
|
+
end
|
160
|
+
it "nesting2 w/o closing tags" do
|
161
|
+
parse("*bold1 *bold2").should == "*bold1 *bold2"
|
162
|
+
end
|
163
|
+
|
164
|
+
it "not parses '*.*'" do
|
165
|
+
parse("*.*").should == "*.*"
|
166
|
+
parse(" *.* ").should == "*.*"
|
167
|
+
parse("aaa *.* bbb").should == "aaa *.* bbb"
|
168
|
+
end
|
169
|
+
|
170
|
+
it "not parses '*.something'" do
|
171
|
+
parse("*.exe").should == "*.exe"
|
172
|
+
parse(" *.exe ").should == "*.exe"
|
173
|
+
parse("aaa *.exe bbb").should == "aaa *.exe bbb"
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
###############################################################################
|
179
|
+
|
180
|
+
describe "_italic_" do
|
181
|
+
it "only" do
|
182
|
+
s = "_italic_"
|
183
|
+
parse(s).should == s
|
184
|
+
end
|
185
|
+
it "at beginning" do
|
186
|
+
s = "_italic_\nxxx"
|
187
|
+
parse(s).should == s.gsub("\n","<br />")
|
188
|
+
end
|
189
|
+
it "in the middle of text" do
|
190
|
+
s = "xxx _italic_ yyy"
|
191
|
+
parse(s).should == s
|
192
|
+
end
|
193
|
+
it "parses _multiline\\nitalic_" do
|
194
|
+
s = "_multiline\nitalic_"
|
195
|
+
parse(s).should == s.gsub("\n","<br />")
|
196
|
+
end
|
197
|
+
it "skips lone underscore inside italic block" do
|
198
|
+
s = "_aaa _ bbb_"
|
199
|
+
parse(s).should == s
|
200
|
+
end
|
201
|
+
it "skips lone underscore" do
|
202
|
+
s = "aaa _ bbb"
|
203
|
+
parse(s).should == s
|
204
|
+
end
|
205
|
+
it "w/o closing tag" do
|
206
|
+
s = "_italic"
|
207
|
+
parse(s).should == s
|
208
|
+
end
|
209
|
+
it "nesting1 w/o closing tags" do
|
210
|
+
s = "_italic1 _italic2"
|
211
|
+
parse(s).should == s
|
212
|
+
end
|
213
|
+
it "nesting2 w/o closing tags" do
|
214
|
+
s = "_italic1 _italic2"
|
215
|
+
parse(s).should == s.gsub(/ +/,' ')
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
###############################################################################
|
220
|
+
|
221
|
+
describe "combinations" do
|
222
|
+
it "bold in italic" do
|
223
|
+
s = "_aaa *bbb* ccc_"
|
224
|
+
parse(s).should == s
|
225
|
+
end
|
226
|
+
it "bold in italic - no closing1" do
|
227
|
+
s = "_aaa *bbb* ccc"
|
228
|
+
parse(s).should == s
|
229
|
+
end
|
230
|
+
it "bold in italic - no closing2" do
|
231
|
+
s = "_aaa *bbb ccc"
|
232
|
+
parse(s).should == s
|
233
|
+
end
|
234
|
+
|
235
|
+
it "italic in bold" do
|
236
|
+
s = "*aaa _bbb_ ccc*"
|
237
|
+
parse(s).should == s
|
238
|
+
end
|
239
|
+
it "italic in bold - no closing1" do
|
240
|
+
s = "*aaa _bbb_ ccc"
|
241
|
+
parse(s).should == s
|
242
|
+
end
|
243
|
+
it "italic in bold - no closing2" do
|
244
|
+
s = "*aaa _bbb ccc"
|
245
|
+
parse(s).should == s
|
246
|
+
end
|
247
|
+
|
248
|
+
{'ul' => '*', 'ol' => '#'}.each do |l,c|
|
249
|
+
it "raw text link inside #{l.upcase}> #1" do
|
250
|
+
s = "#{c} aaa http://www.ru"
|
251
|
+
parse(s).should == "#{c} aaa <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a>"
|
252
|
+
end
|
253
|
+
it "raw text link inside #{l.upcase}> #2" do
|
254
|
+
s = "#{c} aaa http://www.ru\n#{c} bbb"
|
255
|
+
parse(s).should == "#{c} aaa <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a><br />#{c} bbb"
|
256
|
+
end
|
257
|
+
it "raw text link inside #{l.upcase}> #3" do
|
258
|
+
s = "#{c} http://www.ru"
|
259
|
+
parse(s).should == "#{c} <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a>"
|
260
|
+
end
|
261
|
+
it "raw text link inside #{l.upcase}> #4" do
|
262
|
+
s = "#{c} aaa http://www.ru bbb"
|
263
|
+
parse(s).should == "#{c} aaa <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a> bbb"
|
264
|
+
end
|
265
|
+
it "two links inside #{l.upcase}>" do
|
266
|
+
s = "#{c} aaa http://www.ru http://ya.ru bbb"
|
267
|
+
parse(s).should == "#{c} aaa <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a> <a rel=\"nofollow\" href=\"http://ya.ru\">http://ya.ru</a> bbb"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
###############################################################################
|
273
|
+
|
274
|
+
describe "IGNORES unnumbered lists" do
|
275
|
+
it "should ignore" do
|
276
|
+
parse("* a\n* b\n* c").should == "* a<br />* b<br />* c"
|
277
|
+
end
|
278
|
+
it "two lists" do
|
279
|
+
s = "* a\n* b\n* c"
|
280
|
+
s = s + "\nxxx\n" + s
|
281
|
+
parse(s).should == "* a<br />* b<br />* c<br />xxx<br />* a<br />* b<br />* c"
|
282
|
+
end
|
283
|
+
it "in middle of text when begins with space" do
|
284
|
+
parse("hello\n * a\n * b\n * c\nworld").should ==
|
285
|
+
"hello<br />* a<br />* b<br />* c<br />world"
|
286
|
+
end
|
287
|
+
it "in middle of text" do
|
288
|
+
parse("hello\n* a\n* b\n* c\nworld").should ==
|
289
|
+
"hello<br />* a<br />* b<br />* c<br />world"
|
290
|
+
end
|
291
|
+
it "after blank line" do
|
292
|
+
parse("hello\n\n * a\n * b\n * c\nworld").should ==
|
293
|
+
"hello<br /><br />* a<br />* b<br />* c<br />world"
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
###############################################################################
|
298
|
+
|
299
|
+
describe "IGNORES numbered lists" do
|
300
|
+
it "should ignore" do
|
301
|
+
parse("# a\n# b\n# c").should == "# a<br /># b<br /># c"
|
302
|
+
end
|
303
|
+
it "two lists" do
|
304
|
+
s = "# a\n# b\n# c"
|
305
|
+
s = s + "\nxxx\n" + s
|
306
|
+
parse(s).should == h(s).gsub("\n","<br />")
|
307
|
+
end
|
308
|
+
it "in middle of text when begins with space" do
|
309
|
+
parse("hello\n # a\n # b\n # c\nworld").should ==
|
310
|
+
"hello<br /># a<br /># b<br /># c<br />world"
|
311
|
+
end
|
312
|
+
it "in middle of text" do
|
313
|
+
parse("hello\n# a\n# b\n# c\nworld").should ==
|
314
|
+
"hello<br /># a<br /># b<br /># c<br />world"
|
315
|
+
end
|
316
|
+
it "after blank line" do
|
317
|
+
parse("hello\n\n # a\n # b\n # c\nworld").should ==
|
318
|
+
"hello<br /><br /># a<br /># b<br /># c<br />world"
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
###############################################################################
|
323
|
+
|
324
|
+
1.upto(5) do |lvl|
|
325
|
+
describe "H#{lvl}" do
|
326
|
+
it "at the beginning" do
|
327
|
+
s = "h#{lvl}. xxx"
|
328
|
+
parse(s).should == h(s)
|
329
|
+
end
|
330
|
+
it "after 1 line of text" do
|
331
|
+
s = "abcd\nh#{lvl}. xxx"
|
332
|
+
parse(s).should == h(s).gsub("\n","<br />")
|
333
|
+
end
|
334
|
+
it "after 2 lines of text" do
|
335
|
+
s = "abcd\ndefgh\nh#{lvl}. xxx"
|
336
|
+
parse(s).should == h(s).gsub("\n","<br />")
|
337
|
+
end
|
338
|
+
it "in middle of other words" do
|
339
|
+
s = "abcd defgh h#{lvl}. xxx yyy"
|
340
|
+
parse(s).should == h(s).gsub("\n","<br />")
|
341
|
+
end
|
342
|
+
it "in middle of other lines" do
|
343
|
+
s = "abcd defgh\nh#{lvl}. xxx\nyyy"
|
344
|
+
parse(s).should == h(s).gsub("\n","<br />")
|
345
|
+
end
|
346
|
+
|
347
|
+
it "does nothing special on spaces in id" do
|
348
|
+
s = "h#{lvl}. xxx yyy z"
|
349
|
+
parse(s).should == h(s).gsub(/ +/,' ')
|
350
|
+
end
|
351
|
+
it "does nothing special on underscores in id" do
|
352
|
+
s = "h#{lvl}. xxx___yyy_z"
|
353
|
+
parse(s).should == h(s)
|
354
|
+
end
|
355
|
+
it "does nothing special on dashes in id" do
|
356
|
+
s = "h#{lvl}. xxx---yyy-z"
|
357
|
+
parse(s).should == h(s)
|
358
|
+
end
|
359
|
+
it "does nothing special on dots in id" do
|
360
|
+
s = "h#{lvl}. xxx...yyy.z"
|
361
|
+
parse(s).should == h(s)
|
362
|
+
end
|
363
|
+
|
364
|
+
%w'Ъ ъ : ; , привет" \' ! < >'.each do |c|
|
365
|
+
it "does nothing special on \"#{c}\"" do
|
366
|
+
s = "h#{lvl}. xxx#{c}yyy"
|
367
|
+
parse(s).should == h(s)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
###############################################################################
|
374
|
+
|
375
|
+
describe "raw text links" do
|
376
|
+
describe "starting with 'http://'" do
|
377
|
+
it "at the beginning" do
|
378
|
+
parse("http://asd.ru").should == "<a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a>"
|
379
|
+
end
|
380
|
+
it "in middle of other words" do
|
381
|
+
parse("aaa bbb ccc http://asd.ru ddd eee fff").should ==
|
382
|
+
"aaa bbb ccc <a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a> ddd eee fff"
|
383
|
+
end
|
384
|
+
it "in new line" do
|
385
|
+
parse("aaa bbb ccc\nhttp://asd.ru\nddd eee fff").should match(
|
386
|
+
%r"aaa bbb ccc ?<br /> ?<a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a> ?<br /> ?ddd eee fff"
|
387
|
+
)
|
388
|
+
end
|
389
|
+
it "escapes '&' in link _text_" do
|
390
|
+
parse("http://asd.ru/?a=1&b=2").should == "<a rel=\"nofollow\" href=\"http://asd.ru/?a=1&b=2\">http://asd.ru/?a=1&b=2</a>"
|
391
|
+
end
|
392
|
+
|
393
|
+
it "parses https://" do
|
394
|
+
parse("https://asd.ru").should == "<a rel=\"nofollow\" href=\"https://asd.ru\">https://asd.ru</a>"
|
395
|
+
end
|
396
|
+
|
397
|
+
%w', .'.each do |c|
|
398
|
+
it "stops parsing on \"#{c} \"" do
|
399
|
+
parse("http://asd.ru#{c}").should == "<a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a>#{c}"
|
400
|
+
parse(" http://asd.ru#{c} ").should == "<a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a>#{c}"
|
401
|
+
parse(" http://asd.ru#{c} hello!").should == "<a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a>#{c} hello!"
|
402
|
+
parse("xxx http://asd.ru#{c} hello!").should == "xxx <a rel=\"nofollow\" href=\"http://asd.ru\">http://asd.ru</a>#{c} hello!"
|
403
|
+
parse(" http://asd.ru/#{c} hello!").should == "<a rel=\"nofollow\" href=\"http://asd.ru/\">http://asd.ru/</a>#{c} hello!"
|
404
|
+
parse(" http://aaa.com#{c} http://bbb.com").should ==
|
405
|
+
"<a rel=\"nofollow\" href=\"http://aaa.com\">http://aaa.com</a>#{c} <a rel=\"nofollow\" href=\"http://bbb.com\">http://bbb.com</a>"
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
describe "starting with 'www.'" do
|
411
|
+
it "at the beginning" do
|
412
|
+
parse("www.ru").should == "<a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a>"
|
413
|
+
end
|
414
|
+
it "in middle of other words" do
|
415
|
+
parse("aaa bbb ccc www.ru ddd eee fff").should ==
|
416
|
+
"aaa bbb ccc <a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a> ddd eee fff"
|
417
|
+
end
|
418
|
+
it "in new line" do
|
419
|
+
parse("aaa bbb ccc\nwww.ru\nddd eee fff").should match(
|
420
|
+
%r"aaa bbb ccc ?<br /> ?<a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a> ?<br /> ?ddd eee fff"
|
421
|
+
)
|
422
|
+
end
|
423
|
+
it "escapes '&' in link _text_" do
|
424
|
+
parse("www.ru/?a=1&b=2").should == "<a rel=\"nofollow\" href=\"http://www.ru/?a=1&b=2\">www.ru/?a=1&b=2</a>"
|
425
|
+
end
|
426
|
+
|
427
|
+
%w', .'.each do |c|
|
428
|
+
it "stops parsing on \"#{c} \"" do
|
429
|
+
parse("www.ru#{c}").should == "<a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a>#{c}"
|
430
|
+
parse(" www.ru#{c} ").should == "<a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a>#{c}"
|
431
|
+
parse(" www.ru#{c} hello!").should == "<a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a>#{c} hello!"
|
432
|
+
parse("xxx www.ru#{c} hello!").should == "xxx <a rel=\"nofollow\" href=\"http://www.ru\">www.ru</a>#{c} hello!"
|
433
|
+
parse(" www.ru/#{c} hello!").should == "<a rel=\"nofollow\" href=\"http://www.ru/\">www.ru/</a>#{c} hello!"
|
434
|
+
parse(" www.aaa.com#{c} www.bbb.com").should ==
|
435
|
+
"<a rel=\"nofollow\" href=\"http://www.aaa.com\">www.aaa.com</a>#{c} <a rel=\"nofollow\" href=\"http://www.bbb.com\">www.bbb.com</a>"
|
436
|
+
end
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
describe 'e-mails' do
|
441
|
+
it "at the beginning" do
|
442
|
+
parse("aaa@bbb.com").should == "<a href=\"mailto:aaa@bbb.com\">aaa@bbb.com</a>"
|
443
|
+
end
|
444
|
+
it "in middle of other words" do
|
445
|
+
parse("aaa bbb ccc xx@yy.cn ddd eee fff").should ==
|
446
|
+
"aaa bbb ccc <a href=\"mailto:xx@yy.cn\">xx@yy.cn</a> ddd eee fff"
|
447
|
+
end
|
448
|
+
it "in new line" do
|
449
|
+
parse("aaa bbb ccc\naa.bb@cc.dd.ee\nddd eee fff").should match(
|
450
|
+
%r"aaa bbb ccc ?<br /> ?<a href=\"mailto:aa.bb@cc.dd.ee\">aa.bb@cc.dd.ee</a> ?<br /> ?ddd eee fff"
|
451
|
+
)
|
452
|
+
end
|
453
|
+
|
454
|
+
%w', .'.each do |c|
|
455
|
+
it "stops parsing on \"#{c} \"" do
|
456
|
+
parse("a-b@c-d.efghjikl#{c}").should == "<a href=\"mailto:a-b@c-d.efghjikl\">a-b@c-d.efghjikl</a>#{c}"
|
457
|
+
parse(" a-b@c-d.efghjikl#{c} ").should == "<a href=\"mailto:a-b@c-d.efghjikl\">a-b@c-d.efghjikl</a>#{c}"
|
458
|
+
parse(" a-b@c-d.efghjikl#{c} hello!").should == "<a href=\"mailto:a-b@c-d.efghjikl\">a-b@c-d.efghjikl</a>#{c} hello!"
|
459
|
+
parse("xxx a-b@c-d.efghjikl#{c} hello!").should == "xxx <a href=\"mailto:a-b@c-d.efghjikl\">a-b@c-d.efghjikl</a>#{c} hello!"
|
460
|
+
parse(" a-b@c-d.efghjikl#{c} hello!").should == "<a href=\"mailto:a-b@c-d.efghjikl\">a-b@c-d.efghjikl</a>#{c} hello!"
|
461
|
+
parse(" www@aaa.com#{c} www@bbb.com").should ==
|
462
|
+
"<a href=\"mailto:www@aaa.com\">www@aaa.com</a>#{c} <a href=\"mailto:www@bbb.com\">www@bbb.com</a>"
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
it "not parses bad emails" do
|
467
|
+
s="a@b.c a@b a.b@c a.b@@c a@b@c.d a#b@c.d"
|
468
|
+
parse(s).should == s
|
469
|
+
end
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
###############################################################################
|
474
|
+
|
475
|
+
describe "#ticketNum ticket links" do
|
476
|
+
it "at the beginning" do
|
477
|
+
parse("#1234").should == '<a href="/spaces/test_space/tickets/1234">#1234</a>'
|
478
|
+
end
|
479
|
+
it "in middle of other words" do
|
480
|
+
parse("aaa bbb ccc #3476 ddd eee fff").should ==
|
481
|
+
'aaa bbb ccc <a href="/spaces/test_space/tickets/3476">#3476</a> ddd eee fff'
|
482
|
+
end
|
483
|
+
it "in new line" do
|
484
|
+
parse("aaa bbb ccc\n#1234\nddd eee fff").should match(
|
485
|
+
%r|aaa bbb ccc ?<br /> ?<a href="/spaces/test_space/tickets/1234">#1234</a> ?<br /> ?ddd eee fff|
|
486
|
+
)
|
487
|
+
end
|
488
|
+
it "ignores non-digits" do
|
489
|
+
parse("#1234d").should == '#1234d'
|
490
|
+
parse("#xxx").should == '#xxx'
|
491
|
+
end
|
492
|
+
|
493
|
+
".,;!?:-".each_char do |c|
|
494
|
+
it "uses '#{c}' as separator" do
|
495
|
+
l = '<a href="/spaces/test_space/tickets/1234">#1234</a>'
|
496
|
+
t = "L#{c}L"
|
497
|
+
parse(t.gsub('L','#1234')).should == t.gsub('L',l)
|
498
|
+
t = "L#{c}#{c}L"
|
499
|
+
parse(t.gsub('L','#1234')).should == t.gsub('L',l)
|
500
|
+
t = "#{c}L#{c}L#{c}"
|
501
|
+
parse(t.gsub('L','#1234')).should == t.gsub('L',l)
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
###############################################################################
|
507
|
+
|
508
|
+
[
|
509
|
+
%w'<pre><code> </code></pre>',
|
510
|
+
%w'<pre> </pre>',
|
511
|
+
%w'<notextile> </notextile>'
|
512
|
+
].each do |ot,ct|
|
513
|
+
# ot - opening tag
|
514
|
+
# ct - closing tag
|
515
|
+
|
516
|
+
# if ot == '<notextile>'
|
517
|
+
# ote,cte = '',''
|
518
|
+
# else
|
519
|
+
ote,cte = ot,ct
|
520
|
+
# end
|
521
|
+
|
522
|
+
describe "#{ot}..#{ct}" do
|
523
|
+
it "works" do
|
524
|
+
s = <<-EOF
|
525
|
+
for ( n = 0; n < max_size && \
|
526
|
+
(c = getc( yyin )) != EOF && c != '\\n'; ++n ) \
|
527
|
+
buf[n] = (char) c; \
|
528
|
+
|
529
|
+
EOF
|
530
|
+
|
531
|
+
parse("#{ot}#{s.strip}#{ct}").should ==
|
532
|
+
h("#{ot}#{s.strip}#{ct}").gsub(/[ \t]+/,' ').gsub("\n","<br />")
|
533
|
+
|
534
|
+
s = <<-EOF
|
535
|
+
while ( 1 < 2 ) do
|
536
|
+
puts "<b>12345\\t54321</b>"
|
537
|
+
// *bold* comment
|
538
|
+
// _italic_ comment
|
539
|
+
end
|
540
|
+
---
|
541
|
+
* aaa
|
542
|
+
* bbb
|
543
|
+
* ccc
|
544
|
+
|
545
|
+
EOF
|
546
|
+
parse("#{ot}#{s.strip}#{ct}").should ==
|
547
|
+
h("#{ote}#{s.strip}#{cte}").gsub(/[ \t]+/,' ').gsub(/\n */,"<br />")
|
548
|
+
end
|
549
|
+
it "not parses *bold*" do
|
550
|
+
s = "#{ot} *bold*#{ct}"
|
551
|
+
parse(s).should == h(s)
|
552
|
+
end
|
553
|
+
it "not parses _italic_" do
|
554
|
+
s = "#{ot} _italic_#{ct}"
|
555
|
+
parse(s).should == h(s)
|
556
|
+
end
|
557
|
+
it "not parses UL lists" do
|
558
|
+
s = "#{ot}\n * l1\n * l2\n * l3#{ct}"
|
559
|
+
parse(s).should == h(s).gsub("\n ","<br />")
|
560
|
+
end
|
561
|
+
it "not parses OL lists" do
|
562
|
+
s = "#{ot}\n # l1\n # l2\n # l3#{ct}"
|
563
|
+
parse(s).should == h(s).gsub("\n ","<br />")
|
564
|
+
end
|
565
|
+
it "not parses H1..H5" do
|
566
|
+
1.upto(5) do |i|
|
567
|
+
s = "#{ot}\nh#{i}. zzzzzzz\n#{ct}"
|
568
|
+
parse(s).should == h(s).gsub("\n","<br />")
|
569
|
+
end
|
570
|
+
end
|
571
|
+
it "parses raw text links" do
|
572
|
+
s = "#{ot}xxx http://www.ru yyy#{ct}"
|
573
|
+
parse(s).should == "#{h(ote)}xxx <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a> yyy#{h(cte)}"
|
574
|
+
s = "#{ot}http://www.ru#{ct}"
|
575
|
+
parse(s).should == "#{h(ote)}<a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a>#{h(cte)}"
|
576
|
+
end
|
577
|
+
it "keeps newlines" do
|
578
|
+
s = "#{ot}aaa\nbbb#{ct}"
|
579
|
+
parse(s).should == h(s).gsub("\n","<br />")
|
580
|
+
s = "#{ot}aaa\n\nbbb\nccc#{ct}"
|
581
|
+
parse(s).should == h(s).gsub("\n","<br />")
|
582
|
+
end
|
583
|
+
|
584
|
+
it "w/o closing tags" do
|
585
|
+
s = "#{ot}aaa"
|
586
|
+
parse(s).should == h(s)
|
587
|
+
end
|
588
|
+
|
589
|
+
it "in middle of text" do
|
590
|
+
s = "xxx #{ot}yyyy#{ct} jjj"
|
591
|
+
parse(s).should == h(s)
|
592
|
+
end
|
593
|
+
|
594
|
+
it "with 2 instances" do
|
595
|
+
s = "xxx #{ot}yyyy#{ct} <jjj> #{ot}asdkjaslkd#{ct} END"
|
596
|
+
parse(s).should == h(s)
|
597
|
+
end
|
598
|
+
|
599
|
+
it "works with unicode" do
|
600
|
+
s = "привет #{ot} жжж #{ct} пока!"
|
601
|
+
parse(s).should == h(s)
|
602
|
+
|
603
|
+
s = "#{ot}абвгдеёжзийклмнопрстуфхцчшщьыъэюя#{ct}"
|
604
|
+
parse(s).should == h(s)
|
605
|
+
|
606
|
+
s = "#{ot}АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ#{ct}"
|
607
|
+
parse(s).should == h(s)
|
608
|
+
|
609
|
+
s = "#{ot}☸☹☺☻☼☽☾☿#{ct}"
|
610
|
+
parse(s).should == h(s)
|
611
|
+
end
|
612
|
+
|
613
|
+
it "should escape lone closing tags" do
|
614
|
+
s = "#{ct}"
|
615
|
+
parse(s).should == h(s)
|
616
|
+
end
|
617
|
+
|
618
|
+
it "should skip newlines and spaces at end" do
|
619
|
+
s = "#{ot} aaa bbb ccc \n\n\n \t\n\n\n\r\n\r\n \t #{ct}"
|
620
|
+
parse(s).should == "#{h(ote)} aaa bbb ccc<br /><br /><br /><br /><br /><br /><br /><br />#{h(cte)}"
|
621
|
+
end
|
622
|
+
|
623
|
+
it "escapes html chars" do
|
624
|
+
HTML_ESCAPE.each do |k,v|
|
625
|
+
parse("#{ot}#{k}#{ct}").should == h("#{ote}#{k}#{cte}")
|
626
|
+
end
|
627
|
+
end
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
describe "NOT PARSES <pre><code>..</code></pre>" do
|
632
|
+
it "with no spaces between <pre> and <code>" do
|
633
|
+
s = "<pre><code>aaa</code></pre>"
|
634
|
+
parse(s).should == h(s).gsub(/ +/,' ')
|
635
|
+
end
|
636
|
+
|
637
|
+
it "with spaces between <pre> and <code>" do
|
638
|
+
s = "<pre> <code>aaa</code> </pre>"
|
639
|
+
parse(s).should == h(s).gsub(/ +/,' ')
|
640
|
+
end
|
641
|
+
it "with spaces between <pre> and <code> and inside" do
|
642
|
+
s = "<pre> <code> aaa bbb </code> </pre>"
|
643
|
+
parse(s).should == h(s).gsub(/ +/,' ')
|
644
|
+
end
|
645
|
+
end
|
646
|
+
|
647
|
+
###############################################################################
|
648
|
+
|
649
|
+
describe "<code>..</code>" do
|
650
|
+
it "keeps <code> tags" do
|
651
|
+
s = "<code>aaa</code>"
|
652
|
+
parse(s).should == h(s)
|
653
|
+
end
|
654
|
+
it "strips heading & tailing whitespace" do
|
655
|
+
s = "<code> \r\n \t \t\r aaa \r\n\t \t\r </code>"
|
656
|
+
parse(s).should == "<code><br /><br /> aaa<br /><br /> </code>"
|
657
|
+
end
|
658
|
+
it "not parses *bold*" do
|
659
|
+
s = "<code>aaa *bbb* ccc</code>"
|
660
|
+
parse(s).should == h(s)
|
661
|
+
end
|
662
|
+
it "not parses _italic_" do
|
663
|
+
s = "<code>aaa _bbb_ ccc</code>"
|
664
|
+
parse(s).should == h(s)
|
665
|
+
end
|
666
|
+
it "not parses headers" do
|
667
|
+
s = "<code>aaa\nh1. bbb\nccc</code>"
|
668
|
+
parse(s).should == h(s).gsub("\n","<br />")
|
669
|
+
end
|
670
|
+
it "not parses <pre>" do
|
671
|
+
s = "<code>aaa <pre>bbb</pre> ccc</code>"
|
672
|
+
parse(s).should == h(s)
|
673
|
+
end
|
674
|
+
it "NOT closes unclosed <code>" do
|
675
|
+
s = "aaa <code>bbb"
|
676
|
+
parse(s).should == h(s)
|
677
|
+
end
|
678
|
+
it "NOT escapes '&'" do
|
679
|
+
s = "<code>aaa & bbb</code>"
|
680
|
+
parse(s).should == h(s)
|
681
|
+
end
|
682
|
+
it "parses links" do
|
683
|
+
s = "<code>aaa #1 #2 #3 http://www.ru [[wiki:jjj]] [[url:http://www.ru]] bbb</code>"
|
684
|
+
parse(s).should == "<code>aaa <a href=\"/spaces/test_space/tickets/1\">#1</a> <a href=\"/spaces/test_space/tickets/2\">#2</a> <a href=\"/spaces/test_space/tickets/3\">#3</a> <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a> <a class=\"wiki_link\" title=\"jjj\" href=\"/spaces/test_space/wiki/jjj\">jjj</a> <a rel=\"nofollow\" href=\"http://www.ru\">http://www.ru</a> bbb</code>"
|
685
|
+
end
|
686
|
+
it "NOT works" do
|
687
|
+
s = "<code>aaa & bbb</code> xxx <code>jjj&hhh</code>"
|
688
|
+
parse(s).should == h(s)
|
689
|
+
s = "<code> aaa </code>xxx<code> jjj </code>"
|
690
|
+
parse(s).should == h(s).gsub(/ +/,' ')
|
691
|
+
end
|
692
|
+
it "NOT keeps code bold" do
|
693
|
+
s = "*aaa <code>bbb</code> ccc*"
|
694
|
+
parse(s).should == h(s)
|
695
|
+
s = "*<code>aaa</code>*"
|
696
|
+
parse(s).should == h(s)
|
697
|
+
end
|
698
|
+
it "NOT keeps code italic" do
|
699
|
+
s = "_aaa <code>bbb</code> ccc_"
|
700
|
+
parse(s).should == h(s)
|
701
|
+
s = "_<code>aaa</code>_"
|
702
|
+
parse(s).should == h(s)
|
703
|
+
end
|
704
|
+
end
|
705
|
+
|
706
|
+
###############################################################################
|
707
|
+
|
708
|
+
describe "Assembla Links" do
|
709
|
+
a = {}
|
710
|
+
a["wiki:Name"] = '<a class="wiki_link" title="Name" href="/spaces/test_space/wiki/Name">Name</a>'
|
711
|
+
a["Name"] = '<a class="wiki_link" title="Name" href="/spaces/test_space/wiki/Name">Name</a>'
|
712
|
+
a["Name#Ref"] = '<a class="wiki_link" title="Name#Ref" href="/spaces/test_space/wiki/Name#h-Ref">Name#Ref</a>'
|
713
|
+
a["Name#h-Ref"] = '<a class="wiki_link" title="Name#h-Ref" href="/spaces/test_space/wiki/Name#h-h-Ref">Name#h-Ref</a>'
|
714
|
+
a["#Ref"] = '<a href="#h-Ref" title="#Ref" class="wiki_link">#Ref</a>'
|
715
|
+
a["#привет"] = %Q|<a href="#h-#{hex_string("привет")}" title="#привет" class="wiki_link">#привет</a>|
|
716
|
+
a["#with spc"] = %Q|<a href="#h-with__spc" title="#with spc" class="wiki_link">#with spc</a>|
|
717
|
+
a["#with__usc"] = %Q|<a href="#h-with__usc" title="#with__usc" class="wiki_link">#with__usc</a>|
|
718
|
+
a["#with--dsh"] = %Q|<a href="#h-with--dsh" title="#with--dsh" class="wiki_link">#with--dsh</a>|
|
719
|
+
a["#with!xclm"] = %Q|<a href="#h-#{hex_string("with!xclm")}" title="#with!xclm" class="wiki_link">#with!xclm</a>|
|
720
|
+
a["#with&"] = %Q|<a href="#h-#{hex_string("with&")}" title="#with&" class="wiki_link">#with&amp</a>|
|
721
|
+
|
722
|
+
a["ticket:234"] = '<a href="/spaces/test_space/tickets/234">#234</a>'
|
723
|
+
a["revision:1f4bdab77be696efd"] =
|
724
|
+
'<a href="/code/test_space/git/changesets/1f4bdab77be696efd">revision:1f4bdab77be696efd</a>'
|
725
|
+
a["revision:12345"] =
|
726
|
+
'<a href="/code/test_space/subversion/changesets/12345">revision:12345</a>'
|
727
|
+
a["revision:567:1f4bdab77be696efd"] =
|
728
|
+
'<a href="/code/test_space/git-567/changesets/1f4bdab77be696efd">revision:1f4bdab77be696efd</a>'
|
729
|
+
a["revision:3:12345"] =
|
730
|
+
'<a href="/code/test_space/subversion-3/changesets/12345">revision:12345</a>'
|
731
|
+
a["r:2345"] = '<a href="/code/test_space/subversion/changesets/2345">revision:2345</a>'
|
732
|
+
a["r:2345ef"] = '<a href="/code/test_space/git/changesets/2345ef">revision:2345ef</a>'
|
733
|
+
a["r:10:2345"] = '<a href="/code/test_space/subversion-10/changesets/2345">revision:2345</a>'
|
734
|
+
a["r:1:2345ef"] = '<a href="/code/test_space/git-1/changesets/2345ef">revision:2345ef</a>'
|
735
|
+
|
736
|
+
a["url:http://www.ru"] = '<a rel="nofollow" href="http://www.ru">http://www.ru</a>'
|
737
|
+
a["url:https://www.ru"] = '<a rel="nofollow" href="https://www.ru">https://www.ru</a>'
|
738
|
+
a["url:www.ru"] = '<a rel="nofollow" href="http://www.ru">http://www.ru</a>'
|
739
|
+
a["url:www.ru/?a=1&b=2"] = '<a rel="nofollow" href="http://www.ru/?a=1&b=2">http://www.ru/?a=1&b=2</a>'
|
740
|
+
a["url:ftp://www.ru"] = '<a rel="nofollow" href="ftp://www.ru">ftp://www.ru</a>'
|
741
|
+
a["url:/spaces/x2"] = '<a rel="nofollow" href="/spaces/x2">/spaces/x2</a>'
|
742
|
+
|
743
|
+
a["file:ExistingFile.txt"] =
|
744
|
+
'<a href="/spaces/test_space/documents/download/ExistingFile.txt">file:ExistingFile.txt</a>'
|
745
|
+
a["file:cVJUz6ejWr35pEab_qKWB8"] =
|
746
|
+
'<a href="/spaces/test_space/documents/download/cVJUz6ejWr35pEab_qKWB8">file:cVJUz6ejWr35pEab_qKWB8</a>'
|
747
|
+
|
748
|
+
a.each do |k,v|
|
749
|
+
it "parses [[#{k}]]" do
|
750
|
+
parse("[[#{k}]]").should == v
|
751
|
+
end
|
752
|
+
it "parses [[#{k}|привет тест]]" do
|
753
|
+
parse("[[#{k}|привет тест]]").should == v.sub(/>.*</,">привет тест<")
|
754
|
+
end
|
755
|
+
it "parses [[#{k}|test & here]]" do
|
756
|
+
parse("[[#{k}|test & here]]").should == v.sub(/>.*</,">test & here<")
|
757
|
+
end
|
758
|
+
if v['href="/'] && !k['url:']
|
759
|
+
it "parses [[#{k}]] with a site url" do
|
760
|
+
site_url = "http://www.ru"
|
761
|
+
parse("[[#{k}]]", :site_url => site_url).should ==
|
762
|
+
v.gsub('href="/',"href=\"#{site_url}/")
|
763
|
+
|
764
|
+
# with extraordinary slash
|
765
|
+
parse("[[#{k}]]", :site_url => "#{site_url}/").should ==
|
766
|
+
v.gsub('href="/',"href=\"#{site_url}/")
|
767
|
+
|
768
|
+
site_url = "http://127.0.0.1:3000"
|
769
|
+
parse("[[#{k}]]", :site_url => site_url).should ==
|
770
|
+
v.gsub('href="/',"href=\"#{site_url}/")
|
771
|
+
|
772
|
+
# with extraordinary slash
|
773
|
+
parse("[[#{k}]]", :site_url => "#{site_url}/").should ==
|
774
|
+
v.gsub('href="/',"href=\"#{site_url}/")
|
775
|
+
end
|
776
|
+
end
|
777
|
+
if v['/git/']
|
778
|
+
it "parses [[#{k}]] with custom git_url (String)" do
|
779
|
+
git_url = "http://www.ru/"
|
780
|
+
rev = k.split(':').last.tr(']','')
|
781
|
+
parse("[[#{k}]]", :git_url => git_url).should ==
|
782
|
+
v.sub('/code/test_space/git/changesets/',git_url)
|
783
|
+
end
|
784
|
+
|
785
|
+
it "parses [[#{k}]] with custom git_url (ObjProxy)" do
|
786
|
+
rev = k.split(':').last.tr(']','')
|
787
|
+
@asdfg = 'http://mmm.us'
|
788
|
+
git_url = Breakout::ObjProxy.new do
|
789
|
+
@asdfg + '/'
|
790
|
+
end
|
791
|
+
parse("[[#{k}]]", :git_url => git_url).should ==
|
792
|
+
v.sub('/code/test_space/git/changesets/',git_url)
|
793
|
+
end
|
794
|
+
|
795
|
+
it "parses [[#{k}]] with NULL git_url (ObjProxy)" do
|
796
|
+
rev = k.split(':').last.tr(']','')
|
797
|
+
git_url = Breakout::ObjProxy.new do
|
798
|
+
nil
|
799
|
+
end
|
800
|
+
parse("[[#{k}]]", :git_url => git_url).should == v
|
801
|
+
end
|
802
|
+
|
803
|
+
it "parses [[#{k}]] with FALSE git_url (ObjProxy)" do
|
804
|
+
rev = k.split(':').last.tr(']','')
|
805
|
+
git_url = Breakout::ObjProxy.new do
|
806
|
+
false
|
807
|
+
end
|
808
|
+
parse("[[#{k}]]", :git_url => git_url).should == v
|
809
|
+
end
|
810
|
+
end
|
811
|
+
end
|
812
|
+
|
813
|
+
it "should not instantiate ObjProxy's internal object if there are no git or svn links in text" do
|
814
|
+
git_url = Breakout::ObjProxy.new do
|
815
|
+
raise 'should not be raised'
|
816
|
+
end
|
817
|
+
lambda {
|
818
|
+
parse("no revision tag", :git_url => git_url).should == 'no revision tag'
|
819
|
+
}.should_not raise_error
|
820
|
+
end
|
821
|
+
|
822
|
+
describe "absolute_urls" do
|
823
|
+
# 'true' values
|
824
|
+
[true, 1, 'x'].each do |v|
|
825
|
+
it "should NOT convert relative url to absolute when absolute_urls = #{v.inspect} AND site_url is NULL" do
|
826
|
+
parse("[[url:/rel]]", :absolute_urls => v).should ==
|
827
|
+
'<a rel="nofollow" href="/rel">/rel</a>'
|
828
|
+
parse("[[url:/rel|text]]", :absolute_urls => v).should ==
|
829
|
+
'<a rel="nofollow" href="/rel">text</a>'
|
830
|
+
end
|
831
|
+
it "should convert relative url to absolute when absolute_urls = #{v.inspect}" do
|
832
|
+
parse("[[url:/rel]]", :absolute_urls => v, :site_url => 'http://www.ru').should ==
|
833
|
+
'<a rel="nofollow" href="http://www.ru/rel">/rel</a>'
|
834
|
+
parse("[[url:/rel|text]]", :absolute_urls => v, :site_url => 'http://www.ru').should ==
|
835
|
+
'<a rel="nofollow" href="http://www.ru/rel">text</a>'
|
836
|
+
end
|
837
|
+
end
|
838
|
+
# 'false' values
|
839
|
+
[false, nil].each do |v|
|
840
|
+
it "should not convert relative url to absolute when absolute_urls = #{v.inspect}" do
|
841
|
+
parse("[[url:/rel]]", :absolute_urls => v).should ==
|
842
|
+
'<a rel="nofollow" href="/rel">/rel</a>'
|
843
|
+
parse("[[url:/rel|text]]", :absolute_urls => v).should ==
|
844
|
+
'<a rel="nofollow" href="/rel">text</a>'
|
845
|
+
end
|
846
|
+
end
|
847
|
+
end
|
848
|
+
|
849
|
+
a = {}
|
850
|
+
a["image:ExistingImage.png"] =
|
851
|
+
'<img src="/spaces/test_space/documents/download/ExistingImage.png" alt="ALT" />'
|
852
|
+
a["image:cVJUz6ejWr35pEab_qKWB8"] =
|
853
|
+
'<img src="/spaces/test_space/documents/download/cVJUz6ejWr35pEab_qKWB8" alt="ALT" />'
|
854
|
+
|
855
|
+
a.each do |k,v|
|
856
|
+
it "parses [[#{k}]]" do
|
857
|
+
parse("[[#{k}]]").should == v.sub('ALT',k.sub('image:',''))
|
858
|
+
end
|
859
|
+
it "parses [[#{k}|привет тест]]" do
|
860
|
+
parse("[[#{k}|привет тест]]").should == v.sub('ALT','привет тест')
|
861
|
+
end
|
862
|
+
it "parses [[#{k}|test & here]]" do
|
863
|
+
parse("[[#{k}|test & here]]").should == v.sub('ALT','test & here')
|
864
|
+
end
|
865
|
+
end
|
866
|
+
|
867
|
+
it "ignores unknown link types" do
|
868
|
+
s = "[[zzz:xxx]]"
|
869
|
+
parse(s).should == s
|
870
|
+
s = "[[abcd:1234]]"
|
871
|
+
parse(s).should == s
|
872
|
+
s = "[[abcd::1234]] [[abcd:1234]] [[uri:ww.ru]]"
|
873
|
+
parse(s).should == s
|
874
|
+
end
|
875
|
+
|
876
|
+
it "ignores file & image links with forbidden symbols" do
|
877
|
+
s = "[[file:aaa/bbb]]"
|
878
|
+
parse(s).should == s
|
879
|
+
s = "[[file:aaa\\bbb]]"
|
880
|
+
parse(s).should == s
|
881
|
+
s = "[[file:aaa bbb]]"
|
882
|
+
parse(s).should == s
|
883
|
+
|
884
|
+
s = "[[image:aaa/bbb]]"
|
885
|
+
parse(s).should == s
|
886
|
+
s = "[[image:aaa\\bbb]]"
|
887
|
+
parse(s).should == s
|
888
|
+
s = "[[image:aaa bbb]]"
|
889
|
+
parse(s).should == s
|
890
|
+
end
|
891
|
+
end
|
892
|
+
|
893
|
+
###############################################################################
|
894
|
+
###############################################################################
|
895
|
+
###############################################################################
|
896
|
+
|
897
|
+
unless defined?(HTML_ESCAPE)
|
898
|
+
HTML_ESCAPE = { '&' => '&', '>' => '>', '<' => '<', '"' => '"' }
|
899
|
+
end
|
900
|
+
|
901
|
+
def h(s)
|
902
|
+
s.to_s.gsub(/[&"><]/) { |special| HTML_ESCAPE[special] }
|
903
|
+
end
|
904
|
+
|
905
|
+
def parse(s, h = {})
|
906
|
+
h[:space_name] = "test_space" unless h.key?(:space_name)
|
907
|
+
BreakoutParser.parse_links_only(s,
|
908
|
+
h[:space_name],
|
909
|
+
h[:site_url],
|
910
|
+
h[:git_url],
|
911
|
+
h[:absolute_urls],
|
912
|
+
h[:large_files_url],
|
913
|
+
h[:meta_attributes]
|
914
|
+
).strip
|
915
|
+
end
|
916
|
+
end
|