Badger-0.16/000755 000765 000024 00000000000 14437311050 012536 5ustar00abwstaff000000 000000 Badger-0.16/pod/000755 000765 000024 00000000000 14437311050 013320 5ustar00abwstaff000000 000000 Badger-0.16/Changes000644 000765 000024 00000027546 14437310771 014060 0ustar00abwstaff000000 000000 NAME Badger::Changes - Summary of changes in the Badger toolkit CHANGES This document contains a brief overview of what has changed between successive version of the Badger toolkit. Badger is now considered to be mature, stable, reliable, and unlikely to change significantly in future versions. Version 0.16 - 5th June 2023 Fix numerous spelling mistakes in POD Version 0.15 - 24th August 2022 Added "filename_format" option to Badger::Log::File. Version 0.14 - 16th August 2022 Added support for Cpanel::JSON::XS to Badger::Codec::JSON. Added strftime option to Badger::Log. Version 0.13 - 18th October 2018 Silenced various "used only once" warnings. Win32 fixes for Badger::Filesystem::Virtual. Version 0.12 - 12th December 2016 Added some tests for YAML modules in 3 test scripts that were failing. Version 0.11 - 11th December 2016 Fix for missing file in distribution. Version 0.10 - 11th December 2016 Added Badger::Comparable, Badger::Date, Badger::Duration, Badger::Filter, Badger::Progress, Badger::Workplace, Badger::Workspace and Badger::Config::Filesystem. Refactored parts of Badger::Config. Changed Badger::Base message() method to allow message formats to be defined in "$self-"{ messages }> when $self is a blessed hash object. Added no_config() method to Badger::Hub. Fixed a bug in the auto_can feature of Badger::Class::Methods which prevented it from working with subclasses. Fixed a bug in Badger::Debug dump_ref() to make it directly call other "dump_XXX()" functions instead of relying on inheritance of those methods through $self. Added plurality(), inflect(), list_each(), hash_each(), extend(), merge(), split_to_list(), join_uri() and resolve_uri(), to Badger::Utils. Added additional delegate hooks to Badger::Utils to load utility functions in Badger::Filesystem, Badger::Timestamp, Badger::Duration, Badger::Logic and Badger::URL. Squashed a non-numerical warning in Badger::Timestamp. Added the UTF8, JSON and YAML constants to Badger::Constants. Fixed Badger::Codec::YAML to work better with YAML::XS and Badger::Codec::JSON to work better with JSON::XS. Fixed a typo/bug in the "type_args()" in Badger::Factory method which was returning the wrong argument list. Fixed a parser bug in Badger::Logic. Fixes to silence warnings in perl 5.22. Version 0.09 - 8th February 2012 Added Badger::Codec::Timestamp. Changed Badger::Timestamp to numify values to remove leading zeroes (e.g. 2012/04/20 now yields a month of 4 instead of 04). Fixed some obscure bugs in the module loading code in Badger::Class and related modules that could potentially cause unpredictable results on case insensitive file systems (e.g. Apple's HFS with default settings). Added the restat() method to Badger::Filesystem::Path. Added documentation for various methods that was missing. Temporary disabled the Pod::Coverage tests on AUTOMATED_TESTING systems. We know there's still stuff to do. Added SLASH to Badger::Constants Version 0.08 - 13th January 2012 Restored the $VERSION variable to Badger.pm rather than using the "version" import hook in Badger::Class which confused PAUSE. Changed Badger::Test::Manager to detect undefined results. Merged Michael Grubb's bug fix for Badger::Base: Fixed some minor documentation issues. Version 0.07 - 2nd January 2012 Added Badger::Storage, Badger::Storage::Memory. and Badger::Storage::Filesystem. Added Badger::Codec::TT. Added the permissions() method to Badger::Filesystem::Path. Added temp_directory() and temp_file() methods to Badger::Filesystem. Also changed the Path(), File() and Dir() functions to short-circuit and return if passed a single object that is already of the expected type. Added some extra comparison methods to Badger::Timestamp (not_equal(), (not_before() and not_after()) and overloaded these and other methods onto the "==", "!=", "<", ">", "<=" and ">=" operators. Added the export_before() and export_after() methods to Badger::Exporter. Added the if_env import hook and "-a|Badger::Test/all()" option to Badger::Test to make it easier to define tests that don't get run unless a particular environment variable is set (e.g. for Pod coverage/kwalitee tests that you only want to run if either of the "RELEASE_TESTING" or "AUTOMATED_TESTING" environment variables is set). Added the random_name(), camel_case() and permute_fragments() functions to Badger::Utils. Also add some extra debugging code to params() and self_params() to catch any attempt to pass an odd number of arguments. Changed the Badger::Factory module to use permute_fragments() on the module path when specified as a single string. Also added the default() and names() methods along with their corresponding package variable magic. Added the debug_callers(), debugf() and debug_at() methods to Badger::Debug. Added the alias() method to Badger::Class. Added the auto_can() method to Badger::Class::Methods. Changed the Badger::Class::Config module to store the configuration scheme in $CONFIG_SCHEMA instead of $CONFIG. Added the Badger::Codec::HTML module which defines the "html" codec. Changed the throw() method in Badger::Base to pass the exception type to exception(). Changed the try() method in Badger::Base to preserve the list/scalar calling context and to handle false but defined values. Cleaned up and generalised the Badger::Hub module. The Badger-specific data has now been moved into Badger::Hub::Badger. The "configure()" method is now called construct(). Version 0.06 Added copy_file() and move_file() to Badger::Filesystem and copy() and move() methods to Badger::Filesystem::File. Added chmod_path() to Badger::Filesystem and chmod() to Badger::Filesystem::Path. Added Bin() to Badger::Filesystem. Added the encoding() method to Badger::Filesystem::File for specifying the encoding of a file, along with the utf8(), bytes(), crlf() and raw() methods for enabling different encoding layers. Added the codec() method to Badger::Filesystem::File for specifying a serialisation codec to use in conjunction with the new data() method. Added Badger::Timestamp. This is returned by the new created(), accessed() and modified() methods in Badger::Filesystem::Path. Added Badger::Logic. Added Badger::Log and Badger::Log::File. Added numlike() to Badger::Utils as an alias for "looks_like_number". It's the numerical counterpart to textlike() and is significantly easier to type. Added debug_msg() to Badger::Base. Also added the "Badger::Base::Trial" class definition for use with the try() method. Added lib import hook to Badger. Added bclass as an alias for class in Badger::Class. Changed Badger::Class::Config to maintain the order of configuration parameters where possible (i.e. when expressed as a list ref rather than a hash ref). Also added "target:var" fallback which looks in the target object or hash ref for the variable. This allows options to default to the values set by preceeding options. Changed Badger::Codec::JSON to use JSON::XS if available. Mr T is now using Badger 0.06 in production code and is happy to report that everything seems to be working rather well. Anyone for a game of tennis? Version 0.05 - 23rd December 2008 Refactored Badger::Factory. Added support to Badger::Exporter for the "=" pseudo-sigil which can be used to create constants on the fly. package Badger::Example; use Badger::Class exports => { tags => { math => { e => '=2.718', pi => '=3.142', phi => '=1.618', }, } }; package main; use Badger::Example ':math'; print e; # 2.718 print pi; # 3.142 print phi; # 1.618 Mr T is starting to feel rather confident about building a production system based on Badger v0.05. Version 0.04 - 2nd December 2008 Added the throw_msg() method to Badger::Base. Added init_method hook to Badger::Class and initialiaser() to Badger::Class::Methods. Changed Badger::Exception match_type() method to accept a list or hash reference, or a string of whitespace delimited exception types. Changed Badger::Factory to pass $name as an argument to various methods. Also passes arguments to load() (required for Template::TT2::Plugins) Also modified item() to accept a non-textlike type argument which bypasses the module lookup. Moved a whole bunch of stuff out of Badger::Class into "Badger::Class::*" modules. Added Badger::Class::Config for simple configuration. Added hash() method to Badger::Methods and hash_methods hook to Badger::Class. Added trace() hook and related paraphernalia to Badger::Exception. Added the "-t" / "--trace" command line options to Badger::Test to enable it when running tests. Also added "-h" / "--help" options. Added Codec() exportable subroutine to Badger::Codecs. Added Badger::Codec::URL. It's similar to Badger::Codec::URI, but slightly different. See the TT uri/url filters for the reason. Changed the prototype() method in Badger::Prototype to accept a single "undef" value to clear any current prototype. Also added the has_prototype() method. Mr T is looking on the bright side about the possibility of building a production system based on Badger v0.04, but still advises caution. Version 0.03 - 7th October 2008 Added delegate loaders to Badger. This provides some semantic sugar for loading a bunch of different "Badger::*" modules in one go. use Badger Filesystem => 'FS $Bin', Codecs => 'storable base64', Debug => { modules => 'My::Module', }; Added different() to Badger::Test::Manager. Added textlike() to Badger::Utils Added the overload as_text and is_true import hooks and related method to Badger::Class. These delegate to the "overload" module. Added the print method to Badger::Filesystem::File. Added support for dynamic root directories to Badger::Filesystem::Virtual. Added the defaults and aliases hooks to Badger::Class, implemented by Badger::Class::Defaults and Badger::Class::Aliases, respectively. There are still experimental. Fixed up some stat handling in Badger::Filesystem to help with subclassing in Badger::Filesystem::Virtual Mr T pities the fool that attempts to builds a production system based on Badger version 0.03 without first evaluating it carefully and reading the documentation. Version 0.02 - 6th September 2008 Badger::Class got the vars method and hook for declaring and defining variables. Badger::Utils gained the ability to load and export functions from Scalar::Util, List::Util, List::MoreUtils, Hash::Util and Digest::MD5. Various documentation updates. Mr T admires the tenacity of anyone attempting to build a production system based on Badger v0.02 and hopes they have a thorough test suite. Version 0.01 - 27th August 2008 This was the first release version. Mr T pities the fool who builds a production system based on Badger v0.01. AUTHOR Andy Wardley COPYRIGHT Copyright (C) 2008-2013 Andy Wardley. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Badger-0.16/MAINTAINER000644 000765 000024 00000000420 14360244740 014112 0ustar00abwstaff000000 000000 To release a new version: * Update VERSION in Makefile.PL and $VERSION in lib/Badger.pm * Update the pod/Badger/Changes.pod file and regenerate Changes: $ pod2text pod/Badger/Changes.pod > Changes * Build: $ perl Makefile.PL $ make $ make test $ make dist Badger-0.16/MANIFEST000644 000765 000024 00000021263 14437311050 013673 0ustar00abwstaff000000 000000 Changes lib/Badger.pm lib/Badger/App.pm lib/Badger/Apps.pm lib/Badger/Base.pm lib/Badger/Class.pm lib/Badger/Class/Config.pm lib/Badger/Class/Methods.pm lib/Badger/Class/Vars.pm lib/Badger/Codec.pm lib/Badger/Codec/Base64.pm lib/Badger/Codec/Chain.pm lib/Badger/Codec/Encode.pm lib/Badger/Codec/Encoding.pm lib/Badger/Codec/HTML.pm lib/Badger/Codec/JSON.pm lib/Badger/Codec/Storable.pm lib/Badger/Codec/Timestamp.pm lib/Badger/Codec/TT.pm lib/Badger/Codec/Unicode.pm lib/Badger/Codec/URI.pm lib/Badger/Codec/URL.pm lib/Badger/Codec/YAML.pm lib/Badger/Codecs.pm lib/Badger/Comparable.pm lib/Badger/Config.pm lib/Badger/Config/Filesystem.pm lib/Badger/Config/Item.pm lib/Badger/Config/Schema.pm lib/Badger/Constants.pm lib/Badger/Data.pm lib/Badger/Data/Facet.pm lib/Badger/Data/Facet/Class.pm lib/Badger/Data/Facet/List.pm lib/Badger/Data/Facet/List/MaxSize.pm lib/Badger/Data/Facet/List/MinSize.pm lib/Badger/Data/Facet/List/Size.pm lib/Badger/Data/Facet/Number.pm lib/Badger/Data/Facet/Number/Max.pm lib/Badger/Data/Facet/Number/Min.pm lib/Badger/Data/Facet/Text.pm lib/Badger/Data/Facet/Text/Length.pm lib/Badger/Data/Facet/Text/MaxLength.pm lib/Badger/Data/Facet/Text/MinLength.pm lib/Badger/Data/Facet/Text/Pattern.pm lib/Badger/Data/Facet/Text/Whitespace.pm lib/Badger/Data/Facet/tmp lib/Badger/Data/Facets.pm lib/Badger/Data/Type.pm lib/Badger/Data/Type/Class.pm lib/Badger/Data/Type/Number.pm lib/Badger/Data/Type/Simple.pm lib/Badger/Data/Type/Text.pm lib/Badger/Data/Types.pm lib/Badger/Date.pm lib/Badger/Debug.pm lib/Badger/Duration.pm lib/Badger/Exception.pm lib/Badger/Exporter.pm lib/Badger/Factory.pm lib/Badger/Factory/Class.pm lib/Badger/Filesystem.pm lib/Badger/Filesystem/Base.pm lib/Badger/Filesystem/Directory.pm lib/Badger/Filesystem/File.pm lib/Badger/Filesystem/Path.pm lib/Badger/Filesystem/Universal.pm lib/Badger/Filesystem/Virtual.pm lib/Badger/Filesystem/Visitor.pm lib/Badger/Filter.pm lib/Badger/Hub.pm lib/Badger/Hub/Badger.pm lib/Badger/Log.pm lib/Badger/Log/File.pm lib/Badger/Logic.pm lib/Badger/Mixin.pm lib/Badger/Modules.pm lib/Badger/Period.pm lib/Badger/Progress.pm lib/Badger/Prototype.pm lib/Badger/Rainbow.pm lib/Badger/Reporter.pm lib/Badger/Reporter/App.pm lib/Badger/Test.pm lib/Badger/Test/Manager.pm lib/Badger/Timestamp.pm lib/Badger/URL.pm lib/Badger/Utils.pm lib/Badger/Workplace.pm lib/Badger/Workspace.pm MAINTAINER Makefile.PL MANIFEST This list of files MYMETA.json MYMETA.yml pod/Badger/Changes.pod pod/Badger/FAQ.pod pod/Badger/Intro.pod README RELEASE t/app/app.t t/class/alias.t t/class/config.t t/class/lib/My/Aliased.pm t/class/lib/My/Class.pm t/class/lib/My/Config1.pm t/class/lib/My/Config2.pm t/class/lib/My/Config3.pm t/class/lib/My/Config4.pm t/class/lib/My/Config5.pm t/class/lib/My/Vars1.pm t/class/lib/My/Vars2.pm t/class/lib/My/Vars3.pm t/class/lib/My/Vars4.pm t/class/lib/My/Vars5.pm t/class/lib/My/Vars6.pm t/class/lib/My/Vars7.pm t/class/methods.t t/class/subclass.t t/class/vars.t t/codec/base64.t t/codec/codec.t t/codec/codecs.t t/codec/data/example.ts t/codec/encode.t t/codec/encoding.t t/codec/html.t t/codec/json.t t/codec/lib/My/Codec/Foo.pm t/codec/storable.t t/codec/timestamp.t t/codec/tt.t t/codec/unicode.t t/codec/uri.t t/codec/url.t t/config/filesystem.t t/config/filesystem2.t t/config/test_files/config1/pages.yaml t/config/test_files/config1/pages/auth.yaml t/config/test_files/config1/site.yaml t/config/test_files/config1/things.yaml t/config/test_files/config1/user.yaml t/config/test_files/config2/config.yaml t/config/test_files/config2/pages.yaml t/config/test_files/config2/pages/more.yaml t/config/test_files/config2/user.yaml t/config/test_files/dir1/dashes.yaml t/config/test_files/dir1/dashes/admin.yaml t/config/test_files/dir1/dashes/developer.yaml t/config/test_files/dir1/ents.yaml t/config/test_files/dir1/ents/four/ten.yaml t/config/test_files/dir1/ents/four/twenty.yaml t/config/test_files/dir1/ents/misc.yaml t/config/test_files/dir1/nested/one.yaml t/config/test_files/dir1/nested/two/three.yaml t/config/test_files/dir1/nibbles.yaml t/config/test_files/dir1/nibbles/cheese.yaml t/config/test_files/dir1/nibbles/drinks/beers.yaml t/config/test_files/dir1/project.yaml t/config/test_files/dir1/urls.yaml t/config/test_files/dir1/urls/foo.yaml t/config/test_files/dir1/widgets.yaml t/config/test_files/dir1/widgets/more.yaml t/config/test_files/dir1/widgets/still/more.yaml t/config/test_files/dir2/config.yaml t/config/test_files/dir2/one.yaml t/config/test_files/dir2/one/two.yaml t/config/test_files/dir2/ten.yaml t/config/test_files/dir2/ten/eleven.yaml t/config/test_files/dir2/three.yaml t/config/test_files/dir2/three/five/six.yaml t/config/test_files/dir2/three/four.yaml t/config/test_files/dir2/three/iv.yaml t/config/test_files/dir3/config.yaml t/config/test_files/dir3/three.yaml t/config/test_files/dir3/three/iv.yaml t/config/test_files/dir3/three/v.yaml t/config/test_files/wspace1/config/cache.yaml t/config/test_files/wspace1/config/components.yaml t/config/test_files/wspace1/config/pages.yaml t/config/test_files/wspace1/config/pages/auth.yaml t/config/test_files/wspace1/config/wibble.yaml t/config/test_files/wspace1/config/workspace.yaml t/config/test_files/wspace2/config/components.yaml t/config/test_files/wspace2/config/more.yaml t/config/test_files/wspace2/config/workspace.yaml t/core/base.t t/core/class.t t/core/config.t t/core/constants.t t/core/date.t t/core/debug.t t/core/dump.t t/core/exception.t t/core/exporter.t t/core/factory.t t/core/hub.t t/core/lib/Class/Bottom.pm t/core/lib/Class/Middle.pm t/core/lib/Class/Top.pm t/core/lib/My/BadModule.pm t/core/lib/My/Class.pm t/core/lib/My/Constants.pm t/core/lib/My/Debugger1.pm t/core/lib/My/Debugger2.pm t/core/lib/My/Debugger3.pm t/core/lib/My/Exporter/Base1.pm t/core/lib/My/Exporter/Base2.pm t/core/lib/My/Exporter/BeforeAfter.pm t/core/lib/My/Exporter/BeforeAfterOne.pm t/core/lib/My/Exporter/BeforeAfterTwo.pm t/core/lib/My/Exporter/Explicit.pm t/core/lib/My/Exporter/Generator.pm t/core/lib/My/Exporter/Subclass1.pm t/core/lib/My/Exporter/Subclass2.pm t/core/lib/My/Exporter4.pm t/core/lib/My/Exporter5.pm t/core/lib/My/Exporter6.pm t/core/lib/My/Exporter7.pm t/core/lib/My/Exporter8.pm t/core/lib/My/Exporter9.pm t/core/lib/My/Extra/Wudget.pm t/core/lib/My/Mixin/Bar.pm t/core/lib/My/Mixin/Baz.pm t/core/lib/My/Mixin/Foo.pm t/core/lib/My/Widget.pm t/core/lib/My/Wodget.pm t/core/lib/Your/Answer.pm t/core/lib/Your/Doodah.pm t/core/lib/Your/Fail.pm t/core/lib/Your/URL.pm t/core/logic.t t/core/mixin.t t/core/modules.t t/core/prototype.t t/core/rainbow.t t/core/test.t t/core/timestamp.t t/core/trace.t t/core/url.t t/core/utils.t t/data/data.t t/data/facets.t t/data/list_facets.t t/data/number.t t/data/simple.t t/data/text.t t/data/text_facets.t t/data/type.t t/filesystem/codec.t t/filesystem/directory.t t/filesystem/encoding.t t/filesystem/file.t t/filesystem/filesystem.t t/filesystem/path.t t/filesystem/testfiles/callsigns t/filesystem/testfiles/dirtest1 t/filesystem/testfiles/dirtest2 t/filesystem/testfiles/newfile t/filesystem/testfiles/utf8_data t/filesystem/testfiles/vdir_four/wibble t/filesystem/testfiles/vdir_four/wobble/hello t/filesystem/testfiles/vdir_one/foo t/filesystem/testfiles/vdir_three/bar t/filesystem/testfiles/vdir_three/baz t/filesystem/testfiles/vdir_three/foo t/filesystem/testfiles/vdir_two/bar t/filesystem/testfiles/vdir_two/foo t/filesystem/testfiles/visitor/large t/filesystem/testfiles/visitor/medium t/filesystem/testfiles/visitor/one/badger t/filesystem/testfiles/visitor/one/mushroom t/filesystem/testfiles/visitor/one/snake t/filesystem/testfiles/visitor/small t/filesystem/testfiles/visitor/tmp/goodbye.html.old t/filesystem/testfiles/visitor/tmp/README t/filesystem/testfiles/visitor/two/goodbye.bak t/filesystem/testfiles/visitor/two/goodbye.html t/filesystem/testfiles/visitor/two/goodbye.txt t/filesystem/testfiles/visitor/two/hello.html t/filesystem/testfiles/visitor/two/hello.txt t/filesystem/universal.t t/filesystem/virtual.t t/filesystem/visitor.t t/log/log.t t/log/logfile.t t/log/reporter.t t/misc/badger.t t/misc/duration.t t/misc/filter.t t/misc/moose.t t/pod/coverage.t t/pod/kwalitee.t t/work/test_files/workplace1/hello.txt t/work/test_files/workspace1/config/greetings.yaml t/work/test_files/workspace1/config/mystuff.yaml t/work/test_files/workspace1/config/workspace.yaml t/work/test_files/workspace1/goodbye.txt t/work/test_files/workspace1/one/foo t/work/test_files/workspace1/two/bar t/work/test_files/workspace2/config/dirs.yaml t/work/test_files/workspace2/config/workspace.yaml t/work/test_files/workspace2/one/foo t/work/test_files/workspace2/three/four/five t/work/test_files/workspace2/two/bar t/work/workplace.t t/work/workspace.t TODO META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Badger-0.16/MYMETA.yml000644 000765 000024 00000001100 14437311027 014251 0ustar00abwstaff000000 000000 --- abstract: 'Application programming toolkit' author: - 'Andy Wardley ' build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 0 generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Badger no_index: directory: - t - inc resources: repository: https://github.com/abw/Badger version: 0.16 x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Badger-0.16/RELEASE000644 000765 000024 00000000446 14360244740 013553 0ustar00abwstaff000000 000000 To release a new version: * Update $VERSION in lib/Badger.pm * Update pod/Badger/Changes.pod * Regenerate Changes: $ pod2text pod/Badger/Changes.pod > Changes * Make distribution $ perl Makefile.PL $ make $ make test $ make dist * Upload to PAUSE * Do the happy badger dance Badger-0.16/t/000755 000765 000024 00000000000 14437311050 013001 5ustar00abwstaff000000 000000 Badger-0.16/README000644 000765 000024 00000022102 14360244740 013421 0ustar00abwstaff000000 000000 NAME Badger - Perl Application Programming Toolkit SYNOPSIS use Badger; # 1) have more fun # 2) get the job done quicker # 3) make your code skimpier # 4) finish work early # 5) go skateboarding # 6) enjoy life DESCRIPTION The Badger toolkit is a collection of Perl modules designed to simplify the process of building object-oriented Perl applications. It provides a set of foundation classes upon which you can quickly build robust and reliable systems that are simple, skimpy and scalable. Badger was hewn from the living rock of the Template Toolkit. It represents all the generic bits of TT that aren't directly related to template processing. They're also the same kind of generic modules that have appeared in pretty much every non-trivial Perl application I've written over the past 10 years or so. So Badger is essentially a restrospective generalisation of what I've learnt over that time about the right way (or more accurately, some of the less wrong ways) to build Perl applications. Badger is designed to be lightweight, fast, and as simple as it can be without being too simple. It offers convenience, convention and consistency in an attempt to improve the Kwalitee of your code and make it more Skimpy™ (which is my artistic interpretation of what Michael Schwern refers to as skimmable code - that is, code that is easy to read and also easy to skim over). Badger isn't just another object system. Although it does include functionality to simplify the process of building objects in Perl 5, that is really just a consequence of the larger goal. That is, to provide a self-contained set of OO modules that work together in a harmonious way to implement a basic platform upon which applications like TT can easily be built. If you want a comprehensive, highly extensible, postmodern object system then Moose should almost certainly be at the top of your list. The parts of Badger that deal with object construction are in some ways similar to the functionality provided by Moose, not to mention various other object toolkits available from CPAN. However, Badger only goes as far as doing what it needs to in terms of object construction in order to get the rest of the job done. That is, providing a set of objects that do useful things. Furthermore, the choice between Badger, Moose, or something else isn't an either-or decision. There are lots of things that Moose does, that Badger doesn't, and vice-versa. If you need a really powerful object system then Moose is probably the way forward. But that doesn't mean you can't use Badger's file handling tools, codecs, and other useful bits and pieces alongside your Moose classes. Metaphorically speaking, Badger and Moose are best friends and they play nicely together. Anyone for tennis? CONTENTS Let's take a quick frolic through the feature list forest to get an idea what Badger is all about. Foundation classes for OO programming Badger includes base classes for creating regular objects (Badger::Base), mixin objects (Badger::Mixin), prototypes/singletons (Badger::Prototype), factory classes (Badger::Factory) and central resource hubs (Badger::Hub). Class Metaprogramming The Badger::Class module employs metaprogramming techniques to simplify the process of defining object classes. It provides methods to automate many of the annoying trivial tasks required to "bootstrap" an object class: specifying base classes, version numbers, exportable symbols, defining constants, loading utility functions from external modules, creating accessor and mutator methods, and so on. There are also methods that simplify the process of accessing class data (e.g. package variables) to save all that mucking about in symbols tables. Some of these methods will also account for inheritance between related classes, making it much easier to share default configuration values between related classed, for example. A key feature of Badger::Class is that it does this by a process of "hygienic class construction". What this means in practice is that your object classes don't get polluted with methods that are only used to construct the class (e.g. a method that constructs accessor methods). Badger::Class can itself be subclassed, allowing you to build your own metaprogramming modules tailored to your particular needs. Error handling and debugging Base classes and mixin modules provide functionality for both hard errors in the form of exception-based error handling and soft errors for declining requests (e.g. to fetch a resource that doesn't exist) that aren't failures but require special handling. Methods for debugging (see Badger::Debug) and raising general warnings are also provided. Generic hooks are provided for receiving notification of, or implementing custom handling for errors, warnings and declines. Running alongside this is a generic message formatting system that allow you to define all error/warning/debug messages in one place where they can easily be localised (e.g. to a different spoken language) or customised (e.g. to generate HTML format instead of plain text). Symbol Exporter Badger implements an object oriented version of the Exporter module in the form of Badger::Exporter. It works correctly with respect to class inheritance (that is, a subclass automatically inherits the exportable symbols from its base classes) and provides a number of additional features to simplify the process of defining exportable symbols and adding custom import hooks. Standard utilities and constants. The Badger::Utils module provides a number of simple utility functions. It also acts as a delegate to various other standard utility modules (Scalar::Util, List::Util, List::MoreUtils, Hash::Util and Digest::MD5). Badger::Constants defines various constants used by the Badger modules and also of general use. Both these modules are designed to be subclassed so that you can create your own collections of utility functions, constants, and so on. Filesystem modules The Badger::Filesystem module and friends provide an object-oriented interface to a filesystem. Files and directories are represented as Badger::Filesystem::File and Badger::Filesystem::Directory objects respectively. As well as being useful for general filesystem manipulation (in this respect, they are very much like the Path::Class modules), the same modules can also be used to represent virtual filesystems via the Badger::Filesystem::Virtual module. This allows you to "mount" a virtual file system under a particular directory (useful when you're dealing with web sites to map page URLs, e.g. /example/page.html, to the source files, e.g. /path/to/example/page.html). You can also create a virtual file system that is a composite of several root directories (if you're familiar with the Template Toolkit then think of the way the "INCLUDE_PATH" works). Codec modules Going hand-in-hand with many basic filesystem operations, the codec modules provide a simple object interface for encoding and decoding data to and from any particular format. The underlying functionality is provided by existing Perl modules (e.g. MIME::Base64, Storable, YAML, etc). The codec modules are wrappers that provide a standard interface to these various different modules. It provides both functional and object oriented interfaces, regardless of how the underlying module works. It also provides the relevant hooks that allow codec objects to be composed into pipeline sequences. Free Badger is Open Source and "free" in both "free beer" and "free speech" senses of the word. It's 100% pure Perl and has no external dependencies on any modules that aren't part of the Perl core. Badger is the base platform for version 3 of the Template Toolkit (coming RSN) and has portability and ease of installation as primary goals. Non-core Badger add-on modules can make as much use of CPAN as they like (something that is usually to be encouraged) but the Badger core will always be dependency-free to keep it upload-to-your-ISP friendly. FURTHER INFORMATION See the documentation included with the Badger modules, starting with Badger.pm. Or look online: http://badgerpower.com/ AUTHOR Andy Wardley abw@wardley.org http://wardley.org/ COPYRIGHT Copyright (C) 1996-2022 Andy Wardley. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. Badger-0.16/TODO000644 000765 000024 00000011255 14360244740 013240 0ustar00abwstaff000000 000000 Badger::Class ------------- * Also think about different debug flags, e.g. DEBUG_THIS, DEBUG_THAT UPDATE: Badger::Debug now does this - just need to hook class in * make debug hook work better: allow import of other items, e.g. debug => ':dump'. Also generate DEBUG constant using any existing value of $DEBUG. * AUTOLOAD method to delegate to real class if possible? * add 'hook' subroutine attribute * add a way for B::C subclasses to register hooks that automatically get called on import, e.g. for B::Factory::Class to push base() * Remove class($class, $target) second argument in export hooks because UBER should now handle that - needs testing UPDATE - no, I think it's still required to make The Right Thing happen. * Make CLASS static. * Change message() to snippet() NOTE - already changed Badger::Base XXX_msg() method to explicitly package-scope message() to Badger::Base so that problem is mitigated. A subclass can now define a message() method and it will still Just Work[tm] Badger::Codec -------------- * encoded()/decoded() methods (e.g. for utf8) * update docs to clarify the fact that utf8, etc., are available as named codecs via Encode/Encoding modules. Badger::Config -------------- * Just a basic implementation at moment. Merge in TT3 config, AppConfig and other stuff. Badger::Class::Config -------------- * Add 'constant' as alias for 'method'. e.g. 'FOO|class:FOO|constant:FOO' Badger::Debug ------------- * See if we can make this a low-level mixin that we can import into Badger::Utils et al. * make debug enabler export :debug and :dump into module Badger::Docs ------------ * Finish writing it / cleaning it up and release. Badger::Exception ----------------- * Do we still want to add a higher-level catch() method? Badger::Factory --------------- * Subclass out into base class (returns loaded module name), object creator, object creator + cache (e.g. for hub), or whatever. * have it bind fetch methods to item/items if undefined, e.g node => item, nodes => items. * support multi-element names, e.g. node.foo.bar Badger::Filesystem ------------------ * directory files/directories/dirs as grep across children * need to handle encoding better in read_file() and write_file() methods. * read-only filesystem option * write_file() should have an option for writing to a temporary file and renaming into place to avoid race conditions. * I'm considering refactoring this. I'd like to unify the different filesystem-specific formats to an underlying URI-based one. It would require a lens (combined parser + presenter) for each O/S. Unix (inc Mac OSX) are simple, Win32 isn't hard. Delegate to File::Spec for everything else. Some info about Win32 path <-> uri translation, snarfed from http://blogs.msdn.com/ie/archive/2006/12/06/file-uris-in-windows.aspx For the UNC Windows file path \\laptop\My Documents\FileSchemeURIs.doc The corresponding valid file URI in Windows is the following: file://laptop/My%20Documents/FileSchemeURIs.doc For the local Windows file path C:\Documents and Settings\davris\FileSchemeURIs.doc The corresponding valid file URI in Windows is: file:///C:/Documents%20and%20Settings/davris/FileSchemeURIs.doc Functions currently used from File::Spec are: catpath, catdir, canonpath, splitpath, splitdir, filename_is_absolute, abs2rel, no_upwards. Most of those can be moved out to lenses. Path manipulation becomes much easier internally when the path can be stored as a list of path nodes. Badger::Log ----------- * Add code to detect Log::Dispatch objects and forward messages. Badger::Storage --------------- * This is available in the git repository but not yet included in the released distribution. * unify parameter parsing and identity definition between filesystem and database storage modules. * get/put which take data / return id * fetch/store which returns * create/destroy connect/disconnect open/close Badger::Test ------------ * Could do with some proper testing. Although all the other test scripts do tend to thrash it quite well... * Change if_env to use Badger::Logic so we can specify things like: if_env => 'RELEASE_TESTING or AUTOMATED_TESTING' Badger::Utils ------------- * hashlike, listlike, numlike BadgerX ------- * add path to any bases missing it * document Longer Terms Goals / Larger Projects ------------------------------------ * incorporate re-write of AppConfig into Badger::Config * consider doing the same with Pod::POM into Badger::Pod and combining with Badger::Docs. (update: doing now) * Finish cleaning Badger-Web and release * Finish refactoring Badger-Database and release Badger-0.16/MYMETA.json000644 000765 000024 00000001645 14437311027 014437 0ustar00abwstaff000000 000000 { "abstract" : "Application programming toolkit", "author" : [ "Andy Wardley " ], "dynamic_config" : 0, "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Badger", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } } }, "release_status" : "stable", "resources" : { "repository" : { "url" : "https://github.com/abw/Badger" } }, "version" : 0.16, "x_serialization_backend" : "JSON::PP version 4.02" } Badger-0.16/META.yml000644 000765 000024 00000001100 14437311050 013777 0ustar00abwstaff000000 000000 --- abstract: 'Application programming toolkit' author: - 'Andy Wardley ' build_requires: ExtUtils::MakeMaker: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Badger no_index: directory: - t - inc resources: repository: https://github.com/abw/Badger version: 0.16 x_serialization_backend: 'CPAN::Meta::YAML version 0.018' Badger-0.16/lib/000755 000765 000024 00000000000 14437311050 013304 5ustar00abwstaff000000 000000 Badger-0.16/Makefile.PL000644 000765 000024 00000001233 14360244740 014515 0ustar00abwstaff000000 000000 use ExtUtils::MakeMaker; my %opts = ( 'NAME' => 'Badger', 'VERSION_FROM' => 'lib/Badger.pm', 'PMLIBDIRS' => [ 'lib' ], 'dist' => { 'COMPRESS' => 'gzip', 'SUFFIX' => 'gz', }, 'test' => { 'TESTS' => join(' ', glob 't/*/*.t'), }, 'META_MERGE' => { 'resources' => { 'repository' => 'https://github.com/abw/Badger', }, }, ); if ($ExtUtils::MakeMaker::VERSION >= 5.43) { $opts{ AUTHOR } = 'Andy Wardley '; $opts{ ABSTRACT } = 'Application programming toolkit', $opts{ LICENSE } = 'perl', } WriteMakefile( %opts ); Badger-0.16/META.json000644 000765 000024 00000001645 14437311050 014165 0ustar00abwstaff000000 000000 { "abstract" : "Application programming toolkit", "author" : [ "Andy Wardley " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.34, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Badger", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } } }, "release_status" : "stable", "resources" : { "repository" : { "url" : "https://github.com/abw/Badger" } }, "version" : 0.16, "x_serialization_backend" : "JSON::PP version 4.02" } Badger-0.16/lib/Badger.pm000644 000765 000024 00000014456 14437310567 015054 0ustar00abwstaff000000 000000 package Badger; use 5.008; use Carp; use lib; use Badger::Hub; use Badger::Class debug => 0, base => 'Badger::Base', import => 'class', words => 'HUB', constants => 'PKG ARRAY DELIMITER', filesystem => 'Bin', exports => { hooks => { lib => [ sub { $_[0]->lib($_[3]) }, 1], }, fail => \&_export_handler, }; our $VERSION = 0.16; our $HUB = 'Badger::Hub::Badger'; our $AUTOLOAD; sub _export_handler { # TODO: we should be able to refactor this down, now that Badger::Exporter # can handle this argument shifting my ($class, $target, $key, $symbols) = @_; croak "You didn't specify a value for the '$key' load option." unless @$symbols; my $module = join(PKG, $class, $key); my $option = shift @$symbols; class($module)->load; $module->export($target, $option); return 1; } sub init { my ($self, $config) = @_; my $hub = $config->{ hub } || $self->class->any_var(HUB); unless (ref $hub) { class($hub)->load; $hub = $hub->new($config); } $self->{ hub } = $hub; return $self; } sub lib { my ($self, $lib) = @_; $lib = [split(DELIMITER, $lib)] unless ref $lib eq ARRAY; foreach (@$lib) { # resolve directories relative to current working directory so that # relative paths Just Work[tm], e.g. ../perl/lib as well as absolute # paths. e.g. /full/path/to/perl/lib my $dir = Bin->dir($_)->must_exist; $self->debug("adding lib: $dir") if DEBUG; lib->import($dir->absolute); } } sub hub { my $self = shift; if (ref $self) { return @_ ? ($self->{ hub } = shift) : $self->{ hub }; } else { return @_ ? $self->class->var(HUB => shift) : $self->class->var(HUB) } } sub codec { shift->hub->codec(@_); } sub config { my $self = shift; return $self->hub->config; } # TODO: AUTOLOAD method which polls hub to see what it supports 1; __END__ =head1 NAME Badger - Perl Application Programming Toolkit =head1 SYNOPSIS use Badger lib => '../lib', # like 'use lib' but relative to $Bin Filesystem => 'File Dir', # import from Badger::Filesystem use Badger Filesystem => 'Dir File', Utils => 'numlike textlike', Constants => 'ARRAY HASH', Codecs => [codec => 'base64']; This is equivalent to: use Badger; use Badger::Filesystem 'Dir File'; use Badger::Utils 'numlike textlike', use Badger::Constants 'ARRAY HASH', use Badger::Codecs codec => 'base64'; =head1 DESCRIPTION The Badger toolkit is a collection of Perl modules designed to simplify the process of building object-oriented Perl applications. It provides a set of I upon which you can quickly build robust and reliable systems that are simple, sexy and scalable. See C for further information. The C module is a front-end to other C modules. You can use it to import any of the exportable items from any other C module. Simply specify the module name, minus the C prefix as a load option. For example: use Badger Filesystem => 'Dir File', Utils => 'numlike textlike', Constants => 'ARRAY HASH', Codecs => [codec => 'base64']; This is equivalent to: use Badger; use Badger::Filesystem 'Dir File'; use Badger::Utils 'numlike textlike', use Badger::Constants 'ARRAY HASH', use Badger::Codecs codec => 'base64'; Note that multiple arguments for a module should be defined as a list reference. use Badger ...etc... Codecs => [codec => 'base64']; This is equivalent to: use Badger::Codecs [codec => 'base64']; Which is also equivalent to: use Badger::Codecs codec => 'base64'; =head1 EXPORT HOOKS The C module can import items from any other C module, as shown in the examples above. The following export hook is also provided. =head2 lib This performs the same task as C in adding a directory to your C<@INC> module include path. However, there are two differences. First, you can specify a directory relative to the directory in which the script exists. use Badger lib => '../perl/lib'; For example, consider a directory layout like this: my_project/ bin/ example_script.pl perl/ lib/ My/ Module.pm t/ my_module.t The F can be written like so: #!/usr/bin/perl use Badger lib => '../perl/lib'; use My::Module; # your code here... This adds F to the include path so that the C module can be correctly located. It is equivalent to the following code using the L module. #!/usr/bin/perl use FindBin '$Bin'; use lib "$Bin/../perl/lib"; use My::Module; =head1 METHODS =head2 hub() Returns a L object. =head2 codec() Delegates to the L L method to return a L object. my $base64 = Badger->codec('base64'); my $encoded = $base64->encode($uncoded); my $decoded = $base64->decode($encoded); =head2 config() Delegates to the L L method to return a L object. This is still experimental. =head1 TODO Other methods like L to access different C modules. These should be generated dynamically on demand. =head1 BUGS Please report bugs or (preferably) send pull requests to merge bug fixes via the github repository: L. =head1 AUTHOR Andy Wardley L. With contributions from Brad Bowman and Michael Grubb, and code, inspiration and insight borrowed from many other module authors. =head1 COPYRIGHT Copyright (C) 1996-2012 Andy Wardley. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L L =cut # Local Variables: # mode: perl # perl-indent-level: 4 # indent-tabs-mode: nil # End: # # vim: expandtab shiftwidth=4: Badger-0.16/lib/Badger/000755 000765 000024 00000000000 14437311050 014470 5ustar00abwstaff000000 000000 Badger-0.16/lib/Badger/Exception.pm000644 000765 000024 00000042017 14360244740 016776 0ustar00abwstaff000000 000000 #======================================================================== # # Badger::Exception # # DESCRIPTION # Module implementing an exception class for reporting structured # errors. # # AUTHOR # Andy Wardley # #======================================================================== package Badger::Exception; use Badger::Class base => 'Badger::Base', version => 0.01, debug => 0, mutators => 'type', accessors => 'stack', constants => 'TRUE ARRAY HASH DELIMITER', import => 'class', as_text => 'text', # overloaded text stringification is_true => 1, # always evaluates to a true value exports => { hooks => { trace => [ # args are ($self, $target, $symbol, $value) sub { $TRACE = $_[3] }, # expects one value argument 1 ], colour => [ # args are ($self, $target, $symbol, $value) sub { $COLOUR = $_[3] }, # expects one value argument 1 ], }, }, messages => { caller => "<4> called from <1>\n in <2> at line <3>", }; use Badger::Rainbow ANSI => 'cyan yellow green'; our $FORMAT = ' error - ' unless defined $FORMAT; our $TYPE = 'undef' unless defined $TYPE; our $INFO = 'no information' unless defined $INFO; our $ANON = 'unknown' unless defined $ANON; our $TRACE = 0 unless defined $TRACE; our $COLOUR = 0 unless defined $COLOUR; sub init { my ($self, $config) = @_; $self->{ type } = $config->{ type } || $self->class->any_var('TYPE'); $self->{ info } = $config->{ info } || ''; $self->{ file } = $config->{ file }; $self->{ line } = $config->{ line }; # watch out for the case where 'trace' is set explicitly to 0 $self->{ trace } = exists $config->{ trace } ? $config->{ trace } : $TRACE; return $self; } sub info { my $self = shift; return @_ ? ($self->{ info } = shift) : ($self->{ info } || $INFO); } sub file { my $self = shift; return @_ ? ($self->{ file } = shift) : ($self->{ file } || $ANON); } sub line { my $self = shift; return @_ ? ($self->{ line } = shift) : ($self->{ line } || $ANON); } sub text { my $self = shift; my $text = shift || $self->class->any_var('FORMAT'); # TODO: extend Badger::Utils::xprintf to handle this $text =~ s/<(\w+)>/defined $self->{ $1 } ? $self->{ $1 } : "(no $1)"/eg; # TODO: not sure we should add file and line automatically - better to # leave it up to the $FORMAT $text .= " in $self->{ file }" if $self->{ file }; $text .= " at line $self->{ line }" if $self->{ line }; if ($self->{ trace } && (my $trace = $self->stack_trace)) { $text .= "\n" . $trace; } return $text; } sub stack_trace { my $self = shift; my @lines; if (my $stack = $self->{ stack }) { foreach my $caller (@$stack) { my @args = $COLOUR ? ( cyan($caller->[0]), cyan($caller->[1]), yellow($caller->[2]), yellow($caller->[3]), ) : @$caller; push(@lines, $self->message( caller => @args )); } } return join("\n", @lines); } sub trace { my $self = shift; if (ref $self) { return @_ ? ($self->{ trace } = shift ) : $self->{ trace }; } else { return @_ ? $self->class->var( TRACE => shift ) : $self->class->var('TRACE'); } } sub throw { my $self = shift; # save relevant information from caller stack for enhanced debugging, # but only the first time the exception is thrown if ($self->{ trace } && ! $self->{ stack }) { my @stack; my $i = 1; while (1) { my @info = caller($i++); last unless @info; push(@stack, \@info); } $self->{ stack } = \@stack; } die $self; } #------------------------------------------------------------------------ # match_type(@types) # # Selects the most appropriate handler for the current exception type, # from the list of types passed in as arguments. The method returns the # item which is an exact match for type or the closest, more # generic handler (e.g. foo being more generic than foo.bar, etc.) #------------------------------------------------------------------------ sub match_type { my $self = shift; my $types = @_ == 1 ? shift : [@_]; my $type = $self->{ type }; $types = [ split(DELIMITER, $types) ] unless ref $types; $types = { map { $_ => $_ } @$types } if ref $types eq ARRAY; return $self->error( invalid => 'type match' => $types ) unless ref $types eq HASH; while ($type) { return $types->{ $type } if $types->{ $type }; # strip .element from the end of the exception type to find a # more generic handler $type =~ s/\.?[^\.]*$//; } return undef; } 1; __END__ =head1 NAME Badger::Exception - structured exception for error handling =head1 SYNOPSIS use Badger::Exception; # create exception object my $exception = Badger::Exception->new({ type => $type, info => $info, }); # query exception type and info fields $type = $exception->type(); $info = $exception->info(); ($type, $info) = $exception->type_info(); # print string summarising exception print $exception->text(); # use automagic stringification print $exception; # throw exception $exception->throw; =head1 DESCRIPTION This module defines an object class for representing exceptions. These are simple objects that store various bits of information about an error condition. The C denotes what kind of error occurred (e.g. 'C', 'C', 'C', etc.). The C field provides further information about the error (e.g. 'C', 'C', 'C', etc). Other optional fields include C and C for specifying the location of the error. In most cases you wouldn't generate and/or throw an exception object directly from your code. A better approach is to define a C method in a base class which does this for you. The L module is an example of just such a module. You can use this as a base class for your modules to inherit the L method. Here's an example of a module that implements a method which expects an argument. If if doesn't get the argument it's looking for then it throws an exception via the inherited L method. The exception type is C and the additional information is C. package Your::Module; use base 'Badger::Base'; sub example_method { my $self = shift; my $arg = shift || self->throw( example => 'No argument specified' ); # ...do something with ... } The L provides a higher level of abstraction. You provide the error message (which becomes the exception C) and it will generate an exception type based on the package name of your module. package Your::Module; use base 'Badger::Base'; sub example_method { my $self = shift; my $arg = shift || self->error('No argument specified' ); # ...do something with ... } In the example above, an exception will be thrown with a C defined as C. The module name is converted to lower case and the package delimiters are replaced with dots. There are configuration options that allow you to define other exceptions types. Consult the L documentation for further information. You can choose any values you like for C and C. The C is used to identify what kind of error occurred and should be a short word like "C", or a dot-separated sequence of words like "C. In the latter case, dotted exception types are assumed to represent a hierarchy where C error is a more specialised kind of C error, which in turn is a more specialised kind of C error. The L method takes this into account when matching exception types. eval { # some code that throws an exception }; if ($@) { if ($@->match_type('example')) { # caught 'example' or 'example.*' error # ...now do something } else { # re-throw any other exception types $@->throw; } } The C field should provide a more detailed error message in a format suitable for human consumption. =head2 STACK TRACING The C module also has a tracing mode which will automatically save the caller stack at the point at which the error is thrown. This allows you to inspect the full code path which led to the error from the comfort of you exception catching code, rather than having to deal with it at the point where the error is throw. # deep in your code somewhere.... in a class derived from Badger::Base $self->throw( database => 'The database is made of cheese', trace => 1, ); The C method (which is called whenever the object is stringified) will then append a stack track to the end of the generated message. # high up in your calling code: eval { $object->do_something_gnarly }; if ($err = $@) { print $err; exit; } You can also call the L method to return the stored call stack information, or the L method to see a textual summary. You can enable the tracing behaviour for all exception objects by setting the C<$TRACE> package variable. use Badger::Exception; $Badger::Exception::TRACE = 1; The L import hook is provided as a short-cut for this. use Badger::Exception trace => 1; =head1 IMPORT HOOKS =head2 trace This import hook can be used to set the C<$TRACE> package variable to enable stack tracing for the L module. use Badger::Exception trace => 1 When stack tracing is enabled, the exception will store information about the calling stack at the point at which it is thrown. This information will be displayed by the L method. It is also available in raw form via the L method. =head1 METHODS =head2 new() Constructor method for creating a new exception. my $exception = Badger::Exception->new( type => 'database', info => 'could not connect', file => '/path/to/file.pm', line => 420, ); =head2 type() When called without arguments, this method returns the exception type, as defined by the first argument passed to the C constructor method. my $type = $exception->type(); It can also be called with an argument to set a new type for the exception. $exception->type('database'); =head2 info() When called without arguments, this method returns the information field for the exception. my $info = $exception->info(); It can also be called with an argument to define new information for the exception. $exception->info('could not connect'); =head2 file() Method to get or set the name of the file in which the exception was raised. $exception->file('path/to/file.pm'); print $exception->file; # /path/to/file.pm =head2 line() Method to get or set the line number at which the exception was raised. $exception->line(420); print $exception->line; # 420 =head2 text() This method returns a text representation of the exception object. The string returned is formatted as C<$type error - $info>. print $exception->text(); # database error - could not connect This method is also bound to the stringification operator, allowing you to simple C the exception object to get the same result as calling C explicitly. print $exception; # database error - could not connect =head2 trace() Method to get or set the flag which determines if the exception captures a stack backtrace at the point at which it is thrown. It can be called as an object method to affect an individual exception object, or as a class method to get or set the C<$TRACE> package variable which provides the default value for any exceptions created from then on. $exception->trace(1); # object method print $exception->trace; # 1 Badger::Exception->trace(1); # class method - sets $TRACE print Badger::Exception->trace; # 1 =head2 match_type() This method selects and returns a type string from the arguments passed that is the nearest correct match for the current exception type. This is used to select the most appropriate handler for the exception. my $match = $exception->match_type('file', 'parser', 'database') || die "no match for exception\n"; In this example, the exception will return one of the values C, C or C, if and only if its type is one of those values. Otherwise it will return undef; Exception types can be organised into a hierarchical structure by delimiting each part of the type with a period. For example, the C exception type might be further divided into the more specific C, C and C exception types. An exception of type C will match a handler type of C or more generally, C. The longer (more specific) handler name will always match in preference to a shorter (more general) handler as shown in the next example: $exception->type('database.connection'); my $match = $exception->match_type('database', 'database.connection') || die "no match for exception\n"; print $match; # database.connection When there is no exact match, the C method will return something more general that matches. In the following example, there is no specific handler type for C, but the more general C type still matches. $exception->type('database.exploded'); my $match = $exception->match_type('database', 'database.connection') || die "no match for exception\n"; print $match; # database You can also specify multiple exception types using a reference to a list. if ($exception->match_type(['warp.drive', 'shields'])) { ... } Or using a single string of whitespace delimited exception types. if ($exception->match_type('warp.drive shields')) { ... } You can also pass a reference to a hash array in which the keys are exception types. The corresponding value for a matching type will be returned. my $type_map = { 'warp.drive' => 'propulsion', 'impulse.drive' => 'propulsion', 'shields' => 'defence', 'phasers' => 'defence' }; if ($exception->match_type($type_map)) { ... } =head2 throw() This method throws the exception by calling C with the exception object as an argument. If the C<$TRACE> flag is set to a true value then the method will first save the pertinent details from a stack backtrace into the exception object before throwing it. =head2 stack() If stack tracing is enabled then this method will return a reference to a list of information from the caller stack at the point at which the exception was thrown. Each item in the list is a reference to a list containing the information returned by the inbuilt C method. See C for further information. use Badger::Exception trace => 1; eval { # some code that throws an exception object $exception->throw(); }; my $catch = $@; # exception object my $stack = $catch->stack; foreach my $caller (@$stack) { my ($pkg, $file, $line, @other_stuff) = @$caller; # do something } The first set of information relates to the immediate caller of the L method. The next item is the caller of that method, and so on. =head2 stack_trace() If stack tracing is enabled then this method returns a text string summarising the caller stack at the point at which the exception was thrown. use Badger::Exception trace => 1; eval { # some code that throws an exception object $exception->throw(); }; if ($@) { print $@->stack_trace; } =head1 AUTHOR Andy Wardley L =head1 COPYRIGHT Copyright (C) 1996-2009 Andy Wardley. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =head1 SEE ALSO L =cut # Local Variables: # mode: perl # perl-indent-level: 4 # indent-tabs-mode: nil # End: # # vim: expandtab shiftwidth=4: Badger-0.16/lib/Badger/Workplace.pm000644 000765 000024 00000010420 14360244740 016760 0ustar00abwstaff000000 000000 package Badger::Workplace; use Badger::Class version => 0.01, debug => 0, base => 'Badger::Base', import => 'class', utils => 'Dir resolve_uri', # resolve_uri truelike falselike params self_params extend', constants => 'SLASH', accessors => 'root urn', alias => { directory => \&dir, }; #----------------------------------------------------------------------------- # Initialisation methods #----------------------------------------------------------------------------- sub init { my ($self, $config) = @_; $self->init_workplace($config); return $self; } sub init_workplace { my ($self, $config) = @_; # The mkdir flag is used to indicate the special case where the root # directory (and perhaps other support files, data, etc) don't yet exist # because some other bit of code is in the process of creating it anew. my $mkdir = $config->{ mkdir } || 0; # The filespec can be specified to provide a hash of options for files my $filespec = $config->{ filespec } || { }; # The root directory must exist unless this is a neophyte in which case # we can create the directory. my $dir = $config->{ root } || $config->{ dir } || $config->{ directory } || return $self->error_msg( missing => 'root directory' ); my $root = Dir($dir, $filespec); if (! $root->exists) { if ($mkdir) { $root->mkdir; } else { return $self->error_msg( invalid => root => $dir ); } } $self->{ root } = $root; $self->{ urn } = $config->{ urn } // $root->name; $self->{ uri } = $config->{ uri } // $self->{ urn }; $self->{ mkdir } = $mkdir; return $self; } #----------------------------------------------------------------------------- # Methods for accessing directories and files relative to the workplace root #----------------------------------------------------------------------------- sub dir { my $self = shift; return @_ ? $self->root->dir(@_) : $self->root; } sub file { my $self = shift; return $self->root->file(@_); } sub uri { my $self = shift; return @_ ? sprintf("%s%s", $self->{ uri }, resolve_uri(SLASH, @_)) : $self->{ uri }; } 1; =head1 NAME Badger::Workplace - a place to do work =head1 DESCRIPTION This is a very simple base class for modules that operate on or around a particular filesystem directory. See L for an example of it in us. =head1 CONFIGURATION OPTIONS =head2 root / dir / directory Any of C, C or C can be provided to specify the root directory of the workplace. =head2 urn This option can be set to define a Universal Resource Name (URN) for the workplace for reference purposes. If undefined it defaults to the name of the root directory. =head2 uri This option can be set to define a Universal Resource Identifier (URN) for the workplace for reference purposes. If undefined it defaults to the name of the value of L. =head2 mkdir The object constructor will fail if the root directory specified via L (or C or C) does not exist. Alternately, set the C option to any true value and the directory will be created automatically. =head1 METHODS =head2 dir($name) / directory($name) Returns a L object for a named sub-directory relative to the workplace root. When called with any arguments it returns a L object for the workplace root directory. =head2 file($name) Returns a L object for a named files relative to the workplace root. =head2 uri($path) When called without any arguments this method returns the base URI for the workspace. print $workspace->uri; # e.g. foo When called with a relative URI path as an argument, it returns the URI resolved relative to the project base URI. print $workspace->uri('bar'); # e.g. foo/bar =head1 AUTHOR Andy Wardley L =head1 COPYRIGHT Copyright (C) 2008-2014 Andy Wardley. All Rights Reserved. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut Badger-0.16/lib/Badger/Mixin.pm000644 000765 000024 00000011433 14360244740 016122 0ustar00abwstaff000000 000000 #======================================================================== # # Badger::Mixin # # DESCRIPTION # Base class for mixins that allow you to "mix in" functionality using # composition rather than inheritance. Similar in concept to roles, # although operating at a slightly lower level. # # AUTHOR # Andy Wardley # #======================================================================== package Badger::Mixin; use Badger::Class version => 3.00, debug => 0, base => 'Badger::Exporter', import => 'class', constants => 'PKG REFS ONCE ARRAY DELIMITER', words => 'EXPORT_TAGS MIXINS'; sub mixin { my $self = shift; my $target = shift || (caller())[0]; my $class = $self->class; my $mixins = $class->list_vars(MIXINS); $self->debug("mixinto($target): ", $self->dump_data($mixins), "\n") if $DEBUG; $self->export($target, $mixins); } sub mixins { my $self = shift; my $syms = @_ == 1 ? shift : [ @_ ]; my $class = $self->class; my $mixins = $class->var_default(MIXINS, [ ]); $syms = [ split(DELIMITER, $syms) ] unless ref $syms eq ARRAY; push(@$mixins, @$syms); $self->export_any($syms); return $mixins; } 1; =head1 NAME Badger::Mixin - base class mixin object =head1 SYNOPSIS The C module is a base class for mixin modules. You can use the L module to declare mixins: package Your::Mixin::Module; use Badger::Class mixins => '$FOO @BAR %BAZ bam'; # some sample data/methods to mixin our $FOO = 'Some random text'; our @BAR = qw( foo bar baz ); our %BAZ = ( hello => 'world' ); sub bam { 'just testing' }; Behind the scenes this adds C as a base class of C and calls the L method to declare what symbols can be mixed into another module. You can write this code manually if you prefer: package Your::Mixin::Module; use base 'Badger::Mixin'; __PACKAGE__->mixins('$FOO @BAR %BAZ bam'); # sample data/methods as before =head1 DESCRIPTION The L module is a base class for mixin modules. Mixins are modules that implement functionality that can be mixed into other modules. This allows you to create modules using composition instead of misuing inheritance. The easiest way to define a mixin module is via the C module. package Your::Mixin::Module; use Badger::Class mixins => '$FOO @BAR %BAZ bam'; This is syntactic sugar for the following code: package Your::Mixin::Module; use base 'Badger::Mixin'; __PACKAGE__->mixins('$FOO @BAR %BAZ bam'); The mixin module declares what symbols it makes available for mixing using the L (plural) method (either indirectly as in the first example, or directly as in the second). The L (singular) method can then be used to mix those symbols into another module. L provides the L hook which you can use: package Your::Other::Module; use Badger::Class mixin => 'Your::Mixin::Module'; Or you can call the L method manually if you prefer. package Your::Other::Module; use Your::Mixin::Module; Your::Mixin::Module->mixin(__PACKAGE__); Mixins are little more than modules with a specialised export mechanism. In fact, the C module uses the L behind the scenes to export the mixin symbols into the target package. Mixins are intentionally simple. If you want to do anything more complicated in terms of exporting symbols then you should use the L module directly instead. =head1 METHODS =head2 mixins($symbols) This method is used to declare what symbols are available for mixing in to other packages. Symbols can be specified as a list of items, a reference to a list of items or as a single whitespace delimited string. package Your::Module; use base 'Badger::Mixin'; # either list of symbols... __PACKAGE__->mixins('$FOO', '@BAR', '%BAZ', 'bam'); # ...or reference to a list __PACKAGE__->mixins(['$FOO', '@BAR', '%BAZ', 'bam']); # ...or single string of whitespace delimited symbols __PACKAGE__->mixins('$FOO @BAR %BAZ bam'); =head2 mixin($package) This method is used to mixin the symbols declared via L into the package specified by the C<$package> argument. Your::Mixin::Module->mixin('My::Module'); =head1 AUTHOR Andy Wardley L =head1 COPYRIGHT Copyright (C) 2005-2009 Andy Wardley. All rights reserved. =head1 SEE ALSO L =cut # Local Variables: # mode: Perl # perl-indent-level: 4 # indent-tabs-mode: nil # End: # # vim: expandtab shiftwidth=4: # TextMate: rocks my world Badger-0.16/lib/Badger/Log.pm000644 000765 000024 00000033345 14360244740 015565 0ustar00abwstaff000000 000000 #======================================================================== # # Badger::Log # # DESCRIPTION # A simple base class logging module. # # AUTHOR # Andy Wardley # #======================================================================== package Badger::Log; use Badger::Class version => 0.01, base => 'Badger::Prototype', import => 'class', utils => 'blessed Now', config => 'system|class:SYSTEM format|class:FORMAT strftime|class:STRFTIME', constants => 'ARRAY CODE', constant => { MSG => '_msg', # suffix for message methods, e.g. warn_msg() LOG => 'log', # method a delegate must implement }, vars => { SYSTEM => 'Badger', FORMAT => '[