Реализация переключателей функций в Perl5

я хотел бы иметь возможность создавать «призрачные» пакеты и подписки. У меня есть файл конфигурации (ini) с такими записями:

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

Этот файл анализируется, и позже разработчики могут задавать такие вопросы, как:

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

(Вся идея основана на FeatureToggle Мартина Фаулера http://martinfowler.com/bliki/FeatureToggle.html)

Используя AUTOLOAD для перехвата вызовов в MyApp::Feature и блок BEGIN для разбора ini-файла, мы можем предоставить этот API:

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

Вопрос в том, можно ли создать следующий API:

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

имея только MyApp::Feature?

Нижний, верхний регистр можно изменить в файле конфигурации, здесь это не проблема. И уточните, реализация отделена от конфигурации, нет никакого MyApp::Feature::User::Login::RSA и никогда не будет. Реализация этой функции лежит напр. в MyApp::Humans.

Я знаю, что размещение MyApp::Feature::Foo::Bar предполагает, что такой Package должен быть. Но разработчики знают соглашение о том, что пакет функций управляет переключением функций, и у них не будет проблем с этим. Я нахожу первый пример (с использованием enabled( $string ) слишком сложным для чтения

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

второй лучше:

if ( package::package->method )

третий будет еще проще:

if ( package::package::package )

Итак, можно ли имитировать АВТОЗАГРУЗКУ на уровне пакета?

Привет, Роб.



person Robert    schedule 14.03.2012    source источник
comment
Дьявол в деталях: MyApp::Feature::User::Login::RSA строго не проходит, это пустое слово. Вы можете сделать последнюю часть вызовом функции, таким образом: MyApp::Feature::User::Login::RSA()   -  person daxim    schedule 15.03.2012


Ответы (1)


Итак, похоже, у вас есть список ключей из нескольких слов, которые вы хотите установить в пространство имен.

BEGIN {
    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
        }
    }
}

BEGIN {
    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

Подпрограммы-константы, установленные здесь, будут встроены Perl, когда это применимо.

Вы можете сделать install_config немного проще в использовании, поместив его в функцию импорта пакета:

BEGIN {$INC{'Install/Config.pm'}++} # 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
)};
person Eric Strom    schedule 15.03.2012