Text-Markup-0.23000755000767000024 012527274673 13213 5ustar00davidstaff000000000000Text-Markup-0.23/Build.PL000444000767000024 274112527274673 14650 0ustar00davidstaff000000000000use strict; use warnings; use Module::Build; my $build = Module::Build->new( module_name => 'Text::Markup', license => 'perl', create_makefile_pl => 'traditional', configure_requires => { 'Module::Build' => '0.30' }, build_requires => { 'File::Spec::Functions' => 0, 'Module::Build' => '0.30', 'Test::More' => '0.96', }, requires => { 'File::BOM' => '0.14', 'HTML::Entities' => 0, 'HTML::Tagset' => 0, # Needed by Text::MediawikiFormat 'IPC::Open3' => 0, 'perl' => 5.008001, 'Pod::Simple::XHTML' => '3.15', 'Symbol' => 0, 'Text::Markdown' => '1.000004', 'Text::MultiMarkdown' => '1.000028', 'Text::MediawikiFormat' => '1.0', 'Text::Textile' => '2.10', 'Text::Trac' => '0.10', 'Parse::BBCode' => '0.15', 'Text::WikiCreole' => '0.07', }, recommends => { 'Test::Pod' => '1.41', 'Test::Pod::Coverage' => '1.06', }, meta_merge => { resources => { homepage => 'http://search.cpan.org/dist/Text-Markup/', bugtracker => 'http://github.com/theory/text-markup/issues/', repository => 'http://github.com/theory/text-markup', } }, ); $build->add_build_element('py'); $build->create_build_script; Text-Markup-0.23/Changes000444000767000024 637412527274673 14655 0ustar00davidstaff000000000000Revision history for Perl extension Text-Markup. 0.23 2015-05-21T06:23:35Z - Added BBcode and Creole to the module description. - Fixed a failing test for the Mediawiki format due to a change in CGI v4.14. This reverses the workaround required by CGI 4.11, introduced in v0.20. Not that you care. It's just a test change. - Updated the Pod parser to determine the indentation of verbatim blocks by the line with the shortest leading whitespace, rather than the whitespace of just the first line. Inspired by an equivalent approach in Mojolicious by Joel Berger. 0.22 2015-02-20T03:52:36Z - Added support for Creole. Thanks to Lucas Kanashiro for the patch! 0.21 2015-02-17T00:18:20Z - Fixed description of Asciidoc and added it to the README. - Added support for BBcode. Thanks to Lucas Kanashiro for the patch! 0.20 2015-01-22T00:54:50Z - Fixed a failing test for the Mediawiki format due to a change in CGI v4.11. Thanks to Andreas Koenig for the report and diagnosis. 0.19 2014-02-07T04:00:56Z - Fixed Pod markup so that it does not strip text from the first line of verbatim blocks. - Removed the `--safe` option from Asciidoc. It is just borked with the XHTML back end. 0.18 2013-06-08T23:24:09Z - Now require HTML::Tagset, since Text::MediawikiFormat seems to need it but only recommends it. - Removed all Pod tests from the distribution. - Updated reST to support docutils 0.7 - 0.10 and when Pygments is not available. Daniele Varrazzo. 0.17 2012-02-28T04:31:07Z - Added Asciidoc support. 0.16 2012-02-13T17:23:00Z - Rest support now uses its own implementation of `rst2html` so that it can render specialized reST documents, such as Sphinx files, in a more forgiving way: it preserves the content of unknown directives while not emulating specialized rendering. Written by Daniele Varrazzo. - Improved handling of Sphinx directives in Rest output. Most directives are stripped out, although `function` directives now turn out much nicer. Props to Daniele Varrazzo for the work on the Rest parser. - Fixed character encoding issues with the Rest parser. - Fixed a character encoding issue in the test suite. 0.15 2012-01-13T23:04:16Z - Changed the parsers to return `undef` if no content was parsed from a file. - Added reST support, with thanks to Daniele Varrazzo. 0.14 2011-10-09T17:45:28Z - Added option processing to the Pod parser. Thanks to Mark Allen for the pull request. 0.13 2011-05-21T15:33:28 - Fixed broken regular expression in the Pod parser that could eat the first line of a verbatim block. 0.12 2011-04-04T23:16:12 - Documented that the `file` parameter to `parse()` is required. - Added MultiMarkdown support. - Fixed test failure in `t/formats.t` when no supported markup parser is installed. 0.11 2011-02-22T22:41:15 - Added list of supported markups to the README. - Fixed test failures on Perls earlier than 5.12. 0.10 2011-02-22T19:45:27 - Initial version. Includes parsers for: + HTML + Markdown + MediaWiki + Pod + Textile + Trac Text-Markup-0.23/Makefile.PL000444000767000024 202412527274673 15320 0ustar00davidstaff000000000000# Note: this file was auto-generated by Module::Build::Compat version 0.4212 require 5.008001; use ExtUtils::MakeMaker; WriteMakefile ( 'NAME' => 'Text::Markup', 'VERSION_FROM' => 'lib/Text/Markup.pm', 'PREREQ_PM' => { 'File::BOM' => '0.14', 'File::Spec::Functions' => 0, 'HTML::Entities' => 0, 'HTML::Tagset' => 0, 'IPC::Open3' => 0, 'Module::Build' => '0.30', 'Parse::BBCode' => '0.15', 'Pod::Simple::XHTML' => '3.15', 'Symbol' => 0, 'Test::More' => '0.96', 'Text::Markdown' => '1.000004', 'Text::MediawikiFormat' => '1.0', 'Text::MultiMarkdown' => '1.000028', 'Text::Textile' => '2.10', 'Text::Trac' => '0.10', 'Text::WikiCreole' => '0.07' }, 'INSTALLDIRS' => 'site', 'EXE_FILES' => [], 'PL_FILES' => {} ) ; Text-Markup-0.23/MANIFEST000444000767000024 166012527274673 14504 0ustar00davidstaff000000000000Build.PL Changes lib/Text/Markup.pm lib/Text/Markup/Asciidoc.pm lib/Text/Markup/Bbcode.pm lib/Text/Markup/Creole.pm lib/Text/Markup/HTML.pm lib/Text/Markup/Markdown.pm lib/Text/Markup/Mediawiki.pm lib/Text/Markup/Multimarkdown.pm lib/Text/Markup/None.pm lib/Text/Markup/Pod.pm lib/Text/Markup/Rest.pm lib/Text/Markup/rst2html_lenient.py lib/Text/Markup/Textile.pm lib/Text/Markup/Trac.pm Makefile.PL MANIFEST This list of files META.json META.yml README.md t/base.t t/empty.txt t/formats.t t/html/asciidoc.html t/html/bbcode.html t/html/creole.html t/html/html.html t/html/markdown.html t/html/mediawiki.html t/html/multimarkdown.html t/html/pod.html t/html/rest.html t/html/textile.html t/html/trac.html t/markups/asciidoc.txt t/markups/bbcode.txt t/markups/creole.txt t/markups/html.txt t/markups/markdown.txt t/markups/mediawiki.txt t/markups/multimarkdown.txt t/markups/pod.txt t/markups/rest.txt t/markups/textile.txt t/markups/trac.txt Text-Markup-0.23/META.json000444000767000024 636412527274673 15002 0ustar00davidstaff000000000000{ "abstract" : "Parse text markup into HTML", "author" : [ "David E. Wheeler " ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4212", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Text-Markup", "prereqs" : { "build" : { "requires" : { "File::Spec::Functions" : "0", "Module::Build" : "0.30", "Test::More" : "0.96" } }, "configure" : { "requires" : { "Module::Build" : "0.30" } }, "runtime" : { "recommends" : { "Test::Pod" : "1.41", "Test::Pod::Coverage" : "1.06" }, "requires" : { "File::BOM" : "0.14", "HTML::Entities" : "0", "HTML::Tagset" : "0", "IPC::Open3" : "0", "Parse::BBCode" : "0.15", "Pod::Simple::XHTML" : "3.15", "Symbol" : "0", "Text::Markdown" : "1.000004", "Text::MediawikiFormat" : "1.0", "Text::MultiMarkdown" : "1.000028", "Text::Textile" : "2.10", "Text::Trac" : "0.10", "Text::WikiCreole" : "0.07", "perl" : "5.008001" } } }, "provides" : { "Text::Markup" : { "file" : "lib/Text/Markup.pm", "version" : "0.23" }, "Text::Markup::Asciidoc" : { "file" : "lib/Text/Markup/Asciidoc.pm", "version" : "0.23" }, "Text::Markup::Bbcode" : { "file" : "lib/Text/Markup/Bbcode.pm", "version" : "0.23" }, "Text::Markup::Creole" : { "file" : "lib/Text/Markup/Creole.pm", "version" : "0.23" }, "Text::Markup::HTML" : { "file" : "lib/Text/Markup/HTML.pm", "version" : "0.23" }, "Text::Markup::Markdown" : { "file" : "lib/Text/Markup/Markdown.pm", "version" : "0.23" }, "Text::Markup::Mediawiki" : { "file" : "lib/Text/Markup/Mediawiki.pm", "version" : "0.23" }, "Text::Markup::Multimarkdown" : { "file" : "lib/Text/Markup/Multimarkdown.pm", "version" : "0.23" }, "Text::Markup::None" : { "file" : "lib/Text/Markup/None.pm", "version" : "0.23" }, "Text::Markup::Pod" : { "file" : "lib/Text/Markup/Pod.pm", "version" : "0.23" }, "Text::Markup::Rest" : { "file" : "lib/Text/Markup/Rest.pm", "version" : "0.23" }, "Text::Markup::Textile" : { "file" : "lib/Text/Markup/Textile.pm", "version" : "0.23" }, "Text::Markup::Trac" : { "file" : "lib/Text/Markup/Trac.pm", "version" : "0.23" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "http://github.com/theory/text-markup/issues/" }, "homepage" : "http://search.cpan.org/dist/Text-Markup/", "license" : [ "http://dev.perl.org/licenses/" ], "repository" : { "url" : "http://github.com/theory/text-markup" } }, "version" : "0.23" } Text-Markup-0.23/META.yml000444000767000024 413112527274673 14620 0ustar00davidstaff000000000000--- abstract: 'Parse text markup into HTML' author: - 'David E. Wheeler ' build_requires: File::Spec::Functions: '0' Module::Build: '0.30' Test::More: '0.96' configure_requires: Module::Build: '0.30' dynamic_config: 1 generated_by: 'Module::Build version 0.4212, CPAN::Meta::Converter version 2.150001' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Text-Markup provides: Text::Markup: file: lib/Text/Markup.pm version: '0.23' Text::Markup::Asciidoc: file: lib/Text/Markup/Asciidoc.pm version: '0.23' Text::Markup::Bbcode: file: lib/Text/Markup/Bbcode.pm version: '0.23' Text::Markup::Creole: file: lib/Text/Markup/Creole.pm version: '0.23' Text::Markup::HTML: file: lib/Text/Markup/HTML.pm version: '0.23' Text::Markup::Markdown: file: lib/Text/Markup/Markdown.pm version: '0.23' Text::Markup::Mediawiki: file: lib/Text/Markup/Mediawiki.pm version: '0.23' Text::Markup::Multimarkdown: file: lib/Text/Markup/Multimarkdown.pm version: '0.23' Text::Markup::None: file: lib/Text/Markup/None.pm version: '0.23' Text::Markup::Pod: file: lib/Text/Markup/Pod.pm version: '0.23' Text::Markup::Rest: file: lib/Text/Markup/Rest.pm version: '0.23' Text::Markup::Textile: file: lib/Text/Markup/Textile.pm version: '0.23' Text::Markup::Trac: file: lib/Text/Markup/Trac.pm version: '0.23' recommends: Test::Pod: '1.41' Test::Pod::Coverage: '1.06' requires: File::BOM: '0.14' HTML::Entities: '0' HTML::Tagset: '0' IPC::Open3: '0' Parse::BBCode: '0.15' Pod::Simple::XHTML: '3.15' Symbol: '0' Text::Markdown: '1.000004' Text::MediawikiFormat: '1.0' Text::MultiMarkdown: '1.000028' Text::Textile: '2.10' Text::Trac: '0.10' Text::WikiCreole: '0.07' perl: '5.008001' resources: bugtracker: http://github.com/theory/text-markup/issues/ homepage: http://search.cpan.org/dist/Text-Markup/ license: http://dev.perl.org/licenses/ repository: http://github.com/theory/text-markup version: '0.23' Text-Markup-0.23/README.md000444000767000024 307612527274673 14635 0ustar00davidstaff000000000000Text/Markup version 0.23 ======================== This library's module, Text::Markup, provides an single interface for parsing a large number of text markup formats and converting them to HTML. It currently supports the following markups: * [Asciidoc](http://www.methods.co.nz/asciidoc/) * [HTML](http://whatwg.org/html) * [Markdown](http://daringfireball.net/projects/markdown/) * [MultiMarkdown](http://fletcherpenney.net/multimarkdown/) * [MediaWiki](http://en.wikipedia.org/wiki/Help:Contents/Editing_Wikipedia) * [Pod](http://search.cpan.org/perldoc?perlpod) * [reStructuredText](http://docutils.sourceforge.net/docs/user/rst/quickref.html) * [Textile](http://textism.com/tools/textile/) * [Trac](http://trac.edgewall.org/wiki/WikiFormatting) * [BBcode](http://www.bbcode.org/) * [Creole](http://www.wikicreole.org/) Installation ------------ To install this module, type the following: perl Build.PL ./Build ./Build test ./Build install Or, if you don't have Module::Build installed, type the following: perl Makefile.PL make make test make install Dependencies ------------ Text-Markup requires the following modules: * File::BOM 0.15 * HTML::Entities * perl 5.8.1 * Pod::Simple::XHTML 3.15 * Text::Markdown 1.000004 * Text::MediawikiFormat 1.0 * Text::Textile 2.10 * Text::Trac 0.10 * Parse::BBCode 0.15 * Text::WikiCreole 0.07 Copyright and Licence --------------------- Copyright (c) 2011-2014 David E. Wheeler. Some Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Text-Markup-0.23/lib000755000767000024 012527274673 13761 5ustar00davidstaff000000000000Text-Markup-0.23/lib/Text000755000767000024 012527274673 14705 5ustar00davidstaff000000000000Text-Markup-0.23/lib/Text/Markup.pm000444000767000024 3064112527274673 16663 0ustar00davidstaff000000000000package Text::Markup; use 5.8.1; use strict; use Text::Markup::None; use Carp; our $VERSION = '0.23'; my %_PARSER_FOR; my %REGEX_FOR = ( html => qr{x?html?}, markdown => qr{m(?:d(?:own)?|kdn?|arkdown)}, multimarkdown => qr{mm(?:d(?:own)?|kdn?|arkdown)}, pod => qr{p(?:od|m|l)}, textile => qr{textile}, trac => qr{tra?c}, mediawiki => qr{(?:m(?:edia)?)?wiki}, rest => qr{re?st}, asciidoc => qr{a(?:sc(?:iidoc)?|doc)?}, bbcode => qr{bb(?:code)?}, creole => qr{creole}, ); sub register { my ($class, $name, $regex) = @_; my $pkg = caller; $REGEX_FOR{$name} = $regex; $_PARSER_FOR{$name} = $pkg->can('parser') or croak "No parser() function defind in $pkg"; } sub _parser_for { my ($self, $format) = @_; return Text::Markup::None->can('parser') unless $format; return $_PARSER_FOR{$format} if $_PARSER_FOR{$format}; my $pkg = __PACKAGE__ . '::' . ($format eq 'html' ? 'HTML' : ucfirst $format); eval "require $pkg; 1" or die $@; return $_PARSER_FOR{$format} = $pkg->can('parser') || croak "No parser() function defind in $pkg"; } sub formats { sort keys %REGEX_FOR; } sub new { my $class = shift; bless { default_encoding => 'UTF-8', @_ } => $class; } sub parse { my $self = shift; my %p = @_; my $file = $p{file} or croak "No file parameter passed to parse()"; croak "$file does not exist" unless -e $file && !-d _; my $parser = $self->_get_parser(\%p); return $parser->( $file, $p{encoding} || $self->default_encoding, $p{options} ); } sub default_format { my $self = shift; return $self->{default_format} unless @_; $self->{default_format} = shift; } sub default_encoding { my $self = shift; return $self->{default_encoding} unless @_; $self->{default_encoding} = shift; } sub _get_parser { my ($self, $p) = @_; my $format = $p->{format} || $self->guess_format($p->{file}) || $self->default_format; return $self->_parser_for($format); } sub guess_format { my ($self, $file) = @_; for my $format (keys %REGEX_FOR) { return $format if $file =~ qr{[.]$REGEX_FOR{$format}$}; } return; } 1; __END__ =head1 Name Text::Markup - Parse text markup into HTML =head1 Synopsis my $parser = Text::Markup->new( default_format => 'markdown', default_encoding => 'UTF-8', ); my $html = $parser->parse(file => $markup_file); =head1 Description This class is really simple. All it does is take the name of a file and return an HTML-formatted version of that file. The idea is that one might have files in lots of different markups, and not know or care what markups each uses. It's the job of this module to figure that out, parse it, and give you the resulting HTML. This distribution includes support for a number of markup formats: =over =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =item * L =back Adding support for more markup languages is straight-forward, and patches adding them to this distribution are also welcome. See L for step-by-step instructions. Or if you just want to use this module, then read on! =head1 Interface =head2 Constructor =head3 C my $parser = Text::Markup->new(default_format => 'markdown'); Supported parameters: =over =item C The default format to use if one isn't passed to C and one can't be guessed. =item C The character encoding in which to assume a file is encoded if it's not otherwise explicitly determined by examination of the source file. Defaults to "UTF-8". =back =head2 Class Methods =head3 C Text::Markup->register(foobar => qr{fb|foob(?:ar)?}); Registers a markup parser. You likely won't need to use this method unless you're creating a new markup parser and not contributing it back to the Text::Markup project. See L for details. =head3 formats my @formats = Text::Markup->formats; Returns a list of all of the formats currently recognized by Text::Markup. This will include all core parsers (except for "None") and any that have been loaded elsewhere and that call C to register themselves. =head2 Instance Methods =head3 C my $html = $parser->parse(file => $file_to_parse); Parses a file and return the generated HTML, or C if no markup was found in the file. Supported parameters: =over =item C The file from which to read the markup to be parsed. Required. =item C The markup format in the file, which determines the parser used to parse it. If not specified, Text::Markup will try to guess the format from the file's suffix. If it can't guess, it falls back on C. And if that attribute is not set, it uses the C parser, which simply encodes the entire file and wraps it in a C<<
 >> element.

=item C

The character encoding to assume the source file is encoded in (if such cannot
be determined by other means, such as a
L). If not specified, the
value of the C attribute will be used, and if that attribute
is not set, UTF-8 will be assumed.

=item C

An array reference of options for the parser. See the documentation of the
various parser modules for details.

=back

=head3 C

  my $format = $parser->default_format;
  $parser->default_format('markdown');

An accessor for the default format attribute.

=head3 C

  my $encoding = $parser->default_encoding;
  $parser->default_encoding('Big5');

An accessor for the default encoding attribute.

=head3 C

  my $format = $parser->guess_format($filename);

Compares the passed file name's suffix to the regular expressions of all
registered formatting parser and returns the first one that matches. Returns
C if none matches.

=head1 Add a Parser

Adding support for markup formats not supported by the core Text::Markup
distribution is a straight-forward exercise. Say you wanted to add a "FooBar"
markup parser. Here are the steps to take:

=over

=item 1

Fork L

=item 2

Clone your fork and create a new branch in which to work:

  git clone git@github.com:$USER/text-markup.git
  cd text-markup
  git checkout -b foobar

=item 3

Create a new module named C. The simplest thing to do is
copy an existing module and modify it. The HTML parser is probably the simplest:

  cp lib/Text/Markup/HTML.pm lib/Text/Markup/FooBar.pm
  perl -i -pe 's{HTML}{FooBar}g' lib/Text/Markup/FooBar.pm
  perl -i -pe 's{html}{foobar}g' lib/Text/Markup/FooBar.pm

=item 4

Implement the C function in your new module. If you were to use a
C module, it might look something like this:

  package Text::Markup::FooBar;

  use 5.8.1;
  use strict;
  use Text::FooBar ();
  use File::BOM qw(open_bom)

  sub parser {
      my ($file, $encoding, $opts) = @_;
      my $md = Text::FooBar->new(@{ $opts || [] });
      open_bom my $fh, $file, ":encoding($encoding)";
      local $/;
      my $html = $md->parse(<$fh>);
      return unless $html =~ /\S/;
      utf8::encode($html);
      return join( "\n",
          '',
          '',
          '',
          $html,
          '',
          '',
      );
  }

Use the C<$encoding> argument as appropriate to read in the source file. If
your parser requires that text be decoded to Perl's internal form, use of
L is recommended, so that an explicit BOM will determine the
encoding. Otherwise, fall back on the specified encoding. Note that some
parsers, such as an HTML parser, would want text encoded before it parsed it.
In such a case, read in the file as raw bytes:

      open my $fh, '<:raw', $file or die "Cannot open $file: $!\n";

The returned HTML, however, B. Please include an
L, such as
a content-type C<<  >> element:

  

This will allow any consumers of the returned HTML to parse it correctly.
If the parser parsed no content, C should return C.

=item 5

Edit F and add an entry to its C<%REGEX_FOR> hash for your
new format. The key should be the name of the format (lowercase, the same as
the last part of your module's name). The value should be a regular expression
that matches the file extensions that suggest that a file is formatted in your
parser's markup language. For our FooBar parser, the line might look like
this:

    foobar => qr{fb|foob(?:ar)?},

=item 6

Add a file in your parser's markup language to F. It should be
named for your parser and end in F<.txt>, that is, F.

=item 7

Add an HTML file, F, which should be the expected output
once F is parsed into HTML. This will be used to test
that your parser works correctly.

=item 8

Edit F by adding a line to its C<__DATA__> section. The line
should be a comma-separated list describing your parser. The columns are:

=over

=item * Format

The lowercased name of the format.

=item * Format Module

The name of the parser module.

=item * Required Module

The name of a module that's required to be installed in order for your parser
to load.

=item * Extensions

Additional comma-separated values should be a list of file extensions that
your parser should recognize.

=back

So for our FooBar parser, it might look like this:

  markdown,Text::Markup::FooBar,Text::FooBar 0.22,fb,foob,foobar

=item 9

Test your new parser by running

  prove -lv t/formats.t

This will test I included parsers, but of course you should only pay
attention to how your parser works. Tweak until your tests pass. Note that one
test has the parser parse a file with just a couple of empty lines, to ensure
that the parser finds no content and returns C.

=item 10

Don't forget to write the documentation in your new parser module! If you
copied F, you can just modify as appropriate.

=item 11

Add any new module requirements to the C section of F.

=item 12

Commit and push the branch to your fork on GitHub:

  git add .
  git commit -am 'Add great new FooBar parser!'
  git push origin -u foobar

=item 13

And finally, submit a pull request to the upstream repository via the GitHub
UI.

=back

If you don't want to submit your parser, you can still create and use one
independently. Rather than add its information to the C<%REGEX_FOR> hash in
this module, you can just load your parser manually, and have it call the
C method, like so:

  package My::Markup::FooBar;
  use Text::Markup;
  Text::Markup->register(foobar => qr{fb|foob(?:ar)?});

This will be useful for creating private parsers you might not want to
contribute, or that you'd want to distribute independently.

=head1 See Also

=over

=item *

The L Ruby library -- the inspiration
for this module -- provides similar functionality, and is used to parse
F on GitHub.

=item *

L offers similar functionality.

=back

=head1 Support

This module is stored in an open L. Feel free to fork and
contribute!

Please file bug reports via L or by sending mail to
L.

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2014 David E. Wheeler. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
Text-Markup-0.23/lib/Text/Markup000755000767000024          012527274673 16144 5ustar00davidstaff000000000000Text-Markup-0.23/lib/Text/Markup/Asciidoc.pm000444000767000024       635212527274673 20363 0ustar00davidstaff000000000000package Text::Markup::Asciidoc;

use 5.8.1;
use strict;
use File::Spec;
use constant WIN32  => $^O eq 'MSWin32';
use Symbol 'gensym';
use IPC::Open3;
use utf8;

our $VERSION = '0.23';

# Find Asciidoc.
my $ASCIIDOC;
FIND: {
    my @path = (
        File::Spec->path,
        WIN32 ? (map { "C:\\asciidoc$_" } '', '-8.6.6') : ()
    );
    EXE: {
        for my $exe (qw(asciidoc asciidoc.py)) {
            for my $p (@path) {
                my $path = File::Spec->catfile($p, $exe);
                next unless -f $path && -x $path;
                $ASCIIDOC = $path;
                last EXE;
            }
        }
    }

    unless ($ASCIIDOC) {
        use Carp;
        my $sep = WIN32 ? ';' : ':';
        Carp::croak(
            "Cannot find asciidoc or asciidoc.py in path " . join $sep => @path
        );
    }

    # Make sure it looks like it will work.
    my $output = gensym;
    my $pid = open3 undef, $output, $output, $ASCIIDOC, '--version';
    waitpid $pid, 0;
    if ($?) {
        use Carp;
        local $/;
        Carp::croak(
            qq{$ASCIIDOC will not execute\n},
            <$output>
        );
    }
}

# Arguments to pass to asciidoc.
# Restore --safe if Asciidoc ever fixes it with the XHTML back end.
# https://groups.google.com/forum/#!topic/asciidoc/yEr5PqHm4-o
my @OPTIONS = qw(
    --no-header-footer
    --out-file -
    --attribute newline=\\n
);

sub parser {
    my ($file, $encoding, $opts) = @_;
    my $html = do {
        my $fh = _fh(
            $ASCIIDOC, @OPTIONS,
            '--attribute' => "encoding=$encoding",
            $file
        );

        binmode $fh, ":encoding($encoding)";
        local $/;
        <$fh>;
    };

    # Make sure we have something.
    return unless $html =~ /\S/;
    utf8::encode $html;
    return qq{



$html


};
}

# Stolen from SVN::Notify.
sub _fh {
    # Ignored; looks like docutils always emits UTF-8.
    if (WIN32) {
        my $cmd = join join(q{" "}, @_) . q{"|};
        open my $fh, $cmd or die "Cannot fork: $!\n";
        return $fh;
    }

    my $pid = open my $fh, '-|';
    die "Cannot fork: $!\n" unless defined $pid;

    if ($pid) {
        # Parent process, return the file handle.
        return $fh;
    } else {
        # Child process. Execute the commands.
        exec @_ or die "Cannot exec $_[0]: $!\n";
        # Not reached.
    }
}

1;
__END__

=head1 Name

Text::Markup::Asciidoc - Asciidoc parser for Text::Markup

=head1 Synopsis

  use Text::Markup;
  my $html = Text::Markup->new->parse(file => 'hello.adoc');

=head1 Description

This is the L parser for
L. It depends on the C command-line application, for
which there are many
L. It
recognizes files with the following extensions as Asciidoc:

=over

=item F<.asciidoc>

=item F<.asc>

=item F<.adoc>

=back

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2012-2014 David E. Wheeler. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
Text-Markup-0.23/lib/Text/Markup/Bbcode.pm000444000767000024       262612527274673 20023 0ustar00davidstaff000000000000package Text::Markup::Bbcode;

use 5.8.1;
use strict;
use File::BOM qw(open_bom);
use Parse::BBCode;

our $VERSION = '0.23';

sub parser {
    my ($file, $encoding, $opts) = @_;
    my $parse = Parse::BBCode->new;
    open_bom my $fh, $file, ":encoding($encoding)";
    local $/;
    my $html = $parse->render(<$fh>);
    return unless $html =~ /\S/;
    utf8::encode($html);
    return qq{



$html


};

}

1;
__END__

=head1 Name

Text::Markup::Bbcode - BBcode parser for Text::Markup

=head1 Synopsis

  my $html = Text::Markup->new->parse(file => 'file.bbcode');

=head1 Description

This is the L parser for L. It
reads in the file (relying on a
L), hands it off to
L for parsing, and then returns the generated HTML as an
encoded UTF-8 string with an C element identifying
the encoding as UTF-8.

It recognizes files with the following extensions as Markdown:

=over

=item F<.bb>

=item F<.bbcode>

=back

=head1 Author

Lucas Kanashiro 

=head1 Copyright and License

Copyright (c) 2011-2014 Lucas Kanashiro. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
Text-Markup-0.23/lib/Text/Markup/Creole.pm000444000767000024       255112527274673 20053 0ustar00davidstaff000000000000package Text::Markup::Creole;

use 5.8.1;
use strict;
use File::BOM qw(open_bom);
use Text::WikiCreole;

our $VERSION = '0.23';

sub parser {
    my ($file, $encoding, $opts) = @_;
    open_bom my $fh, $file, ":encoding($encoding)";
    local $/;
    my $html = creole_parse(<$fh>);
    return unless $html =~ /\S/;
    utf8::encode($html);
    return qq{



$html


};

}

1;
__END__

=head1 Name

Text::Markup::Creole - Creole parser for Text::Markup

=head1 Synopsis

  my $html = Text::Markup->new->parse(file => 'file.creole');

=head1 Description

This is the L parser for L. It
reads in the file (relying on a
L), hands it off to
L for parsing, and then returns the generated HTML as an
encoded UTF-8 string with an C element identifying
the encoding as UTF-8.

It recognizes files with the following extensions as Markdown:

=over

=item F<.creole>

=back

=head1 Author

Lucas Kanashiro 

=head1 Copyright and License

Copyright (c) 2011-2014 Lucas Kanashiro. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
Text-Markup-0.23/lib/Text/Markup/HTML.pm000444000767000024       217212527274673 17405 0ustar00davidstaff000000000000package Text::Markup::HTML;

use 5.8.1;
use strict;

our $VERSION = '0.23';

sub parser {
    my ($file, $encoding, $opts) = @_;
    my $html = do {
        open my $fh, '<:raw', $file or die "Cannot open $file: $!\n";
        local $/;
        <$fh>;
    };
    return $html =~ /\S/ ? $html : undef
}

1;
__END__

=head1 Name

Text::Markup::HTML - HTML parser for Text::Markup

=head1 Synopsis

  use Text::Markup;
  my $html = Text::Markup->new->parse(file => 'hello.html');

=head1 Description

This is the L parser for L. All it
does is read in the HTML file and return it as a string. It makes no
assumptions about encoding, and returns the string raw as read from the file,
with no decoding. It recognizes files with the following extensions as HTML:

=over

=item F<.html>

=item F<.htm>

=item F<.xhtml>

=item F<.xhtm>

=back

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2014 David E. Wheeler. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
Text-Markup-0.23/lib/Text/Markup/Markdown.pm000444000767000024       327012527274673 20423 0ustar00davidstaff000000000000package Text::Markup::Markdown;

use 5.8.1;
use strict;
use File::BOM qw(open_bom);
use Text::Markdown ();

our $VERSION = '0.23';

sub parser {
    my ($file, $encoding, $opts) = @_;
    my $md = Text::Markdown->new(@{ $opts || [] });
    open_bom my $fh, $file, ":encoding($encoding)";
    local $/;
    my $html = $md->markdown(<$fh>);
    return unless $html =~ /\S/;
    utf8::encode($html);
    return qq{



$html


};

}

1;
__END__

=head1 Name

Text::Markup::Markdown - Markdown parser for Text::Markup

=head1 Synopsis

  my $html = Text::Markup->new->parse(file => 'README.md');

=head1 Description

This is the L parser
for L. It reads in the file (relying on a
L), hands it off to
L for parsing, and then returns the generated HTML as an
encoded UTF-8 string with an C element identifying
the encoding as UTF-8.

It recognizes files with the following extensions as Markdown:

=over

=item F<.md>

=item F<.mkd>

=item F<.mkdn>

=item F<.mdown>

=item F<.markdown>

=back

=head1 See Also

L.
MarkI or MarkI?

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2014 David E. Wheeler. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
Text-Markup-0.23/lib/Text/Markup/Mediawiki.pm000444000767000024       300112527274673 20534 0ustar00davidstaff000000000000package Text::Markup::Mediawiki;

use 5.8.1;
use strict;
use File::BOM qw(open_bom);
use Text::MediawikiFormat '1.0';

our $VERSION = '0.23';

sub parser {
    my ($file, $encoding, $opts) = @_;
    open_bom my $fh, $file, ":encoding($encoding)";
    local $/;
    my $html = Text::MediawikiFormat::format(<$fh>, @{ $opts || [] });
    return unless $html =~ /\S/;
    utf8::encode($html);
    return qq{



$html


};

}

1;
__END__

=head1 Name

Text::Markup::Mediawiki - MediaWiki syntax parser for Text::Markup

=head1 Synopsis

  my $html = Text::Markup->new->parse(file => 'README.mediawiki');

=head1 Description

This is the L parser
for L. It reads in the file (relying on a
L), hands it off to
L for parsing, and then returns the generated HTML as
an encoded UTF-8 string with an C element
identifying the encoding as UTF-8.

It recognizes files with the following extensions as MediaWiki:

=over

=item F<.mediawiki>

=item F<.mwiki>

=item F<.wiki>

=back

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2014 David E. Wheeler. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
Text-Markup-0.23/lib/Text/Markup/Multimarkdown.pm000444000767000024       304112527274673 21472 0ustar00davidstaff000000000000package Text::Markup::Multimarkdown;

use 5.8.1;
use strict;
use File::BOM qw(open_bom);
use Text::MultiMarkdown ();

our $VERSION = '0.23';

sub parser {
    my ($file, $encoding, $opts) = @_;
    my $md = Text::MultiMarkdown->new(@{ $opts || [] });
    open_bom my $fh, $file, ":encoding($encoding)";
    local $/;
    my $html = $md->markdown(<$fh>);
    return unless $html =~ /\S/;
    utf8::encode($html);
    return qq{



$html


};

}

1;
__END__

=head1 Name

Text::Markup::Multimarkdown - MultiMarkdown parser for Text::Markup

=head1 Synopsis

  my $html = Text::Markup->new->parse(file => 'README.md');

=head1 Description

This is the L parser
for L. It reads in the file (relying on a
L), hands it off to
L for parsing, and then returns the generated HTML as an
encoded UTF-8 string with an C element identifying
the encoding as UTF-8.

It recognizes files with the following extensions as MultiMarkdown:

=over

=item F<.mmd>

=item F<.mmkd>

=item F<.mmkdn>

=item F<.mmdown>

=item F<.multimarkdown>

=back

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2014 David E. Wheeler. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
Text-Markup-0.23/lib/Text/Markup/None.pm000444000767000024       247312527274673 17544 0ustar00davidstaff000000000000package Text::Markup::None;

use 5.8.1;
use strict;
use HTML::Entities;
use File::BOM qw(open_bom);

our $VERSION = '0.23';

sub parser {
    my ($file, $encoding, $opts) = @_;
    open_bom my $fh, $file, ":encoding($encoding)";
    local $/;
    my $html = encode_entities(<$fh>, '<>&"');
    utf8::encode($html);
    return qq{



$html
}; } 1; __END__ =head1 Name Text::Markup::None - Turn a file with no known markup into HTML =head1 Synopsis use Text::Markup; my $html = Text::Markup->new->parse(file => 'README'); =head1 Description This is the default parser used by Text::Markdown in the event that it cannot determine the format of a text file. All it does is read the file in (relying on a L, encodes all entities, and then returns an HTML string with the file in a C<<
 >>
element. This will be handy for files that really are nothing but plain text,
like F files.

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2014 David E. Wheeler. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
Text-Markup-0.23/lib/Text/Markup/Pod.pm000444000767000024       443412527274673 17366 0ustar00davidstaff000000000000package Text::Markup::Pod;

use 5.8.1;
use strict;
use Pod::Simple::XHTML '3.15';

# Disable the use of HTML::Entities.
$Pod::Simple::XHTML::HAS_HTML_ENTITIES = 0;

our $VERSION = '0.23';

sub parser {
    my ($file, $encoding, $opts) = @_;
    my $p = Pod::Simple::XHTML->new;
    # Output everything as UTF-8.
    $p->html_header_tags('');
    $p->strip_verbatim_indent(sub { (sort map { /^(\s+)/ } @{$_[0]})[0] });
    $p->output_string(\my $html);
    # Want user supplied options to override even these default behaviors,
    # if necessary
    my $opt = $opts ? { @$opts } : {};
    foreach my $method ( keys %$opt ) {
        my $v = $opt->{$method};
        $p->$method($v);
    }
    $p->parse_file($file);
    return unless $p->content_seen;
    utf8::encode($html);
    return $html;
}

1;
__END__

=head1 Name

Text::Markup::Pod - Pod parser for Text::Markup

=head1 Synopsis

  use Text::Markup;
  my $pod = Text::Markup->new->parse(file => 'README.pod');

=head1 Description

This is the L parser for L. It runs the file
through L and returns the result. If the Pod contains any
non-ASCII characters, the encoding must be declared either via a BOM or via
the C<=encoding> tag. Text::Markup::Pod recognizes files with the following
extensions as Pod:

=over

=item F<.pod>

=item F<.pm>

=item F<.pl>

=back

=head1 Options

You may pass an arrayref of settings to this parser which changes the output returned.  For example,
to suppress an HTML header and footer, pass:

  my $pod_fragment = Text::Markup->new->parse(
          file => 'README.pod',
          options => [
              html_header => '',
              html_footer => '',
          ]
  );

This implementation makes method calls to the L parser using the key as the method
name and the value as the parameter list to pass.  

See L and L for the full list of options and inherited options
which can be manipulated.

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2014 David E. Wheeler. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
Text-Markup-0.23/lib/Text/Markup/Rest.pm000444000767000024      1036212527274673 17576 0ustar00davidstaff000000000000package Text::Markup::Rest;

use 5.8.1;
use strict;
use File::Spec;
use File::Basename ();
use constant WIN32  => $^O eq 'MSWin32';
use Symbol 'gensym';
use IPC::Open3;

our $VERSION = '0.23';

# Find Python (process stolen from App::Info).
my ($PYTHON, $RST2HTML);
for my $exe (WIN32 ? 'python.exe' : 'python') {
    my @path = (
        File::Spec->path,
        WIN32 ? (map { "C:\\Python$_" } '', 27, 26, 25) : ()
    );

    for my $p (@path) {
        my $path = File::Spec->catfile($p, $exe);
        next unless -f $path && -x $path;
        $PYTHON = $path;
        last;
    }

    unless ($PYTHON) {
        use Carp;
        my $sep = WIN32 ? ';' : ':';
        Carp::croak(
            "Cannot find $exe in path " . join $sep => @path
        );
    }

    # We have python, let's find out if we have docutils.
    my $output = gensym;
    my $pid = open3 undef, $output, $output, $PYTHON, '-c', 'import docutils';
    waitpid $pid, 0;
    if ($?) {
        use Carp;
        local $/;
        Carp::croak(
            qq{Missing required Python "docutils" module\n},
            <$output>
        );
    }

    # We ship with our own rst2html that's lenient with unknown directives.
    $RST2HTML = File::Spec->catfile(
        File::Basename::dirname(__FILE__),
        'rst2html_lenient.py'
    );

    # Make sure it looks like it will work.
    $pid = open3 undef, $output, $output, $PYTHON, $RST2HTML, '--test-patch';
    waitpid $pid, 0;
    if ($?) {
        use Carp;
        local $/;
        Carp::croak(
            qq{$RST2HTML will not execute\n},
            <$output>
        );
    }
}

# Optional arguments to pass to rst2html
my @OPTIONS = qw(
    --no-raw
    --no-file-insertion
    --stylesheet=
    --cloak-email-address
    --no-generator
    --quiet
);

# Options to improve rendering of Sphinx documents
my @SPHINX_OPTIONS = qw(
    --dir-ignore toctree
    --dir-ignore highlight
    --dir-ignore index
    --dir-ignore default-domain

    --dir-nested note
    --dir-nested warning
    --dir-nested versionadded
    --dir-nested versionchanged
    --dir-nested deprecated
    --dir-nested seealso
    --dir-nested hlist
    --dir-nested glossary

    --dir-notitle code-block

    --dir-nested module
    --dir-nested function
    --output-encoding utf-8
);
# note: domains directive (last 2 options) incomplete

sub parser {
    my ($file, $encoding, $opts) = @_;
    my $html = do {
        my $fh = _fh(
            $PYTHON, $RST2HTML,
            @OPTIONS, @SPHINX_OPTIONS,
            '--input-encoding', $encoding,
            $file
        );
        local $/;
        <$fh>;
    };

    # Make sure we have something.
    return undef if $html =~ m{\s+}ms;

    # Alas, --no-generator does not remove the generator meta tag. :-(
    $html =~ s{^\s*]+>\n}{}ms;

    return $html;
}

# Stolen from SVN::Notify.
sub _fh {
    # Ignored; looks like docutils always emits UTF-8.
    if (WIN32) {
        my $cmd = join join(q{" "}, @_) . q{"|};
        open my $fh, $cmd or die "Cannot fork: $!\n";
        return $fh;
    }

    my $pid = open my $fh, '-|';
    die "Cannot fork: $!\n" unless defined $pid;

    if ($pid) {
        # Parent process, return the file handle.
        return $fh;
    } else {
        # Child process. Execute the commands.
        exec @_ or die "Cannot exec $_[0]: $!\n";
        # Not reached.
    }
}

1;
__END__

=head1 Name

Text::Markup::Rest - reStructuredText parser for Text::Markup

=head1 Synopsis

  use Text::Markup;
  my $html = Text::Markup->new->parse(file => 'hello.rst');

=head1 Description

This is the
L
parser for L. It depends on the C Python package
(which can be found as C in many Linux distributions, or
installed using the command C). It recognizes files
with the following extensions as reST:

=over

=item F<.rest>

=item F<.rst>

=back

=head1 Author

Daniele Varrazzo 

=head1 Copyright and License

Copyright (c) 2011-2014 Daniele Varrazzo. Some Rights Reserved.

This module is free software; you can redistribute it and/or modify it under
the same terms as Perl itself.

=cut
Text-Markup-0.23/lib/Text/Markup/rst2html_lenient.py000555000767000024      2266312527274673 22204 0ustar00davidstaff000000000000#!/usr/bin/env python
"""
Parse a reST file into HTML in a very forgiving way.

The script is meant to render specialized reST documents, such as Sphinx
files, preserving the content, while not emulating the original rendering.

The script is currently tested against docutils 0.7-0.10. Other versions may
break it as it deals with the parser at a relatively low level. Use
--test-patch to verify if the script works as expected with your library
version.
"""

import sys

import docutils
from docutils import nodes, utils, SettingsSpec
from docutils.core import publish_cmdline, publish_string, default_description
from docutils.parsers.rst import Directive, directives, roles
from docutils.writers.html4css1 import HTMLTranslator, Writer
from docutils.parsers.rst.states import Body, Inliner
from docutils.frontend import validate_boolean

class any_directive(nodes.General, nodes.FixedTextElement):
    """A generic directive to deal with any unknown directive we may find."""
    pass

class AnyDirective(Directive):
    """A directive returning its unaltered body."""
    optional_arguments = 100 # should suffice
    has_content = True

    def run(self):
        if self.name in self.state.document.settings.dir_ignore:
            return []

        children = []

        if self.name not in self.state.document.settings.dir_notitle:
            children.append(nodes.strong(self.name, u"%s: " % self.name))
            # keep the arguments, drop the options
            for a in self.arguments:
                if a.startswith(':') and a.endswith(':'):
                    break
                children.append(nodes.emphasis(a, u"%s " % a))

        if self.name in self.state.document.settings.dir_nested:
            if self.content:
                container = nodes.Element()
                self.state.nested_parse(self.content, self.content_offset,
                                        container)
                children.extend(container.children)
        else:
            content = u'\n'.join(self.content)
            children.append(nodes.literal_block(content, content))

        node = any_directive(self.block_text, '', *children, dir_name=self.name)

        return [node]


class any_role(nodes.Inline, nodes.TextElement):
    """A generic role to deal with any unknown role we may find."""
    pass

class AnyRole:
    """A role to be rendered as a generic element with a specific class."""
    def __init__(self, role_name):
        self.role_name = role_name

    def __call__(self, role, rawtext, text, lineno, inliner,
                 options={}, content=[]):
        roles.set_classes(options)
        options['role_name'] = self.role_name
        node = any_role(rawtext, utils.unescape(text), **options)
        return [node], []


def catchall_directive(self, match, **option_presets):
    """Directive dispatch method.

    Replacement for Body.directive(): if a directive is not known, build one
    on the fly instead of reporting an error.
    """
    type_name = match.group(1)
    directive_class, messages = directives.directive(
        type_name, self.memo.language, self.document)

    # in case it's missing, register a generic directive
    if not directive_class:
        directives.register_directive(type_name, AnyDirective)
        directive_class, messages = directives.directive(
            type_name, self.memo.language, self.document)
        assert directive_class, "can't find just defined directive"

    self.parent += messages
    return self.run_directive(
        directive_class, match, type_name, option_presets)


def catchall_interpreted(self, rawsource, text, role, lineno):
    """Interpreted text role dispatch method.

    Replacement for Inliner.interpreted(): if a role is not known, build one
    on the fly instead of reporting an error.
    """
    role_fn, messages = roles.role(role, self.language, lineno,
                                   self.reporter)
    # in case it's missing, register a generic role
    if not role_fn:
        role_obj = AnyRole(role)
        roles.register_canonical_role(role, role_obj)
        role_fn, messages = roles.role(
            role, self.language, lineno, self.reporter)
        assert role_fn, "can't find just defined role"

    nodes, messages2 = role_fn(role, rawsource, text, lineno, self)
    return nodes, messages + messages2


def patch_docutils():
    """Change the docutils parser behaviour."""
    # Patch the constructs dispatch table
    for i, (f, p) in enumerate(Body.explicit.constructs):
        if f is Body.directive.im_func is f:
            Body.explicit.constructs[i] = (catchall_directive, p)
            break
    else:
        assert False, "can't find directive dispatch entry"

    # Patch the parser so that when an unknown directive is found, a generic one
    # is generated on the fly.
    Body.directive = catchall_directive

    # Patch the parser so that when an unknown interpreted text role is found,
    # a generic one is generated on the fly.
    Inliner.interpreted = catchall_interpreted


class MyTranslator(HTMLTranslator):
    """An HTML translator that can render with any_role/any_directive.
    """
    def visit_any_directive(self, node):
        cls = node.get('dir_name')
        cls = cls and 'directive-%s' % cls or 'directive'
        self.body.append(self.starttag(node, 'div', CLASS=cls))

    def depart_any_directive(self, node):
        self.body.append('\n\n')

    def visit_any_role(self, node):
        cls = node.get('role_name')
        cls = cls and 'role-%s' % cls or 'role'
        self.body.append(self.starttag(node, 'span', '', CLASS=cls))

    def depart_any_role(self, node):
        self.body.append('')


class LenientSettingsSpecs(SettingsSpec):
    settings_spec = ("Lenient parsing options", None, (
        ("Directive whose content should be interpreted as reST.  "
         "By default emit the content as unparsed text block.  "
         "Can be specified more than once",
            ["--dir-nested"],
            {'metavar': 'NAME', 'default': [], 'action': 'append'}),
        ("Directive that should produce no output.  "
         "Can be specified more than once",
            ["--dir-ignore"],
            {'metavar': 'NAME', 'default': [], 'action': 'append'}),
        ("Only emit the content of the directive, no title and options.  "
         "Can be specified more than once",
            ["--dir-notitle"],
            {'metavar': 'NAME', 'default': [], 'action': 'append'}),
        ("Verify that lenient customization works fine.  "
         "Immediately return with 0 (success) or 1 (error).  "
         "In case of error, print a report on stdout.",
            ['--test-patch'],
            {'action': 'store_true', 'validator': validate_boolean}),
    ))


def main():

    # Create a writer to deal with the generic element we may have created.
    writer = Writer()
    writer.translator_class = MyTranslator

    description = (
        'Generates (X)HTML documents from standalone reStructuredText '
       'sources.  Be forgiving against unknown elements.  '
       + default_description)

    # the parser processes the settings too late: we want to decide earlier if
    # we are running or testing.
    if ('--test-patch' in sys.argv
            and not ('-h' in sys.argv or '--help' in sys.argv)):
        return test_patch(writer)

    else:
        # Make docutils lenient.
        patch_docutils()

        overrides = {
            # If Pygments is missing, code-block directives are swallowed
            # with Docutils >= 0.9.
            'syntax_highlight': 'none',

            # not available on Docutils < 0.8 so can't pass as an option
            'math_output': 'HTML',
        }

        publish_cmdline(writer=writer, description=description,
             settings_spec=LenientSettingsSpecs, settings_overrides=overrides)
        return 0

def test_patch(writer):
    """Verify that patching docutils works as expected."""
    TEST_SOURCE = """`
Hello `role`:norole:

.. nodirective::
"""
    rv = 0
    problems = []
    exc = None

    # patch and use lenient docutils
    try:
        try:
            patch_docutils()
        except Exception, exc:
            problems.append("error during library patching")
            raise

        try:
            out = publish_string(TEST_SOURCE,
                writer=writer, settings_spec=LenientSettingsSpecs)
        except Exception, exc:
            problems.append("error while running patched docutils")
            raise

    except:
        pass

    # verify conform output
    else:
        out = out.replace("'", '"')
        if '' not in out:
            problems.append(
                "unknown role didn't produce the expected output")

        if '
' not in out: problems.append( "unknown directive didn't produce the expected output") # report problems if any if problems: rv = 1 print >> sys.stderr, "Patching docutils failed!" for problem in problems: print >> sys.stderr, "-", problem if rv: print >> sys.stderr, "\nVersions:", \ 'docutils:', docutils.__version__, docutils.__version_details__, \ '\nPython:', sys.version if exc: if '--traceback' in sys.argv: print >> sys.stderr import traceback traceback.print_exc() else: print >> sys.stderr, \ "\nUse --traceback to display the error stack trace." return rv if __name__ == '__main__': sys.exit(main()) Text-Markup-0.23/lib/Text/Markup/Textile.pm000444000767000024 303712527274673 20260 0ustar00davidstaff000000000000package Text::Markup::Textile; use 5.8.1; use strict; use File::BOM qw(open_bom); use Text::Textile '2.10'; our $VERSION = '0.23'; sub parser { my ($file, $encoding, $opts) = @_; my $textile = Text::Textile->new( charset => 'utf-8', char_encoding => 0, trim_spaces => 1, @{ $opts || [] } ); open_bom my $fh, $file, ":encoding($encoding)"; local $/; my $html = $textile->process(<$fh>); return unless $html =~ /\S/; utf8::encode($html); return qq{ $html }; } 1; __END__ =head1 Name Text::Markup::Textile - Textile parser for Text::Markup =head1 Synopsis my $html = Text::Markup->new->parse(file => 'README.textile'); =head1 Description This is the L parser for L. It reads in the file (relying on a L), hands it off to L for parsing, and then returns the generated HTML as an encoded UTF-8 string with an C element identifying the encoding as UTF-8. It recognizes files with the following extension as Textile: =over =item F<.textile> =back =head1 Author David E. Wheeler =head1 Copyright and License Copyright (c) 2011-2014 David E. Wheeler. Some Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Text-Markup-0.23/lib/Text/Markup/Trac.pm000444000767000024 271112527274673 17531 0ustar00davidstaff000000000000package Text::Markup::Trac; use 5.8.1; use strict; use File::BOM qw(open_bom); use Text::Trac '0.10'; our $VERSION = '0.23'; sub parser { my ($file, $encoding, $opts) = @_; my $trac = Text::Trac->new(@{ $opts || [] }); open_bom my $fh, $file, ":encoding($encoding)"; local $/; my $html = $trac->parse(<$fh>); return unless $html =~ /\S/; utf8::encode($html); return qq{ $html }; } 1; __END__ =head1 Name Text::Markup::Trac - Trac wiki syntax parser for Text::Markup =head1 Synopsis my $html = Text::Markup->new->parse(file => 'README.trac'); =head1 Description This is the L parser for L. It reads in the file (relying on a L), hands it off to L for parsing, and then returns the generated HTML as an encoded UTF-8 string with an C element identifying the encoding as UTF-8. It recognizes files with the following extensions as Trac: =over =item F<.trac> =item F<.trc> =back =head1 Author David E. Wheeler =head1 Copyright and License Copyright (c) 2011-2014 David E. Wheeler. Some Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Text-Markup-0.23/t000755000767000024 012527274673 13456 5ustar00davidstaff000000000000Text-Markup-0.23/t/base.t000444000767000024 1036712527274673 14741 0ustar00davidstaff000000000000#!/usr/bin/env perl -w use strict; use warnings; use Test::More tests => 25; #use Test::More 'no_plan'; use File::Spec::Functions qw(catdir); use HTML::Entities; BEGIN { use_ok 'Text::Markup' or die; } can_ok 'Text::Markup' => qw( register formats new parse default_format _get_parser ); # Find core parsers. my $dir = catdir qw(lib Text Markup); opendir my $dh, $dir or die "Cannot open diretory $dir: $!\n"; my @core_parsers; while (my $f = readdir $dh) { next if $f eq '.' || $f eq '..' || $f eq 'None.pm'; $f =~ s{[.]pm$}{} or next; push @core_parsers => lc $f; } is_deeply [Text::Markup->formats], [sort @core_parsers], 'Should have core parsers'; # Register one. PARSER: { package My::Cool::Parser; use Text::Markup; Text::Markup->register(cool => qr{cool}); sub parser { return $_[2] ? $_[2]->[0] : 'hello'; } } is_deeply [Text::Markup->formats], [sort @core_parsers, 'cool'], 'Should be now have the "cool" parser'; my $parser = new_ok 'Text::Markup'; is $parser->default_format, undef, 'Should have no default format'; $parser = new_ok 'Text::Markup', [default_format => 'cool']; is $parser->default_format, 'cool', 'Should have default format'; is $parser->_get_parser({ format => 'cool' }), My::Cool::Parser->can('parser'), 'Should be able to find specific parser'; is $parser->_get_parser({ file => 'foo' }), My::Cool::Parser->can('parser'), 'Should be able to find default format parser'; $parser->default_format(undef); is $parser->_get_parser({ file => 'foo'}), Text::Markup::None->can('parser'), 'Should be find the specified default parser'; # Now make it guess the format. $parser->default_format(undef); is $parser->_get_parser({ file => 'foo.cool'}), My::Cool::Parser->can('parser'), 'Should be able to guess the parser file the file name'; # Now test guess_format. is $parser->guess_format('foo.cool'), 'cool', 'Should guess "cool" format file "foo.cool"'; is $parser->guess_format('foocool'), undef, 'Should not guess "cool" format file "foocool"'; is $parser->guess_format('foo.cool.txt'), undef, 'Should not guess "cool" format file "foo.cool.txt"'; # Add another parser. PARSER: { package My::Funky::Parser; Text::Markup->register(funky => qr{funky(?:[.]txt)?}); sub parser { # Must return a UTF-8 encoded string. use utf8; my $ret = 'fünky'; utf8::encode($ret); return $ret; } } is_deeply [Text::Markup->formats], [sort @core_parsers, qw(cool funky)], 'Should be now have the "cool" and "funky" parsers'; is $parser->guess_format('foo.cool'), 'cool', 'Should still guess "cool" format file "foo.cool"'; is $parser->guess_format('foo.funky'), 'funky', 'Should guess "funky" format file "foo.funky"'; is $parser->guess_format('foo.funky.txt'), 'funky', 'Should guess "funky" format file "foo.funky.txt"'; # Now try parsing. is $parser->parse( file => 'README.md', format => 'cool', ), 'hello', 'Test the "cool" parser'; # Send output to a file. is $parser->parse( file => 'README.md', format => 'funky', ), 'fünky', 'Test the "funky" parser'; # Test opts to the parser. is $parser->parse( file => 'README.md', format => 'cool', options => ['goodbye'], ), 'goodbye', 'Test the "cool" parser with options'; my $pod_dir = catdir (qw(t markups)); like $parser->parse( file => "$pod_dir/pod.txt", format => "pod", options => [ html_header => '', ], ), qr||, 'Test pod option to suppress HTML header'; unlike $parser->parse( file => "$pod_dir/pod.txt", format => "pod", options => [ html_header => '', html_footer => '', ], ), qr||, 'Test pod options to suppress HTML header and footer'; # Test the "none" parser. my $output = do { my $f = __FILE__; open my $fh, '<:utf8', $f or die "Cannot open $f: $!\n"; local $/; my $html = encode_entities(<$fh>, '<>&"'); utf8::encode($html); qq{
$html
}; }; $parser->default_format(undef); is $parser->parse( file => __FILE__, ), $output, 'Test the "none" parser'; Text-Markup-0.23/t/empty.txt000444000767000024 212527274673 15422 0ustar00davidstaff000000000000 Text-Markup-0.23/t/formats.t000444000767000024 510512527274673 15454 0ustar00davidstaff000000000000#!/usr/bin/env perl -w use strict; use warnings; use Test::More 0.96; use File::Spec::Functions qw(catfile); use Carp; # Need to have at least one test outside subtests, in case no subtests are run # at all. So it might as well be this. BEGIN { use_ok 'Text::Markup' or die; } sub slurp($$) { my ($filter, $file) = @_; $filter ||= sub { shift }; open my $fh, '<:raw', $file or die "Cannot open $file: $!\n"; local $/; return $filter->(<$fh>); } my %filter_for = ( mediawiki => sub { $_[0] =~ s/ö/CGI::escapeHTML(do { use utf8; 'ö' })/e if eval { CGI->VERSION >= 4.11 && CGI->VERSION < 4.14 }; return shift; }, ); my @loaded = Text::Markup->formats; while (my $data = ) { next if $data =~ /^#/; chomp $data; my ($format, $module, $req, @exts) = split /,/ => $data; subtest "Testing $format format" => sub { local $@; eval "use $req; 1;" if $req; plan skip_all => "$module not loading" if $@; plan tests => @exts + 5; use_ok $module or next; push @loaded => $format unless grep { $_ eq $format } @loaded; is_deeply [Text::Markup->formats], \@loaded, "$format should be loaded"; my $parser = new_ok 'Text::Markup'; for my $ext (@exts) { is $parser->guess_format("foo.$ext"), $format, "Should guess that .$ext extension is $format"; } my $expect = slurp $filter_for{$format}, catfile('t', 'html', "$format.html"); is $parser->parse( file => catfile('t', 'markups', "$format.txt"), format => $format, ), $expect, "Parse $format file"; is $parser->parse( file => catfile('t', 'empty.txt'), format => $format, ), undef, "Parse empty $format file"; } } done_testing; __DATA__ # Format,Format Module,Required Module,extensions markdown,Text::Markup::Markdown,Text::Markdown 1.000004,md,mkdn,mkd,mdown,markdown html,Text::Markup::HTML,,html,htm,xhtml,xhtm pod,Text::Markup::Pod,Pod::Simple::XHTML 3.15,pod,pm,pl trac,Text::Markup::Trac,Text::Trac 0.10,trac,trc textile,Text::Markup::Textile,Text::Textile 2.10,textile mediawiki,Text::Markup::Mediawiki,Text::MediawikiFormat 1.0,wiki,mwiki,mediawiki multimarkdown,Text::Markup::Multimarkdown,Text::MultiMarkdown 1.000033,mmd,mmkdn,mmkd,mmdown,mmarkdown rest,Text::Markup::Rest,Text::Markup::Rest,rest,rst asciidoc,Text::Markup::Asciidoc,Text::Markup::Asciidoc,asciidoc,asc,adoc bbcode,Text::Markup::Bbcode,Parse::BBCode,bbcode,bb creole,Text::Markup::Creole,Text::WikiCreole,creole Text-Markup-0.23/t/html000755000767000024 012527274673 14422 5ustar00davidstaff000000000000Text-Markup-0.23/t/html/asciidoc.html000444000767000024 103512527274673 17222 0ustar00davidstaff000000000000

start paragraph

another paragraph

  • list of things with ürls in

  • more things in the list

Text-Markup-0.23/t/html/bbcode.html000444000767000024 36012527274673 16642 0ustar00davidstaff000000000000 BBcode Test File

This file tests BBcode.

  • BBcode
  • Test
  • File

Text-Markup-0.23/t/html/creole.html000444000767000024 42512527274673 16677 0ustar00davidstaff000000000000

Creole Test File

This file tests Creole markup language.

  • Creole
  • Test
  • File
Text-Markup-0.23/t/html/html.html000444000767000024 61612527274673 16374 0ustar00davidstaff000000000000 Hi There

The Header

This is the body. I mean a paragraph in the body.

Text-Markup-0.23/t/html/markdown.html000444000767000024 50612527274673 17250 0ustar00davidstaff000000000000

Markdown Test File

This file tests the Markdown parser — which is powered by Text::Markdown. Öy.

Text-Markup-0.23/t/html/mediawiki.html000444000767000024 37212527274673 17372 0ustar00davidstaff000000000000

heading

* unordered item 1. ordered item

some code

a normal paragraph, yö.

Text-Markup-0.23/t/html/multimarkdown.html000444000767000024 107212527274673 20342 0ustar00davidstaff000000000000

Markdown Test File

This file tests the MultiMarkdown parser — which is powered by Text::MultiMarkdown. Öy.1


  1. Yes, you heard right. ↩

Text-Markup-0.23/t/html/pod.html000444000767000024 111712527274673 16227 0ustar00davidstaff000000000000

Title

This is a Pod document

Description

This is where we have a précis describing stuff, you know?

And now, for some Japanese.

萎衣謂違遺医井亥域育郁磯一壱溢逸稲茨芋鰯允印咽員因姻引飲淫胤蔭

Now some verbatim text:

-- Provide a comment
SELECT *
  FROM users
 WHERE nickname = 'theory';

The end.

Text-Markup-0.23/t/html/rest.html000444000767000024 262312527274673 16425 0ustar00davidstaff000000000000 I am a reST document

I am a reST document

And I am its subtitle

Rest allows inline style and other stuff, but I guess this code is enough.

unknown: arg1 arg2
We also support unknown directive, so that no content is lost if reST
specialization is parsed.

Of course we may also find new roles.

module: mymodule

This is a module that doesn't exist

function: foo()

In Sphinx documentation you could find this stuff.

print "I have no title"
Text-Markup-0.23/t/html/textile.html000444000767000024 51712527274673 17106 0ustar00davidstaff000000000000

start paragraph

another paragraph

  • list of things with ürls in
  • more things in the list

a http://bare.url.here. and an email@address.com

Text-Markup-0.23/t/html/trac.html000444000767000024 54512527274673 16362 0ustar00davidstaff000000000000

Trac Markup

This should contain Trac markup. Öy.

  • Item 1
    • Item 1.1
      • Item 1.1.1
      • Item 1.1.2
      • Item 1.1.3
    • Item 1.2
  • Item 2
Text-Markup-0.23/t/markups000755000767000024 012527274673 15140 5ustar00davidstaff000000000000Text-Markup-0.23/t/markups/asciidoc.txt000444000767000024 25012527274673 17571 0ustar00davidstaff000000000000start paragraph another paragraph - list of things with http://www.jerakeen.org[ürls] in - more things in the list a http://bare.url.here. and an email@address.com Text-Markup-0.23/t/markups/bbcode.txt000444000767000024 14612527274673 17235 0ustar00davidstaff000000000000[b]BBcode Test File[/b] This file tests [i]BBcode[/i]. [list] [*] BBcode [*] Test [*] File [/list] Text-Markup-0.23/t/markups/creole.txt000444000767000024 13312527274673 17264 0ustar00davidstaff000000000000**Creole Test File** This file tests //Creole markup language//. * Creole * Test * File Text-Markup-0.23/t/markups/html.txt000444000767000024 61612527274673 16765 0ustar00davidstaff000000000000 Hi There

The Header

This is the body. I mean a paragraph in the body.

Text-Markup-0.23/t/markups/markdown.txt000444000767000024 30512527274673 17636 0ustar00davidstaff000000000000Markdown Test File ================== This file tests the [Markdown](http://daringfireball.net/projects/markdown/) parser — which is powered by [Text::Markdown](http://p3rl/Text::Markdown). Öy.Text-Markup-0.23/t/markups/mediawiki.txt000444000767000024 13112527274673 17754 0ustar00davidstaff000000000000= heading = * unordered item 1. ordered item some code a normal paragraph, yö. Text-Markup-0.23/t/markups/multimarkdown.txt000444000767000024 36312527274673 20715 0ustar00davidstaff000000000000Markdown Test File ================== This file tests the [MultiMarkdown](http://fletcherpenney.net/multimarkdown/) parser — which is powered by [Text::MultiMarkdown](http://p3rl/Text::MultiMarkdown). Öy.[^1] [^1]: Yes, you heard right. Text-Markup-0.23/t/markups/pod.txt000444000767000024 56612527274673 16607 0ustar00davidstaff000000000000=encoding UTF-8 =head1 Title This is a Pod document =head1 Description This is where we have a précis describing stuff, you know? And now, for some Japanese. 萎衣謂違遺医井亥域育郁磯一壱溢逸稲茨芋鰯允印咽員因姻引飲淫胤蔭 Now some verbatim text: -- Provide a comment SELECT * FROM users WHERE nickname = 'theory'; The end. Text-Markup-0.23/t/markups/rest.txt000444000767000024 124612527274673 17016 0ustar00davidstaff000000000000===================== I am a reST document ===================== And I am its subtitle ===================== Rest__ allows *inline* **style** and other stuff, but I guess this ``code`` is enough. .. __: http://docutils.sourceforge.net/ .. unknown:: arg1 arg2 :option: foo We also support unknown directive, so that no content is lost if reST specialization is parsed. Of course we may also find :unknown:`new roles`. .. module:: mymodule This is a module that doesn't *exist* .. function:: foo() In Sphinx documentation you could find this stuff. .. toctree:: we dont care .. code-block:: python print "I have no title" Text-Markup-0.23/t/markups/textile.txt000444000767000024 25112527274673 17472 0ustar00davidstaff000000000000start paragraph another paragraph * list of things with "ürls":http://www.jerakeen.org in * more things in the list a http://bare.url.here. and an email@address.com Text-Markup-0.23/t/markups/trac.txt000444000767000024 25012527274673 16744 0ustar00davidstaff000000000000= Trac Markup = This should contain ''Trac'' markup. Öy. * Item 1 * Item 1.1 * Item 1.1.1 * Item 1.1.2 * Item 1.1.3 * Item 1.2 * Item 2