summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2014-04-29 19:39:41 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2014-04-29 19:39:41 +0000
commitb0ac2743153dd707789f7541af790f5a53843a36 (patch)
tree229984bf86661cccdd353248e7a6ef2211e2a138
downloadTry-Tiny-tarball-master.tar.gz
-rw-r--r--Changes89
-rw-r--r--LICENSE32
-rw-r--r--MANIFEST26
-rw-r--r--META.json492
-rw-r--r--META.yml358
-rw-r--r--Makefile.PL70
-rw-r--r--README16
-rw-r--r--dist.ini30
-rw-r--r--lib/Try/Tiny.pm677
-rw-r--r--maint/bench.pl14
-rw-r--r--t/00-compile.t50
-rw-r--r--t/basic.t166
-rw-r--r--t/context.t71
-rw-r--r--t/erroneous_usage.t77
-rw-r--r--t/finally.t131
-rw-r--r--t/given_when.t40
-rw-r--r--t/global_destruction_forked.t57
-rw-r--r--t/global_destruction_load.t18
-rw-r--r--t/lib/TryUser.pm9
-rw-r--r--t/named.t37
-rw-r--r--t/when.t37
-rw-r--r--xt/release/eol.t8
-rw-r--r--xt/release/no-tabs.t25
-rw-r--r--xt/release/pod-coverage.t7
-rw-r--r--xt/release/pod-syntax.t6
25 files changed, 2543 insertions, 0 deletions
diff --git a/Changes b/Changes
new file mode 100644
index 0000000..05a5051
--- /dev/null
+++ b/Changes
@@ -0,0 +1,89 @@
+Revision history for Try-Tiny
+
+0.22 2014-04-29
+ - add optional test deps as recommended prereqs (Karen Etheridge, #18)
+
+0.21 2014-04-15
+ - also skip the test if Capture::Tiny is too old (Martin Popel, #17)
+
+0.20 2014-03-21
+ - documentation updates (Flimm, #15)
+
+0.19 2014-01-22
+ - fix an obscure issue with loading modules during global destruction
+ (ilmari, #11)
+ - documentation updates (anaxagoras, #12)
+
+0.18 2013-08-17
+ - fix tests for pre-Test-More-0.88 (Paul Howarth, #10)
+
+0.17 2013-08-16
+ - work around [rt.perl #119311] which was causing incorrect error messages in
+ some cases during global destruction (Graham Knop, #9)
+
+0.16 2013-07-10
+ - remove accidental Sub::Name test dep
+
+0.15 2013-07-08
+ - optionally use Sub::Name to name the try/catch/finally blocks, if available
+ (Mark Fowler)
+
+0.14 2013-07-05
+ - also throw an exception for catch/finally in scalar context (RT#81070)
+
+0.13 2013-07-04
+ - fix tests failing on 5.6.x due to differing DESTROY semantics
+ - excise superfluous local($@) call - 7% speedup
+ - fix (fsvo) broken URLs (RT#55659)
+ - proper exception on erroneous usage of bare catch/finally (RT#81070)
+ - proper exception on erroneous use of multiple catch{} blocks
+ - clarify exception occuring on unterminated try block (RT#75712)
+ - fix the prototypes shown in docs to match code (RT#79590; thanks, Pushtaev
+ Vadim)
+ - warn loudly on exceptions in finally() blocks
+ - dzilify
+
+0.12 2013-01-02
+ - doc fixes
+
+0.11 2011-08-30
+ - fix broken dist
+
+0.10 2011-04-27
+ - clarify some docs
+
+0.09 2010-11-28
+ - don't index Try::Tiny::ScopeGuard
+
+0.08 2010-11-28
+ - fix require vs use issue in blead (RT63410)
+
+0.07 2010-10-21
+ - allow multiple finally blocks
+ - pass the error, if any, to finally blocks when called
+
+0.06 2010-05-27
+ - in t/given_when.t use a plan instead of done_testing for more backwards
+ compatibility
+
+0.05 2010-05-26
+ - Documentation fixes and clarifications
+
+0.04 2010-01-22
+ - Restore list context propagation for catch blocks
+ - Fix a bug where finally blocks weren't always invoked
+
+0.03 2010-01-22
+ - Support for 'finally' blocks (Andy Yates)
+ - More documentation and tests (many people)
+ - Sets $@ to the previous value at the beginning of the eval, to allow
+ the capture of an error stack when calling die.
+
+0.02 2009-09-02
+ - Doc fixes from chromatic
+ - Various minor fixes from Adam Kennedy
+ - Additional documentation and code clarifications
+ - 5.005_04 compatibility
+
+0.01 2009-08-31
+ - Initial release
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..8d4141c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,32 @@
+This software is Copyright (c) 2014 by Yuval Kogman.
+
+This is free software, licensed under:
+
+ The MIT (X11) License
+
+The MIT License
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to
+whom the Software is furnished to do so, subject to the
+following conditions:
+
+The above copyright notice and this permission notice shall
+be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT
+WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/MANIFEST b/MANIFEST
new file mode 100644
index 0000000..56994ad
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,26 @@
+# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.014.
+Changes
+LICENSE
+MANIFEST
+META.json
+META.yml
+Makefile.PL
+README
+dist.ini
+lib/Try/Tiny.pm
+maint/bench.pl
+t/00-compile.t
+t/basic.t
+t/context.t
+t/erroneous_usage.t
+t/finally.t
+t/given_when.t
+t/global_destruction_forked.t
+t/global_destruction_load.t
+t/lib/TryUser.pm
+t/named.t
+t/when.t
+xt/release/eol.t
+xt/release/no-tabs.t
+xt/release/pod-coverage.t
+xt/release/pod-syntax.t
diff --git a/META.json b/META.json
new file mode 100644
index 0000000..7464c6e
--- /dev/null
+++ b/META.json
@@ -0,0 +1,492 @@
+{
+ "abstract" : "minimal try/catch with proper preservation of $@",
+ "author" : [
+ "Yuval Kogman <nothingmuch@woobling.org>",
+ "Jesse Luehrs <doy@tozt.net>"
+ ],
+ "dynamic_config" : 0,
+ "generated_by" : "Dist::Zilla version 5.014, CPAN::Meta::Converter version 2.140640",
+ "license" : [
+ "mit"
+ ],
+ "meta-spec" : {
+ "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
+ "version" : "2"
+ },
+ "name" : "Try-Tiny",
+ "prereqs" : {
+ "configure" : {
+ "requires" : {
+ "ExtUtils::MakeMaker" : "6.30"
+ }
+ },
+ "develop" : {
+ "requires" : {
+ "Pod::Coverage::TrustPod" : "0",
+ "Test::More" : "0",
+ "Test::NoTabs" : "0",
+ "Test::Pod" : "1.41",
+ "Test::Pod::Coverage" : "1.08"
+ }
+ },
+ "runtime" : {
+ "requires" : {
+ "Carp" : "0",
+ "Exporter" : "5.57",
+ "constant" : "0",
+ "perl" : "5.006",
+ "strict" : "0",
+ "warnings" : "0"
+ }
+ },
+ "test" : {
+ "recommends" : {
+ "Capture::Tiny" : "0.12",
+ "Sub::Name" : "0",
+ "perl" : "5.010"
+ },
+ "requires" : {
+ "File::Spec" : "0",
+ "IO::Handle" : "0",
+ "IPC::Open3" : "0",
+ "Test::More" : "0",
+ "if" : "0"
+ }
+ }
+ },
+ "provides" : {
+ "Try::Tiny" : {
+ "file" : "lib/Try/Tiny.pm",
+ "version" : "0.22"
+ }
+ },
+ "release_status" : "stable",
+ "resources" : {
+ "bugtracker" : {
+ "web" : "https://github.com/doy/try-tiny/issues"
+ },
+ "homepage" : "http://metacpan.org/release/Try-Tiny",
+ "repository" : {
+ "type" : "git",
+ "url" : "git://github.com/doy/try-tiny.git",
+ "web" : "https://github.com/doy/try-tiny"
+ }
+ },
+ "version" : "0.22",
+ "x_Dist_Zilla" : {
+ "perl" : {
+ "version" : "5.018002"
+ },
+ "plugins" : [
+ {
+ "class" : "Dist::Zilla::Plugin::GatherDir",
+ "name" : "@DOY/GatherDir",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::PruneCruft",
+ "name" : "@DOY/PruneCruft",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::ManifestSkip",
+ "name" : "@DOY/ManifestSkip",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::MetaYAML",
+ "name" : "@DOY/MetaYAML",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::License",
+ "name" : "@DOY/License",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::Readme",
+ "name" : "@DOY/Readme",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::RunExtraTests",
+ "config" : {
+ "Dist::Zilla::Role::TestRunner" : {
+ "default_jobs" : 1
+ }
+ },
+ "name" : "@DOY/RunExtraTests",
+ "version" : "0.018"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::ExecDir",
+ "name" : "@DOY/ExecDir",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::ShareDir",
+ "name" : "@DOY/ShareDir",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::MakeMaker",
+ "config" : {
+ "Dist::Zilla::Role::TestRunner" : {
+ "default_jobs" : 1
+ }
+ },
+ "name" : "@DOY/MakeMaker",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::Manifest",
+ "name" : "@DOY/Manifest",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::TestRelease",
+ "name" : "@DOY/TestRelease",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::ConfirmRelease",
+ "name" : "@DOY/ConfirmRelease",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::MetaConfig",
+ "name" : "@DOY/MetaConfig",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::MetaJSON",
+ "name" : "@DOY/MetaJSON",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::NextRelease",
+ "name" : "@DOY/NextRelease",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::CheckChangesHasContent",
+ "name" : "@DOY/CheckChangesHasContent",
+ "version" : "0.006"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::PkgVersion",
+ "name" : "@DOY/PkgVersion",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::Authority",
+ "name" : "@DOY/Authority",
+ "version" : "1.006"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::PodCoverageTests",
+ "name" : "@DOY/PodCoverageTests",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::PodSyntaxTests",
+ "name" : "@DOY/PodSyntaxTests",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::NoTabsTests",
+ "config" : {
+ "Dist::Zilla::Plugin::Test::NoTabs" : {
+ "module_finder" : [
+ ":InstallModules"
+ ],
+ "script_finder" : [
+ ":ExecFiles",
+ ":TestFiles"
+ ]
+ }
+ },
+ "name" : "@DOY/NoTabsTests",
+ "version" : "0.07"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::EOLTests",
+ "name" : "@DOY/EOLTests",
+ "version" : "0.02"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::Test::Compile",
+ "config" : {
+ "Dist::Zilla::Plugin::Test::Compile" : {
+ "filename" : "t/00-compile.t",
+ "module_finder" : [
+ ":InstallModules"
+ ],
+ "script_finder" : [
+ ":ExecFiles"
+ ]
+ }
+ },
+ "name" : "@DOY/Test::Compile",
+ "version" : "2.039"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::Metadata",
+ "name" : "@DOY/Metadata",
+ "version" : "3.03"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::MetaResources",
+ "name" : "@DOY/MetaResources",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::Git::Check",
+ "name" : "@DOY/Git::Check",
+ "version" : "2.020"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::Git::Commit",
+ "name" : "@DOY/Git::Commit",
+ "version" : "2.020"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::Git::Tag",
+ "name" : "@DOY/Git::Tag",
+ "version" : "2.020"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::Git::NextVersion",
+ "name" : "@DOY/Git::NextVersion",
+ "version" : "2.020"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::ContributorsFromGit",
+ "name" : "@DOY/ContributorsFromGit",
+ "version" : "0.006"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::MetaProvides::Package",
+ "config" : {
+ "Dist::Zilla::Plugin::MetaProvides::Package" : {
+ "finder_objects" : [
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : "@DOY/MetaProvides::Package/AUTOVIV/:InstallModulesPM",
+ "version" : "5.014"
+ }
+ ]
+ },
+ "Dist::Zilla::Role::MetaProvider::Provider" : {
+ "inherit_missing" : "1",
+ "inherit_version" : "1",
+ "meta_noindex" : "1"
+ }
+ },
+ "name" : "@DOY/MetaProvides::Package",
+ "version" : "2.000001"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::PodWeaver",
+ "config" : {
+ "Dist::Zilla::Plugin::PodWeaver" : {
+ "finder" : [
+ ":InstallModules",
+ ":ExecFiles"
+ ],
+ "plugins" : [
+ {
+ "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::Plugin::SingleEncoding",
+ "name" : "@Default/SingleEncoding",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Name",
+ "name" : "@Default/Name",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Version",
+ "name" : "@Default/Version",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Region",
+ "name" : "@Default/prelude",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Generic",
+ "name" : "SYNOPSIS",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Generic",
+ "name" : "DESCRIPTION",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Generic",
+ "name" : "OVERVIEW",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Collect",
+ "name" : "ATTRIBUTES",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Collect",
+ "name" : "METHODS",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Collect",
+ "name" : "FUNCTIONS",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Leftovers",
+ "name" : "@Default/Leftovers",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Region",
+ "name" : "@Default/postlude",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Authors",
+ "name" : "@Default/Authors",
+ "version" : "4.006"
+ },
+ {
+ "class" : "Pod::Weaver::Section::Legal",
+ "name" : "@Default/Legal",
+ "version" : "4.006"
+ }
+ ]
+ }
+ },
+ "name" : "@DOY/PodWeaver",
+ "version" : "4.005"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::UploadToCPAN",
+ "name" : "@DOY/UploadToCPAN",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::AutoPrereqs",
+ "name" : "AutoPrereqs",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::Prereqs",
+ "config" : {
+ "Dist::Zilla::Plugin::Prereqs" : {
+ "phase" : "runtime",
+ "type" : "requires"
+ }
+ },
+ "name" : "Prereqs",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::Prereqs",
+ "config" : {
+ "Dist::Zilla::Plugin::Prereqs" : {
+ "phase" : "test",
+ "type" : "recommends"
+ }
+ },
+ "name" : "TestRecommends",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":InstallModules",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":IncModules",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":TestFiles",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":ExecFiles",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":ShareFiles",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":MainModule",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":AllFiles",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : ":NoFiles",
+ "version" : "5.014"
+ },
+ {
+ "class" : "Dist::Zilla::Plugin::FinderCode",
+ "name" : "@DOY/MetaProvides::Package/AUTOVIV/:InstallModulesPM",
+ "version" : "5.014"
+ }
+ ],
+ "zilla" : {
+ "class" : "Dist::Zilla::Dist::Builder",
+ "config" : {
+ "is_trial" : "0"
+ },
+ "version" : "5.014"
+ }
+ },
+ "x_authority" : "cpan:NUFFIN",
+ "x_contributors" : [
+ "Alex <alex@koban.(none)>",
+ "Andrew Yates <ayates@haddock.local>",
+ "Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>",
+ "David Lowe <davidl@lokku.com>",
+ "Glenn Fowler <cebjyre@cpan.org>",
+ "Graham Knop <haarg@haarg.org>",
+ "Hans Dieter Pearcey <hdp@weftsoar.net>",
+ "Jonathan Yu <JAWNSY@cpan.org>",
+ "Karen Etheridge <ether@cpan.org>",
+ "Marc Mims <marc@questright.com>",
+ "Mark Fowler <mark@twoshortplanks.com>",
+ "Mark Stosberg <mark@stosberg.com>",
+ "Paul Howarth <paul@city-fan.org>",
+ "Peter Rabbitson <ribasushi@cpan.org>",
+ "Ricardo Signes <rjbs@cpan.org>",
+ "anaxagoras <walkeraj@gmail.com>",
+ "awalker <awalker@sourcefire.com>",
+ "chromatic <chromatic@wgz.org>"
+ ]
+}
+
diff --git a/META.yml b/META.yml
new file mode 100644
index 0000000..1c9bbde
--- /dev/null
+++ b/META.yml
@@ -0,0 +1,358 @@
+---
+abstract: 'minimal try/catch with proper preservation of $@'
+author:
+ - 'Yuval Kogman <nothingmuch@woobling.org>'
+ - 'Jesse Luehrs <doy@tozt.net>'
+build_requires:
+ File::Spec: '0'
+ IO::Handle: '0'
+ IPC::Open3: '0'
+ Test::More: '0'
+ if: '0'
+configure_requires:
+ ExtUtils::MakeMaker: '6.30'
+dynamic_config: 0
+generated_by: 'Dist::Zilla version 5.014, CPAN::Meta::Converter version 2.140640'
+license: mit
+meta-spec:
+ url: http://module-build.sourceforge.net/META-spec-v1.4.html
+ version: '1.4'
+name: Try-Tiny
+provides:
+ Try::Tiny:
+ file: lib/Try/Tiny.pm
+ version: '0.22'
+requires:
+ Carp: '0'
+ Exporter: '5.57'
+ constant: '0'
+ perl: '5.006'
+ strict: '0'
+ warnings: '0'
+resources:
+ bugtracker: https://github.com/doy/try-tiny/issues
+ homepage: http://metacpan.org/release/Try-Tiny
+ repository: git://github.com/doy/try-tiny.git
+version: '0.22'
+x_Dist_Zilla:
+ perl:
+ version: '5.018002'
+ plugins:
+ -
+ class: Dist::Zilla::Plugin::GatherDir
+ name: '@DOY/GatherDir'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::PruneCruft
+ name: '@DOY/PruneCruft'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::ManifestSkip
+ name: '@DOY/ManifestSkip'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::MetaYAML
+ name: '@DOY/MetaYAML'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::License
+ name: '@DOY/License'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::Readme
+ name: '@DOY/Readme'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::RunExtraTests
+ config:
+ Dist::Zilla::Role::TestRunner:
+ default_jobs: 1
+ name: '@DOY/RunExtraTests'
+ version: '0.018'
+ -
+ class: Dist::Zilla::Plugin::ExecDir
+ name: '@DOY/ExecDir'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::ShareDir
+ name: '@DOY/ShareDir'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::MakeMaker
+ config:
+ Dist::Zilla::Role::TestRunner:
+ default_jobs: 1
+ name: '@DOY/MakeMaker'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::Manifest
+ name: '@DOY/Manifest'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::TestRelease
+ name: '@DOY/TestRelease'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::ConfirmRelease
+ name: '@DOY/ConfirmRelease'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::MetaConfig
+ name: '@DOY/MetaConfig'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::MetaJSON
+ name: '@DOY/MetaJSON'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::NextRelease
+ name: '@DOY/NextRelease'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::CheckChangesHasContent
+ name: '@DOY/CheckChangesHasContent'
+ version: '0.006'
+ -
+ class: Dist::Zilla::Plugin::PkgVersion
+ name: '@DOY/PkgVersion'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::Authority
+ name: '@DOY/Authority'
+ version: '1.006'
+ -
+ class: Dist::Zilla::Plugin::PodCoverageTests
+ name: '@DOY/PodCoverageTests'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::PodSyntaxTests
+ name: '@DOY/PodSyntaxTests'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::NoTabsTests
+ config:
+ Dist::Zilla::Plugin::Test::NoTabs:
+ module_finder:
+ - ':InstallModules'
+ script_finder:
+ - ':ExecFiles'
+ - ':TestFiles'
+ name: '@DOY/NoTabsTests'
+ version: '0.07'
+ -
+ class: Dist::Zilla::Plugin::EOLTests
+ name: '@DOY/EOLTests'
+ version: '0.02'
+ -
+ class: Dist::Zilla::Plugin::Test::Compile
+ config:
+ Dist::Zilla::Plugin::Test::Compile:
+ filename: t/00-compile.t
+ module_finder:
+ - ':InstallModules'
+ script_finder:
+ - ':ExecFiles'
+ name: '@DOY/Test::Compile'
+ version: '2.039'
+ -
+ class: Dist::Zilla::Plugin::Metadata
+ name: '@DOY/Metadata'
+ version: '3.03'
+ -
+ class: Dist::Zilla::Plugin::MetaResources
+ name: '@DOY/MetaResources'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::Git::Check
+ name: '@DOY/Git::Check'
+ version: '2.020'
+ -
+ class: Dist::Zilla::Plugin::Git::Commit
+ name: '@DOY/Git::Commit'
+ version: '2.020'
+ -
+ class: Dist::Zilla::Plugin::Git::Tag
+ name: '@DOY/Git::Tag'
+ version: '2.020'
+ -
+ class: Dist::Zilla::Plugin::Git::NextVersion
+ name: '@DOY/Git::NextVersion'
+ version: '2.020'
+ -
+ class: Dist::Zilla::Plugin::ContributorsFromGit
+ name: '@DOY/ContributorsFromGit'
+ version: '0.006'
+ -
+ class: Dist::Zilla::Plugin::MetaProvides::Package
+ config:
+ Dist::Zilla::Plugin::MetaProvides::Package:
+ finder_objects:
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: '@DOY/MetaProvides::Package/AUTOVIV/:InstallModulesPM'
+ version: '5.014'
+ Dist::Zilla::Role::MetaProvider::Provider:
+ inherit_missing: '1'
+ inherit_version: '1'
+ meta_noindex: '1'
+ name: '@DOY/MetaProvides::Package'
+ version: '2.000001'
+ -
+ class: Dist::Zilla::Plugin::PodWeaver
+ config:
+ Dist::Zilla::Plugin::PodWeaver:
+ finder:
+ - ':InstallModules'
+ - ':ExecFiles'
+ plugins:
+ -
+ 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::Plugin::SingleEncoding
+ name: '@Default/SingleEncoding'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Name
+ name: '@Default/Name'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Version
+ name: '@Default/Version'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Region
+ name: '@Default/prelude'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Generic
+ name: SYNOPSIS
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Generic
+ name: DESCRIPTION
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Generic
+ name: OVERVIEW
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Collect
+ name: ATTRIBUTES
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Collect
+ name: METHODS
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Collect
+ name: FUNCTIONS
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Leftovers
+ name: '@Default/Leftovers'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Region
+ name: '@Default/postlude'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Authors
+ name: '@Default/Authors'
+ version: '4.006'
+ -
+ class: Pod::Weaver::Section::Legal
+ name: '@Default/Legal'
+ version: '4.006'
+ name: '@DOY/PodWeaver'
+ version: '4.005'
+ -
+ class: Dist::Zilla::Plugin::UploadToCPAN
+ name: '@DOY/UploadToCPAN'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::AutoPrereqs
+ name: AutoPrereqs
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::Prereqs
+ config:
+ Dist::Zilla::Plugin::Prereqs:
+ phase: runtime
+ type: requires
+ name: Prereqs
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::Prereqs
+ config:
+ Dist::Zilla::Plugin::Prereqs:
+ phase: test
+ type: recommends
+ name: TestRecommends
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':InstallModules'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':IncModules'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':TestFiles'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':ExecFiles'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':ShareFiles'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':MainModule'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':AllFiles'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: ':NoFiles'
+ version: '5.014'
+ -
+ class: Dist::Zilla::Plugin::FinderCode
+ name: '@DOY/MetaProvides::Package/AUTOVIV/:InstallModulesPM'
+ version: '5.014'
+ zilla:
+ class: Dist::Zilla::Dist::Builder
+ config:
+ is_trial: '0'
+ version: '5.014'
+x_authority: cpan:NUFFIN
+x_contributors:
+ - 'Alex <alex@koban.(none)>'
+ - 'Andrew Yates <ayates@haddock.local>'
+ - 'Dagfinn Ilmari Mannsåker <ilmari@ilmari.org>'
+ - 'David Lowe <davidl@lokku.com>'
+ - 'Glenn Fowler <cebjyre@cpan.org>'
+ - 'Graham Knop <haarg@haarg.org>'
+ - 'Hans Dieter Pearcey <hdp@weftsoar.net>'
+ - 'Jonathan Yu <JAWNSY@cpan.org>'
+ - 'Karen Etheridge <ether@cpan.org>'
+ - 'Marc Mims <marc@questright.com>'
+ - 'Mark Fowler <mark@twoshortplanks.com>'
+ - 'Mark Stosberg <mark@stosberg.com>'
+ - 'Paul Howarth <paul@city-fan.org>'
+ - 'Peter Rabbitson <ribasushi@cpan.org>'
+ - 'Ricardo Signes <rjbs@cpan.org>'
+ - 'anaxagoras <walkeraj@gmail.com>'
+ - 'awalker <awalker@sourcefire.com>'
+ - 'chromatic <chromatic@wgz.org>'
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644
index 0000000..521700b
--- /dev/null
+++ b/Makefile.PL
@@ -0,0 +1,70 @@
+
+# This file was automatically generated by Dist::Zilla::Plugin::MakeMaker v5.014.
+use strict;
+use warnings;
+
+use 5.006;
+
+use ExtUtils::MakeMaker 6.30;
+
+
+
+my %WriteMakefileArgs = (
+ "ABSTRACT" => "minimal try/catch with proper preservation of \$\@",
+ "AUTHOR" => "Yuval Kogman <nothingmuch\@woobling.org>, Jesse Luehrs <doy\@tozt.net>",
+ "BUILD_REQUIRES" => {},
+ "CONFIGURE_REQUIRES" => {
+ "ExtUtils::MakeMaker" => "6.30"
+ },
+ "DISTNAME" => "Try-Tiny",
+ "EXE_FILES" => [],
+ "LICENSE" => "mit",
+ "NAME" => "Try::Tiny",
+ "PREREQ_PM" => {
+ "Carp" => 0,
+ "Exporter" => "5.57",
+ "constant" => 0,
+ "strict" => 0,
+ "warnings" => 0
+ },
+ "TEST_REQUIRES" => {
+ "File::Spec" => 0,
+ "IO::Handle" => 0,
+ "IPC::Open3" => 0,
+ "Test::More" => 0,
+ "if" => 0
+ },
+ "VERSION" => "0.22",
+ "test" => {
+ "TESTS" => "t/*.t"
+ }
+);
+
+
+my %FallbackPrereqs = (
+ "Carp" => 0,
+ "Exporter" => "5.57",
+ "File::Spec" => 0,
+ "IO::Handle" => 0,
+ "IPC::Open3" => 0,
+ "Test::More" => 0,
+ "constant" => 0,
+ "if" => 0,
+ "strict" => 0,
+ "warnings" => 0
+);
+
+
+unless ( eval { ExtUtils::MakeMaker->VERSION(6.63_03) } ) {
+ delete $WriteMakefileArgs{TEST_REQUIRES};
+ delete $WriteMakefileArgs{BUILD_REQUIRES};
+ $WriteMakefileArgs{PREREQ_PM} = \%FallbackPrereqs;
+}
+
+delete $WriteMakefileArgs{CONFIGURE_REQUIRES}
+ unless eval { ExtUtils::MakeMaker->VERSION(6.52) };
+
+WriteMakefile(%WriteMakefileArgs);
+
+
+
diff --git a/README b/README
new file mode 100644
index 0000000..d96b179
--- /dev/null
+++ b/README
@@ -0,0 +1,16 @@
+
+
+This archive contains the distribution Try-Tiny,
+version 0.22:
+
+ minimal try/catch with proper preservation of $@
+
+This software is Copyright (c) 2014 by Yuval Kogman.
+
+This is free software, licensed under:
+
+ The MIT (X11) License
+
+
+This README file was generated by Dist::Zilla::Plugin::Readme v5.014.
+
diff --git a/dist.ini b/dist.ini
new file mode 100644
index 0000000..000b1b3
--- /dev/null
+++ b/dist.ini
@@ -0,0 +1,30 @@
+name = Try-Tiny
+author = Yuval Kogman <nothingmuch@woobling.org>
+author = Jesse Luehrs <doy@tozt.net>
+license = MIT
+copyright_holder = Yuval Kogman
+
+[@DOY]
+:version = 0.14
+dist = Try-Tiny
+repository = github
+authority = cpan:NUFFIN
+done_testing = 0
+Git::Tag_tag_format = %N-%v
+Git::NextVersion_version_regexp = ^Try-Tiny-(.+)$
+
+[AutoPrereqs]
+; tests optionally require 5.010
+skip = ^perl$
+; tests for optional Sub::Name stuff
+skip = ^Sub::Name$
+; tests optionally require Capture::Tiny
+skip = ^Capture::Tiny$
+
+[Prereqs]
+perl = 5.006
+
+[Prereqs / TestRecommends]
+Capture::Tiny = 0.12 ; capture_stderr
+perl = 5.010
+Sub::Name = 0
diff --git a/lib/Try/Tiny.pm b/lib/Try/Tiny.pm
new file mode 100644
index 0000000..300561e
--- /dev/null
+++ b/lib/Try/Tiny.pm
@@ -0,0 +1,677 @@
+package Try::Tiny;
+BEGIN {
+ $Try::Tiny::AUTHORITY = 'cpan:NUFFIN';
+}
+$Try::Tiny::VERSION = '0.22';
+use 5.006;
+# ABSTRACT: minimal try/catch with proper preservation of $@
+
+use strict;
+use warnings;
+
+use Exporter 5.57 'import';
+our @EXPORT = our @EXPORT_OK = qw(try catch finally);
+
+use Carp;
+$Carp::Internal{+__PACKAGE__}++;
+
+BEGIN { eval "use Sub::Name; 1" or *{subname} = sub {1} }
+
+# Need to prototype as @ not $$ because of the way Perl evaluates the prototype.
+# Keeping it at $$ means you only ever get 1 sub because we need to eval in a list
+# context & not a scalar one
+
+sub try (&;@) {
+ my ( $try, @code_refs ) = @_;
+
+ # we need to save this here, the eval block will be in scalar context due
+ # to $failed
+ my $wantarray = wantarray;
+
+ # work around perl bug by explicitly initializing these, due to the likelyhood
+ # this will be used in global destruction (perl rt#119311)
+ my ( $catch, @finally ) = ();
+
+ # find labeled blocks in the argument list.
+ # catch and finally tag the blocks by blessing a scalar reference to them.
+ foreach my $code_ref (@code_refs) {
+
+ if ( ref($code_ref) eq 'Try::Tiny::Catch' ) {
+ croak 'A try() may not be followed by multiple catch() blocks'
+ if $catch;
+ $catch = ${$code_ref};
+ } elsif ( ref($code_ref) eq 'Try::Tiny::Finally' ) {
+ push @finally, ${$code_ref};
+ } else {
+ croak(
+ 'try() encountered an unexpected argument ('
+ . ( defined $code_ref ? $code_ref : 'undef' )
+ . ') - perhaps a missing semi-colon before or'
+ );
+ }
+ }
+
+ # FIXME consider using local $SIG{__DIE__} to accumulate all errors. It's
+ # not perfect, but we could provide a list of additional errors for
+ # $catch->();
+
+ # name the blocks if we have Sub::Name installed
+ my $caller = caller;
+ subname("${caller}::try {...} " => $try);
+ subname("${caller}::catch {...} " => $catch) if $catch;
+ subname("${caller}::finally {...} " => $_) foreach @finally;
+
+ # save the value of $@ so we can set $@ back to it in the beginning of the eval
+ # and restore $@ after the eval finishes
+ my $prev_error = $@;
+
+ my ( @ret, $error );
+
+ # failed will be true if the eval dies, because 1 will not be returned
+ # from the eval body
+ my $failed = not eval {
+ $@ = $prev_error;
+
+ # evaluate the try block in the correct context
+ if ( $wantarray ) {
+ @ret = $try->();
+ } elsif ( defined $wantarray ) {
+ $ret[0] = $try->();
+ } else {
+ $try->();
+ };
+
+ return 1; # properly set $fail to false
+ };
+
+ # preserve the current error and reset the original value of $@
+ $error = $@;
+ $@ = $prev_error;
+
+ # set up a scope guard to invoke the finally block at the end
+ my @guards =
+ map { Try::Tiny::ScopeGuard->_new($_, $failed ? $error : ()) }
+ @finally;
+
+ # at this point $failed contains a true value if the eval died, even if some
+ # destructor overwrote $@ as the eval was unwinding.
+ if ( $failed ) {
+ # if we got an error, invoke the catch block.
+ if ( $catch ) {
+ # This works like given($error), but is backwards compatible and
+ # sets $_ in the dynamic scope for the body of C<$catch>
+ for ($error) {
+ return $catch->($error);
+ }
+
+ # in case when() was used without an explicit return, the C<for>
+ # loop will be aborted and there's no useful return value
+ }
+
+ return;
+ } else {
+ # no failure, $@ is back to what it was, everything is fine
+ return $wantarray ? @ret : $ret[0];
+ }
+}
+
+sub catch (&;@) {
+ my ( $block, @rest ) = @_;
+
+ croak 'Useless bare catch()' unless wantarray;
+
+ return (
+ bless(\$block, 'Try::Tiny::Catch'),
+ @rest,
+ );
+}
+
+sub finally (&;@) {
+ my ( $block, @rest ) = @_;
+
+ croak 'Useless bare finally()' unless wantarray;
+
+ return (
+ bless(\$block, 'Try::Tiny::Finally'),
+ @rest,
+ );
+}
+
+{
+ package # hide from PAUSE
+ Try::Tiny::ScopeGuard;
+
+ use constant UNSTABLE_DOLLARAT => ($] < '5.013002') ? 1 : 0;
+
+ sub _new {
+ shift;
+ bless [ @_ ];
+ }
+
+ sub DESTROY {
+ my ($code, @args) = @{ $_[0] };
+
+ local $@ if UNSTABLE_DOLLARAT;
+ eval {
+ $code->(@args);
+ 1;
+ } or do {
+ warn
+ "Execution of finally() block $code resulted in an exception, which "
+ . '*CAN NOT BE PROPAGATED* due to fundamental limitations of Perl. '
+ . 'Your program will continue as if this event never took place. '
+ . "Original exception text follows:\n\n"
+ . (defined $@ ? $@ : '$@ left undefined...')
+ . "\n"
+ ;
+ }
+ }
+}
+
+__PACKAGE__
+
+__END__
+
+=pod
+
+=encoding UTF-8
+
+=head1 NAME
+
+Try::Tiny - minimal try/catch with proper preservation of $@
+
+=head1 VERSION
+
+version 0.22
+
+=head1 SYNOPSIS
+
+You can use Try::Tiny's C<try> and C<catch> to expect and handle exceptional
+conditions, avoiding quirks in Perl and common mistakes:
+
+ # handle errors with a catch handler
+ try {
+ die "foo";
+ } catch {
+ warn "caught error: $_"; # not $@
+ };
+
+You can also use it like a standalone C<eval> to catch and ignore any error
+conditions. Obviously, this is an extreme measure not to be undertaken
+lightly:
+
+ # just silence errors
+ try {
+ die "foo";
+ };
+
+=head1 DESCRIPTION
+
+This module provides bare bones C<try>/C<catch>/C<finally> statements that are designed to
+minimize common mistakes with eval blocks, and NOTHING else.
+
+This is unlike L<TryCatch> which provides a nice syntax and avoids adding
+another call stack layer, and supports calling C<return> from the C<try> block to
+return from the parent subroutine. These extra features come at a cost of a few
+dependencies, namely L<Devel::Declare> and L<Scope::Upper> which are
+occasionally problematic, and the additional catch filtering uses L<Moose>
+type constraints which may not be desirable either.
+
+The main focus of this module is to provide simple and reliable error handling
+for those having a hard time installing L<TryCatch>, but who still want to
+write correct C<eval> blocks without 5 lines of boilerplate each time.
+
+It's designed to work as correctly as possible in light of the various
+pathological edge cases (see L</BACKGROUND>) and to be compatible with any style
+of error values (simple strings, references, objects, overloaded objects, etc).
+
+If the C<try> block dies, it returns the value of the last statement executed in
+the C<catch> block, if there is one. Otherwise, it returns C<undef> in scalar
+context or the empty list in list context. The following examples all
+assign C<"bar"> to C<$x>:
+
+ my $x = try { die "foo" } catch { "bar" };
+ my $x = try { die "foo" } || { "bar" };
+ my $x = (try { die "foo" }) // { "bar" };
+
+ my $x = eval { die "foo" } || "bar";
+
+You can add C<finally> blocks, yielding the following:
+
+ my $x;
+ try { die 'foo' } finally { $x = 'bar' };
+ try { die 'foo' } catch { warn "Got a die: $_" } finally { $x = 'bar' };
+
+C<finally> blocks are always executed making them suitable for cleanup code
+which cannot be handled using local. You can add as many C<finally> blocks to a
+given C<try> block as you like.
+
+Note that adding a C<finally> block without a preceding C<catch> block
+suppresses any errors. This behaviour is consistent with using a standalone
+C<eval>, but it is not consistent with C<try>/C<finally> patterns found in
+other programming languages, such as Java, Python, Javascript or C#. If you
+learnt the C<try>/C<finally> pattern from one of these languages, watch out for
+this.
+
+=head1 EXPORTS
+
+All functions are exported by default using L<Exporter>.
+
+If you need to rename the C<try>, C<catch> or C<finally> keyword consider using
+L<Sub::Import> to get L<Sub::Exporter>'s flexibility.
+
+=over 4
+
+=item try (&;@)
+
+Takes one mandatory C<try> subroutine, an optional C<catch> subroutine and C<finally>
+subroutine.
+
+The mandatory subroutine is evaluated in the context of an C<eval> block.
+
+If no error occurred the value from the first block is returned, preserving
+list/scalar context.
+
+If there was an error and the second subroutine was given it will be invoked
+with the error in C<$_> (localized) and as that block's first and only
+argument.
+
+C<$@> does B<not> contain the error. Inside the C<catch> block it has the same
+value it had before the C<try> block was executed.
+
+Note that the error may be false, but if that happens the C<catch> block will
+still be invoked.
+
+Once all execution is finished then the C<finally> block, if given, will execute.
+
+=item catch (&;@)
+
+Intended to be used in the second argument position of C<try>.
+
+Returns a reference to the subroutine it was given but blessed as
+C<Try::Tiny::Catch> which allows try to decode correctly what to do
+with this code reference.
+
+ catch { ... }
+
+Inside the C<catch> block the caught error is stored in C<$_>, while previous
+value of C<$@> is still available for use. This value may or may not be
+meaningful depending on what happened before the C<try>, but it might be a good
+idea to preserve it in an error stack.
+
+For code that captures C<$@> when throwing new errors (i.e.
+L<Class::Throwable>), you'll need to do:
+
+ local $@ = $_;
+
+=item finally (&;@)
+
+ try { ... }
+ catch { ... }
+ finally { ... };
+
+Or
+
+ try { ... }
+ finally { ... };
+
+Or even
+
+ try { ... }
+ finally { ... }
+ catch { ... };
+
+Intended to be the second or third element of C<try>. C<finally> blocks are always
+executed in the event of a successful C<try> or if C<catch> is run. This allows
+you to locate cleanup code which cannot be done via C<local()> e.g. closing a file
+handle.
+
+When invoked, the C<finally> block is passed the error that was caught. If no
+error was caught, it is passed nothing. (Note that the C<finally> block does not
+localize C<$_> with the error, since unlike in a C<catch> block, there is no way
+to know if C<$_ == undef> implies that there were no errors.) In other words,
+the following code does just what you would expect:
+
+ try {
+ die_sometimes();
+ } catch {
+ # ...code run in case of error
+ } finally {
+ if (@_) {
+ print "The try block died with: @_\n";
+ } else {
+ print "The try block ran without error.\n";
+ }
+ };
+
+B<You must always do your own error handling in the C<finally> block>. C<Try::Tiny> will
+not do anything about handling possible errors coming from code located in these
+blocks.
+
+Furthermore B<exceptions in C<finally> blocks are not trappable and are unable
+to influence the execution of your program>. This is due to limitation of
+C<DESTROY>-based scope guards, which C<finally> is implemented on top of. This
+may change in a future version of Try::Tiny.
+
+In the same way C<catch()> blesses the code reference this subroutine does the same
+except it bless them as C<Try::Tiny::Finally>.
+
+=back
+
+=head1 BACKGROUND
+
+There are a number of issues with C<eval>.
+
+=head2 Clobbering $@
+
+When you run an C<eval> block and it succeeds, C<$@> will be cleared, potentially
+clobbering an error that is currently being caught.
+
+This causes action at a distance, clearing previous errors your caller may have
+not yet handled.
+
+C<$@> must be properly localized before invoking C<eval> in order to avoid this
+issue.
+
+More specifically, C<$@> is clobbered at the beginning of the C<eval>, which
+also makes it impossible to capture the previous error before you die (for
+instance when making exception objects with error stacks).
+
+For this reason C<try> will actually set C<$@> to its previous value (the one
+available before entering the C<try> block) in the beginning of the C<eval>
+block.
+
+=head2 Localizing $@ silently masks errors
+
+Inside an C<eval> block, C<die> behaves sort of like:
+
+ sub die {
+ $@ = $_[0];
+ return_undef_from_eval();
+ }
+
+This means that if you were polite and localized C<$@> you can't die in that
+scope, or your error will be discarded (printing "Something's wrong" instead).
+
+The workaround is very ugly:
+
+ my $error = do {
+ local $@;
+ eval { ... };
+ $@;
+ };
+
+ ...
+ die $error;
+
+=head2 $@ might not be a true value
+
+This code is wrong:
+
+ if ( $@ ) {
+ ...
+ }
+
+because due to the previous caveats it may have been unset.
+
+C<$@> could also be an overloaded error object that evaluates to false, but
+that's asking for trouble anyway.
+
+The classic failure mode is:
+
+ sub Object::DESTROY {
+ eval { ... }
+ }
+
+ eval {
+ my $obj = Object->new;
+
+ die "foo";
+ };
+
+ if ( $@ ) {
+
+ }
+
+In this case since C<Object::DESTROY> is not localizing C<$@> but still uses
+C<eval>, it will set C<$@> to C<"">.
+
+The destructor is called when the stack is unwound, after C<die> sets C<$@> to
+C<"foo at Foo.pm line 42\n">, so by the time C<if ( $@ )> is evaluated it has
+been cleared by C<eval> in the destructor.
+
+The workaround for this is even uglier than the previous ones. Even though we
+can't save the value of C<$@> from code that doesn't localize, we can at least
+be sure the C<eval> was aborted due to an error:
+
+ my $failed = not eval {
+ ...
+
+ return 1;
+ };
+
+This is because an C<eval> that caught a C<die> will always return a false
+value.
+
+=head1 SHINY SYNTAX
+
+Using Perl 5.10 you can use L<perlsyn/"Switch statements">.
+
+The C<catch> block is invoked in a topicalizer context (like a C<given> block),
+but note that you can't return a useful value from C<catch> using the C<when>
+blocks without an explicit C<return>.
+
+This is somewhat similar to Perl 6's C<CATCH> blocks. You can use it to
+concisely match errors:
+
+ try {
+ require Foo;
+ } catch {
+ when (/^Can't locate .*?\.pm in \@INC/) { } # ignore
+ default { die $_ }
+ };
+
+=head1 CAVEATS
+
+=over 4
+
+=item *
+
+C<@_> is not available within the C<try> block, so you need to copy your
+arglist. In case you want to work with argument values directly via C<@_>
+aliasing (i.e. allow C<$_[1] = "foo">), you need to pass C<@_> by reference:
+
+ sub foo {
+ my ( $self, @args ) = @_;
+ try { $self->bar(@args) }
+ }
+
+or
+
+ sub bar_in_place {
+ my $self = shift;
+ my $args = \@_;
+ try { $_ = $self->bar($_) for @$args }
+ }
+
+=item *
+
+C<return> returns from the C<try> block, not from the parent sub (note that
+this is also how C<eval> works, but not how L<TryCatch> works):
+
+ sub parent_sub {
+ try {
+ die;
+ }
+ catch {
+ return;
+ };
+
+ say "this text WILL be displayed, even though an exception is thrown";
+ }
+
+Instead, you should capture the return value:
+
+ sub parent_sub {
+ my $success = try {
+ die;
+ 1;
+ };
+ return unless $success;
+
+ say "This text WILL NEVER appear!";
+ }
+ # OR
+ sub parent_sub_with_catch {
+ my $success = try {
+ die;
+ 1;
+ }
+ catch {
+ # do something with $_
+ return undef; #see note
+ };
+ return unless $success;
+
+ say "This text WILL NEVER appear!";
+ }
+
+Note that if you have a C<catch> block, it must return C<undef> for this to work,
+since if a C<catch> block exists, its return value is returned in place of C<undef>
+when an exception is thrown.
+
+=item *
+
+C<try> introduces another caller stack frame. L<Sub::Uplevel> is not used. L<Carp>
+will not report this when using full stack traces, though, because
+C<%Carp::Internal> is used. This lack of magic is considered a feature.
+
+=item *
+
+The value of C<$_> in the C<catch> block is not guaranteed to be the value of
+the exception thrown (C<$@>) in the C<try> block. There is no safe way to
+ensure this, since C<eval> may be used unhygenically in destructors. The only
+guarantee is that the C<catch> will be called if an exception is thrown.
+
+=item *
+
+The return value of the C<catch> block is not ignored, so if testing the result
+of the expression for truth on success, be sure to return a false value from
+the C<catch> block:
+
+ my $obj = try {
+ MightFail->new;
+ } catch {
+ ...
+
+ return; # avoid returning a true value;
+ };
+
+ return unless $obj;
+
+=item *
+
+C<$SIG{__DIE__}> is still in effect.
+
+Though it can be argued that C<$SIG{__DIE__}> should be disabled inside of
+C<eval> blocks, since it isn't people have grown to rely on it. Therefore in
+the interests of compatibility, C<try> does not disable C<$SIG{__DIE__}> for
+the scope of the error throwing code.
+
+=item *
+
+Lexical C<$_> may override the one set by C<catch>.
+
+For example Perl 5.10's C<given> form uses a lexical C<$_>, creating some
+confusing behavior:
+
+ given ($foo) {
+ when (...) {
+ try {
+ ...
+ } catch {
+ warn $_; # will print $foo, not the error
+ warn $_[0]; # instead, get the error like this
+ }
+ }
+ }
+
+Note that this behavior was changed once again in L<Perl5 version 18
+|https://metacpan.org/module/perldelta#given-now-aliases-the-global-_>.
+However, since the entirety of lexical C<$_> is now L<considired experimental
+|https://metacpan.org/module/perldelta#Lexical-_-is-now-experimental>, it
+is unclear whether the new version 18 behavior is final.
+
+=back
+
+=head1 SEE ALSO
+
+=over 4
+
+=item L<TryCatch>
+
+Much more feature complete, more convenient semantics, but at the cost of
+implementation complexity.
+
+=item L<autodie>
+
+Automatic error throwing for builtin functions and more. Also designed to
+work well with C<given>/C<when>.
+
+=item L<Throwable>
+
+A lightweight role for rolling your own exception classes.
+
+=item L<Error>
+
+Exception object implementation with a C<try> statement. Does not localize
+C<$@>.
+
+=item L<Exception::Class::TryCatch>
+
+Provides a C<catch> statement, but properly calling C<eval> is your
+responsibility.
+
+The C<try> keyword pushes C<$@> onto an error stack, avoiding some of the
+issues with C<$@>, but you still need to localize to prevent clobbering.
+
+=back
+
+=head1 LIGHTNING TALK
+
+I gave a lightning talk about this module, you can see the slides (Firefox
+only):
+
+L<http://web.archive.org/web/20100628040134/http://nothingmuch.woobling.org/talks/takahashi.xul>
+
+Or read the source:
+
+L<http://web.archive.org/web/20100305133605/http://nothingmuch.woobling.org/talks/yapc_asia_2009/try_tiny.yml>
+
+=head1 VERSION CONTROL
+
+L<http://github.com/doy/try-tiny/>
+
+=head1 AUTHORS
+
+=over 4
+
+=item *
+
+Yuval Kogman <nothingmuch@woobling.org>
+
+=item *
+
+Jesse Luehrs <doy@tozt.net>
+
+=back
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is Copyright (c) 2014 by Yuval Kogman.
+
+This is free software, licensed under:
+
+ The MIT (X11) License
+
+=cut
diff --git a/maint/bench.pl b/maint/bench.pl
new file mode 100644
index 0000000..215097c
--- /dev/null
+++ b/maint/bench.pl
@@ -0,0 +1,14 @@
+#!/usr/bin/env perl
+
+use warnings;
+use strict;
+
+use Benchmark::Dumb ':all';
+use Try::Tiny;
+
+my $max = 10_000;
+
+cmpthese('0.003', {
+ eval => sub { do { local $@; eval { die 'foo' } } for (1..$max) },
+ try => sub { do { try { die 'foo' } } for (1..$max) },
+});
diff --git a/t/00-compile.t b/t/00-compile.t
new file mode 100644
index 0000000..f9cf666
--- /dev/null
+++ b/t/00-compile.t
@@ -0,0 +1,50 @@
+use 5.006;
+use strict;
+use warnings;
+
+# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.039
+
+use Test::More tests => 1 + ($ENV{AUTHOR_TESTING} ? 1 : 0);
+
+
+
+my @module_files = (
+ 'Try/Tiny.pm'
+);
+
+
+
+# no fake home requested
+
+my $inc_switch = -d 'blib' ? '-Mblib' : '-Ilib';
+
+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?>
+ my $stderr = IO::Handle->new;
+
+ my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, '-e', "require q[$lib]");
+ binmode $stderr, ':crlf' if $^O eq 'MSWin32';
+ my @_warnings = <$stderr>;
+ waitpid($pid, 0);
+ is($?, 0, "$lib loaded ok");
+
+ if (@_warnings)
+ {
+ warn @_warnings;
+ push @warnings, @_warnings;
+ }
+}
+
+
+
+is(scalar(@warnings), 0, 'no warnings found') if $ENV{AUTHOR_TESTING};
+
+
diff --git a/t/basic.t b/t/basic.t
new file mode 100644
index 0000000..3f0e2ac
--- /dev/null
+++ b/t/basic.t
@@ -0,0 +1,166 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 25;
+
+use Try::Tiny;
+
+sub _eval {
+ local $@;
+ local $Test::Builder::Level = $Test::Builder::Level + 2;
+ return ( scalar(eval { $_[0]->(); 1 }), $@ );
+}
+
+
+sub lives_ok (&$) {
+ my ( $code, $desc ) = @_;
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ my ( $ok, $error ) = _eval($code);
+
+ ok($ok, $desc );
+
+ diag "error: $@" unless $ok;
+}
+
+sub throws_ok (&$$) {
+ my ( $code, $regex, $desc ) = @_;
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ my ( $ok, $error ) = _eval($code);
+
+ if ( $ok ) {
+ fail($desc);
+ } else {
+ like($error || '', $regex, $desc );
+ }
+}
+
+
+my $prev;
+
+lives_ok {
+ try {
+ die "foo";
+ };
+} "basic try";
+
+throws_ok {
+ try {
+ die "foo";
+ } catch { die $_ };
+} qr/foo/, "rethrow";
+
+
+{
+ local $@ = "magic";
+ is( try { 42 }, 42, "try block evaluated" );
+ is( $@, "magic", '$@ untouched' );
+}
+
+{
+ local $@ = "magic";
+ is( try { die "foo" }, undef, "try block died" );
+ is( $@, "magic", '$@ untouched' );
+}
+
+{
+ local $@ = "magic";
+ like( (try { die "foo" } catch { $_ }), qr/foo/, "catch block evaluated" );
+ is( $@, "magic", '$@ untouched' );
+}
+
+is( scalar(try { "foo", "bar", "gorch" }), "gorch", "scalar context try" );
+is_deeply( [ try {qw(foo bar gorch)} ], [qw(foo bar gorch)], "list context try" );
+
+is( scalar(try { die } catch { "foo", "bar", "gorch" }), "gorch", "scalar context catch" );
+is_deeply( [ try { die } catch {qw(foo bar gorch)} ], [qw(foo bar gorch)], "list context catch" );
+
+
+{
+ my ($sub) = catch { my $a = $_; };
+ is(ref($sub), 'Try::Tiny::Catch', 'Checking catch subroutine scalar reference is correctly blessed');
+}
+
+{
+ my ($sub) = finally { my $a = $_; };
+ is(ref($sub), 'Try::Tiny::Finally', 'Checking finally subroutine scalar reference is correctly blessed');
+}
+
+lives_ok {
+ try {
+ die "foo";
+ } catch {
+ my $err = shift;
+
+ try {
+ like $err, qr/foo/;
+ } catch {
+ fail("shouldn't happen");
+ };
+
+ pass "got here";
+ }
+} "try in try catch block";
+
+throws_ok {
+ try {
+ die "foo";
+ } catch {
+ my $err = shift;
+
+ try { } catch { };
+
+ die "rethrowing $err";
+ }
+} qr/rethrowing foo/, "rethrow with try in catch block";
+
+
+sub Evil::DESTROY {
+ eval { "oh noes" };
+}
+
+sub Evil::new { bless { }, $_[0] }
+
+{
+ local $@ = "magic";
+ local $_ = "other magic";
+
+ try {
+ my $object = Evil->new;
+ die "foo";
+ } catch {
+ pass("catch invoked");
+ local $TODO = "i don't think we can ever make this work sanely, maybe with SIG{__DIE__}" if $] < 5.014;
+ like($_, qr/foo/);
+ };
+
+ is( $@, "magic", '$@ untouched' );
+ is( $_, "other magic", '$_ untouched' );
+}
+
+{
+ my ( $caught, $prev );
+
+ {
+ local $@;
+
+ eval { die "bar\n" };
+
+ is( $@, "bar\n", 'previous value of $@' );
+
+ try {
+ die {
+ prev => $@,
+ }
+ } catch {
+ $caught = $_;
+ $prev = $@;
+ }
+ }
+
+ is_deeply( $caught, { prev => "bar\n" }, 'previous value of $@ available for capture' );
+ is( $prev, "bar\n", 'previous value of $@ also available in catch block' );
+}
diff --git a/t/context.t b/t/context.t
new file mode 100644
index 0000000..1a57ba0
--- /dev/null
+++ b/t/context.t
@@ -0,0 +1,71 @@
+use strict;
+use warnings;
+
+use Test::More;
+
+use Try::Tiny;
+
+plan tests =>
+ (4+1) * 2 # list/scalar with exception (try + catch + 2 x finally) + is_deeply
++ 4 # void with exception
++ (3+1) * 2 # list/scalar no exception (try + 2 x finally) + is_deeply
++ 3 # void no exception
+;
+
+my $ctx_index = {
+ VOID => undef,
+ LIST => 1,
+ SCALAR => '',
+};
+my ($ctx, $die);
+
+for (sort keys %$ctx_index) {
+ $ctx = $_;
+ for (0,1) {
+ $die = $_;
+ if ($ctx_index->{$ctx}) {
+ is_deeply(
+ [ run() ],
+ [ $die ? 'catch' : 'try' ],
+ );
+ }
+ elsif (defined $ctx_index->{$ctx}) {
+ is_deeply(
+ [ scalar run() ],
+ [ $die ? 'catch' : 'try' ],
+ );
+ }
+ else {
+ run();
+ 1;
+ }
+ }
+}
+
+sub run {
+ try {
+ is (wantarray, $ctx_index->{$ctx}, "Proper context $ctx in try{}");
+ die if $die;
+ return 'try';
+ }
+ catch {
+ is (wantarray, $ctx_index->{$ctx}, "Proper context $ctx in catch{}");
+ return 'catch';
+ }
+ finally {
+ SKIP: {
+ skip "DESTROY() not called in void context on perl $]", 1
+ if $] < '5.008';
+ is (wantarray, undef, "Proper VOID context in finally{} 1");
+ }
+ return 'finally';
+ }
+ finally {
+ SKIP: {
+ skip "DESTROY() not called in void context on perl $]", 1
+ if $] < '5.008';
+ is (wantarray, undef, "Proper VOID context in finally{} 2");
+ }
+ return 'finally';
+ };
+}
diff --git a/t/erroneous_usage.t b/t/erroneous_usage.t
new file mode 100644
index 0000000..c8cc478
--- /dev/null
+++ b/t/erroneous_usage.t
@@ -0,0 +1,77 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 8;
+
+use Try::Tiny;
+
+sub _eval {
+ local $@;
+ local $Test::Builder::Level = $Test::Builder::Level + 2;
+ return ( scalar(eval { $_[0]->(); 1 }), $@ );
+}
+
+sub throws_ok (&$$) {
+ my ( $code, $regex, $desc ) = @_;
+ local $Test::Builder::Level = $Test::Builder::Level + 1;
+
+ my ( $ok, $error ) = _eval($code);
+
+ if ( $ok ) {
+ fail($desc);
+ } else {
+ like($error || '', $regex, $desc );
+ }
+}
+
+throws_ok {
+ try { 1 }; catch { 2 };
+} qr/\QUseless bare catch()/, 'Bare catch() detected';
+
+throws_ok {
+ try { 1 }; finally { 2 };
+} qr/\QUseless bare finally()/, 'Bare finally() detected';
+
+throws_ok {
+ try { 1 }; catch { 2 } finally { 2 };
+} qr/\QUseless bare catch()/, 'Bare catch()/finally() detected';
+
+throws_ok {
+ try { 1 }; finally { 2 } catch { 2 };
+} qr/\QUseless bare finally()/, 'Bare finally()/catch() detected';
+
+
+throws_ok {
+ try { 1 } catch { 2 } catch { 3 } finally { 4 } finally { 5 }
+} qr/\QA try() may not be followed by multiple catch() blocks/, 'Multi-catch detected';
+
+
+throws_ok {
+ try { 1 } catch { 2 }
+ do { 2 }
+} qr/\Qtry() encountered an unexpected argument (2) - perhaps a missing semi-colon before or at/,
+ 'Unterminated try detected';
+
+sub foo {
+ try { 0 }; catch { 2 }
+}
+
+throws_ok {
+ if (foo()) {
+ # ...
+ }
+} qr/\QUseless bare catch/,
+ 'Bare catch at the end of a function call';
+
+sub bar {
+ try { 0 }; finally { 2 }
+}
+
+throws_ok {
+ if (bar()) {
+ # ...
+ }
+} qr/\QUseless bare finally/,
+ 'Bare finally at the end of a function call';
diff --git a/t/finally.t b/t/finally.t
new file mode 100644
index 0000000..2624cc9
--- /dev/null
+++ b/t/finally.t
@@ -0,0 +1,131 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More tests => 27;
+
+use Try::Tiny;
+
+try {
+ my $a = 1+1;
+} catch {
+ fail('Cannot go into catch block because we did not throw an exception')
+} finally {
+ pass('Moved into finally from try');
+};
+
+try {
+ die('Die');
+} catch {
+ ok($_ =~ /Die/, 'Error text as expected');
+ pass('Into catch block as we died in try');
+} finally {
+ pass('Moved into finally from catch');
+};
+
+try {
+ die('Die');
+} finally {
+ pass('Moved into finally from catch');
+} catch {
+ ok($_ =~ /Die/, 'Error text as expected');
+};
+
+try {
+ die('Die');
+} finally {
+ pass('Moved into finally block when try throws an exception and we have no catch block');
+};
+
+try {
+ die('Die');
+} finally {
+ pass('First finally clause run');
+} finally {
+ pass('Second finally clause run');
+};
+
+try {
+ # do not die
+} finally {
+ if (@_) {
+ fail("errors reported: @_");
+ } else {
+ pass("no error reported") ;
+ }
+};
+
+try {
+ die("Die\n");
+} finally {
+ is_deeply(\@_, [ "Die\n" ], "finally got passed the exception");
+};
+
+try {
+ try {
+ die "foo";
+ }
+ catch {
+ die "bar";
+ }
+ finally {
+ pass("finally called");
+ };
+};
+
+$_ = "foo";
+try {
+ is($_, "foo", "not localized in try");
+}
+catch {
+}
+finally {
+ is(scalar(@_), 0, "nothing in \@_ (finally)");
+ is($_, "foo", "\$_ not localized (finally)");
+};
+is($_, "foo", "same afterwards");
+
+$_ = "foo";
+try {
+ is($_, "foo", "not localized in try");
+ die "bar\n";
+}
+catch {
+ is($_[0], "bar\n", "error in \@_ (catch)");
+ is($_, "bar\n", "error in \$_ (catch)");
+}
+finally {
+ is(scalar(@_), 1, "error in \@_ (finally)");
+ is($_[0], "bar\n", "error in \@_ (finally)");
+ is($_, "foo", "\$_ not localized (finally)");
+};
+is($_, "foo", "same afterwards");
+
+{
+ my @warnings;
+ local $SIG{__WARN__} = sub {
+ $_[0] =~ /\QExecution of finally() block CODE(0x\E.+\Q) resulted in an exception/
+ ? push @warnings, @_
+ : warn @_
+ };
+
+ try {
+ die 'tring'
+ } finally {
+ die 'fin 1'
+ } finally {
+ pass('fin 2 called')
+ } finally {
+ die 'fin 3'
+ };
+
+ is( scalar @warnings, 2, 'warnings from both fatal finally blocks' );
+
+ my @originals = sort map { $_ =~ /Original exception text follows:\n\n(.+)/s } @warnings;
+
+ like $originals[0], qr/fin 1 at/, 'First warning contains original exception';
+ like $originals[1], qr/fin 3 at/, 'Second warning contains original exception';
+}
+
+1;
diff --git a/t/given_when.t b/t/given_when.t
new file mode 100644
index 0000000..afa0733
--- /dev/null
+++ b/t/given_when.t
@@ -0,0 +1,40 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More;
+
+BEGIN {
+ plan skip_all => "Perl 5.10 is required" unless eval { require 5.010 };
+ plan tests => 2;
+}
+
+use Try::Tiny;
+
+use 5.010;
+no if $] >= 5.017011, warnings => 'experimental::smartmatch';
+
+my ( $error, $topic );
+
+given ("foo") {
+ when (qr/./) {
+ try {
+ die "blah\n";
+ } catch {
+ $topic = $_;
+ $error = $_[0];
+ }
+ };
+}
+
+is( $error, "blah\n", "error caught" );
+
+{
+ local $TODO = "perhaps a workaround can be found"
+ if $] < 5.017003;
+ is( $topic, $error, 'error is also in $_' );
+}
+
+# ex: set sw=4 et:
+
diff --git a/t/global_destruction_forked.t b/t/global_destruction_forked.t
new file mode 100644
index 0000000..a533000
--- /dev/null
+++ b/t/global_destruction_forked.t
@@ -0,0 +1,57 @@
+use strict;
+use warnings;
+use Test::More tests => 3;
+use Try::Tiny;
+
+{
+ package WithCatch;
+ use Try::Tiny;
+
+ sub DESTROY {
+ try {}
+ catch {};
+ return;
+ }
+}
+
+{
+ package WithFinally;
+ use Try::Tiny;
+
+ sub DESTROY {
+ try {}
+ finally {};
+ return;
+ }
+}
+
+my $parent = $$;
+
+try {
+ my $pid = fork;
+ unless ($pid) {
+ my $o = bless {}, 'WithCatch';
+ $SIG{__DIE__} = sub {
+ exit 1
+ if $_[0] =~ /A try\(\) may not be followed by multiple catch\(\) blocks/;
+ exit 2;
+ };
+ exit 0;
+ }
+ waitpid $pid, 0;
+ is $?, 0, 'nested try in cleanup after fork does not maintain outer catch block';
+}
+catch {};
+
+try {
+ my $pid = fork;
+ unless ($pid) {
+ my $o = bless {}, 'WithFinally';
+ exit 0;
+ }
+ waitpid $pid, 0;
+ is $?, 0, 'nested try in cleanup after fork does not maintain outer finally block';
+}
+finally { exit 1 if $parent != $$ };
+
+pass("Didn't just exit");
diff --git a/t/global_destruction_load.t b/t/global_destruction_load.t
new file mode 100644
index 0000000..9c73850
--- /dev/null
+++ b/t/global_destruction_load.t
@@ -0,0 +1,18 @@
+use strict;
+use warnings;
+use Test::More;
+
+BEGIN {
+ plan skip_all => 'Capture::Tiny 0.12 required'
+ unless eval { require Capture::Tiny; Capture::Tiny->VERSION(0.12); 1 };
+ plan tests => 3;
+ Capture::Tiny->import(qw(capture_stderr));
+}
+
+for my $func (qw(try catch finally)) {
+ is capture_stderr {
+ system $^X, qw(-It/lib -we),
+ qq{sub DESTROY { require TryUser; TryUser->test_$func }} .
+ q{our $o; $o = bless []};
+ }, '', "$func gets installed when loading Try::Tiny during global destruction";
+}
diff --git a/t/lib/TryUser.pm b/t/lib/TryUser.pm
new file mode 100644
index 0000000..c44d36b
--- /dev/null
+++ b/t/lib/TryUser.pm
@@ -0,0 +1,9 @@
+package TryUser;
+
+use Try::Tiny;
+
+sub test_try { try { } }
+sub test_catch { try { } catch { } }
+sub test_finally { try { } finally { } }
+
+1;
diff --git a/t/named.t b/t/named.t
new file mode 100644
index 0000000..7de53b1
--- /dev/null
+++ b/t/named.t
@@ -0,0 +1,37 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More;
+
+BEGIN {
+ plan skip_all => "Sub::Name required"
+ unless eval { require Sub::Name; 1 };
+ plan tests => 3;
+}
+
+use Try::Tiny;
+
+my $name;
+try {
+ $name = (caller(0))[3];
+};
+is $name, "main::try {...} ", "try name"; # note extra space
+
+try {
+ die "Boom";
+} catch {
+ $name = (caller(0))[3];
+};
+is $name, "main::catch {...} ", "catch name"; # note extra space
+
+try {
+ die "Boom";
+} catch {
+ # noop
+} finally {
+ $name = (caller(0))[3];
+};
+is $name, "main::finally {...} ", "finally name"; # note extra space
+
diff --git a/t/when.t b/t/when.t
new file mode 100644
index 0000000..54fd678
--- /dev/null
+++ b/t/when.t
@@ -0,0 +1,37 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More;
+
+BEGIN {
+ plan skip_all => "Perl 5.10 required" unless eval { require 5.010; 1 };
+ plan tests => 5;
+}
+
+use Try::Tiny;
+
+use 5.010;
+no if $] >= 5.017011, warnings => 'experimental::smartmatch';
+
+my ( $foo, $bar, $other );
+
+$_ = "magic";
+
+try {
+ die "foo";
+} catch {
+
+ like( $_, qr/foo/ );
+
+ when (/bar/) { $bar++ };
+ when (/foo/) { $foo++ };
+ default { $other++ };
+};
+
+is( $_, "magic", '$_ not clobbered' );
+
+ok( !$bar, "bar didn't match" );
+ok( $foo, "foo matched" );
+ok( !$other, "fallback didn't match" );
diff --git a/xt/release/eol.t b/xt/release/eol.t
new file mode 100644
index 0000000..d13c49d
--- /dev/null
+++ b/xt/release/eol.t
@@ -0,0 +1,8 @@
+use strict;
+use warnings;
+use Test::More;
+
+eval 'use Test::EOL';
+plan skip_all => 'Test::EOL required' if $@;
+
+all_perl_files_ok({ trailing_whitespace => 1 });
diff --git a/xt/release/no-tabs.t b/xt/release/no-tabs.t
new file mode 100644
index 0000000..7619ba2
--- /dev/null
+++ b/xt/release/no-tabs.t
@@ -0,0 +1,25 @@
+use strict;
+use warnings;
+
+# this test was generated with Dist::Zilla::Plugin::NoTabsTests 0.07
+
+use Test::More 0.88;
+use Test::NoTabs;
+
+my @files = (
+ 'lib/Try/Tiny.pm',
+ 't/00-compile.t',
+ 't/basic.t',
+ 't/context.t',
+ 't/erroneous_usage.t',
+ 't/finally.t',
+ 't/given_when.t',
+ 't/global_destruction_forked.t',
+ 't/global_destruction_load.t',
+ 't/lib/TryUser.pm',
+ 't/named.t',
+ 't/when.t'
+);
+
+notabs_ok($_) foreach @files;
+done_testing;
diff --git a/xt/release/pod-coverage.t b/xt/release/pod-coverage.t
new file mode 100644
index 0000000..66b3b64
--- /dev/null
+++ b/xt/release/pod-coverage.t
@@ -0,0 +1,7 @@
+#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::PodCoverageTests.
+
+use Test::Pod::Coverage 1.08;
+use Pod::Coverage::TrustPod;
+
+all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' });
diff --git a/xt/release/pod-syntax.t b/xt/release/pod-syntax.t
new file mode 100644
index 0000000..f0468f1
--- /dev/null
+++ b/xt/release/pod-syntax.t
@@ -0,0 +1,6 @@
+#!perl
+# This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests.
+use Test::More;
+use Test::Pod 1.41;
+
+all_pod_files_ok();