wikitext 0.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/parser.c +19 -9
- data/ext/wikitext.c +1 -0
- data/spec/internal_link_spec.rb +430 -1
- data/spec/wikitext_spec.rb +10 -0
- metadata +2 -2
data/ext/parser.c
CHANGED
@@ -36,6 +36,7 @@ typedef struct
|
|
36
36
|
VALUE pending_crlf; // boolean (Qtrue or Qfalse)
|
37
37
|
VALUE autolink; // boolean (Qtrue or Qfalse)
|
38
38
|
VALUE treat_slash_as_special; // boolean (Qtrue or Qfalse)
|
39
|
+
VALUE space_to_underscore; // boolean (Qtrue or Qfalse)
|
39
40
|
VALUE special_link; // boolean (Qtrue or Qfalse): is the current link_target a "special" link?
|
40
41
|
str_t *line_ending;
|
41
42
|
int base_indent; // controlled by the :indent option to Wikitext::Parser#parse
|
@@ -548,10 +549,11 @@ inline VALUE _Wikitext_parser_trim_link_target(VALUE string)
|
|
548
549
|
|
549
550
|
// - non-printable (non-ASCII) characters converted to numeric entities
|
550
551
|
// - QUOT and AMP characters converted to named entities
|
551
|
-
// -
|
552
|
-
|
552
|
+
// - if rollback is Qtrue, there is no special treatment of spaces
|
553
|
+
// - if rollback is Qfalse, leading and trailing whitespace trimmed if trimmed
|
554
|
+
inline VALUE _Wikitext_parser_sanitize_link_target(parser_t *parser, VALUE rollback)
|
553
555
|
{
|
554
|
-
string
|
556
|
+
VALUE string = StringValue(parser->link_target); // raises if string is nil or doesn't quack like a string
|
555
557
|
char *src = RSTRING_PTR(string);
|
556
558
|
char *start = src; // remember this so we can check if we're at the start
|
557
559
|
long len = RSTRING_LEN(string);
|
@@ -605,7 +607,7 @@ inline VALUE _Wikitext_parser_sanitize_link_target(VALUE string, VALUE trim)
|
|
605
607
|
free(dest_ptr);
|
606
608
|
rb_raise(rb_eRangeError, "invalid link text (\">\" may not appear in link text)");
|
607
609
|
}
|
608
|
-
else if (*src == ' ' && src == start &&
|
610
|
+
else if (*src == ' ' && src == start && rollback == Qfalse)
|
609
611
|
start++; // we eat leading space
|
610
612
|
else if (*src >= 0x20 && *src <= 0x7e) // printable ASCII
|
611
613
|
{
|
@@ -630,7 +632,7 @@ inline VALUE _Wikitext_parser_sanitize_link_target(VALUE string, VALUE trim)
|
|
630
632
|
}
|
631
633
|
|
632
634
|
// trim trailing space if necessary
|
633
|
-
if (
|
635
|
+
if (rollback == Qfalse && non_space > dest_ptr && dest != non_space)
|
634
636
|
len = non_space - dest_ptr;
|
635
637
|
else
|
636
638
|
len = dest - dest_ptr;
|
@@ -641,7 +643,9 @@ inline VALUE _Wikitext_parser_sanitize_link_target(VALUE string, VALUE trim)
|
|
641
643
|
|
642
644
|
VALUE Wikitext_parser_sanitize_link_target(VALUE self, VALUE string)
|
643
645
|
{
|
644
|
-
|
646
|
+
parser_t parser;
|
647
|
+
parser.link_target = string;
|
648
|
+
return _Wikitext_parser_sanitize_link_target(&parser, Qfalse);
|
645
649
|
}
|
646
650
|
|
647
651
|
// encodes the input string according to RFCs 2396 and 2718
|
@@ -729,6 +733,8 @@ inline static void _Wikitext_parser_encode_link_target(parser_t *parser)
|
|
729
733
|
}
|
730
734
|
else if (*input == ' ' && input == start)
|
731
735
|
start++; // we eat leading space
|
736
|
+
else if (*input == ' ' && parser->space_to_underscore == Qtrue)
|
737
|
+
*dest++ = '_';
|
732
738
|
else // everything else gets URL-encoded
|
733
739
|
{
|
734
740
|
*dest++ = '%';
|
@@ -740,7 +746,7 @@ inline static void _Wikitext_parser_encode_link_target(parser_t *parser)
|
|
740
746
|
}
|
741
747
|
|
742
748
|
// trim trailing space if necessary
|
743
|
-
if (non_space > dest_ptr && dest
|
749
|
+
if (non_space > dest_ptr && dest != non_space)
|
744
750
|
dest_len = non_space - dest_ptr;
|
745
751
|
else
|
746
752
|
dest_len = dest - dest_ptr;
|
@@ -753,6 +759,7 @@ VALUE Wikitext_parser_encode_link_target(VALUE self, VALUE in)
|
|
753
759
|
parser_t parser;
|
754
760
|
parser.link_target = in;
|
755
761
|
parser.treat_slash_as_special = Qfalse;
|
762
|
+
parser.space_to_underscore = Qfalse;
|
756
763
|
_Wikitext_parser_encode_link_target(&parser);
|
757
764
|
return parser.link_target;
|
758
765
|
}
|
@@ -763,6 +770,7 @@ VALUE Wikitext_parser_encode_special_link_target(VALUE self, VALUE in)
|
|
763
770
|
parser_t parser;
|
764
771
|
parser.link_target = in;
|
765
772
|
parser.treat_slash_as_special = Qtrue;
|
773
|
+
parser.space_to_underscore = Qfalse;
|
766
774
|
_Wikitext_parser_encode_link_target(&parser);
|
767
775
|
return parser.link_target;
|
768
776
|
}
|
@@ -777,7 +785,7 @@ inline void _Wikitext_rollback_failed_link(parser_t *parser)
|
|
777
785
|
rb_str_cat(parser->output, link_start, sizeof(link_start) - 1);
|
778
786
|
if (!NIL_P(parser->link_target))
|
779
787
|
{
|
780
|
-
VALUE sanitized = _Wikitext_parser_sanitize_link_target(parser
|
788
|
+
VALUE sanitized = _Wikitext_parser_sanitize_link_target(parser, Qtrue);
|
781
789
|
rb_str_append(parser->output, sanitized);
|
782
790
|
if (scope_includes_separator)
|
783
791
|
{
|
@@ -823,6 +831,7 @@ VALUE Wikitext_parser_initialize(VALUE self)
|
|
823
831
|
rb_iv_set(self, "@external_link_class", rb_str_new2("external"));
|
824
832
|
rb_iv_set(self, "@mailto_class", rb_str_new2("mailto"));
|
825
833
|
rb_iv_set(self, "@internal_link_prefix", rb_str_new2("/wiki/"));
|
834
|
+
rb_iv_set(self, "@space_to_underscore", Qfalse);
|
826
835
|
rb_iv_set(self, "@treat_slash_as_special", Qtrue);
|
827
836
|
return self;
|
828
837
|
}
|
@@ -883,6 +892,7 @@ VALUE Wikitext_parser_parse(int argc, VALUE *argv, VALUE self)
|
|
883
892
|
parser->pending_crlf = Qfalse;
|
884
893
|
parser->autolink = rb_iv_get(self, "@autolink");
|
885
894
|
parser->treat_slash_as_special = rb_iv_get(self, "@treat_slash_as_special");
|
895
|
+
parser->space_to_underscore = rb_iv_get(self, "@space_to_underscore");
|
886
896
|
parser->special_link = Qfalse;
|
887
897
|
parser->line_ending = str_new_from_string(line_ending);
|
888
898
|
parser->base_indent = base_indent;
|
@@ -1872,7 +1882,7 @@ VALUE Wikitext_parser_parse(int argc, VALUE *argv, VALUE self)
|
|
1872
1882
|
// in internal link scope!
|
1873
1883
|
if (NIL_P(parser->link_text) || RSTRING_LEN(parser->link_text) == 0)
|
1874
1884
|
// use link target as link text
|
1875
|
-
parser->link_text = _Wikitext_parser_sanitize_link_target(parser
|
1885
|
+
parser->link_text = _Wikitext_parser_sanitize_link_target(parser, Qfalse);
|
1876
1886
|
else
|
1877
1887
|
parser->link_text = _Wikitext_parser_trim_link_target(parser->link_text);
|
1878
1888
|
_Wikitext_parser_encode_link_target(parser);
|
data/ext/wikitext.c
CHANGED
@@ -41,6 +41,7 @@ void Init_wikitext()
|
|
41
41
|
rb_define_attr(cWikitextParser, "mailto_class", Qtrue, Qtrue);
|
42
42
|
rb_define_attr(cWikitextParser, "autolink", Qtrue, Qtrue);
|
43
43
|
rb_define_attr(cWikitextParser, "treat_slash_as_special", Qtrue, Qtrue);
|
44
|
+
rb_define_attr(cWikitextParser, "space_to_underscore", Qtrue, Qtrue);
|
44
45
|
|
45
46
|
// Wikitext::Parser::Error
|
46
47
|
eWikitextParserError = rb_define_class_under(cWikitextParser, "Error", rb_eException);
|
data/spec/internal_link_spec.rb
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
17
17
|
require 'wikitext'
|
18
18
|
|
19
|
-
describe Wikitext::Parser, 'internal links' do
|
19
|
+
describe Wikitext::Parser, 'internal links (space to underscore off)' do
|
20
20
|
before do
|
21
21
|
@parser = Wikitext::Parser.new
|
22
22
|
end
|
@@ -443,3 +443,432 @@ describe Wikitext::Parser, 'internal links' do
|
|
443
443
|
end
|
444
444
|
end
|
445
445
|
end
|
446
|
+
|
447
|
+
describe Wikitext::Parser, 'internal links (space to underscore on)' do
|
448
|
+
before do
|
449
|
+
@parser = Wikitext::Parser.new
|
450
|
+
@parser.space_to_underscore = true
|
451
|
+
end
|
452
|
+
|
453
|
+
it 'should pass through unexpected link end tokens literally' do
|
454
|
+
@parser.parse('foo ]] bar').should == "<p>foo ]] bar</p>\n" # in plain scope
|
455
|
+
@parser.parse("foo '']]'' bar").should == "<p>foo <em>]]</em> bar</p>\n" # in EM scope
|
456
|
+
@parser.parse("foo ''']]''' bar").should == "<p>foo <strong>]]</strong> bar</p>\n" # in STRONG scope
|
457
|
+
@parser.parse("foo ''''']]''''' bar").should == "<p>foo <strong><em>]]</em></strong> bar</p>\n" # in STRONG_EM scope
|
458
|
+
@parser.parse('foo <tt>]]</tt> bar').should == "<p>foo <tt>]]</tt> bar</p>\n" # in TT scope
|
459
|
+
@parser.parse('= foo ]] bar =').should == "<h1>foo ]] bar</h1>\n" # in H1 scope
|
460
|
+
@parser.parse('== foo ]] bar ==').should == "<h2>foo ]] bar</h2>\n" # in H2 scope
|
461
|
+
@parser.parse('=== foo ]] bar ===').should == "<h3>foo ]] bar</h3>\n" # in H3 scope
|
462
|
+
@parser.parse('==== foo ]] bar ====').should == "<h4>foo ]] bar</h4>\n" # in H4 scope
|
463
|
+
@parser.parse('===== foo ]] bar =====').should == "<h5>foo ]] bar</h5>\n" # in H5 scope
|
464
|
+
@parser.parse('====== foo ]] bar ======').should == "<h6>foo ]] bar</h6>\n" # in H6 scope
|
465
|
+
@parser.parse('> ]]').should == "<blockquote>\n <p>]]</p>\n</blockquote>\n" # in BLOCKQUOTE scope
|
466
|
+
end
|
467
|
+
|
468
|
+
it 'should turn single words into links' do
|
469
|
+
@parser.parse('[[foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
470
|
+
end
|
471
|
+
|
472
|
+
it 'should turn multiple words into links, converting spaces into underscores' do
|
473
|
+
@parser.parse('[[foo bar]]').should == %Q{<p><a href="/wiki/foo_bar">foo bar</a></p>\n}
|
474
|
+
end
|
475
|
+
|
476
|
+
it 'should trim leading whitespace' do
|
477
|
+
@parser.parse('[[ foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
478
|
+
@parser.parse('[[ foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
479
|
+
@parser.parse('[[ foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
480
|
+
@parser.parse('[[ foo]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
481
|
+
end
|
482
|
+
|
483
|
+
it 'should trim trailing whitespace' do
|
484
|
+
@parser.parse('[[foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
485
|
+
@parser.parse('[[foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
486
|
+
@parser.parse('[[foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
487
|
+
@parser.parse('[[foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n} # was a bug (exception)
|
488
|
+
@parser.parse('[[foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n} # was a bug (crash)
|
489
|
+
end
|
490
|
+
|
491
|
+
it 'should trim leading and trailing whitespace (combined)' do
|
492
|
+
@parser.parse('[[ foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
493
|
+
@parser.parse('[[ foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
494
|
+
@parser.parse('[[ foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
495
|
+
@parser.parse('[[ foo ]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
496
|
+
end
|
497
|
+
|
498
|
+
it 'should convert embedded whitespace into underscores' do
|
499
|
+
@parser.parse('[[ foo bar ]]').should == %Q{<p><a href="/wiki/foo_bar">foo bar</a></p>\n}
|
500
|
+
@parser.parse('[[foo bar ]]').should == %Q{<p><a href="/wiki/foo_bar">foo bar</a></p>\n}
|
501
|
+
@parser.parse('[[ foo bar ]]').should == %Q{<p><a href="/wiki/foo_bar">foo bar</a></p>\n}
|
502
|
+
end
|
503
|
+
|
504
|
+
it 'should encode and sanitize quotes' do
|
505
|
+
# note how percent encoding is used in the href, and named entities in the link text
|
506
|
+
@parser.parse('[[hello "world"]]').should == %Q{<p><a href="/wiki/hello_%22world%22">hello "world"</a></p>\n}
|
507
|
+
end
|
508
|
+
|
509
|
+
it 'should encode and sanitize ampersands' do
|
510
|
+
@parser.parse('[[a & b]]').should == %Q{<p><a href="/wiki/a_%26_b">a & b</a></p>\n}
|
511
|
+
end
|
512
|
+
|
513
|
+
it 'should allow ampersand entities (special exception)' do
|
514
|
+
@parser.parse('[[a & b]]').should == %Q{<p><a href="/wiki/a_%26_b">a & b</a></p>\n}
|
515
|
+
end
|
516
|
+
|
517
|
+
it 'should allow quote entities (special exception)' do
|
518
|
+
@parser.parse('[[a " b]]').should == %Q{<p><a href="/wiki/a_%22_b">a " b</a></p>\n}
|
519
|
+
end
|
520
|
+
|
521
|
+
it 'should handle mixed scenarios (quotes, ampersands, non-ASCII characers)' do
|
522
|
+
expected = %Q{<p><a href="/wiki/foo%2c_%22bar%22_%26_baz_%e2%82%ac">foo, "bar" & baz €</a></p>\n}
|
523
|
+
@parser.parse('[[foo, "bar" & baz €]]').should == expected
|
524
|
+
end
|
525
|
+
|
526
|
+
it 'should handle links in paragraph flows' do
|
527
|
+
expected = %Q{<p>foo <a href="/wiki/bar">bar</a> baz</p>\n}
|
528
|
+
@parser.parse('foo [[bar]] baz').should == expected # was a bug
|
529
|
+
end
|
530
|
+
|
531
|
+
describe 'custom link text' do
|
532
|
+
it 'should recognize link text placed after the separator' do
|
533
|
+
@parser.parse('[[foo|bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
534
|
+
end
|
535
|
+
|
536
|
+
it 'should trim whitespace to the left of the separator' do
|
537
|
+
@parser.parse('[[foo |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
538
|
+
@parser.parse('[[foo |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
539
|
+
@parser.parse('[[foo |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
540
|
+
@parser.parse('[[foo |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
541
|
+
@parser.parse('[[foo |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
542
|
+
@parser.parse('[[foo |bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
543
|
+
end
|
544
|
+
|
545
|
+
it 'should trim whitespace to the right of the separator' do
|
546
|
+
@parser.parse('[[foo| bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
547
|
+
@parser.parse('[[foo| bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
548
|
+
@parser.parse('[[foo| bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
549
|
+
@parser.parse('[[foo| bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
550
|
+
@parser.parse('[[foo| bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
551
|
+
@parser.parse('[[foo| bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
552
|
+
end
|
553
|
+
|
554
|
+
it 'should trim whitespace on both sides of the separator (at the same time)' do
|
555
|
+
@parser.parse('[[foo | bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
556
|
+
@parser.parse('[[foo | bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
557
|
+
@parser.parse('[[foo | bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
558
|
+
@parser.parse('[[foo | bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
559
|
+
@parser.parse('[[foo | bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
560
|
+
@parser.parse('[[foo | bar]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
561
|
+
end
|
562
|
+
|
563
|
+
it 'should trim trailing whitespace from the link text' do
|
564
|
+
@parser.parse('[[foo|bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
565
|
+
@parser.parse('[[foo|bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
566
|
+
@parser.parse('[[foo|bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
567
|
+
@parser.parse('[[foo|bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
568
|
+
@parser.parse('[[foo|bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
569
|
+
@parser.parse('[[foo|bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
570
|
+
end
|
571
|
+
|
572
|
+
it 'should trim leading and trailing whitespace from the link text' do
|
573
|
+
@parser.parse('[[foo| bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
574
|
+
@parser.parse('[[foo| bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
575
|
+
@parser.parse('[[foo| bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
576
|
+
@parser.parse('[[foo| bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
577
|
+
@parser.parse('[[foo| bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
578
|
+
@parser.parse('[[foo| bar ]]').should == %Q{<p><a href="/wiki/foo">bar</a></p>\n}
|
579
|
+
end
|
580
|
+
|
581
|
+
it 'should treat a separator inside the link text as part of the link text' do
|
582
|
+
@parser.parse('[[foo|bar|baz]]').should == %Q{<p><a href="/wiki/foo">bar|baz</a></p>\n}
|
583
|
+
end
|
584
|
+
|
585
|
+
it 'should treat separators outside of links as normal text' do
|
586
|
+
@parser.parse('foo|bar').should == %Q{<p>foo|bar</p>\n}
|
587
|
+
end
|
588
|
+
|
589
|
+
it 'should allow em markup in the custom link text' do
|
590
|
+
expected = %Q{<p><a href="/wiki/foo">bar <em>baz</em></a></p>\n}
|
591
|
+
@parser.parse("[[foo|bar ''baz'']]").should == expected
|
592
|
+
end
|
593
|
+
|
594
|
+
it 'should automatically close unclosed em markup in the custom link text' do
|
595
|
+
expected = %Q{<p><a href="/wiki/foo">bar <em>baz</em></a></p>\n}
|
596
|
+
@parser.parse("[[foo|bar ''baz]]").should == expected
|
597
|
+
end
|
598
|
+
|
599
|
+
it 'should allow strong markup in the custom link text' do
|
600
|
+
expected = %Q{<p><a href="/wiki/foo">bar <strong>baz</strong></a></p>\n}
|
601
|
+
@parser.parse("[[foo|bar '''baz''']]").should == expected
|
602
|
+
end
|
603
|
+
|
604
|
+
it 'should automatically close unclosed strong markup in the custom link text' do
|
605
|
+
expected = %Q{<p><a href="/wiki/foo">bar <strong>baz</strong></a></p>\n}
|
606
|
+
@parser.parse("[[foo|bar '''baz]]").should == expected
|
607
|
+
end
|
608
|
+
|
609
|
+
it 'should allow strong/em markup in the custom link text' do
|
610
|
+
expected = %Q{<p><a href="/wiki/foo">bar <strong><em>baz</em></strong></a></p>\n}
|
611
|
+
@parser.parse("[[foo|bar '''''baz''''']]").should == expected
|
612
|
+
end
|
613
|
+
|
614
|
+
it 'should automatically close unclosed strong/em markup in the custom link text' do
|
615
|
+
expected = %Q{<p><a href="/wiki/foo">bar <strong><em>baz</em></strong></a></p>\n}
|
616
|
+
@parser.parse("[[foo|bar '''''baz]]").should == expected
|
617
|
+
end
|
618
|
+
|
619
|
+
it 'should allow tt markup in the custom link text' do
|
620
|
+
expected = %Q{<p><a href="/wiki/foo">bar <tt>baz</tt></a></p>\n}
|
621
|
+
@parser.parse('[[foo|bar <tt>baz</tt>]]').should == expected
|
622
|
+
end
|
623
|
+
|
624
|
+
it 'should automatically close unclosed tt markup in the custom link text' do
|
625
|
+
expected = %Q{<p><a href="/wiki/foo">bar <tt>baz</tt></a></p>\n}
|
626
|
+
@parser.parse('[[foo|bar <tt>baz]]').should == expected
|
627
|
+
end
|
628
|
+
|
629
|
+
it 'should allow named entities in the custom link text' do
|
630
|
+
expected = %Q{<p><a href="/wiki/foo">bar ©</a></p>\n}
|
631
|
+
@parser.parse('[[foo|bar ©]]').should == expected
|
632
|
+
|
633
|
+
# explicitly test " because it is tokenized separately from the other named entities
|
634
|
+
expected = %Q{<p><a href="/wiki/foo">bar "</a></p>\n}
|
635
|
+
@parser.parse('[[foo|bar "]]').should == expected
|
636
|
+
|
637
|
+
# explicitly test & because it is tokenized separately from the other named entities
|
638
|
+
expected = %Q{<p><a href="/wiki/foo">bar &</a></p>\n}
|
639
|
+
@parser.parse('[[foo|bar &]]').should == expected
|
640
|
+
end
|
641
|
+
|
642
|
+
it 'should allow decimal entities in the custom link text' do
|
643
|
+
expected = %Q{<p><a href="/wiki/foo">bar €</a></p>\n}
|
644
|
+
@parser.parse('[[foo|bar €]]').should == expected
|
645
|
+
end
|
646
|
+
|
647
|
+
it 'should allow hexadecimal entities in the custom link text' do
|
648
|
+
expected = %Q{<p><a href="/wiki/foo">bar €</a></p>\n}
|
649
|
+
@parser.parse('[[foo|bar €]]').should == expected
|
650
|
+
end
|
651
|
+
|
652
|
+
it 'should sanitize non-ASCII characters in the custom link text' do
|
653
|
+
expected = %Q{<p><a href="/wiki/foo">bar €</a></p>\n}
|
654
|
+
@parser.parse('[[foo|bar €]]').should == expected
|
655
|
+
end
|
656
|
+
|
657
|
+
it 'should sanitize characters that have special meaning in HTML in the custom link text' do
|
658
|
+
expected = %Q{<p><a href="/wiki/foo">bar <</a></p>\n}
|
659
|
+
@parser.parse('[[foo|bar <]]').should == expected
|
660
|
+
|
661
|
+
expected = %Q{<p><a href="/wiki/foo">bar ></a></p>\n}
|
662
|
+
@parser.parse('[[foo|bar >]]').should == expected
|
663
|
+
|
664
|
+
expected = %Q{<p><a href="/wiki/foo">bar &</a></p>\n}
|
665
|
+
@parser.parse('[[foo|bar &]]').should == expected
|
666
|
+
|
667
|
+
expected = %Q{<p><a href="/wiki/foo">bar "baz"</a></p>\n}
|
668
|
+
@parser.parse('[[foo|bar "baz"]]').should == expected
|
669
|
+
end
|
670
|
+
|
671
|
+
it 'should allow nowiki markup in the custom link text' do
|
672
|
+
expected = %Q{<p><a href="/wiki/foo">bar [[</a></p>\n}
|
673
|
+
@parser.parse("[[foo|bar <nowiki>[[</nowiki>]]").should == expected
|
674
|
+
|
675
|
+
expected = %Q{<p><a href="/wiki/foo">bar [</a></p>\n}
|
676
|
+
@parser.parse("[[foo|bar <nowiki>[</nowiki>]]").should == expected
|
677
|
+
|
678
|
+
expected = %Q{<p><a href="/wiki/foo">bar ]]</a></p>\n}
|
679
|
+
@parser.parse("[[foo|bar <nowiki>]]</nowiki>]]").should == expected
|
680
|
+
|
681
|
+
expected = %Q{<p><a href="/wiki/foo">bar ]</a></p>\n}
|
682
|
+
@parser.parse("[[foo|bar <nowiki>]</nowiki>]]").should == expected
|
683
|
+
end
|
684
|
+
end
|
685
|
+
|
686
|
+
describe 'overriding the link prefix' do
|
687
|
+
it 'should be able to override the link prefix' do
|
688
|
+
@parser.internal_link_prefix = '/custom/'
|
689
|
+
@parser.parse('[[foo]]').should == %Q{<p><a href="/custom/foo">foo</a></p>\n}
|
690
|
+
end
|
691
|
+
|
692
|
+
it 'should interpet a nil link prefix as meaning no prefix' do
|
693
|
+
@parser.internal_link_prefix = nil
|
694
|
+
@parser.parse('[[foo]]').should == %Q{<p><a href="foo">foo</a></p>\n}
|
695
|
+
end
|
696
|
+
end
|
697
|
+
|
698
|
+
describe 'special links' do
|
699
|
+
it 'should recognize links of the form "bug/10" as special links' do
|
700
|
+
@parser.parse('[[bug/10]]').should == %Q{<p><a href="/bug/10">bug/10</a></p>\n}
|
701
|
+
@parser.parse('[[issue/25]]').should == %Q{<p><a href="/issue/25">issue/25</a></p>\n}
|
702
|
+
@parser.parse('[[post/7]]').should == %Q{<p><a href="/post/7">post/7</a></p>\n}
|
703
|
+
end
|
704
|
+
|
705
|
+
it 'should not recognize special links when "treat_slash_as_special" is set to false' do
|
706
|
+
@parser.treat_slash_as_special = false
|
707
|
+
@parser.parse('[[bug/10]]').should == %Q{<p><a href="/wiki/bug%2f10">bug/10</a></p>\n}
|
708
|
+
@parser.parse('[[issue/25]]').should == %Q{<p><a href="/wiki/issue%2f25">issue/25</a></p>\n}
|
709
|
+
@parser.parse('[[post/7]]').should == %Q{<p><a href="/wiki/post%2f7">post/7</a></p>\n}
|
710
|
+
end
|
711
|
+
|
712
|
+
it 'should accept custom link text in conjunction with special links' do
|
713
|
+
@parser.parse('[[bug/10|bug #10]]').should == %Q{<p><a href="/bug/10">bug #10</a></p>\n}
|
714
|
+
end
|
715
|
+
|
716
|
+
it 'should ignore link prefix overrides when emitting special links' do
|
717
|
+
@parser.internal_link_prefix = '/custom/'
|
718
|
+
@parser.parse('[[bug/10]]').should == %Q{<p><a href="/bug/10">bug/10</a></p>\n}
|
719
|
+
end
|
720
|
+
|
721
|
+
it 'should not classify links as special merely because of the presence of a slash' do
|
722
|
+
# we want the syntax to be tight to minimize false positives
|
723
|
+
@parser.parse('[[foo/bar]]').should == %Q{<p><a href="/wiki/foo%2fbar">foo/bar</a></p>\n}
|
724
|
+
end
|
725
|
+
|
726
|
+
it 'should not accept special links which have a leading forward slash' do
|
727
|
+
# this is a syntax error
|
728
|
+
@parser.parse('[[/bug/10]]').should == %Q{<p><a href="/wiki/%2fbug%2f10">/bug/10</a></p>\n}
|
729
|
+
end
|
730
|
+
end
|
731
|
+
|
732
|
+
describe 'invalid links' do
|
733
|
+
it 'should not allow entities in the link text' do
|
734
|
+
@parser.parse('[[a € b]]').should == "<p>[[a € b]]</p>\n"
|
735
|
+
end
|
736
|
+
|
737
|
+
it 'should not allow URIs in the link text' do
|
738
|
+
expected = %Q{<p>[[hello <a href="http://example.com/" class="external">http://example.com/</a> world]]</p>\n}
|
739
|
+
@parser.parse('[[hello http://example.com/ world]]').should == expected
|
740
|
+
end
|
741
|
+
|
742
|
+
it 'should handle embedded [[ inside links' do
|
743
|
+
# note how first part "[[foo " in itself is invalid and so gets rejected and echoed literally
|
744
|
+
expected = %Q{<p>[[foo <a href="/wiki/bar">bar</a></p>\n}
|
745
|
+
@parser.parse('[[foo [[bar]]').should == expected
|
746
|
+
end
|
747
|
+
|
748
|
+
it 'should handled embedded ]] inside links' do
|
749
|
+
# note how the link gets terminated early and the trailing part is rejected and echoed literally
|
750
|
+
expected = %Q{<p><a href="/wiki/foo">foo</a>bar]]</p>\n}
|
751
|
+
@parser.parse('[[foo ]]bar]]').should == expected
|
752
|
+
end
|
753
|
+
|
754
|
+
it 'should handle embedded [ inside links' do
|
755
|
+
# [ is not allowed at all so the entire link is rendered invalid
|
756
|
+
expected = "<p>[[foo [bar]]</p>\n"
|
757
|
+
@parser.parse('[[foo [bar]]').should == expected
|
758
|
+
end
|
759
|
+
|
760
|
+
it 'should handle embedded ] inside links' do
|
761
|
+
# [ is not allowed at all so the entire link is rendered invalid
|
762
|
+
expected = "<p>[[foo ]bar]]</p>\n"
|
763
|
+
@parser.parse('[[foo ]bar]]').should == expected
|
764
|
+
end
|
765
|
+
|
766
|
+
describe 'unterminated link targets (end-of-file)' do
|
767
|
+
it 'should rollback and show the unterminated link' do
|
768
|
+
@parser.parse('[[foo').should == %Q{<p>[[foo</p>\n}
|
769
|
+
end
|
770
|
+
|
771
|
+
it 'should not trim leading whitespace when rolling back' do
|
772
|
+
@parser.parse('[[ foo').should == %Q{<p>[[ foo</p>\n}
|
773
|
+
@parser.parse('[[ foo').should == %Q{<p>[[ foo</p>\n}
|
774
|
+
@parser.parse('[[ foo').should == %Q{<p>[[ foo</p>\n}
|
775
|
+
@parser.parse('[[ foo').should == %Q{<p>[[ foo</p>\n}
|
776
|
+
end
|
777
|
+
|
778
|
+
it 'should not trim trailing whitespace when rolling back' do
|
779
|
+
@parser.parse('[[foo ').should == %Q{<p>[[foo </p>\n}
|
780
|
+
@parser.parse('[[foo ').should == %Q{<p>[[foo </p>\n}
|
781
|
+
@parser.parse('[[foo ').should == %Q{<p>[[foo </p>\n}
|
782
|
+
@parser.parse('[[foo ').should == %Q{<p>[[foo </p>\n}
|
783
|
+
end
|
784
|
+
|
785
|
+
it 'should not trim leadig and trailing whitespace (combined) when rolling back' do
|
786
|
+
@parser.parse('[[ foo ').should == %Q{<p>[[ foo </p>\n}
|
787
|
+
@parser.parse('[[ foo ').should == %Q{<p>[[ foo </p>\n}
|
788
|
+
@parser.parse('[[ foo ').should == %Q{<p>[[ foo </p>\n}
|
789
|
+
@parser.parse('[[ foo ').should == %Q{<p>[[ foo </p>\n}
|
790
|
+
end
|
791
|
+
end
|
792
|
+
|
793
|
+
describe 'unterminated link targets (end-of-line)' do
|
794
|
+
it 'should rollback and show the unterminated link' do
|
795
|
+
@parser.parse("[[foo\n").should == %Q{<p>[[foo</p>\n}
|
796
|
+
end
|
797
|
+
|
798
|
+
it 'should not trim leading whitespace when rolling back' do
|
799
|
+
@parser.parse("[[ foo\n").should == %Q{<p>[[ foo</p>\n}
|
800
|
+
@parser.parse("[[ foo\n").should == %Q{<p>[[ foo</p>\n}
|
801
|
+
@parser.parse("[[ foo\n").should == %Q{<p>[[ foo</p>\n}
|
802
|
+
@parser.parse("[[ foo\n").should == %Q{<p>[[ foo</p>\n}
|
803
|
+
end
|
804
|
+
|
805
|
+
it 'should not trim trailing whitespace when rolling back' do
|
806
|
+
@parser.parse("[[foo \n").should == %Q{<p>[[foo </p>\n}
|
807
|
+
@parser.parse("[[foo \n").should == %Q{<p>[[foo </p>\n}
|
808
|
+
@parser.parse("[[foo \n").should == %Q{<p>[[foo </p>\n}
|
809
|
+
@parser.parse("[[foo \n").should == %Q{<p>[[foo </p>\n}
|
810
|
+
end
|
811
|
+
|
812
|
+
it 'should not trim leading and trailing whitespace (combined) when rolling back' do
|
813
|
+
@parser.parse("[[ foo \n").should == %Q{<p>[[ foo </p>\n}
|
814
|
+
@parser.parse("[[ foo \n").should == %Q{<p>[[ foo </p>\n}
|
815
|
+
@parser.parse("[[ foo \n").should == %Q{<p>[[ foo </p>\n}
|
816
|
+
@parser.parse("[[ foo \n").should == %Q{<p>[[ foo </p>\n}
|
817
|
+
end
|
818
|
+
end
|
819
|
+
|
820
|
+
describe 'missing link text' do
|
821
|
+
it 'should use link target' do
|
822
|
+
@parser.parse('[[foo|]]').should == %Q{<p><a href="/wiki/foo">foo</a></p>\n}
|
823
|
+
end
|
824
|
+
end
|
825
|
+
|
826
|
+
describe 'link cut off at separator (end-of-file)' do
|
827
|
+
it 'should rollback and show the unterminated link' do
|
828
|
+
@parser.parse('[[foo|').should == %Q{<p>[[foo|</p>\n}
|
829
|
+
@parser.parse('[[foo| ').should == %Q{<p>[[foo| </p>\n}
|
830
|
+
@parser.parse('[[foo| ').should == %Q{<p>[[foo| </p>\n}
|
831
|
+
@parser.parse('[[foo| ').should == %Q{<p>[[foo| </p>\n}
|
832
|
+
@parser.parse('[[foo| ').should == %Q{<p>[[foo| </p>\n}
|
833
|
+
@parser.parse('[[foo| ').should == %Q{<p>[[foo| </p>\n}
|
834
|
+
@parser.parse('[[foo| ').should == %Q{<p>[[foo| </p>\n}
|
835
|
+
end
|
836
|
+
end
|
837
|
+
|
838
|
+
describe 'link cut off at separator (end-of-line)' do
|
839
|
+
it 'should rollback and show the unterminated link' do
|
840
|
+
@parser.parse("[[foo|\n").should == %Q{<p>[[foo|</p>\n}
|
841
|
+
@parser.parse("[[foo| \n").should == %Q{<p>[[foo| </p>\n}
|
842
|
+
@parser.parse("[[foo| \n").should == %Q{<p>[[foo| </p>\n}
|
843
|
+
@parser.parse("[[foo| \n").should == %Q{<p>[[foo| </p>\n}
|
844
|
+
@parser.parse("[[foo| \n").should == %Q{<p>[[foo| </p>\n}
|
845
|
+
@parser.parse("[[foo| \n").should == %Q{<p>[[foo| </p>\n}
|
846
|
+
@parser.parse("[[foo| \n").should == %Q{<p>[[foo| </p>\n}
|
847
|
+
end
|
848
|
+
end
|
849
|
+
|
850
|
+
describe 'unterminated link text (end-of-file)' do
|
851
|
+
it 'should rollback and show the unterminated link' do
|
852
|
+
@parser.parse('[[foo|hello').should == %Q{<p>[[foo|hello</p>\n}
|
853
|
+
@parser.parse('[[foo|hello ').should == %Q{<p>[[foo|hello </p>\n}
|
854
|
+
@parser.parse('[[foo|hello ').should == %Q{<p>[[foo|hello </p>\n}
|
855
|
+
@parser.parse('[[foo|hello ').should == %Q{<p>[[foo|hello </p>\n}
|
856
|
+
@parser.parse('[[foo|hello ').should == %Q{<p>[[foo|hello </p>\n}
|
857
|
+
@parser.parse('[[foo|hello ').should == %Q{<p>[[foo|hello </p>\n}
|
858
|
+
@parser.parse('[[foo|hello ').should == %Q{<p>[[foo|hello </p>\n}
|
859
|
+
end
|
860
|
+
end
|
861
|
+
|
862
|
+
describe 'unterminated link text (end-of-line)' do
|
863
|
+
it 'should rollback and show the unterminated link' do
|
864
|
+
@parser.parse("[[foo|hello\n").should == %Q{<p>[[foo|hello</p>\n}
|
865
|
+
@parser.parse("[[foo|hello \n").should == %Q{<p>[[foo|hello </p>\n}
|
866
|
+
@parser.parse("[[foo|hello \n").should == %Q{<p>[[foo|hello </p>\n}
|
867
|
+
@parser.parse("[[foo|hello \n").should == %Q{<p>[[foo|hello </p>\n}
|
868
|
+
@parser.parse("[[foo|hello \n").should == %Q{<p>[[foo|hello </p>\n}
|
869
|
+
@parser.parse("[[foo|hello \n").should == %Q{<p>[[foo|hello </p>\n}
|
870
|
+
@parser.parse("[[foo|hello \n").should == %Q{<p>[[foo|hello </p>\n}
|
871
|
+
end
|
872
|
+
end
|
873
|
+
end
|
874
|
+
end
|
data/spec/wikitext_spec.rb
CHANGED
@@ -16,6 +16,16 @@
|
|
16
16
|
require File.join(File.dirname(__FILE__), 'spec_helper.rb')
|
17
17
|
require 'wikitext'
|
18
18
|
|
19
|
+
describe Wikitext::Parser do
|
20
|
+
before do
|
21
|
+
@parser = Wikitext::Parser.new
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should turn space-to-underscore off by default' do
|
25
|
+
@parser.space_to_underscore.should == false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
19
29
|
describe Wikitext::Parser, 'parsing non-ASCII input' do
|
20
30
|
before do
|
21
31
|
@parser = Wikitext::Parser.new
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wikitext
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.2"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wincent Colaiuta
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-02-
|
12
|
+
date: 2008-02-18 00:00:00 +01:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|