@@ -1,5 +1,42 @@
Revision history for Perl extension Pod-Markdown
+2.000 2014-02-01T14:38:27Z
+
+ - Releasing previous (1.99[01]) as stable
+ (now uses Pod::Simple instead of Pod::Parser).
+ See below for changes.
+
+1.991-TRIAL 2014-01-03T04:07:49Z
+
+ [Test Fixes]
+ - Ignore worthless testing of empty links that fail with Pod::Simple 3.16.
+
+1.990-TRIAL 2014-01-02T14:13:40Z
+
+ [Enhancements]
+ - Change backend from Pod::Parser to Pod::Simple.
+ Previous documented API has been ported
+ however the Pod::Simple API should be preferred for new code.
+ - Improve escaping of markdown characters.
+ - Accept for/begin 'markdown' and 'html' regions by default.
+ - Represent over/back regions without items as blockquotes.
+
+ [Backward Incompatible Changes]
+ - E<> codes used to produce equivalent html entities (&foo;).
+ These now simply print the corresponding unicode character as utf-8.
+ If you desire alternate behavior please report a bug.
+ - Tabs are now expanded.
+
+1.500 2013-11-22T15:05:31Z
+
+ - Format url fragments (in links to perldoc sections)
+ according to the destination site (perldoc_url_prefix).
+ This makes links to sections work where they probably never did before.
+ They are also customizable.
+
+ - Use multiple backticks to delimit code spans
+ that contain literal backticks.
+
1.401 2013-11-06T05:30:55Z
- Require Pod::Parser 1.51 for bug fixes.
@@ -1,3 +1,4 @@
+# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.012.
Changes
LICENSE
MANIFEST
@@ -7,15 +8,22 @@ META.yml
Makefile.PL
README
bin/pod2markdown
+corpus/tinypod.txt
dist.ini
lib/Pod/Markdown.pm
t/00-compile.t
t/00-report-prereqs.t
+t/back-compat.t
+t/basic.t
t/codes.t
+t/formats.t
+t/lib/MarkdownTests.pm
t/links.t
t/lists.t
t/meta.t
t/misc.t
+t/nested.t
+t/new.t
t/pod2markdown.t
t/verbatim.t
xt/author/critic.t
@@ -31,7 +39,6 @@ xt/release/minimum-version.t
xt/release/mojibake.t
xt/release/no-tabs.t
xt/release/pod-coverage.t
-xt/release/pod-linkcheck.t
xt/release/pod-syntax.t
xt/release/portability.t
xt/release/synopsis.t
@@ -8,7 +8,7 @@
"Randy Stauner <rwstauner@cpan.org>"
],
"dynamic_config" : 0,
- "generated_by" : "Dist::Zilla version 5.005, CPAN::Meta::Converter version 2.132830",
+ "generated_by" : "Dist::Zilla version 5.012, CPAN::Meta::Converter version 2.133380",
"license" : [
"perl_5"
],
@@ -54,8 +54,8 @@
},
"runtime" : {
"requires" : {
- "Pod::ParseLink" : "1.10",
- "Pod::Parser" : "1.51",
+ "Pod::Simple" : "3.14",
+ "Pod::Simple::Methody" : "0",
"parent" : "0",
"perl" : "5.008",
"strict" : "0",
@@ -65,9 +65,10 @@
"test" : {
"recommends" : {
"CPAN::Meta" : "0",
- "CPAN::Meta::Requirements" : "0"
+ "CPAN::Meta::Requirements" : "2.120900"
},
"requires" : {
+ "Exporter" : "0",
"ExtUtils::MakeMaker" : "0",
"File::Spec" : "0",
"File::Spec::Functions" : "0",
@@ -75,15 +76,19 @@
"IO::Handle" : "0",
"IPC::Open3" : "0",
"List::Util" : "0",
+ "Symbol" : "0",
"Test::Differences" : "0",
- "Test::More" : "0"
+ "Test::More" : "0.88",
+ "lib" : "0",
+ "utf8" : "0",
+ "version" : "0"
}
}
},
"provides" : {
"Pod::Markdown" : {
"file" : "lib/Pod/Markdown.pm",
- "version" : "1.401"
+ "version" : "2.000"
}
},
"release_status" : "stable",
@@ -99,7 +104,7 @@
"web" : "https://github.com/rwstauner/Pod-Markdown"
}
},
- "version" : "1.401",
+ "version" : "2.000",
"x_Dist_Zilla" : {
"perl" : {
"version" : "5.016003"
@@ -116,47 +121,47 @@
}
},
"name" : "Bootstrap::lib",
- "version" : "0.04000001"
+ "version" : "0.04000002"
},
{
"class" : "Dist::Zilla::Plugin::Git::NextVersion",
"name" : "@Author::RWSTAUNER/Git::NextVersion",
- "version" : "2.017"
+ "version" : "2.019"
},
{
"class" : "Dist::Zilla::Plugin::GenerateFile",
"name" : "@Author::RWSTAUNER/GenerateManifestSkip",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::GatherDir",
"name" : "@Author::RWSTAUNER/GatherDir",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::PruneCruft",
"name" : "@Author::RWSTAUNER/PruneCruft",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::ManifestSkip",
"name" : "@Author::RWSTAUNER/ManifestSkip",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::PruneFiles",
"name" : "@Author::RWSTAUNER/PruneDevelCoverDatabase",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::PruneFiles",
"name" : "@Author::RWSTAUNER/PruneCodeStatCollection",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::PruneFiles",
"name" : "@Author::RWSTAUNER/PruneTags",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::Authority",
@@ -166,7 +171,7 @@
{
"class" : "Dist::Zilla::Plugin::NextRelease",
"name" : "@Author::RWSTAUNER/NextRelease",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::Git::Describe",
@@ -176,7 +181,7 @@
{
"class" : "Dist::Zilla::Plugin::PkgVersion",
"name" : "@Author::RWSTAUNER/PkgVersion",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::Prepender",
@@ -187,30 +192,154 @@
"class" : "Dist::Zilla::Plugin::PodWeaver",
"config" : {
"Dist::Zilla::Plugin::PodWeaver" : {
- "config_plugin" : "@Author::RWSTAUNER",
+ "config_plugins" : [
+ "@Author::RWSTAUNER"
+ ],
"finder" : [
":InstallModules",
":ExecFiles"
+ ],
+ "plugins" : [
+ {
+ "class" : "Pod::Weaver::Plugin::Encoding",
+ "name" : "@Author::RWSTAUNER/Encoding",
+ "version" : "0.02"
+ },
+ {
+ "class" : "Pod::Weaver::Plugin::WikiDoc",
+ "name" : "@Author::RWSTAUNER/WikiDoc",
+ "version" : "0.093003"
+ },
+ {
+ "class" : "Pod::Weaver::Plugin::EnsurePod5",
+ "name" : "@CorePrep/EnsurePod5",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Plugin::H1Nester",
+ "name" : "@CorePrep/H1Nester",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Name",
+ "name" : "@Author::RWSTAUNER/Name",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Version",
+ "name" : "@Author::RWSTAUNER/Version",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Region",
+ "name" : "@Author::RWSTAUNER/Prelude",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Generic",
+ "name" : "@Author::RWSTAUNER/Synopsis",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Generic",
+ "name" : "@Author::RWSTAUNER/Description",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Generic",
+ "name" : "@Author::RWSTAUNER/Overview",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Generic",
+ "name" : "@Author::RWSTAUNER/Usage",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Collect",
+ "name" : "@Author::RWSTAUNER/Class Methods",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Collect",
+ "name" : "@Author::RWSTAUNER/Attributes",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Collect",
+ "name" : "@Author::RWSTAUNER/Methods",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Collect",
+ "name" : "@Author::RWSTAUNER/Functions",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Leftovers",
+ "name" : "@Author::RWSTAUNER/Leftovers",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Region",
+ "name" : "@Author::RWSTAUNER/Postlude",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Support",
+ "name" : "@Author::RWSTAUNER/Support",
+ "version" : "1.005"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Generic",
+ "name" : "@Author::RWSTAUNER/Acknowledgements",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Authors",
+ "name" : "@Author::RWSTAUNER/Authors",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Contributors",
+ "name" : "@Author::RWSTAUNER/Contributors",
+ "version" : "0.007"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Legal",
+ "name" : "@Author::RWSTAUNER/Legal",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Plugin::Transformer",
+ "name" : "@Author::RWSTAUNER/List",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Plugin::StopWords",
+ "name" : "@Author::RWSTAUNER/StopWords",
+ "version" : "1.008"
+ }
]
}
},
"name" : "@Author::RWSTAUNER/PodWeaver",
- "version" : "4.001"
+ "version" : "4.005"
},
{
"class" : "Dist::Zilla::Plugin::License",
"name" : "@Author::RWSTAUNER/License",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::Readme",
"name" : "@Author::RWSTAUNER/Readme",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod",
"name" : "@Author::RWSTAUNER/ReadmeAnyFromPod",
- "version" : "0.131500"
+ "version" : "0.133360"
},
{
"class" : "Dist::Zilla::Plugin::Bugtracker",
@@ -235,22 +364,25 @@
{
"class" : "Dist::Zilla::Plugin::AutoPrereqs",
"name" : "@Author::RWSTAUNER/AutoPrereqs",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::MetaNoIndex",
"name" : "@Author::RWSTAUNER/MetaNoIndex",
- "version" : "5.005"
- },
- {
- "class" : "Dist::Zilla::Plugin::FinderCode",
- "name" : "@Author::RWSTAUNER/MetaProvides::Package/AUTOVIV/:InstallModulesPM",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::MetaProvides::Package",
"config" : {
- "Dist::Zilla::Plugin::MetaProvides::Package" : {},
+ "Dist::Zilla::Plugin::MetaProvides::Package" : {
+ "finder_objects" : [
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : "@Author::RWSTAUNER/MetaProvides::Package/AUTOVIV/:InstallModulesPM",
+ "version" : "5.012"
+ }
+ ]
+ },
"Dist::Zilla::Role::MetaProvider::Provider" : {
"inherit_missing" : "1",
"inherit_version" : "1",
@@ -258,7 +390,7 @@
}
},
"name" : "@Author::RWSTAUNER/MetaProvides::Package",
- "version" : "1.15000000"
+ "version" : "1.15000003"
},
{
"class" : "Dist::Zilla::Plugin::MinimumPerl",
@@ -268,37 +400,37 @@
{
"class" : "Dist::Zilla::Plugin::MetaConfig",
"name" : "@Author::RWSTAUNER/MetaConfig",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::MetaYAML",
"name" : "@Author::RWSTAUNER/MetaYAML",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::MetaJSON",
"name" : "@Author::RWSTAUNER/MetaJSON",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::ExecDir",
"name" : "@Author::RWSTAUNER/ExecDir",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::ShareDir",
"name" : "@Author::RWSTAUNER/ShareDir",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::MakeMaker",
"name" : "@Author::RWSTAUNER/MakeMaker",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::Test::ReportPrereqs",
"name" : "@Author::RWSTAUNER/Test::ReportPrereqs",
- "version" : "0.010"
+ "version" : "0.013"
},
{
"class" : "Dist::Zilla::Plugin::Test::ChangesHasContent",
@@ -308,7 +440,7 @@
{
"class" : "Dist::Zilla::Plugin::Test::PodSpelling",
"name" : "@Author::RWSTAUNER/Test::PodSpelling",
- "version" : "2.006001"
+ "version" : "2.006002"
},
{
"class" : "Dist::Zilla::Plugin::Test::UnusedVars",
@@ -328,7 +460,7 @@
{
"class" : "Dist::Zilla::Plugin::PodCoverageTests",
"name" : "@Author::RWSTAUNER/@TestingMania/PodCoverageTests",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::Test::Perl::Critic",
@@ -343,7 +475,7 @@
{
"class" : "Dist::Zilla::Plugin::MetaTests",
"name" : "@Author::RWSTAUNER/@TestingMania/MetaTests",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::Test::Kwalitee",
@@ -353,7 +485,7 @@
{
"class" : "Dist::Zilla::Plugin::Test::EOL",
"name" : "@Author::RWSTAUNER/@TestingMania/Test::EOL",
- "version" : "0.08"
+ "version" : "0.10"
},
{
"class" : "Dist::Zilla::Plugin::Test::Synopsis",
@@ -384,12 +516,7 @@
}
},
"name" : "@Author::RWSTAUNER/@TestingMania/Test::Compile",
- "version" : "2.037"
- },
- {
- "class" : "Dist::Zilla::Plugin::Test::Pod::LinkCheck",
- "name" : "@Author::RWSTAUNER/@TestingMania/Test::Pod::LinkCheck",
- "version" : "1.001"
+ "version" : "2.039"
},
{
"class" : "Dist::Zilla::Plugin::Test::MinimumVersion",
@@ -409,7 +536,7 @@
}
},
"name" : "@Author::RWSTAUNER/@TestingMania/NoTabsTests",
- "version" : "0.05"
+ "version" : "0.06"
},
{
"class" : "Dist::Zilla::Plugin::MojibakeTests",
@@ -419,17 +546,17 @@
{
"class" : "Dist::Zilla::Plugin::PodSyntaxTests",
"name" : "@Author::RWSTAUNER/@TestingMania/PodSyntaxTests",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::Manifest",
"name" : "@Author::RWSTAUNER/Manifest",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::CheckExtraTests",
"name" : "@Author::RWSTAUNER/CheckExtraTests",
- "version" : "0.015"
+ "version" : "0.016"
},
{
"class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
@@ -444,42 +571,42 @@
{
"class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed",
"name" : "@Author::RWSTAUNER/CheckPrereqsIndexed",
- "version" : "0.009"
+ "version" : "0.010"
},
{
"class" : "Dist::Zilla::Plugin::TestRelease",
"name" : "@Author::RWSTAUNER/TestRelease",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::Git::Check",
"name" : "@Author::RWSTAUNER/@Git/Check",
- "version" : "2.017"
+ "version" : "2.019"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
"name" : "@Author::RWSTAUNER/@Git/Commit",
- "version" : "2.017"
+ "version" : "2.019"
},
{
"class" : "Dist::Zilla::Plugin::Git::Tag",
"name" : "@Author::RWSTAUNER/@Git/Tag",
- "version" : "2.017"
+ "version" : "2.019"
},
{
"class" : "Dist::Zilla::Plugin::Git::Push",
"name" : "@Author::RWSTAUNER/@Git/Push",
- "version" : "2.017"
+ "version" : "2.019"
},
{
"class" : "Dist::Zilla::Plugin::ConfirmRelease",
"name" : "@Author::RWSTAUNER/ConfirmRelease",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::UploadToCPAN",
"name" : "@Author::RWSTAUNER/UploadToCPAN",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::InstallRelease",
@@ -487,45 +614,49 @@
"version" : "0.008"
},
{
- "class" : "Dist::Zilla::Plugin::Prereqs",
- "config" : {
- "Dist::Zilla::Plugin::Prereqs" : {
- "phase" : "runtime",
- "type" : "requires"
- }
- },
- "name" : "Prereqs",
- "version" : "5.005"
- },
- {
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":InstallModules",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":IncModules",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":TestFiles",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExecFiles",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ShareFiles",
- "version" : "5.005"
+ "version" : "5.012"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":MainModule",
- "version" : "5.005"
+ "version" : "5.012"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":AllFiles",
+ "version" : "5.012"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":NoFiles",
+ "version" : "5.012"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : "@Author::RWSTAUNER/MetaProvides::Package/AUTOVIV/:InstallModulesPM",
+ "version" : "5.012"
}
],
"zilla" : {
@@ -533,7 +664,7 @@
"config" : {
"is_trial" : "0"
},
- "version" : "5.005"
+ "version" : "5.012"
}
},
"x_authority" : "cpan:RWSTAUNER",
@@ -7,23 +7,28 @@ author:
- 'Aristotle Pagaltzis <pagaltzis@gmx.de>'
- 'Randy Stauner <rwstauner@cpan.org>'
build_requires:
- ExtUtils::MakeMaker: 0
- File::Spec: 0
- File::Spec::Functions: 0
- File::Temp: 0
- IO::Handle: 0
- IPC::Open3: 0
- List::Util: 0
- Test::Differences: 0
- Test::More: 0
+ Exporter: '0'
+ ExtUtils::MakeMaker: '0'
+ File::Spec: '0'
+ File::Spec::Functions: '0'
+ File::Temp: '0'
+ IO::Handle: '0'
+ IPC::Open3: '0'
+ List::Util: '0'
+ Symbol: '0'
+ Test::Differences: '0'
+ Test::More: '0.88'
+ lib: '0'
+ utf8: '0'
+ version: '0'
configure_requires:
- ExtUtils::MakeMaker: 6.30
+ ExtUtils::MakeMaker: '6.30'
dynamic_config: 0
-generated_by: 'Dist::Zilla version 5.005, CPAN::Meta::Converter version 2.132830'
+generated_by: 'Dist::Zilla version 5.012, CPAN::Meta::Converter version 2.133380'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
- version: 1.4
+ version: '1.4'
name: Pod-Markdown
no_index:
directory:
@@ -41,233 +46,332 @@ no_index:
provides:
Pod::Markdown:
file: lib/Pod/Markdown.pm
- version: 1.401
+ version: '2.000'
requires:
- Pod::ParseLink: 1.10
- Pod::Parser: 1.51
- parent: 0
- perl: 5.008
- strict: 0
- warnings: 0
+ Pod::Simple: '3.14'
+ Pod::Simple::Methody: '0'
+ parent: '0'
+ perl: '5.008'
+ strict: '0'
+ warnings: '0'
resources:
bugtracker: http://rt.cpan.org/Public/Dist/Display.html?Name=Pod-Markdown
homepage: https://github.com/rwstauner/Pod-Markdown
repository: https://github.com/rwstauner/Pod-Markdown.git
-version: 1.401
+version: '2.000'
x_Dist_Zilla:
perl:
- version: 5.016003
+ version: '5.016003'
plugins:
-
class: Dist::Zilla::Plugin::Bootstrap::lib
config:
Dist::Zilla::Role::Bootstrap:
distname: Pod-Markdown
- fallback: 1
+ fallback: '1'
try_built: ~
try_built_method: mtime
name: Bootstrap::lib
- version: 0.04000001
+ version: '0.04000002'
-
class: Dist::Zilla::Plugin::Git::NextVersion
name: '@Author::RWSTAUNER/Git::NextVersion'
- version: 2.017
+ version: '2.019'
-
class: Dist::Zilla::Plugin::GenerateFile
name: '@Author::RWSTAUNER/GenerateManifestSkip'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::GatherDir
name: '@Author::RWSTAUNER/GatherDir'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::PruneCruft
name: '@Author::RWSTAUNER/PruneCruft'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::ManifestSkip
name: '@Author::RWSTAUNER/ManifestSkip'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::PruneFiles
name: '@Author::RWSTAUNER/PruneDevelCoverDatabase'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::PruneFiles
name: '@Author::RWSTAUNER/PruneCodeStatCollection'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::PruneFiles
name: '@Author::RWSTAUNER/PruneTags'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::Authority
name: '@Author::RWSTAUNER/Authority'
- version: 1.006
+ version: '1.006'
-
class: Dist::Zilla::Plugin::NextRelease
name: '@Author::RWSTAUNER/NextRelease'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::Git::Describe
name: '@Author::RWSTAUNER/Git::Describe'
- version: 0.003
+ version: '0.003'
-
class: Dist::Zilla::Plugin::PkgVersion
name: '@Author::RWSTAUNER/PkgVersion'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::Prepender
name: '@Author::RWSTAUNER/Prepender'
- version: 1.112280
+ version: '1.112280'
-
class: Dist::Zilla::Plugin::PodWeaver
config:
Dist::Zilla::Plugin::PodWeaver:
- config_plugin: '@Author::RWSTAUNER'
+ config_plugins:
+ - '@Author::RWSTAUNER'
finder:
- ':InstallModules'
- ':ExecFiles'
+ plugins:
+ -
+ class: Pod::Weaver::Plugin::Encoding
+ name: '@Author::RWSTAUNER/Encoding'
+ version: '0.02'
+ -
+ class: Pod::Weaver::Plugin::WikiDoc
+ name: '@Author::RWSTAUNER/WikiDoc'
+ version: '0.093003'
+ -
+ class: Pod::Weaver::Plugin::EnsurePod5
+ name: '@CorePrep/EnsurePod5'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Plugin::H1Nester
+ name: '@CorePrep/H1Nester'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Name
+ name: '@Author::RWSTAUNER/Name'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Version
+ name: '@Author::RWSTAUNER/Version'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Region
+ name: '@Author::RWSTAUNER/Prelude'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Generic
+ name: '@Author::RWSTAUNER/Synopsis'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Generic
+ name: '@Author::RWSTAUNER/Description'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Generic
+ name: '@Author::RWSTAUNER/Overview'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Generic
+ name: '@Author::RWSTAUNER/Usage'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Collect
+ name: '@Author::RWSTAUNER/Class Methods'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Collect
+ name: '@Author::RWSTAUNER/Attributes'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Collect
+ name: '@Author::RWSTAUNER/Methods'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Collect
+ name: '@Author::RWSTAUNER/Functions'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Leftovers
+ name: '@Author::RWSTAUNER/Leftovers'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Region
+ name: '@Author::RWSTAUNER/Postlude'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Support
+ name: '@Author::RWSTAUNER/Support'
+ version: '1.005'
+ -
+ class: Pod::Weaver::Section::Generic
+ name: '@Author::RWSTAUNER/Acknowledgements'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Authors
+ name: '@Author::RWSTAUNER/Authors'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Contributors
+ name: '@Author::RWSTAUNER/Contributors'
+ version: '0.007'
+ -
+ class: Pod::Weaver::Section::Legal
+ name: '@Author::RWSTAUNER/Legal'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Plugin::Transformer
+ name: '@Author::RWSTAUNER/List'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Plugin::StopWords
+ name: '@Author::RWSTAUNER/StopWords'
+ version: '1.008'
name: '@Author::RWSTAUNER/PodWeaver'
- version: 4.001
+ version: '4.005'
-
class: Dist::Zilla::Plugin::License
name: '@Author::RWSTAUNER/License'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::Readme
name: '@Author::RWSTAUNER/Readme'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::ReadmeAnyFromPod
name: '@Author::RWSTAUNER/ReadmeAnyFromPod'
- version: 0.131500
+ version: '0.133360'
-
class: Dist::Zilla::Plugin::Bugtracker
name: '@Author::RWSTAUNER/Bugtracker'
- version: 1.111080
+ version: '1.111080'
-
class: Dist::Zilla::Plugin::Repository
name: '@Author::RWSTAUNER/Repository'
- version: 0.19
+ version: '0.19'
-
class: Dist::Zilla::Plugin::GithubMeta
name: '@Author::RWSTAUNER/GithubMeta'
- version: 0.42
+ version: '0.42'
-
class: Dist::Zilla::Plugin::ContributorsFromGit
name: '@Author::RWSTAUNER/ContributorsFromGit'
- version: 0.006
+ version: '0.006'
-
class: Dist::Zilla::Plugin::AutoPrereqs
name: '@Author::RWSTAUNER/AutoPrereqs'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::MetaNoIndex
name: '@Author::RWSTAUNER/MetaNoIndex'
- version: 5.005
- -
- class: Dist::Zilla::Plugin::FinderCode
- name: '@Author::RWSTAUNER/MetaProvides::Package/AUTOVIV/:InstallModulesPM'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::MetaProvides::Package
config:
- Dist::Zilla::Plugin::MetaProvides::Package: {}
+ Dist::Zilla::Plugin::MetaProvides::Package:
+ finder_objects:
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: '@Author::RWSTAUNER/MetaProvides::Package/AUTOVIV/:InstallModulesPM'
+ version: '5.012'
Dist::Zilla::Role::MetaProvider::Provider:
- inherit_missing: 1
- inherit_version: 1
- meta_noindex: 1
+ inherit_missing: '1'
+ inherit_version: '1'
+ meta_noindex: '1'
name: '@Author::RWSTAUNER/MetaProvides::Package'
- version: 1.15000000
+ version: '1.15000003'
-
class: Dist::Zilla::Plugin::MinimumPerl
name: '@Author::RWSTAUNER/MinimumPerl'
- version: 1.003
+ version: '1.003'
-
class: Dist::Zilla::Plugin::MetaConfig
name: '@Author::RWSTAUNER/MetaConfig'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::MetaYAML
name: '@Author::RWSTAUNER/MetaYAML'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::MetaJSON
name: '@Author::RWSTAUNER/MetaJSON'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::ExecDir
name: '@Author::RWSTAUNER/ExecDir'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::ShareDir
name: '@Author::RWSTAUNER/ShareDir'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::MakeMaker
name: '@Author::RWSTAUNER/MakeMaker'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::Test::ReportPrereqs
name: '@Author::RWSTAUNER/Test::ReportPrereqs'
- version: 0.010
+ version: '0.013'
-
class: Dist::Zilla::Plugin::Test::ChangesHasContent
name: '@Author::RWSTAUNER/Test::ChangesHasContent'
- version: 0.006
+ version: '0.006'
-
class: Dist::Zilla::Plugin::Test::PodSpelling
name: '@Author::RWSTAUNER/Test::PodSpelling'
- version: 2.006001
+ version: '2.006002'
-
class: Dist::Zilla::Plugin::Test::UnusedVars
name: '@Author::RWSTAUNER/@TestingMania/Test::UnusedVars'
- version: 2.000005
+ version: '2.000005'
-
class: Dist::Zilla::Plugin::Test::Portability
name: '@Author::RWSTAUNER/@TestingMania/Test::Portability'
- version: 2.000005
+ version: '2.000005'
-
class: Dist::Zilla::Plugin::Test::Version
name: '@Author::RWSTAUNER/@TestingMania/Test::Version'
- version: 0.002004
+ version: '0.002004'
-
class: Dist::Zilla::Plugin::PodCoverageTests
name: '@Author::RWSTAUNER/@TestingMania/PodCoverageTests'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::Test::Perl::Critic
name: '@Author::RWSTAUNER/@TestingMania/Test::Perl::Critic'
- version: 2.112410
+ version: '2.112410'
-
class: Dist::Zilla::Plugin::Test::CPAN::Changes
name: '@Author::RWSTAUNER/@TestingMania/Test::CPAN::Changes'
- version: 0.008
+ version: '0.008'
-
class: Dist::Zilla::Plugin::MetaTests
name: '@Author::RWSTAUNER/@TestingMania/MetaTests'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::Test::Kwalitee
name: '@Author::RWSTAUNER/@TestingMania/Test::Kwalitee'
- version: 2.07
+ version: '2.07'
-
class: Dist::Zilla::Plugin::Test::EOL
name: '@Author::RWSTAUNER/@TestingMania/Test::EOL'
- version: 0.08
+ version: '0.10'
-
class: Dist::Zilla::Plugin::Test::Synopsis
name: '@Author::RWSTAUNER/@TestingMania/Test::Synopsis'
- version: 2.000004
+ version: '2.000004'
-
class: Dist::Zilla::Plugin::Test::DistManifest
name: '@Author::RWSTAUNER/@TestingMania/Test::DistManifest'
- version: 2.000004
+ version: '2.000004'
-
class: Dist::Zilla::Plugin::Test::CPAN::Meta::JSON
name: '@Author::RWSTAUNER/@TestingMania/Test::CPAN::Meta::JSON'
- version: 0.003
+ version: '0.003'
-
class: Dist::Zilla::Plugin::Test::Compile
config:
@@ -278,15 +382,11 @@ x_Dist_Zilla:
script_finder:
- ':ExecFiles'
name: '@Author::RWSTAUNER/@TestingMania/Test::Compile'
- version: 2.037
- -
- class: Dist::Zilla::Plugin::Test::Pod::LinkCheck
- name: '@Author::RWSTAUNER/@TestingMania/Test::Pod::LinkCheck'
- version: 1.001
+ version: '2.039'
-
class: Dist::Zilla::Plugin::Test::MinimumVersion
name: '@Author::RWSTAUNER/@TestingMania/Test::MinimumVersion'
- version: 2.000005
+ version: '2.000005'
-
class: Dist::Zilla::Plugin::NoTabsTests
config:
@@ -296,104 +396,108 @@ x_Dist_Zilla:
script_finder:
- ':ExecFiles'
name: '@Author::RWSTAUNER/@TestingMania/NoTabsTests'
- version: 0.05
+ version: '0.06'
-
class: Dist::Zilla::Plugin::MojibakeTests
name: '@Author::RWSTAUNER/@TestingMania/MojibakeTests'
- version: 0.5
+ version: '0.5'
-
class: Dist::Zilla::Plugin::PodSyntaxTests
name: '@Author::RWSTAUNER/@TestingMania/PodSyntaxTests'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::Manifest
name: '@Author::RWSTAUNER/Manifest'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::CheckExtraTests
name: '@Author::RWSTAUNER/CheckExtraTests'
- version: 0.015
+ version: '0.016'
-
class: Dist::Zilla::Plugin::CheckChangesHasContent
name: '@Author::RWSTAUNER/CheckChangesHasContent'
- version: 0.006
+ version: '0.006'
-
class: Dist::Zilla::Plugin::CheckMetaResources
name: '@Author::RWSTAUNER/CheckMetaResources'
- version: 0.001
+ version: '0.001'
-
class: Dist::Zilla::Plugin::CheckPrereqsIndexed
name: '@Author::RWSTAUNER/CheckPrereqsIndexed'
- version: 0.009
+ version: '0.010'
-
class: Dist::Zilla::Plugin::TestRelease
name: '@Author::RWSTAUNER/TestRelease'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::Git::Check
name: '@Author::RWSTAUNER/@Git/Check'
- version: 2.017
+ version: '2.019'
-
class: Dist::Zilla::Plugin::Git::Commit
name: '@Author::RWSTAUNER/@Git/Commit'
- version: 2.017
+ version: '2.019'
-
class: Dist::Zilla::Plugin::Git::Tag
name: '@Author::RWSTAUNER/@Git/Tag'
- version: 2.017
+ version: '2.019'
-
class: Dist::Zilla::Plugin::Git::Push
name: '@Author::RWSTAUNER/@Git/Push'
- version: 2.017
+ version: '2.019'
-
class: Dist::Zilla::Plugin::ConfirmRelease
name: '@Author::RWSTAUNER/ConfirmRelease'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::UploadToCPAN
name: '@Author::RWSTAUNER/UploadToCPAN'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::InstallRelease
name: '@Author::RWSTAUNER/InstallRelease'
- version: 0.008
- -
- class: Dist::Zilla::Plugin::Prereqs
- config:
- Dist::Zilla::Plugin::Prereqs:
- phase: runtime
- type: requires
- name: Prereqs
- version: 5.005
+ version: '0.008'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':InstallModules'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':IncModules'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':TestFiles'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':ExecFiles'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':ShareFiles'
- version: 5.005
+ version: '5.012'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':MainModule'
- version: 5.005
+ version: '5.012'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':AllFiles'
+ version: '5.012'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':NoFiles'
+ version: '5.012'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: '@Author::RWSTAUNER/MetaProvides::Package/AUTOVIV/:InstallModulesPM'
+ version: '5.012'
zilla:
class: Dist::Zilla::Dist::Builder
config:
- is_trial: 0
- version: 5.005
+ is_trial: '0'
+ version: '5.012'
x_authority: cpan:RWSTAUNER
x_contributors:
- 'Aristotle Pagaltzis <aristotle@cpan.org>'
@@ -1,4 +1,5 @@
+# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.012.
use strict;
use warnings;
@@ -22,13 +23,14 @@ my %WriteMakefileArgs = (
"LICENSE" => "perl",
"NAME" => "Pod::Markdown",
"PREREQ_PM" => {
- "Pod::ParseLink" => "1.10",
- "Pod::Parser" => "1.51",
+ "Pod::Simple" => "3.14",
+ "Pod::Simple::Methody" => 0,
"parent" => 0,
"strict" => 0,
"warnings" => 0
},
"TEST_REQUIRES" => {
+ "Exporter" => 0,
"ExtUtils::MakeMaker" => 0,
"File::Spec" => 0,
"File::Spec::Functions" => 0,
@@ -36,10 +38,14 @@ my %WriteMakefileArgs = (
"IO::Handle" => 0,
"IPC::Open3" => 0,
"List::Util" => 0,
+ "Symbol" => 0,
"Test::Differences" => 0,
- "Test::More" => 0
+ "Test::More" => "0.88",
+ "lib" => 0,
+ "utf8" => 0,
+ "version" => 0
},
- "VERSION" => "1.401",
+ "VERSION" => "2.000",
"test" => {
"TESTS" => "t/*.t"
}
@@ -47,6 +53,7 @@ my %WriteMakefileArgs = (
my %FallbackPrereqs = (
+ "Exporter" => 0,
"ExtUtils::MakeMaker" => 0,
"File::Spec" => 0,
"File::Spec::Functions" => 0,
@@ -54,12 +61,16 @@ my %FallbackPrereqs = (
"IO::Handle" => 0,
"IPC::Open3" => 0,
"List::Util" => 0,
- "Pod::ParseLink" => "1.10",
- "Pod::Parser" => "1.51",
+ "Pod::Simple" => "3.14",
+ "Pod::Simple::Methody" => 0,
+ "Symbol" => 0,
"Test::Differences" => 0,
- "Test::More" => 0,
+ "Test::More" => "0.88",
+ "lib" => 0,
"parent" => 0,
"strict" => 0,
+ "utf8" => 0,
+ "version" => 0,
"warnings" => 0
);
@@ -1,7 +1,7 @@
This archive contains the distribution Pod-Markdown,
-version 1.401:
+version 2.000:
Convert POD to Markdown
@@ -11,3 +11,5 @@ This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
+This README file was generated by Dist::Zilla::Plugin::Readme v5.012.
+
@@ -23,8 +23,8 @@ convert($in_fh, $out_fh);
sub convert {
my ($in_file, $out_file) = @_;
my $parser = Pod::Markdown->new;
- $parser->parse_from_filehandle($in_file);
- print $out_file $parser->as_markdown;
+ $parser->output_fh($out_file);
+ $parser->parse_file($in_file);
}
sub get_handle {
@@ -54,7 +54,7 @@ pod2markdown - Convert POD text to Markdown
=head1 VERSION
-version 1.401
+version 2.000
=head1 SYNOPSIS
@@ -0,0 +1,5 @@
+=pod
+
+This is I<pod>.
+
+=cut
@@ -9,13 +9,12 @@ copyright_year = 2004
[Bootstrap::lib]
[@Author::RWSTAUNER]
+; This seems broken (https://rt.cpan.org/Public/Bug/Display.html?id=73280)
+-remove = Test::Pod::LinkCheck
+
ReadmeAnyFromPod.type = markdown
Git::Check.allow_dirty = README.mkdn
Git::Commit.allow_dirty = README.mkdn
; Verbatim tests have trailing whitespace (in pod and and heredocs).
Test::EOL.trailing_whitespace = 0
-
-[Prereqs]
-; this could be RuntimeRecommends if it causes a problem
-Pod::ParseLink = 1.10
@@ -1,4 +1,4 @@
-# vim: set ts=4 sts=4 sw=4 expandtab smarttab:
+# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
#
# This file is part of Pod-Markdown
#
@@ -12,19 +12,15 @@ use strict;
use warnings;
package Pod::Markdown;
-{
- $Pod::Markdown::VERSION = '1.401';
-}
-# git description: v1.400-1-ge7a28a2
-
+# git description: v1.991-0-ge2edfd9
+$Pod::Markdown::VERSION = '2.000';
BEGIN {
$Pod::Markdown::AUTHORITY = 'cpan:RWSTAUNER';
}
# ABSTRACT: Convert POD to Markdown
-use Pod::Parser 1.51 ();
-use parent qw(Pod::Parser);
-use Pod::ParseLink (); # core
+use Pod::Simple 3.14 (); # external links with text
+use parent qw(Pod::Simple::Methody);
our %URL_PREFIXES = (
sco => 'http://search.cpan.org/perldoc?',
@@ -33,52 +29,203 @@ our %URL_PREFIXES = (
);
$URL_PREFIXES{perldoc} = $URL_PREFIXES{metacpan};
-sub initialize {
- my $self = shift;
- $self->SUPER::initialize(@_);
+
+sub new {
+ my $class = shift;
+ my %args = @_;
+
+ my $self = $class->SUPER::new();
+ $self->preserve_whitespace(1);
+ $self->accept_targets(qw( markdown html ));
+
+ my $data = $self->_private;
+ while( my ($attr, $val) = each %args ){
+ $data->{ $attr } = $val;
+ }
for my $type ( qw( perldoc man ) ){
my $attr = $type . '_url_prefix';
- my $url = $self->{ $attr } || $type;
+ # Use provided argument or default alias.
+ my $url = $self->$attr || $type;
# Expand alias if defined (otherwise use url as is).
- $self->{ $attr } = $URL_PREFIXES{ $url } || $url;
+ $data->{ $attr } = $URL_PREFIXES{ $url } || $url;
}
- $self->_private;
- $self;
+ $self->_prepare_fragment_formats;
+
+ return $self;
+}
+
+## Attribute accessors ##
+
+
+my @attr = qw(
+ man_url_prefix
+ perldoc_url_prefix
+ perldoc_fragment_format
+ markdown_fragment_format
+ include_meta_tags
+);
+
+{
+ no strict 'refs'; ## no critic
+ foreach my $attr ( @attr ){
+ *$attr = sub { return $_[0]->_private->{ $attr } };
+ }
}
+sub _prepare_fragment_formats {
+ my ($self) = @_;
+
+ foreach my $attr ( @attr ){
+ next unless $attr =~ /^(\w+)_fragment_format/;
+ my $type = $1;
+ my $format = $self->$attr;
+
+ # If one was provided.
+ if( $format ){
+ # If the attribute is a coderef just use it.
+ next if ref($format) eq 'CODE';
+ }
+ # Else determine a default.
+ else {
+ if( $type eq 'perldoc' ){
+ # Choose a default that matches the destination url.
+ my $target = $self->perldoc_url_prefix;
+ foreach my $alias ( qw( metacpan sco ) ){
+ if( $target eq $URL_PREFIXES{ $alias } ){
+ $format = $alias;
+ }
+ }
+ # This seems like a reasonable fallback.
+ $format ||= 'pod_simple_xhtml';
+ }
+ else {
+ $format = $type;
+ }
+ }
+
+ # The short name should become a method name with the prefix prepended.
+ my $prefix = 'format_fragment_';
+ $format =~ s/^$prefix//;
+ die "Unknown fragment format '$format'"
+ unless $self->can($prefix . $format);
+
+ # Save it.
+ $self->_private->{ $attr } = $format;
+ }
-# For consistency with Pod::Simple method names.
-sub perldoc_url_prefix {
- return $_[0]->{perldoc_url_prefix};
+ return;
}
-sub man_url_prefix {
- return $_[0]->{man_url_prefix};
+
+## Backward compatible API ##
+
+# For backward compatibility (previously based on Pod::Parser):
+# While Pod::Simple provides a parse_from_file() method
+# it's primarily for Pod::Parser compatibility.
+# When called without an output handle it will print to STDOUT
+# but the old Pod::Markdown never printed to a handle
+# so we don't want to start now.
+sub parse_from_file {
+ my ($self, $file) = @_;
+ $self->output_string(\($self->{_as_markdown_}));
+ $self->parse_file($file);
}
+# Likewise, though Pod::Simple doesn't define this method at all.
+sub parse_from_filehandle { shift->parse_from_file(@_) }
+
+
+## Document state ##
+
sub _private {
- my $self = shift;
- $self->{_MyParser} ||= {
- Text => [], # final text
- Indent => 0, # list indent levels counter
- ListType => '-', # character on every item
- searching => '' , # what are we searching for? (title, author etc.)
- sstack => [] , # Stack for searching, needed for nested list
- Title => undef, # page title
- Author => undef, # page author
- };
+ my ($self) = @_;
+ $self->{_Pod_Markdown_} ||= {
+ indent => 0,
+ stacks => [],
+ states => [{}],
+ link => [],
+ };
+}
+
+sub _increase_indent {
+ ++$_[0]->_private->{indent} >= 1
+ or die 'Invalid state: indent < 0';
+}
+sub _decrease_indent {
+ --$_[0]->_private->{indent} >= 0
+ or die 'Invalid state: indent < 0';
+}
+
+sub _new_stack {
+ push @{ $_[0]->_private->{stacks} }, [];
+ push @{ $_[0]->_private->{states} }, {};
+}
+
+sub _last_string {
+ $_[0]->_private->{stacks}->[-1][-1];
+}
+
+sub _pop_stack_text {
+ $_[0]->_private->{last_state} = pop @{ $_[0]->_private->{states} };
+ join '', @{ pop @{ $_[0]->_private->{stacks} } };
+}
+
+sub _stack_state {
+ $_[0]->_private->{states}->[-1];
}
+sub _save {
+ my ($self, $text) = @_;
+ push @{ $self->_private->{stacks}->[-1] }, $text;
+ # return $text; # DEBUG
+}
+
+sub _save_line {
+ my ($self, $text) = @_;
+ $self->_save($text . $/);
+}
+
+# For paragraphs, etc.
+sub _save_block {
+ my ($self, $text) = @_;
+
+ $self->_stack_state->{blocks}++;
+
+ $self->_save_line($self->_indent($text) . $/);
+}
+
+## Formatting ##
+
+sub _chomp_all {
+ my ($self, $text) = @_;
+ 1 while chomp $text;
+ return $text;
+}
+
+sub _indent {
+ my ($self, $text) = @_;
+ my $level = $self->_private->{indent};
+
+ if( $level ){
+ my $indent = ' ' x ($level * 4);
+
+ # Capture text on the line so that we don't indent blank lines (/^\x20{4}$/).
+ $text =~ s/^(.+)/$indent$1/mg;
+ }
+
+ return $text;
+}
+
+
sub as_markdown {
my ($parser, %args) = @_;
- my $data = $parser->_private;
- my $lines = $data->{Text};
my @header;
- if ($args{with_meta}) {
+ # Don't add meta tags again if we've already done it.
+ if( $args{with_meta} && !$parser->include_meta_tags ){
@header = $parser->_build_markdown_head;
}
- join("\n" x 2, @header, @{$lines}) . "\n";
+ return join("\n" x 2, @header, $parser->{_as_markdown_});
}
sub _build_markdown_head {
@@ -90,135 +237,141 @@ sub _build_markdown_head {
qw( Title Author );
}
-# $prelisthead:
-# undef : not list head
-# '' : list head not huddled
-# otherwise: list head huddled
-sub _save {
- my ($parser, $text, $prelisthead) = @_;
- my $data = $parser->_private;
- $text = $parser->_indent_text($text, defined($prelisthead));
- $text = $prelisthead."\n".$text if defined $prelisthead && $prelisthead ne '';
- push @{ $data->{Text} }, $text;
- return;
-}
-
-sub _unsave {
- my $parser = shift;
- my $data = $parser->_private;
- return pop @{ $data->{Text} };
-}
+## Escaping ##
-sub _indent_text {
- my ($parser, $text, $listhead) = @_;
- my $data = $parser->_private;
- my $level = $data->{Indent};
- --$level if $listhead;
- my $indent = undef;
- $indent = ' ' x ($level * 4);
- my @lines = map { $indent . $_; } split(/\n/, $text);
- return wantarray ? @lines : join("\n", @lines);
-}
-
-sub _clean_text {
- my $text = $_[1];
- my @trimmed = grep { $_; } split(/\n/, $text);
-
- return wantarray ? @trimmed : join("\n", @trimmed);
+# http://daringfireball.net/projects/markdown/syntax#backslash
+# Markdown provides backslash escapes for the following characters:
+#
+# \ backslash
+# ` backtick
+# * asterisk
+# _ underscore
+# {} curly braces
+# [] square brackets
+# () parentheses
+# # hash mark
+# + plus sign
+# - minus sign (hyphen)
+# . dot
+# ! exclamation mark
+
+# However some of those only need to be escaped in certain places:
+# * Backslashes *do* need to be escaped or they may be swallowed by markdown.
+# * Word-surrounding characters (/[`*_]/) *do* need to be escaped mid-word
+# because the markdown spec explicitly allows mid-word em*pha*sis.
+# * I don't actually see anything that curly braces are used for.
+# * Escaping square brackets is enough to avoid accidentally
+# creating links and images (so we don't need to escape plain parentheses
+# or exclamation points as that would generate a lot of unnecesary noise).
+# Parentheses will be escaped in urls (&end_L) to avoid premature termination.
+# * We don't need a backslash for every hash mark or every hyphen found mid-word,
+# just the ones that start a line (likewise for plus and dot).
+# (Those will all be handled by _escape_paragraph_markdown).
+
+# Backslash escape markdown characters to avoid having them interpreted.
+sub _escape_inline_markdown {
+ local $_ = $_[1];
+
+# s/([\\`*_{}\[\]()#+-.!])/\\$1/g; # See comments above.
+ s/([\\`*_\[\]])/\\$1/g;
+
+ return $_;
}
-sub _escape {
+# Escape markdown characters that would be interpreted
+# at the start of a line.
+sub _escape_paragraph_markdown {
local $_ = $_[1];
- # do inline characters first
- s/([][\\`*_#])/\\$1/g;
+ # Escape headings, horizontal rules, (unordered) lists, and blockquotes.
+ s/^([-+*#>])/\\$1/mg;
- # escape unordered lists and blockquotes
- s/^([-+*>])/\\$1/mg;
+ # Markdown doesn't support backslash escapes for equal signs
+ # even though they can be used to underline a header.
+ # So use html to escape them to avoid having them interpreted.
+ s/^([=])/sprintf '&#x%x;', ord($1)/mge;
- # escape dots that would wrongfully create numbered lists
+ # Escape the dots that would wrongfully create numbered lists.
s/^( (?:>\s+)? \d+ ) (\.\x20)/$1\\$2/xgm;
return $_;
}
-# Handles POD command paragraphs, denoted by a line beginning with C<=>.
-sub command {
- my ($parser, $command, $paragraph, $line_num) = @_;
- my $data = $parser->_private;
+## Parsing ##
- # cleaning the text
- $paragraph = $parser->_clean_text($paragraph);
+sub handle_text {
+ my ($self, $text) = @_;
- # is it a header ?
- if ($command =~ m{head(\d)}xms) {
- my $level = $1;
+ # Markdown is for html, so use html entities.
+ $text =~ s/ / /g
+ if $self->_private->{nbsp};
- $paragraph = $parser->_escape_and_interpolate($paragraph, $line_num);
+ # Unless we're in a code span or verbatim block.
+ unless( $self->_private->{no_escape} ){
- # the headers never are indented
- $parser->_save($parser->format_header($level, $paragraph));
- if ($level == 1) {
- if ($paragraph =~ m{NAME}xmsi) {
- $data->{searching} = 'title';
- } elsif ($paragraph =~ m{AUTHOR}xmsi) {
- $data->{searching} = 'author';
- } else {
- $data->{searching} = '';
- }
- }
- }
+ # We could, in theory, alter what gets escaped according to context
+ # (for example, escape square brackets (but not parens) inside link text).
+ # The markdown produced might look slightly nicer but either way you're
+ # at the whim of the markdown processor to interpret things correctly.
+ # For now just escape everything.
- # opening a list ?
- elsif ($command =~ m{over}xms) {
+ # Don't let literal characters be interpreted as markdown.
+ $text = $self->_escape_inline_markdown($text);
- # update indent level
- $data->{Indent}++;
- push @{$data->{sstack}}, $data->{searching};
+ }
- # closing a list ?
- } elsif ($command =~ m{back}xms) {
+ $self->_save($text);
+}
- # decrement indent level
- $data->{Indent}--;
- $data->{searching} = pop @{$data->{sstack}};
+sub start_Document {
+ my ($self) = @_;
+ $self->_new_stack;
+}
- } elsif ($command =~ m{item}xms) {
- # this strips the POD list head; the searching=listhead will insert markdown's
- # FIXME: this does not account for named lists
+sub end_Document {
+ my ($self) = @_;
+ $self->_check_search_header;
+ my $end = pop @{ $self->_private->{stacks} };
- # Assuming that POD is correctly wrtitten, we just use POD list head as markdown's
- $data->{ListType} = '-'; # Default
- if($paragraph =~ m{^[ \t]* \* [ \t]*}xms) {
- $paragraph =~ s{^[ \t]* \* [ \t]*}{}xms;
- } elsif($paragraph =~ m{^[ \t]* (\d+)\.? [ \t]*}xms) {
- $data->{ListType} = $1.'.'; # For numbered list only
- $paragraph =~ s{^[ \t]* \d+\.? [ \t]*}{}xms;
- }
+ @{ $self->_private->{stacks} } == 0
+ or die 'Document ended with stacks remaining';
- if ($data->{searching} eq 'listpara') {
- $data->{searching} = 'listheadhuddled';
- }
- else {
- $data->{searching} = 'listhead';
- }
+ my @doc = $self->_chomp_all(join('', @$end)) . $/;
- if (length $paragraph) {
- $parser->textblock($paragraph, $line_num);
- }
- }
+ if( $self->include_meta_tags ){
+ unshift @doc, $self->_build_markdown_head, ($/ x 2);
+ }
- # ignore other commands
- return;
+ print { $self->{output_fh} } @doc;
+}
+
+## Blocks ##
+
+sub start_Verbatim {
+ my ($self) = @_;
+ $self->_new_stack;
+ $self->_private->{no_escape} = 1;
+}
+
+sub end_Verbatim {
+ my ($self) = @_;
+
+ my $text = $self->_pop_stack_text;
+
+ $text = $self->_indent_verbatim($text);
+
+ $self->_private->{no_escape} = 0;
+
+ # Verbatim blocks do not generate a separate "Para" event.
+ $self->_save_block($text);
}
-# Handles verbatim text.
-sub verbatim {
- my ($parser, $paragraph) = @_;
+sub _indent_verbatim {
+ my ($self, $paragraph) = @_;
- # NOTE: perlpodspec says parsers should expand tabs by default
- # NOTE: Apparently Pod::Parser does not. should we?
- # NOTE: this might be s/^\t/" " x 8/e, but what about tabs inside the para?
+ # NOTE: Pod::Simple expands the tabs for us (as suggested by perlpodspec).
+ # Pod::Simple also has a 'strip_verbatim_indent' attribute
+ # but it doesn't sound like it gains us anything over this method.
# POD verbatim can start with any number of spaces (or tabs)
# markdown should be 4 spaces (or a tab)
@@ -233,179 +386,495 @@ sub verbatim {
if( (my $smallest = length($indent)) < 4 ){
# invert to get what needs to be prepended
$indent = ' ' x (4 - $smallest);
- # leave tabs alone
- $paragraph = join "\n", map { /^\t/ ? $_ : $indent . $_ } @lines;
+
+ # Prepend indent to each line.
+ # We could check /\S/ to only indent non-blank lines,
+ # but it's backward compatible to respect the whitespace.
+ # Additionally, both pod and markdown say they ignore blank lines
+ # so it shouldn't hurt to leave them in.
+ $paragraph = join "\n", map { length($_) ? $indent . $_ : '' } @lines;
}
- # FIXME: Checking _PREVIOUS is breaking Pod::Parser encapsulation
- # but helps solve the extraneous extra blank line b/t verbatim blocks.
- # We could probably keep track ourselves if need be.
- # NOTE: This requires Pod::Parser 1.50.
- # This is another reason to switch to Pod::Simple.
- my $previous_was_verbatim =
- $parser->{_PREVIOUS} && $parser->{_PREVIOUS} eq 'verbatim';
+ return $paragraph;
+}
+
+sub start_Para {
+ $_[0]->_new_stack;
+}
+
+sub end_Para {
+ my ($self) = @_;
+ my $text = $self->_pop_stack_text;
+
+ $text = $self->_escape_paragraph_markdown($text);
+
+ $self->_save_block($text);
+}
+
- if($previous_was_verbatim && $parser->_private->{Text}->[-1] =~ /[ \t]+$/){
- $paragraph = $parser->_unsave . "\n" . $paragraph;
+## Headings ##
+
+sub start_head1 { $_[0]->_start_head(1) }
+sub end_head1 { $_[0]->_end_head(1) }
+sub start_head2 { $_[0]->_start_head(2) }
+sub end_head2 { $_[0]->_end_head(2) }
+sub start_head3 { $_[0]->_start_head(3) }
+sub end_head3 { $_[0]->_end_head(3) }
+sub start_head4 { $_[0]->_start_head(4) }
+sub end_head4 { $_[0]->_end_head(4) }
+
+sub _check_search_header {
+ my ($self) = @_;
+ # Save the text since the last heading if we want it for metadata.
+ if( my $last = $self->_private->{search_header} ){
+ for( $self->_private->{$last} = $self->_last_string ){
+ s/\A\s+//;
+ s/\s+\z//;
}
+ }
+}
+sub _start_head {
+ my ($self) = @_;
+ $self->_check_search_header;
+ $self->_new_stack;
+}
+
+sub _end_head {
+ my ($self, $num) = @_;
+ my $h = '#' x $num;
+
+ my $text = $self->_pop_stack_text;
+ $self->_private->{search_header} =
+ $text =~ /NAME/ ? 'Title'
+ : $text =~ /AUTHOR/ ? 'Author'
+ : undef;
+
+ # TODO: option for $h suffix
+ # TODO: put a name="" if $self->{embed_anchor_tags}; ?
+ # https://rt.cpan.org/Ticket/Display.html?id=57776
+ $self->_save_block(join(' ', $h, $text));
+}
+
+## Lists ##
+
+# TODO: over_empty
- $parser->_save($paragraph);
+sub _start_list {
+ my ($self) = @_;
+ $self->_new_stack;
+
+ # Nest again b/c start_item will pop this to look for preceding content.
+ $self->_increase_indent;
+ $self->_new_stack;
}
-sub _escape_and_interpolate {
- my ($parser, $paragraph, $line_num) = @_;
+sub _end_list {
+ my ($self) = @_;
+ $self->_handle_between_item_content;
- # escape markdown characters in text sequences except for inline code
- $paragraph = join '', $parser->parse_text(
- { -expand_text => '_escape_non_code' },
- $paragraph, $line_num
- )->raw_text;
+ # Finish the list.
- # interpolate the paragraph for embedded sequences
- $paragraph = $parser->interpolate($paragraph, $line_num);
+ # All the child elements should be blocks,
+ # but don't end with a double newline.
+ my $text = $self->_chomp_all($self->_pop_stack_text);
- return $paragraph;
+ # FIXME:
+ $_[0]->_save_line($text . $/);
}
-sub _escape_non_code {
- my ($parser, $text, $ptree) = @_;
+sub _handle_between_item_content {
+ my ($self) = @_;
- if ($ptree->isa('Pod::InteriorSequence') && $ptree->cmd_name =~ /\A[CFL]\z/) {
- return $text;
+ # This might be empty (if the list item had no additional content).
+ if( my $text = $self->_pop_stack_text ){
+ # Else it's a sub-document.
+ # If there are blocks we need to separate with blank lines.
+ if( $self->_private->{last_state}->{blocks} ){
+ $text = $/ . $text;
}
- return $parser->_escape($text);
-}
-
-# Handles normal blocks of POD.
-sub textblock {
- my ($parser, $paragraph, $line_num) = @_;
- my $data = $parser->_private;
- my $prelisthead;
-
- $paragraph = $parser->_escape_and_interpolate($paragraph, $line_num);
-
- # clean the empty lines
- $paragraph = $parser->_clean_text($paragraph);
-
- # searching ?
- if ($data->{searching} =~ m{title|author}xms) {
- $data->{ ucfirst $data->{searching} } = $paragraph;
- $data->{searching} = '';
- } elsif ($data->{searching} =~ m{listhead(huddled)?$}xms) {
- my $is_huddled = $1;
- $paragraph = sprintf '%s %s', $data->{ListType}, $paragraph;
- if ($is_huddled) {
- # To compress into an item in order to avoid "\n\n" insertion.
- $prelisthead = $parser->_unsave();
- } else {
- $prelisthead = '';
- }
- $data->{searching} = 'listpara';
- } elsif ($data->{searching} eq 'listpara') {
- $data->{searching} = '';
+ # If not, we can condense the text.
+ # In this module's history there was a patch contributed to specifically
+ # produce "huddled" lists so we'll try to maintain that functionality.
+ else {
+ $text = $self->_chomp_all($text) . $/;
}
+ $self->_save($text)
+ }
- # save the text
- $parser->_save($paragraph, $prelisthead);
-}
-
-# An interior sequence is an embedded command
-# within a block of text which appears as a command name - usually a single
-# uppercase character - followed immediately by a string of text which is
-# enclosed in angle brackets.
-sub interior_sequence {
- my ($self, $seq_command, $seq_argument, $pod_seq) = @_;
-
- # nested links are not allowed
- return sprintf '%s<%s>', $seq_command, $seq_argument
- if $seq_command eq 'L' && $self->_private->{InsideLink};
-
- my $i = 2;
- my %interiors = (
- 'I' => sub { return '_' . $_[$i] . '_' }, # italic
- 'B' => sub { return '__' . $_[$i] . '__' }, # bold
- 'C' => sub { return '`' . $_[$i] . '`' }, # monospace
- 'F' => sub { return '`' . $_[$i] . '`' }, # system path
- # non-breaking space
- 'S' => sub {
- (my $s = $_[$i]) =~ s/ / /g;
- return $s;
- },
- 'E' => sub {
- my $charname = $_[$i];
- return '<' if $charname eq 'lt';
- return '>' if $charname eq 'gt';
- return '|' if $charname eq 'verbar';
- return '/' if $charname eq 'sol';
-
- # convert legacy charnames to more modern ones (see perlpodspec)
- $charname =~ s/\A([lr])chevron\z/${1}aquo/;
-
- return "&#$1;" if $charname =~ /^0(x[0-9a-fA-Z]+)$/;
-
- $charname = oct($charname) if $charname =~ /^0\d+$/;
-
- return "&#$charname;" if $charname =~ /^\d+$/;
-
- return "&$charname;";
- },
- 'L' => \&_resolv_link,
- 'X' => sub { '' },
- 'Z' => sub { '' },
- );
- if (exists $interiors{$seq_command}) {
- my $code = $interiors{$seq_command};
- return $code->($self, $seq_command, $seq_argument, $pod_seq);
- } else {
- return sprintf '%s<%s>', $seq_command, $seq_argument;
- }
+ $self->_decrease_indent;
}
-sub _resolv_link {
- my ($self, $cmd, $arg) = @_;
+sub _start_item {
+ my ($self) = @_;
+ $self->_handle_between_item_content;
+ $self->_new_stack;
+}
- local $self->_private->{InsideLink} = 1;
+sub _end_item {
+ my ($self, $marker) = @_;
+ $self->_save_line($self->_indent($marker . ' ' . $self->_pop_stack_text));
- my ($text, $inferred, $name, $section, $type) =
- # perlpodspec says formatting codes can occur in all parts of an L<>
- map { $_ && $self->interpolate($_, 1) }
- Pod::ParseLink::parselink($arg);
- my $url = '';
+ # Store any possible contents in a new stack (like a sub-document).
+ $self->_increase_indent;
+ $self->_new_stack;
+}
- if ($type eq 'url') {
- $url = $name;
- } elsif ($type eq 'man') {
- # stolen from Pod::Simple::(X)HTML
- my ($page, $part) = $name =~ /\A([^(]+)(?:[(](\S*)[)])?/;
- $url = $self->man_url_prefix . ($part || 1) . '/' . ($page || $name);
- } else {
- if ($name) {
- $url = $self->perldoc_url_prefix . $name;
- }
- if ($section){
- # TODO: sites/pod formatters differ on how to transform the section
- # TODO: we could do it according to specified url prefix or pod formatter
- # TODO: or allow a coderef?
- # TODO: (Pod::Simple::XHTML:idify() for metacpan)
- # TODO: (Pod::Simple::HTML section_escape/unicode_escape_url/section_url_escape for s.c.o.)
- $url .= '#' . $section;
- }
- }
+sub start_over_bullet { $_[0]->_start_list }
+sub end_over_bullet { $_[0]->_end_list }
- # if we don't know how to handle the url just print the pod back out
- if (!$url) {
- return sprintf '%s<%s>', $cmd, $arg;
+sub start_item_bullet { $_[0]->_start_item }
+sub end_item_bullet { $_[0]->_end_item('-') }
+
+sub start_over_number { $_[0]->_start_list }
+sub end_over_number { $_[0]->_end_list }
+
+sub start_item_number {
+ $_[0]->_start_item;
+ # It seems like this should be a stack,
+ # but from testing it appears that the corresponding 'end' event
+ # comes right after the text (it doesn't surround any embedded content).
+ # See t/nested.t which shows start-item, text, end-item, para, start-item....
+ $_[0]->_private->{item_number} = $_[1]->{number};
+}
+
+sub end_item_number {
+ my ($self) = @_;
+ $self->_end_item($self->_private->{item_number} . '.');
+}
+
+# Markdown doesn't support definition lists
+# so do regular (unordered) lists with indented paragraphs.
+sub start_over_text { $_[0]->_start_list }
+sub end_over_text { $_[0]->_end_list }
+
+sub start_item_text { $_[0]->_start_item }
+sub end_item_text { $_[0]->_end_item('-')}
+
+
+# perlpodspec equates an over/back region with no items to a blockquote.
+sub start_over_block {
+ # NOTE: We don't actually need to indent for a blockquote.
+ $_[0]->_new_stack;
+}
+
+sub end_over_block {
+ my ($self) = @_;
+
+ # Chomp first to avoid prefixing a blank line with a `>`.
+ my $text = $self->_chomp_all($self->_pop_stack_text);
+
+ # NOTE: Paragraphs will already be escaped.
+
+ # I don't really like either of these implementations
+ # but the join/map/split seems a little better and benches a little faster.
+ # You would lose the last newline but we've already chomped.
+ #$text =~ s{^(.)?}{'>' . (defined($1) && length($1) ? (' ' . $1) : '')}mge;
+ $text = join $/, map { length($_) ? '> ' . $_ : '>' } split qr-$/-, $text;
+
+ $self->_save_block($text);
+}
+
+## Custom Formats ##
+
+sub start_for {
+ my ($self, $attr) = @_;
+ $self->_new_stack;
+
+ if( $attr->{target} eq 'html' ){
+ # Use another stack so we can indent
+ # (not syntactily necessary but seems appropriate).
+ $self->_new_stack;
+ $self->_increase_indent;
+ $self->_private->{no_escape} = 1;
+ # Mark this so we know to undo it.
+ $self->_stack_state->{for_html} = 1;
+ }
+}
+
+sub end_for {
+ my ($self) = @_;
+ # Data gets saved as a block (which will handle indents),
+ # but if there was html we'll alter this, so chomp and save a block again.
+ my $text = $self->_chomp_all($self->_pop_stack_text);
+
+ if( $self->_private->{last_state}->{for_html} ){
+ $self->_private->{no_escape} = 0;
+ # Save it to the next stack up so we can pop it again (we made two stacks).
+ $self->_save($text);
+ $self->_decrease_indent;
+ $text = join "\n", '<div>', $self->_chomp_all($self->_pop_stack_text), '</div>';
+ }
+
+ $self->_save_block($text);
+}
+
+# Data events will be emitted for any formatted regions that have been enabled
+# (by default, `markdown` and `html`).
+
+sub start_Data {
+ my ($self) = @_;
+ # TODO: limit this to what's in attr?
+ $self->_private->{no_escape}++;
+ $self->_new_stack;
+}
+
+sub end_Data {
+ my ($self) = @_;
+ my $text = $self->_pop_stack_text;
+ $self->_private->{no_escape}--;
+ $self->_save_block($text);
+}
+
+## Codes ##
+
+# TODO: change to '**' ?
+sub start_B { $_[0]->_save('__') }
+sub end_B { $_[0]->start_B() }
+
+sub start_I { $_[0]->_save('_') }
+sub end_I { $_[0]->start_I() }
+
+sub start_C {
+ my ($self) = @_;
+ $self->_new_stack;
+ $self->_private->{no_escape}++;
+}
+
+sub end_C {
+ my ($self) = @_;
+ $self->_private->{no_escape}--;
+ $self->_save( $self->_wrap_code_span($self->_pop_stack_text) );
+}
+
+# Use code spans for F<>.
+sub start_F { shift->start_C(@_); }
+sub end_F { shift ->end_C(@_); }
+
+sub start_S { $_[0]->_private->{nbsp}++; }
+sub end_S { $_[0]->_private->{nbsp}--; }
+
+sub start_L {
+ my ($self, $flags) = @_;
+ $self->_new_stack;
+ push @{ $self->_private->{link} }, $flags;
+}
+
+sub end_L {
+ my ($self) = @_;
+ my $flags = pop @{ $self->_private->{link} }
+ or die 'Invalid state: link end with no link start';
+
+ my ($type, $to, $section) = @{$flags}{qw( type to section )};
+
+ my $url = (
+ $type eq 'url' ? $to
+ : $type eq 'man' ? $self->format_man_url($to, $section)
+ : $type eq 'pod' ? $self->format_perldoc_url($to, $section)
+ : undef
+ );
+
+ my $text = $self->_pop_stack_text;
+
+ # NOTE: I don't think the perlpodspec says what to do with L<|blah>
+ # but it seems like a blank link text just doesn't make sense
+ if( !length($text) ){
+ $text =
+ $section ?
+ $to ? sprintf('"%s" in %s', $section, $to)
+ : ('"' . $section . '"')
+ : $to;
+ }
+
+ # FIXME: What does Pod::Simple::X?HTML do for this?
+ # if we don't know how to handle the url just print the pod back out
+ if (!$url) {
+ $self->_save(sprintf 'L<%s>', $flags->{raw});
+ return;
+ }
+
+ # In the url we need to escape quotes and parentheses lest markdown
+ # break the url (cut it short and/or wrongfully interpret a title).
+
+ # Backslash escapes do not work for the space and quotes.
+ # URL-encoding the space is not sufficient
+ # (the quotes confuse some parsers and produce invalid html).
+ # I've arbitratily chosen HTML encoding to hide them from markdown
+ # while mangling the url as litle as possible.
+ $url =~ s/([ '"])/sprintf '&#x%x;', ord($1)/ge;
+
+ # We also need to double any backslashes that may be present
+ # (lest they be swallowed up) and stop parens from breaking the url.
+ $url =~ s/([\\()])/\\$1/g;
+
+ # TODO: put section name in title if not the same as $text
+ $self->_save('[' . $text . '](' . $url . ')');
+}
+
+sub start_X {
+ $_[0]->_new_stack;
+}
+
+sub end_X {
+ my ($self) = @_;
+ my $text = $self->_pop_stack_text;
+ # TODO: mangle $text?
+ # TODO: put <a name="$text"> if configured
+}
+
+# A code span can be delimited by multiple backticks (and a space)
+# similar to pod codes (C<< code >>), so ensure we use a big enough
+# delimiter to not have it broken by embedded backticks.
+sub _wrap_code_span {
+ my ($self, $arg) = @_;
+ my $longest = 0;
+ while( $arg =~ /([`]+)/g ){
+ my $len = length($1);
+ $longest = $len if $longest < $len;
+ }
+ my $delim = '`' x ($longest + 1);
+ my $pad = $longest > 0 ? ' ' : '';
+ return $delim . $pad . $arg . $pad . $delim;
+}
+
+## Link Formatting (TODO: Move this to another module) ##
+
+
+sub format_man_url {
+ my ($self, $to) = @_;
+ my ($page, $part) = ($to =~ /^ ([^(]+) (?: \( (\S+) \) )? /x);
+ return $self->man_url_prefix . ($part || 1) . '/' . ($page || $to);
+}
+
+
+sub format_perldoc_url {
+ my ($self, $name, $section) = @_;
+
+ my $url_prefix = $self->perldoc_url_prefix;
+ my $url = '';
+
+ # If the link is to another module (external link).
+ if ($name) {
+ $url = $url_prefix . $name;
+ }
+
+ # See https://rt.cpan.org/Ticket/Display.html?id=57776
+ # for a discussion on the need to mangle the section.
+ if ($section){
+
+ my $method = $url
+ # If we already have a prefix on the url it's external.
+ ? $self->perldoc_fragment_format
+ # Else an internal link points to this markdown doc.
+ : $self->markdown_fragment_format;
+
+ $method = 'format_fragment_' . $method
+ unless ref($method);
+
+ {
+ # Set topic to enable code refs to be simple.
+ local $_ = $section;
+ $section = $self->$method($section);
}
- return sprintf '[%s](%s)', ($text || $inferred), $url;
+ $url .= '#' . $section;
+ }
+
+ return $url;
+}
+
+
+# TODO: simple, pandoc, etc?
+
+sub format_fragment_markdown {
+ my ($self, $section) = @_;
+
+ # If this is an internal link (to another section in this doc)
+ # we can't be sure what the heading id's will look like
+ # (it depends on what is rendering the markdown to html)
+ # but we can try to follow popular conventions.
+
+ # http://johnmacfarlane.net/pandoc/demo/example9/pandocs-markdown.html#header-identifiers-in-html-latex-and-context
+ #$section =~ s/(?![-_.])[[:punct:]]//g;
+ #$section =~ s/\s+/-/g;
+ $section =~ s/\W+/-/g;
+ $section =~ s/-+$//;
+ $section =~ s/^-+//;
+ $section = lc $section;
+ #$section =~ s/^[^a-z]+//;
+ $section ||= 'section';
+
+ return $section;
+}
+
+
+{
+ # From Pod::Simple::XHTML 3.28.
+ # The strings gets passed through encode_entities() before idify().
+ # If we don't do it here the substitutions below won't operate consistently.
+
+ # encode_entities {
+ my %entities = (
+ q{>} => 'gt',
+ q{<} => 'lt',
+ q{'} => '#39',
+ q{"} => 'quot',
+ q{&} => 'amp',
+ );
+
+ my
+ $ents = join '', keys %entities;
+ # }
+
+ sub format_fragment_pod_simple_xhtml {
+ my ($self, $t) = @_;
+
+ # encode_entities {
+ $t =~ s/([$ents])/'&' . ($entities{$1} || sprintf '#x%X', ord $1) . ';'/ge;
+ # }
+
+ # idify {
+ for ($t) {
+ s/<[^>]+>//g; # Strip HTML.
+ s/&[^;]+;//g; # Strip entities.
+ s/^\s+//; s/\s+$//; # Strip white space.
+ s/^([^a-zA-Z]+)$/pod$1/; # Prepend "pod" if no valid chars.
+ s/^[^a-zA-Z]+//; # First char must be a letter.
+ s/[^-a-zA-Z0-9_:.]+/-/g; # All other chars must be valid.
+ s/[-:.]+$//; # Strip trailing punctuation.
+ }
+ # }
+
+ return $t;
+ }
}
-# Formats a header according to the given level.
-sub format_header {
- my ($level, $paragraph) = @_[1,2];
- sprintf '%s %s', '#' x $level, $paragraph;
+
+sub format_fragment_pod_simple_html {
+ my ($self, $section) = @_;
+
+ # From Pod::Simple::HTML 3.28.
+
+ # section_name_tidy {
+ $section =~ s/^\s+//;
+ $section =~ s/\s+$//;
+ $section =~ tr/ /_/;
+ $section =~ tr/\x00-\x1F\x80-\x9F//d if 'A' eq chr(65); # drop crazy characters
+
+ #$section = $self->unicode_escape_url($section);
+ # unicode_escape_url {
+ $section =~ s/([^\x00-\xFF])/'('.ord($1).')'/eg;
+ # Turn char 1234 into "(1234)"
+ # }
+
+ $section = '_' unless length $section;
+ return $section;
+ # }
}
+
+sub format_fragment_metacpan { shift->format_fragment_pod_simple_xhtml(@_); }
+sub format_fragment_sco { shift->format_fragment_pod_simple_html(@_); }
+
1;
__END__
@@ -418,9 +887,9 @@ __END__
org> Aristotle Pagaltzis Randy Stauner ACKNOWLEDGEMENTS ATARASHI motemen
moznion Graham Ollis Peter Vereshagin Yasutaka <aristotle@cpan.org>
<plicease@cpan.org> <veresc@cpan.org> <rthompson@cpan.org> <yakex@cpan.org>
-<motemen@cpan.org> <moznion@cpan.org> textblock cpan testmatrix url
-annocpan anno bugtracker rt cpants kwalitee diff irc mailto metadata
-placeholders metacpan
+<motemen@cpan.org> <moznion@cpan.org> html cpan testmatrix url annocpan
+anno bugtracker rt cpants kwalitee diff irc mailto metadata placeholders
+metacpan
=head1 NAME
@@ -428,42 +897,68 @@ Pod::Markdown - Convert POD to Markdown
=head1 VERSION
-version 1.401
+version 2.000
=head1 SYNOPSIS
- my $parser = Pod::Markdown->new;
- $parser->parse_from_filehandle(\*STDIN);
- print $parser->as_markdown;
+ # Pod::Simple API is supported.
+
+ # Parse a pod file and print to STDOUT:
+ Pod::Markdown->new->filter($pod_file);
+
+ # Work with strings:
+ my $markdown;
+ my $parser = Pod::Markdown->new;
+ $parser->output_string(\$markdown);
+ $parser->parse_string_document($pod_string);
+
+ # See Pod::Simple docs for more.
+
+ # Legacy (Pod::Parser-based) API is supported for backward compatibility:
+ my $parser = Pod::Markdown->new;
+ $parser->parse_from_filehandle(\*STDIN);
+ print $parser->as_markdown;
=head1 DESCRIPTION
-This module subclasses L<Pod::Parser> and converts POD to Markdown.
+This module uses L<Pod::Simple> to convert POD to Markdown.
Literal characters in Pod that are special in Markdown
(like *asterisks*) are backslash-escaped when appropriate.
-=head1 METHODS
-
-=head2 perldoc_url_prefix
-
-Returns the url prefix in use (after resolving shortcuts to urls).
+By default C<markdown> and C<html> formatted regions are accepted.
+Regions of C<markdown> will be passed through unchanged.
+Regions of C<html> will be placed inside a C<< E<lt>divE<gt> >> tag
+so that markdown characters won't be processed.
+Regions of C<:markdown> or C<:html> will be processed as POD and included.
+To change which regions are accepted use the L<Pod::Simple> API:
-=head2 man_url_prefix
+ my $parser = Pod::Markdown->new;
+ $parser->unaccept_targets(qw( markdown html ));
-Returns the url prefix in use for man pages.
+=head1 METHODS
=head2 new
+ Pod::Markdown->new(%options);
+
The constructor accepts the following named arguments:
=over 4
=item *
+C<man_url_prefix>
+
+Alters the man page urls that are created from C<< LE<lt>E<gt> >> codes.
+
+The default is C<http://man.he.net/man>.
+
+=item *
+
C<perldoc_url_prefix>
-This alters the perldoc urls that are created from C<< LE<lt>E<gt> >> codes.
+Alters the perldoc urls that are created from C<< LE<lt>E<gt> >> codes.
Can be:
=over 4
@@ -488,22 +983,148 @@ The default is C<metacpan>.
=item *
-C<man_url_prefix>
+C<perldoc_fragment_format>
-This alters the man page urls that are created from C<< LE<lt>E<gt> >> codes.
+Alters the format of the url fragment for any C<< LE<lt>E<gt> >> links
+that point to a section of an external document (C<< L<name/section> >>).
+The default will be chosen according to the destination L</perldoc_url_prefix>.
+Alternatively you can specify one of the following:
-The default is C<http://man.he.net/man>.
+=over 4
+
+=item *
+
+C<metacpan>
+
+=item *
+
+C<sco>
+
+=item *
+
+C<pod_simple_xhtml>
+
+=item *
+
+C<pod_simple_html>
+
+=item *
+
+A code ref
+
+=back
+
+The code ref can expect to receive two arguments:
+the parser object (C<$self>) and the section text.
+For convenience the topic variable (C<$_>) is also set to the section text:
+
+ perldoc_fragment_format => sub { s/\W+/-/g; }
+
+=item *
+
+C<markdown_fragment_format>
+
+Alters the format of the url fragment for any C<< LE<lt>E<gt> >> links
+that point to an internal section of this document (C<< L</section> >>).
+
+Unfortunately the format of the id attributes produced
+by whatever system translates the markdown into html is unknown at the time
+the markdown is generated so we do some simple clean up.
+
+B<Note:> C<markdown_fragment_format> and C<perldoc_fragment_format> accept
+the same values: a (shortcut to a) method name or a code ref.
+
+=item *
+
+C<include_meta_tags>
+
+Specifies whether or not to print author/title meta tags at the top of the document.
+Default is false.
=back
+=head2 man_url_prefix
+
+Returns the url prefix in use for man pages.
+
+=head2 perldoc_url_prefix
+
+Returns the url prefix in use (after resolving shortcuts to urls).
+
+=head2 perldoc_fragment_format
+
+Returns the coderef or format name used to format a url fragment
+to a section in an external document.
+
+=head2 markdown_fragment_format
+
+Returns the coderef or format name used to format a url fragment
+to an internal section in this document.
+
+=head2 include_meta_tags
+
+Returns the boolean value indicating
+whether or not meta tags will be printed.
+
=head2 as_markdown
Returns the parsed POD as Markdown. Takes named arguments. If the C<with_meta>
argument is given a positive value, meta tags are generated as well.
-=for Pod::Coverage format_header
-initialize
-command interior_sequence textblock verbatim
+=head2 format_man_url
+
+Used internally to create a url (using L</man_url_prefix>)
+from a string like C<man(1)>.
+
+=head2 format_perldoc_url
+
+ # With $name and section being the two parts of L<name/section>.
+ my $url = $parser->format_perldoc_url($name, $section);
+
+Used internally to create a url from
+the name (of a module or script)
+and a possible section (heading).
+
+The format of the url fragment (when pointing to a section in a document)
+varies depending on the destination url
+so L</perldoc_fragment_format> is used (which can be customized).
+
+If the module name portion of the link is blank
+then the section is treated as an internal fragment link
+(to a section of the generated markdown document)
+and L</markdown_fragment_format> is used (which can be customized).
+
+=head2 format_fragment_markdown
+
+Format url fragment for an internal link
+by replacing non-word characters with dashes.
+
+=head2 format_fragment_pod_simple_xhtml
+
+Format url fragment like L<Pod::Simple::XHTML/idify>.
+
+=head2 format_fragment_pod_simple_html
+
+Format url fragment like L<Pod::Simple::HTML/section_name_tidy>.
+
+=head2 format_fragment_metacpan
+
+Format fragment for L<metacpan.org>
+(uses L</format_fragment_pod_simple_xhtml>).
+
+=head2 format_fragment_sco
+
+Format fragment for L<search.cpan.org>
+(uses L</format_fragment_pod_simple_html>).
+
+=for Pod::Coverage parse_from_file
+parse_from_filehandle
+
+=for Pod::Coverage handle_text
+end_.+
+start_.+
+
+=for test_synopsis my ($pod_file, $pod_string);
=head1 SEE ALSO
@@ -513,6 +1134,22 @@ command interior_sequence textblock verbatim
L<pod2markdown> - script included for command line usage
+=item *
+
+L<Pod::Simple> - Super class that handles Pod parsing
+
+=item *
+
+L<perlpod> - For writing POD
+
+=item *
+
+L<perlpodspec> - For parsing POD
+
+=item *
+
+L<http://daringfireball.net/projects/markdown/syntax> - Markdown spec
+
=back
=head1 SUPPORT
@@ -1,7 +1,8 @@
+use 5.006;
use strict;
use warnings;
-# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.037
+# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.039
use Test::More tests => 2 + ($ENV{AUTHOR_TESTING} ? 1 : 0);
@@ -26,11 +27,12 @@ use File::Spec;
use IPC::Open3;
use IO::Handle;
+open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!";
+
my @warnings;
for my $lib (@module_files)
{
# see L<perlfaq8/How can I capture STDERR from an external command?>
- open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!";
my $stderr = IO::Handle->new;
my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, '-e', "require q[$lib]");
@@ -54,7 +56,6 @@ foreach my $file (@scripts)
my @flags = $1 ? split(/\s+/, $1) : ();
- open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!";
my $stderr = IO::Handle->new;
my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, @flags, '-c', $file);
@@ -3,71 +3,128 @@
use strict;
use warnings;
-# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.010
+# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.013
use Test::More tests => 1;
use ExtUtils::MakeMaker;
use File::Spec::Functions;
use List::Util qw/max/;
+use version;
+
+# hide optional CPAN::Meta modules from prereq scanner
+# and check if they are available
+my $cpan_meta = "CPAN::Meta";
+my $cpan_meta_req = "CPAN::Meta::Requirements";
+my $HAS_CPAN_META = eval "require $cpan_meta"; ## no critic
+my $HAS_CPAN_META_REQ = eval "require $cpan_meta_req; $cpan_meta_req->VERSION('2.120900')";
+
+# Verify requirements?
+my $DO_VERIFY_PREREQS = 1;
+
+sub _merge_requires {
+ my ($collector, $prereqs) = @_;
+ for my $phase ( qw/configure build test runtime develop/ ) {
+ next unless exists $prereqs->{$phase};
+ if ( my $req = $prereqs->{$phase}{'requires'} ) {
+ my $cmr = CPAN::Meta::Requirements->from_string_hash( $req );
+ $collector->add_requirements( $cmr );
+ }
+ }
+}
+
+my %include = map {; $_ => 1 } qw(
-my @modules = qw(
- CPAN::Meta
- CPAN::Meta::Requirements
- ExtUtils::MakeMaker
- File::Spec
- File::Spec::Functions
- File::Temp
- IO::Handle
- IPC::Open3
- List::Util
- Pod::ParseLink
- Pod::Parser
- Test::Differences
- Test::More
- parent
- perl
- strict
- warnings
);
my %exclude = map {; $_ => 1 } qw(
);
-my ($source) = grep { -f $_ } qw/MYMETA.json MYMETA.yml META.json/;
-$source = "META.yml" unless defined $source;
-
-# replace modules with dynamic results from MYMETA.json if we can
-# (hide CPAN::Meta from prereq scanner)
-my $cpan_meta = "CPAN::Meta";
-my $cpan_meta_req = "CPAN::Meta::Requirements";
+# Add static prereqs to the included modules list
+my $static_prereqs = do { my $x = {
+ 'configure' => {
+ 'requires' => {
+ 'ExtUtils::MakeMaker' => '6.30'
+ }
+ },
+ 'develop' => {
+ 'requires' => {
+ 'Pod::Coverage::TrustPod' => '0',
+ 'Test::CPAN::Changes' => '0.19',
+ 'Test::CPAN::Meta' => '0',
+ 'Test::Kwalitee' => '1.12',
+ 'Test::More' => '0',
+ 'Test::NoTabs' => '0',
+ 'Test::Pod' => '1.41',
+ 'Test::Pod::Coverage' => '1.08'
+ }
+ },
+ 'runtime' => {
+ 'requires' => {
+ 'Pod::Simple' => '3.14',
+ 'Pod::Simple::Methody' => '0',
+ 'parent' => '0',
+ 'perl' => '5.008',
+ 'strict' => '0',
+ 'warnings' => '0'
+ }
+ },
+ 'test' => {
+ 'recommends' => {
+ 'CPAN::Meta' => '0',
+ 'CPAN::Meta::Requirements' => '2.120900'
+ },
+ 'requires' => {
+ 'Exporter' => '0',
+ 'ExtUtils::MakeMaker' => '0',
+ 'File::Spec' => '0',
+ 'File::Spec::Functions' => '0',
+ 'File::Temp' => '0',
+ 'IO::Handle' => '0',
+ 'IPC::Open3' => '0',
+ 'List::Util' => '0',
+ 'Symbol' => '0',
+ 'Test::Differences' => '0',
+ 'Test::More' => '0.88',
+ 'lib' => '0',
+ 'utf8' => '0',
+ 'version' => '0'
+ }
+ }
+ };
+ $x;
+ };
+
+delete $static_prereqs->{develop} if not $ENV{AUTHOR_TESTING};
+$include{$_} = 1 for map { keys %$_ } map { values %$_ } values %$static_prereqs;
+
+# Merge requirements for major phases (if we can)
my $all_requires;
-if ( -f $source && eval "require $cpan_meta" ) { ## no critic
+if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META_REQ ) {
+ $all_requires = $cpan_meta_req->new;
+ _merge_requires($all_requires, $static_prereqs);
+}
+
+
+# Add dynamic prereqs to the included modules list (if we can)
+my ($source) = grep { -f } 'MYMETA.json', 'MYMETA.yml';
+if ( $source && $HAS_CPAN_META ) {
if ( my $meta = eval { CPAN::Meta->load_file($source) } ) {
+ my $dynamic_prereqs = $meta->prereqs;
+ delete $dynamic_prereqs->{develop} if not $ENV{AUTHOR_TESTING};
+ $include{$_} = 1 for map { keys %$_ } map { values %$_ } values %$dynamic_prereqs;
- # Get ALL modules mentioned in META (any phase/type)
- my $prereqs = $meta->prereqs;
- delete $prereqs->{develop} if not $ENV{AUTHOR_TESTING};
- my %uniq = map {$_ => 1} map { keys %$_ } map { values %$_ } values %$prereqs;
- $uniq{$_} = 1 for @modules; # don't lose any static ones
- @modules = sort grep { ! $exclude{$_} } keys %uniq;
-
- # If verifying, merge 'requires' only for major phases
- if ( 1 ) {
- $prereqs = $meta->effective_prereqs; # get the object, not the hash
- if (eval "require $cpan_meta_req; 1") { ## no critic
- $all_requires = $cpan_meta_req->new;
- for my $phase ( qw/configure build test runtime/ ) {
- $all_requires->add_requirements(
- $prereqs->requirements_for($phase, 'requires')
- );
- }
- }
+ if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META_REQ ) {
+ _merge_requires($all_requires, $dynamic_prereqs);
}
}
}
+else {
+ $source = 'static metadata';
+}
+my @modules = sort grep { ! $exclude{$_} } keys %include;
my @reports = [qw/Version Module/];
my @dep_errors;
my $req_hash = defined($all_requires) ? $all_requires->as_string_hash : {};
@@ -83,7 +140,7 @@ for my $mod ( @modules ) {
$ver = "undef" unless defined $ver; # Newer MM should do this anyway
push @reports, [$ver, $mod];
- if ( 1 && $all_requires ) {
+ if ( $DO_VERIFY_PREREQS && $all_requires ) {
my $req = $req_hash->{$mod};
if ( defined $req && length $req ) {
if ( ! defined eval { version->parse($ver) } ) {
@@ -99,7 +156,7 @@ for my $mod ( @modules ) {
else {
push @reports, ["missing", $mod];
- if ( 1 && $all_requires ) {
+ if ( $DO_VERIFY_PREREQS && $all_requires ) {
my $req = $req_hash->{$mod};
if ( defined $req && length $req ) {
push @dep_errors, "$mod is not installed (version '$req' required)";
@@ -127,4 +184,4 @@ if ( @dep_errors ) {
pass;
-# vim: ts=2 sts=2 sw=2 et:
+# vim: ts=4 sts=4 sw=4 et:
@@ -0,0 +1,63 @@
+# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
+use strict;
+use warnings;
+use lib 't/lib';
+use MarkdownTests;
+use File::Spec ();
+
+# Explicitly test using a real file.
+my $_pod_path = File::Spec->catfile(qw(corpus tinypod.txt));
+my $_pod_text = "This is _pod_.";
+
+sub compare {
+ my ($got, $exp, $desc) = @_;
+ chomp $got;
+ eq_or_diff $got, $exp, $desc;
+}
+
+# Dist::Zilla::Plugin::ReadmeAnyFromPod
+SKIP: {
+ eval 'require IO::Scalar'
+ or skip 'IO::Scalar not available for testing.', 1;
+
+ my $pod = "=pod\n\nB<foo>\n";
+
+ my $parser = Pod::Markdown->new();
+
+ my $input_handle = IO::Scalar->new(\$pod);
+
+ $parser->parse_from_filehandle($input_handle);
+ my $content = $parser->as_markdown();
+
+ compare $content, '__foo__',
+ 'parse_from_filehandle( IO::Scalar->new(\$string) )';
+}
+
+# Minilla
+# Module::Build::Pluggable::ReadmeMarkdownFromPod
+# Module::Install::ReadmeMarkdownFromPod
+{
+ my $readme_from = $_pod_path;
+
+ my $parser = Pod::Markdown->new;
+ $parser->parse_from_file($readme_from);
+
+ my $markdown = $parser->as_markdown;
+
+ compare $markdown, $_pod_text,
+ 'parse_from_file( $path )';
+}
+
+{
+ my $pod = $_pod_path;
+
+ open my $pod_fh, '<', $pod or die "Can't read POD '$pod'";
+
+ my $md = Pod::Markdown->new;
+ $md->parse_from_filehandle($pod_fh);
+
+ compare $md->as_markdown, $_pod_text,
+ 'parse_from_filehandle( open(my) )';
+}
+
+done_testing;
@@ -0,0 +1,69 @@
+# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
+use strict;
+use warnings;
+use lib 't/lib';
+use MarkdownTests tests => 1;
+
+# Test a small, easy section of pod just to show when the parser
+# is working. We'll test more of the details in other scripts.
+
+my $parser = Pod::Markdown->new(
+);
+
+$parser->parse_from_filehandle(\*DATA);
+my $markdown = $parser->as_markdown;
+my $expect = <<EOMARKDOWN;
+# POD
+
+One line.
+
+## MORE
+
+One paragraph.
+Another line.
+
+ verbatim `text`
+
+Another paragraph.
+
+- Bullet
+- Again
+
+`ode`
+__old__
+_talic_
+EOMARKDOWN
+
+eq_or_diff $markdown, $expect, 'convert some basic pod into markdown';
+
+__DATA__
+=head1 POD
+
+One line.
+
+=head2 MORE
+
+One paragraph.
+Another line.
+
+ verbatim `text`
+
+Another paragraph.
+
+=over
+
+=item *
+
+Bullet
+
+=item *
+
+Again
+
+=back
+
+C<ode>
+B<old>
+I<talic>
+
+=cut
@@ -1,13 +1,12 @@
# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
+use utf8;
use strict;
use warnings;
-use Test::More;
-use Pod::Markdown;
+use lib 't/lib';
+use MarkdownTests;
my $pod_prefix = Pod::Markdown->new->perldoc_url_prefix;
-my $parser = Pod::Markdown->new;
-
my @tests = (
[I => q<italic>, q{_italic_}],
[B => q<bold>, q{__bold__}],
@@ -16,41 +15,43 @@ my @tests = (
# links tested extensively in t/links.t
[L => q<link>, "[link](${pod_prefix}link)"],
- [L => q<star*>, "[star*](${pod_prefix}star*)"],
+ [L => q<star*>, "[star\\*](${pod_prefix}star*)"],
+ # Pod::Simple handles the E<> entirely (Pod::Markdown never sees them).
[E => q<lt>, q{<}],
[E => q<gt>, q{>}],
[E => q<verbar>, q{|}],
[E => q<sol>, q{/}],
- [E => q<eacute>, q{é}],
- [E => q<0x201E>, q{„}, 'E hex'],
- [E => q<075>, q{=}, 'E octal'],
- [E => q<181>, q{µ}, 'E decimal'],
+ [E => q<eacute>, q{é}],
+ [E => q<0x201E>, q{„}, 'E hex'],
+ [E => q<075>, q{=}, 'E octal'],
+ [E => q<181>, q{µ}, 'E decimal'],
# legacy charnames specifically mentioned by perlpodspec
- [E => q<lchevron>, q{«}],
- [E => q<rchevron>, q{»}],
- [E => q<zchevron>, q{&zchevron;}],
- [E => q<rchevrony>, q{&rchevrony;}],
+ [E => q<lchevron>, q{«}],
+ [E => q<rchevron>, q{»}],
[F => q<file.ext>, q{`file.ext`}],
[F => q<file_path.ext>, q{`file_path.ext`}],
[S => q<$x ? $y : $z>, q{$x ? $y : $z}],
[X => q<index>, q{}],
- [Z => q<null>, q{}],
+ [Z => q<>, q{}],
- [Q => q<unknown>, q{Q<unknown>}, 'uknown code (Q<>)' ],
+ #[Q => q<unknown>, q{Q<unknown>}, 'uknown code (Q<>)' ],
);
-plan tests => scalar @tests * 2;
+plan tests => scalar @tests;
foreach my $test ( @tests ){
my ($code, $text, $exp, $desc) = @$test;
$desc ||= "$code<$text>";
- # explicitly test interior_sequence (which is what we've defined)
- is $parser->interior_sequence($code => $text), $exp, $desc . ' (interior_sequence)';
- # also test parsing it as pod
- is $parser->interpolate("$code<<< $text >>>"), $exp, $desc . ' (interpolate)';
+ my $parser = Pod::Markdown->new;
+ $parser->output_string(\(my $got));
+ # Prefix line to avoid escaping beginning-of-line characters (like `>`).
+ my $prefix = 'Code:';
+ $parser->parse_string_document("=pod\n\n$prefix $code<<< $text >>>");
+ chomp($got);
+ is $got, "$prefix $exp", $desc;
}
@@ -0,0 +1,160 @@
+# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
+use strict;
+use warnings;
+use lib 't/lib';
+use MarkdownTests;
+
+convert_ok(
+ <<'POD',
+Some I<pod>
+
+=for html <b>html</b>
+
+=for markdown **mkdn**
+
+=for something_else `ignored`
+POD
+ <<'MKDN',
+Some _pod_
+MKDN
+ 'disable html and markdown targets',
+ init => sub { $_[0]->unaccept_targets(qw(markdown html)) },
+);
+
+
+convert_ok(
+ <<'POD',
+Some I<pod>
+
+=for other no
+
+=for html foo
+
+=for :html bar
+
+=for :other nope
+
+=for markdown baz
+
+=for :markdown qux
+POD
+ <<'MKDN',
+Some _pod_
+
+<div>
+ foo
+</div>
+
+bar
+
+baz
+
+qux
+MKDN
+ 'by default accept html and markdown targets',
+);
+
+
+convert_ok(
+ <<'POD',
+Some I<pod>
+
+=for markdown **BOLD**! B<not pod>
+POD
+ <<'MKDN',
+Some _pod_
+
+**BOLD**! B<not pod>
+MKDN
+ '=for markdown passed through',
+);
+
+
+convert_ok(
+ <<'POD',
+Some I<pod>
+
+=begin markdown
+
+**BOLD**! B<not pod>
+
+=end markdown
+POD
+ <<'MKDN',
+Some _pod_
+
+**BOLD**! B<not pod>
+MKDN
+ '=begin/end markdown passed through',
+);
+
+
+convert_ok(
+ <<'POD',
+Some I<pod>
+
+=for :markdown **BOLD**! B<real bold>
+
+=for :other `ignored`
+POD
+ <<'MKDN',
+Some _pod_
+
+\*\*BOLD\*\*! __real bold__
+MKDN
+ '=for :markdown gets processed and escaped',
+);
+
+
+convert_ok(
+ <<'POD',
+Some I<pod>
+
+=begin :markdown
+
+**BOLD**! B<real bold>
+
+=end :markdown
+POD
+ <<'MKDN',
+Some _pod_
+
+\*\*BOLD\*\*! __real bold__
+MKDN
+ '=begin/end :markdown gets processed and escaped',
+);
+
+
+convert_ok(
+ <<'POD',
+Some I<pod>
+
+=for html <i>not</i> I<pod> *text*
+POD
+ <<'MKDN',
+Some _pod_
+
+<div>
+ <i>not</i> I<pod> *text*
+</div>
+MKDN
+ '=for html passes through',
+);
+
+
+convert_ok(
+ <<'POD',
+Some I<pod>
+
+=for :html <i>yes</i> I<pod> *text*
+POD
+ <<'MKDN',
+Some _pod_
+
+<i>yes</i> _pod_ \*text\*
+MKDN
+ '=for :html gets processed and escaped',
+);
+
+
+done_testing;
@@ -0,0 +1,89 @@
+use strict;
+use warnings;
+
+package # no_index
+ MarkdownTests;
+
+use Test::More 0.88; # done_testing
+use Test::Differences;
+use Pod::Markdown ();
+
+use Exporter ();
+our @ISA = qw(Exporter);
+our @EXPORT = (
+ qw(
+ convert_ok
+ io_string
+ eq_or_diff
+ ),
+ @Test::More::EXPORT
+);
+
+sub import {
+ my $class = shift;
+ Test::More::plan(@_) if @_;
+ @_ = ($class);
+ strict->import;
+ warnings->import;
+ goto &Exporter::import;
+}
+
+sub diag_xml {
+ diag_with('Pod::Simple::DumpAsXML', @_);
+}
+
+sub diag_text {
+ diag_with('Pod::Simple::DumpAsText', @_);
+}
+
+sub diag_with {
+ my ($class, $pod) = @_;
+ $class =~ /[^a-zA-Z0-9:]/ and die "Invalid class name '$class'";
+ eval "require $class" or die $@;
+ my $parser = $class->new;
+ $parser->output_string(\(my $got));
+ $parser->parse_string_document("=pod\n\n$pod\n");
+ diag $got;
+}
+
+sub convert_ok {
+ my ($pod, $exp, $desc, %opts) = @_;
+ my $parser = Pod::Markdown->new;
+
+ diag_xml($pod) if $opts{diag_xml};
+ diag_text($pod) if $opts{diag_text};
+
+ $opts{init}->($parser) if $opts{init};
+
+ $parser->output_string(\(my $got));
+ $parser->parse_string_document("=pod\n\n$pod\n\n=cut\n");
+
+ chomp for ($got, $exp);
+
+ eq_or_diff($got, $exp, $desc);
+}
+
+{ package # no_index
+ MarkdownTests::IOString;
+ use Symbol ();
+ sub new {
+ my $class = ref($_[0]) || $_[0];
+ my $s = $_[1];
+ my $self = Symbol::gensym;
+ tie *$self, $class, $self;
+ *$self->{lines} = [map { "$_\n" } split /\n/, $s ];
+ $self;
+ }
+ sub READLINE { shift @{ *{$_[0]}->{lines} } }
+ sub TIEHANDLE {
+ my ($class, $s) = @_;
+ bless $s, $class;
+ }
+ { no warnings 'once'; *getline = \&READLINE; }
+}
+
+sub io_string {
+ MarkdownTests::IOString->new(@_);
+}
+
+1;
@@ -1,33 +1,45 @@
# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
use strict;
use warnings;
-use Test::More;
-use Pod::Markdown;
+use lib 't/lib';
+use MarkdownTests;
# Test url aliases.
local $Pod::Markdown::URL_PREFIXES{manny} = 'http://manny.local/page/';
+my %defaults = (
+ # We'll test the various formats later
+ # so for the first set just pass them through.
+ perldoc_fragment_format => sub { $_ },
+ markdown_fragment_format => sub { $_ },
+);
+
my ($pod_prefix, $man_prefix) =
- map { ($_->perldoc_url_prefix, $_->man_url_prefix) } Pod::Markdown->new;
+ map { ($_->perldoc_url_prefix, $_->man_url_prefix) }
+ Pod::Markdown->new;
-my $parser = Pod::Markdown->new;
+my $alt_text_for_urls = 1; # Assume we have a sufficient Pod::Simple version.
-my $alt_text_for_urls = (Pod::ParseLink->VERSION >= 1.10);
+my ($space, $quot) =
+ map { sprintf '&#x%x;', ord }
+ q[ ], q["];
my @tests = (
# in order of L<> examples in perlpod:
['name', q<name>, qq^[name](${pod_prefix}name)^],
['other module', q<Other::Pod>, qq^[Other::Pod](${pod_prefix}Other::Pod)^],
+['other module, empty text', q<|Other::Pod>, qq^[Other::Pod](${pod_prefix}Other::Pod)^],
+['other module/sec, empty text', q<|Other::Pod/sec>, qq^["sec" in Other::Pod](${pod_prefix}Other::Pod#sec)^],
['section in other module', q<Other::Pod/sec>, qq^["sec" in Other::Pod](${pod_prefix}Other::Pod#sec)^],
-['quoted section in other doc', q<perlsyn/"For Loops">, qq^["For Loops" in perlsyn](${pod_prefix}perlsyn#For Loops)^],
+['quoted section in other doc', q<perlsyn/"For Loops">, qq^["For Loops" in perlsyn](${pod_prefix}perlsyn#For${space}Loops)^],
['section in this doc', q</sec>, qq^["sec"](#sec)^],
['quoted section in this doc', q</"sec">, qq^["sec"](#sec)^],
+['/sec, empty text', q<|/sec>, qq^["sec"](#sec)^],
['other module, alternate text', q<other-pod|Other::Pod>, qq^[other-pod](${pod_prefix}Other::Pod)^],
-['other module, empty text', q<|Other::Pod>, qq^[Other::Pod](${pod_prefix}Other::Pod)^],
['sec in other mod, alt text', q<x-sec|Other::Pod/sec>, qq^[x-sec](${pod_prefix}Other::Pod#sec)^],
['"sec" in other mod, alt text', q<x-sec|Other::Pod/"sec">, qq^[x-sec](${pod_prefix}Other::Pod#sec)^],
@@ -41,14 +53,14 @@ my @tests = (
['http, alt text (perl 5.12)', q<web|http://website>, qq^[web](http://website)^],
['embedded codes', q^the docs on C<$.>|perlvar/"$."^, qq^[the docs on `\$.`](${pod_prefix}perlvar#\$.)^],
-["don't expand nested L's", q^perlpodspec/"About LE<lt>...E<gt> Codes"^, qq^["About L<...> Codes" in perlpodspec](${pod_prefix}perlpodspec#About L<...> Codes)^],
+["don't expand nested L's", q^perlpodspec/"About LE<lt>...E<gt> Codes"^, qq^["About L<...> Codes" in perlpodspec](${pod_prefix}perlpodspec#About${space}L<...>${space}Codes)^],
# perlpodspec examples:
['name', q<Foo::Bar>, qq^[Foo::Bar](${pod_prefix}Foo::Bar)^],
['alt|pod/sec', q<Perlport's section on NL's|perlport/Newlines>, qq^[Perlport's section on NL's](${pod_prefix}perlport#Newlines)^],
['pod/sec', q<perlport/Newlines>, qq^["Newlines" in perlport](${pod_prefix}perlport#Newlines)^],
['man/sec', q<crontab(5)/"DESCRIPTION">, qq^["DESCRIPTION" in crontab(5)](${man_prefix}5/crontab)^],
-['/section name', q</Object Attributes>, qq^["Object Attributes"](#Object Attributes)^],
+['/section name', q</Object Attributes>, qq^["Object Attributes"](#Object${space}Attributes)^],
['http', q<http://www.perl.org/>, qq^[http://www.perl.org/](http://www.perl.org/)^],
['text|http', q<Perl.org|http://www.perl.org/>, qq^[Perl.org](http://www.perl.org/)^],
@@ -57,24 +69,27 @@ my @tests = (
['man(5)', q<crontab(5)>, qq^[crontab(5)](${man_prefix}5/crontab)^],
# how should these be handled? these are unlikely/contrived occurrences and are mostly here for test coverage
-['man()', q<crontab()>, qq^[crontab()](${man_prefix}1/crontab)^],
-['man(X)', q<crontab(X)>, qq^[crontab(X)](${man_prefix}X/crontab)^],
-['man(2)-page', q<crontab(2)-page>, qq^[crontab(2)-page](${man_prefix}2/crontab)^],
-['(X)man', q<(X)foo>, qq^[(X)foo](${man_prefix}1/(X)foo)^],
-['()', q<()>, qq^[()](${man_prefix}1/())^],
+#['man()', q<crontab()>, qq^[crontab()](${man_prefix}1/crontab)^],
+#['man(X)', q<crontab(X)>, qq^[crontab(X)](${man_prefix}X/crontab)^],
+#['man(2)-page', q<crontab(2)-page>, qq^[crontab(2)-page](${man_prefix}2/crontab)^],
+#['(X)man', q<(X)foo>, qq^[(X)foo](${man_prefix}1/(X)foo)^],
+#['()', q<()>, qq^[()](${man_prefix}1/())^],
# varies according to pod-to-html formatter:
-['other/section name', q<Other/Section Name>, qq^["Section Name" in Other](${pod_prefix}Other#Section Name)^],
+['other/section name', q<Other/Section Name>, qq^["Section Name" in Other](${pod_prefix}Other#Section${space}Name)^],
-# Don't insert backslashes (to escape markdown).
-['_underscore_', q<_underscore_>, qq^[_underscore_](${pod_prefix}_underscore_)^],
-['*asterisk*', q<*asterisk*>, qq^[*asterisk*](${pod_prefix}*asterisk*)^],
+# Insert backslashes (to escape markdown).
+['_underscore_', q<_underscore_>, qq^[\\_underscore\\_](${pod_prefix}_underscore_)^],
+['*asterisk*', q<*asterisk*>, qq^[\\*asterisk\\*](${pod_prefix}*asterisk*)^],
+['section with quotes', q<whiskey|/Say "Cheese">, qq^[whiskey](#Say${space}${quot}Cheese${quot})^],
# is there something better to do?
-['no url: empty', q<>, qq^L<>^],
-['no url: pipe', q<|>, qq^L<|>^],
-['no url: slash', q</>, qq^L</>^],
-['no url: quotes', q<"">, qq^L<"">^],
+# These seem so useless I don't think I care what they do.
+#['no url: empty', q<>, qq^L<>^], # FIXME: Error
+# These work on 3.28 but not on 3.16:
+#['no url: pipe', q<|>, qq^L<|>^],
+#['no url: slash', q</>, qq^L</>^],
+#['no url: quotes', q<"">, qq^L<"">^],
['empty text: |url', q<|http://foo>, qq^[http://foo](http://foo)^],
['false text: 0|url', q<0|http://foo>, qq^[0](http://foo)^],
@@ -91,12 +106,98 @@ my @tests = (
);
-plan tests => scalar @tests * 2;
+# Most of these examples were internal links
+# so we add the perldoc name to make testing easier.
+
+test_fragments(
+ q^perlvar/$.^,
+ {
+ # It's unfortunate that Pod::Simple::XHTML can't do links to just symbols:
+ # https://rt.cpan.org/Ticket/Display.html?id=90207
+ metacpan => q^["$." in perlvar](:perlvar#pod)^,
+ sco => q^["$." in perlvar](:perlvar#$.)^,
+ },
+ 'section with only symbols',
+);
+
+test_fragments(
+ q^perlop/"IE<sol>O Operators"^,
+ {
+ metacpan => q^["I/O Operators" in perlop](:perlop#I-O-Operators)^,
+ sco => q^["I/O Operators" in perlop](:perlop#I/O_Operators)^,
+ },
+ 'perlvar.pod: external section with symbols',
+);
+
+test_fragments(
+ q^perlpodspec/"About LE<lt>...E<gt> Codes"^,
+ {
+ metacpan => q^["About L<...> Codes" in perlpodspec](:perlpodspec#About-L...-Codes)^,
+ sco => q^["About L<...> Codes" in perlpodspec](:perlpodspec#About_L<...>_Codes)^,
+ markdown => q^["About L<...> Codes" in perlpodspec](:perlpodspec#about-l-codes)^,
+ },
+ 'section with pod escapes',
+);
+
+test_fragments(
+ q^perlpodspec/About Data Paragraphs and "=beginE<sol>=end" Regions^,
+ {
+ metacpan => q^["About Data Paragraphs and "=begin/=end" Regions" in perlpodspec](:perlpodspec#About-Data-Paragraphs-and-begin-end-Regions)^,
+ sco => qq^["About Data Paragraphs and "=begin/=end" Regions" in perlpodspec](:perlpodspec#About_Data_Paragraphs_and_${quot}=begin/=end${quot}_Regions)^,
+ },
+ 'section with pod commands',
+);
+
+test_fragments(
+ q^detach|Catalyst/"$c->detach( $action [, \@arguments ] )"^,
+ {
+ metacpan => q^[detach](:Catalyst#c-detach-action-arguments)^,
+ sco => q^[detach](:Catalyst#$c->detach\(_$action_[,_\\\\@arguments_]_\))^,
+ },
+ 'section with sigils and syntax',
+);
+
+test_fragments(
+ q^perlpod/"Formatting Codes"^,
+ {
+ metacpan => q^["Formatting Codes" in perlpod](:perlpod#Formatting-Codes)^,
+ sco => q^["Formatting Codes" in perlpod](:perlpod#Formatting_Codes)^,
+ },
+ 'quoted section in other doc',
+);
+
+
+test_fragments(
+ q</Some, OTHER Section!>,
+ {
+ markdown => q^["Some, OTHER Section!"](#some-other-section)^,
+ },
+ 'complicated section',
+);
+
+test_fragments(
+ q</"If you have a setup working, share your 'definition' with me. That would be fun!">,
+ {
+ markdown => qq^["If you have a setup working, share your 'definition' with me. That would be fun!"](#if-you-have-a-setup-working-share-your-definition-with-me-that-would-be-fun)^,
+ },
+ 'extra long real life example complicated section',
+);
+
+test_fragments(
+ q<A [charclass] is \\* bad|page/section with (Parens) and \\Escapes *star*>,
+ {
+ metacpan => q^[A \\[charclass\\] is \\\\\\* bad](:page#section-with-Parens-and-Escapes-star)^,
+ sco => qq^[A \\[charclass\\] is \\\\\\* bad](:page#section_with_\\(Parens\\)_and_\\\\Escapes_*star*)^,
+ },
+ 'extra long real life example complicated section',
+);
+
foreach my $test ( @tests ){
my ($desc, $pod, $mkdn, %opts) = @$test;
+ %opts = %defaults unless %opts;
test_link(
- (%opts ? Pod::Markdown->new(%opts) : $parser),
+ Pod::Markdown->new(%opts),
$pod, $mkdn, $desc,
);
}
@@ -108,9 +209,30 @@ sub test_link {
skip 'alt text with schemes/absolute URLs not supported until perl 5.12 / Pod::ParseLink 1.10', 1
if !$alt_text_for_urls && $pod =~ m/\|\w+:[^:\s]\S*\z/; # /alt text \| url (not perl module)/ (regexp from perlpodspec)
- # interior_sequence is what we specifically want to test
- is $parser->interior_sequence(L => $pod), $mkdn, $desc . ' (interior_sequence)';
- # but interpolate() tests the pod parsing as a whole (which can expose recursion bugs, etc)
- is $parser->interpolate("L<<< $pod >>>"), $mkdn, $desc . ' (interpolate)';
+ $parser->output_string(\(my $got));
+ $parser->parse_string_document("=pod\n\nL<<< $pod >>>");
+ chomp($got);
+
+ is $got, $mkdn, $desc . ' (interpolate)';
}
}
+
+sub test_fragments {
+ my ($pod, $tests, $desc) = @_;
+ foreach my $format ( sort keys %$tests ){
+ test_link(
+ # Only some combinations of these will normally make sense
+ # but it makes the function reusable.
+ Pod::Markdown->new(
+ perldoc_fragment_format => $format,
+ perldoc_url_prefix => ':', # easier
+ markdown_fragment_format => $format,
+ ),
+ $pod,
+ $tests->{$format},
+ "$desc: $format",
+ );
+ }
+}
+
+done_testing;
@@ -1,17 +1,17 @@
# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
use strict;
use warnings;
-use Test::More tests => 1;
-use Test::Differences;
-use Pod::Markdown;
+use lib 't/lib';
+use MarkdownTests tests => 1;
-my $pod_prefix = Pod::Markdown->new->perldoc_url_prefix;
-
-my $parser = Pod::Markdown->new;
+my $parser = Pod::Markdown->new(
+ perldoc_url_prefix => 'pod:',
+);
$parser->parse_from_filehandle(\*DATA);
my $markdown = $parser->as_markdown;
-my $expect = <<EOMARKDOWN;
+# TODO: Verify this list behavior in html and perlpod(spec).
+my $expect = <<'EOMARKDOWN';
# Lists
## Unordered
@@ -28,9 +28,9 @@ my $expect = <<EOMARKDOWN;
- list
- test
-- and _Italics_, __Bold__, `Code`, and [Links](${pod_prefix}Links) should work in list item
+- and _Italics_, __Bold__, `Code`, and [Links](pod:Links) should work in list item
- and _in_ __paragraph__ `after` [item](${pod_prefix}item)
+ and _in_ __paragraph__ `after` [item](pod:item)
- verbatim paragraphs
@@ -43,6 +43,7 @@ __Note:__ Markdown does not support definition lists (word => text), just bullet
- Head1
Paragraph should be indented.
+ \* And escaped.
- Head2
@@ -59,6 +60,12 @@ __Note:__ Markdown does not support definition lists (word => text), just bullet
- Again, this is a list head.
- Finally, this is also a list head.
+And
+
+- A list item
+\\with a line that starts with a markdown char.
+- item 2
+
## Ordered
1. B
@@ -126,6 +133,7 @@ B<Note:> Markdown does not support definition lists (word => text), just bullets
=item Head1
Paragraph should be indented.
+* And escaped.
=over 4
@@ -167,6 +175,21 @@ Finally, this is also a list head.
=back
+And
+
+=over
+
+=item *
+
+A list item
+\with a line that starts with a markdown char.
+
+=item *
+
+item 2
+
+=back
+
=head2 Ordered
=over
@@ -1,15 +1,8 @@
# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
use strict;
use warnings;
-use Test::More;
-use Test::Differences;
-use Pod::Markdown;
-
-{ package # no_index
- IOString;
- sub new { bless [map { "$_\n" } split /\n/, $_[1] ], $_[0] }
- sub getline { shift @{ $_[0] } }
-}
+use lib 't/lib';
+use MarkdownTests;
my @tests;
@@ -80,14 +73,39 @@ MKDN
push @tests, [ 'name, author', $pod, $mkdn ];
}
-plan tests => scalar @tests;
+plan tests => scalar @tests * 3;
foreach my $test ( @tests ) {
- my ($desc, $pod, $exp) = @$test;
+ as_markdown_with_meta(@$test);
+ output_string_include_meta_tags(@$test);
+ both(@$test);
+}
+
+sub as_markdown_with_meta {
+ my ($desc, $pod, $exp, $use_attr) = @_;
- my $parser = Pod::Markdown->new;
- $parser->parse_from_filehandle( IOString->new($pod) );
+ my $parser = Pod::Markdown->new(
+ include_meta_tags => $use_attr,
+ );
+ $parser->parse_from_filehandle( io_string($pod) );
my $markdown = $parser->as_markdown(with_meta => ($desc ne 'none'));
- eq_or_diff $markdown, $exp, "meta tags: $desc";
+ my $prefix = $use_attr ? 'both' : 'with_meta';
+ eq_or_diff $markdown, $exp, "${prefix}: $desc";
+}
+
+sub output_string_include_meta_tags {
+ my ($desc, $pod, $exp) = @_;
+
+ my $parser = Pod::Markdown->new(
+ include_meta_tags => ($desc ne 'none'),
+ );
+ $parser->output_string(\(my $markdown));
+ $parser->parse_string_document($pod);
+
+ eq_or_diff $markdown, $exp, "include_meta_tags: $desc";
+}
+
+sub both {
+ as_markdown_with_meta(@_, $_[0] ne 'none');
}
@@ -1,27 +1,31 @@
# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
use strict;
use warnings;
-use Test::More tests => 1;
-use Test::Differences;
-use Pod::Markdown;
+use lib 't/lib';
+use MarkdownTests tests => 1;
-my $pod_prefix = Pod::Markdown->new->perldoc_url_prefix;
+my $parser = Pod::Markdown->new(
+ perldoc_url_prefix => 'pod://',
+ # Just return the raw fragment so we know that it isn't unexpectedly mangled.
+ perldoc_fragment_format => sub { $_ },
+ markdown_fragment_format => sub { $_ },
+);
+my $pod_prefix = $parser->perldoc_url_prefix;
-my $parser = Pod::Markdown->new;
$parser->parse_from_filehandle(\*DATA);
my $markdown = $parser->as_markdown;
-my $expect = <<EOMARKDOWN;
+my $expect = <<'EOMARKDOWN';
# POD
pod2markdown - Convert POD text to Markdown
# SYNOPSIS
- \$ pod2markdown < POD_File > Markdown_File
+ $ pod2markdown < POD_File > Markdown_File
# DESCRIPTION
-This program uses [Pod::Markdown](${pod_prefix}Pod::Markdown) to convert POD into Markdown sources. It is
+This program uses [Pod::Markdown](pod://Pod::Markdown) to convert POD into Markdown sources. It is
a filter that expects POD on STDIN and outputs Markdown on STDOUT.
FTP is at [ftp://ftp.univie.ac.at/foo/bar](ftp://ftp.univie.ac.at/foo/bar).
@@ -30,36 +34,43 @@ HTTP is at [http://univie.ac.at/baz/](http://univie.ac.at/baz/).
# SEE ALSO
-This program is strongly based on `pod2mdwn` from [Module::Build::IkiWiki](${pod_prefix}Module::Build::IkiWiki).
+This program is strongly based on `pod2mdwn` from [Module::Build::IkiWiki](pod://Module::Build::IkiWiki).
And see ["foobar"](#foobar) as well.
+> Quote some poetry
+> or say something special.
+
# MORE TESTS
-## _Italics_, __Bold__, `Code`, and [Links](${pod_prefix}Links) should work in headers
+## _Italics_, __Bold__, `Code`, and [Links](pod://Links) should work in headers
-_Italics_, __Bold__, `Code`, and [Links](${pod_prefix}Links) should work in body text.
+_Italics_, __Bold__, `Code`, and [Links](pod://Links) should work in body text.
__Nested `codes`__ work, too
-## \\_Other\\_ \\*Characters\\* \\[Should\\](Be) \\`Escaped\\` in headers
+## \_Other\_ \*Characters\* \[Should\](Be) \`Escaped\` in headers
Inline `code _need not_ be escaped`.
-Inline [link_should_not_be_escaped](${pod_prefix}link_should_not_be_escaped).
+Inline [link \*should\* \\\_ be\_escaped](#or\\things\(can\)go\\*wrong).
-Inline `filename_should_not_be_escaped`.
+Inline `filename_should_not_be_escaped` because it is a code span.
### Heading `code _need not_ be escaped, either`.
-__Nested `c*des` \\_should\\_ be escaped__ (but not code).
+__Nested `c*des` \_should\_ be escaped__ (but not code).
non-breaking space: foo bar.
-non-breaking code: `\$x ? \$y : \$z` foo `bar` baz
+non-breaking code: `$x ? $y : $z` foo `bar` baz
verbatim para B<with> C<< E<verbar> >> codes
+A `` code span with `backticks` inside ``.
+
+A ```` code span with triple ``` inside ````.
+
- This
- is
- a
@@ -72,13 +83,13 @@ non-breaking code: `\$x ? \$y : \$z` foo `bar` baz
- list
- test
-- and _Italics_, __Bold__, `Code`, and [Links](${pod_prefix}Links) should work in list item
+- and _Italics_, __Bold__, `Code`, and [Links](pod://Links) should work in list item
# Links
-[Formatting `C`odes](${pod_prefix}Links#L<...>)
-EOMARKDOWN
-$expect .= <<'EOMARKDOWN';
+[Formatting `C`odes](pod://Links#L<...>)
+
+[back \`tick](pod://inside#a link)
# \*Special\* characters
@@ -96,7 +107,14 @@ lists:
\- b
\# fake headings
-\#\#\# fake headings \#\#\#
+
+\### fake headings ###
+
+Setext fake
+===========
+
+Another fake
+\------------
\> Quote
\> blocks
@@ -166,6 +184,13 @@ This program is strongly based on C<pod2mdwn> from L<Module::Build::IkiWiki>.
And see L</foobar> as well.
+=over
+
+Quote some poetry
+or say something special.
+
+=back
+
=head1 MORE TESTS
=head2 I<Italics>, B<Bold>, C<Code>, and L<Links> should work in headers
@@ -178,9 +203,9 @@ B<< Nested C<codes> >> work, too
Inline C<< code _need not_ be escaped >>.
-Inline L<< link_should_not_be_escaped >>.
+Inline L<< link *should* \_ be_escaped|/or\things(can)go\*wrong >>.
-Inline F<< filename_should_not_be_escaped >>.
+Inline F<< filename_should_not_be_escaped >> because it is a code span.
=head3 Heading C<< code _need not_ be escaped, either >>.
@@ -192,6 +217,10 @@ non-breaking code: S<C<$x ? $y : $z>> S<foo C<bar> baz>
verbatim para B<with> C<< E<verbar> >> codes
+A C<< code span with `backticks` inside >>.
+
+A C<< code span with triple ``` inside >>.
+
=over 4
=item *
@@ -224,6 +253,8 @@ list
L<<< FormattZ<>ing C<C>odes|Links/"LE<lt>...E<gt>" >>>
+L<<< back `tick|inside/"a link" >>>
+
=head1 *Special* characters
foo_bar is the result of 4 * 4
@@ -240,8 +271,15 @@ lists:
- b
# fake headings
+
### fake headings ###
+Setext fake
+===========
+
+Another fake
+------------
+
> Quote
> blocks
> 1. with
@@ -0,0 +1,146 @@
+# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
+use strict;
+use warnings;
+use lib 't/lib';
+use MarkdownTests;
+
+# TODO: Test everything beneath a numbered list and inside a blockquote.
+
+convert_ok(
+ <<'POD',
+=over
+
+=item 1.
+
+lizard
+
+=item 2.
+
+bird
+
+=over
+
+=item 1.
+
+duck
+
+=item 2.
+
+penguin
+
+=item 3.
+
+turkey
+
+gobble
+gobble.
+
+=item 4.
+
+eagle
+
+=back
+
+=item 3.
+
+bear
+
+=over
+
+=item 1.
+
+grizzly
+
+=item 2.
+
+polar
+
+=over
+
+=item 1.
+
+angry
+
+=item 2.
+
+sleepy
+
+=back
+
+=back
+
+=back
+POD
+ <<'MKDN',
+1. lizard
+2. bird
+ 1. duck
+ 2. penguin
+ 3. turkey
+
+ gobble
+ gobble.
+
+ 4. eagle
+3. bear
+ 1. grizzly
+ 2. polar
+ 1. angry
+ 2. sleepy
+MKDN
+ 'indent content of numbered list items',
+);
+
+convert_ok(
+ # NOTE: Pod::Simple considers a heading inside over/back an error.
+ <<'POD',
+=over
+
+Quote:
+
+=over
+
+line 1
+line 2
+
+=over
+
+=item *
+
+a
+
+=over
+
+=item *
+
+b
+
+para
+
+ verbatim
+
+=back
+
+=back
+
+=back
+
+=back
+POD
+ <<'MKDN',
+> Quote:
+>
+> > line 1
+> > line 2
+> >
+> > - a
+> > - b
+> >
+> > para
+> >
+> > verbatim
+MKDN
+ 'test nesting inside blockquotes'
+);
+
+done_testing;
@@ -0,0 +1,62 @@
+# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
+use strict;
+use warnings;
+use lib 't/lib';
+use MarkdownTests;
+
+sub test_args {
+ my $desc = pop;
+ my $args = shift || {};
+ my %exp = (
+ man_url_prefix => $Pod::Markdown::URL_PREFIXES{man},
+ perldoc_url_prefix => $Pod::Markdown::URL_PREFIXES{metacpan},
+ perldoc_fragment_format => 'metacpan',
+ markdown_fragment_format => 'markdown',
+ @_ ? %{ $_[0] } : ()
+ );
+ my $parser = Pod::Markdown->new(%$args);
+
+ foreach my $attr ( sort keys %exp ){
+ is $parser->$attr, $exp{$attr}, "$desc: $attr";
+ }
+}
+
+test_args 'Default attributes';
+
+foreach my $site ( qw( metacpan sco ) ){
+ test_args
+ { perldoc_url_prefix => $site },
+ {
+ perldoc_url_prefix => $Pod::Markdown::URL_PREFIXES{$site},
+ perldoc_fragment_format => $site,
+ },
+ "Set perldoc_url_prefix to $site; get matching fragment format";
+}
+
+foreach my $format ( map { 'pod_simple_' . $_ } qw( xhtml html ) ){
+ test_args
+ { perldoc_fragment_format => $format },
+ { perldoc_fragment_format => $format },
+ "Explicit format $format";
+}
+
+foreach my $fragtype ( map { $_ . '_fragment_format' } qw( perldoc markdown ) ){
+ my $sub = sub { 'blah' };
+ test_args
+ { $fragtype => $sub },
+ { $fragtype => $sub },
+ "Pass a code ref for $fragtype";
+}
+
+test_args
+ {
+ markdown_fragment_format => 'pod_simple_html',
+ perldoc_fragment_format => 'markdown',
+ },
+ {
+ markdown_fragment_format => 'pod_simple_html',
+ perldoc_fragment_format => 'markdown',
+ },
+ 'Values are interchangeable';
+
+done_testing;
@@ -1,9 +1,8 @@
# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
use strict;
use warnings;
-use Test::More;
-use Test::Differences;
-use Pod::Markdown;
+use lib 't/lib';
+use MarkdownTests;
use File::Temp qw{ tempfile }; # core
use File::Spec::Functions qw( catfile ); # core
@@ -1,9 +1,8 @@
# vim: set ts=2 sts=2 sw=2 expandtab smarttab:
use strict;
use warnings;
-use Test::More tests => 1;
-use Test::Differences;
-use Pod::Markdown;
+use lib 't/lib';
+use MarkdownTests tests => 1;
my $parser = Pod::Markdown->new;
$parser->parse_from_filehandle(\*DATA);
@@ -16,8 +15,8 @@ my $expect = <<'EOMARKDOWN';
# TABS
- These tabs
- can be left alone
+ These tabs
+ will be expanded.
# 3 SPACES
@@ -34,7 +33,7 @@ Mixed paragraphs should all get the same indentation added
to preserve the formatting:
4 spaces (+ 2 = 6)
- a tab
+ a tab
3 spaces (+ 2 = 5)
2 spaces (+ 2 = 4) (the minimum)
@@ -78,7 +77,7 @@ __DATA__
=head1 TABS
These tabs
- can be left alone
+ will be expanded.
=head1 3 SPACES
@@ -2,7 +2,7 @@ use strict;
use warnings;
use Test::More;
-# generated by Dist::Zilla::Plugin::Test::PodSpelling 2.006001
+# generated by Dist::Zilla::Plugin::Test::PodSpelling 2.006002
use Test::Spelling 0.12;
use Pod::Wordlist;
@@ -2,7 +2,7 @@ use strict;
use warnings;
use Test::More;
-# generated by Dist::Zilla::Plugin::Test::EOL 0.08
+# generated by Dist::Zilla::Plugin::Test::EOL 0.10
use Test::EOL;
all_perl_files_ok({ trailing_whitespace => 0 });
@@ -4,7 +4,7 @@ use Test::More tests => 2;
note 'Checking Changes';
my $changes_file = 'Changes';
-my $newver = '1.401';
+my $newver = '2.000';
my $trial_token = '-TRIAL';
SKIP: {
@@ -1,4 +1,5 @@
#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::MetaTests.
use Test::More;
@@ -1,7 +1,7 @@
use strict;
use warnings;
-# this test was generated with Dist::Zilla::Plugin::NoTabsTests 0.05
+# this test was generated with Dist::Zilla::Plugin::NoTabsTests 0.06
use Test::More 0.88;
use Test::NoTabs;
@@ -1,4 +1,5 @@
#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::PodCoverageTests.
use Test::More;
@@ -1,20 +0,0 @@
-#!perl
-
-use strict;
-use warnings;
-use Test::More;
-
-foreach my $env_skip ( qw(
- SKIP_POD_LINKCHECK
-) ){
- plan skip_all => "\$ENV{$env_skip} is set, skipping"
- if $ENV{$env_skip};
-}
-
-eval "use Test::Pod::LinkCheck";
-if ( $@ ) {
- plan skip_all => 'Test::Pod::LinkCheck required for testing POD';
-}
-else {
- Test::Pod::LinkCheck->new->all_pod_ok;
-}
@@ -1,4 +1,5 @@
#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests.
use Test::More;
eval "use Test::Pod 1.41";