Text-Markup-0.24000755000765000024 013574307541 13204 5ustar00davidstaff000000000000Text-Markup-0.24/Build.PL000444000765000024 274113574307541 14641 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.24/Changes000444000765000024 766613574307541 14653 0ustar00davidstaff000000000000Revision history for Perl extension Text-Markup. 0.24 2019-12-12T00:53:25Z - Added missing `` tag to all output. Thanks to Axel Beckert for the pull request (#16, #18)! - Added the `format_matchers` class method, which returns a list of formats and the regular expressions that match them. - Added `use warnings;` to all modules, thanks to a patch from John SJ Anderson (#22). - Added support for a `--raw` option to the markup modules for which it makes sense. This option allows markup to be output without wrapping it in a minimal HTML skeleton. Thanks to John SJ Anderson for the patch (#2, #24)! - Ported reST to Python 3. Thanks to gregor herrmann for the PR (#26). 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.24/MANIFEST000444000765000024 166013574307541 14475 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 MANIFEST This list of files 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 Makefile.PL META.yml META.json Text-Markup-0.24/META.json000444000765000024 645213574307541 14771 0ustar00davidstaff000000000000{ "abstract" : "Parse text markup into HTML", "author" : [ "David E. Wheeler " ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4229", "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.24" }, "Text::Markup::Asciidoc" : { "file" : "lib/Text/Markup/Asciidoc.pm", "version" : "0.24" }, "Text::Markup::Bbcode" : { "file" : "lib/Text/Markup/Bbcode.pm", "version" : "0.24" }, "Text::Markup::Creole" : { "file" : "lib/Text/Markup/Creole.pm", "version" : "0.24" }, "Text::Markup::HTML" : { "file" : "lib/Text/Markup/HTML.pm", "version" : "0.24" }, "Text::Markup::Markdown" : { "file" : "lib/Text/Markup/Markdown.pm", "version" : "0.24" }, "Text::Markup::Mediawiki" : { "file" : "lib/Text/Markup/Mediawiki.pm", "version" : "0.24" }, "Text::Markup::Multimarkdown" : { "file" : "lib/Text/Markup/Multimarkdown.pm", "version" : "0.24" }, "Text::Markup::None" : { "file" : "lib/Text/Markup/None.pm", "version" : "0.24" }, "Text::Markup::Pod" : { "file" : "lib/Text/Markup/Pod.pm", "version" : "0.24" }, "Text::Markup::Rest" : { "file" : "lib/Text/Markup/Rest.pm", "version" : "0.24" }, "Text::Markup::Textile" : { "file" : "lib/Text/Markup/Textile.pm", "version" : "0.24" }, "Text::Markup::Trac" : { "file" : "lib/Text/Markup/Trac.pm", "version" : "0.24" } }, "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.24", "x_serialization_backend" : "JSON::PP version 4.02" } Text-Markup-0.24/META.yml000444000765000024 422313574307541 14613 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.4229, CPAN::Meta::Converter version 2.150010' 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.24' Text::Markup::Asciidoc: file: lib/Text/Markup/Asciidoc.pm version: '0.24' Text::Markup::Bbcode: file: lib/Text/Markup/Bbcode.pm version: '0.24' Text::Markup::Creole: file: lib/Text/Markup/Creole.pm version: '0.24' Text::Markup::HTML: file: lib/Text/Markup/HTML.pm version: '0.24' Text::Markup::Markdown: file: lib/Text/Markup/Markdown.pm version: '0.24' Text::Markup::Mediawiki: file: lib/Text/Markup/Mediawiki.pm version: '0.24' Text::Markup::Multimarkdown: file: lib/Text/Markup/Multimarkdown.pm version: '0.24' Text::Markup::None: file: lib/Text/Markup/None.pm version: '0.24' Text::Markup::Pod: file: lib/Text/Markup/Pod.pm version: '0.24' Text::Markup::Rest: file: lib/Text/Markup/Rest.pm version: '0.24' Text::Markup::Textile: file: lib/Text/Markup/Textile.pm version: '0.24' Text::Markup::Trac: file: lib/Text/Markup/Trac.pm version: '0.24' 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.24' x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Text-Markup-0.24/Makefile.PL000444000765000024 202413574307541 15311 0ustar00davidstaff000000000000# Note: this file was auto-generated by Module::Build::Compat version 0.4229 require 5.008001; use ExtUtils::MakeMaker; WriteMakefile ( 'NAME' => 'Text::Markup', 'PL_FILES' => {}, 'EXE_FILES' => [], 'INSTALLDIRS' => 'site', 'VERSION_FROM' => 'lib/Text/Markup.pm', 'PREREQ_PM' => { 'Text::Trac' => '0.10', 'Module::Build' => '0.30', 'Text::WikiCreole' => '0.07', 'IPC::Open3' => 0, 'Text::MultiMarkdown' => '1.000028', 'Pod::Simple::XHTML' => '3.15', 'Test::More' => '0.96', 'HTML::Tagset' => 0, 'File::Spec::Functions' => 0, 'Text::MediawikiFormat' => '1.0', 'Symbol' => 0, 'File::BOM' => '0.14', 'Text::Markdown' => '1.000004', 'Text::Textile' => '2.10', 'Parse::BBCode' => '0.15', 'HTML::Entities' => 0 } ) ; Text-Markup-0.24/README.md000444000765000024 341313574307541 14621 0ustar00davidstaff000000000000Text/Markup version 0.24 ======================== [![CPAN version](https://badge.fury.io/pl/Text-Markup.svg)](https://badge.fury.io/pl/Text-Markup) [![Build Status](https://travis-ci.org/theory/text-markup.svg)](https://travis-ci.org/theory/text-markup) 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-2019 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.24/lib000755000765000024 013574307541 13752 5ustar00davidstaff000000000000Text-Markup-0.24/lib/Text000755000765000024 013574307541 14676 5ustar00davidstaff000000000000Text-Markup-0.24/lib/Text/Markup.pm000444000765000024 3124313574307541 16653 0ustar00davidstaff000000000000package Text::Markup; use 5.8.1; use strict; use warnings; use Text::Markup::None; use Carp; our $VERSION = '0.24'; 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 format_matchers { %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 C 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. =head3 C my %matchers = Text::Markup->format_matchers; Returns a list of key/value pairs mapping all the formats returned by C to the regular expressions used to match them. =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-2019 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.24/lib/Text/Markup000755000765000024          013574307541 16135 5ustar00davidstaff000000000000Text-Markup-0.24/lib/Text/Markup/Asciidoc.pm000444000765000024       712013574307541 20346 0ustar00davidstaff000000000000package Text::Markup::Asciidoc;

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

our $VERSION = '0.24';

# 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 $html if $opts->{raw};
    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');
  my $raw_asciidoc = Text::Markup->new->parse(file => 'hello.adoc', raw => 1 );

=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

Normally this parser returns the output of C wrapped in a minimal
HTML page skeleton. If you would prefer to just get the exact output returned
by C, you can pass in a true value for the C option.

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2012-2019 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.24/lib/Text/Markup/Bbcode.pm000444000765000024       331713574307541 20012 0ustar00davidstaff000000000000package Text::Markup::Bbcode;

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

our $VERSION = '0.24';

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 $html if $opts->{raw};
    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');
  my $raw  = Text::Markup->new->parse(file => 'file.bbcode', raw => 1);

=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

Normally this module returns the output wrapped in a minimal HTML document
skeleton. If you would like the raw output with the raw skeleton, you can pass
the C option to C.

=head1 Author

Lucas Kanashiro 

=head1 Copyright and License

Copyright (c) 2011-2019 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.24/lib/Text/Markup/Creole.pm000444000765000024       324113574307541 20041 0ustar00davidstaff000000000000package Text::Markup::Creole;

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

our $VERSION = '0.24';

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 $html if $opts->{raw};
    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');
  my $raw  = Text::Markup->new->parse(file => 'file.creole', raw => 1);

=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

Normally this module returns the output wrapped in a minimal HTML document
skeleton. If you would like the raw output without the skeleton, you can pass
the C option to C.

=head1 Author

Lucas Kanashiro 

=head1 Copyright and License

Copyright (c) 2011-2019 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.24/lib/Text/Markup/HTML.pm000444000765000024       221013574307541 17367 0ustar00davidstaff000000000000package Text::Markup::HTML;

use 5.8.1;
use strict;
use warnings;

our $VERSION = '0.24';

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-2019 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.24/lib/Text/Markup/Markdown.pm000444000765000024       375613574307541 20425 0ustar00davidstaff000000000000package Text::Markup::Markdown;

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

our $VERSION = '0.24';

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 $html if $opts->{raw};
    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');
  my $raw  = Text::Markup->new->parse(file => 'README.md', raw => 1);

=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

Normally this module returns the output wrapped in a minimal HTML document
skeleton. If you would like the raw output without the skeleton, you can pass
the C option to C.

=head1 See Also

L.
MarkI or MarkI?

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2019 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.24/lib/Text/Markup/Mediawiki.pm000444000765000024       347613574307541 20545 0ustar00davidstaff000000000000package Text::Markup::Mediawiki;

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

our $VERSION = '0.24';

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 $html if $opts->{raw};
    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');
  my $raw  = Text::Markup->new->parse(file => 'README.mediawiki', raw => 1);

=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>

Normally this module returns the output wrapped in a minimal HTML document
skeleton. If you would like the raw output without the skeleton, you can pass
the C option to C.

=back

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2019 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.24/lib/Text/Markup/Multimarkdown.pm000444000765000024       352713574307541 21474 0ustar00davidstaff000000000000package Text::Markup::Multimarkdown;

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

our $VERSION = '0.24';

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 $html if $opts->{raw};
    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');
  my $raw  = Text::Markup->new->parse(file => 'README.md', raw => 1);

=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

Normally this module returns the output wrapped in a minimal HTML document
skeleton. If you would like the raw output without the skeleton, you can pass
the C option to C.

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2019 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.24/lib/Text/Markup/None.pm000444000765000024       315613574307541 17534 0ustar00davidstaff000000000000package Text::Markup::None;

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

our $VERSION = '0.24';

sub parser {
    my ($file, $encoding, $opts) = @_;
    open_bom my $fh, $file, ":encoding($encoding)";
    local $/;
    my $html = encode_entities(<$fh>, '<>&"');
    utf8::encode($html);
    return $html if $opts->{raw};
    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'); my $raw = Text::Markup->new->parse(file => 'README', raw => 1); =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.

Normally this module returns the output wrapped in a minimal HTML document
skeleton. If you would like the raw output without the skeleton, you can pass
the C option to C.

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2019 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.24/lib/Text/Markup/Pod.pm000444000765000024       445213574307541 17357 0ustar00davidstaff000000000000package Text::Markup::Pod;

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

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

our $VERSION = '0.24';

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-2019 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.24/lib/Text/Markup/Rest.pm000444000765000024      1040213574307541 17562 0ustar00davidstaff000000000000package Text::Markup::Rest;

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

our $VERSION = '0.24';

# Find Python (process stolen from App::Info).
my ($PYTHON, $RST2HTML);
for my $exe (WIN32 ? 'python3.exe' : 'python3') {
    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-2019 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.24/lib/Text/Markup/Textile.pm000444000765000024       353213574307541 20251 0ustar00davidstaff000000000000package Text::Markup::Textile;

use 5.8.1;
use strict;
use warnings;
use File::BOM qw(open_bom);
use Text::Textile '2.10';

our $VERSION = '0.24';

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 $html if $opts->{raw};
    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');
  my $raw  = Text::Markup->new->parse(file => 'README.textile', raw => 1);

=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

Normally this module returns the output wrapped in a minimal HTML document
skeleton. If you would like the raw output without the skeleton, you can pass
the C option to C.

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2019 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.24/lib/Text/Markup/Trac.pm000444000765000024       340113574307541 17517 0ustar00davidstaff000000000000package Text::Markup::Trac;

use 5.8.1;
use strict;
use warnings;
use File::BOM qw(open_bom);
use Text::Trac '0.10';

our $VERSION = '0.24';

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 $html if $opts->{raw};
    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');
  my $raw  = Text::Markup->new->parse(file => 'README.trac', raw => 1);

=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

Normally this module returns the output wrapped in a minimal HTML document
skeleton. If you would like the raw output without the skeleton, you can pass
the C option to C.

=head1 Author

David E. Wheeler 

=head1 Copyright and License

Copyright (c) 2011-2019 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.24/lib/Text/Markup/rst2html_lenient.py000555000765000024      2275513574307541 22177 0ustar00davidstaff000000000000#!/usr/bin/env python3
"""
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, "%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, "%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 = '\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 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 as exc:
            problems.append("error during library patching")
            raise

        try:
            out = publish_string(TEST_SOURCE,
                writer=writer, settings_spec=LenientSettingsSpecs,
                settings_overrides={'output_encoding': 'unicode'})
        except Exception as 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("Patching docutils failed!", file=sys.stderr) for problem in problems: print("-", problem, file=sys.stderr) if rv: print("\nVersions:", \ 'docutils:', docutils.__version__, docutils.__version_details__, \ '\nPython:', sys.version, file=sys.stderr) if exc: if '--traceback' in sys.argv: print(file=sys.stderr) import traceback traceback.print_exc() else: print("\nUse --traceback to display the error stack trace.", file=sys.stderr) return rv if __name__ == '__main__': sys.exit(main()) Text-Markup-0.24/t000755000765000024 013574307541 13447 5ustar00davidstaff000000000000Text-Markup-0.24/t/base.t000444000765000024 1073013574307541 14724 0ustar00davidstaff000000000000#!/usr/bin/env perl -w use strict; use warnings; use Test::More tests => 38; #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 formats'; ok my %matchers = Text::Markup->format_matchers, 'Get format matchers'; is_deeply [sort keys %matchers], [sort @core_parsers], 'Should have core format matchers'; isa_ok $_, 'Regexp', $_ for values %matchers; # 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.24/t/empty.txt000444000765000024 213574307541 15413 0ustar00davidstaff000000000000 Text-Markup-0.24/t/formats.t000444000765000024 510513574307541 15445 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.24/t/html000755000765000024 013574307541 14413 5ustar00davidstaff000000000000Text-Markup-0.24/t/html/asciidoc.html000444000765000024 104413574307541 17213 0ustar00davidstaff000000000000

start paragraph

another paragraph

  • list of things with ürls in

  • more things in the list

Text-Markup-0.24/t/html/bbcode.html000444000765000024 36713574307541 16642 0ustar00davidstaff000000000000 BBcode Test File

This file tests BBcode.

  • BBcode
  • Test
  • File

Text-Markup-0.24/t/html/creole.html000444000765000024 43413574307541 16670 0ustar00davidstaff000000000000

Creole Test File

This file tests Creole markup language.

  • Creole
  • Test
  • File
Text-Markup-0.24/t/html/html.html000444000765000024 61613574307541 16365 0ustar00davidstaff000000000000 Hi There

The Header

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

Text-Markup-0.24/t/html/markdown.html000444000765000024 51513574307541 17241 0ustar00davidstaff000000000000

Markdown Test File

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

Text-Markup-0.24/t/html/mediawiki.html000444000765000024 40113574307541 17354 0ustar00davidstaff000000000000

heading

* unordered item 1. ordered item

some code

a normal paragraph, yö.

Text-Markup-0.24/t/html/multimarkdown.html000444000765000024 110113574307541 20324 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.24/t/html/pod.html000444000765000024 111713574307541 16220 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.24/t/html/rest.html000444000765000024 262313574307541 16416 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.24/t/html/textile.html000444000765000024 52613574307541 17077 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.24/t/html/trac.html000444000765000024 55413574307541 16353 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.24/t/markups000755000765000024 013574307541 15131 5ustar00davidstaff000000000000Text-Markup-0.24/t/markups/asciidoc.txt000444000765000024 25013574307541 17562 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.24/t/markups/bbcode.txt000444000765000024 14613574307541 17226 0ustar00davidstaff000000000000[b]BBcode Test File[/b] This file tests [i]BBcode[/i]. [list] [*] BBcode [*] Test [*] File [/list] Text-Markup-0.24/t/markups/creole.txt000444000765000024 13313574307541 17255 0ustar00davidstaff000000000000**Creole Test File** This file tests //Creole markup language//. * Creole * Test * File Text-Markup-0.24/t/markups/html.txt000444000765000024 61613574307541 16756 0ustar00davidstaff000000000000 Hi There

The Header

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

Text-Markup-0.24/t/markups/markdown.txt000444000765000024 30513574307541 17627 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.24/t/markups/mediawiki.txt000444000765000024 13113574307541 17745 0ustar00davidstaff000000000000= heading = * unordered item 1. ordered item some code a normal paragraph, yö. Text-Markup-0.24/t/markups/multimarkdown.txt000444000765000024 36313574307541 20706 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.24/t/markups/pod.txt000444000765000024 56613574307541 16600 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.24/t/markups/rest.txt000444000765000024 124613574307541 17007 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.24/t/markups/textile.txt000444000765000024 25113574307541 17463 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.24/t/markups/trac.txt000444000765000024 25013574307541 16735 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