gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 10:22:55 24 4
gpt4 key购买 nike

我有一个类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;

有没有更简洁的表达方式?比如我在check中重复环境变量名和构造函数的返回值。

我可以很容易地看到编写另一个更通用的类,它封装了配置参数的必要信息:
class ConfigurationParameter {
has $.name;
has $.envVarName;
has Bool $.required;

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

然后将这些滚动到 Configuration 中的列表中类(class)。但是,我不知道如何重构 Configuration 中的构造函数以适应这一点。

最佳答案

想到的最直接的改变是改变new成为:

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返回 Pair , 和 |将其展平到参数列表中,就好像它是一个命名参数一样。

最后,“强力工具”方法是在类之外编写这样的特征:
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;
}

Traits 在编译时运行,并且可以以各种方式操作声明。这个特征根据属性名称计算环境变量的名称(属性名称总是像 $!config_string_a ,因此是 substr )。 set_build设置将在创建类时运行以初始化属性的代码。这通过了在我们的情况下不重要的各种事情,所以我们忽略了 | 的参数。 . with就像 if defined ,所以这与 // 的方法相同早些时候。最后, Any ~~ $attr.type check 询问参数是否以某种方式受到约束,如果是,则执行强制转换(通过调用具有值的类型来完成)。

关于raku - 使用环境变量构建配置类的更简洁方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51914754/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com