File Coverage

blib/lib/Bot/Cobalt/Lang.pm
Criterion Covered Total %
statement 65 71 91.5
branch 16 22 72.7
condition 5 7 71.4
subroutine 18 19 94.7
pod 0 1 0.0
total 104 120 86.6


line stmt bran cond sub pod time code
1             package Bot::Cobalt::Lang;
2             $Bot::Cobalt::Lang::VERSION = '0.021003';
3 7     7   57287 use v5.10;
  7         17  
4 7     7   424 use strictures 2;
  7         1132  
  7         207  
5 7     7   1012 use Carp;
  7         9  
  7         328  
6              
7 7     7   429 use Bot::Cobalt::Common qw/:types/;
  7         9  
  7         34  
8 7     7   1571 use Bot::Cobalt::Serializer;
  7         15  
  7         193  
9              
10 7     7   2515 use File::ShareDir 'dist_dir';
  7         22582  
  7         453  
11              
12 7     7   1645 use Types::Path::Tiny -types;
  7         65427  
  7         67  
13 7     7   4431 use Path::Tiny;
  7         9  
  7         283  
14              
15 7     7   26 use Try::Tiny;
  7         10  
  7         257  
16              
17              
18 7     7   27 use Moo;
  7         8  
  7         50  
19              
20             ## Configurable:
21             has lang_dir => (
22             # BUILD dies without me or absolute_path (unless use_core_only => 1)
23             lazy => 1,
24             is => 'ro',
25             isa => Dir,
26             coerce => 1,
27             predicate => 'has_lang_dir',
28             writer => '_set_lang_dir',
29             );
30              
31             has lang => (
32             required => 1,
33             is => 'rwp',
34             isa => Str,
35             );
36              
37             has absolute_path => (
38             # BUILD dies without me or lang_dir (unless use_core_only => 1)
39             lazy => 1,
40             is => 'ro',
41             isa => AbsPath,
42             coerce => 1,
43             predicate => 'has_absolute_path',
44             writer => '_set_absolute_path',
45             );
46              
47             has _full_lang_path => (
48             lazy => 1,
49             is => 'ro',
50             isa => Path,
51             coerce => 1,
52             builder => sub {
53 5     5   1291 my ($self) = @_;
54 5 100       20 return $self->absolute_path if $self->has_absolute_path;
55 4         18 path( $self->lang_dir .'/'. $self->lang .'.yml' )
56             },
57             );
58              
59             has use_core => (
60             is => 'rwp',
61             isa => Bool,
62 5     5   134 builder => sub { 0 },
63             );
64              
65             has use_core_only => (
66             is => 'rwp',
67             isa => Bool,
68 6     6   178 builder => sub { 0 },
69             trigger => sub {
70             my ($self, $val) = @_;
71             $self->_set_use_core(1) if $val
72             },
73             );
74              
75             has _core_set => (
76             lazy => 1,
77             is => 'ro',
78             isa => HashObj,
79             coerce => 1,
80             builder => sub {
81 3     3   1205 my ($self) = @_;
82 3         14 my $cset_path = dist_dir('Bot-Cobalt') .'/etc/langs/english.yml';
83 3         179 my $core_set_yaml = path($cset_path)->slurp_utf8;
84 3 50       434 confess "Failed to read core set at $cset_path"
85             unless $core_set_yaml;
86 3         71 Bot::Cobalt::Serializer->new->thaw($core_set_yaml)
87             },
88             );
89              
90             has rpls => (
91             lazy => 1,
92             is => 'rwp',
93             isa => HashObj,
94             coerce => 1,
95             builder => sub {
96             ## FIXME ? at least cleanups, certainly
97 6     6   1248 my ($self) = @_;
98 6         6 my $rpl_hash;
99              
100             ## Core (built-in) load; shallow copy:
101 6 100       18 $rpl_hash = \%{ $self->_core_set->{RPL} }
  3         20  
102             if $self->use_core;
103              
104 6 100       333 if ( $self->use_core_only ) {
105 1         15 $self->_set_spec( $self->_core_set->{SPEC} );
106 1         30 return $rpl_hash
107             }
108              
109 5         4 my $croakable;
110             my $loaded_set = try {
111 5     5   205 Bot::Cobalt::Serializer->new->readfile( $self->_full_lang_path )
112             } catch {
113             ## croak() by default.
114             ## If this is a core set load, return empty hash.
115 0 0   0   0 if ( !$self->use_core ) {
116 0         0 $croakable = "readfile() failure for " . $self->lang .
117             "(" . $self->_full_lang_path . "): " .
118             $_ ;
119             undef
120 0         0 } else {
121 0         0 carp "Language load failure for ".$self->lang.": $_\n";
122 0         0 +{ RPL => +{} }
123             }
124 5 50       36 } or croak $croakable;
125              
126 5 100       168 if ( $self->use_core ) {
127 2   50     11 my $rev_for_loaded = $loaded_set->{SPEC} // 0;
128 2   50     35 my $rev_for_builtin = $self->_core_set->{SPEC} // 0;
129              
130 2 50       19 if ($rev_for_builtin > $rev_for_loaded) {
131 0         0 warn
132             "Appear to be loading a core language set, but the internal",
133             " set has a higher SPEC number than the loaded set",
134             " ($rev_for_builtin > $rev_for_loaded).\n",
135             " You may want to update language sets.\n" ;
136             }
137              
138             }
139            
140 5         7 my $loaded_rpl_hash = $loaded_set->{RPL};
141              
142 5 50       13 confess "Language set loaded but no RPL hash found"
143             unless ref $loaded_rpl_hash eq 'HASH';
144              
145 5         49 $self->_set_spec( $loaded_set->{SPEC} );
146            
147 5         77 @{$rpl_hash}{ keys(%$loaded_rpl_hash) }
148 5         995 = @{$loaded_set->{RPL}}{ keys(%$loaded_rpl_hash) } ;
  5         34  
149              
150 5         51 $rpl_hash
151             },
152             );
153              
154             has spec => (
155             is => 'rwp',
156             isa => Int,
157 7     7   19932 builder => sub { 0 },
158             );
159              
160              
161             sub BUILD {
162 7     7 0 575 my ($self) = @_;
163 7 100       26 unless ( $self->use_core_only ) {
164 6 100 100     52 die "Need either a lang_dir or an absolute path"
165             unless $self->has_absolute_path or $self->has_lang_dir;
166             }
167             ## Load/validate rpls() at construction time.
168 6         61 $self->rpls;
169             }
170              
171             1;
172              
173             =pod
174              
175             =head1 NAME
176              
177             Bot::Cobalt::Lang - Bot::Cobalt language set loader
178              
179             =head1 SYNOPSIS
180              
181             use Bot::Cobalt::Lang;
182              
183             ## Load 'english.yml' from language dir:
184             my $english = Bot::Cobalt::Lang->new(
185             lang => 'english',
186             lang_dir => $path_to_lang_dir,
187             );
188            
189             ## Access loaded RPL hash:
190             my $str = $english->rpls->{$rpl};
191              
192             ## Fall back to core set:
193             my $language = Bot::Cobalt::Lang->new(
194             use_core => 1,
195             lang => $language,
196             lang_dir => $lang_dir,
197             );
198            
199             ## Use an absolute path:
200             my $language = Bot::Cobalt::Lang->new(
201             lang => "mylangset",
202             absolute_path => $path_to_my_lang_yaml,
203             );
204              
205             ## Load only the core (built-in) set:
206             my $coreset = Bot::Cobalt::Lang->new(
207             lang => 'coreset',
208             use_core_only => 1,
209             );
210              
211             =head1 DESCRIPTION
212              
213             Bot::Cobalt::Lang provides language set loading facilities to
214             L and extensions.
215              
216             This is primarily used by L to feed the core
217             B hash.
218              
219             B requires a 'lang' option and either a 'lang_dir' or
220             'absolute_path' -- if an absolute path is not specified, the named
221             'lang' is (attempted to be) loaded from the specified 'lang_dir' with an
222             extension of ".yml".
223              
224             The 'use_core' option will load the built-in language set.
225             'use_core_only' will not attempt to load anything except the built-in
226             set.
227              
228             If the load fails, an exception is thrown.
229              
230             =head2 rpls
231              
232             The B attribute accesses the loaded RPL
233             L:
234              
235             my $this_str = $language->rpls->get($rpl) // "Missing RPL $rpl";
236              
237             =head2 spec
238              
239             The B attribute returns the SPEC: definition for the loaded
240             language set.
241              
242             =head1 AUTHOR
243              
244             Jon Portnoy
245              
246             =cut