wikitext 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ // Copyright 2008 Wincent Colaiuta
2
+ // This program is free software: you can redistribute it and/or modify
3
+ // it under the terms of the GNU General Public License as published by
4
+ // the Free Software Foundation, either version 3 of the License, or
5
+ // (at your option) any later version.
6
+ //
7
+ // This program is distributed in the hope that it will be useful,
8
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ // GNU General Public License for more details.
11
+ //
12
+ // You should have received a copy of the GNU General Public License
13
+ // along with this program. If not, see <http://www.gnu.org/licenses/>.
14
+
15
+ #include "token.h"
16
+
17
+ void next_token(token_t *out, token_t *last_token, char *p, char *pe);
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright 2007-2008 Wincent Colaiuta
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require File.join(File.dirname(__FILE__), 'spec_helper.rb')
17
+ require 'wikitext'
18
+
19
+ describe Wikitext::Parser, 'autolinking' do
20
+ before do
21
+ @parser = Wikitext::Parser.new
22
+ end
23
+
24
+ it 'should default to autolinking on' do
25
+ @parser.autolink.should == true
26
+ end
27
+
28
+ describe 'on' do
29
+ it 'should convert HTTP URIs into hyperlinks' do
30
+ uri = 'http://example.com/'
31
+ @parser.parse(uri).should == %Q{<p><a href="http://example.com/" class="external">http://example.com/</a></p>\n}
32
+ end
33
+
34
+ it 'should convert HTTPS URIs into hyperlinks' do
35
+ uri = 'https://example.com/'
36
+ @parser.parse(uri).should == %Q{<p><a href="https://example.com/" class="external">https://example.com/</a></p>\n}
37
+ end
38
+
39
+ it 'should convert FTP URIs into hyperlinks' do
40
+ uri = 'ftp://example.com/'
41
+ @parser.parse(uri).should == %Q{<p><a href="ftp://example.com/" class="external">ftp://example.com/</a></p>\n}
42
+ end
43
+
44
+ it 'should convert mailto URIs into hyperlinks' do
45
+ uri = 'mailto:user@example.com'
46
+ @parser.parse(uri).should == %Q{<p><a href="mailto:user@example.com" class="external">mailto:user@example.com</a></p>\n}
47
+ end
48
+
49
+ it 'should convert SVN URIs into hyperlinks' do
50
+ uri = 'svn://example.com/'
51
+ @parser.parse(uri).should == %Q{<p><a href="svn://example.com/" class="external">svn://example.com/</a></p>\n}
52
+ end
53
+
54
+ it 'should apple the external_link_class CSS class if set' do
55
+ uri = 'http://example.com/'
56
+ @parser.external_link_class = 'bar'
57
+ @parser.parse(uri).should == %Q{<p><a href="http://example.com/" class="bar">http://example.com/</a></p>\n}
58
+ end
59
+
60
+ it 'should apply no CSS if external_link_class is set to nil' do
61
+ uri = 'http://example.com/'
62
+ @parser.external_link_class = nil
63
+ @parser.parse(uri).should == %Q{<p><a href="http://example.com/">http://example.com/</a></p>\n}
64
+ end
65
+
66
+ it 'should pass through URIs unchanged inside <nowiki></nowiki> spans' do
67
+ @parser.parse("<nowiki>http://example.com/</nowiki>").should == "<p>http://example.com/</p>\n"
68
+ end
69
+
70
+ it 'should autolink URIs inside <pre></pre> spans' do
71
+ input = ' http://example.com/'
72
+ expected = %Q{<pre><a href="http://example.com/" class="external">http://example.com/</a></pre>\n}
73
+ @parser.parse(input).should == expected
74
+ @parser.external_link_class = nil
75
+ expected = %Q{<pre><a href="http://example.com/">http://example.com/</a></pre>\n}
76
+ @parser.parse(input).should == expected
77
+ end
78
+
79
+ it 'should convert emails into hyperlinks' do
80
+ uri = 'user@example.com'
81
+ @parser.parse(uri).should == %Q{<p><a href="mailto:user@example.com" class="mailto">user@example.com</a></p>\n}
82
+ end
83
+
84
+ it 'should apply the mailto CSS class if set' do
85
+ uri = 'user@example.com'
86
+ @parser.mailto_class = 'foo'
87
+ @parser.parse(uri).should == %Q{<p><a href="mailto:user@example.com" class="foo">user@example.com</a></p>\n}
88
+ end
89
+
90
+ it 'should apply no CSS if the mailto class is set to nil' do
91
+ uri = 'user@example.com'
92
+ @parser.mailto_class = nil
93
+ @parser.parse(uri).should == %Q{<p><a href="mailto:user@example.com">user@example.com</a></p>\n}
94
+ end
95
+
96
+ it 'should pass through emails unchanged inside <nowiki></nowiki> spans' do
97
+ @parser.parse("<nowiki>user@example.com</nowiki>").should == "<p>user@example.com</p>\n" # was a crasher
98
+ end
99
+
100
+ it 'should pass through emails unchanged inside <pre></pre> blocks' do
101
+ @parser.parse(" user@example.com").should == "<pre>user@example.com</pre>\n" # was a crasher
102
+ end
103
+ end
104
+
105
+ describe 'off' do
106
+ before do
107
+ @parser.autolink = false
108
+ end
109
+
110
+ it 'should accept "autolink = false"' do
111
+ @parser.autolink.should == false
112
+ end
113
+
114
+ it 'should not convert URIs into hyperlinks' do
115
+ @parser.parse('http://example.com/').should == "<p>http://example.com/</p>\n"
116
+ end
117
+
118
+ it 'should not convert emails into hyperlinks' do
119
+ @parser.parse('user@example.com').should == "<p>user@example.com</p>\n"
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,570 @@
1
+ #!/usr/bin/env ruby
2
+ # Copyright 2007-2008 Wincent Colaiuta
3
+ # This program is free software: you can redistribute it and/or modify
4
+ # it under the terms of the GNU General Public License as published by
5
+ # the Free Software Foundation, either version 3 of the License, or
6
+ # (at your option) any later version.
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+
16
+ require File.join(File.dirname(__FILE__), 'spec_helper.rb')
17
+ require 'wikitext'
18
+
19
+ describe Wikitext::Parser, 'standard blockquotes (">" in first column)' do
20
+ before do
21
+ @parser = Wikitext::Parser.new
22
+ end
23
+
24
+ it 'should treat ">" in first column as a blockquote marker' do
25
+ expected = dedent <<-END
26
+ <blockquote>
27
+ <p>foo</p>
28
+ </blockquote>
29
+ END
30
+ @parser.parse('>foo').should == expected
31
+ end
32
+
33
+ it 'should accept (and ignore) one optional space after the ">"' do
34
+ expected = dedent <<-END
35
+ <blockquote>
36
+ <p>foo</p>
37
+ </blockquote>
38
+ END
39
+ @parser.parse('> foo').should == expected
40
+ end
41
+
42
+ it 'should recognize consecutive ">" as continuance of blockquote section' do
43
+ expected = dedent <<-END
44
+ <blockquote>
45
+ <p>foo bar</p>
46
+ </blockquote>
47
+ END
48
+ @parser.parse("> foo\n> bar").should == expected
49
+ end
50
+
51
+ it 'should not give ">" special treatment when not on the far left' do
52
+ @parser.parse('foo > bar').should == "<p>foo &gt; bar</p>\n"
53
+ end
54
+
55
+ it 'should allow nesting of blockquotes' do
56
+ expected = dedent <<-END
57
+ <blockquote>
58
+ <blockquote>
59
+ <p>foo</p>
60
+ </blockquote>
61
+ </blockquote>
62
+ END
63
+ @parser.parse('> > foo').should == expected
64
+ end
65
+
66
+ it 'should allow opening of a nested blockquote after other content' do
67
+ expected = dedent <<-END
68
+ <blockquote>
69
+ <p>foo</p>
70
+ <blockquote>
71
+ <p>bar</p>
72
+ </blockquote>
73
+ </blockquote>
74
+ END
75
+ @parser.parse("> foo\n> > bar").should == expected
76
+ end
77
+
78
+ it 'should allow opening of a nested blockquote before other content' do
79
+ expected = dedent <<-END
80
+ <blockquote>
81
+ <blockquote>
82
+ <p>foo</p>
83
+ </blockquote>
84
+ <p>bar</p>
85
+ </blockquote>
86
+ END
87
+ @parser.parse("> > foo\n> bar").should == expected
88
+ end
89
+
90
+ it 'should accept an empty blockquote' do
91
+ expected = dedent <<-END
92
+ <blockquote>
93
+ </blockquote>
94
+ END
95
+ @parser.parse('>').should == expected
96
+ end
97
+
98
+ it 'should jump out of blockquote mode on seeing a normal line of text' do
99
+ expected = dedent <<-END
100
+ <blockquote>
101
+ <p>foo</p>
102
+ </blockquote>
103
+ <p>bar</p>
104
+ END
105
+ @parser.parse("> foo\nbar").should == expected
106
+ end
107
+
108
+ it 'should allow nesting of h1 blocks' do
109
+ expected = dedent <<-END
110
+ <blockquote>
111
+ <h1>foo</h1>
112
+ </blockquote>
113
+ END
114
+ @parser.parse('> = foo =').should == expected
115
+ end
116
+
117
+ it 'should allow nesting of h2 blocks' do
118
+ expected = dedent <<-END
119
+ <blockquote>
120
+ <h2>foo</h2>
121
+ </blockquote>
122
+ END
123
+ @parser.parse('> == foo ==').should == expected
124
+ end
125
+
126
+ it 'should allow nesting of h3 blocks' do
127
+ expected = dedent <<-END
128
+ <blockquote>
129
+ <h3>foo</h3>
130
+ </blockquote>
131
+ END
132
+ @parser.parse('> === foo ===').should == expected
133
+ end
134
+
135
+ it 'should allow nesting of h4 blocks' do
136
+ expected = dedent <<-END
137
+ <blockquote>
138
+ <h4>foo</h4>
139
+ </blockquote>
140
+ END
141
+ @parser.parse('> ==== foo ====').should == expected
142
+ end
143
+
144
+ it 'should allow nesting of h5 blocks' do
145
+ expected = dedent <<-END
146
+ <blockquote>
147
+ <h5>foo</h5>
148
+ </blockquote>
149
+ END
150
+ @parser.parse('> ===== foo =====').should == expected
151
+ end
152
+
153
+ it 'should allow nesting of h6 blocks' do
154
+ expected = dedent <<-END
155
+ <blockquote>
156
+ <h6>foo</h6>
157
+ </blockquote>
158
+ END
159
+ @parser.parse('> ====== foo ======').should == expected
160
+ end
161
+
162
+ it 'should allow alternating nested paragraphs and pre blocks' do
163
+ # was a bug
164
+ input = dedent <<-END
165
+ > para 1
166
+ >
167
+ > pre 1
168
+ > pre 2
169
+ >
170
+ > para 2
171
+ END
172
+ expected = dedent <<-END
173
+ <blockquote>
174
+ <p>para 1</p>
175
+ <pre>pre 1
176
+ pre 2</pre>
177
+ <p>para 2</p>
178
+ </blockquote>
179
+ END
180
+ @parser.parse(input).should == expected
181
+ end
182
+
183
+ it 'should allow nesting of styled spans inside blockquotes' do
184
+ input = dedent <<-END
185
+ > link to [[something]], and ''other''
186
+ > `styled` '''spans'''.
187
+ END
188
+ expected = dedent <<-END
189
+ <blockquote>
190
+ <p>link to <a href="/wiki/something">something</a>, and <em>other</em> <tt>styled</tt> <strong>spans</strong>.</p>
191
+ </blockquote>
192
+ END
193
+ @parser.parse(input).should == expected
194
+ end
195
+
196
+ it 'should allow complex nestings inside blockquotes' do
197
+ # was a bug: further reduced in the following example, "should handle TT spans inside blockquotes"
198
+ input = dedent <<-END
199
+ code block
200
+
201
+ a normal para
202
+
203
+ > will nest
204
+ >
205
+ > line 1
206
+ > line 2
207
+ >
208
+ > other
209
+ >
210
+ > * here
211
+ > * is
212
+ > * a
213
+ > * list
214
+ >
215
+ > outer para with ''styled''
216
+ > `stuff` in it
217
+ >
218
+ > > inner
219
+ > > blockquote
220
+ > > # inner list
221
+ > > ## nested list
222
+
223
+ follow-up para
224
+ END
225
+ expected = dedent <<-END
226
+ <pre>code block</pre>
227
+ <p>a normal para</p>
228
+ <blockquote>
229
+ <p>will nest</p>
230
+ <pre>line 1
231
+ line 2</pre>
232
+ <p>other</p>
233
+ <ul>
234
+ <li>here</li>
235
+ <li>is</li>
236
+ <li>a</li>
237
+ <li>list</li>
238
+ </ul>
239
+ <p>outer para with <em>styled</em> <tt>stuff</tt> in it</p>
240
+ <blockquote>
241
+ <p>inner blockquote</p>
242
+ <ol>
243
+ <li>inner list
244
+ <ol>
245
+ <li>nested list</li>
246
+ </ol>
247
+ </li>
248
+ </ol>
249
+ </blockquote>
250
+ </blockquote>
251
+ <p>follow-up para</p>
252
+ END
253
+ @parser.parse(input).should == expected
254
+ end
255
+
256
+ it 'should handle TT spans inside blockquotes' do
257
+ # was a bug: this is a minimally reduced test case extracted from the integration tests
258
+ input = dedent <<-END
259
+ > some
260
+ > `styled`
261
+ END
262
+ expected = dedent <<-END
263
+ <blockquote>
264
+ <p>some <tt>styled</tt></p>
265
+ </blockquote>
266
+ END
267
+ @parser.parse(input).should == expected
268
+ end
269
+
270
+
271
+ it 'should handled nested lists which immediately follow paragraphs' do
272
+ # was a bug: this is a minimally reduced test case extracted from the integration tests
273
+ input = dedent <<-END
274
+ > Finally
275
+ > # Which
276
+ END
277
+ expected = dedent <<-END
278
+ <blockquote>
279
+ <p>Finally</p>
280
+ <ol>
281
+ <li>Which</li>
282
+ </ol>
283
+ </blockquote>
284
+ END
285
+ @parser.parse(input).should == expected
286
+ end
287
+
288
+ # TODO: tests for nesting other types of blocks
289
+ end
290
+
291
+ describe Wikitext::Parser, 'literal BLOCKQUOTE_START/BLOCKQUOTE_END tags' do
292
+ before do
293
+ @parser = Wikitext::Parser.new
294
+ end
295
+
296
+ it 'should accept literal BLOCKQUOTE_START/BLOCKQUOTE_END tags as an alternative to the standard syntax' do
297
+ input = '<blockquote>hello</blockquote>'
298
+ expected = dedent <<-END
299
+ <blockquote>
300
+ <p>hello</p>
301
+ </blockquote>
302
+ END
303
+ @parser.parse(input).should == expected
304
+
305
+ # alternative 1
306
+ input = dedent <<-END
307
+ <blockquote>
308
+ hello
309
+ </blockquote>
310
+ END
311
+ expected = dedent <<-END
312
+ <blockquote>
313
+ <p>hello</p>
314
+ </blockquote>
315
+ END
316
+ @parser.parse(input).should == expected
317
+
318
+ # alternative 2
319
+ input = dedent <<-END
320
+ <blockquote>hello
321
+ </blockquote>
322
+ END
323
+ expected = dedent <<-END
324
+ <blockquote>
325
+ <p>hello</p>
326
+ </blockquote>
327
+ END
328
+ @parser.parse(input).should == expected
329
+
330
+ # alternative 3
331
+ input = dedent <<-END
332
+ <blockquote>
333
+ hello</blockquote>
334
+ END
335
+ expected = dedent <<-END
336
+ <blockquote>
337
+ <p>hello</p>
338
+ </blockquote>
339
+ END
340
+ @parser.parse(input).should == expected
341
+
342
+ # note what happens if we indent (whitespace gets carried through; it is not identified as a PRE block
343
+ # in reality you'd never indent when editing wikitext anyway; the idea is to free yourself from details like that
344
+ input = dedent <<-END
345
+ <blockquote>
346
+ hello
347
+ </blockquote>
348
+ END
349
+ expected = dedent <<-END
350
+ <blockquote>
351
+ <p> hello</p>
352
+ </blockquote>
353
+ END
354
+ @parser.parse(input).should == expected
355
+ end
356
+
357
+ it 'should merge consecutive lines into a single paragraph' do
358
+ input = dedent <<-END
359
+ <blockquote>foo
360
+ bar
361
+ baz</blockquote>
362
+ END
363
+ expected = dedent <<-END
364
+ <blockquote>
365
+ <p>foo bar baz</p>
366
+ </blockquote>
367
+ END
368
+ @parser.parse(input).should == expected
369
+ end
370
+
371
+ it 'should process paragraph breaks' do
372
+ input = dedent <<-END
373
+ <blockquote>foo
374
+
375
+ baz</blockquote>
376
+ END
377
+ expected = dedent <<-END
378
+ <blockquote>
379
+ <p>foo</p>
380
+ <p>baz</p>
381
+ </blockquote>
382
+ END
383
+ @parser.parse(input).should == expected
384
+ end
385
+
386
+ it 'should pass through PRE tokens unaltered' do
387
+ input = dedent <<-END
388
+ <blockquote>foo
389
+ bar</blockquote>
390
+ END
391
+
392
+ # note the extra space: one for the CRLF and another for the PRE token
393
+ expected = dedent <<-END
394
+ <blockquote>
395
+ <p>foo bar</p>
396
+ </blockquote>
397
+ END
398
+ @parser.parse(input).should == expected
399
+ end
400
+
401
+ it 'should terminate open span-level elements on hitting the newline' do
402
+ # for now just test with EM; potentially add more examples later
403
+ input = dedent <<-END
404
+ <blockquote>foo ''bar
405
+ baz</blockquote>
406
+ END
407
+ expected = dedent <<-END
408
+ <blockquote>
409
+ <p>foo <em>bar</em> baz</p>
410
+ </blockquote>
411
+ END
412
+ @parser.parse(input).should == expected
413
+ end
414
+
415
+ it 'should pass through BLOCKQUOTE tokens escaped' do
416
+ input = dedent <<-END
417
+ <blockquote>foo
418
+ > bar
419
+ baz</blockquote>
420
+ END
421
+ expected = dedent <<-END
422
+ <blockquote>
423
+ <p>foo &gt; bar baz</p>
424
+ </blockquote>
425
+ END
426
+ @parser.parse(input).should == expected
427
+ end
428
+
429
+ it 'should be able to nest single-item unordered lists' do
430
+ input = '<blockquote>* foo</blockquote>'
431
+ expected = dedent <<-END
432
+ <blockquote>
433
+ <ul>
434
+ <li>foo</li>
435
+ </ul>
436
+ </blockquote>
437
+ END
438
+ @parser.parse(input).should == expected
439
+ end
440
+
441
+ it 'should be able to nest multi-item unordered lists' do
442
+ input = dedent <<-END
443
+ <blockquote>
444
+ * foo
445
+ * bar
446
+ * baz
447
+ </blockquote>
448
+ END
449
+ expected = dedent <<-END
450
+ <blockquote>
451
+ <ul>
452
+ <li>foo</li>
453
+ <li>bar</li>
454
+ <li>baz</li>
455
+ </ul>
456
+ </blockquote>
457
+ END
458
+ @parser.parse(input).should == expected
459
+ end
460
+
461
+ it 'should be able to nest nested unordered lists' do
462
+ input = dedent <<-END
463
+ <blockquote>
464
+ * foo
465
+ ** bar
466
+ * baz
467
+ </blockquote>
468
+ END
469
+ expected = dedent <<-END
470
+ <blockquote>
471
+ <ul>
472
+ <li>foo
473
+ <ul>
474
+ <li>bar</li>
475
+ </ul>
476
+ </li>
477
+ <li>baz</li>
478
+ </ul>
479
+ </blockquote>
480
+ END
481
+ @parser.parse(input).should == expected
482
+
483
+ # note that the exact placement of the closing tag doesn't matter
484
+ input = dedent <<-END
485
+ <blockquote>
486
+ * foo
487
+ ** bar
488
+ * baz</blockquote>
489
+ END
490
+ @parser.parse(input).should == expected
491
+
492
+ # likewise for the opening tag
493
+ input = dedent <<-END
494
+ <blockquote>* foo
495
+ ** bar
496
+ * baz
497
+ </blockquote>
498
+ END
499
+ @parser.parse(input).should == expected
500
+ end
501
+
502
+ it 'should be able to nest blockquotes' do
503
+ input = dedent <<-END
504
+ <blockquote>
505
+ foo
506
+ <blockquote>
507
+ bar
508
+ </blockquote>
509
+ baz
510
+ </blockquote>
511
+ END
512
+ expected = dedent <<-END
513
+ <blockquote>
514
+ <p>foo</p>
515
+ <blockquote>
516
+ <p>bar</p>
517
+ </blockquote>
518
+ <p>baz</p>
519
+ </blockquote>
520
+ END
521
+ @parser.parse(input).should == expected
522
+ end
523
+
524
+ it 'should be able to nest pre blocks' do
525
+ input = dedent <<-END
526
+ <blockquote>
527
+ outer 1
528
+ <pre>inner 1
529
+ inner 2</pre>
530
+ outer 2
531
+ </blockquote>
532
+ END
533
+ expected = dedent <<-END
534
+ <blockquote>
535
+ <p>outer 1</p>
536
+ <pre>inner 1
537
+ inner 2</pre>
538
+ <p>outer 2</p>
539
+ </blockquote>
540
+ END
541
+ @parser.parse(input).should == expected
542
+ end
543
+
544
+ it 'should support nesting of H1 spans' do
545
+ input = dedent <<-END
546
+ <blockquote>
547
+ = foo =
548
+ bar
549
+ </blockquote>
550
+ END
551
+
552
+ expected = dedent <<-END
553
+ <blockquote>
554
+ <h1>foo</h1>
555
+ <p>bar</p>
556
+ </blockquote>
557
+ END
558
+ @parser.parse(input).should == expected
559
+
560
+ # but note that this won't work
561
+ # the second "=" is not recognized as an H1_END because the scanner has no lookahead at the token level
562
+ input = '<blockquote>= foo =</blockquote>'
563
+ expected = dedent <<-END
564
+ <blockquote>
565
+ <h1>foo =</h1>
566
+ </blockquote>
567
+ END
568
+ @parser.parse(input).should == expected
569
+ end
570
+ end