perl6 – 使用环境变量构建配置类的更简洁方法?

前端之家收集整理的这篇文章主要介绍了perl6 – 使用环境变量构建配置类的更简洁方法?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个读取环境变量的类Configuration:
class Configuration {
    has $.config_string_a;
    has $.config_string_b;
    has Bool $.config_flag_c;

    method new() {
        sub assertHasEnv(Str $envVar) {
            die "environment variable $envVar must exist" unless %*ENV{$envVar}:exists;
        }

        assertHasEnv('CONFIG_STRING_A');
        assertHasEnv('CONFIG_STRING_B');
        assertHasEnv('CONFIG_FLAG_C');

        return self.bless(
            config_string_a => %*ENV{'CONFIG_STRING_A'},config_string_b => %*ENV{'CONFIG_STRING_B'},config_flag_c => Bool(%*ENV{'CONFIG_FLAG_C'}),);
    }
}

my $config = Configuration.new;

say $config.config_string_a;
say $config.config_string_b;
say $config.config_flag_c;

是否有更简洁的方式来表达这一点?例如,我在检查中重复环境变量名称和构造函数的返回值.

我可以很容易地看到编写另一个更通用的类,它封装了config参数的必要信息:

class ConfigurationParameter {
    has $.name;
    has $.envVarName;
    has Bool $.required;

    method new (:$name,:$envVarName,:$required = True) {
        return self.bless(:$name,:$required);
    }
}

然后将它们滚动到Configuration类中的List中.但是,我不知道如何重构Configuration中的构造函数以适应这种情况.

解决方法

想到的最直接的变化是将新变为:
method new() {
    sub env(Str $envVar) {
        %*ENV{$envVar} // die "environment variable $envVar must exist"
    }

    return self.bless(
        config_string_a => env('CONFIG_STRING_A'),config_string_b => env('CONFIG_STRING_B'),config_flag_c => Bool(env('CONFIG_FLAG_C')),);
}

虽然//是定义检查而不是存在检查,但环境变量未定义的唯一方法是它是否未设置.这可以归结为%* ENV和每个环境变量的提及.

如果只有少数几个,那么我可能会停在那里,但下一个重复的事情让我感到震惊的是,属性的​​名称只是环境变量名称的小写,所以我们也可以消除这种重复.更复杂的成本:

method new() {
    multi env(Str $envVar) {
        $envVar.lc => %*ENV{$envVar} // die "environment variable $envVar must exist"
    }
    multi env(Str $envVar,$type) {
        .key => $type(.value) given env($envVar)
    }

    return self.bless(
        |env('CONFIG_STRING_A'),|env('CONFIG_STRING_B'),|env('CONFIG_FLAG_C',Bool),);
}

现在env返回一对,和|将其展平到参数列表中,就像它是一个命名参数一样.

最后,“电动工具”的方法是在课外写一个这样的特征:

multi trait_mod:<is>(Attribute $attr,:$from-env!) {
    my $env-name = $attr.name.substr(2).uc;
    $attr.set_build(-> | {
        with %*ENV{$env-name} -> $value {
            Any ~~ $attr.type ?? $value !! $attr.type()($value)
        }
        else {
            die "environment variable $env-name must exist"
        }
    });
}

然后把课程写成:

class Configuration {
    has $.config_string_a is from-env;
    has $.config_string_b is from-env;
    has Bool $.config_flag_c is from-env;
}

特征在编译时运行,并且可以以各种方式操纵声明.此特征根据属性名称计算环境变量的名称(属性名称始终类似于$!config_string_a,因此是substr). set_build设置在创建类时将运行以初始化属性代码.在我们的情况下,这会传递各种不重要的东西,所以我们忽略了|的参数. with就像定义一样,所以这与//之前的方法相同.最后,Any ~~ $attr.type检查是否以某种方式约束参数,如果是,则执行强制(通过使用值调用类型来完成).

猜你在找的Perl相关文章