From b70be2ef5c7123d0d77ed4ee75032726134d3a84 Mon Sep 17 00:00:00 2001 From: TizenOpenSource Date: Tue, 13 Feb 2024 14:57:35 +0900 Subject: [PATCH] Imported Upstream version 2.05 --- CODE_OF_CONDUCT.md | 75 +++ CONTRIBUTING.md | 115 ++++ Changes | 379 ++++++++++++ INSTALL | 75 +++ LICENSE | 207 +++++++ MANIFEST | 47 ++ META.json | 1077 +++++++++++++++++++++++++++++++++ META.yml | 791 ++++++++++++++++++++++++ Makefile.PL | 63 ++ README.md | 270 +++++++++ azure-pipelines.yml | 31 + cpanfile | 57 ++ dev-bin/install-xt-tools.sh | 19 + dist.ini | 14 + git/hooks/pre-commit.sh | 15 + git/setup.pl | 27 + lib/Devel/StackTrace.pm | 624 +++++++++++++++++++ lib/Devel/StackTrace/Frame.pm | 272 +++++++++ perlcriticrc | 70 +++ perltidyrc | 22 + precious.toml | 51 ++ t/00-report-prereqs.dd | 63 ++ t/00-report-prereqs.t | 197 ++++++ t/01-basic.t | 585 ++++++++++++++++++ t/02-bad-utf8.t | 41 ++ t/03-message.t | 34 ++ t/04-indent.t | 35 ++ t/05-back-compat.t | 10 + t/06-dollar-at.t | 25 + t/07-no-args.t | 45 ++ t/08-filter-early.t | 33 + t/09-skip-frames.t | 55 ++ t/10-set-frames.t | 37 ++ xt/author/00-compile.t | 61 ++ xt/author/eol.t | 27 + xt/author/mojibake.t | 9 + xt/author/no-tabs.t | 27 + xt/author/pod-coverage.t | 44 ++ xt/author/pod-spell.t | 47 ++ xt/author/pod-syntax.t | 7 + xt/author/portability.t | 8 + xt/author/precious.t | 24 + xt/author/synopsis.t | 5 + xt/author/test-version.t | 23 + xt/release/cpan-changes.t | 10 + xt/release/meta-json.t | 4 + 46 files changed, 5757 insertions(+) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 Changes create mode 100644 INSTALL create mode 100644 LICENSE create mode 100644 MANIFEST create mode 100644 META.json create mode 100644 META.yml create mode 100644 Makefile.PL create mode 100644 README.md create mode 100644 azure-pipelines.yml create mode 100644 cpanfile create mode 100755 dev-bin/install-xt-tools.sh create mode 100644 dist.ini create mode 100755 git/hooks/pre-commit.sh create mode 100755 git/setup.pl create mode 100644 lib/Devel/StackTrace.pm create mode 100644 lib/Devel/StackTrace/Frame.pm create mode 100644 perlcriticrc create mode 100644 perltidyrc create mode 100644 precious.toml create mode 100644 t/00-report-prereqs.dd create mode 100644 t/00-report-prereqs.t create mode 100644 t/01-basic.t create mode 100644 t/02-bad-utf8.t create mode 100644 t/03-message.t create mode 100644 t/04-indent.t create mode 100644 t/05-back-compat.t create mode 100644 t/06-dollar-at.t create mode 100644 t/07-no-args.t create mode 100644 t/08-filter-early.t create mode 100644 t/09-skip-frames.t create mode 100644 t/10-set-frames.t create mode 100644 xt/author/00-compile.t create mode 100644 xt/author/eol.t create mode 100644 xt/author/mojibake.t create mode 100644 xt/author/no-tabs.t create mode 100644 xt/author/pod-coverage.t create mode 100644 xt/author/pod-spell.t create mode 100644 xt/author/pod-syntax.t create mode 100644 xt/author/portability.t create mode 100644 xt/author/precious.t create mode 100644 xt/author/synopsis.t create mode 100644 xt/author/test-version.t create mode 100644 xt/release/cpan-changes.t create mode 100644 xt/release/meta-json.t diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..ac28652 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,75 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, +body size, disability, ethnicity, gender identity and expression, level of +experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an +appointed representative at an online or offline event. Representation of a +project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at autarch@urth.org. All complaints +will be reviewed and investigated and will result in a response that is deemed +necessary and appropriate to the circumstances. The project team is obligated +to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.4, available at +https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..4db2f42 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,115 @@ +# CONTRIBUTING + +Thank you for considering contributing to this distribution. This file +contains instructions that will help you work with the source code. + +Please note that if you have any questions or difficulties, you can reach the +maintainer(s) through the bug queue described later in this document +(preferred), or by emailing the releaser directly. You are not required to +follow any of the steps in this document to submit a patch or bug report; +these are just recommendations, intended to help you (and help us help you +faster). + +The distribution is managed with +[Dist::Zilla](https://metacpan.org/release/Dist-Zilla). + +However, you can still compile and test the code with the +`Makefile.PL` +in the repository: + + perl Makefile.PL + make + make test + + +You may need to satisfy some dependencies. The easiest way to satisfy +dependencies is to install the last release. This is available at +https://metacpan.org/release/Devel-StackTrace + +You can use [`cpanminus`](https://metacpan.org/pod/App::cpanminus) to do this +without downloading the tarball first: + + $> cpanm --reinstall --installdeps --with-recommends Devel::StackTrace + +[`Dist::Zilla`](https://metacpan.org/pod/Dist::Zilla) is a very powerful +authoring tool, but requires a number of author-specific plugins. If you would +like to use it for contributing, install it from CPAN, then the following +command to install the needed distros: + + $> dzil authordeps --missing | cpanm + +There may also be additional requirements not needed by the dzil build which +are needed for tests or other development: + + $> dzil listdeps --author --missing | cpanm + +Or, you can use the 'dzil stale' command to install all requirements at once: + + $> cpanm Dist::Zilla::App::Command::stale + $> dzil stale --all | cpanm + +You can also do this via cpanm directly: + + $> cpanm --reinstall --installdeps --with-develop --with-recommends Devel::StackTrace + +Once installed, here are some dzil commands you might try: + + $> dzil build + $> dzil test + $> dzil test --release + $> dzil xtest + $> dzil listdeps --json + $> dzil build --notgz + +You can learn more about Dist::Zilla at http://dzil.org/. + +The code for this distribution is [hosted on GitHub](https://github.com/houseabsolute/Devel-StackTrace). + +You can submit code changes by forking the repository, pushing your code +changes to your clone, and then submitting a pull request. Please update the +Changes file with a user-facing description of your changes as part of your +work. See the GitHub documentation for [detailed instructions on pull +requests](https://help.github.com/articles/creating-a-pull-request) + +If you have found a bug, but do not have an accompanying patch to fix it, you +can submit an issue report [via the web](https://github.com/houseabsolute/Devel-StackTrace/issues). + +## Continuous Integration + +All pull requests for this distribution will be automatically tested using +[Azure Pipelines](https://dev.azure.com/houseabsolute/houseabsolute/_build). + +All CI results will be visible in the pull request on GitHub. Follow the +appropriate links for details when tests fail. PRs cannot be merged until tests +pass. + +## Precious + +This distribution uses [precious](https://github.com/houseabsolute/precious) +to enforce a uniform coding style. This is tested as part of the author +testing suite. You can install this and any other necessary non-Perl tools by +running `./dev-bin/install-xt-tools.sh`. + +Then you can use `precious` to tidy and lint your code: + + $> precious tidy -a + $> precious lint -a + +Please run `precious tidy -a` and `precious lint -a` before committing your +changes and address any issues that it reports. + +You can also set up a git pre-commit hook that checks all changed files for +linting issues by running `./git/setup.pl`. + +## Contributor Names + +If you send a patch or pull request, your name and email address will be +included in the documentation as a contributor (using the attribution on the +commit or patch), unless you specifically request for it not to be. If you +wish to be listed under a different name or address, you should submit a pull +request to the `.mailmap` file to contain the correct mapping. + +## Generated By + +This file was generated via Dist::Zilla::Plugin::GenerateFile::FromShareDir 0.015 from a +template file originating in Dist-Zilla-PluginBundle-DROLSKY-1.22. diff --git a/Changes b/Changes new file mode 100644 index 0000000..a559f5c --- /dev/null +++ b/Changes @@ -0,0 +1,379 @@ +2.05 2024-01-08 + +- Added explicit boolean overloading for trace objects. Without this, Perl + will use the object's string overloading and then check the truthiness of + the returned string, which is a lot of extra work. This can produce + significant slowdowns in some cases, as seen in + https://github.com/plack/Plack/pull/697. Requested by Tatsuhiko + Miyagawa. GH #23. + + +2.04 2019-05-24 + +- Add a partial workaround for "Bizarre copy" errors (GH #11) that come when + attempting to look at arguments in the call stack. This is only a partial + fix as there are cases that can lead to a SEGV. Ultimately this needs to be + fixed in the Perl core. See + https://rt.perl.org/Public/Bug/Display.html?id=131046 for relevant + discussion. Fixed by pali. GH #21. + + +2.03 2017-11-18 + +- If all frames in the trace were skipped (via skip_frames, frame_filter, + ignore_*, etc.), then the stringified stack trace would be an empty + string. Now this has been changed to always return the message given to the + constructor or the string "Trace begun". Fixes GH #15, reported by Karen + Etheridge. + + +2.02 2016-12-07 + +- Switch to GitHub Issues. + +- Some small pod fixes. + + +2.01 2016-03-02 + +- Fixed the frames method when it is called with arguments. Previously this + did not work if it was called before the method was called as a + reader. Fixed by Mark Fowler. PR #8. + + +2.00 2014-11-01 + +[BACKWARDS INCOMPATIBILITIES] + +- The no_refs constructor parameter is now deprecated, and has been replace by + a new unsafe_ref_capture parameter that defaults to false, meaning no + references are captured by default. Capturing references by default caused + too many issues that couldn't be worked around, including running DESTROY + blocks multiple times on captured objects in the worst case. + +- Removed support for the long-deprecated no_object_refs constructor parameter + (deprecated in 2002!). + + +1.34 2014-06-26 + +- Fixed use of // operator (my use, not Graham's) in previous release. + + +1.33 2014-06-26 + +- Added a skip_frames option. This causes the stack trace to skip an arbitrary + number of frames. Patch by Graham Knopp. PR #5. + + +1.32 2014-05-05 + +- Added a filter_frames_early option to filter frames before arguments are + stringified. Added by Dagfinn Ilmari Mannsåker. PR #4. + + +1.31 2014-01-16 + +- No code changes, just doc updates, including documenting the as_string() + method in Devel::StackTrace::Frame. Requested by Skef. RT #91575. + + +1.30 2012-11-19 + +- There was an eval which did not first localize $@ and $SIG{__DIE__}. This + broke Plack::Middleware::StackTrace (and possibly other tihngs). + + +1.29 2012-11-16 + +- The Devel::StackTrace->frames() method is now read-write. This allows you to + do more complex filtering of frames than is easily possible with the + frame_filter argument to the constructor. Patch by David Cantrell. + + +1.28 2012-11-16 + +- Allow arguments to a trace's as_string method, specifically max_arg_length + Patch by Ricardo Signes. + +- Added a no_args option to the constructor in 1.26 but forgot to mention it + in Changes. Requested by Scott J. Miller. RT #71482. + + +1.27 2011-01-16 + +- Skip some tests on 5.13.8+ that are no longer relevant because of a change + in the Perl core. Reported by Andreas Koenig. RT #64828. + + +1.26 2010-10-15 + +- The as_string method did not localize $@ and $SIG{__DIE__} before doing an + eval. Reported and tested by Marc Mims. RT #61072. + + +1.25 2010-09-06 + +- Devel::StackTraceFrame was not actually subclassing + Devel::StackTrace::Frame. Patch by Tatsuhiko Miyagawa. + + +1.24 2010-09-03 + +- Version 1.23 was missing a $VERSION assignment. Reported by Sergei + Vyshenski. + +- Moved the frame object to its own file, and renamed it + Devel::StackTrace::Frame. The old package name, Devel::StackTraceFrame, is + now a subclass of the new package, to provide a backwards compatibility + shim. + + +1.23 2010-08-27 + +- Added message and indent constructor parameters. Based on a patch by James + Laver. RT #59830. + + +1.22 2009-07-15 + +- Apparently, overload::StrVal on older Perls (5.8.5, but not 5.8.8) + tried to call a stringification method if it existed. So now, + Devel::StackTrace just uses overload::AddrRef instead, which should + always be safe. Reported by Michael Stevens. Fixes RT #47900. + + +1.21 2009-07-01 + +- Overloaded objects which didn't provide a stringification method + cause Devel::StackTrace to die when respect_overload was + true. Reported by Laurent Dami. RT #39533. + +- Added a frame_filter option which allows for fine-grained control + over what frames are included in a trace. Based on (but expanded) + from a patch proposed by Florian Ragwitz. RT #47415. + + +1.20 2008-10-25 + +- The change in 1.15 to object creation broke the no_refs feature, + causing references to be stored until the trace's frame objects were + created. + +* Exception::Class objects are always stringified by calling + overload::StrVal(). + + +1.1902 2008-07-16 + +- This release just contains another test fix. + +- The new tests for bad utf-8 apparently fail with any Perl before + 5.8.8. Reported by Lee Heagney. RT #37702. + + +1.1901 2008-06-13 + +- This release just contains a test fix. + +- The new tests for bad utf-8 fail with Perl 5.8.x where x <= + 6. Apparently, utf-8 was just more broken back then. Reported by + Andreas Koenig's smokebots. + + +1.19 2008-06-13 + +- Dropped support for Perl 5.005. + +- If a function was in stack trace had been called with invalid utf-8 + bytes, this could cause stringifying a stack trace to blow up when + it tried to stringify that argument. We now catch those (and other) + errors and simply put "(bad utf-8)" or "?" in the stringified + argument list. Reported by Alex Vandiver. + + +1.18 2008-03-31 + +- Fix a test failure on Win32. No changes to the non-test code. + + +1.17 2008-03-30 + +- Added a max_arg_length parameter, which if set causes + Devel::StackTrace to truncate long strings when printing out a + frame. RT #33519. Patch by Ian Burrell. + + +1.16 2008-02-02 + +- A test fix for bleadperl. The value of wantarray from caller() needs + to be treated as a boolean, as opposed to expecting 0 (vs + undef). RT #32583. Patch by Jerry Hedden. + + +1.15 2007-04-28 + +- Changed how objects are created in order to greatly speed up the + constructor. Instead of processing all the stack trace data when the + object is first created, this is delayed until it is needed. This + was done in order to help speed up Exception::Class. There are cases + where code may be throwing many exceptions but never examining the + stack traces. + + Here is a representative benchmark of object construction for the + old code versus the new code: + + Rate old new + old 1764/s -- -76% + new 7353/s 317% -- + + +1.14 2007-03-16 + +- Added a few micro-optimizations from Ruslan Zakirov, who is hoping + this will ultimately help speed up RT. + + +1.13 2006-04-01 + +- Add another fix for filename handling in the tests. Tests were + giving false failures on Win32 because the tests needed to use + File::Spec->canonpath(), just like Devel::StackTrace does + internally. + + +1.12 2005-09-30 + +- Newer versions of Perl use Unix-style filenames when reporting the + filename in caller(), which breaks Exception::Class tests on other + platforms, and is just kind of funky. This module now calls + File::Spec->canonpath() to clean up the filename in each frame. + Reported by Garret Goebel. + + +1.11 2004-04-12 + +- No code changes, just switching to including a Makefile.PL that uses + ExtUtils::MakeMaker instead of one that sneakily uses Module::Build. + Requested by Perrin Harkins. + + +1.10 2004-03-10 + +- Silence a warning from the test code if Exception::Class isn't + installed. Reported by Stefano Ruberti. + +- Localize $@ to avoid overwriting a previously set $@ while creating + a Devel::StackTrace object. This caused a test failure in the + Exception::Class tests when run with Perl 5.6.1, but not with 5.8.3. + I don't really know how to test for it outside of Exception::Class. + Reported by Jesse Erlbaum. + + +1.09 2004-02-26 + +- The overload workaround blows up if a DBI handle is anywhere in the + stack, because of a bad interaction between overload::Overloaded and + DBI's custom dispatching. This release works around that. + + +1.08 2004-02-23 + +- Some tests failed on Win32 because they were hardcoded to expect a + file name with forward slashes. Reported by Steve Hay. + + +1.07 2004-02-21 + +- This release includes a change to the overload handling that is + necessary for cooperation with Exception::Class. + + +1.06 2004-02-21 + +- Devel::StackTrace now uses overload::StrVal() to get the underlying + string value of an overloaded object when creating a stack frame for + display. This can be turned off by setting respect_overload to a + true value. Suggested by Matt Sisk. + + +1.05 2004-02-17 + +- Devel::StackTrace incorrectly reported that arguments were being + passed to eval blocks (which isn't possible). Reported by Mark + Dedlow. + + +1.04 2003-09-25 + +- The special handling of Exception::Class::Base objects was broken. + This was exposed by the fact that Exception::Class 1.15 now uses + Devel::StackTrace in a slightly different way than it did + previously. + + +1.03 2003-01-22 + +- Special handling of Exception::Class::Base objects when stringifying + references. This avoids infinite recursion between the two classes. + + +1.02 2002-09-19 + +- Forgot to add Test::More to PREREQ_PM for previous releases. + + +1.01 2002-09-18 + +- Change the "no object refs" feature to be a plain old "no refs" + feature. As was pointed out to me by Jean-Phillippe Bouchard, a + plain reference (to an array, for example), can easily hold + references to objects internally. And since I'm not going to bother + descending through nested data structures weeding out objects, this + is an easier way to handle the problem. Thanks to Jean-Phillippe + Bouchard for a patch for this as well. + + The "no_object_refs" parameter is deprecated, and now does the same + thing as the "no_refs" parameter. + + +1.00 2010-10-15 + +- Add an option to not store references to objects in stack frames. + This can be important if you're expecting DESTROY to be called but a + Devel::StackTraceFrame object is still holding a reference to your + object(s). Based on discussion with Tatsuhiko Miyagawa. + + +0.9 2001-11-24 + +- Doc tweaks. + + +0.85 2000-09-02 + +- doc bug fix that made it seem like args method was only available + under Perl 5.6.0 + +- converted objects from pseudo-hashes to regular hashes. + + +0.8 2000-09-02 + +- Should work under Perl 5.6.0+. + +- Added hints & bitmask methods for use under Perl 5.6.0. + + +0.75 2000-06-29 + +- Added frames method (and docs for it). + +- Added 'use 5.005' which I should have put in there earlier. + +- DOCS: explanation of 'top' and 'bottom' as they refer to the stack. + + +0.7 2000-06-27 + +- First release (I think) diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..ca65ad5 --- /dev/null +++ b/INSTALL @@ -0,0 +1,75 @@ +This is the Perl distribution Devel-StackTrace. + +Installing Devel-StackTrace is straightforward. + +## Installation with cpanm + +If you have cpanm, you only need one line: + + % cpanm Devel::StackTrace + +If it does not have permission to install modules to the current perl, cpanm +will automatically set up and install to a local::lib in your home directory. +See the local::lib documentation (https://metacpan.org/pod/local::lib) for +details on enabling it in your environment. + +## Installing with the CPAN shell + +Alternatively, if your CPAN shell is set up, you should just be able to do: + + % cpan Devel::StackTrace + +## Manual installation + +As a last resort, you can manually install it. If you have not already +downloaded the release tarball, you can find the download link on the module's +MetaCPAN page: https://metacpan.org/pod/Devel::StackTrace + +Untar the tarball, install configure prerequisites (see below), then build it: + + % perl Makefile.PL + % make && make test + +Then install it: + + % make install + +On Windows platforms, you should use `dmake` or `nmake`, instead of `make`. + +If your perl is system-managed, you can create a local::lib in your home +directory to install modules to. For details, see the local::lib documentation: +https://metacpan.org/pod/local::lib + +The prerequisites of this distribution will also have to be installed manually. The +prerequisites are listed in one of the files: `MYMETA.yml` or `MYMETA.json` generated +by running the manual build process described above. + +## Configure Prerequisites + +This distribution requires other modules to be installed before this +distribution's installer can be run. They can be found under the +"configure_requires" key of META.yml or the +"{prereqs}{configure}{requires}" key of META.json. + +## Other Prerequisites + +This distribution may require additional modules to be installed after running +Makefile.PL. +Look for prerequisites in the following phases: + +* to run make, PHASE = build +* to use the module code itself, PHASE = runtime +* to run tests, PHASE = test + +They can all be found in the "PHASE_requires" key of MYMETA.yml or the +"{prereqs}{PHASE}{requires}" key of MYMETA.json. + +## Documentation + +Devel-StackTrace documentation is available as POD. +You can run `perldoc` from a shell to read the documentation: + + % perldoc Devel::StackTrace + +For more information on installing Perl modules via CPAN, please see: +https://www.cpan.org/modules/INSTALL.html diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a9bfe88 --- /dev/null +++ b/LICENSE @@ -0,0 +1,207 @@ +This software is Copyright (c) 2000 - 2024 by David Rolsky. + +This is free software, licensed under: + + The Artistic License 2.0 (GPL Compatible) + + The Artistic License 2.0 + + Copyright (c) 2000-2006, The Perl Foundation. + + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +Preamble + +This license establishes the terms under which a given free software +Package may be copied, modified, distributed, and/or redistributed. +The intent is that the Copyright Holder maintains some artistic +control over the development of that Package while still keeping the +Package available as open source and free software. + +You are always permitted to make arrangements wholly outside of this +license directly with the Copyright Holder of a given Package. If the +terms of this license do not permit the full use that you propose to +make of the Package, you should contact the Copyright Holder and seek +a different licensing arrangement. + +Definitions + + "Copyright Holder" means the individual(s) or organization(s) + named in the copyright notice for the entire Package. + + "Contributor" means any party that has contributed code or other + material to the Package, in accordance with the Copyright Holder's + procedures. + + "You" and "your" means any person who would like to copy, + distribute, or modify the Package. + + "Package" means the collection of files distributed by the + Copyright Holder, and derivatives of that collection and/or of + those files. A given Package may consist of either the Standard + Version, or a Modified Version. + + "Distribute" means providing a copy of the Package or making it + accessible to anyone else, or in the case of a company or + organization, to others outside of your company or organization. + + "Distributor Fee" means any fee that you charge for Distributing + this Package or providing support for this Package to another + party. It does not mean licensing fees. + + "Standard Version" refers to the Package if it has not been + modified, or has been modified only in ways explicitly requested + by the Copyright Holder. + + "Modified Version" means the Package, if it has been changed, and + such changes were not explicitly requested by the Copyright + Holder. + + "Original License" means this Artistic License as Distributed with + the Standard Version of the Package, in its current version or as + it may be modified by The Perl Foundation in the future. + + "Source" form means the source code, documentation source, and + configuration files for the Package. + + "Compiled" form means the compiled bytecode, object code, binary, + or any other form resulting from mechanical transformation or + translation of the Source form. + + +Permission for Use and Modification Without Distribution + +(1) You are permitted to use the Standard Version and create and use +Modified Versions for any purpose without restriction, provided that +you do not Distribute the Modified Version. + + +Permissions for Redistribution of the Standard Version + +(2) You may Distribute verbatim copies of the Source form of the +Standard Version of this Package in any medium without restriction, +either gratis or for a Distributor Fee, provided that you duplicate +all of the original copyright notices and associated disclaimers. At +your discretion, such verbatim copies may or may not include a +Compiled form of the Package. + +(3) You may apply any bug fixes, portability changes, and other +modifications made available from the Copyright Holder. The resulting +Package will still be considered the Standard Version, and as such +will be subject to the Original License. + + +Distribution of Modified Versions of the Package as Source + +(4) You may Distribute your Modified Version as Source (either gratis +or for a Distributor Fee, and with or without a Compiled form of the +Modified Version) provided that you clearly document how it differs +from the Standard Version, including, but not limited to, documenting +any non-standard features, executables, or modules, and provided that +you do at least ONE of the following: + + (a) make the Modified Version available to the Copyright Holder + of the Standard Version, under the Original License, so that the + Copyright Holder may include your modifications in the Standard + Version. + + (b) ensure that installation of your Modified Version does not + prevent the user installing or running the Standard Version. In + addition, the Modified Version must bear a name that is different + from the name of the Standard Version. + + (c) allow anyone who receives a copy of the Modified Version to + make the Source form of the Modified Version available to others + under + + (i) the Original License or + + (ii) a license that permits the licensee to freely copy, + modify and redistribute the Modified Version using the same + licensing terms that apply to the copy that the licensee + received, and requires that the Source form of the Modified + Version, and of any works derived from it, be made freely + available in that license fees are prohibited but Distributor + Fees are allowed. + + +Distribution of Compiled Forms of the Standard Version +or Modified Versions without the Source + +(5) You may Distribute Compiled forms of the Standard Version without +the Source, provided that you include complete instructions on how to +get the Source of the Standard Version. Such instructions must be +valid at the time of your distribution. If these instructions, at any +time while you are carrying out such distribution, become invalid, you +must provide new instructions on demand or cease further distribution. +If you provide valid instructions or cease distribution within thirty +days after you become aware that the instructions are invalid, then +you do not forfeit any of your rights under this license. + +(6) You may Distribute a Modified Version in Compiled form without +the Source, provided that you comply with Section 4 with respect to +the Source of the Modified Version. + + +Aggregating or Linking the Package + +(7) You may aggregate the Package (either the Standard Version or +Modified Version) with other packages and Distribute the resulting +aggregation provided that you do not charge a licensing fee for the +Package. Distributor Fees are permitted, and licensing fees for other +components in the aggregation are permitted. The terms of this license +apply to the use and Distribution of the Standard or Modified Versions +as included in the aggregation. + +(8) You are permitted to link Modified and Standard Versions with +other works, to embed the Package in a larger work of your own, or to +build stand-alone binary or bytecode versions of applications that +include the Package, and Distribute the result without restriction, +provided the result does not expose a direct interface to the Package. + + +Items That are Not Considered Part of a Modified Version + +(9) Works (including, but not limited to, modules and scripts) that +merely extend or make use of the Package, do not, by themselves, cause +the Package to be a Modified Version. In addition, such works are not +considered parts of the Package itself, and are not subject to the +terms of this license. + + +General Provisions + +(10) Any use, modification, and distribution of the Standard or +Modified Versions is governed by this Artistic License. By using, +modifying or distributing the Package, you accept this license. Do not +use, modify, or distribute the Package, if you do not accept this +license. + +(11) If your Modified Version has been derived from a Modified +Version made by someone other than you, you are nevertheless required +to ensure that your Modified Version complies with the requirements of +this license. + +(12) This license does not grant you the right to use any trademark, +service mark, tradename, or logo of the Copyright Holder. + +(13) This license includes the non-exclusive, worldwide, +free-of-charge patent license to make, have made, use, offer to sell, +sell, import and otherwise transfer the Package with respect to any +patent claims licensable by the Copyright Holder that are necessarily +infringed by the Package. If you institute patent litigation +(including a cross-claim or counterclaim) against any party alleging +that the Package constitutes direct or contributory patent +infringement, then this Artistic License to you shall terminate on the +date that such litigation is filed. + +(14) Disclaimer of Warranty: +THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS +IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL +LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/MANIFEST b/MANIFEST new file mode 100644 index 0000000..a62592e --- /dev/null +++ b/MANIFEST @@ -0,0 +1,47 @@ +# This file was automatically generated by Dist::Zilla::Plugin::Manifest v6.031. +CODE_OF_CONDUCT.md +CONTRIBUTING.md +Changes +INSTALL +LICENSE +MANIFEST +META.json +META.yml +Makefile.PL +README.md +azure-pipelines.yml +cpanfile +dev-bin/install-xt-tools.sh +dist.ini +git/hooks/pre-commit.sh +git/setup.pl +lib/Devel/StackTrace.pm +lib/Devel/StackTrace/Frame.pm +perlcriticrc +perltidyrc +precious.toml +t/00-report-prereqs.dd +t/00-report-prereqs.t +t/01-basic.t +t/02-bad-utf8.t +t/03-message.t +t/04-indent.t +t/05-back-compat.t +t/06-dollar-at.t +t/07-no-args.t +t/08-filter-early.t +t/09-skip-frames.t +t/10-set-frames.t +xt/author/00-compile.t +xt/author/eol.t +xt/author/mojibake.t +xt/author/no-tabs.t +xt/author/pod-coverage.t +xt/author/pod-spell.t +xt/author/pod-syntax.t +xt/author/portability.t +xt/author/precious.t +xt/author/synopsis.t +xt/author/test-version.t +xt/release/cpan-changes.t +xt/release/meta-json.t diff --git a/META.json b/META.json new file mode 100644 index 0000000..38c75f1 --- /dev/null +++ b/META.json @@ -0,0 +1,1077 @@ +{ + "abstract" : "An object representing a stack trace", + "author" : [ + "Dave Rolsky " + ], + "dynamic_config" : 0, + "generated_by" : "Dist::Zilla version 6.031, CPAN::Meta::Converter version 2.150010", + "license" : [ + "artistic_2" + ], + "meta-spec" : { + "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", + "version" : 2 + }, + "name" : "Devel-StackTrace", + "prereqs" : { + "configure" : { + "requires" : { + "ExtUtils::MakeMaker" : "0" + }, + "suggests" : { + "JSON::PP" : "2.27300" + } + }, + "develop" : { + "requires" : { + "Capture::Tiny" : "0", + "Encode" : "0", + "File::Spec" : "0", + "FindBin" : "0", + "IO::Handle" : "0", + "IPC::Open3" : "0", + "Perl::Critic" : "1.138", + "Perl::Critic::Moose" : "1.05", + "Perl::Tidy" : "20210111", + "Pod::Checker" : "1.74", + "Pod::Coverage::TrustPod" : "0", + "Pod::Tidy" : "0.10", + "Pod::Wordlist" : "0", + "Test::CPAN::Changes" : "0.19", + "Test::CPAN::Meta::JSON" : "0.16", + "Test::EOL" : "0", + "Test::Mojibake" : "0", + "Test::More" : "0.88", + "Test::NoTabs" : "0", + "Test::Pod" : "1.41", + "Test::Pod::Coverage" : "1.08", + "Test::Portability::Files" : "0", + "Test::Spelling" : "0.12", + "Test::Synopsis" : "0", + "Test::Version" : "2.05" + } + }, + "runtime" : { + "requires" : { + "File::Spec" : "0", + "Scalar::Util" : "0", + "overload" : "0", + "perl" : "5.006", + "strict" : "0", + "warnings" : "0" + } + }, + "test" : { + "recommends" : { + "CPAN::Meta" : "2.120900" + }, + "requires" : { + "ExtUtils::MakeMaker" : "0", + "File::Spec" : "0", + "Test::More" : "0.96", + "base" : "0", + "bytes" : "0" + } + } + }, + "provides" : { + "Devel::StackTrace" : { + "file" : "lib/Devel/StackTrace.pm", + "version" : "2.05" + }, + "Devel::StackTrace::Frame" : { + "file" : "lib/Devel/StackTrace/Frame.pm", + "version" : "2.05" + } + }, + "release_status" : "stable", + "resources" : { + "bugtracker" : { + "web" : "https://github.com/houseabsolute/Devel-StackTrace/issues" + }, + "homepage" : "https://metacpan.org/release/Devel-StackTrace", + "repository" : { + "type" : "git", + "url" : "git://github.com/houseabsolute/Devel-StackTrace.git", + "web" : "https://github.com/houseabsolute/Devel-StackTrace" + } + }, + "version" : "2.05", + "x_Dist_Zilla" : { + "perl" : { + "version" : "5.038002" + }, + "plugins" : [ + { + "class" : "Dist::Zilla::Plugin::DROLSKY::BundleAuthordep", + "name" : "@DROLSKY/DROLSKY::BundleAuthordep", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::Git::GatherDir", + "config" : { + "Dist::Zilla::Plugin::GatherDir" : { + "exclude_filename" : [ + "CODE_OF_CONDUCT.md", + "CONTRIBUTING.md", + "LICENSE", + "Makefile.PL", + "README.md", + "cpanfile" + ], + "exclude_match" : [], + "include_dotfiles" : 0, + "prefix" : "", + "prune_directory" : [], + "root" : "." + }, + "Dist::Zilla::Plugin::Git::GatherDir" : { + "include_untracked" : 0 + } + }, + "name" : "@DROLSKY/Git::GatherDir", + "version" : "2.049" + }, + { + "class" : "Dist::Zilla::Plugin::ManifestSkip", + "name" : "@DROLSKY/ManifestSkip", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::License", + "name" : "@DROLSKY/License", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::ExecDir", + "name" : "@DROLSKY/ExecDir", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::ShareDir", + "name" : "@DROLSKY/ShareDir", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::Manifest", + "name" : "@DROLSKY/Manifest", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::CheckVersionIncrement", + "name" : "@DROLSKY/CheckVersionIncrement", + "version" : "0.121750" + }, + { + "class" : "Dist::Zilla::Plugin::TestRelease", + "name" : "@DROLSKY/TestRelease", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::ConfirmRelease", + "name" : "@DROLSKY/ConfirmRelease", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::UploadToCPAN", + "name" : "@DROLSKY/UploadToCPAN", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::VersionFromMainModule", + "config" : { + "Dist::Zilla::Role::ModuleMetadata" : { + "Module::Metadata" : "1.000037", + "version" : "0.006" + } + }, + "name" : "@DROLSKY/VersionFromMainModule", + "version" : "0.04" + }, + { + "class" : "Dist::Zilla::Plugin::Authority", + "name" : "@DROLSKY/Authority", + "version" : "1.009" + }, + { + "class" : "Dist::Zilla::Plugin::AutoPrereqs", + "name" : "@DROLSKY/AutoPrereqs", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::CopyFilesFromBuild", + "name" : "@DROLSKY/CopyFilesFromBuild", + "version" : "0.170880" + }, + { + "class" : "Dist::Zilla::Plugin::GitHub::Meta", + "name" : "@DROLSKY/GitHub::Meta", + "version" : "0.49" + }, + { + "class" : "Dist::Zilla::Plugin::GitHub::Update", + "config" : { + "Dist::Zilla::Plugin::GitHub::Update" : { + "metacpan" : 1 + } + }, + "name" : "@DROLSKY/GitHub::Update", + "version" : "0.49" + }, + { + "class" : "Dist::Zilla::Plugin::MetaResources", + "name" : "@DROLSKY/MetaResources", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::MetaProvides::Package", + "config" : { + "Dist::Zilla::Plugin::MetaProvides::Package" : { + "finder_objects" : [ + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : "@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM", + "version" : "6.031" + } + ], + "include_underscores" : 0 + }, + "Dist::Zilla::Role::MetaProvider::Provider" : { + "$Dist::Zilla::Role::MetaProvider::Provider::VERSION" : "2.002004", + "inherit_missing" : 1, + "inherit_version" : 1, + "meta_noindex" : 1 + }, + "Dist::Zilla::Role::ModuleMetadata" : { + "Module::Metadata" : "1.000037", + "version" : "0.006" + } + }, + "name" : "@DROLSKY/MetaProvides::Package", + "version" : "2.004003" + }, + { + "class" : "Dist::Zilla::Plugin::Meta::Contributors", + "name" : "@DROLSKY/Meta::Contributors", + "version" : "0.003" + }, + { + "class" : "Dist::Zilla::Plugin::MetaConfig", + "name" : "@DROLSKY/MetaConfig", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::MetaJSON", + "name" : "@DROLSKY/MetaJSON", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::MetaYAML", + "name" : "@DROLSKY/MetaYAML", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::NextRelease", + "name" : "@DROLSKY/NextRelease", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::Prereqs", + "config" : { + "Dist::Zilla::Plugin::Prereqs" : { + "phase" : "test", + "type" : "requires" + } + }, + "name" : "@DROLSKY/Test::More with subtest", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::Prereqs", + "config" : { + "Dist::Zilla::Plugin::Prereqs" : { + "phase" : "develop", + "type" : "requires" + } + }, + "name" : "@DROLSKY/Tools for use with precious", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::Prereqs", + "config" : { + "Dist::Zilla::Plugin::Prereqs" : { + "phase" : "develop", + "type" : "requires" + } + }, + "name" : "@DROLSKY/Test::Version which fixes https://github.com/plicease/Test-Version/issues/7", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::PromptIfStale", + "config" : { + "Dist::Zilla::Plugin::PromptIfStale" : { + "check_all_plugins" : 0, + "check_all_prereqs" : 0, + "modules" : [ + "Dist::Zilla::PluginBundle::DROLSKY" + ], + "phase" : "build", + "run_under_travis" : 0, + "skip" : [] + } + }, + "name" : "@DROLSKY/Dist::Zilla::PluginBundle::DROLSKY", + "version" : "0.058" + }, + { + "class" : "Dist::Zilla::Plugin::PromptIfStale", + "config" : { + "Dist::Zilla::Plugin::PromptIfStale" : { + "check_all_plugins" : 1, + "check_all_prereqs" : 1, + "modules" : [], + "phase" : "release", + "run_under_travis" : 0, + "skip" : [ + "Dist::Zilla::Plugin::DROLSKY::BundleAuthordep", + "Dist::Zilla::Plugin::DROLSKY::Contributors", + "Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch", + "Dist::Zilla::Plugin::DROLSKY::License", + "Dist::Zilla::Plugin::DROLSKY::MakeMaker", + "Dist::Zilla::Plugin::DROLSKY::PerlLinterConfigFiles", + "Dist::Zilla::Plugin::DROLSKY::Precious", + "Dist::Zilla::Plugin::DROLSKY::Test::Precious", + "Dist::Zilla::Plugin::DROLSKY::WeaverConfig", + "Pod::Weaver::PluginBundle::DROLSKY" + ] + } + }, + "name" : "@DROLSKY/PromptIfStale", + "version" : "0.058" + }, + { + "class" : "Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable", + "name" : "@DROLSKY/Test::Pod::Coverage::Configurable", + "version" : "0.07" + }, + { + "class" : "Dist::Zilla::Plugin::Test::PodSpelling", + "config" : { + "Dist::Zilla::Plugin::Test::PodSpelling" : { + "directories" : [ + "bin", + "lib" + ], + "spell_cmd" : "", + "stopwords" : [ + "CPAN", + "DROLSKY", + "DROLSKY's", + "PayPal", + "Rolsky", + "Rolsky", + "Rolsky's", + "drolsky", + "stacktrace" + ], + "wordlist" : "Pod::Wordlist" + } + }, + "name" : "@DROLSKY/Test::PodSpelling", + "version" : "2.007005" + }, + { + "class" : "Dist::Zilla::Plugin::PodSyntaxTests", + "name" : "@DROLSKY/PodSyntaxTests", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::MojibakeTests", + "name" : "@DROLSKY/MojibakeTests", + "version" : "0.8" + }, + { + "class" : "Dist::Zilla::Plugin::RunExtraTests", + "config" : { + "Dist::Zilla::Role::TestRunner" : { + "default_jobs" : "12" + } + }, + "name" : "@DROLSKY/RunExtraTests", + "version" : "0.029" + }, + { + "class" : "Dist::Zilla::Plugin::Test::CPAN::Changes", + "config" : { + "Dist::Zilla::Plugin::Test::CPAN::Changes" : { + "changelog" : "Changes" + } + }, + "name" : "@DROLSKY/Test::CPAN::Changes", + "version" : "0.012" + }, + { + "class" : "Dist::Zilla::Plugin::Test::CPAN::Meta::JSON", + "name" : "@DROLSKY/Test::CPAN::Meta::JSON", + "version" : "0.004" + }, + { + "class" : "Dist::Zilla::Plugin::Test::EOL", + "config" : { + "Dist::Zilla::Plugin::Test::EOL" : { + "filename" : "xt/author/eol.t", + "finder" : [ + ":ExecFiles", + ":InstallModules", + ":TestFiles" + ], + "trailing_whitespace" : 1 + } + }, + "name" : "@DROLSKY/Test::EOL", + "version" : "0.19" + }, + { + "class" : "Dist::Zilla::Plugin::Test::NoTabs", + "config" : { + "Dist::Zilla::Plugin::Test::NoTabs" : { + "filename" : "xt/author/no-tabs.t", + "finder" : [ + ":InstallModules", + ":ExecFiles", + ":TestFiles" + ] + } + }, + "name" : "@DROLSKY/Test::NoTabs", + "version" : "0.15" + }, + { + "class" : "Dist::Zilla::Plugin::Test::Portability", + "config" : { + "Dist::Zilla::Plugin::Test::Portability" : { + "options" : "" + } + }, + "name" : "@DROLSKY/Test::Portability", + "version" : "2.001001" + }, + { + "class" : "Dist::Zilla::Plugin::Test::Synopsis", + "name" : "@DROLSKY/Test::Synopsis", + "version" : "2.000007" + }, + { + "class" : "Dist::Zilla::Plugin::Test::Compile", + "config" : { + "Dist::Zilla::Plugin::Test::Compile" : { + "bail_out_on_fail" : 0, + "fail_on_warning" : "author", + "fake_home" : 0, + "filename" : "xt/author/00-compile.t", + "module_finder" : [ + ":InstallModules" + ], + "needs_display" : 0, + "phase" : "develop", + "script_finder" : [ + ":PerlExecFiles" + ], + "skips" : [], + "switch" : [] + } + }, + "name" : "@DROLSKY/Test::Compile", + "version" : "2.058" + }, + { + "class" : "Dist::Zilla::Plugin::Test::ReportPrereqs", + "name" : "@DROLSKY/Test::ReportPrereqs", + "version" : "0.029" + }, + { + "class" : "Dist::Zilla::Plugin::Test::Version", + "name" : "@DROLSKY/Test::Version", + "version" : "1.09" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::Test::Precious", + "name" : "@DROLSKY/DROLSKY::Test::Precious", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::Contributors", + "name" : "@DROLSKY/DROLSKY::Contributors", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Contributors", + "config" : { + "Dist::Zilla::Plugin::Git::Contributors" : { + "git_version" : "2.43.0", + "include_authors" : 0, + "include_releaser" : 1, + "order_by" : "name", + "paths" : [] + } + }, + "name" : "@DROLSKY/Git::Contributors", + "version" : "0.036" + }, + { + "class" : "Dist::Zilla::Plugin::SurgicalPodWeaver", + "config" : { + "Dist::Zilla::Plugin::PodWeaver" : { + "config_plugins" : [ + "@DROLSKY" + ], + "finder" : [ + ":InstallModules", + ":PerlExecFiles" + ], + "plugins" : [ + { + "class" : "Pod::Weaver::Plugin::EnsurePod5", + "name" : "@CorePrep/EnsurePod5", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Plugin::H1Nester", + "name" : "@CorePrep/H1Nester", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Plugin::SingleEncoding", + "name" : "@DROLSKY/SingleEncoding", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Plugin::Transformer", + "name" : "@DROLSKY/List", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Plugin::Transformer", + "name" : "@DROLSKY/Verbatim", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@DROLSKY/header", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Name", + "name" : "@DROLSKY/Name", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Version", + "name" : "@DROLSKY/Version", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@DROLSKY/prelude", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "SYNOPSIS", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "DESCRIPTION", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Generic", + "name" : "OVERVIEW", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "ATTRIBUTES", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "METHODS", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "FUNCTIONS", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Collect", + "name" : "TYPES", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Leftovers", + "name" : "@DROLSKY/Leftovers", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@DROLSKY/postlude", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::GenerateSection", + "name" : "@DROLSKY/generate SUPPORT", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::AllowOverride", + "name" : "@DROLSKY/allow override SUPPORT", + "version" : "0.05" + }, + { + "class" : "Pod::Weaver::Section::GenerateSection", + "name" : "@DROLSKY/generate SOURCE", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::GenerateSection", + "name" : "@DROLSKY/generate DONATIONS", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Authors", + "name" : "@DROLSKY/Authors", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::Contributors", + "name" : "@DROLSKY/Contributors", + "version" : "0.009" + }, + { + "class" : "Pod::Weaver::Section::Legal", + "name" : "@DROLSKY/Legal", + "version" : "4.019" + }, + { + "class" : "Pod::Weaver::Section::AllowOverride", + "name" : "@DROLSKY/allow override Legal", + "version" : "0.05" + }, + { + "class" : "Pod::Weaver::Section::Region", + "name" : "@DROLSKY/footer", + "version" : "4.019" + } + ] + } + }, + "name" : "@DROLSKY/SurgicalPodWeaver", + "version" : "0.0023" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::WeaverConfig", + "name" : "@DROLSKY/DROLSKY::WeaverConfig", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod", + "config" : { + "Dist::Zilla::Role::FileWatcher" : { + "version" : "0.006" + } + }, + "name" : "@DROLSKY/README.md in build", + "version" : "0.163250" + }, + { + "class" : "Dist::Zilla::Plugin::GenerateFile::FromShareDir", + "config" : { + "Dist::Zilla::Plugin::GenerateFile::FromShareDir" : { + "destination_filename" : "CONTRIBUTING.md", + "dist" : "Dist-Zilla-PluginBundle-DROLSKY", + "encoding" : "UTF-8", + "has_xs" : 0, + "location" : "build", + "source_filename" : "CONTRIBUTING.md" + }, + "Dist::Zilla::Role::RepoFileInjector" : { + "allow_overwrite" : 1, + "repo_root" : ".", + "version" : "0.009" + } + }, + "name" : "@DROLSKY/Generate CONTRIBUTING.md", + "version" : "0.015" + }, + { + "class" : "Dist::Zilla::Plugin::GenerateFile::FromShareDir", + "config" : { + "Dist::Zilla::Plugin::GenerateFile::FromShareDir" : { + "destination_filename" : "CODE_OF_CONDUCT.md", + "dist" : "Dist-Zilla-PluginBundle-DROLSKY", + "encoding" : "UTF-8", + "has_xs" : 0, + "location" : "build", + "source_filename" : "CODE_OF_CONDUCT.md" + }, + "Dist::Zilla::Role::RepoFileInjector" : { + "allow_overwrite" : 1, + "repo_root" : ".", + "version" : "0.009" + } + }, + "name" : "@DROLSKY/Generate CODE_OF_CONDUCT.md", + "version" : "0.015" + }, + { + "class" : "Dist::Zilla::Plugin::InstallGuide", + "config" : { + "Dist::Zilla::Role::ModuleMetadata" : { + "Module::Metadata" : "1.000037", + "version" : "0.006" + } + }, + "name" : "@DROLSKY/InstallGuide", + "version" : "1.200014" + }, + { + "class" : "Dist::Zilla::Plugin::CPANFile", + "name" : "@DROLSKY/CPANFile", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::License", + "name" : "@DROLSKY/DROLSKY::License", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::CheckStrictVersion", + "name" : "@DROLSKY/CheckStrictVersion", + "version" : "0.001" + }, + { + "class" : "Dist::Zilla::Plugin::CheckSelfDependency", + "config" : { + "Dist::Zilla::Plugin::CheckSelfDependency" : { + "finder" : [ + ":InstallModules" + ] + }, + "Dist::Zilla::Role::ModuleMetadata" : { + "Module::Metadata" : "1.000037", + "version" : "0.006" + } + }, + "name" : "@DROLSKY/CheckSelfDependency", + "version" : "0.011" + }, + { + "class" : "Dist::Zilla::Plugin::CheckPrereqsIndexed", + "name" : "@DROLSKY/CheckPrereqsIndexed", + "version" : "0.022" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch", + "config" : { + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.43.0", + "repo_root" : "." + } + }, + "name" : "@DROLSKY/DROLSKY::Git::CheckFor::CorrectBranch", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::EnsureChangesHasContent", + "name" : "@DROLSKY/EnsureChangesHasContent", + "version" : "0.02" + }, + { + "class" : "Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts", + "config" : { + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.43.0", + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::CheckFor::MergeConflicts", + "version" : "0.014" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::PerlLinterConfigFiles", + "name" : "@DROLSKY/DROLSKY::PerlLinterConfigFiles", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::DevTools", + "name" : "@DROLSKY/DROLSKY::DevTools", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::Precious", + "name" : "@DROLSKY/DROLSKY::Precious", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Check", + "config" : { + "Dist::Zilla::Plugin::Git::Check" : { + "untracked_files" : "die" + }, + "Dist::Zilla::Role::Git::DirtyFiles" : { + "allow_dirty" : [ + "CODE_OF_CONDUCT.md", + "CONTRIBUTING.md", + "Changes", + "LICENSE", + "Makefile.PL", + "README.md", + "cpanfile", + "precious.toml" + ], + "allow_dirty_match" : [], + "changelog" : "Changes" + }, + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.43.0", + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::Check", + "version" : "2.049" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Commit", + "config" : { + "Dist::Zilla::Plugin::Git::Commit" : { + "add_files_in" : [], + "commit_msg" : "v%V%n%n%c", + "signoff" : 0 + }, + "Dist::Zilla::Role::Git::DirtyFiles" : { + "allow_dirty" : [ + "CODE_OF_CONDUCT.md", + "CONTRIBUTING.md", + "Changes", + "LICENSE", + "Makefile.PL", + "README.md", + "cpanfile", + "precious.toml" + ], + "allow_dirty_match" : [], + "changelog" : "Changes" + }, + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.43.0", + "repo_root" : "." + }, + "Dist::Zilla::Role::Git::StringFormatter" : { + "time_zone" : "local" + } + }, + "name" : "@DROLSKY/Commit generated files", + "version" : "2.049" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Tag", + "config" : { + "Dist::Zilla::Plugin::Git::Tag" : { + "branch" : null, + "changelog" : "Changes", + "signed" : 0, + "tag" : "v2.05", + "tag_format" : "v%V", + "tag_message" : "v%V" + }, + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.43.0", + "repo_root" : "." + }, + "Dist::Zilla::Role::Git::StringFormatter" : { + "time_zone" : "local" + } + }, + "name" : "@DROLSKY/Git::Tag", + "version" : "2.049" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Push", + "config" : { + "Dist::Zilla::Plugin::Git::Push" : { + "push_to" : [ + "origin" + ], + "remotes_must_exist" : 1 + }, + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.43.0", + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Git::Push", + "version" : "2.049" + }, + { + "class" : "Dist::Zilla::Plugin::BumpVersionAfterRelease", + "config" : { + "Dist::Zilla::Plugin::BumpVersionAfterRelease" : { + "finders" : [ + ":ExecFiles", + ":InstallModules" + ], + "global" : 0, + "munge_makefile_pl" : 1 + } + }, + "name" : "@DROLSKY/BumpVersionAfterRelease", + "version" : "0.018" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Commit", + "config" : { + "Dist::Zilla::Plugin::Git::Commit" : { + "add_files_in" : [], + "commit_msg" : "Bump version after release", + "signoff" : 0 + }, + "Dist::Zilla::Role::Git::DirtyFiles" : { + "allow_dirty" : [ + "Changes", + "dist.ini" + ], + "allow_dirty_match" : [ + "(?^:.+)" + ], + "changelog" : "Changes" + }, + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.43.0", + "repo_root" : "." + }, + "Dist::Zilla::Role::Git::StringFormatter" : { + "time_zone" : "local" + } + }, + "name" : "@DROLSKY/Commit version bump", + "version" : "2.049" + }, + { + "class" : "Dist::Zilla::Plugin::Git::Push", + "config" : { + "Dist::Zilla::Plugin::Git::Push" : { + "push_to" : [ + "origin" + ], + "remotes_must_exist" : 1 + }, + "Dist::Zilla::Role::Git::Repo" : { + "git_version" : "2.43.0", + "repo_root" : "." + } + }, + "name" : "@DROLSKY/Push version bump", + "version" : "2.049" + }, + { + "class" : "Dist::Zilla::Plugin::DROLSKY::MakeMaker", + "config" : { + "Dist::Zilla::Plugin::MakeMaker" : { + "make_path" : "make", + "version" : "6.031" + }, + "Dist::Zilla::Plugin::MakeMaker::Awesome" : { + "version" : "0.49" + }, + "Dist::Zilla::Role::TestRunner" : { + "default_jobs" : "12", + "version" : "6.031" + } + }, + "name" : "@DROLSKY/DROLSKY::MakeMaker", + "version" : "1.22" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":InstallModules", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":IncModules", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":TestFiles", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":ExtraTestFiles", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":ExecFiles", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":PerlExecFiles", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":ShareFiles", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":MainModule", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":AllFiles", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : ":NoFiles", + "version" : "6.031" + }, + { + "class" : "Dist::Zilla::Plugin::FinderCode", + "name" : "@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM", + "version" : "6.031" + } + ], + "zilla" : { + "class" : "Dist::Zilla::Dist::Builder", + "config" : { + "is_trial" : 0 + }, + "version" : "6.031" + } + }, + "x_authority" : "cpan:DROLSKY", + "x_contributors" : [ + "Dagfinn Ilmari Manns\u00e5ker ", + "David Cantrell ", + "Graham Knop ", + "Ivan Bessarabov ", + "Mark Fowler ", + "Pali ", + "Ricardo Signes " + ], + "x_generated_by_perl" : "v5.38.2", + "x_serialization_backend" : "Cpanel::JSON::XS version 4.37", + "x_spdx_expression" : "Artistic-2.0" +} + diff --git a/META.yml b/META.yml new file mode 100644 index 0000000..a3f592c --- /dev/null +++ b/META.yml @@ -0,0 +1,791 @@ +--- +abstract: 'An object representing a stack trace' +author: + - 'Dave Rolsky ' +build_requires: + ExtUtils::MakeMaker: '0' + File::Spec: '0' + Test::More: '0.96' + base: '0' + bytes: '0' +configure_requires: + ExtUtils::MakeMaker: '0' +dynamic_config: 0 +generated_by: 'Dist::Zilla version 6.031, CPAN::Meta::Converter version 2.150010' +license: artistic_2 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.4.html + version: '1.4' +name: Devel-StackTrace +provides: + Devel::StackTrace: + file: lib/Devel/StackTrace.pm + version: '2.05' + Devel::StackTrace::Frame: + file: lib/Devel/StackTrace/Frame.pm + version: '2.05' +requires: + File::Spec: '0' + Scalar::Util: '0' + overload: '0' + perl: '5.006' + strict: '0' + warnings: '0' +resources: + bugtracker: https://github.com/houseabsolute/Devel-StackTrace/issues + homepage: https://metacpan.org/release/Devel-StackTrace + repository: git://github.com/houseabsolute/Devel-StackTrace.git +version: '2.05' +x_Dist_Zilla: + perl: + version: '5.038002' + plugins: + - + class: Dist::Zilla::Plugin::DROLSKY::BundleAuthordep + name: '@DROLSKY/DROLSKY::BundleAuthordep' + version: '1.22' + - + class: Dist::Zilla::Plugin::Git::GatherDir + config: + Dist::Zilla::Plugin::GatherDir: + exclude_filename: + - CODE_OF_CONDUCT.md + - CONTRIBUTING.md + - LICENSE + - Makefile.PL + - README.md + - cpanfile + exclude_match: [] + include_dotfiles: 0 + prefix: '' + prune_directory: [] + root: . + Dist::Zilla::Plugin::Git::GatherDir: + include_untracked: 0 + name: '@DROLSKY/Git::GatherDir' + version: '2.049' + - + class: Dist::Zilla::Plugin::ManifestSkip + name: '@DROLSKY/ManifestSkip' + version: '6.031' + - + class: Dist::Zilla::Plugin::License + name: '@DROLSKY/License' + version: '6.031' + - + class: Dist::Zilla::Plugin::ExecDir + name: '@DROLSKY/ExecDir' + version: '6.031' + - + class: Dist::Zilla::Plugin::ShareDir + name: '@DROLSKY/ShareDir' + version: '6.031' + - + class: Dist::Zilla::Plugin::Manifest + name: '@DROLSKY/Manifest' + version: '6.031' + - + class: Dist::Zilla::Plugin::CheckVersionIncrement + name: '@DROLSKY/CheckVersionIncrement' + version: '0.121750' + - + class: Dist::Zilla::Plugin::TestRelease + name: '@DROLSKY/TestRelease' + version: '6.031' + - + class: Dist::Zilla::Plugin::ConfirmRelease + name: '@DROLSKY/ConfirmRelease' + version: '6.031' + - + class: Dist::Zilla::Plugin::UploadToCPAN + name: '@DROLSKY/UploadToCPAN' + version: '6.031' + - + class: Dist::Zilla::Plugin::VersionFromMainModule + config: + Dist::Zilla::Role::ModuleMetadata: + Module::Metadata: '1.000037' + version: '0.006' + name: '@DROLSKY/VersionFromMainModule' + version: '0.04' + - + class: Dist::Zilla::Plugin::Authority + name: '@DROLSKY/Authority' + version: '1.009' + - + class: Dist::Zilla::Plugin::AutoPrereqs + name: '@DROLSKY/AutoPrereqs' + version: '6.031' + - + class: Dist::Zilla::Plugin::CopyFilesFromBuild + name: '@DROLSKY/CopyFilesFromBuild' + version: '0.170880' + - + class: Dist::Zilla::Plugin::GitHub::Meta + name: '@DROLSKY/GitHub::Meta' + version: '0.49' + - + class: Dist::Zilla::Plugin::GitHub::Update + config: + Dist::Zilla::Plugin::GitHub::Update: + metacpan: 1 + name: '@DROLSKY/GitHub::Update' + version: '0.49' + - + class: Dist::Zilla::Plugin::MetaResources + name: '@DROLSKY/MetaResources' + version: '6.031' + - + class: Dist::Zilla::Plugin::MetaProvides::Package + config: + Dist::Zilla::Plugin::MetaProvides::Package: + finder_objects: + - + class: Dist::Zilla::Plugin::FinderCode + name: '@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM' + version: '6.031' + include_underscores: 0 + Dist::Zilla::Role::MetaProvider::Provider: + $Dist::Zilla::Role::MetaProvider::Provider::VERSION: '2.002004' + inherit_missing: 1 + inherit_version: 1 + meta_noindex: 1 + Dist::Zilla::Role::ModuleMetadata: + Module::Metadata: '1.000037' + version: '0.006' + name: '@DROLSKY/MetaProvides::Package' + version: '2.004003' + - + class: Dist::Zilla::Plugin::Meta::Contributors + name: '@DROLSKY/Meta::Contributors' + version: '0.003' + - + class: Dist::Zilla::Plugin::MetaConfig + name: '@DROLSKY/MetaConfig' + version: '6.031' + - + class: Dist::Zilla::Plugin::MetaJSON + name: '@DROLSKY/MetaJSON' + version: '6.031' + - + class: Dist::Zilla::Plugin::MetaYAML + name: '@DROLSKY/MetaYAML' + version: '6.031' + - + class: Dist::Zilla::Plugin::NextRelease + name: '@DROLSKY/NextRelease' + version: '6.031' + - + class: Dist::Zilla::Plugin::Prereqs + config: + Dist::Zilla::Plugin::Prereqs: + phase: test + type: requires + name: '@DROLSKY/Test::More with subtest' + version: '6.031' + - + class: Dist::Zilla::Plugin::Prereqs + config: + Dist::Zilla::Plugin::Prereqs: + phase: develop + type: requires + name: '@DROLSKY/Tools for use with precious' + version: '6.031' + - + class: Dist::Zilla::Plugin::Prereqs + config: + Dist::Zilla::Plugin::Prereqs: + phase: develop + type: requires + name: '@DROLSKY/Test::Version which fixes https://github.com/plicease/Test-Version/issues/7' + version: '6.031' + - + class: Dist::Zilla::Plugin::PromptIfStale + config: + Dist::Zilla::Plugin::PromptIfStale: + check_all_plugins: 0 + check_all_prereqs: 0 + modules: + - Dist::Zilla::PluginBundle::DROLSKY + phase: build + run_under_travis: 0 + skip: [] + name: '@DROLSKY/Dist::Zilla::PluginBundle::DROLSKY' + version: '0.058' + - + class: Dist::Zilla::Plugin::PromptIfStale + config: + Dist::Zilla::Plugin::PromptIfStale: + check_all_plugins: 1 + check_all_prereqs: 1 + modules: [] + phase: release + run_under_travis: 0 + skip: + - Dist::Zilla::Plugin::DROLSKY::BundleAuthordep + - Dist::Zilla::Plugin::DROLSKY::Contributors + - Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch + - Dist::Zilla::Plugin::DROLSKY::License + - Dist::Zilla::Plugin::DROLSKY::MakeMaker + - Dist::Zilla::Plugin::DROLSKY::PerlLinterConfigFiles + - Dist::Zilla::Plugin::DROLSKY::Precious + - Dist::Zilla::Plugin::DROLSKY::Test::Precious + - Dist::Zilla::Plugin::DROLSKY::WeaverConfig + - Pod::Weaver::PluginBundle::DROLSKY + name: '@DROLSKY/PromptIfStale' + version: '0.058' + - + class: Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable + name: '@DROLSKY/Test::Pod::Coverage::Configurable' + version: '0.07' + - + class: Dist::Zilla::Plugin::Test::PodSpelling + config: + Dist::Zilla::Plugin::Test::PodSpelling: + directories: + - bin + - lib + spell_cmd: '' + stopwords: + - CPAN + - DROLSKY + - "DROLSKY's" + - PayPal + - Rolsky + - Rolsky + - "Rolsky's" + - drolsky + - stacktrace + wordlist: Pod::Wordlist + name: '@DROLSKY/Test::PodSpelling' + version: '2.007005' + - + class: Dist::Zilla::Plugin::PodSyntaxTests + name: '@DROLSKY/PodSyntaxTests' + version: '6.031' + - + class: Dist::Zilla::Plugin::MojibakeTests + name: '@DROLSKY/MojibakeTests' + version: '0.8' + - + class: Dist::Zilla::Plugin::RunExtraTests + config: + Dist::Zilla::Role::TestRunner: + default_jobs: '12' + name: '@DROLSKY/RunExtraTests' + version: '0.029' + - + class: Dist::Zilla::Plugin::Test::CPAN::Changes + config: + Dist::Zilla::Plugin::Test::CPAN::Changes: + changelog: Changes + name: '@DROLSKY/Test::CPAN::Changes' + version: '0.012' + - + class: Dist::Zilla::Plugin::Test::CPAN::Meta::JSON + name: '@DROLSKY/Test::CPAN::Meta::JSON' + version: '0.004' + - + class: Dist::Zilla::Plugin::Test::EOL + config: + Dist::Zilla::Plugin::Test::EOL: + filename: xt/author/eol.t + finder: + - ':ExecFiles' + - ':InstallModules' + - ':TestFiles' + trailing_whitespace: 1 + name: '@DROLSKY/Test::EOL' + version: '0.19' + - + class: Dist::Zilla::Plugin::Test::NoTabs + config: + Dist::Zilla::Plugin::Test::NoTabs: + filename: xt/author/no-tabs.t + finder: + - ':InstallModules' + - ':ExecFiles' + - ':TestFiles' + name: '@DROLSKY/Test::NoTabs' + version: '0.15' + - + class: Dist::Zilla::Plugin::Test::Portability + config: + Dist::Zilla::Plugin::Test::Portability: + options: '' + name: '@DROLSKY/Test::Portability' + version: '2.001001' + - + class: Dist::Zilla::Plugin::Test::Synopsis + name: '@DROLSKY/Test::Synopsis' + version: '2.000007' + - + class: Dist::Zilla::Plugin::Test::Compile + config: + Dist::Zilla::Plugin::Test::Compile: + bail_out_on_fail: 0 + fail_on_warning: author + fake_home: 0 + filename: xt/author/00-compile.t + module_finder: + - ':InstallModules' + needs_display: 0 + phase: develop + script_finder: + - ':PerlExecFiles' + skips: [] + switch: [] + name: '@DROLSKY/Test::Compile' + version: '2.058' + - + class: Dist::Zilla::Plugin::Test::ReportPrereqs + name: '@DROLSKY/Test::ReportPrereqs' + version: '0.029' + - + class: Dist::Zilla::Plugin::Test::Version + name: '@DROLSKY/Test::Version' + version: '1.09' + - + class: Dist::Zilla::Plugin::DROLSKY::Test::Precious + name: '@DROLSKY/DROLSKY::Test::Precious' + version: '1.22' + - + class: Dist::Zilla::Plugin::DROLSKY::Contributors + name: '@DROLSKY/DROLSKY::Contributors' + version: '1.22' + - + class: Dist::Zilla::Plugin::Git::Contributors + config: + Dist::Zilla::Plugin::Git::Contributors: + git_version: 2.43.0 + include_authors: 0 + include_releaser: 1 + order_by: name + paths: [] + name: '@DROLSKY/Git::Contributors' + version: '0.036' + - + class: Dist::Zilla::Plugin::SurgicalPodWeaver + config: + Dist::Zilla::Plugin::PodWeaver: + config_plugins: + - '@DROLSKY' + finder: + - ':InstallModules' + - ':PerlExecFiles' + plugins: + - + class: Pod::Weaver::Plugin::EnsurePod5 + name: '@CorePrep/EnsurePod5' + version: '4.019' + - + class: Pod::Weaver::Plugin::H1Nester + name: '@CorePrep/H1Nester' + version: '4.019' + - + class: Pod::Weaver::Plugin::SingleEncoding + name: '@DROLSKY/SingleEncoding' + version: '4.019' + - + class: Pod::Weaver::Plugin::Transformer + name: '@DROLSKY/List' + version: '4.019' + - + class: Pod::Weaver::Plugin::Transformer + name: '@DROLSKY/Verbatim' + version: '4.019' + - + class: Pod::Weaver::Section::Region + name: '@DROLSKY/header' + version: '4.019' + - + class: Pod::Weaver::Section::Name + name: '@DROLSKY/Name' + version: '4.019' + - + class: Pod::Weaver::Section::Version + name: '@DROLSKY/Version' + version: '4.019' + - + class: Pod::Weaver::Section::Region + name: '@DROLSKY/prelude' + version: '4.019' + - + class: Pod::Weaver::Section::Generic + name: SYNOPSIS + version: '4.019' + - + class: Pod::Weaver::Section::Generic + name: DESCRIPTION + version: '4.019' + - + class: Pod::Weaver::Section::Generic + name: OVERVIEW + version: '4.019' + - + class: Pod::Weaver::Section::Collect + name: ATTRIBUTES + version: '4.019' + - + class: Pod::Weaver::Section::Collect + name: METHODS + version: '4.019' + - + class: Pod::Weaver::Section::Collect + name: FUNCTIONS + version: '4.019' + - + class: Pod::Weaver::Section::Collect + name: TYPES + version: '4.019' + - + class: Pod::Weaver::Section::Leftovers + name: '@DROLSKY/Leftovers' + version: '4.019' + - + class: Pod::Weaver::Section::Region + name: '@DROLSKY/postlude' + version: '4.019' + - + class: Pod::Weaver::Section::GenerateSection + name: '@DROLSKY/generate SUPPORT' + version: '4.019' + - + class: Pod::Weaver::Section::AllowOverride + name: '@DROLSKY/allow override SUPPORT' + version: '0.05' + - + class: Pod::Weaver::Section::GenerateSection + name: '@DROLSKY/generate SOURCE' + version: '4.019' + - + class: Pod::Weaver::Section::GenerateSection + name: '@DROLSKY/generate DONATIONS' + version: '4.019' + - + class: Pod::Weaver::Section::Authors + name: '@DROLSKY/Authors' + version: '4.019' + - + class: Pod::Weaver::Section::Contributors + name: '@DROLSKY/Contributors' + version: '0.009' + - + class: Pod::Weaver::Section::Legal + name: '@DROLSKY/Legal' + version: '4.019' + - + class: Pod::Weaver::Section::AllowOverride + name: '@DROLSKY/allow override Legal' + version: '0.05' + - + class: Pod::Weaver::Section::Region + name: '@DROLSKY/footer' + version: '4.019' + name: '@DROLSKY/SurgicalPodWeaver' + version: '0.0023' + - + class: Dist::Zilla::Plugin::DROLSKY::WeaverConfig + name: '@DROLSKY/DROLSKY::WeaverConfig' + version: '1.22' + - + class: Dist::Zilla::Plugin::ReadmeAnyFromPod + config: + Dist::Zilla::Role::FileWatcher: + version: '0.006' + name: '@DROLSKY/README.md in build' + version: '0.163250' + - + class: Dist::Zilla::Plugin::GenerateFile::FromShareDir + config: + Dist::Zilla::Plugin::GenerateFile::FromShareDir: + destination_filename: CONTRIBUTING.md + dist: Dist-Zilla-PluginBundle-DROLSKY + encoding: UTF-8 + has_xs: 0 + location: build + source_filename: CONTRIBUTING.md + Dist::Zilla::Role::RepoFileInjector: + allow_overwrite: 1 + repo_root: . + version: '0.009' + name: '@DROLSKY/Generate CONTRIBUTING.md' + version: '0.015' + - + class: Dist::Zilla::Plugin::GenerateFile::FromShareDir + config: + Dist::Zilla::Plugin::GenerateFile::FromShareDir: + destination_filename: CODE_OF_CONDUCT.md + dist: Dist-Zilla-PluginBundle-DROLSKY + encoding: UTF-8 + has_xs: 0 + location: build + source_filename: CODE_OF_CONDUCT.md + Dist::Zilla::Role::RepoFileInjector: + allow_overwrite: 1 + repo_root: . + version: '0.009' + name: '@DROLSKY/Generate CODE_OF_CONDUCT.md' + version: '0.015' + - + class: Dist::Zilla::Plugin::InstallGuide + config: + Dist::Zilla::Role::ModuleMetadata: + Module::Metadata: '1.000037' + version: '0.006' + name: '@DROLSKY/InstallGuide' + version: '1.200014' + - + class: Dist::Zilla::Plugin::CPANFile + name: '@DROLSKY/CPANFile' + version: '6.031' + - + class: Dist::Zilla::Plugin::DROLSKY::License + name: '@DROLSKY/DROLSKY::License' + version: '1.22' + - + class: Dist::Zilla::Plugin::CheckStrictVersion + name: '@DROLSKY/CheckStrictVersion' + version: '0.001' + - + class: Dist::Zilla::Plugin::CheckSelfDependency + config: + Dist::Zilla::Plugin::CheckSelfDependency: + finder: + - ':InstallModules' + Dist::Zilla::Role::ModuleMetadata: + Module::Metadata: '1.000037' + version: '0.006' + name: '@DROLSKY/CheckSelfDependency' + version: '0.011' + - + class: Dist::Zilla::Plugin::CheckPrereqsIndexed + name: '@DROLSKY/CheckPrereqsIndexed' + version: '0.022' + - + class: Dist::Zilla::Plugin::DROLSKY::Git::CheckFor::CorrectBranch + config: + Dist::Zilla::Role::Git::Repo: + git_version: 2.43.0 + repo_root: . + name: '@DROLSKY/DROLSKY::Git::CheckFor::CorrectBranch' + version: '1.22' + - + class: Dist::Zilla::Plugin::EnsureChangesHasContent + name: '@DROLSKY/EnsureChangesHasContent' + version: '0.02' + - + class: Dist::Zilla::Plugin::Git::CheckFor::MergeConflicts + config: + Dist::Zilla::Role::Git::Repo: + git_version: 2.43.0 + repo_root: . + name: '@DROLSKY/Git::CheckFor::MergeConflicts' + version: '0.014' + - + class: Dist::Zilla::Plugin::DROLSKY::PerlLinterConfigFiles + name: '@DROLSKY/DROLSKY::PerlLinterConfigFiles' + version: '1.22' + - + class: Dist::Zilla::Plugin::DROLSKY::DevTools + name: '@DROLSKY/DROLSKY::DevTools' + version: '1.22' + - + class: Dist::Zilla::Plugin::DROLSKY::Precious + name: '@DROLSKY/DROLSKY::Precious' + version: '1.22' + - + class: Dist::Zilla::Plugin::Git::Check + config: + Dist::Zilla::Plugin::Git::Check: + untracked_files: die + Dist::Zilla::Role::Git::DirtyFiles: + allow_dirty: + - CODE_OF_CONDUCT.md + - CONTRIBUTING.md + - Changes + - LICENSE + - Makefile.PL + - README.md + - cpanfile + - precious.toml + allow_dirty_match: [] + changelog: Changes + Dist::Zilla::Role::Git::Repo: + git_version: 2.43.0 + repo_root: . + name: '@DROLSKY/Git::Check' + version: '2.049' + - + class: Dist::Zilla::Plugin::Git::Commit + config: + Dist::Zilla::Plugin::Git::Commit: + add_files_in: [] + commit_msg: v%V%n%n%c + signoff: 0 + Dist::Zilla::Role::Git::DirtyFiles: + allow_dirty: + - CODE_OF_CONDUCT.md + - CONTRIBUTING.md + - Changes + - LICENSE + - Makefile.PL + - README.md + - cpanfile + - precious.toml + allow_dirty_match: [] + changelog: Changes + Dist::Zilla::Role::Git::Repo: + git_version: 2.43.0 + repo_root: . + Dist::Zilla::Role::Git::StringFormatter: + time_zone: local + name: '@DROLSKY/Commit generated files' + version: '2.049' + - + class: Dist::Zilla::Plugin::Git::Tag + config: + Dist::Zilla::Plugin::Git::Tag: + branch: ~ + changelog: Changes + signed: 0 + tag: v2.05 + tag_format: v%V + tag_message: v%V + Dist::Zilla::Role::Git::Repo: + git_version: 2.43.0 + repo_root: . + Dist::Zilla::Role::Git::StringFormatter: + time_zone: local + name: '@DROLSKY/Git::Tag' + version: '2.049' + - + class: Dist::Zilla::Plugin::Git::Push + config: + Dist::Zilla::Plugin::Git::Push: + push_to: + - origin + remotes_must_exist: 1 + Dist::Zilla::Role::Git::Repo: + git_version: 2.43.0 + repo_root: . + name: '@DROLSKY/Git::Push' + version: '2.049' + - + class: Dist::Zilla::Plugin::BumpVersionAfterRelease + config: + Dist::Zilla::Plugin::BumpVersionAfterRelease: + finders: + - ':ExecFiles' + - ':InstallModules' + global: 0 + munge_makefile_pl: 1 + name: '@DROLSKY/BumpVersionAfterRelease' + version: '0.018' + - + class: Dist::Zilla::Plugin::Git::Commit + config: + Dist::Zilla::Plugin::Git::Commit: + add_files_in: [] + commit_msg: 'Bump version after release' + signoff: 0 + Dist::Zilla::Role::Git::DirtyFiles: + allow_dirty: + - Changes + - dist.ini + allow_dirty_match: + - (?^:.+) + changelog: Changes + Dist::Zilla::Role::Git::Repo: + git_version: 2.43.0 + repo_root: . + Dist::Zilla::Role::Git::StringFormatter: + time_zone: local + name: '@DROLSKY/Commit version bump' + version: '2.049' + - + class: Dist::Zilla::Plugin::Git::Push + config: + Dist::Zilla::Plugin::Git::Push: + push_to: + - origin + remotes_must_exist: 1 + Dist::Zilla::Role::Git::Repo: + git_version: 2.43.0 + repo_root: . + name: '@DROLSKY/Push version bump' + version: '2.049' + - + class: Dist::Zilla::Plugin::DROLSKY::MakeMaker + config: + Dist::Zilla::Plugin::MakeMaker: + make_path: make + version: '6.031' + Dist::Zilla::Plugin::MakeMaker::Awesome: + version: '0.49' + Dist::Zilla::Role::TestRunner: + default_jobs: '12' + version: '6.031' + name: '@DROLSKY/DROLSKY::MakeMaker' + version: '1.22' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':InstallModules' + version: '6.031' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':IncModules' + version: '6.031' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':TestFiles' + version: '6.031' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':ExtraTestFiles' + version: '6.031' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':ExecFiles' + version: '6.031' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':PerlExecFiles' + version: '6.031' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':ShareFiles' + version: '6.031' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':MainModule' + version: '6.031' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':AllFiles' + version: '6.031' + - + class: Dist::Zilla::Plugin::FinderCode + name: ':NoFiles' + version: '6.031' + - + class: Dist::Zilla::Plugin::FinderCode + name: '@DROLSKY/MetaProvides::Package/AUTOVIV/:InstallModulesPM' + version: '6.031' + zilla: + class: Dist::Zilla::Dist::Builder + config: + is_trial: 0 + version: '6.031' +x_authority: cpan:DROLSKY +x_contributors: + - 'Dagfinn Ilmari Mannsåker ' + - 'David Cantrell ' + - 'Graham Knop ' + - 'Ivan Bessarabov ' + - 'Mark Fowler ' + - 'Pali ' + - 'Ricardo Signes ' +x_generated_by_perl: v5.38.2 +x_serialization_backend: 'YAML::Tiny version 1.74' +x_spdx_expression: Artistic-2.0 diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..1930eb1 --- /dev/null +++ b/Makefile.PL @@ -0,0 +1,63 @@ +# This Makefile.PL for Devel-StackTrace was generated by +# Dist::Zilla::Plugin::DROLSKY::MakeMaker 1.22 +# and Dist::Zilla::Plugin::MakeMaker::Awesome 0.49. +# Don't edit it but the dist.ini and plugins used to construct it. + +use strict; +use warnings; + +use 5.006; +use ExtUtils::MakeMaker; + +my %WriteMakefileArgs = ( + "ABSTRACT" => "An object representing a stack trace", + "AUTHOR" => "Dave Rolsky ", + "CONFIGURE_REQUIRES" => { + "ExtUtils::MakeMaker" => 0 + }, + "DISTNAME" => "Devel-StackTrace", + "LICENSE" => "artistic_2", + "MIN_PERL_VERSION" => "5.006", + "NAME" => "Devel::StackTrace", + "PREREQ_PM" => { + "File::Spec" => 0, + "Scalar::Util" => 0, + "overload" => 0, + "strict" => 0, + "warnings" => 0 + }, + "TEST_REQUIRES" => { + "ExtUtils::MakeMaker" => 0, + "File::Spec" => 0, + "Test::More" => "0.96", + "base" => 0, + "bytes" => 0 + }, + "VERSION" => "2.05", + "test" => { + "TESTS" => "t/*.t" + } +); + +my %FallbackPrereqs = ( + "ExtUtils::MakeMaker" => 0, + "File::Spec" => 0, + "Scalar::Util" => 0, + "Test::More" => "0.96", + "base" => 0, + "bytes" => 0, + "overload" => 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.md b/README.md new file mode 100644 index 0000000..a317870 --- /dev/null +++ b/README.md @@ -0,0 +1,270 @@ +# NAME + +Devel::StackTrace - An object representing a stack trace + +# VERSION + +version 2.05 + +# SYNOPSIS + + use Devel::StackTrace; + + my $trace = Devel::StackTrace->new; + + print $trace->as_string; # like carp + + # from top (most recent) of stack to bottom. + while ( my $frame = $trace->next_frame ) { + print "Has args\n" if $frame->hasargs; + } + + # from bottom (least recent) of stack to top. + while ( my $frame = $trace->prev_frame ) { + print "Sub: ", $frame->subroutine, "\n"; + } + +# DESCRIPTION + +The `Devel::StackTrace` module contains two classes, `Devel::StackTrace` and +[Devel::StackTrace::Frame](https://metacpan.org/pod/Devel%3A%3AStackTrace%3A%3AFrame). These objects encapsulate the information that can +retrieved via Perl's `caller` function, as well as providing a simple +interface to this data. + +The `Devel::StackTrace` object contains a set of `Devel::StackTrace::Frame` +objects, one for each level of the stack. The frames contain all the data +available from `caller`. + +This code was created to support my [Exception::Class::Base](https://metacpan.org/pod/Exception%3A%3AClass%3A%3ABase) class (part of +[Exception::Class](https://metacpan.org/pod/Exception%3A%3AClass)) but may be useful in other contexts. + +# 'TOP' AND 'BOTTOM' OF THE STACK + +When describing the methods of the trace object, I use the words 'top' and +'bottom'. In this context, the 'top' frame on the stack is the most recent +frame and the 'bottom' is the least recent. + +Here's an example: + + foo(); # bottom frame is here + + sub foo { + bar(); + } + + sub bar { + Devel::StackTrace->new; # top frame is here. + } + +# METHODS + +This class provide the following methods: + +## Devel::StackTrace->new(%named\_params) + +Returns a new Devel::StackTrace object. + +Takes the following parameters: + +- frame\_filter => $sub + + By default, Devel::StackTrace will include all stack frames before the call to + its constructor. + + However, you may want to filter out some frames with more granularity than + 'ignore\_package' or 'ignore\_class' allow. + + You can provide a subroutine which is called with the raw frame data for each + frame. This is a hash reference with two keys, "caller", and "args", both of + which are array references. The "caller" key is the raw data as returned by + Perl's `caller` function, and the "args" key are the subroutine arguments + found in `@DB::args`. + + The filter should return true if the frame should be included, or false if it + should be skipped. + +- filter\_frames\_early => $boolean + + If this parameter is true, `frame_filter` will be called as soon as the + stacktrace is created, and before refs are stringified (if + `unsafe_ref_capture` is not set), rather than being filtered lazily when + [Devel::StackTrace::Frame](https://metacpan.org/pod/Devel%3A%3AStackTrace%3A%3AFrame) objects are first needed. + + This is useful if you want to filter based on the frame's arguments and want to + be able to examine object properties, for example. + +- ignore\_package => $package\_name OR \\@package\_names + + Any frames where the package is one of these packages will not be on the stack. + +- ignore\_class => $package\_name OR \\@package\_names + + Any frames where the package is a subclass of one of these packages (or is the + same package) will not be on the stack. + + Devel::StackTrace internally adds itself to the 'ignore\_package' parameter, + meaning that the Devel::StackTrace package is **ALWAYS** ignored. However, if + you create a subclass of Devel::StackTrace it will not be ignored. + +- skip\_frames => $integer + + This will cause this number of stack frames to be excluded from top of the + stack trace. This prevents the frames from being captured at all, and applies + before the `frame_filter`, `ignore_package`, or `ignore_class` options, even + with `filter_frames_early`. + +- unsafe\_ref\_capture => $boolean + + If this parameter is true, then Devel::StackTrace will store references + internally when generating stacktrace frames. + + **This option is very dangerous, and should never be used with exception + objects**. Using this option will keep any objects or references alive past + their normal lifetime, until the stack trace object goes out of scope. It can + keep objects alive even after their `DESTROY` sub is called, resulting it it + being called multiple times on the same object. + + If not set, Devel::StackTrace replaces any references with their stringified + representation. + +- no\_args => $boolean + + If this parameter is true, then Devel::StackTrace will not store caller + arguments in stack trace frames at all. + +- respect\_overload => $boolean + + By default, Devel::StackTrace will call `overload::AddrRef` to get the + underlying string representation of an object, instead of respecting the + object's stringification overloading. If you would prefer to see the overloaded + representation of objects in stack traces, then set this parameter to true. + +- max\_arg\_length => $integer + + By default, Devel::StackTrace will display the entire argument for each + subroutine call. Setting this parameter causes truncates each subroutine + argument's string representation if it is longer than this number of + characters. + +- message => $string + + By default, Devel::StackTrace will use 'Trace begun' as the message for the + first stack frame when you call `as_string`. You can supply an alternative + message using this option. + +- indent => $boolean + + If this parameter is true, each stack frame after the first will start with a + tab character, just like `Carp::confess`. + +## $trace->next\_frame + +Returns the next [Devel::StackTrace::Frame](https://metacpan.org/pod/Devel%3A%3AStackTrace%3A%3AFrame) object on the stack, going down. +If this method hasn't been called before it returns the first frame. It returns +`undef` when it reaches the bottom of the stack and then resets its pointer so +the next call to `$trace->next_frame` or `$trace->prev_frame` will +work properly. + +## $trace->prev\_frame + +Returns the next [Devel::StackTrace::Frame](https://metacpan.org/pod/Devel%3A%3AStackTrace%3A%3AFrame) object on the stack, going up. If +this method hasn't been called before it returns the last frame. It returns +undef when it reaches the top of the stack and then resets its pointer so the +next call to `$trace->next_frame` or `$trace->prev_frame` will work +properly. + +## $trace->reset\_pointer + +Resets the pointer so that the next call to `$trace->next_frame` or `$trace->prev_frame` will start at the top or bottom of the stack, as +appropriate. + +## $trace->frames + +When this method is called with no arguments, it returns a list of +[Devel::StackTrace::Frame](https://metacpan.org/pod/Devel%3A%3AStackTrace%3A%3AFrame) objects. They are returned in order from top (most +recent) to bottom. + +This method can also be used to set the object's frames if you pass it a list +of [Devel::StackTrace::Frame](https://metacpan.org/pod/Devel%3A%3AStackTrace%3A%3AFrame) objects. + +This is useful if you want to filter the list of frames in ways that are more +complex than can be handled by the `$trace->filter_frames` method: + + $stacktrace->frames( my_filter( $stacktrace->frames ) ); + +## $trace->frame($index) + +Given an index, this method returns the relevant frame, or undef if there is no +frame at that index. The index is exactly like a Perl array. The first frame is +0 and negative indexes are allowed. + +## $trace->frame\_count + +Returns the number of frames in the trace object. + +## $trace->as\_string(\\%p) + +Calls `$frame->as_string` on each frame from top to bottom, producing +output quite similar to the Carp module's cluck/confess methods. + +The optional `\%p` parameter only has one option. The `max_arg_length` +parameter truncates each subroutine argument's string representation if it is +longer than this number of characters. + +If all the frames in a trace are skipped then this just returns the `message` +passed to the constructor or the string `"Trace begun"`. + +## $trace->message + +Returns the message passed to the constructor. If this wasn't passed then this +method returns `undef`. + +# SUPPORT + +Bugs may be submitted at [https://github.com/houseabsolute/Devel-StackTrace/issues](https://github.com/houseabsolute/Devel-StackTrace/issues). + +# SOURCE + +The source code repository for Devel-StackTrace can be found at [https://github.com/houseabsolute/Devel-StackTrace](https://github.com/houseabsolute/Devel-StackTrace). + +# DONATIONS + +If you'd like to thank me for the work I've done on this module, please +consider making a "donation" to me via PayPal. I spend a lot of free time +creating free software, and would appreciate any support you'd care to offer. + +Please note that **I am not suggesting that you must do this** in order for me +to continue working on this particular software. I will continue to do so, +inasmuch as I have in the past, for as long as it interests me. + +Similarly, a donation made in this way will probably not make me work on this +software much more, unless I get so many donations that I can consider working +on free software full time (let's all have a chuckle at that together). + +To donate, log into PayPal and send money to autarch@urth.org, or use the +button at [https://houseabsolute.com/foss-donations/](https://houseabsolute.com/foss-donations/). + +# AUTHOR + +Dave Rolsky + +# CONTRIBUTORS + +- Dagfinn Ilmari Mannsåker +- David Cantrell +- Graham Knop +- Ivan Bessarabov +- Mark Fowler +- Pali +- Ricardo Signes + +# COPYRIGHT AND LICENSE + +This software is Copyright (c) 2000 - 2024 by David Rolsky. + +This is free software, licensed under: + + The Artistic License 2.0 (GPL Compatible) + +The full text of the license can be found in the +`LICENSE` file included with this distribution. diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 0000000..4b4cb68 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,31 @@ +resources: + repositories: + - repository: ci-perl-helpers + type: github + name: houseabsolute/ci-perl-helpers + endpoint: houseabsolute + +stages: + - template: templates/helpers/build.yml@ci-perl-helpers + parameters: + debug: true + + - template: templates/helpers/linux.yml@ci-perl-helpers + parameters: + coverage: codecov + debug: true + include_threads: true + test_xt: true + use_default_perls: true + + - template: templates/helpers/macos.yml@ci-perl-helpers + parameters: + debug: true + include_threads: true + use_default_perls: true + + - template: templates/helpers/windows.yml@ci-perl-helpers + parameters: + debug: true + use_default_perls: true + diff --git a/cpanfile b/cpanfile new file mode 100644 index 0000000..3c8df37 --- /dev/null +++ b/cpanfile @@ -0,0 +1,57 @@ +# This file is generated by Dist::Zilla::Plugin::CPANFile v6.031 +# Do not edit this file directly. To change prereqs, edit the `dist.ini` file. + +requires "File::Spec" => "0"; +requires "Scalar::Util" => "0"; +requires "overload" => "0"; +requires "perl" => "5.006"; +requires "strict" => "0"; +requires "warnings" => "0"; + +on 'test' => sub { + requires "ExtUtils::MakeMaker" => "0"; + requires "File::Spec" => "0"; + requires "Test::More" => "0.96"; + requires "base" => "0"; + requires "bytes" => "0"; +}; + +on 'test' => sub { + recommends "CPAN::Meta" => "2.120900"; +}; + +on 'configure' => sub { + requires "ExtUtils::MakeMaker" => "0"; +}; + +on 'configure' => sub { + suggests "JSON::PP" => "2.27300"; +}; + +on 'develop' => sub { + requires "Capture::Tiny" => "0"; + requires "Encode" => "0"; + requires "File::Spec" => "0"; + requires "FindBin" => "0"; + requires "IO::Handle" => "0"; + requires "IPC::Open3" => "0"; + requires "Perl::Critic" => "1.138"; + requires "Perl::Critic::Moose" => "1.05"; + requires "Perl::Tidy" => "20210111"; + requires "Pod::Checker" => "1.74"; + requires "Pod::Coverage::TrustPod" => "0"; + requires "Pod::Tidy" => "0.10"; + requires "Pod::Wordlist" => "0"; + requires "Test::CPAN::Changes" => "0.19"; + requires "Test::CPAN::Meta::JSON" => "0.16"; + requires "Test::EOL" => "0"; + requires "Test::Mojibake" => "0"; + requires "Test::More" => "0.88"; + requires "Test::NoTabs" => "0"; + requires "Test::Pod" => "1.41"; + requires "Test::Pod::Coverage" => "1.08"; + requires "Test::Portability::Files" => "0"; + requires "Test::Spelling" => "0.12"; + requires "Test::Synopsis" => "0"; + requires "Test::Version" => "2.05"; +}; diff --git a/dev-bin/install-xt-tools.sh b/dev-bin/install-xt-tools.sh new file mode 100755 index 0000000..0f3e7b6 --- /dev/null +++ b/dev-bin/install-xt-tools.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +set -e + +TARGET="$HOME/bin" +if [ $(id -u) -eq 0 ]; then + TARGET="/usr/local/bin" +fi +echo "Installing dev tools to $TARGET" + +mkdir -p $TARGET +curl --silent --location \ + https://raw.githubusercontent.com/houseabsolute/ubi/master/bootstrap/bootstrap-ubi.sh | + sh + +"$TARGET/ubi" --project houseabsolute/precious --in "$TARGET" +"$TARGET/ubi" --project houseabsolute/omegasort --in "$TARGET" + +echo "Add $TARGET to your PATH in order to use precious for linting and tidying" diff --git a/dist.ini b/dist.ini new file mode 100644 index 0000000..da9cc98 --- /dev/null +++ b/dist.ini @@ -0,0 +1,14 @@ +name = Devel-StackTrace +author = Dave Rolsky +copyright_year = 2000 + +; authordep Dist::Zilla::PluginBundle::DROLSKY = 1.22 +[@DROLSKY] +dist = Devel-StackTrace +next_release_width = 6 +prereqs_skip = Test +stopwords = CPAN +stopwords = Rolsky +stopwords = stacktrace +use_github_issues = 1 +-remove = Test::CleanNamespaces \ No newline at end of file diff --git a/git/hooks/pre-commit.sh b/git/hooks/pre-commit.sh new file mode 100755 index 0000000..63595ad --- /dev/null +++ b/git/hooks/pre-commit.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +status=0 + +PRECIOUS=$(which precious) +if [[ -z $PRECIOUS ]]; then + PRECIOUS=./bin/precious +fi + +"$PRECIOUS" lint -s +if (( $? != 0 )); then + status+=1 +fi + +exit $status diff --git a/git/setup.pl b/git/setup.pl new file mode 100755 index 0000000..8c99cb8 --- /dev/null +++ b/git/setup.pl @@ -0,0 +1,27 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Cwd qw( abs_path ); + +symlink_hook('pre-commit'); + +sub symlink_hook { + my $hook = shift; + + my $dot = ".git/hooks/$hook"; + my $file = "git/hooks/$hook.sh"; + my $link = "../../$file"; + + if ( -e $dot ) { + if ( -l $dot ) { + return if readlink $dot eq $link; + } + warn "You already have a hook at $dot!\n"; + return; + } + + symlink $link, $dot + or die "Could not link $dot => $link: $!"; +} diff --git a/lib/Devel/StackTrace.pm b/lib/Devel/StackTrace.pm new file mode 100644 index 0000000..67fa362 --- /dev/null +++ b/lib/Devel/StackTrace.pm @@ -0,0 +1,624 @@ +package Devel::StackTrace; + +use 5.006; + +use strict; +use warnings; + +our $VERSION = '2.05'; + +use Devel::StackTrace::Frame; +use File::Spec; +use Scalar::Util qw( blessed ); + +use overload + '""' => \&as_string, + bool => sub {1}, + fallback => 1; + +sub new { + my $class = shift; + my %p = @_; + + $p{unsafe_ref_capture} = !delete $p{no_refs} + if exists $p{no_refs}; + + my $self = bless { + index => undef, + frames => [], + raw => [], + %p, + }, $class; + + $self->_record_caller_data; + + return $self; +} + +sub _record_caller_data { + my $self = shift; + + my $filter = $self->{filter_frames_early} && $self->_make_frame_filter; + + # We exclude this method by starting at least one frame back. + my $x = 1 + ( $self->{skip_frames} || 0 ); + + while ( + my @c + = $self->{no_args} + ? caller( $x++ ) + : do { + ## no critic (Modules::ProhibitMultiplePackages, Variables::ProhibitPackageVars) + package # the newline keeps dzil from adding a version here + DB; + @DB::args = (); + caller( $x++ ); + } + ) { + + my @args; + + ## no critic (Variables::ProhibitPackageVars, BuiltinFunctions::ProhibitComplexMappings) + unless ( $self->{no_args} ) { + + # This is the same workaroud as was applied to Carp.pm a little + # while back + # (https://rt.perl.org/Public/Bug/Display.html?id=131046): + # + # Guard our serialization of the stack from stack refcounting + # bugs NOTE this is NOT a complete solution, we cannot 100% + # guard against these bugs. However in many cases Perl *is* + # capable of detecting them and throws an error when it + # does. Unfortunately serializing the arguments on the stack is + # a perfect way of finding these bugs, even when they would not + # affect normal program flow that did not poke around inside the + # stack. Inside of Carp.pm it makes little sense reporting these + # bugs, as Carp's job is to report the callers errors, not the + # ones it might happen to tickle while doing so. See: + # https://rt.perl.org/Public/Bug/Display.html?id=131046 and: + # https://rt.perl.org/Public/Bug/Display.html?id=52610 for more + # details and discussion. - Yves + @args = map { + my $arg; + local $@ = $@; + eval { + $arg = $_; + 1; + } or do { + $arg = '** argument not available anymore **'; + }; + $arg; + } @DB::args; + } + ## use critic + + my $raw = { + caller => \@c, + args => \@args, + }; + + next if $filter && !$filter->($raw); + + unless ( $self->{unsafe_ref_capture} ) { + $raw->{args} = [ map { ref $_ ? $self->_ref_to_string($_) : $_ } + @{ $raw->{args} } ]; + } + + push @{ $self->{raw} }, $raw; + } +} + +sub _ref_to_string { + my $self = shift; + my $ref = shift; + + return overload::AddrRef($ref) + if blessed $ref && $ref->isa('Exception::Class::Base'); + + return overload::AddrRef($ref) unless $self->{respect_overload}; + + ## no critic (Variables::RequireInitializationForLocalVars) + local $@; + local $SIG{__DIE__}; + ## use critic + + my $str = eval { $ref . q{} }; + + return $@ ? overload::AddrRef($ref) : $str; +} + +sub _make_frames { + my $self = shift; + + my $filter = !$self->{filter_frames_early} && $self->_make_frame_filter; + + my $raw = delete $self->{raw}; + for my $r ( @{$raw} ) { + next if $filter && !$filter->($r); + + $self->_add_frame( $r->{caller}, $r->{args} ); + } +} + +my $default_filter = sub {1}; + +sub _make_frame_filter { + my $self = shift; + + my ( @i_pack_re, %i_class ); + if ( $self->{ignore_package} ) { + ## no critic (Variables::RequireInitializationForLocalVars) + local $@; + local $SIG{__DIE__}; + ## use critic + + $self->{ignore_package} = [ $self->{ignore_package} ] + unless eval { @{ $self->{ignore_package} } }; + + @i_pack_re + = map { ref $_ ? $_ : qr/^\Q$_\E$/ } @{ $self->{ignore_package} }; + } + + my $p = __PACKAGE__; + push @i_pack_re, qr/^\Q$p\E$/; + + if ( $self->{ignore_class} ) { + $self->{ignore_class} = [ $self->{ignore_class} ] + unless ref $self->{ignore_class}; + %i_class = map { $_ => 1 } @{ $self->{ignore_class} }; + } + + my $user_filter = $self->{frame_filter}; + + return sub { + return 0 if grep { $_[0]{caller}[0] =~ /$_/ } @i_pack_re; + return 0 if grep { $_[0]{caller}[0]->isa($_) } keys %i_class; + + if ($user_filter) { + return $user_filter->( $_[0] ); + } + + return 1; + }; +} + +sub _add_frame { + my $self = shift; + my $c = shift; + my $p = shift; + + # eval and is_require are only returned when applicable under 5.00503. + push @$c, ( undef, undef ) if scalar @$c == 6; + + push @{ $self->{frames} }, + Devel::StackTrace::Frame->new( + $c, + $p, + $self->{respect_overload}, + $self->{max_arg_length}, + $self->{message}, + $self->{indent} + ); +} + +sub next_frame { + my $self = shift; + + # reset to top if necessary. + $self->{index} = -1 unless defined $self->{index}; + + my @f = $self->frames; + if ( defined $f[ $self->{index} + 1 ] ) { + return $f[ ++$self->{index} ]; + } + else { + $self->{index} = undef; + ## no critic (Subroutines::ProhibitExplicitReturnUndef) + return undef; + } +} + +sub prev_frame { + my $self = shift; + + my @f = $self->frames; + + # reset to top if necessary. + $self->{index} = scalar @f unless defined $self->{index}; + + if ( defined $f[ $self->{index} - 1 ] && $self->{index} >= 1 ) { + return $f[ --$self->{index} ]; + } + else { + ## no critic (Subroutines::ProhibitExplicitReturnUndef) + $self->{index} = undef; + return undef; + } +} + +sub reset_pointer { + my $self = shift; + + $self->{index} = undef; + + return; +} + +sub frames { + my $self = shift; + + if (@_) { + die + "Devel::StackTrace->frames can only take Devel::StackTrace::Frame args\n" + if grep { !$_->isa('Devel::StackTrace::Frame') } @_; + + $self->{frames} = \@_; + delete $self->{raw}; + } + else { + $self->_make_frames if $self->{raw}; + } + + return @{ $self->{frames} }; +} + +sub frame { + my $self = shift; + my $i = shift; + + return unless defined $i; + + return ( $self->frames )[$i]; +} + +sub frame_count { + my $self = shift; + + return scalar( $self->frames ); +} + +sub message { $_[0]->{message} } + +sub as_string { + my $self = shift; + my $p = shift; + + my @frames = $self->frames; + if (@frames) { + my $st = q{}; + my $first = 1; + for my $f (@frames) { + $st .= $f->as_string( $first, $p ) . "\n"; + $first = 0; + } + + return $st; + } + + my $msg = $self->message; + return $msg if defined $msg; + + return 'Trace begun'; +} + +{ + ## no critic (Modules::ProhibitMultiplePackages, ClassHierarchies::ProhibitExplicitISA) + package # hide from PAUSE + Devel::StackTraceFrame; + + our @ISA = 'Devel::StackTrace::Frame'; +} + +1; + +# ABSTRACT: An object representing a stack trace + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Devel::StackTrace - An object representing a stack trace + +=head1 VERSION + +version 2.05 + +=head1 SYNOPSIS + + use Devel::StackTrace; + + my $trace = Devel::StackTrace->new; + + print $trace->as_string; # like carp + + # from top (most recent) of stack to bottom. + while ( my $frame = $trace->next_frame ) { + print "Has args\n" if $frame->hasargs; + } + + # from bottom (least recent) of stack to top. + while ( my $frame = $trace->prev_frame ) { + print "Sub: ", $frame->subroutine, "\n"; + } + +=head1 DESCRIPTION + +The C module contains two classes, C and +L. These objects encapsulate the information that can +retrieved via Perl's C function, as well as providing a simple +interface to this data. + +The C object contains a set of C +objects, one for each level of the stack. The frames contain all the data +available from C. + +This code was created to support my L class (part of +L) but may be useful in other contexts. + +=head1 'TOP' AND 'BOTTOM' OF THE STACK + +When describing the methods of the trace object, I use the words 'top' and +'bottom'. In this context, the 'top' frame on the stack is the most recent +frame and the 'bottom' is the least recent. + +Here's an example: + + foo(); # bottom frame is here + + sub foo { + bar(); + } + + sub bar { + Devel::StackTrace->new; # top frame is here. + } + +=head1 METHODS + +This class provide the following methods: + +=head2 Devel::StackTrace->new(%named_params) + +Returns a new Devel::StackTrace object. + +Takes the following parameters: + +=over 4 + +=item * frame_filter => $sub + +By default, Devel::StackTrace will include all stack frames before the call to +its constructor. + +However, you may want to filter out some frames with more granularity than +'ignore_package' or 'ignore_class' allow. + +You can provide a subroutine which is called with the raw frame data for each +frame. This is a hash reference with two keys, "caller", and "args", both of +which are array references. The "caller" key is the raw data as returned by +Perl's C function, and the "args" key are the subroutine arguments +found in C<@DB::args>. + +The filter should return true if the frame should be included, or false if it +should be skipped. + +=item * filter_frames_early => $boolean + +If this parameter is true, C will be called as soon as the +stacktrace is created, and before refs are stringified (if +C is not set), rather than being filtered lazily when +L objects are first needed. + +This is useful if you want to filter based on the frame's arguments and want to +be able to examine object properties, for example. + +=item * ignore_package => $package_name OR \@package_names + +Any frames where the package is one of these packages will not be on the stack. + +=item * ignore_class => $package_name OR \@package_names + +Any frames where the package is a subclass of one of these packages (or is the +same package) will not be on the stack. + +Devel::StackTrace internally adds itself to the 'ignore_package' parameter, +meaning that the Devel::StackTrace package is B ignored. However, if +you create a subclass of Devel::StackTrace it will not be ignored. + +=item * skip_frames => $integer + +This will cause this number of stack frames to be excluded from top of the +stack trace. This prevents the frames from being captured at all, and applies +before the C, C, or C options, even +with C. + +=item * unsafe_ref_capture => $boolean + +If this parameter is true, then Devel::StackTrace will store references +internally when generating stacktrace frames. + +B. Using this option will keep any objects or references alive past +their normal lifetime, until the stack trace object goes out of scope. It can +keep objects alive even after their C sub is called, resulting it it +being called multiple times on the same object. + +If not set, Devel::StackTrace replaces any references with their stringified +representation. + +=item * no_args => $boolean + +If this parameter is true, then Devel::StackTrace will not store caller +arguments in stack trace frames at all. + +=item * respect_overload => $boolean + +By default, Devel::StackTrace will call C to get the +underlying string representation of an object, instead of respecting the +object's stringification overloading. If you would prefer to see the overloaded +representation of objects in stack traces, then set this parameter to true. + +=item * max_arg_length => $integer + +By default, Devel::StackTrace will display the entire argument for each +subroutine call. Setting this parameter causes truncates each subroutine +argument's string representation if it is longer than this number of +characters. + +=item * message => $string + +By default, Devel::StackTrace will use 'Trace begun' as the message for the +first stack frame when you call C. You can supply an alternative +message using this option. + +=item * indent => $boolean + +If this parameter is true, each stack frame after the first will start with a +tab character, just like C. + +=back + +=head2 $trace->next_frame + +Returns the next L object on the stack, going down. +If this method hasn't been called before it returns the first frame. It returns +C when it reaches the bottom of the stack and then resets its pointer so +the next call to C<< $trace->next_frame >> or C<< $trace->prev_frame >> will +work properly. + +=head2 $trace->prev_frame + +Returns the next L object on the stack, going up. If +this method hasn't been called before it returns the last frame. It returns +undef when it reaches the top of the stack and then resets its pointer so the +next call to C<< $trace->next_frame >> or C<< $trace->prev_frame >> will work +properly. + +=head2 $trace->reset_pointer + +Resets the pointer so that the next call to C<< $trace->next_frame >> or C<< +$trace->prev_frame >> will start at the top or bottom of the stack, as +appropriate. + +=head2 $trace->frames + +When this method is called with no arguments, it returns a list of +L objects. They are returned in order from top (most +recent) to bottom. + +This method can also be used to set the object's frames if you pass it a list +of L objects. + +This is useful if you want to filter the list of frames in ways that are more +complex than can be handled by the C<< $trace->filter_frames >> method: + + $stacktrace->frames( my_filter( $stacktrace->frames ) ); + +=head2 $trace->frame($index) + +Given an index, this method returns the relevant frame, or undef if there is no +frame at that index. The index is exactly like a Perl array. The first frame is +0 and negative indexes are allowed. + +=head2 $trace->frame_count + +Returns the number of frames in the trace object. + +=head2 $trace->as_string(\%p) + +Calls C<< $frame->as_string >> on each frame from top to bottom, producing +output quite similar to the Carp module's cluck/confess methods. + +The optional C<\%p> parameter only has one option. The C +parameter truncates each subroutine argument's string representation if it is +longer than this number of characters. + +If all the frames in a trace are skipped then this just returns the C +passed to the constructor or the string C<"Trace begun">. + +=head2 $trace->message + +Returns the message passed to the constructor. If this wasn't passed then this +method returns C. + +=head1 SUPPORT + +Bugs may be submitted at L. + +=head1 SOURCE + +The source code repository for Devel-StackTrace can be found at L. + +=head1 DONATIONS + +If you'd like to thank me for the work I've done on this module, please +consider making a "donation" to me via PayPal. I spend a lot of free time +creating free software, and would appreciate any support you'd care to offer. + +Please note that B in order for me +to continue working on this particular software. I will continue to do so, +inasmuch as I have in the past, for as long as it interests me. + +Similarly, a donation made in this way will probably not make me work on this +software much more, unless I get so many donations that I can consider working +on free software full time (let's all have a chuckle at that together). + +To donate, log into PayPal and send money to autarch@urth.org, or use the +button at L. + +=head1 AUTHOR + +Dave Rolsky + +=head1 CONTRIBUTORS + +=for stopwords Dagfinn Ilmari Mannsåker David Cantrell Graham Knop Ivan Bessarabov Mark Fowler Pali Ricardo Signes + +=over 4 + +=item * + +Dagfinn Ilmari Mannsåker + +=item * + +David Cantrell + +=item * + +Graham Knop + +=item * + +Ivan Bessarabov + +=item * + +Mark Fowler + +=item * + +Pali + +=item * + +Ricardo Signes + +=back + +=head1 COPYRIGHT AND LICENSE + +This software is Copyright (c) 2000 - 2024 by David Rolsky. + +This is free software, licensed under: + + The Artistic License 2.0 (GPL Compatible) + +The full text of the license can be found in the +F file included with this distribution. + +=cut diff --git a/lib/Devel/StackTrace/Frame.pm b/lib/Devel/StackTrace/Frame.pm new file mode 100644 index 0000000..f7e8d3f --- /dev/null +++ b/lib/Devel/StackTrace/Frame.pm @@ -0,0 +1,272 @@ +package Devel::StackTrace::Frame; + +use strict; +use warnings; + +our $VERSION = '2.05'; + +# Create accessor routines +BEGIN { + ## no critic (TestingAndDebugging::ProhibitNoStrict) + no strict 'refs'; + + my @attrs = qw( + package + filename + line + subroutine + hasargs + wantarray + evaltext + is_require + hints + bitmask + ); + + for my $attr (@attrs) { + *{$attr} = sub { my $s = shift; return $s->{$attr} }; + } +} + +{ + my @args = qw( + package + filename + line + subroutine + hasargs + wantarray + evaltext + is_require + hints + bitmask + ); + + sub new { + my $proto = shift; + my $class = ref $proto || $proto; + + my $self = bless {}, $class; + + @{$self}{@args} = @{ shift() }; + $self->{args} = shift; + $self->{respect_overload} = shift; + $self->{max_arg_length} = shift; + $self->{message} = shift; + $self->{indent} = shift; + + # fixup unix-style paths on win32 + $self->{filename} = File::Spec->canonpath( $self->{filename} ); + + return $self; + } +} + +sub args { + my $self = shift; + + return @{ $self->{args} }; +} + +sub as_string { + my $self = shift; + my $first = shift; + my $p = shift; + + my $sub = $self->subroutine; + + # This code stolen straight from Carp.pm and then tweaked. All + # errors are probably my fault -dave + if ($first) { + $sub + = defined $self->{message} + ? $self->{message} + : 'Trace begun'; + } + else { + + # Build a string, $sub, which names the sub-routine called. + # This may also be "require ...", "eval '...' or "eval {...}" + if ( my $eval = $self->evaltext ) { + if ( $self->is_require ) { + $sub = "require $eval"; + } + else { + $eval =~ s/([\\\'])/\\$1/g; + $sub = "eval '$eval'"; + } + } + elsif ( $sub eq '(eval)' ) { + $sub = 'eval {...}'; + } + + # if there are any arguments in the sub-routine call, format + # them according to the format variables defined earlier in + # this file and join them onto the $sub sub-routine string + # + # We copy them because they're going to be modified. + # + if ( my @a = $self->args ) { + for (@a) { + + # set args to the string "undef" if undefined + unless ( defined $_ ) { + $_ = 'undef'; + next; + } + + # hack! + ## no critic (Subroutines::ProtectPrivateSubs) + $_ = $self->Devel::StackTrace::_ref_to_string($_) + if ref $_; + ## use critic; + + ## no critic (Variables::RequireInitializationForLocalVars) + local $SIG{__DIE__}; + local $@; + ## use critic; + + ## no critic (ErrorHandling::RequireCheckingReturnValueOfEval) + eval { + my $max_arg_length + = exists $p->{max_arg_length} + ? $p->{max_arg_length} + : $self->{max_arg_length}; + + if ( $max_arg_length + && length $_ > $max_arg_length ) { + ## no critic (BuiltinFunctions::ProhibitLvalueSubstr) + substr( $_, $max_arg_length ) = '...'; + } + + s/'/\\'/g; + + # 'quote' arg unless it looks like a number + $_ = "'$_'" unless /^-?[\d.]+$/; + + # print control/high ASCII chars as 'M-' or '^' + s/([\200-\377])/sprintf("M-%c",ord($1)&0177)/eg; + s/([\0-\37\177])/sprintf("^%c",ord($1)^64)/eg; + }; + ## use critic + + if ( my $e = $@ ) { + $_ = $e =~ /malformed utf-8/i ? '(bad utf-8)' : '?'; + } + } + + # append ('all', 'the', 'arguments') to the $sub string + $sub .= '(' . join( ', ', @a ) . ')'; + $sub .= ' called'; + } + } + + # If the user opted into indentation (a la Carp::confess), pre-add a tab + my $tab = $self->{indent} && !$first ? "\t" : q{}; + + return "${tab}$sub at " . $self->filename . ' line ' . $self->line; +} + +1; + +# ABSTRACT: A single frame in a stack trace + +__END__ + +=pod + +=encoding UTF-8 + +=head1 NAME + +Devel::StackTrace::Frame - A single frame in a stack trace + +=head1 VERSION + +version 2.05 + +=head1 DESCRIPTION + +See L for details. + +=for Pod::Coverage new + +=head1 METHODS + +See Perl's C documentation for more information on what these methods +return. + +=head2 $frame->package + +The package which created this frame. + +=head2 $frame->filename + +The filename which created this frame. + +=head2 $frame->line + +The line where the frame was created. + +=head2 $frame->subroutine + +The subroutine which created this frame. + +=head2 $frame->hasargs + +This will be true if a new C<@_> was created for this this frame. + +=head2 $frame->wantarray + +This indicates the context for the call for this frame. This will be true if +called in array context, false in scalar context, and C in void context. + +=head2 $frame->evaltext + +Returns undef if the frame was not part of an eval. + +=head2 $frame->is_require + +Returns undef if the frame was not part of a require. + +=head2 $frame->args + +Returns the arguments passed to the frame. Note that any arguments that are +references are returned as references, not copies. + +=head2 $frame->hints + +Returns the value of C<$^H> for this frame. + +=head2 $frame->bitmask + +Returns the value of C<$bitmask> for this frame. + +=head2 $frame->as_string + +Returns a string containing a description of the frame. + +=head1 SUPPORT + +Bugs may be submitted at L. + +=head1 SOURCE + +The source code repository for Devel-StackTrace can be found at L. + +=head1 AUTHOR + +Dave Rolsky + +=head1 COPYRIGHT AND LICENSE + +This software is Copyright (c) 2000 - 2024 by David Rolsky. + +This is free software, licensed under: + + The Artistic License 2.0 (GPL Compatible) + +The full text of the license can be found in the +F file included with this distribution. + +=cut diff --git a/perlcriticrc b/perlcriticrc new file mode 100644 index 0000000..1754348 --- /dev/null +++ b/perlcriticrc @@ -0,0 +1,70 @@ +severity = 3 +verbose = 11 +theme = (core && (pbp || bugs || maintenance || cosmetic || complexity || security || tests)) || moose +program-extensions = pl psgi t + +exclude = Subroutines::ProhibitCallsToUndeclaredSubs + +[BuiltinFunctions::ProhibitStringySplit] +severity = 3 + +[CodeLayout::RequireTrailingCommas] +severity = 3 + +[ControlStructures::ProhibitCStyleForLoops] +severity = 3 + +[InputOutput::RequireCheckedSyscalls] +functions = :builtins +exclude_functions = sleep +severity = 3 + +[RegularExpressions::ProhibitComplexRegexes] +max_characters = 200 + +[RegularExpressions::ProhibitUnusualDelimiters] +severity = 3 + +[Subroutines::ProhibitUnusedPrivateSubroutines] +private_name_regex = _(?!build)\w+ + +[TestingAndDebugging::ProhibitNoWarnings] +allow = redefine + +[ValuesAndExpressions::ProhibitEmptyQuotes] +severity = 3 + +[ValuesAndExpressions::ProhibitInterpolationOfLiterals] +severity = 3 + +[ValuesAndExpressions::RequireUpperCaseHeredocTerminator] +severity = 3 + +[Variables::ProhibitPackageVars] +add_packages = Carp Test::Builder + +[-Subroutines::RequireFinalReturn] + +# This incorrectly thinks signatures are prototypes. +[-Subroutines::ProhibitSubroutinePrototypes] + +[-ErrorHandling::RequireCarping] + +# No need for /xsm everywhere +[-RegularExpressions::RequireDotMatchAnything] +[-RegularExpressions::RequireExtendedFormatting] +[-RegularExpressions::RequireLineBoundaryMatching] + +# http://stackoverflow.com/questions/2275317/why-does-perlcritic-dislike-using-shift-to-populate-subroutine-variables +[-Subroutines::RequireArgUnpacking] + +# "use v5.14" is more readable than "use 5.014" +[-ValuesAndExpressions::ProhibitVersionStrings] + +# Explicitly returning undef is a _good_ thing in many cases, since it +# prevents very common errors when using a sub in list context to construct a +# hash and ending up with a missing value or key. +[-Subroutines::ProhibitExplicitReturnUndef] + +# Sometimes I want to write "return unless $x > 4" +[-ControlStructures::ProhibitNegativeExpressionsInUnlessAndUntilConditions] diff --git a/perltidyrc b/perltidyrc new file mode 100644 index 0000000..b54e60d --- /dev/null +++ b/perltidyrc @@ -0,0 +1,22 @@ +-l=78 +-i=4 +-ci=4 +-se +-b +-bar +-boc +-vt=0 +-vtc=0 +-cti=0 +-pt=1 +-bt=1 +-sbt=1 +-bbt=1 +-nolq +-npro +-nsfs +--blank-lines-before-packages=0 +--opening-hash-brace-right +--no-outdent-long-comments +--iterations=2 +-wbb="% + - * / x != == >= <= =~ !~ < > | & >= < = **= += *= &= <<= &&= -= /= |= >>= ||= .= %= ^= x=" diff --git a/precious.toml b/precious.toml new file mode 100644 index 0000000..b6c9ae8 --- /dev/null +++ b/precious.toml @@ -0,0 +1,51 @@ +exclude = [ + ".build/**/*", + "Devel-StackTrace-*/**/*", + "blib/**/*", + "t/00-*", + "t/author-*", + "t/release-*", + "t/zzz-*", + "xt/**/*", +] + +[commands.omegasort-gitignore] +type = "both" +include = "**/.gitignore" +cmd = [ "omegasort", "--sort=path" ] +lint_flags = "--check" +tidy_flags = "--in-place" +ok_exit_codes = 0 +lint_failure_exit_codes = 1 + +[commands.perlcritic] +type = "lint" +include = [ "**/*.{pl,pm,t,psgi}" ] +cmd = [ "perlcritic", "--profile=$PRECIOUS_ROOT/perlcriticrc" ] +ok_exit_codes = 0 +lint_failure_exit_codes = 2 + +[commands.perltidy] +type = "both" +include = [ "**/*.{pl,pm,t,psgi}" ] +cmd = [ "perltidy", "--profile=$PRECIOUS_ROOT/perltidyrc" ] +lint_flags = [ "--assert-tidy", "--no-standard-output", "--outfile=/dev/null" ] +tidy_flags = [ "--backup-and-modify-in-place", "--backup-file-extension=/" ] +ok_exit_codes = 0 +lint_failure_exit_codes = 2 +ignore_stderr = "Begin Error Output Stream" + +[commands.podchecker] +type = "lint" +include = [ "**/*.{pl,pm,pod}" ] +cmd = [ "podchecker", "--warnings", "--warnings" ] +ok_exit_codes = [ 0, 2 ] +lint_failure_exit_codes = 1 +ignore_stderr = [ ".+ pod syntax OK", ".+ does not contain any pod commands" ] + +[commands.podtidy] +type = "tidy" +include = [ "**/*.{pl,pm,pod}" ] +cmd = [ "podtidy", "--columns", "80", "--inplace", "--nobackup" ] +ok_exit_codes = 0 +lint_failure_exit_codes = 1 diff --git a/t/00-report-prereqs.dd b/t/00-report-prereqs.dd new file mode 100644 index 0000000..c6f53bf --- /dev/null +++ b/t/00-report-prereqs.dd @@ -0,0 +1,63 @@ +do { my $x = { + 'configure' => { + 'requires' => { + 'ExtUtils::MakeMaker' => '0' + }, + 'suggests' => { + 'JSON::PP' => '2.27300' + } + }, + 'develop' => { + 'requires' => { + 'Capture::Tiny' => '0', + 'Encode' => '0', + 'File::Spec' => '0', + 'FindBin' => '0', + 'IO::Handle' => '0', + 'IPC::Open3' => '0', + 'Perl::Critic' => '1.138', + 'Perl::Critic::Moose' => '1.05', + 'Perl::Tidy' => '20210111', + 'Pod::Checker' => '1.74', + 'Pod::Coverage::TrustPod' => '0', + 'Pod::Tidy' => '0.10', + 'Pod::Wordlist' => '0', + 'Test::CPAN::Changes' => '0.19', + 'Test::CPAN::Meta::JSON' => '0.16', + 'Test::EOL' => '0', + 'Test::Mojibake' => '0', + 'Test::More' => '0.88', + 'Test::NoTabs' => '0', + 'Test::Pod' => '1.41', + 'Test::Pod::Coverage' => '1.08', + 'Test::Portability::Files' => '0', + 'Test::Spelling' => '0.12', + 'Test::Synopsis' => '0', + 'Test::Version' => '2.05' + } + }, + 'runtime' => { + 'requires' => { + 'File::Spec' => '0', + 'Scalar::Util' => '0', + 'overload' => '0', + 'perl' => '5.006', + 'strict' => '0', + 'warnings' => '0' + } + }, + 'test' => { + 'recommends' => { + 'CPAN::Meta' => '2.120900' + }, + 'requires' => { + 'ExtUtils::MakeMaker' => '0', + 'File::Spec' => '0', + 'Test::More' => '0.96', + 'base' => '0', + 'bytes' => '0' + } + } + }; + $x; + } \ No newline at end of file diff --git a/t/00-report-prereqs.t b/t/00-report-prereqs.t new file mode 100644 index 0000000..5696476 --- /dev/null +++ b/t/00-report-prereqs.t @@ -0,0 +1,197 @@ +#!perl + +use strict; +use warnings; + +# This test was generated by Dist::Zilla::Plugin::Test::ReportPrereqs 0.029 + +use Test::More tests => 1; + +use ExtUtils::MakeMaker; +use File::Spec; + +# from $version::LAX +my $lax_version_re = + qr/(?: undef | (?: (?:[0-9]+) (?: \. | (?:\.[0-9]+) (?:_[0-9]+)? )? + | + (?:\.[0-9]+) (?:_[0-9]+)? + ) | (?: + v (?:[0-9]+) (?: (?:\.[0-9]+)+ (?:_[0-9]+)? )? + | + (?:[0-9]+)? (?:\.[0-9]+){2,} (?:_[0-9]+)? + ) + )/x; + +# hide optional CPAN::Meta modules from prereq scanner +# and check if they are available +my $cpan_meta = "CPAN::Meta"; +my $cpan_meta_pre = "CPAN::Meta::Prereqs"; +my $HAS_CPAN_META = eval "require $cpan_meta; $cpan_meta->VERSION('2.120900')" && eval "require $cpan_meta_pre"; ## no critic + +# Verify requirements? +my $DO_VERIFY_PREREQS = 1; + +sub _max { + my $max = shift; + $max = ( $_ > $max ) ? $_ : $max for @_; + return $max; +} + +sub _merge_prereqs { + my ($collector, $prereqs) = @_; + + # CPAN::Meta::Prereqs object + if (ref $collector eq $cpan_meta_pre) { + return $collector->with_merged_prereqs( + CPAN::Meta::Prereqs->new( $prereqs ) + ); + } + + # Raw hashrefs + for my $phase ( keys %$prereqs ) { + for my $type ( keys %{ $prereqs->{$phase} } ) { + for my $module ( keys %{ $prereqs->{$phase}{$type} } ) { + $collector->{$phase}{$type}{$module} = $prereqs->{$phase}{$type}{$module}; + } + } + } + + return $collector; +} + +my @include = qw( + +); + +my @exclude = qw( + +); + +# Add static prereqs to the included modules list +my $static_prereqs = do './t/00-report-prereqs.dd'; + +# Merge all prereqs (either with ::Prereqs or a hashref) +my $full_prereqs = _merge_prereqs( + ( $HAS_CPAN_META ? $cpan_meta_pre->new : {} ), + $static_prereqs +); + +# Add dynamic prereqs to the included modules list (if we can) +my ($source) = grep { -f } 'MYMETA.json', 'MYMETA.yml'; +my $cpan_meta_error; +if ( $source && $HAS_CPAN_META + && (my $meta = eval { CPAN::Meta->load_file($source) } ) +) { + $full_prereqs = _merge_prereqs($full_prereqs, $meta->prereqs); +} +else { + $cpan_meta_error = $@; # capture error from CPAN::Meta->load_file($source) + $source = 'static metadata'; +} + +my @full_reports; +my @dep_errors; +my $req_hash = $HAS_CPAN_META ? $full_prereqs->as_string_hash : $full_prereqs; + +# Add static includes into a fake section +for my $mod (@include) { + $req_hash->{other}{modules}{$mod} = 0; +} + +for my $phase ( qw(configure build test runtime develop other) ) { + next unless $req_hash->{$phase}; + next if ($phase eq 'develop' and not $ENV{AUTHOR_TESTING}); + + for my $type ( qw(requires recommends suggests conflicts modules) ) { + next unless $req_hash->{$phase}{$type}; + + my $title = ucfirst($phase).' '.ucfirst($type); + my @reports = [qw/Module Want Have/]; + + for my $mod ( sort keys %{ $req_hash->{$phase}{$type} } ) { + next if grep { $_ eq $mod } @exclude; + + my $want = $req_hash->{$phase}{$type}{$mod}; + $want = "undef" unless defined $want; + $want = "any" if !$want && $want == 0; + + if ($mod eq 'perl') { + push @reports, ['perl', $want, $]]; + next; + } + + my $req_string = $want eq 'any' ? 'any version required' : "version '$want' required"; + + my $file = $mod; + $file =~ s{::}{/}g; + $file .= ".pm"; + my ($prefix) = grep { -e File::Spec->catfile($_, $file) } @INC; + + if ($prefix) { + my $have = MM->parse_version( File::Spec->catfile($prefix, $file) ); + $have = "undef" unless defined $have; + push @reports, [$mod, $want, $have]; + + if ( $DO_VERIFY_PREREQS && $HAS_CPAN_META && $type eq 'requires' ) { + if ( $have !~ /\A$lax_version_re\z/ ) { + push @dep_errors, "$mod version '$have' cannot be parsed ($req_string)"; + } + elsif ( ! $full_prereqs->requirements_for( $phase, $type )->accepts_module( $mod => $have ) ) { + push @dep_errors, "$mod version '$have' is not in required range '$want'"; + } + } + } + else { + push @reports, [$mod, $want, "missing"]; + + if ( $DO_VERIFY_PREREQS && $type eq 'requires' ) { + push @dep_errors, "$mod is not installed ($req_string)"; + } + } + } + + if ( @reports ) { + push @full_reports, "=== $title ===\n\n"; + + my $ml = _max( map { length $_->[0] } @reports ); + my $wl = _max( map { length $_->[1] } @reports ); + my $hl = _max( map { length $_->[2] } @reports ); + + if ($type eq 'modules') { + splice @reports, 1, 0, ["-" x $ml, "", "-" x $hl]; + push @full_reports, map { sprintf(" %*s %*s\n", -$ml, $_->[0], $hl, $_->[2]) } @reports; + } + else { + splice @reports, 1, 0, ["-" x $ml, "-" x $wl, "-" x $hl]; + push @full_reports, map { sprintf(" %*s %*s %*s\n", -$ml, $_->[0], $wl, $_->[1], $hl, $_->[2]) } @reports; + } + + push @full_reports, "\n"; + } + } +} + +if ( @full_reports ) { + diag "\nVersions for all modules listed in $source (including optional ones):\n\n", @full_reports; +} + +if ( $cpan_meta_error || @dep_errors ) { + diag "\n*** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING ***\n"; +} + +if ( $cpan_meta_error ) { + my ($orig_source) = grep { -f } 'MYMETA.json', 'MYMETA.yml'; + diag "\nCPAN::Meta->load_file('$orig_source') failed with: $cpan_meta_error\n"; +} + +if ( @dep_errors ) { + diag join("\n", + "\nThe following REQUIRED prerequisites were not satisfied:\n", + @dep_errors, + "\n" + ); +} + +pass('Reported prereqs'); + +# vim: ts=4 sts=4 sw=4 et: diff --git a/t/01-basic.t b/t/01-basic.t new file mode 100644 index 0000000..e873049 --- /dev/null +++ b/t/01-basic.t @@ -0,0 +1,585 @@ +use strict; +use warnings; + +use Test::More 0.88; + +use Devel::StackTrace; + +sub get_file_name { File::Spec->canonpath( ( caller(0) )[1] ) } +my $test_file_name = get_file_name(); + +# Test all accessors +{ + my $trace = foo(); + + my @f = (); + while ( my $f = $trace->prev_frame ) { push @f, $f; } + + my $cnt = scalar @f; + is( + $cnt, 4, + 'Trace should have 4 frames' + ); + + @f = (); + while ( my $f = $trace->next_frame ) { push @f, $f; } + + $cnt = scalar @f; + is( + $cnt, 4, + 'Trace should have 4 frames' + ); + + is( + $f[0]->package, 'main', + 'First frame package should be main' + ); + + is( + $f[0]->filename, $test_file_name, + "First frame filename should be $test_file_name" + ); + + is( $f[0]->line, 1009, 'First frame line should be 1009' ); + + is( + $f[0]->subroutine, 'Devel::StackTrace::new', + 'First frame subroutine should be Devel::StackTrace::new' + ); + + is( $f[0]->hasargs, 1, 'First frame hasargs should be true' ); + + ok( + !$f[0]->wantarray, + 'First frame wantarray should be false' + ); + + my $trace_text = <<"EOF"; +Trace begun at $test_file_name line 1009 +main::baz(1, 2) called at $test_file_name line 1005 +main::bar(1) called at $test_file_name line 1001 +main::foo at $test_file_name line 13 +EOF + + is( $trace->as_string, $trace_text, 'trace text' ); +} + +# Test constructor params +{ + my $trace = SubTest::foo( ignore_class => 'Test' ); + + my @f = (); + while ( my $f = $trace->prev_frame ) { push @f, $f; } + + my $cnt = scalar @f; + + is( $cnt, 1, 'Trace should have 1 frame' ); + + is( + $f[0]->package, 'main', + 'The package for this frame should be main' + ); + + $trace = Test::foo( ignore_class => 'Test' ); + + @f = (); + while ( my $f = $trace->prev_frame ) { push @f, $f; } + + $cnt = scalar @f; + + is( $cnt, 1, 'Trace should have 1 frame' ); + is( + $f[0]->package, 'main', + 'The package for this frame should be main' + ); +} + +# 15 - stringification overloading +{ + my $trace = baz(); + + my $trace_text = <<"EOF"; +Trace begun at $test_file_name line 1009 +main::baz at $test_file_name line 99 +EOF + + my $t = "$trace"; + is( $t, $trace_text, 'trace text' ); +} + +# 16-18 - frame_count, frame, reset_pointer, frames methods +{ + my $trace = foo(); + + is( + $trace->frame_count, 4, + 'Trace should have 4 frames' + ); + + my $f = $trace->frame(2); + + is( + $f->subroutine, 'main::bar', + q{Frame 2's subroutine should be 'main::bar'} + ); + + $trace->next_frame; + $trace->next_frame; + $trace->reset_pointer; + + $f = $trace->next_frame; + is( + $f->subroutine, 'Devel::StackTrace::new', + 'next_frame should return first frame after call to reset_pointer' + ); + + my @f = $trace->frames; + is( + scalar @f, 4, + 'frames method should return four frames' + ); + + is( + $f[0]->subroutine, 'Devel::StackTrace::new', + q{first frame's subroutine should be Devel::StackTrace::new} + ); + + is( + $f[3]->subroutine, 'main::foo', + q{last frame's subroutine should be main::foo} + ); +} + +# Not storing references +{ + my $obj = RefTest->new; + + my $trace = $obj->{trace}; + + my $call_to_trace = ( $trace->frames )[1]; + + my @args = $call_to_trace->args; + + is( + scalar @args, 1, + 'Only one argument should have been passed in the call to trace()' + ); + + like( + $args[0], qr/RefTest=HASH/, + q{Actual object should be replaced by string 'RefTest=HASH'} + ); +} + +# Storing references +{ + my $obj = RefTest2->new; + + my $trace = $obj->{trace}; + + my $call_to_trace = ( $trace->frames )[1]; + + my @args = $call_to_trace->args; + + is( + scalar @args, 1, + 'Only one argument should have been passed in the call to trace()' + ); + + isa_ok( $args[0], 'RefTest2' ); +} + +# Storing references (deprecated interface 1) +{ + my $obj = RefTestDep1->new; + + my $trace = $obj->{trace}; + + my $call_to_trace = ( $trace->frames )[1]; + + my @args = $call_to_trace->args; + + is( + scalar @args, 1, + 'Only one argument should have been passed in the call to trace()' + ); + + isa_ok( $args[0], 'RefTestDep1' ); +} + +# No ref to Exception::Class::Base object without refs +if ( $Exception::Class::VERSION && $Exception::Class::VERSION >= 1.09 ) +{ + ## no critic (ErrorHandling::RequireCheckingReturnValueOfEval) + eval { + Exception::Class::Base->throw( + error => 'error', + show_trace => 1, + ); + }; + my $exc = $@; + eval { quux($exc) }; + + ok( !$@, 'create stacktrace with no refs and exception object on stack' ); +} + +{ + sub FooBar::some_sub { return Devel::StackTrace->new } + + my $trace = eval { FooBar::some_sub('args') }; + + my $f = ( $trace->frames )[2]; + + is( $f->subroutine, '(eval)', 'subroutine is (eval)' ); + + my @args = $f->args; + + is( scalar @args, 0, 'no args given to eval block' ); +} + +{ + { + package #hide + FooBarBaz; + + sub func2 { + return Devel::StackTrace->new( ignore_package => qr/^FooBar/ ); + } + sub func1 { FooBarBaz::func2() } + } + + my $trace = FooBarBaz::func1('args'); + + my @f = $trace->frames; + + is( scalar @f, 1, 'check regex as ignore_package arg' ); +} + +## no critic (Modules::ProhibitMultiplePackages) +{ + package #hide + StringOverloaded; + + use overload q{""} => sub {'overloaded'}; +} + +{ + my $o = bless {}, 'StringOverloaded'; + + my $trace = baz($o); + + unlike( + $trace->as_string, qr/\boverloaded\b/, + 'overloading is ignored by default' + ); +} + +{ + my $o = bless {}, 'StringOverloaded'; + + my $trace = respect_overloading($o); + + like( + $trace->as_string, qr/\boverloaded\b/, + 'overloading is ignored by default' + ); +} + +{ + package #hide + BlowOnCan; + + sub can { die 'foo' } +} + +{ + my $o = bless {}, 'BlowOnCan'; + + my $trace = baz($o); + + like( + $trace->as_string, qr/BlowOnCan/, + 'death in overload::Overloaded is ignored' + ); +} + +{ + my $trace = max_arg_length('abcdefghijklmnop'); + + my $trace_text = <<"EOF"; +Trace begun at $test_file_name line 1021 +main::max_arg_length('abcdefghij...') called at $test_file_name line 307 +EOF + + is( $trace->as_string, $trace_text, 'trace text' ); + + my $trace_text_1 = <<"EOF"; +Trace begun at $test_file_name line 1021 +main::max_arg_length('abc...') called at $test_file_name line 307 +EOF + + is( + $trace->as_string( { max_arg_length => 3 } ), + $trace_text_1, + 'trace text, max_arg_length = 3', + ); +} + +SKIP: +{ + skip 'Test only runs on Linux', 1 + unless $^O eq 'linux'; + + my $frame = Devel::StackTrace::Frame->new( + [ 'Foo', 'foo/bar///baz.pm', 10, 'bar', 1, 1, q{}, 0 ], + [] + ); + + is( $frame->filename, 'foo/bar/baz.pm', 'filename is canonicalized' ); +} + +{ + my $obj = RefTest4->new(); + + my $trace = $obj->{trace}; + + ok( + ( !grep { ref $_ } map { @{ $_->{args} } } @{ $trace->{raw} } ), + 'raw data does not contain any references when unsafe_ref_capture not set' + ); + + is( + $trace->{raw}[1]{args}[1], 'not a ref', + 'non-refs are preserved properly in raw data as well' + ); +} + +{ + my $trace = overload_no_stringify( CodeOverload->new() ); + + ## no critic (ErrorHandling::RequireCheckingReturnValueOfEval) + eval { $trace->as_string() }; + + is( + $@, q{}, + 'no error when respect_overload is true and object overloads but does not stringify' + ); +} + +{ + my $trace = Filter::foo(); + + my @frames = $trace->frames(); + is( scalar @frames, 2, 'frame_filtered trace has just 2 frames' ); + is( + $frames[0]->subroutine(), 'Devel::StackTrace::new', + 'first subroutine' + ); + is( + $frames[1]->subroutine(), 'Filter::bar', + 'second subroutine (skipped Filter::foo)' + ); +} + +{ + my $trace = FilterAllFrames::a_foo(); + + my @frames = $trace->frames(); + is( + scalar @frames, 2, + 'after filtering whole list of frames, got just 2 frames' + ); + is( + $frames[0]->subroutine(), 'FilterAllFrames::a_bar', + 'first subroutine' + ); + is( + $frames[1]->subroutine(), 'FilterAllFrames::a_foo', + 'second subroutine' + ); +} + +{ + my $trace = Devel::StackTrace->new; + my $ok = 0; + if ($trace) { + $ok = 1; + } + ok( $ok, 'trace overloads bool as true' ); +} + +done_testing(); + +# This means I can move these lines down without constantly fiddling +# with the checks for line numbers in the tests. + +#line 1000 +sub foo { + bar( @_, 1 ); +} + +sub bar { + baz( @_, 2 ); +} + +sub baz { + Devel::StackTrace->new( @_ ? @_[ 0, 1 ] : () ); +} + +sub quux { + Devel::StackTrace->new(); +} + +sub respect_overloading { + Devel::StackTrace->new( respect_overload => 1 ); +} + +sub max_arg_length { + Devel::StackTrace->new( max_arg_length => 10 ); +} + +sub overload_no_stringify { + return Devel::StackTrace->new( respect_overload => 1 ); +} + +{ + package #hide + Test; + + sub foo { + trace(@_); + } + + sub trace { + Devel::StackTrace->new(@_); + } +} + +{ + package #hide + SubTest; + + use base qw(Test); + + sub foo { + trace(@_); + } + + sub trace { + Devel::StackTrace->new(@_); + } +} + +{ + package #hide + RefTest; + + sub new { + my $self = bless {}, shift; + + $self->{trace} = trace($self); + + return $self; + } + + sub trace { + Devel::StackTrace->new(); + } +} + +{ + package #hide + RefTest2; + + sub new { + my $self = bless {}, shift; + + $self->{trace} = trace($self); + + return $self; + } + + sub trace { + Devel::StackTrace->new( unsafe_ref_capture => 1 ); + } +} + +{ + package #hide + RefTestDep1; + + sub new { + my $self = bless {}, shift; + + $self->{trace} = trace($self); + + return $self; + } + + sub trace { + Devel::StackTrace->new( no_refs => 0 ); + } +} + +{ + package #hide + RefTest4; + + sub new { + my $self = bless {}, shift; + + $self->{trace} = trace( $self, 'not a ref' ); + + return $self; + } + + sub trace { + Devel::StackTrace->new(); + } +} + +{ + package #hide + CodeOverload; + + use overload '&{}' => sub {'foo'}; + + sub new { + my $class = shift; + return bless {}, $class; + } +} + +{ + package #hide + Filter; + + sub foo { + bar(); + } + + sub bar { + return Devel::StackTrace->new( + frame_filter => sub { $_[0]{caller}[3] ne 'Filter::foo' } ); + } +} + +{ + package #hide + FilterAllFrames; + + sub a_foo { b_foo() } + sub b_foo { a_bar() } + sub a_bar { b_bar() } + + sub b_bar { + my $stacktrace = Devel::StackTrace->new(); + $stacktrace->frames( only_a_frames( $stacktrace->frames() ) ); + return $stacktrace; + } + + sub only_a_frames { + my @frames = @_; + return grep { $_->subroutine() =~ /^FilterAllFrames::a/ } @frames; + } +} diff --git a/t/02-bad-utf8.t b/t/02-bad-utf8.t new file mode 100644 index 0000000..1a55a6a --- /dev/null +++ b/t/02-bad-utf8.t @@ -0,0 +1,41 @@ +use strict; +use warnings; + +use Test::More; + +## no critic (BuiltinFunctions::ProhibitStringyEval, ErrorHandling::RequireCheckingReturnValueOfEval) +plan skip_all => 'These tests require Encode.pm' + unless eval 'use Encode; 1'; +## use critic + +plan skip_all => 'These tests require Perl 5.8.8+' + if $] < 5.008008; + +plan skip_all => 'These tests are not relevant with Perl 5.13.8+' + if $] >= 5.013008; + +use Devel::StackTrace; + +# This should be invalid UTF8 +my $raw_bad = do { use bytes; chr(0xED) . chr(0xA1) . chr(0xBA) }; + +my $decoded = Encode::decode( 'utf8' => $raw_bad ); +my $trace = foo($decoded); + +my $string = eval { $trace->as_string() }; + +my $e = $@; +is( + $e, q{}, + 'as_string() does not throw an exception' +); +like( + $string, qr/\Q(bad utf-8)/, + 'stringified output notes bad utf-8' +); + +sub foo { + Devel::StackTrace->new(); +} + +done_testing(); diff --git a/t/03-message.t b/t/03-message.t new file mode 100644 index 0000000..50eb219 --- /dev/null +++ b/t/03-message.t @@ -0,0 +1,34 @@ +use strict; +use warnings; + +use Test::More; + +use Devel::StackTrace; + +sub foo { + return Devel::StackTrace->new(@_); +} + +sub make_dst { + foo(@_); +} + +{ + my $dst = make_dst(); + + like( + $dst->as_string(), qr/^Trace begun/, + q{default message is "Trace begun"} + ); +} + +{ + my $dst = make_dst( message => 'Foo bar' ); + + like( + $dst->as_string(), qr/^Foo bar/, + q{set explicit message for trace} + ); +} + +done_testing(); diff --git a/t/04-indent.t b/t/04-indent.t new file mode 100644 index 0000000..5b0391c --- /dev/null +++ b/t/04-indent.t @@ -0,0 +1,35 @@ +use strict; +use warnings; + +use Test::More; + +use Devel::StackTrace; + +sub foo { + return Devel::StackTrace->new(@_); +} + +sub make_dst { + foo(@_); +} + +{ + my $dst = make_dst(); + + for my $line ( split /\n/, $dst->as_string() ) { + unlike( $line, qr/^\s/, 'line does not start with whitespace' ); + } +} + +{ + my $dst = make_dst( indent => 1 ); + + my @lines = split /\n/, $dst->as_string(); + shift @lines; + + for my $line (@lines) { + like( $line, qr/^\s/, 'line starts with whitespace' ); + } +} + +done_testing(); diff --git a/t/05-back-compat.t b/t/05-back-compat.t new file mode 100644 index 0000000..3b0c4fc --- /dev/null +++ b/t/05-back-compat.t @@ -0,0 +1,10 @@ +use strict; +use warnings; + +use Test::More; + +use Devel::StackTrace; + +isa_ok( 'Devel::StackTraceFrame', 'Devel::StackTrace::Frame' ); + +done_testing(); diff --git a/t/06-dollar-at.t b/t/06-dollar-at.t new file mode 100644 index 0000000..b8d1412 --- /dev/null +++ b/t/06-dollar-at.t @@ -0,0 +1,25 @@ +use strict; +use warnings; + +use Test::More; + +use Devel::StackTrace; + +## no critic (Variables::RequireLocalizedPunctuationVars) +{ + $@ = my $msg = q{Don't tread on me}; + + Devel::StackTrace->new()->frame(0)->as_string(); + + is( $@, $msg, '$@ is not overwritten in as_string() method' ); +} + +{ + $@ = my $msg = q{Don't tread on me}; + + Devel::StackTrace->new( ignore_package => 'Foo' )->frames(); + + is( $@, $msg, '$@ is not overwritten in _make_filter() method' ); +} + +done_testing(); diff --git a/t/07-no-args.t b/t/07-no-args.t new file mode 100644 index 0000000..7bdc166 --- /dev/null +++ b/t/07-no-args.t @@ -0,0 +1,45 @@ +use strict; +use warnings; + +use Test::More; + +use Devel::StackTrace; + +{ + my $trace = foo( 1, 2 ); + is_deeply( + [ map { [ $_->args() ] } $trace->frames() ], + [ + ['Devel::StackTrace'], + [ 3, 4 ], + [ 1, 2 ], + ], + 'trace includes args' + ); + + $trace = foo( 0, 2 ); + is_deeply( + [ map { [ $_->args() ] } $trace->frames() ], + [ + [], + [], + [], + ], + 'trace does not include args' + ); + +} + +done_testing(); + +sub foo { + $_[0] ? bar( 3, 4 ) : baz( 3, 4 ); +} + +sub bar { + return Devel::StackTrace->new(); +} + +sub baz { + return Devel::StackTrace->new( no_args => 1 ); +} diff --git a/t/08-filter-early.t b/t/08-filter-early.t new file mode 100644 index 0000000..120b7dd --- /dev/null +++ b/t/08-filter-early.t @@ -0,0 +1,33 @@ +use strict; +use warnings; + +use Test::More; + +use Devel::StackTrace; + +{ + my $trace = foo( [] ); + is( + ( scalar grep {ref} map { $_->args } $trace->frames ), 0, + 'args stringified in trace' + ); +} + +done_testing(); + +sub foo { + my $filter = sub { + my $frame = shift; + if ( $frame->{caller}[3] eq 'main::foo' ) { + ok( ref $frame->{args}[0], 'ref arg passed to filter' ); + } + 1; + }; + + return Devel::StackTrace->new( + frame_filter => $filter, + filter_frames_early => 1, + no_refs => 1, + ); +} + diff --git a/t/09-skip-frames.t b/t/09-skip-frames.t new file mode 100644 index 0000000..6c1c44d --- /dev/null +++ b/t/09-skip-frames.t @@ -0,0 +1,55 @@ +use strict; +use warnings; + +use Test::More; + +use Devel::StackTrace; + +{ + my $trace = baz(2); + my @f; + while ( my $f = $trace->next_frame ) { push @f, $f; } + + my $cnt = scalar @f; + is( + $cnt, 2, + 'Trace should have 2 frames' + ); + + is( + $f[0]->subroutine, 'main::bar', + 'First frame subroutine should be main::bar' + ); + is( + $f[1]->subroutine, 'main::baz', + 'Second frame subroutine should be main::baz' + ); +} + +{ + for my $i ( 1 .. 6 ) { + my $trace = baz($i); + like( + $trace->as_string, + qr/trace message/, + "stringified trace includes message when skipping $i frame(s)" + ); + } +} + +done_testing(); + +sub foo { + return Devel::StackTrace->new( + message => 'trace message', + skip_frames => shift, + ); +} + +sub bar { + foo(@_); +} + +sub baz { + bar(@_); +} diff --git a/t/10-set-frames.t b/t/10-set-frames.t new file mode 100644 index 0000000..04f2464 --- /dev/null +++ b/t/10-set-frames.t @@ -0,0 +1,37 @@ +use strict; +use warnings; + +use Test::More; + +use Devel::StackTrace; + +{ + my $trace = baz(); + my $other_trace = bar(); + + $trace->frames( $other_trace->frames ); + + my @f; + while ( my $f = $trace->next_frame ) { push @f, $f; } + + ok( @f == 1, 'only one frame' ); + + is( + $f[0]->subroutine, 'main::bar', + 'First frame subroutine should be main::bar' + ); +} + +done_testing(); + +sub foo { + return Devel::StackTrace->new( skip_frames => 2 ); +} + +sub bar { + foo(); +} + +sub baz { + bar(); +} diff --git a/xt/author/00-compile.t b/xt/author/00-compile.t new file mode 100644 index 0000000..281c83c --- /dev/null +++ b/xt/author/00-compile.t @@ -0,0 +1,61 @@ +use 5.006; +use strict; +use warnings; + +# this test was generated with Dist::Zilla::Plugin::Test::Compile 2.058 + +use Test::More; + +plan tests => 3; + +my @module_files = ( + 'Devel/StackTrace.pm', + 'Devel/StackTrace/Frame.pm' +); + + + +# no fake home requested + +my @switches = ( + -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 + my $stderr = IO::Handle->new; + + diag('Running: ', join(', ', map { my $str = $_; $str =~ s/'/\\'/g; q{'} . $str . q{'} } + $^X, @switches, '-e', "require q[$lib]")) + if $ENV{PERL_COMPILE_TEST_DEBUG}; + + my $pid = open3($stdin, '>&STDERR', $stderr, $^X, @switches, '-e', "require q[$lib]"); + binmode $stderr, ':crlf' if $^O eq 'MSWin32'; + my @_warnings = <$stderr>; + waitpid($pid, 0); + is($?, 0, "$lib loaded ok"); + + shift @_warnings if @_warnings and $_warnings[0] =~ /^Using .*\bblib/ + and not eval { +require blib; blib->VERSION('1.01') }; + + if (@_warnings) + { + warn @_warnings; + push @warnings, @_warnings; + } +} + + + +is(scalar(@warnings), 0, 'no warnings found') + or diag 'got warnings: ', ( Test::More->can('explain') ? Test::More::explain(\@warnings) : join("\n", '', @warnings) ); + + diff --git a/xt/author/eol.t b/xt/author/eol.t new file mode 100644 index 0000000..d793286 --- /dev/null +++ b/xt/author/eol.t @@ -0,0 +1,27 @@ +use strict; +use warnings; + +# this test was generated with Dist::Zilla::Plugin::Test::EOL 0.19 + +use Test::More 0.88; +use Test::EOL; + +my @files = ( + 'lib/Devel/StackTrace.pm', + 'lib/Devel/StackTrace/Frame.pm', + 't/00-report-prereqs.dd', + 't/00-report-prereqs.t', + 't/01-basic.t', + 't/02-bad-utf8.t', + 't/03-message.t', + 't/04-indent.t', + 't/05-back-compat.t', + 't/06-dollar-at.t', + 't/07-no-args.t', + 't/08-filter-early.t', + 't/09-skip-frames.t', + 't/10-set-frames.t' +); + +eol_unix_ok($_, { trailing_whitespace => 1 }) foreach @files; +done_testing; diff --git a/xt/author/mojibake.t b/xt/author/mojibake.t new file mode 100644 index 0000000..5ef161e --- /dev/null +++ b/xt/author/mojibake.t @@ -0,0 +1,9 @@ +#!perl + +use strict; +use warnings qw(all); + +use Test::More; +use Test::Mojibake; + +all_files_encoding_ok(); diff --git a/xt/author/no-tabs.t b/xt/author/no-tabs.t new file mode 100644 index 0000000..5f35a7f --- /dev/null +++ b/xt/author/no-tabs.t @@ -0,0 +1,27 @@ +use strict; +use warnings; + +# this test was generated with Dist::Zilla::Plugin::Test::NoTabs 0.15 + +use Test::More 0.88; +use Test::NoTabs; + +my @files = ( + 'lib/Devel/StackTrace.pm', + 'lib/Devel/StackTrace/Frame.pm', + 't/00-report-prereqs.dd', + 't/00-report-prereqs.t', + 't/01-basic.t', + 't/02-bad-utf8.t', + 't/03-message.t', + 't/04-indent.t', + 't/05-back-compat.t', + 't/06-dollar-at.t', + 't/07-no-args.t', + 't/08-filter-early.t', + 't/09-skip-frames.t', + 't/10-set-frames.t' +); + +notabs_ok($_) foreach @files; +done_testing; diff --git a/xt/author/pod-coverage.t b/xt/author/pod-coverage.t new file mode 100644 index 0000000..8878c2d --- /dev/null +++ b/xt/author/pod-coverage.t @@ -0,0 +1,44 @@ +#!perl +# This file was automatically generated by Dist::Zilla::Plugin::Test::Pod::Coverage::Configurable 0.07. + +use Test::Pod::Coverage 1.08; +use Test::More 0.88; + +BEGIN { + if ( $] <= 5.008008 ) { + plan skip_all => 'These tests require Pod::Coverage::TrustPod, which only works with Perl 5.8.9+'; + } +} +use Pod::Coverage::TrustPod; + +my %skip = map { $_ => 1 } qw( ); + +my @modules; +for my $module ( all_modules() ) { + next if $skip{$module}; + + push @modules, $module; +} + +plan skip_all => 'All the modules we found were excluded from POD coverage test.' + unless @modules; + +plan tests => scalar @modules; + +my %trustme = (); + +my @also_private; + +for my $module ( sort @modules ) { + pod_coverage_ok( + $module, + { + coverage_class => 'Pod::Coverage::TrustPod', + also_private => \@also_private, + trustme => $trustme{$module} || [], + }, + "pod coverage for $module" + ); +} + +done_testing(); diff --git a/xt/author/pod-spell.t b/xt/author/pod-spell.t new file mode 100644 index 0000000..aa3ad0e --- /dev/null +++ b/xt/author/pod-spell.t @@ -0,0 +1,47 @@ +use strict; +use warnings; +use Test::More; + +# generated by Dist::Zilla::Plugin::Test::PodSpelling 2.007005 +use Test::Spelling 0.12; +use Pod::Wordlist; + + +add_stopwords(); +all_pod_files_spelling_ok( qw( bin lib ) ); +__DATA__ +Bessarabov +CPAN +Cantrell +DROLSKY +DROLSKY's +Dagfinn +Dave +David +Devel +Fowler +Frame +Graham +Ilmari +Ivan +Knop +Mannsåker +Mark +Pali +PayPal +Ricardo +Rolsky +Rolsky's +Signes +StackTrace +autarch +david +drolsky +haarg +ilmari +ivan +lib +mark +pali +rjbs +stacktrace diff --git a/xt/author/pod-syntax.t b/xt/author/pod-syntax.t new file mode 100644 index 0000000..e563e5d --- /dev/null +++ b/xt/author/pod-syntax.t @@ -0,0 +1,7 @@ +#!perl +# This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. +use strict; use warnings; +use Test::More; +use Test::Pod 1.41; + +all_pod_files_ok(); diff --git a/xt/author/portability.t b/xt/author/portability.t new file mode 100644 index 0000000..6d1d92d --- /dev/null +++ b/xt/author/portability.t @@ -0,0 +1,8 @@ +use strict; +use warnings; + +use Test::More; + +use Test::Portability::Files; + +run_tests(); diff --git a/xt/author/precious.t b/xt/author/precious.t new file mode 100644 index 0000000..ee161de --- /dev/null +++ b/xt/author/precious.t @@ -0,0 +1,24 @@ +use strict; +use warnings; + +use Test::More; + +use Capture::Tiny qw( capture ); +use Encode qw( decode ); +use FindBin qw( $Bin ); + +binmode $_, ':encoding(utf-8)' + for map { Test::More->builder->$_ } + qw( output failure_output todo_output ); + +chdir "$Bin/../.." + or die "Cannot chdir to $Bin/../..: $!"; + +my ( $out, $err ) = capture { system(qw( precious lint -a )) }; +$_ = decode( 'UTF-8', $_ ) for grep {defined} $out, $err; + +is( $? >> 8, 0, 'precious lint -a exited with 0' ) + or diag($out); +is( $err, q{}, 'no output to stderr' ); + +done_testing(); diff --git a/xt/author/synopsis.t b/xt/author/synopsis.t new file mode 100644 index 0000000..3e03427 --- /dev/null +++ b/xt/author/synopsis.t @@ -0,0 +1,5 @@ +#!perl + +use Test::Synopsis; + +all_synopsis_ok(); diff --git a/xt/author/test-version.t b/xt/author/test-version.t new file mode 100644 index 0000000..b47210e --- /dev/null +++ b/xt/author/test-version.t @@ -0,0 +1,23 @@ +use strict; +use warnings; +use Test::More; + +# generated by Dist::Zilla::Plugin::Test::Version 1.09 +use Test::Version; + +my @imports = qw( version_all_ok ); + +my $params = { + is_strict => 1, + has_version => 1, + multiple => 0, + +}; + +push @imports, $params + if version->parse( $Test::Version::VERSION ) >= version->parse('1.002'); + +Test::Version->import(@imports); + +version_all_ok; +done_testing; diff --git a/xt/release/cpan-changes.t b/xt/release/cpan-changes.t new file mode 100644 index 0000000..286005a --- /dev/null +++ b/xt/release/cpan-changes.t @@ -0,0 +1,10 @@ +use strict; +use warnings; + +# this test was generated with Dist::Zilla::Plugin::Test::CPAN::Changes 0.012 + +use Test::More 0.96 tests => 1; +use Test::CPAN::Changes; +subtest 'changes_ok' => sub { + changes_file_ok('Changes'); +}; diff --git a/xt/release/meta-json.t b/xt/release/meta-json.t new file mode 100644 index 0000000..5ddad73 --- /dev/null +++ b/xt/release/meta-json.t @@ -0,0 +1,4 @@ +#!perl + +use Test::CPAN::Meta::JSON; +meta_json_ok(); -- 2.34.1