@@ -1,5 +1,8 @@
Revision history for App-Cmd
+0.324 2014-10-20 18:22:25-04:00 America/New_York
+ note that `cmd help` can take a subcommand in `cmd help help`
+
0.323 2013-12-07 08:46:51 America/New_York
fall back to "(unknown)" for command abstract in more cases (thanks,
Jakob Voss!)
@@ -1,4 +1,4 @@
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -12,7 +12,7 @@ b) the "Artistic License"
--- The GNU General Public License, Version 1, February 1989 ---
-This software is Copyright (c) 2013 by Ricardo Signes.
+This software is Copyright (c) 2014 by Ricardo Signes.
This is free software, licensed under:
@@ -22,7 +22,7 @@ This is free software, licensed under:
Version 1, February 1989
Copyright (C) 1989 Free Software Foundation, Inc.
- 51 Franklin St, Suite 500, Boston, MA 02110-1335 USA
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -272,7 +272,7 @@ That's all there is to it!
--- The Artistic License 1.0 ---
-This software is Copyright (c) 2013 by Ricardo Signes.
+This software is Copyright (c) 2014 by Ricardo Signes.
This is free software, licensed under:
@@ -1,3 +1,4 @@
+# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.020.
Changes
LICENSE
MANIFEST
@@ -4,7 +4,7 @@
"Ricardo Signes <rjbs@cpan.org>"
],
"dynamic_config" : 0,
- "generated_by" : "Dist::Zilla version 5.006, CPAN::Meta::Converter version 2.132830",
+ "generated_by" : "Dist::Zilla version 5.020, CPAN::Meta::Converter version 2.142060",
"license" : [
"perl_5"
],
@@ -16,7 +16,7 @@
"prereqs" : {
"configure" : {
"requires" : {
- "ExtUtils::MakeMaker" : "6.30"
+ "ExtUtils::MakeMaker" : "0"
}
},
"develop" : {
@@ -71,26 +71,34 @@
"web" : "https://github.com/rjbs/App-Cmd"
}
},
- "version" : "0.323",
+ "version" : "0.324",
"x_Dist_Zilla" : {
"perl" : {
- "version" : "5.018001"
+ "version" : "5.021003"
},
"plugins" : [
{
"class" : "Dist::Zilla::Plugin::Git::GatherDir",
+ "config" : {
+ "Dist::Zilla::Plugin::Git::GatherDir" : {
+ "include_untracked" : "0"
+ },
+ "Dist::Zilla::Role::Git::Repo" : {
+ "repo_root" : "."
+ }
+ },
"name" : "@RJBS/Git::GatherDir",
- "version" : "2.019"
+ "version" : "2.025"
},
{
"class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed",
"name" : "@RJBS/CheckPrereqsIndexed",
- "version" : "0.009"
+ "version" : "0.012"
},
{
"class" : "Dist::Zilla::Plugin::CheckExtraTests",
"name" : "@RJBS/CheckExtraTests",
- "version" : "0.016"
+ "version" : "0.022"
},
{
"class" : "Dist::Zilla::Plugin::PromptIfStale",
@@ -106,7 +114,7 @@
}
},
"name" : "@RJBS/RJBS-Outdated",
- "version" : "0.014"
+ "version" : "0.028"
},
{
"class" : "Dist::Zilla::Plugin::PromptIfStale",
@@ -120,97 +128,112 @@
}
},
"name" : "@RJBS/CPAN-Outdated",
- "version" : "0.014"
+ "version" : "0.028"
},
{
"class" : "Dist::Zilla::Plugin::PruneCruft",
"name" : "@RJBS/@Filter/PruneCruft",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::ManifestSkip",
"name" : "@RJBS/@Filter/ManifestSkip",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::MetaYAML",
"name" : "@RJBS/@Filter/MetaYAML",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::License",
"name" : "@RJBS/@Filter/License",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::Readme",
"name" : "@RJBS/@Filter/Readme",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::ExecDir",
"name" : "@RJBS/@Filter/ExecDir",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::ShareDir",
"name" : "@RJBS/@Filter/ShareDir",
- "version" : "5.006"
- },
- {
- "class" : "Dist::Zilla::Plugin::MakeMaker",
- "name" : "@RJBS/@Filter/MakeMaker",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::Manifest",
"name" : "@RJBS/@Filter/Manifest",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::TestRelease",
"name" : "@RJBS/@Filter/TestRelease",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::ConfirmRelease",
"name" : "@RJBS/@Filter/ConfirmRelease",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::UploadToCPAN",
"name" : "@RJBS/@Filter/UploadToCPAN",
- "version" : "5.006"
+ "version" : "5.020"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::MakeMaker",
+ "config" : {
+ "Dist::Zilla::Role::TestRunner" : {
+ "default_jobs" : 9
+ }
+ },
+ "name" : "@RJBS/MakeMaker",
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::AutoPrereqs",
"name" : "@RJBS/AutoPrereqs",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::Git::NextVersion",
+ "config" : {
+ "Dist::Zilla::Plugin::Git::NextVersion" : {
+ "first_version" : "0.001",
+ "version_by_branch" : "0",
+ "version_regexp" : "(?^:^([0-9]+\\.[0-9]+)$)"
+ },
+ "Dist::Zilla::Role::Git::Repo" : {
+ "repo_root" : "."
+ }
+ },
"name" : "@RJBS/Git::NextVersion",
- "version" : "2.019"
+ "version" : "2.025"
},
{
"class" : "Dist::Zilla::Plugin::PkgVersion",
"name" : "@RJBS/PkgVersion",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::MetaConfig",
"name" : "@RJBS/MetaConfig",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::MetaJSON",
"name" : "@RJBS/MetaJSON",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::NextRelease",
"name" : "@RJBS/NextRelease",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::Test::ChangesHasContent",
@@ -220,7 +243,7 @@
{
"class" : "Dist::Zilla::Plugin::PodSyntaxTests",
"name" : "@RJBS/PodSyntaxTests",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::ReportVersions::Tiny",
@@ -236,13 +259,15 @@
}
},
"name" : "@RJBS/TestMoreWithSubtests",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::PodWeaver",
"config" : {
"Dist::Zilla::Plugin::PodWeaver" : {
- "config_plugin" : "@RJBS",
+ "config_plugins" : [
+ "@RJBS"
+ ],
"finder" : [
":InstallModules",
":ExecFiles"
@@ -251,123 +276,182 @@
{
"class" : "Pod::Weaver::Plugin::EnsurePod5",
"name" : "@CorePrep/EnsurePod5",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Plugin::H1Nester",
"name" : "@CorePrep/H1Nester",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Plugin::SingleEncoding",
"name" : "@RJBS/SingleEncoding",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Name",
"name" : "@RJBS/Name",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Version",
"name" : "@RJBS/Version",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@RJBS/Prelude",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "@RJBS/Synopsis",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "@RJBS/Description",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "@RJBS/Overview",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Generic",
"name" : "@RJBS/Stability",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "Attributes",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "Methods",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Collect",
"name" : "Functions",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Leftovers",
"name" : "@RJBS/Leftovers",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Region",
"name" : "@RJBS/postlude",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Authors",
"name" : "@RJBS/Authors",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Section::Legal",
"name" : "@RJBS/Legal",
- "version" : "4.004"
+ "version" : "4.006"
},
{
"class" : "Pod::Weaver::Plugin::Transformer",
"name" : "@RJBS/List",
- "version" : "4.004"
+ "version" : "4.006"
}
]
}
},
"name" : "@RJBS/PodWeaver",
- "version" : "4.002"
+ "version" : "4.006"
},
{
"class" : "Dist::Zilla::Plugin::GithubMeta",
"name" : "@RJBS/GithubMeta",
- "version" : "0.42"
+ "version" : "0.46"
},
{
"class" : "Dist::Zilla::Plugin::Git::Check",
+ "config" : {
+ "Dist::Zilla::Plugin::Git::Check" : {
+ "untracked_files" : "die"
+ },
+ "Dist::Zilla::Role::Git::DirtyFiles" : {
+ "allow_dirty" : [
+ "dist.ini",
+ "Changes"
+ ],
+ "allow_dirty_match" : [],
+ "changelog" : "Changes"
+ },
+ "Dist::Zilla::Role::Git::Repo" : {
+ "repo_root" : "."
+ }
+ },
"name" : "@RJBS/@Git/Check",
- "version" : "2.019"
+ "version" : "2.025"
},
{
"class" : "Dist::Zilla::Plugin::Git::Commit",
+ "config" : {
+ "Dist::Zilla::Plugin::Git::Commit" : {
+ "add_files_in" : [],
+ "commit_msg" : "v%v%n%n%c",
+ "time_zone" : "local"
+ },
+ "Dist::Zilla::Role::Git::DirtyFiles" : {
+ "allow_dirty" : [
+ "dist.ini",
+ "Changes"
+ ],
+ "allow_dirty_match" : [],
+ "changelog" : "Changes"
+ },
+ "Dist::Zilla::Role::Git::Repo" : {
+ "repo_root" : "."
+ }
+ },
"name" : "@RJBS/@Git/Commit",
- "version" : "2.019"
+ "version" : "2.025"
},
{
"class" : "Dist::Zilla::Plugin::Git::Tag",
+ "config" : {
+ "Dist::Zilla::Plugin::Git::Tag" : {
+ "branch" : null,
+ "signed" : 0,
+ "tag" : "0.324",
+ "tag_format" : "%v",
+ "tag_message" : "v%v",
+ "time_zone" : "local"
+ },
+ "Dist::Zilla::Role::Git::Repo" : {
+ "repo_root" : "."
+ }
+ },
"name" : "@RJBS/@Git/Tag",
- "version" : "2.019"
+ "version" : "2.025"
},
{
"class" : "Dist::Zilla::Plugin::Git::Push",
+ "config" : {
+ "Dist::Zilla::Plugin::Git::Push" : {
+ "push_to" : [
+ "origin :",
+ "github :"
+ ],
+ "remotes_must_exist" : 0
+ },
+ "Dist::Zilla::Role::Git::Repo" : {
+ "repo_root" : "."
+ }
+ },
"name" : "@RJBS/@Git/Push",
- "version" : "2.019"
+ "version" : "2.025"
},
{
"class" : "Dist::Zilla::Plugin::Prereqs",
@@ -378,37 +462,47 @@
}
},
"name" : "Prereqs",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":InstallModules",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":IncModules",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":TestFiles",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ExecFiles",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":ShareFiles",
- "version" : "5.006"
+ "version" : "5.020"
},
{
"class" : "Dist::Zilla::Plugin::FinderCode",
"name" : ":MainModule",
- "version" : "5.006"
+ "version" : "5.020"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":AllFiles",
+ "version" : "5.020"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":NoFiles",
+ "version" : "5.020"
}
],
"zilla" : {
@@ -416,7 +510,7 @@
"config" : {
"is_trial" : "0"
},
- "version" : "5.006"
+ "version" : "5.020"
}
}
}
@@ -3,62 +3,67 @@ abstract: 'write command line apps with less suffering'
author:
- 'Ricardo Signes <rjbs@cpan.org>'
build_requires:
- Data::Dumper: 0
- IPC::Cmd: 0
- Test::Fatal: 0
- Test::More: 0.96
- base: 0
- lib: 0
+ Data::Dumper: '0'
+ IPC::Cmd: '0'
+ Test::Fatal: '0'
+ Test::More: '0.96'
+ base: '0'
+ lib: '0'
configure_requires:
- ExtUtils::MakeMaker: 6.30
+ ExtUtils::MakeMaker: '0'
dynamic_config: 0
-generated_by: 'Dist::Zilla version 5.006, CPAN::Meta::Converter version 2.132830'
+generated_by: 'Dist::Zilla version 5.020, CPAN::Meta::Converter version 2.142060'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
- version: 1.4
+ version: '1.4'
name: App-Cmd
requires:
- Capture::Tiny: 0.13
- Carp: 0
- Class::Load: 0.06
- Data::OptList: 0
- File::Basename: 0
- Getopt::Long: 2.39
- Getopt::Long::Descriptive: 0.084
- IO::TieCombine: 0
- Module::Pluggable::Object: 0
- String::RewritePrefix: 0
- Sub::Exporter: 0
- Sub::Exporter::Util: 0
- Sub::Install: 0
- Text::Abbrev: 0
- constant: 0
- parent: 0
- perl: 5.006
- strict: 0
- warnings: 0
+ Capture::Tiny: '0.13'
+ Carp: '0'
+ Class::Load: '0.06'
+ Data::OptList: '0'
+ File::Basename: '0'
+ Getopt::Long: '2.39'
+ Getopt::Long::Descriptive: '0.084'
+ IO::TieCombine: '0'
+ Module::Pluggable::Object: '0'
+ String::RewritePrefix: '0'
+ Sub::Exporter: '0'
+ Sub::Exporter::Util: '0'
+ Sub::Install: '0'
+ Text::Abbrev: '0'
+ constant: '0'
+ parent: '0'
+ perl: '5.006'
+ strict: '0'
+ warnings: '0'
resources:
bugtracker: https://github.com/rjbs/App-Cmd/issues
homepage: https://github.com/rjbs/App-Cmd
repository: https://github.com/rjbs/App-Cmd.git
-version: 0.323
+version: '0.324'
x_Dist_Zilla:
perl:
- version: 5.018001
+ version: '5.021003'
plugins:
-
class: Dist::Zilla::Plugin::Git::GatherDir
+ config:
+ Dist::Zilla::Plugin::Git::GatherDir:
+ include_untracked: '0'
+ Dist::Zilla::Role::Git::Repo:
+ repo_root: .
name: '@RJBS/Git::GatherDir'
- version: 2.019
+ version: '2.025'
-
class: Dist::Zilla::Plugin::CheckPrereqsIndexed
name: '@RJBS/CheckPrereqsIndexed'
- version: 0.009
+ version: '0.012'
-
class: Dist::Zilla::Plugin::CheckExtraTests
name: '@RJBS/CheckExtraTests'
- version: 0.016
+ version: '0.022'
-
class: Dist::Zilla::Plugin::PromptIfStale
config:
@@ -70,102 +75,112 @@ x_Dist_Zilla:
phase: build
skip: []
name: '@RJBS/RJBS-Outdated'
- version: 0.014
+ version: '0.028'
-
class: Dist::Zilla::Plugin::PromptIfStale
config:
Dist::Zilla::Plugin::PromptIfStale:
- check_all_plugins: 1
+ check_all_plugins: '1'
check_all_prereqs: 0
modules: []
phase: release
skip: []
name: '@RJBS/CPAN-Outdated'
- version: 0.014
+ version: '0.028'
-
class: Dist::Zilla::Plugin::PruneCruft
name: '@RJBS/@Filter/PruneCruft'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::ManifestSkip
name: '@RJBS/@Filter/ManifestSkip'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::MetaYAML
name: '@RJBS/@Filter/MetaYAML'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::License
name: '@RJBS/@Filter/License'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::Readme
name: '@RJBS/@Filter/Readme'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::ExecDir
name: '@RJBS/@Filter/ExecDir'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::ShareDir
name: '@RJBS/@Filter/ShareDir'
- version: 5.006
- -
- class: Dist::Zilla::Plugin::MakeMaker
- name: '@RJBS/@Filter/MakeMaker'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::Manifest
name: '@RJBS/@Filter/Manifest'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::TestRelease
name: '@RJBS/@Filter/TestRelease'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::ConfirmRelease
name: '@RJBS/@Filter/ConfirmRelease'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::UploadToCPAN
name: '@RJBS/@Filter/UploadToCPAN'
- version: 5.006
+ version: '5.020'
+ -
+ class: Dist::Zilla::Plugin::MakeMaker
+ config:
+ Dist::Zilla::Role::TestRunner:
+ default_jobs: 9
+ name: '@RJBS/MakeMaker'
+ version: '5.020'
-
class: Dist::Zilla::Plugin::AutoPrereqs
name: '@RJBS/AutoPrereqs'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::Git::NextVersion
+ config:
+ Dist::Zilla::Plugin::Git::NextVersion:
+ first_version: '0.001'
+ version_by_branch: '0'
+ version_regexp: (?^:^([0-9]+\.[0-9]+)$)
+ Dist::Zilla::Role::Git::Repo:
+ repo_root: .
name: '@RJBS/Git::NextVersion'
- version: 2.019
+ version: '2.025'
-
class: Dist::Zilla::Plugin::PkgVersion
name: '@RJBS/PkgVersion'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::MetaConfig
name: '@RJBS/MetaConfig'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::MetaJSON
name: '@RJBS/MetaJSON'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::NextRelease
name: '@RJBS/NextRelease'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::Test::ChangesHasContent
name: '@RJBS/Test::ChangesHasContent'
- version: 0.006
+ version: '0.006'
-
class: Dist::Zilla::Plugin::PodSyntaxTests
name: '@RJBS/PodSyntaxTests'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::ReportVersions::Tiny
name: '@RJBS/ReportVersions::Tiny'
- version: 1.10
+ version: '1.10'
-
class: Dist::Zilla::Plugin::Prereqs
config:
@@ -173,12 +188,13 @@ x_Dist_Zilla:
phase: test
type: requires
name: '@RJBS/TestMoreWithSubtests'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::PodWeaver
config:
Dist::Zilla::Plugin::PodWeaver:
- config_plugin: '@RJBS'
+ config_plugins:
+ - '@RJBS'
finder:
- ':InstallModules'
- ':ExecFiles'
@@ -186,97 +202,139 @@ x_Dist_Zilla:
-
class: Pod::Weaver::Plugin::EnsurePod5
name: '@CorePrep/EnsurePod5'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Plugin::H1Nester
name: '@CorePrep/H1Nester'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Plugin::SingleEncoding
name: '@RJBS/SingleEncoding'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Name
name: '@RJBS/Name'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Version
name: '@RJBS/Version'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Region
name: '@RJBS/Prelude'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Generic
name: '@RJBS/Synopsis'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Generic
name: '@RJBS/Description'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Generic
name: '@RJBS/Overview'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Generic
name: '@RJBS/Stability'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Collect
name: Attributes
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Collect
name: Methods
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Collect
name: Functions
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Leftovers
name: '@RJBS/Leftovers'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Region
name: '@RJBS/postlude'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Authors
name: '@RJBS/Authors'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Section::Legal
name: '@RJBS/Legal'
- version: 4.004
+ version: '4.006'
-
class: Pod::Weaver::Plugin::Transformer
name: '@RJBS/List'
- version: 4.004
+ version: '4.006'
name: '@RJBS/PodWeaver'
- version: 4.002
+ version: '4.006'
-
class: Dist::Zilla::Plugin::GithubMeta
name: '@RJBS/GithubMeta'
- version: 0.42
+ version: '0.46'
-
class: Dist::Zilla::Plugin::Git::Check
+ config:
+ Dist::Zilla::Plugin::Git::Check:
+ untracked_files: die
+ Dist::Zilla::Role::Git::DirtyFiles:
+ allow_dirty:
+ - dist.ini
+ - Changes
+ allow_dirty_match: []
+ changelog: Changes
+ Dist::Zilla::Role::Git::Repo:
+ repo_root: .
name: '@RJBS/@Git/Check'
- version: 2.019
+ version: '2.025'
-
class: Dist::Zilla::Plugin::Git::Commit
+ config:
+ Dist::Zilla::Plugin::Git::Commit:
+ add_files_in: []
+ commit_msg: v%v%n%n%c
+ time_zone: local
+ Dist::Zilla::Role::Git::DirtyFiles:
+ allow_dirty:
+ - dist.ini
+ - Changes
+ allow_dirty_match: []
+ changelog: Changes
+ Dist::Zilla::Role::Git::Repo:
+ repo_root: .
name: '@RJBS/@Git/Commit'
- version: 2.019
+ version: '2.025'
-
class: Dist::Zilla::Plugin::Git::Tag
+ config:
+ Dist::Zilla::Plugin::Git::Tag:
+ branch: ~
+ signed: 0
+ tag: '0.324'
+ tag_format: '%v'
+ tag_message: v%v
+ time_zone: local
+ Dist::Zilla::Role::Git::Repo:
+ repo_root: .
name: '@RJBS/@Git/Tag'
- version: 2.019
+ version: '2.025'
-
class: Dist::Zilla::Plugin::Git::Push
+ config:
+ Dist::Zilla::Plugin::Git::Push:
+ push_to:
+ - 'origin :'
+ - 'github :'
+ remotes_must_exist: 0
+ Dist::Zilla::Role::Git::Repo:
+ repo_root: .
name: '@RJBS/@Git/Push'
- version: 2.019
+ version: '2.025'
-
class: Dist::Zilla::Plugin::Prereqs
config:
@@ -284,33 +342,41 @@ x_Dist_Zilla:
phase: runtime
type: requires
name: Prereqs
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':InstallModules'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':IncModules'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':TestFiles'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':ExecFiles'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':ShareFiles'
- version: 5.006
+ version: '5.020'
-
class: Dist::Zilla::Plugin::FinderCode
name: ':MainModule'
- version: 5.006
+ version: '5.020'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':AllFiles'
+ version: '5.020'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':NoFiles'
+ version: '5.020'
zilla:
class: Dist::Zilla::Dist::Builder
config:
- is_trial: 0
- version: 5.006
+ is_trial: '0'
+ version: '5.020'
@@ -1,19 +1,19 @@
+# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.020.
use strict;
use warnings;
use 5.006;
-use ExtUtils::MakeMaker 6.30;
+use ExtUtils::MakeMaker ;
my %WriteMakefileArgs = (
"ABSTRACT" => "write command line apps with less suffering",
"AUTHOR" => "Ricardo Signes <rjbs\@cpan.org>",
- "BUILD_REQUIRES" => {},
"CONFIGURE_REQUIRES" => {
- "ExtUtils::MakeMaker" => "6.30"
+ "ExtUtils::MakeMaker" => 0
},
"DISTNAME" => "App-Cmd",
"EXE_FILES" => [],
@@ -47,7 +47,7 @@ my %WriteMakefileArgs = (
"base" => 0,
"lib" => 0
},
- "VERSION" => "0.323",
+ "VERSION" => "0.324",
"test" => {
"TESTS" => "t/*.t"
}
@@ -1,13 +1,15 @@
This archive contains the distribution App-Cmd,
-version 0.323:
+version 0.324:
write command line apps with less suffering
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
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.020.
+
@@ -2,9 +2,7 @@ use strict;
use warnings;
package App::Cmd::ArgProcessor;
-{
- $App::Cmd::ArgProcessor::VERSION = '0.323';
-}
+$App::Cmd::ArgProcessor::VERSION = '0.324';
# ABSTRACT: App::Cmd-specific wrapper for Getopt::Long::Descriptive
sub _process_args {
@@ -37,7 +35,7 @@ App::Cmd::ArgProcessor - App::Cmd-specific wrapper for Getopt::Long::Descriptive
=head1 VERSION
-version 0.323
+version 0.324
=head1 AUTHOR
@@ -45,7 +43,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -2,14 +2,27 @@ use strict;
use warnings;
package App::Cmd::Command::commands;
-{
- $App::Cmd::Command::commands::VERSION = '0.323';
-}
+$App::Cmd::Command::commands::VERSION = '0.324';
use App::Cmd::Command;
BEGIN { our @ISA = 'App::Cmd::Command' };
# ABSTRACT: list the application's commands
+#pod =head1 DESCRIPTION
+#pod
+#pod This command plugin implements a "commands" command. This command will list
+#pod all of an App::Cmd's commands and their abstracts.
+#pod
+#pod =method execute
+#pod
+#pod This is the command's primary method and raison d'etre. It prints the
+#pod application's usage text (if any) followed by a sorted listing of the
+#pod application's commands and their abstracts.
+#pod
+#pod The commands are printed in sorted groups (created by C<sort_commands>); each
+#pod group is set off by blank lines.
+#pod
+#pod =cut
sub execute {
my ($self, $opt, $args) = @_;
@@ -41,6 +54,17 @@ sub execute {
}
}
+#pod =method C<sort_commands>
+#pod
+#pod my @sorted = $cmd->sort_commands(@unsorted);
+#pod
+#pod This method orders the list of commands into sets which it returns as a list of
+#pod arrayrefs.
+#pod
+#pod By default, the first group is for the "help" and "commands" commands, and all
+#pod other commands are in the second group.
+#pod
+#pod =cut
sub sort_commands {
my ($self, @commands) = @_;
@@ -78,7 +102,7 @@ App::Cmd::Command::commands - list the application's commands
=head1 VERSION
-version 0.323
+version 0.324
=head1 DESCRIPTION
@@ -112,7 +136,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -2,14 +2,77 @@ use strict;
use warnings;
package App::Cmd::Command::help;
-{
- $App::Cmd::Command::help::VERSION = '0.323';
-}
+$App::Cmd::Command::help::VERSION = '0.324';
use App::Cmd::Command;
BEGIN { our @ISA = 'App::Cmd::Command'; }
# ABSTRACT: display a command's help screen
+#pod =head1 DESCRIPTION
+#pod
+#pod This command plugin implements a "help" command. This command will either list
+#pod all of an App::Cmd's commands and their abstracts, or display the usage screen
+#pod for a subcommand with its description.
+#pod
+#pod =head1 USAGE
+#pod
+#pod The help text is generated from three sources:
+#pod
+#pod =for :list
+#pod * The C<usage_desc> method
+#pod * The C<description> method
+#pod * The C<opt_spec> data structure
+#pod
+#pod The C<usage_desc> method provides the opening usage line, following the
+#pod specification described in L<Getopt::Long::Descriptive>. In some cases,
+#pod the default C<usage_desc> in L<App::Cmd::Command> may be sufficient and
+#pod you will only need to override it to provide additional command line
+#pod usage information.
+#pod
+#pod The C<opt_spec> data structure is used with L<Getopt::Long::Descriptive>
+#pod to generate the description of the options.
+#pod
+#pod Subcommand classes should override the C<discription> method to provide
+#pod additional information that is prepended before the option descriptions.
+#pod
+#pod For example, consider the following subcommand module:
+#pod
+#pod package YourApp::Command::initialize;
+#pod
+#pod # This is the default from App::Cmd::Command
+#pod sub usage_desc {
+#pod my ($self) = @_;
+#pod my $desc = $self->SUPER::usage_desc; # "%c COMMAND %o"
+#pod return "$desc [DIRECTORY]";
+#pod }
+#pod
+#pod sub description {
+#pod return "The initialize command prepares the application...";
+#pod }
+#pod
+#pod sub opt_spec {
+#pod return (
+#pod [ "skip-refs|R", "skip reference checks during init", ],
+#pod [ "values|v=s@", "starting values", { default => [ 0, 1, 3 ] } ],
+#pod );
+#pod }
+#pod
+#pod ...
+#pod
+#pod That module would generate help output like this:
+#pod
+#pod $ yourapp help initialize
+#pod yourapp initialize [-Rv] [long options...] [DIRECTORY]
+#pod
+#pod The initialize command prepares the application...
+#pod
+#pod --help This usage screen
+#pod -R --skip-refs skip reference checks during init
+#pod -v --values starting values
+#pod
+#pod =cut
+
+sub usage_desc { '%c help [subcommand]' }
sub command_names { qw/help --help -h -?/ }
@@ -70,7 +133,7 @@ App::Cmd::Command::help - display a command's help screen
=head1 VERSION
-version 0.323
+version 0.324
=head1 DESCRIPTION
@@ -151,7 +214,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -2,14 +2,19 @@ use strict;
use warnings;
package App::Cmd::Command::version;
-{
- $App::Cmd::Command::version::VERSION = '0.323';
-}
+$App::Cmd::Command::version::VERSION = '0.324';
use App::Cmd::Command;
BEGIN { our @ISA = 'App::Cmd::Command'; }
# ABSTRACT: display an app's version
+#pod =head1 DESCRIPTION
+#pod
+#pod This plugin implements the C<version> command, often invoked by its switch-like
+#pod name, C<--version>. On execution it shows the program name, its base class
+#pod with version number, and the full program name.
+#pod
+#pod =cut
sub command_names { qw/version --version/ }
@@ -43,7 +48,7 @@ App::Cmd::Command::version - display an app's version
=head1 VERSION
-version 0.323
+version 0.324
=head1 DESCRIPTION
@@ -57,7 +62,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -2,9 +2,7 @@ use strict;
use warnings;
package App::Cmd::Command;
-{
- $App::Cmd::Command::VERSION = '0.323';
-}
+$App::Cmd::Command::VERSION = '0.324';
use App::Cmd::ArgProcessor;
BEGIN { our @ISA = 'App::Cmd::ArgProcessor' };
@@ -12,6 +10,19 @@ BEGIN { our @ISA = 'App::Cmd::ArgProcessor' };
use Carp ();
+#pod =method prepare
+#pod
+#pod my ($cmd, $opt, $args) = $class->prepare($app, @args);
+#pod
+#pod This method is the primary way in which App::Cmd::Command objects are built.
+#pod Given the remaining command line arguments meant for the command, it returns
+#pod the Command object, parsed options (as a hashref), and remaining arguments (as
+#pod an arrayref).
+#pod
+#pod In the usage above, C<$app> is the App::Cmd object that is invoking the
+#pod command.
+#pod
+#pod =cut
sub prepare {
my ($class, $app, @args) = @_;
@@ -35,12 +46,30 @@ sub _option_processing_params {
);
}
+#pod =method new
+#pod
+#pod This returns a new instance of the command plugin. Probably only C<prepare>
+#pod should use this.
+#pod
+#pod =cut
sub new {
my ($class, $arg) = @_;
bless $arg => $class;
}
+#pod =method execute
+#pod
+#pod $command_plugin->execute(\%opt, \@args);
+#pod
+#pod This method does whatever it is the command should do! It is passed a hash
+#pod reference of the parsed command-line options and an array reference of left
+#pod over arguments.
+#pod
+#pod If no C<execute> method is defined, it will try to call C<run> -- but it will
+#pod warn about this behavior during testing, to remind you to fix the method name!
+#pod
+#pod =cut
sub execute {
my $class = shift;
@@ -55,12 +84,37 @@ sub execute {
Carp::croak ref($class) . " does not implement mandatory method 'execute'\n";
}
+#pod =method app
+#pod
+#pod This method returns the App::Cmd object into which this command is plugged.
+#pod
+#pod =cut
sub app { $_[0]->{app}; }
+#pod =method usage
+#pod
+#pod This method returns the usage object for this command. (See
+#pod L<Getopt::Long::Descriptive>).
+#pod
+#pod =cut
sub usage { $_[0]->{usage}; }
+#pod =method command_names
+#pod
+#pod This method returns a list of command names handled by this plugin. The
+#pod first item returned is the 'canonical' name of the command.
+#pod
+#pod If this method is not overridden by an App::Cmd::Command subclass, it will
+#pod return the last part of the plugin's package name, converted to lowercase.
+#pod For example, YourApp::Cmd::Command::Init will, by default, handle the command
+#pod "init".
+#pod
+#pod Subclasses should generally get the superclass value of C<command_names>
+#pod and then append aliases.
+#pod
+#pod =cut
sub command_names {
# from UNIVERSAL::moniker
@@ -68,6 +122,15 @@ sub command_names {
return lc $1;
}
+#pod =method usage_desc
+#pod
+#pod This method should be overridden to provide a usage string. (This is the first
+#pod argument passed to C<describe_options> from Getopt::Long::Descriptive.)
+#pod
+#pod If not overridden, it returns "%c COMMAND %o"; COMMAND is the first item in
+#pod the result of the C<command_names> method.
+#pod
+#pod =cut
sub usage_desc {
my ($self) = @_;
@@ -76,14 +139,41 @@ sub usage_desc {
return "%c $command %o"
}
+#pod =method opt_spec
+#pod
+#pod This method should be overridden to provide option specifications. (This is
+#pod list of arguments passed to C<describe_options> from Getopt::Long::Descriptive,
+#pod after the first.)
+#pod
+#pod If not overridden, it returns an empty list.
+#pod
+#pod =cut
sub opt_spec {
return;
}
+#pod =method validate_args
+#pod
+#pod $command_plugin->validate_args(\%opt, \@args);
+#pod
+#pod This method is passed a hashref of command line options (as processed by
+#pod Getopt::Long::Descriptive) and an arrayref of leftover arguments. It may throw
+#pod an exception (preferably by calling C<usage_error>, below) if they are invalid,
+#pod or it may do nothing to allow processing to continue.
+#pod
+#pod =cut
sub validate_args { }
+#pod =method usage_error
+#pod
+#pod $self->usage_error("This command must not be run by root!");
+#pod
+#pod This method should be called to die with human-friendly usage output, during
+#pod C<validate_args>.
+#pod
+#pod =cut
sub usage_error {
my ( $self, $error ) = @_;
@@ -96,6 +186,14 @@ sub _usage_text {
join "\n", eval { $self->app->_usage_text }, eval { $self->usage->text };
}
+#pod =method abstract
+#pod
+#pod This method returns a short description of the command's purpose. If this
+#pod method is not overridden, it will return the abstract from the module's Pod.
+#pod If it can't find the abstract, it will look for a comment starting with
+#pod "ABSTRACT:" like the ones used by L<Pod::Weaver::Section::Name>.
+#pod
+#pod =cut
# stolen from ExtUtils::MakeMaker
sub abstract {
@@ -137,6 +235,14 @@ sub abstract {
return $result || $weaver_abstract || "(unknown)";
}
+#pod =method description
+#pod
+#pod This method should be overridden to provide full option description. It
+#pod is used by the built-in L<help|App::Cmd::Command::help> command.
+#pod
+#pod If not overridden, it returns an empty string.
+#pod
+#pod =cut
sub description { '' }
@@ -154,7 +260,7 @@ App::Cmd::Command - a base class for App::Cmd commands
=head1 VERSION
-version 0.323
+version 0.324
=head1 METHODS
@@ -260,7 +366,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -1,9 +1,7 @@
use strict;
use warnings;
package App::Cmd::Plugin;
-{
- $App::Cmd::Plugin::VERSION = '0.323';
-}
+$App::Cmd::Plugin::VERSION = '0.324';
# ABSTRACT: a plugin for App::Cmd commands
sub _faux_curried_method {
@@ -29,7 +27,7 @@ App::Cmd::Plugin - a plugin for App::Cmd commands
=head1 VERSION
-version 0.323
+version 0.324
=head1 AUTHOR
@@ -37,7 +35,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -1,11 +1,73 @@
use strict;
use warnings;
package App::Cmd::Setup;
-{
- $App::Cmd::Setup::VERSION = '0.323';
-}
+$App::Cmd::Setup::VERSION = '0.324';
# ABSTRACT: helper for setting up App::Cmd classes
+#pod =head1 OVERVIEW
+#pod
+#pod App::Cmd::Setup is a helper library, used to set up base classes that will be
+#pod used as part of an App::Cmd program. For the most part you should refer to
+#pod L<the tutorial|App::Cmd::Tutorial> for how you should use this library.
+#pod
+#pod This class is useful in three scenarios:
+#pod
+#pod =begin :list
+#pod
+#pod = when writing your App::Cmd subclass
+#pod
+#pod Instead of writing:
+#pod
+#pod package MyApp;
+#pod use base 'App::Cmd';
+#pod
+#pod ...you can write:
+#pod
+#pod package MyApp;
+#pod use App::Cmd::Setup -app;
+#pod
+#pod The benefits of doing this are mostly minor, and relate to sanity-checking your
+#pod class. The significant benefit is that this form allows you to specify
+#pod plugins, as in:
+#pod
+#pod package MyApp;
+#pod use App::Cmd::Setup -app => { plugins => [ 'Prompt' ] };
+#pod
+#pod Plugins are described in L<App::Cmd::Tutorial> and L<App::Cmd::Plugin>.
+#pod
+#pod = when writing abstract base classes for commands
+#pod
+#pod That is: when you write a subclass of L<App::Cmd::Command> that is intended for
+#pod other commands to use as their base class, you should use App::Cmd::Setup. For
+#pod example, if you want all the commands in MyApp to inherit from MyApp::Command,
+#pod you may want to write that package like this:
+#pod
+#pod package MyApp::Command;
+#pod use App::Cmd::Setup -command;
+#pod
+#pod Do not confuse this with the way you will write specific commands:
+#pod
+#pod package MyApp::Command::mycmd;
+#pod use MyApp -command;
+#pod
+#pod Again, this form mostly performs some validation and setup behind the scenes
+#pod for you. You can use C<L<base>> if you prefer.
+#pod
+#pod = when writing App::Cmd plugins
+#pod
+#pod L<App::Cmd::Plugin> is a mechanism that allows an App::Cmd class to inject code
+#pod into all its command classes, providing them with utility routines.
+#pod
+#pod To write a plugin, you must use App::Cmd::Setup. As seen above, you must also
+#pod use App::Cmd::Setup to set up your App::Cmd subclass if you wish to consume
+#pod plugins.
+#pod
+#pod For more information on writing plugins, see L<App::Cmd::Manual> and
+#pod L<App::Cmd::Plugin>.
+#pod
+#pod =end :list
+#pod
+#pod =cut
use App::Cmd ();
use App::Cmd::Command ();
@@ -152,7 +214,7 @@ App::Cmd::Setup - helper for setting up App::Cmd classes
=head1 VERSION
-version 0.323
+version 0.324
=head1 OVERVIEW
@@ -223,7 +285,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -2,9 +2,7 @@ use strict;
use warnings;
package App::Cmd::Simple;
-{
- $App::Cmd::Simple::VERSION = '0.323';
-}
+$App::Cmd::Simple::VERSION = '0.324';
use App::Cmd::Command;
BEGIN { our @ISA = 'App::Cmd::Command' }
@@ -13,6 +11,80 @@ BEGIN { our @ISA = 'App::Cmd::Command' }
use App::Cmd;
use Sub::Install;
+#pod =head1 SYNOPSIS
+#pod
+#pod in F<simplecmd>:
+#pod
+#pod use YourApp::Cmd;
+#pod Your::Cmd->run;
+#pod
+#pod in F<YourApp/Cmd.pm>:
+#pod
+#pod package YourApp::Cmd;
+#pod use base qw(App::Cmd::Simple);
+#pod
+#pod sub opt_spec {
+#pod return (
+#pod [ "blortex|X", "use the blortex algorithm" ],
+#pod [ "recheck|r", "recheck all results" ],
+#pod );
+#pod }
+#pod
+#pod sub validate_args {
+#pod my ($self, $opt, $args) = @_;
+#pod
+#pod # no args allowed but options!
+#pod $self->usage_error("No args allowed") if @$args;
+#pod }
+#pod
+#pod sub execute {
+#pod my ($self, $opt, $args) = @_;
+#pod
+#pod my $result = $opt->{blortex} ? blortex() : blort();
+#pod
+#pod recheck($result) if $opt->{recheck};
+#pod
+#pod print $result;
+#pod }
+#pod
+#pod and, finally, at the command line:
+#pod
+#pod knight!rjbs$ simplecmd --recheck
+#pod
+#pod All blorts successful.
+#pod
+#pod =head1 SUBCLASSING
+#pod
+#pod When writing a subclass of App::Cmd:Simple, there are only a few methods that
+#pod you might want to implement. They behave just like the same-named methods in
+#pod App::Cmd.
+#pod
+#pod =head2 opt_spec
+#pod
+#pod This method should be overridden to provide option specifications. (This is
+#pod list of arguments passed to C<describe_options> from Getopt::Long::Descriptive,
+#pod after the first.)
+#pod
+#pod If not overridden, it returns an empty list.
+#pod
+#pod =head2 validate_args
+#pod
+#pod $cmd->validate_args(\%opt, \@args);
+#pod
+#pod This method is passed a hashref of command line options (as processed by
+#pod Getopt::Long::Descriptive) and an arrayref of leftover arguments. It may throw
+#pod an exception (preferably by calling C<usage_error>) if they are invalid, or it
+#pod may do nothing to allow processing to continue.
+#pod
+#pod =head2 execute
+#pod
+#pod Your::App::Cmd::Simple->execute(\%opt, \@args);
+#pod
+#pod This method does whatever it is the command should do! It is passed a hash
+#pod reference of the parsed command-line options and an array reference of left
+#pod over arguments.
+#pod
+#pod =cut
# The idea here is that the user will someday replace "Simple" in his ISA with
# "Command" and then write a standard App::Cmd package. To make that possible,
@@ -106,6 +178,26 @@ sub usage_desc {
sub _cmd_pkg { }
+#pod =head1 WARNINGS
+#pod
+#pod B<This should be considered experimental!> Although it is probably not going
+#pod to change much, don't build your business model around it yet, okay?
+#pod
+#pod App::Cmd::Simple is not rich in black magic, but it does do some somewhat
+#pod gnarly things to make an App::Cmd::Simple look as much like an
+#pod App::Cmd::Command as possible. This means that you can't deviate too much from
+#pod the sort of thing shown in the synopsis as you might like. If you're doing
+#pod something other than writing a fairly simple command, and you want to screw
+#pod around with the App::Cmd-iness of your program, Simple might not be the best
+#pod choice.
+#pod
+#pod B<One specific warning...> if you are writing a program with the
+#pod App::Cmd::Simple class embedded in it, you B<must> call import on the class.
+#pod That's how things work. You can just do this:
+#pod
+#pod YourApp::Cmd->import->run;
+#pod
+#pod =cut
1;
@@ -121,7 +213,7 @@ App::Cmd::Simple - a helper for building one-command App::Cmd applications
=head1 VERSION
-version 0.323
+version 0.324
=head1 SYNOPSIS
@@ -221,7 +313,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -2,14 +2,22 @@ use strict;
use warnings;
package App::Cmd::Subdispatch::DashedStyle;
-{
- $App::Cmd::Subdispatch::DashedStyle::VERSION = '0.323';
-}
+$App::Cmd::Subdispatch::DashedStyle::VERSION = '0.324';
use App::Cmd::Subdispatch;
BEGIN { our @ISA = 'App::Cmd::Subdispatch' };
# ABSTRACT: "app cmd --subcmd" style subdispatching
+#pod =method get_command
+#pod
+#pod my ($subcommand, $opt, $args) = $subdispatch->get_command(@args)
+#pod
+#pod A version of get_command that chooses commands as options in the following
+#pod style:
+#pod
+#pod mytool mycommand --mysubcommand
+#pod
+#pod =cut
sub get_command {
my ($self, @args) = @_;
@@ -25,12 +33,21 @@ sub get_command {
}
}
+#pod =for Pod::Coverage prepare_default_command
+#pod
+#pod =cut
sub prepare_default_command {
my ( $self, $opt, @args ) = @_;
$self->_prepare_command( "help" );
}
+#pod =method opt_spec
+#pod
+#pod A version of C<opt_spec> that calculates the getopt specification from the
+#pod subcommands.
+#pod
+#pod =cut
sub opt_spec {
my ($self, $app) = @_;
@@ -67,7 +84,7 @@ App::Cmd::Subdispatch::DashedStyle - "app cmd --subcmd" style subdispatching
=head1 VERSION
-version 0.323
+version 0.324
=head1 METHODS
@@ -93,7 +110,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -2,16 +2,19 @@ use strict;
use warnings;
package App::Cmd::Subdispatch;
-{
- $App::Cmd::Subdispatch::VERSION = '0.323';
-}
-
+$App::Cmd::Subdispatch::VERSION = '0.324';
use App::Cmd;
use App::Cmd::Command;
BEGIN { our @ISA = qw(App::Cmd::Command App::Cmd) }
# ABSTRACT: an App::Cmd::Command that is also an App::Cmd
+#pod =method new
+#pod
+#pod A hackish new that allows us to have an Command instance before they normally
+#pod exist.
+#pod
+#pod =cut
sub new {
my ($inv, $fields, @args) = @_;
@@ -23,6 +26,14 @@ sub new {
}
}
+#pod =method prepare
+#pod
+#pod my $subcmd = $subdispatch->prepare($app, @args);
+#pod
+#pod An overridden version of L<App::Cmd::Command/prepare> that performs a new
+#pod dispatch cycle.
+#pod
+#pod =cut
sub prepare {
my ($class, $app, @args) = @_;
@@ -49,9 +60,27 @@ sub _plugin_prepare {
return $plugin->prepare($self->choose_parent_app($self->app, $plugin), @args);
}
+#pod =method app
+#pod
+#pod $subdispatch->app;
+#pod
+#pod This method returns the application that this subdispatch is a command of.
+#pod
+#pod =cut
sub app { $_[0]{app} }
+#pod =method choose_parent_app
+#pod
+#pod $subcmd->prepare(
+#pod $subdispatch->choose_parent_app($app, $opt, $plugin),
+#pod @$args
+#pod );
+#pod
+#pod A method that chooses whether the parent app or the subdispatch is going to be
+#pod C<< $cmd->app >>.
+#pod
+#pod =cut
sub choose_parent_app {
my ( $self, $app, $plugin ) = @_;
@@ -81,7 +110,7 @@ App::Cmd::Subdispatch - an App::Cmd::Command that is also an App::Cmd
=head1 VERSION
-version 0.323
+version 0.324
=head1 METHODS
@@ -119,7 +148,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -1,15 +1,46 @@
use strict;
use warnings;
package App::Cmd::Tester::CaptureExternal;
-{
- $App::Cmd::Tester::CaptureExternal::VERSION = '0.323';
-}
-
+$App::Cmd::Tester::CaptureExternal::VERSION = '0.324';
use parent 'App::Cmd::Tester';
use Capture::Tiny 0.13 qw/capture/;
# ABSTRACT: Extends App::Cmd::Tester to capture from external subprograms
+#pod =head1 SYNOPSIS
+#pod
+#pod use Test::More tests => 4;
+#pod use App::Cmd::Tester::CaptureExternal;
+#pod
+#pod use YourApp;
+#pod
+#pod my $result = test_app(YourApp => [ qw(command --opt value) ]);
+#pod
+#pod like($result->stdout, qr/expected output/, 'printed what we expected');
+#pod
+#pod is($result->stderr, '', 'nothing sent to sderr');
+#pod
+#pod ok($result->output, "STDOUT concatenated with STDERR");
+#pod
+#pod =head1 DESCRIPTION
+#pod
+#pod L<App::Cmd::Tester> provides a useful scaffold for testing applications, but it
+#pod is unable to capture output generated from any external subprograms that are
+#pod invoked from the application.
+#pod
+#pod This subclass uses an alternate mechanism for capturing output
+#pod (L<Capture::Tiny>) that does capture from external programs, with one
+#pod major limitation.
+#pod
+#pod It is not possible to capture externally from both STDOUT and STDERR while
+#pod also having appropriately interleaved combined output. Therefore, the
+#pod C<output> from this subclass simply concatenates the two.
+#pod
+#pod You can still use C<output> for testing if there is any output at all or for
+#pod testing if something appeared in either output stream, but you can't rely on
+#pod the ordering being correct between lines to STDOUT and lines to STDERR.
+#pod
+#pod =cut
sub _run_with_capture {
my ($class, $app, $argv) = @_;
@@ -50,7 +81,7 @@ App::Cmd::Tester::CaptureExternal - Extends App::Cmd::Tester to capture from ext
=head1 VERSION
-version 0.323
+version 0.324
=head1 SYNOPSIS
@@ -91,7 +122,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -1,12 +1,60 @@
use strict;
use warnings;
package App::Cmd::Tester;
-{
- $App::Cmd::Tester::VERSION = '0.323';
-}
-
+$App::Cmd::Tester::VERSION = '0.324';
# ABSTRACT: for capturing the result of running an app
+#pod =head1 SYNOPSIS
+#pod
+#pod use Test::More tests => 4;
+#pod use App::Cmd::Tester;
+#pod
+#pod use YourApp;
+#pod
+#pod my $result = test_app(YourApp => [ qw(command --opt value) ]);
+#pod
+#pod like($result->stdout, qr/expected output/, 'printed what we expected');
+#pod
+#pod is($result->stderr, '', 'nothing sent to sderr');
+#pod
+#pod is($result->error, undef, 'threw no exceptions');
+#pod
+#pod my $result = test_app(YourApp => [ qw(command --opt value --quiet) ]);
+#pod
+#pod is($result->output, '', 'absolutely no output with --quiet');
+#pod
+#pod =head1 DESCRIPTION
+#pod
+#pod One of the reasons that user-executed programs are so often poorly tested is
+#pod that they are hard to test. App::Cmd::Tester is one of the tools App-Cmd
+#pod provides to help make it easy to test App::Cmd-based programs.
+#pod
+#pod It provides one routine: test_app.
+#pod
+#pod =method test_app
+#pod
+#pod B<Note>: while C<test_app> is a method, it is by default exported as a
+#pod subroutine into the namespace that uses App::Cmd::Tester. In other words: you
+#pod probably don't need to think about this as a method unless you want to subclass
+#pod App::Cmd::Tester.
+#pod
+#pod my $result = test_app($app_class => \@argv_contents);
+#pod
+#pod This will locally set C<@ARGV> to simulate command line arguments, and will
+#pod then call the C<run> method on the given application class (or application).
+#pod Output to the standard output and standard error filehandles will be captured.
+#pod
+#pod C<$result> is an App::Cmd::Tester::Result object, which has methods to access
+#pod the following data:
+#pod
+#pod stdout - the output sent to stdout
+#pod stderr - the output sent to stderr
+#pod output - the combined output of stdout and stderr
+#pod error - the exception thrown by running the application, or undef
+#pod run_rv - the return value of the run method (generally irrelevant)
+#pod exit_code - the numeric exit code that would've been issued (0 is 'okay')
+#pod
+#pod =cut
use Sub::Exporter::Util qw(curry_method);
use Sub::Exporter -setup => {
@@ -22,6 +70,9 @@ BEGIN {
};
}
+#pod =for Pod::Coverage result_class
+#pod
+#pod =cut
sub result_class { 'App::Cmd::Tester::Result' }
@@ -82,11 +133,8 @@ sub _run_with_capture {
{
package App::Cmd::Tester::Result;
-{
- $App::Cmd::Tester::Result::VERSION = '0.323';
-}
-
- sub new {
+$App::Cmd::Tester::Result::VERSION = '0.324';
+sub new {
my ($class, $arg) = @_;
bless $arg => $class;
}
@@ -101,10 +149,8 @@ sub _run_with_capture {
{
package App::Cmd::Tester::Exited;
-{
- $App::Cmd::Tester::Exited::VERSION = '0.323';
-}
- sub throw {
+$App::Cmd::Tester::Exited::VERSION = '0.324';
+sub throw {
my ($class, $code) = @_;
$code = 0 unless defined $code;
my $self = (bless \$code => $class);
@@ -126,7 +172,7 @@ App::Cmd::Tester - for capturing the result of running an app
=head1 VERSION
-version 0.323
+version 0.324
=head1 SYNOPSIS
@@ -188,7 +234,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -1,4 +1,327 @@
+#pod =head1 DESCRIPTION
+#pod
+#pod App::Cmd is a set of tools designed to make it simple to write sophisticated
+#pod command line programs. It handles commands with multiple subcommands,
+#pod generates usage text, validates options, and lets you write your program as
+#pod easy-to-test classes.
+#pod
+#pod An App::Cmd-based application is made up of three main parts: the script,
+#pod the application class, and the command classes.
+#pod
+#pod =head2 The Script
+#pod
+#pod The script is the actual executable file run at the command line. It can
+#pod generally consist of just a few lines:
+#pod
+#pod #!/usr/bin/perl
+#pod use YourApp;
+#pod YourApp->run;
+#pod
+#pod =head2 The Application Class
+#pod
+#pod All the work of argument parsing, validation, and dispatch is taken care of by
+#pod your application class. The application class can also be pretty simple, and
+#pod might look like this:
+#pod
+#pod package YourApp;
+#pod use App::Cmd::Setup -app;
+#pod 1;
+#pod
+#pod When a new application instance is created, it loads all of the command classes
+#pod it can find, looking for modules under the Command namespace under its own
+#pod name. In the above snippet, for example, YourApp will look for any module with
+#pod a name starting with C<YourApp::Command::>.
+#pod
+#pod =head2 The Command Classes
+#pod
+#pod We can set up a simple command class like this:
+#pod
+#pod # ABSTRACT: set up YourApp
+#pod package YourApp::Command::initialize;
+#pod use YourApp -command;
+#pod 1;
+#pod
+#pod Now, a user can run this command, but he'll get an error:
+#pod
+#pod $ yourcmd initialize
+#pod YourApp::Command::initialize does not implement mandatory method 'execute'
+#pod
+#pod Oops! This dies because we haven't told the command class what it should do
+#pod when executed. This is easy, we just add some code:
+#pod
+#pod sub execute {
+#pod my ($self, $opt, $args) = @_;
+#pod
+#pod print "Everything has been initialized. (Not really.)\n";
+#pod }
+#pod
+#pod Now it works:
+#pod
+#pod $ yourcmd initialize
+#pod Everything has been initialized. (Not really.)
+#pod
+#pod =head2 Default Commands
+#pod
+#pod By default applications made with App::Cmd know two commands: C<commands> and
+#pod C<help>.
+#pod
+#pod =over
+#pod
+#pod =item commands
+#pod
+#pod lists available commands.
+#pod
+#pod $yourcmd commands
+#pod Available commands:
+#pod
+#pod commands: list the application's commands
+#pod help: display a command's help screen
+#pod
+#pod init: set up YourApp
+#pod
+#pod Note that by default the commands receive a description from the C<# ABSTRACT>
+#pod comment in the respective command's module, or from the C<=head1 NAME> Pod
+#pod section.
+#pod
+#pod =item help
+#pod
+#pod allows one to query for details on command's specifics.
+#pod
+#pod $yourcmd help initialize
+#pod yourcmd initialize [-z] [long options...]
+#pod
+#pod -z --zero ignore zeros
+#pod
+#pod Of course, it's possible to disable or change the default commands, see
+#pod L<App::Cmd>.
+#pod
+#pod =back
+#pod
+#pod =head2 Arguments and Options
+#pod
+#pod In this example
+#pod
+#pod $ yourcmd reset -zB --new-seed xyzxy foo.db bar.db
+#pod
+#pod C<-zB> and C<--new-seed xyzxy> are "options" and C<foo.db> and C<bar.db>
+#pod are "arguments."
+#pod
+#pod With a properly configured command class, the above invocation results in
+#pod nicely formatted data:
+#pod
+#pod $opt = {
+#pod zero => 1,
+#pod no_backup => 1, #default value
+#pod new_seed => 'xyzzy',
+#pod };
+#pod
+#pod $args = [ qw(foo.db bar.db) ];
+#pod
+#pod Arguments are processed by L<Getopt::Long::Descriptive> (GLD). To customize
+#pod its argument processing, a command class can implement a few methods:
+#pod C<usage_desc> provides the usage format string; C<opt_spec> provides the option
+#pod specification list; C<validate_args> is run after Getopt::Long::Descriptive,
+#pod and is meant to validate the C<$args>, which GLD ignores. See L<Getopt::Long>
+#pod for format specifications.
+#pod
+#pod The first two methods provide configuration passed to GLD's C<describe_options>
+#pod routine. To improve our command class, we might add the following code:
+#pod
+#pod sub usage_desc { "yourcmd %o [dbfile ...]" }
+#pod
+#pod sub opt_spec {
+#pod return (
+#pod [ "skip-refs|R", "skip reference checks during init", ],
+#pod [ "values|v=s@", "starting values", { default => [ 0, 1, 3 ] } ],
+#pod );
+#pod }
+#pod
+#pod sub validate_args {
+#pod my ($self, $opt, $args) = @_;
+#pod
+#pod # we need at least one argument beyond the options; die with that message
+#pod # and the complete "usage" text describing switches, etc
+#pod $self->usage_error("too few arguments") unless @$args;
+#pod }
+#pod
+#pod =head2 Global Options
+#pod
+#pod There are several ways of making options available everywhere (globally). This
+#pod recipe makes local options accessible in all commands.
+#pod
+#pod To add a C<--help> option to all your commands create a base class like:
+#pod
+#pod package MyApp::Command;
+#pod use App::Cmd::Setup -command;
+#pod
+#pod sub opt_spec {
+#pod my ( $class, $app ) = @_;
+#pod return (
+#pod [ 'help' => "this usage screen" ],
+#pod $class->options($app),
+#pod )
+#pod }
+#pod
+#pod sub validate_args {
+#pod my ( $self, $opt, $args ) = @_;
+#pod if ( $opt->{help} ) {
+#pod my ($command) = $self->command_names;
+#pod $self->app->execute_command(
+#pod $self->app->prepare_command("help", $command)
+#pod );
+#pod exit;
+#pod }
+#pod $self->validate( $opt, $args );
+#pod }
+#pod
+#pod Where C<options> and C<validate> are "inner" methods which your command
+#pod subclasses implement to provide command-specific options and validation.
+#pod
+#pod Note: this is a new file, previously not mentioned in this tutorial and this
+#pod tip does not recommend the use of global_opt_spec which offers an alternative
+#pod way of specifying global options.
+#pod
+#pod =head1 TIPS
+#pod
+#pod =over 4
+#pod
+#pod =item *
+#pod
+#pod Delay using large modules using L<autouse>, L<Class::Autouse> or C<require> in
+#pod your commands to save memory and make startup faster. Since only one of these
+#pod commands will be run anyway, there's no need to preload the requirements for
+#pod all of them.
+#pod
+#pod =item *
+#pod
+#pod Add a C<description> method to your commands for more verbose output
+#pod from the built-in L<help|App::Cmd::Command::help> command.
+#pod
+#pod sub description {
+#pod return "The initialize command prepares ...";
+#pod }
+#pod
+#pod =item *
+#pod
+#pod To let your users configure default values for options, put a sub like
+#pod
+#pod sub config {
+#pod my $app = shift;
+#pod $app->{config} ||= TheLovelyConfigModule->load_config_file();
+#pod }
+#pod
+#pod in your main app file, and then do something like:
+#pod
+#pod package YourApp;
+#pod sub opt_spec {
+#pod my ( $class, $app ) = @_;
+#pod my ( $name ) = $class->command_names;
+#pod return (
+#pod [ 'blort=s' => "That special option",
+#pod { default => $app->config->{$name}{blort} || $fallback_default },
+#pod ],
+#pod );
+#pod }
+#pod
+#pod Or better yet, put this logic in a superclass and process the return value from
+#pod an "inner" method:
+#pod
+#pod package YourApp::Command;
+#pod sub opt_spec {
+#pod my ( $class, $app ) = @_;
+#pod return (
+#pod [ 'help' => "this usage screen" ],
+#pod $class->options($app),
+#pod )
+#pod }
+#pod
+#pod
+#pod =item *
+#pod
+#pod You need to activate C<strict> and C<warnings> as usual if you want them.
+#pod App::Cmd doesn't do that for you.
+#pod
+#pod =back
+#pod
+#pod =head1 IGNORING THINGS
+#pod
+#pod Some people find that for whatever reason, they wish to put Modules in their
+#pod C<MyApp::Command::> namespace which are not commands, or not commands intended
+#pod for use by C<MyApp>.
+#pod
+#pod Good examples include, but are not limited to, things like
+#pod C<MyApp::Command::frobrinate::Plugin::Quietly>, where C<::Quietly> is only
+#pod useful for the C<frobrinate> command.
+#pod
+#pod The default behaviour is to treat such packages as errors, as for the majority
+#pod of use cases, things in C<::Command> are expected to I<only> be commands, and
+#pod thus, anything that, by our heuristics, is not a command, is highly likely to be
+#pod a mistake.
+#pod
+#pod And as all commands are loaded simultaneously, an error in any one of these
+#pod commands will yield a fatal error.
+#pod
+#pod There are a few ways to specify that you are sure you want to do this, with
+#pod varying ranges of scope and complexity.
+#pod
+#pod =head2 Ignoring a Single Module.
+#pod
+#pod This is the simplest approach, and most useful for one-offs.
+#pod
+#pod package YourApp::Command::foo::NotACommand;
+#pod
+#pod use YourApp -ignore;
+#pod
+#pod <whatever you want here>
+#pod
+#pod This will register this package's namespace with YourApp to be excluded from
+#pod its plugin validation magic. It otherwise makes no changes to
+#pod C<::NotACommand>'s namespace, does nothing magical with C<@ISA>, and doesn't
+#pod bolt any hidden functions on.
+#pod
+#pod Its also probably good to notice that it is ignored I<only> by
+#pod C<YourApp>. If for whatever reason you have two different C<App::Cmd> systems
+#pod under which C<::NotACommand> is visible, you'll need to set it ignored to both.
+#pod
+#pod This is probably a big big warning B<NOT> to do that.
+#pod
+#pod =head2 Ignoring Multiple modules from the App level.
+#pod
+#pod If you really fancy it, you can override the C<should_ignore> method provided by
+#pod C<App::Cmd> to tweak its ignore logic. The most useful example of this is as
+#pod follows:
+#pod
+#pod sub should_ignore {
+#pod my ( $self, $command_class ) = @_;
+#pod return 1 if not $command_class->isa( 'App::Cmd::Command' );
+#pod return;
+#pod }
+#pod
+#pod This will prematurely mark for ignoring all packages that don't subclass
+#pod C<App::Cmd::Command>, which causes non-commands ( or perhaps commands that are
+#pod coded wrongly / broken ) to be silently skipped.
+#pod
+#pod Note that by overriding this method, you will lose the effect of any of the
+#pod other ignore mechanisms completely. If you want to combine the original
+#pod C<should_ignore> method with your own logic, you'll want to steal C<Moose>'s
+#pod C<around> method modifier.
+#pod
+#pod use Moose::Util;
+#pod
+#pod Moose::Util::add_method_modifier( __PACKAGE__, 'around', [
+#pod should_ignore => sub {
+#pod my $orig = shift;
+#pod my $self = shift;
+#pod return 1 if not $command_class->isa( 'App::Cmd::Command' );
+#pod return $self->$orig( @_ );
+#pod }]);
+#pod
+#pod =head1 SEE ALSO
+#pod
+#pod L<CPAN modules using App::Cmd|http://deps.cpantesters.org/depended-on-by.pl?module=App%3A%3ACmd>
+#pod
+#pod =cut
# ABSTRACT: getting started with App::Cmd
# PODNAME: App::Cmd::Tutorial
@@ -15,7 +338,7 @@ App::Cmd::Tutorial - getting started with App::Cmd
=head1 VERSION
-version 0.323
+version 0.324
=head1 DESCRIPTION
@@ -344,7 +667,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -3,9 +3,7 @@ use warnings;
use 5.006;
package App::Cmd;
-{
- $App::Cmd::VERSION = '0.323';
-}
+$App::Cmd::VERSION = '0.324';
use App::Cmd::ArgProcessor;
BEGIN { our @ISA = 'App::Cmd::ArgProcessor' };
# ABSTRACT: write command line apps with less suffering
@@ -62,6 +60,95 @@ sub _setup_ignore {
sub _plugin_plugins { return }
+#pod =head1 SYNOPSIS
+#pod
+#pod in F<yourcmd>:
+#pod
+#pod use YourApp;
+#pod YourApp->run;
+#pod
+#pod in F<YourApp.pm>:
+#pod
+#pod package YourApp;
+#pod use App::Cmd::Setup -app;
+#pod 1;
+#pod
+#pod in F<YourApp/Command/blort.pm>:
+#pod
+#pod package YourApp::Command::blort;
+#pod use YourApp -command;
+#pod use strict; use warnings;
+#pod
+#pod sub opt_spec {
+#pod return (
+#pod [ "blortex|X", "use the blortex algorithm" ],
+#pod [ "recheck|r", "recheck all results" ],
+#pod );
+#pod }
+#pod
+#pod sub validate_args {
+#pod my ($self, $opt, $args) = @_;
+#pod
+#pod # no args allowed but options!
+#pod $self->usage_error("No args allowed") if @$args;
+#pod }
+#pod
+#pod sub execute {
+#pod my ($self, $opt, $args) = @_;
+#pod
+#pod my $result = $opt->{blortex} ? blortex() : blort();
+#pod
+#pod recheck($result) if $opt->{recheck};
+#pod
+#pod print $result;
+#pod }
+#pod
+#pod and, finally, at the command line:
+#pod
+#pod knight!rjbs$ yourcmd blort --recheck
+#pod
+#pod All blorts successful.
+#pod
+#pod =head1 DESCRIPTION
+#pod
+#pod App::Cmd is intended to make it easy to write complex command-line applications
+#pod without having to think about most of the annoying things usually involved.
+#pod
+#pod For information on how to start using App::Cmd, see L<App::Cmd::Tutorial>.
+#pod
+#pod =method new
+#pod
+#pod my $cmd = App::Cmd->new(\%arg);
+#pod
+#pod This method returns a new App::Cmd object. During initialization, command
+#pod plugins will be loaded.
+#pod
+#pod Valid arguments are:
+#pod
+#pod no_commands_plugin - if true, the command list plugin is not added
+#pod
+#pod no_help_plugin - if true, the help plugin is not added
+#pod
+#pod no_version_plugin - if true, the version plugin is not added
+#pod
+#pod plugin_search_path - The path to search for commands in. Defaults to
+#pod results of plugin_search_path method
+#pod
+#pod If C<no_commands_plugin> is not given, L<App::Cmd::Command::commands> will be
+#pod required, and it will be registered to handle all of its command names not
+#pod handled by other plugins.
+#pod
+#pod If C<no_help_plugin> is not given, L<App::Cmd::Command::help> will be required,
+#pod and it will be registered to handle all of its command names not handled by
+#pod other plugins. B<Note:> "help" is the default command, so if you do not load
+#pod the default help plugin, you should provide your own or override the
+#pod C<default_command> method.
+#pod
+#pod If C<no_version_plugin> is not given, L<App::Cmd::Command::version> will be
+#pod required to show the application's version with command C<--version>. The
+#pod version command is not included in the command list.
+#pod
+#pod =cut
sub new {
my ($class, $arg) = @_;
@@ -195,6 +282,21 @@ sub _load_default_plugin {
}
}
+#pod =method run
+#pod
+#pod $cmd->run;
+#pod
+#pod This method runs the application. If called the class, it will instantiate a
+#pod new App::Cmd object to run.
+#pod
+#pod It determines the requested command (generally by consuming the first
+#pod command-line argument), finds the plugin to handle that command, parses the
+#pod remaining arguments according to that plugin's rules, and runs the plugin.
+#pod
+#pod It passes the contents of the global argument array (C<@ARGV>) to
+#pod L</C<prepare_command>>, but C<@ARGV> is not altered by running an App::Cmd.
+#pod
+#pod =cut
sub run {
my ($self) = @_;
@@ -210,6 +312,12 @@ sub run {
$self->execute_command($cmd, $opt, @args);
}
+#pod =method prepare_args
+#pod
+#pod Normally App::Cmd uses C<@ARGV> for its commandline arguments. You can override
+#pod this method to change that behavior for testing or otherwise.
+#pod
+#pod =cut
sub prepare_args {
my ($self) = @_;
@@ -218,13 +326,55 @@ sub prepare_args {
: (@{$self->default_args});
}
+#pod =method default_args
+#pod
+#pod If C<L</prepare_args>> is not changed and there are no arguments in C<@ARGV>,
+#pod this method is called and should return an arrayref to be used as the arguments
+#pod to the program. By default, it returns an empty arrayref.
+#pod
+#pod =cut
use constant default_args => [];
+#pod =method arg0
+#pod
+#pod =method full_arg0
+#pod
+#pod my $program_name = $app->arg0;
+#pod
+#pod my $full_program_name = $app->full_arg0;
+#pod
+#pod These methods return the name of the program invoked to run this application.
+#pod This is determined by inspecting C<$0> when the App::Cmd object is
+#pod instantiated, so it's probably correct, but doing weird things with App::Cmd
+#pod could lead to weird values from these methods.
+#pod
+#pod If the program was run like this:
+#pod
+#pod knight!rjbs$ ~/bin/rpg dice 3d6
+#pod
+#pod Then the methods return:
+#pod
+#pod arg0 - rpg
+#pod full_arg0 - /Users/rjbs/bin/rpg
+#pod
+#pod These values are captured when the App::Cmd object is created, so it is safe to
+#pod assign to C<$0> later.
+#pod
+#pod =cut
sub arg0 { $_[0]->{arg0} }
sub full_arg0 { $_[0]->{full_arg0} }
+#pod =method prepare_command
+#pod
+#pod my ($cmd, $opt, @args) = $app->prepare_command(@ARGV);
+#pod
+#pod This method will load the plugin for the requested command, use its options to
+#pod parse the command line arguments, and eventually return everything necessary to
+#pod actually execute the command.
+#pod
+#pod =cut
sub prepare_command {
my ($self, @args) = @_;
@@ -269,9 +419,22 @@ sub _bad_command {
END { exit 1 if our $_bad };
+#pod =method default_command
+#pod
+#pod This method returns the name of the command to run if none is given on the
+#pod command line. The default default is "help"
+#pod
+#pod =cut
sub default_command { "help" }
+#pod =method execute_command
+#pod
+#pod $app->execute_command($cmd, \%opt, @args);
+#pod
+#pod This method will invoke C<validate_args> and then C<run> on C<$cmd>.
+#pod
+#pod =cut
sub execute_command {
my ($self, $cmd, $opt, @args) = @_;
@@ -282,6 +445,16 @@ sub execute_command {
$cmd->execute($opt, \@args);
}
+#pod =method plugin_search_path
+#pod
+#pod This method returns the plugin_search_path as set. The default implementation,
+#pod if called on "YourApp::Cmd" will return "YourApp::Cmd::Command"
+#pod
+#pod This is a method because it's fun to override it with, for example:
+#pod
+#pod use constant plugin_search_path => __PACKAGE__;
+#pod
+#pod =cut
sub _default_command_base {
my ($self) = @_;
@@ -312,9 +485,31 @@ sub plugin_search_path {
}
}
+#pod =method allow_any_unambiguous_abbrev
+#pod
+#pod If this method returns true (which, by default, it does I<not>), then any
+#pod unambiguous abbreviation for a registered command name will be allowed as a
+#pod means to use that command. For example, given the following commands:
+#pod
+#pod reticulate
+#pod reload
+#pod rasterize
+#pod
+#pod Then the user could use C<ret> for C<reticulate> or C<ra> for C<rasterize> and
+#pod so on.
+#pod
+#pod =cut
sub allow_any_unambiguous_abbrev { return 0 }
+#pod =method global_options
+#pod
+#pod if ($cmd->app->global_options->{verbose}) { ... }
+#pod
+#pod This method returns the running application's global options as a hashref. If
+#pod there are no options specified, an empty hashref is returned.
+#pod
+#pod =cut
sub global_options {
my $self = shift;
@@ -322,18 +517,40 @@ sub global_options {
return {};
}
+#pod =method set_global_options
+#pod
+#pod $app->set_global_options(\%opt);
+#pod
+#pod This method sets the global options.
+#pod
+#pod =cut
sub set_global_options {
my ($self, $opt) = @_;
return $self->{global_options} = $opt;
}
+#pod =method command_names
+#pod
+#pod my @names = $cmd->command_names;
+#pod
+#pod This returns the commands names which the App::Cmd object will handle.
+#pod
+#pod =cut
sub command_names {
my ($self) = @_;
keys %{ $self->_command };
}
+#pod =method command_plugins
+#pod
+#pod my @plugins = $cmd->command_plugins;
+#pod
+#pod This method returns the package names of the plugins that implement the
+#pod App::Cmd object's commands.
+#pod
+#pod =cut
sub command_plugins {
my ($self) = @_;
@@ -341,6 +558,14 @@ sub command_plugins {
keys %seen;
}
+#pod =method plugin_for
+#pod
+#pod my $plugin = $cmd->plugin_for($command);
+#pod
+#pod This method returns the plugin (module) for the given command. If no plugin
+#pod implements the command, it returns false.
+#pod
+#pod =cut
sub plugin_for {
my ($self, $command) = @_;
@@ -350,6 +575,13 @@ sub plugin_for {
return $self->_command->{ $command };
}
+#pod =method get_command
+#pod
+#pod my ($command_name, $opt, @args) = $app->get_command(@args);
+#pod
+#pod Process arguments and into a command name and (optional) global options.
+#pod
+#pod =cut
sub get_command {
my ($self, @args) = @_;
@@ -381,21 +613,48 @@ sub _global_option_processing_params {
);
}
+#pod =method usage
+#pod
+#pod print $self->app->usage->text;
+#pod
+#pod Returns the usage object for the global options.
+#pod
+#pod =cut
sub usage { $_[0]{usage} };
+#pod =method usage_desc
+#pod
+#pod The top level usage line. Looks something like
+#pod
+#pod "yourapp <command> [options]"
+#pod
+#pod =cut
sub usage_desc {
# my ($self) = @_; # no point in creating these ops, just to toss $self
return "%c <command> %o";
}
+#pod =method global_opt_spec
+#pod
+#pod Returns an empty list. Can be overridden for pre-dispatch option processing.
+#pod This is useful for flags like --verbose.
+#pod
+#pod =cut
sub global_opt_spec {
# my ($self) = @_; # no point in creating these ops, just to toss $self
return;
}
+#pod =method usage_error
+#pod
+#pod $self->usage_error("Something's wrong!");
+#pod
+#pod Used to die with nice usage output, during C<validate_args>.
+#pod
+#pod =cut
sub usage_error {
my ($self, $error) = @_;
@@ -409,6 +668,14 @@ sub _usage_text {
return $text;
}
+#pod =head1 TODO
+#pod
+#pod =for :list
+#pod * publish and bring in Log::Speak (simple quiet/verbose output)
+#pod * publish and use our internal enhanced describe_options
+#pod * publish and use our improved simple input routines
+#pod
+#pod =cut
1;
@@ -424,7 +691,7 @@ App::Cmd - write command line apps with less suffering
=head1 VERSION
-version 0.323
+version 0.324
=head1 SYNOPSIS
@@ -693,7 +960,7 @@ Ricardo Signes <rjbs@cpan.org>
=head1 COPYRIGHT AND LICENSE
-This software is copyright (c) 2013 by Ricardo Signes.
+This software is copyright (c) 2014 by Ricardo Signes.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
@@ -53,7 +53,7 @@ eval { $v .= pmver('Carp','any version') };
eval { $v .= pmver('Class::Load','0.06') };
eval { $v .= pmver('Data::Dumper','any version') };
eval { $v .= pmver('Data::OptList','any version') };
-eval { $v .= pmver('ExtUtils::MakeMaker','6.30') };
+eval { $v .= pmver('ExtUtils::MakeMaker','any version') };
eval { $v .= pmver('File::Basename','any version') };
eval { $v .= pmver('Getopt::Long','2.39') };
eval { $v .= pmver('Getopt::Long::Descriptive','0.084') };
@@ -4,7 +4,7 @@ use Test::More tests => 2;
note 'Checking Changes';
my $changes_file = 'Changes';
-my $newver = '0.323';
+my $newver = '0.324';
my $trial_token = '-TRIAL';
SKIP: {
@@ -1,7 +1,6 @@
#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests.
use Test::More;
-
-eval "use Test::Pod 1.41";
-plan skip_all => "Test::Pod 1.41 required for testing POD" if $@;
+use Test::Pod 1.41;
all_pod_files_ok();