Implementing the Toggle Function in Perl5

I would like to be able to create packages "ghost" and subtitles. I have a config file (ini) with items like this:

sys.ext.latex = off
gui.super.duper.elastic = off
user.login.rsa = on


This file is parsed and later, developers can ask questions such as:

if ( MyApp::Feature->enabled ( 'user.login.rsa' ) { ... }


(The whole idea is based on Martin Fowler FeatureToggle )

Using AUTOLOAD to look up calls in MyApp :: Feature and a BEGIN block to parse the ini file, we can provide this API:

if ( MyApp::Feature->user_login_rsa ) { ... }


Question: is it possible to create the following API:

if ( MyApp::Feature::User::Login::RSA ) { ... }


only has MyApp :: Feature?

Below, upper case can be changed in the config file, this is not a problem. And it's clear that implementation is separate from configuration, there is no MyApp :: Feature :: User :: Login :: RSA and never will be. The implementation of this feature is that fe in MyApp :: People.

I am aware that including MyApp :: Feature :: Foo :: Bar presupposes such a package. But developers know the convention that the Feature package manages feature switching, and they would have no problem with that. I find the first example (using the enabled ($ string) bit too tricky to read

if ( package::package->method ( string ) )


the second is better:

if ( package::package->method )


the third will be even easier:

if ( package::package::package )


So, can AUTOLOAD be simulated at the package level?

Hi Rob.


source to share

1 answer

So it looks like you have a list of verbose keys that you want to set to the namespace.

    my %states = ( # the values that should be transformed
        on  => sub () {1},
        off => sub () {''},
    sub install_config {
        my ($package, $config) = @_;
        for my $key (keys %$config) {
            my @parts = map ucfirst, split /\./, $key;
            my $name  = join '::' => $package, @parts;
            no strict 'refs';
            *{$name} = $states{$$config{$key}} # use a tranformed value
                    || sub () {$$config{$key}} # or the value itself

    my %config = qw(
        sys.ext.latex            off
        gui.super.duper.elastic  off
        user.login.rsa           on
        some.other.config        other_value
    install_config 'MyApp::Feature' => \%config;

say MyApp::Feature::Sys::Ext::Latex ? 'ON' : 'OFF';             # OFF
say MyApp::Feature::Gui::Super::Duper::Elastic ? 'ON' : 'OFF';  # OFF
say MyApp::Feature::User::Login::Rsa ? 'ON' : 'OFF';            # ON
say MyApp::Feature::Some::Other::Config;                        # other_value


The persistent routines set here will be bound by perl when applicable.

You can make it a install_config

little easier to use by putting it in the package import function:

BEGIN {$INC{'Install/'}++} # fool require

sub Install::Config::import {shift; goto &install_config}

use Install::Config 'MyApp::Feature' => {qw(
    sys.ext.latex            off
    gui.super.duper.elastic  off
    user.login.rsa           on
    some.other.config        other_value




All Articles