Я пишу неоднократно и переписать следующий вид кода:
my %default = (x => "a", y => "b");
sub new
{
my ($package, $config) = @_;
my $self = {%default};
for my $k (keys %default) {
$self->{$k} = $config->{$k} if defined $config->{$k};
}
for my $k (keys %$config) {
if (! exists $default{$k}) {
carp "Unknown config option $k\n";
}
}
bless $self;
# etc. etc.
}
Прежде чем я сделаю свой собственный модуль, чтобы сделать это, я просто задавался вопросом, существует ли уже что-нибудь на CPAN как этот? Я просто хочу это очень простое выше функциональности, так предложение Американского лося использования не является подходящим ответом на этот вопрос.
Params::Validate может оказать некоторую помощь. Это позволит вам отказаться от хэша %defaults
и указать значения по умолчанию для каждого (возможно, необязательного) параметра.
Кроме того, вы можете сделать это немного менее подробным, используя map
. Конечно, это будет молча игнорировать недопустимые аргументы.
#!/usr/bin/perl
package My::Class;
use strict; use warnings;
my %defaults = ( x => 'a', y => 'b' );
sub new {
my $class = shift;
my ($args) = @_;
my $self = {
%defaults,
map {
exists $args->{$_} ? ($_ => $args->{$_}) : ()
} keys %defaults,
};
return bless $self, $class;
}
package main;
use strict; use warnings;
my $x = My::Class->new({ x => 1, z => 10});
use YAML;
print Dump $x;
Выход:
--- !!perl/hash:My::Class x: 1 y: b
Moose поддерживает значения по умолчанию для атрибутов, например:
has 'foo' => ( is => 'rw', isa => 'Int', default => 42 );
Но если вы не хотите идти по пути Moose, более простой способ достижения того, что вы хотите:
sub new {
my ( $package, %config ) = @_;
my %defaults = ( x => 'a', y => 'b' );
my $self = { %defaults, %config };
# error checking here
return bless $self, $package;
}
Поскольку указание одного и того же хэш-ключа дважды в хэш-инициализации приведет к забитию первого, любые ключи в %config
просто переопределяют ключи в %defaults
.
Если вы уже используете Moose в своих модулях, вы можете получить это поведение, объединив MooseX::Getopt и MooseX::SimpleConfig. Ваш конфигурационный файл может содержать значения по умолчанию, а затем вы переопределяете все, что необходимо, передавая эти значения конструктору:
my $obj = Class->new_with_options(configfile => "myconfig.yaml", key1 => 'val', key2 => 'val');
package Class;
use Moose;
with 'MooseX::Getopt::Strict',
'MooseX::SimpleConfig';
has configfile => (
is => 'ro', isa => 'Str',
traits => ['Getopt'],
documentation => 'File containing default configs',
lazy => 1,
default => sub { File::Spec->catfile($base_dir, 'my_default_config.yaml') },
);
has [ qw(key1 key2) ] => (
is => 'ro', isa => 'Str',
);