wikitext 0.1 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- // - leading and trailing whitespace trimmed if trim is Qtrue
552
- inline VALUE _Wikitext_parser_sanitize_link_target(VALUE string, VALUE trim)
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 = StringValue(string); // raises if string is nil or doesn't quack like a 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 && trim == Qtrue)
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 (trim == Qtrue && non_space > dest_ptr && dest != non_space)
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
- return (_Wikitext_parser_sanitize_link_target(string, Qtrue));
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 - 1 != non_space)
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->link_target, Qfalse);
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->link_target, Qtrue);
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);
@@ -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);
@@ -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 &quot;world&quot;</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 &amp; b</a></p>\n}
511
+ end
512
+
513
+ it 'should allow ampersand entities (special exception)' do
514
+ @parser.parse('[[a &amp; b]]').should == %Q{<p><a href="/wiki/a_%26_b">a &amp; b</a></p>\n}
515
+ end
516
+
517
+ it 'should allow quote entities (special exception)' do
518
+ @parser.parse('[[a &quot; b]]').should == %Q{<p><a href="/wiki/a_%22_b">a &quot; 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, &quot;bar&quot; &amp; baz &#x20ac;</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 &copy;</a></p>\n}
631
+ @parser.parse('[[foo|bar &copy;]]').should == expected
632
+
633
+ # explicitly test &quot; because it is tokenized separately from the other named entities
634
+ expected = %Q{<p><a href="/wiki/foo">bar &quot;</a></p>\n}
635
+ @parser.parse('[[foo|bar &quot;]]').should == expected
636
+
637
+ # explicitly test &amp; because it is tokenized separately from the other named entities
638
+ expected = %Q{<p><a href="/wiki/foo">bar &amp;</a></p>\n}
639
+ @parser.parse('[[foo|bar &amp;]]').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 &#8364;</a></p>\n}
644
+ @parser.parse('[[foo|bar &#8364;]]').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 &#x20ac;</a></p>\n}
649
+ @parser.parse('[[foo|bar &#x20ac;]]').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 &#x20ac;</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 &lt;</a></p>\n}
659
+ @parser.parse('[[foo|bar <]]').should == expected
660
+
661
+ expected = %Q{<p><a href="/wiki/foo">bar &gt;</a></p>\n}
662
+ @parser.parse('[[foo|bar >]]').should == expected
663
+
664
+ expected = %Q{<p><a href="/wiki/foo">bar &amp;</a></p>\n}
665
+ @parser.parse('[[foo|bar &]]').should == expected
666
+
667
+ expected = %Q{<p><a href="/wiki/foo">bar &quot;baz&quot;</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 &euro; b]]').should == "<p>[[a &euro; 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
@@ -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.1"
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-13 00:00:00 +01:00
12
+ date: 2008-02-18 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15