package Bot::Cobalt::Lang;
our $VERSION = '0.016002';
use 5.12.1;
use strictures 1;
use Carp;
use Moo;
use Bot::Cobalt::Common qw/:types/;
use Bot::Cobalt::Serializer;
use File::Spec;
use Try::Tiny;
## Configurable:
has 'lang_dir' => (
lazy => 1,
is => 'ro',
isa => Str,
predicate => 'has_lang_dir',
writer => '_set_lang_dir',
);
has 'lang' => (
required => 1,
is => 'rwp',
isa => Str,
);
has 'absolute_path' => (
lazy => 1,
is => 'ro',
isa => Str,
predicate => 'has_absolute_path',
writer => '_set_absolute_path',
);
has 'use_core' => (
is => 'rwp',
isa => Bool,
default => sub { 0 },
);
has 'use_core_only' => (
is => 'rwp',
isa => Bool,
default => sub { 0 },
trigger => sub {
my ($self, $val) = @_;
$self->_set_use_core(1) if $val;
},
);
## Public:
has 'rpls' => (
lazy => 1,
is => 'rwp',
isa => HashRef,
builder => '_build_rpls_hash',
);
has 'spec' => (
is => 'rwp',
isa => Int,
default => sub { 0 },
);
## Private:
has '_full_lang_path' => (
lazy => 1,
is => 'ro',
isa => Str,
builder => '_build_full_lang_path',
);
has '_core_set' => (
lazy => 1,
is => 'ro',
isa => HashRef,
builder => '_build_core_set',
);
sub BUILD {
my ($self) = @_;
unless ( $self->use_core_only ) {
die "Need either a lang_dir or an absolute path"
unless $self->has_absolute_path or $self->has_lang_dir;
}
## Load/validate rpls() at construction time.
$self->rpls;
}
sub _build_full_lang_path {
my ($self) = @_;
return $self->absolute_path if $self->has_absolute_path;
my $file_path = $self->lang . ".yml" ;
File::Spec->catfile(
File::Spec->splitdir($self->lang_dir),
$file_path
)
}
sub _build_core_set {
my ($self) = @_;
my $core_set_yaml =
$Bot::Cobalt::Lang::BUILTIN_SET
//= do { local $/; <DATA> } ;
my $serializer = Bot::Cobalt::Serializer->new;
$serializer->thaw( $core_set_yaml )
}
sub _build_rpls_hash {
my ($self) = @_;
my $rpl_hash;
## Core (built-in) load; shallow copy:
$rpl_hash = \%{ $self->_core_set->{RPL} }
if $self->use_core;
if ( $self->use_core_only ) {
$self->_set_spec( $self->_core_set->{SPEC} );
return $rpl_hash
}
my $serializer = Bot::Cobalt::Serializer->new;
my $croakable;
my $loaded_set = try {
$serializer->readfile( $self->_full_lang_path )
} catch {
## croak() by default.
## If this is a core set load, return empty hash.
if ( !$self->use_core ) {
$croakable = "readfile() failure for ". $self->lang().
"(". $self->_full_lang_path(). "): ".
$_ ;
0
} else {
carp "Language load failure for ".$self->lang.": $_\n";
{ RPL => {} }
}
} or croak $croakable;
if ( $self->use_core ) {
my $rev_for_loaded = $loaded_set->{SPEC} // 0;
my $rev_for_builtin = $self->_core_set->{SPEC} // 0;
if ($rev_for_builtin > $rev_for_loaded) {
warn("Appear to be loading a core language set, but the internal",
" set has a higher SPEC number than the loaded set",
" ($rev_for_builtin > $rev_for_loaded).\n",
" You may want to update language sets.\n",
);
}
}
my $loaded_rpl_hash = $loaded_set->{RPL};
confess "Language set loaded but no RPL hash found"
unless ref $loaded_rpl_hash eq 'HASH';
$self->_set_spec( $loaded_set->{SPEC} );
@{$rpl_hash}{ keys(%$loaded_rpl_hash) }
= @{$loaded_set->{RPL}}{ keys(%$loaded_rpl_hash) } ;
$rpl_hash
}
### this module will have a langset appended at build-time
1;
__DATA__