App-Config-Chronicle
view release on metacpan or search on metacpan
lib/App/Config/Chronicle.pm view on Meta::CPAN
is => 'ro',
isa => 'Str',
default => 'app_settings',
);
has setting_name => (
is => 'ro',
isa => 'Str',
required => 1,
default => 'settings1',
);
=head2 refresh_interval
How much time (in seconds) should pass between L<check_for_update> invocations until
it actually will do (a bit heavy) lookup for settings in redis.
Default value is 10 seconds
=cut
has refresh_interval => (
is => 'ro',
isa => 'Num',
required => 1,
default => 10,
);
has _updated_at => (
is => 'rw',
isa => 'Num',
required => 1,
default => 0,
);
# definitions database
has _defdb => (
is => 'rw',
lazy => 1,
default => sub { LoadFile(shift->definition_yml) },
);
has 'data_set' => (
is => 'ro',
lazy_build => 1,
);
sub _build_class {
my $self = shift;
$self->_create_attributes($self->_defdb, $self);
return;
}
sub _create_attributes {
my $self = shift;
my $definitions = shift;
my $containing_section = shift;
$containing_section->meta->make_mutable;
foreach my $definition_key (keys %{$definitions}) {
$self->_validate_key($definition_key, $containing_section);
my $definition = $definitions->{$definition_key};
if ($definition->{isa} eq 'section') {
$self->_create_section($containing_section, $definition_key, $definition);
$self->_create_attributes($definition->{contains}, $containing_section->$definition_key);
} elsif ($definition->{global}) {
$self->_create_global_attribute($containing_section, $definition_key, $definition);
} else {
$self->_create_generic_attribute($containing_section, $definition_key, $definition);
}
}
$containing_section->meta->make_immutable;
return;
}
sub _create_section {
my $self = shift;
my $section = shift;
my $name = shift;
my $definition = shift;
my $writer = "_$name";
my $path_config = {};
if ($section->isa('App::Config::Chronicle::Attribute::Section')) {
$path_config = {parent_path => $section->path};
}
my $new_section = Moose::Meta::Class->create_anon_class(superclasses => ['App::Config::Chronicle::Attribute::Section'])->new_object(
name => $name,
definition => $definition,
data_set => {},
%$path_config
);
$section->meta->add_attribute(
$name,
is => 'ro',
isa => 'App::Config::Chronicle::Attribute::Section',
writer => $writer,
documentation => $definition->{description},
);
$section->$writer($new_section);
#Force Moose Validation
$section->$name;
return;
}
sub _create_global_attribute {
my $self = shift;
my $section = shift;
my $name = shift;
my $definition = shift;
my $attribute = $self->_add_attribute('App::Config::Chronicle::Attribute::Global', $section, $name, $definition);
$self->_add_dynamic_setting_info($attribute->path, $definition);
return;
}
sub _create_generic_attribute {
my $self = shift;
my $section = shift;
my $name = shift;
my $definition = shift;
$self->_add_attribute('App::Config::Chronicle::Attribute', $section, $name, $definition);
return;
}
sub _add_attribute {
my $self = shift;
my $attr_class = shift;
my $section = shift;
my $name = shift;
my $definition = shift;
my $fake_name = "a_$name";
my $writer = "_$fake_name";
my $attribute = $attr_class->new(
name => $name,
definition => $definition,
parent_path => $section->path,
data_set => $self->data_set,
)->build;
$section->meta->add_attribute(
$fake_name,
is => 'ro',
handles => {
$name => 'value',
'has_' . $name => 'has_value',
},
documentation => $definition->{description},
writer => $writer,
);
$section->$writer($attribute);
return $attribute;
}
sub _validate_key {
my $self = shift;
my $key = shift;
my $section = shift;
if (grep { $key eq $_ } qw(path parent_path name definition version data_set check_for_update save_dynamic refresh_interval)) {
die "Variable with name $key found under "
. $section->path
. ".\n$key is an internally used variable and cannot be reused, please use a different name";
}
return;
}
=head2 check_for_update
check and load updated settings from chronicle db
Checks at most every C<refresh_interval> unless forced with
a truthy first argument
=cut
sub check_for_update {
my ($self, $force) = @_;
return unless $force or $self->_has_refresh_interval_passed();
$self->_updated_at(Time::HiRes::time());
# do check in Redis
my $data_set = $self->data_set;
my $app_settings = $self->chronicle_reader->get($self->setting_namespace, $self->setting_name);
my $db_version;
if ($app_settings and $data_set) {
$db_version = $app_settings->{_rev};
unless ($data_set->{version} and $db_version and $db_version eq $data_set->{version}) {
# refresh all
$self->_add_app_setttings($data_set, $app_settings);
}
}
return $db_version;
}
=head2 save_dynamic
Save dynamic settings into chronicle db
=cut
sub save_dynamic {
my $self = shift;
my ($package, $filename, $line) = caller;
warnings::warnif deprecated => "Deprecated call used (save_dynamic). Called from package: $package | file: $filename | line: $line";
return $self->_save_dynamic();
}
sub _save_dynamic {
my $self = shift;
my $settings = $self->chronicle_reader->get($self->setting_namespace, $self->setting_name) || {};
( run in 1.245 second using v1.01-cache-2.11-cpan-5735350b133 )