wikitext 0.1 → 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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