{
    "content": [
        {
            "type": "text",
            "text": "# Sub::Exporter::Cookbook (perldoc)\n\n## NAME\n\nSub::Exporter::Cookbook - useful, demonstrative, or stupid Sub::Exporter tricks\n\n## Sections\n\n- **NAME**\n- **VERSION**\n- **OVERVIEW**\n- **PERL VERSION SUPPORT**\n- **THE RECIPES** (5 subsections)\n- **AUTHOR**\n- **COPYRIGHT AND LICENSE**\n\nUse structuredContent.sections for detailed options, examples, and full documentation.\n"
        }
    ],
    "structuredContent": {
        "command": "Sub::Exporter::Cookbook",
        "section": "",
        "mode": "perldoc",
        "summary": "Sub::Exporter::Cookbook - useful, demonstrative, or stupid Sub::Exporter tricks",
        "synopsis": null,
        "tldr_summary": null,
        "tldr_examples": [],
        "tldr_source": null,
        "flags": [],
        "examples": [],
        "see_also": [],
        "section_outline": [
            {
                "name": "NAME",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "VERSION",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "OVERVIEW",
                "lines": 6,
                "subsections": []
            },
            {
                "name": "PERL VERSION SUPPORT",
                "lines": 7,
                "subsections": []
            },
            {
                "name": "THE RECIPES",
                "lines": 1,
                "subsections": [
                    {
                        "name": "Exporting Methods as Routines",
                        "lines": 45
                    },
                    {
                        "name": "Exporting Methods as Methods",
                        "lines": 46
                    },
                    {
                        "name": "Mixing-in Complex External Behavior",
                        "lines": 37
                    },
                    {
                        "name": "Exporting Constants",
                        "lines": 77
                    },
                    {
                        "name": "Eating Exporter.pm's Brain",
                        "lines": 45
                    }
                ]
            },
            {
                "name": "AUTHOR",
                "lines": 2,
                "subsections": []
            },
            {
                "name": "COPYRIGHT AND LICENSE",
                "lines": 5,
                "subsections": []
            }
        ],
        "sections": {
            "NAME": {
                "content": "Sub::Exporter::Cookbook - useful, demonstrative, or stupid Sub::Exporter tricks\n",
                "subsections": []
            },
            "VERSION": {
                "content": "version 0.988\n",
                "subsections": []
            },
            "OVERVIEW": {
                "content": "Sub::Exporter is a fairly simple tool, and can be used to achieve some very simple goals. Its\nbasic behaviors and their basic application (that is, \"traditional\" exporting of routines) are\ndescribed in Sub::Exporter::Tutorial and Sub::Exporter. This document presents applications that\nmay not be immediately obvious, or that can demonstrate how certain features can be put to use\n(for good or evil).\n",
                "subsections": []
            },
            "PERL VERSION SUPPORT": {
                "content": "This module has a long-term perl support period. That means it will not require a version of\nperl released fewer than five years ago.\n\nAlthough it may work on older versions of perl, no guarantee is made that the minimum required\nversion will not be increased. The version may be increased for any reason, and there is no\npromise that patches will be accepted to lower the minimum required perl.\n",
                "subsections": []
            },
            "THE RECIPES": {
                "content": "",
                "subsections": [
                    {
                        "name": "Exporting Methods as Routines",
                        "content": "With Exporter.pm, exporting methods is a non-starter. Sub::Exporter makes it simple. By using\nthe \"currymethod\" utility provided in Sub::Exporter::Util, a method can be exported with the\ninvocant built in.\n\npackage Object::Strenuous;\n\nuse Sub::Exporter::Util 'currymethod';\nuse Sub::Exporter -setup => {\nexports => [ objection => currymethod('new') ],\n};\n\nWith this configuration, the importing code may contain:\n\nmy $obj = objection(\"irrelevant\");\n\n...and this will be equivalent to:\n\nmy $obj = Object::Strenuous->new(\"irrelevant\");\n\nThe built-in invocant is determined by the invocant for the \"import\" method. That means that if\nwe were to subclass Object::Strenuous as follows:\n\npackage Object::Strenuous::Repeated;\n@ISA = 'Object::Strenuous';\n\n...then importing \"objection\" from the subclass would build-in that subclass.\n\nFinally, since the invocant can be an object, you can write something like this:\n\npackage Cypher;\nuse Sub::Exporter::Util 'currymethod';\nuse Sub::Exporter -setup => {\nexports => [ encypher => currymethod ],\n};\n\nwith the expectation that \"import\" will be called on an instantiated Cypher object:\n\nBEGIN {\nmy $cypher = Cypher->new( ... );\n$cypher->import('encypher');\n}\n\nNow there is a globally-available \"encypher\" routine which calls the encypher method on an\notherwise unavailable Cypher object.\n"
                    },
                    {
                        "name": "Exporting Methods as Methods",
                        "content": "While exporting modules usually export subroutines to be called as subroutines, it's easy to use\nSub::Exporter to export subroutines meant to be called as methods on the importing package or\nits objects.\n\nHere's a trivial (and naive) example:\n\npackage Mixin::DumpObj;\n\nuse Data::Dumper;\n\nuse Sub::Exporter -setup => {\nexports => [ qw(dump) ]\n};\n\nsub dump {\nmy ($self) = @;\nreturn Dumper($self);\n}\n\nWhen writing your own object class, you can then import \"dump\" to be used as a method, called\nlike so:\n\n$object->dump;\n\nBy assuming that the importing class will provide a certain interface, a method-exporting module\ncan be used as a simple plugin:\n\npackage Number::Plugin::Upto;\nuse Sub::Exporter -setup => {\ninto    => 'Number',\nexports => [ qw(upto) ],\ngroups  => [ default => [ qw(upto) ] ],\n};\n\nsub upto {\nmy ($self) = @;\nreturn 1 .. abs($self->asinteger);\n}\n\nThe \"into\" line in the configuration says that this plugin will export, by default, into the\nNumber package, not into the \"use\"-ing package. It can be exported anyway, though, and will work\nas long as the destination provides an \"asinteger\" method like the one it expects. To import it\nto a different destination, one can just write:\n\nuse Number::Plugin::Upto { into => 'Quantity' };\n"
                    },
                    {
                        "name": "Mixing-in Complex External Behavior",
                        "content": "When exporting methods to be used as methods (see above), one very powerful option is to export\nmethods that are generated routines that maintain an enclosed reference to the exporting module.\nThis allows a user to import a single method which is implemented in terms of a complete,\nwell-structured package.\n\nHere is a very small example:\n\npackage Data::Analyzer;\n\nuse Sub::Exporter -setup => {\nexports => [ analyze => \\'generateanalyzer' ],\n};\n\nsub generateanalyzer {\nmy ($mixin, $name, $arg, $col) = @;\n\nreturn sub {\nmy ($self) = @;\n\nmy $values = [ $self->values ];\n\nmy $analyzer = $mixin->new($values);\n$analyzer->performanalysis;\n$analyzer->aggregateresults;\n\nreturn $analyzer->summary;\n};\n}\n\nIf imported by any package providing a \"values\" method, this plugin will provide a single\n\"analyze\" method that acts as a simple interface to a more complex set of behaviors.\n\nEven more importantly, because the $mixin value will be the invocant on which the \"import\" was\nactually called, one can subclass \"Data::Analyzer\" and replace only individual pieces of the\ncomplex behavior, making it easy to write complex, subclassable toolkits with simple single\npoints of entry for external interfaces.\n"
                    },
                    {
                        "name": "Exporting Constants",
                        "content": "While Sub::Exporter isn't in the constant-exporting business, it's easy to export constants by\nusing one of its sister modules, Package::Generator.\n\npackage Important::Constants;\n\nuse Sub::Exporter -setup => {\ncollectors => [ constants => \\'setconstants' ],\n};\n\nsub setconstants {\nmy ($class, $value, $data) = @;\n\nPackage::Generator->assignsymbols(\n$data->{into},\n[\nMEANINGOFLIFE => \\42,\nONETRUEBASE   => \\13,\nFACTORS         => [ 6, 9 ],\n],\n);\n\nreturn 1;\n}\n\nThen, someone can write:\n\nuse Important::Constants 'constants';\n\nprint \"The factors @FACTORS produce $MEANINGOFLIFE in $ONETRUEBASE.\";\n\n(The constants must be exported via a collector, because they are effectively altering the\nimporting class in a way other than installing subroutines.)\n\nAltering the Importer's @ISA\nIt's trivial to make a collector that changes the inheritance of an importing package:\n\nuse Sub::Exporter -setup => {\ncollectors => { -base => \\'makebase' },\n};\n\nsub makebase {\nmy ($class, $value, $data) = @;\n\nmy $target = $data->{into};\npush @{\"$target\\::ISA\"}, $class;\n}\n\nThen, the user of your class can write:\n\nuse Some::Class -base;\n\nand become a subclass. This can be quite useful in building, for example, a module that helps\nbuild plugins. We may want a few utilities imported, but we also want to inherit behavior from\nsome base plugin class;\n\npackage Framework::Util;\n\nuse Sub::Exporter -setup => {\nexports    => [ qw(log globalconfig) ],\ngroups     => [ plugin => [ qw(log globalconfig) ]\ncollectors => { '-plugin' => \\'becomeplugin' },\n};\n\nsub becomeplugin {\nmy ($class, $value, $data) = @;\n\nmy $target = $data->{into};\npush @{\"$target\\::ISA\"}, $class->pluginbaseclass;\n\npush @{ $data->{importargs} }, '-plugin';\n}\n\nNow, you can write a plugin like this:\n\npackage Framework::Plugin::AirFreshener;\nuse Framework::Util -plugin;\n"
                    },
                    {
                        "name": "Eating Exporter.pm's Brain",
                        "content": "You probably shouldn't actually do this in production. It's offered more as a demonstration than\na suggestion.\n\nsub exporterupgrade {\nmy ($pkg) = @;\nmy $newpkg = \"$pkg\\::UsingSubExporter\";\n\nreturn $newpkg if $newpkg->isa($pkg);\n\nSub::Exporter::setupexporter({\nas      => 'import',\ninto    => $newpkg,\nexports => [ @{\"$pkg\\::EXPORTOK\"} ],\ngroups  => {\n%{\"$pkg\\::EXPORTTAG\"},\ndefault => [ @{\"$pkg\\::EXPORTS\"} ],\n},\n});\n\n@{\"$newpkg\\::ISA\"} = $pkg;\nreturn $newpkg;\n}\n\nThis routine, given the name of an existing package configured to use Exporter.pm, returns the\nname of a new package with a Sub::Exporter-powered \"import\" routine. This lets you import\n\"Toolkit::exportedsub\" into the current package with the name \"foo\" by writing:\n\nBEGIN {\nrequire Toolkit;\nexporterupgrade('Toolkit')->import(exportedsub => { -as => 'foo' })\n}\n\nIf you're feeling particularly naughty, this routine could have been declared in the UNIVERSAL\npackage, meaning you could write:\n\nBEGIN {\nrequire Toolkit;\nToolkit->exporterupgrade->import(exportedsub => { -as => 'foo' })\n}\n\nThe new package will have all the same exporter configuration as the original, but will support\nexport and group renaming, including exporting into scalar references. Further, since\nSub::Exporter uses \"can\" to find the routine being exported, the new package may be subclassed\nand some of its exports replaced.\n"
                    }
                ]
            },
            "AUTHOR": {
                "content": "Ricardo Signes <rjbs@semiotic.systems>\n",
                "subsections": []
            },
            "COPYRIGHT AND LICENSE": {
                "content": "This software is copyright (c) 2007 by Ricardo Signes.\n\nThis is free software; you can redistribute it and/or modify it under the same terms as the Perl\n5 programming language system itself.\n",
                "subsections": []
            }
        }
    }
}