File Coverage

blib/lib/Data/Phrasebook/Loader/YAML.pm
Criterion Covered Total %
statement 58 58 100.0
branch 34 34 100.0
condition 11 12 91.6
subroutine 10 10 100.0
pod 5 5 100.0
total 118 119 99.1


line stmt bran cond sub pod time code
1             package Data::Phrasebook::Loader::YAML;
2              
3 9     9   367425 use strict;
  9         23  
  9         527  
4 9     9   57 use warnings FATAL => 'all';
  9         20  
  9         888  
5              
6             our $VERSION = '0.13';
7              
8             #--------------------------------------------------------------------------
9              
10 9     9   58 use base qw( Data::Phrasebook::Loader::Base Data::Phrasebook::Debug );
  9         29  
  9         10323  
11              
12 9     9   20311 use Carp qw( croak );
  9         22  
  9         418  
13 9     9   9181 use YAML;
  9         111316  
  9         7212  
14              
15             #--------------------------------------------------------------------------
16              
17             =head1 NAME
18              
19             Data::Phrasebook::Loader::YAML - Absract your phrases with YAML.
20              
21             =head1 SYNOPSIS
22              
23             use Data::Phrasebook;
24              
25             my $q = Data::Phrasebook->new(
26             class => 'Fnerk',
27             loader => 'YAML',
28             file => 'phrases.yaml',
29             );
30              
31             $q->delimiters( qr{ \[% \s* (\w+) \s* %\] }x );
32             my $phrase = $q->fetch($keyword);
33              
34             =head1 DESCRIPTION
35              
36             This class loader implements phrasebook patterns using YAML.
37              
38             Phrases can be contained within one or more dictionaries, with each phrase
39             accessible via a unique key. Phrases may contain placeholders, please see
40             L for an explanation of how to use these. Groups of phrases
41             are kept in a dictionary. In this implementation a single file is one
42             complete dictionary.
43              
44             An example YAML file:
45              
46             ---
47             foo: >
48             Welcome to [% my %] world.
49             It is a nice [%place %].
50              
51             Within the phrase text placeholders can be used, which are then replaced with
52             the appropriate values once the get() method is called. The default style of
53             placeholders can be altered using the delimiters() method.
54              
55             =head1 INHERITANCE
56              
57             L inherits from the base class
58             L.
59             See that module for other available methods and documentation.
60              
61             =head1 METHODS
62              
63             =head2 load
64              
65             Given a C, load it. C must contain a YAML map.
66              
67             $loader->load( $file, @dict );
68              
69             This method is used internally by L's
70             C method, to initialise the data store.
71              
72             It must take a C (be it a scalar, or something more complex)
73             and return a handle. The C is optional, should you wish to use the
74             dictionary support.
75              
76             =cut
77              
78             sub load {
79 11     11 1 5479 my ($class, $file, @dict) = @_;
80 11 100       530 croak "No file given as argument!" unless defined $file;
81 9         47 my ($d) = YAML::LoadFile( $file );
82 9 100       133376 croak "Badly formatted YAML file $file" unless ref $d eq 'HASH';
83 8         60 $class->{yaml} = $d;
84              
85             # what sections are we using?
86 8   100     79 my $key = $class->{defaultname} || ($class->dicts)[0];
87 8 100       44 $class->{default} = ($key ? $class->{yaml}->{$key}
88             : $class->{yaml});
89              
90 8         31 $class->{dict} = [];
91 8 100       39 $class->{dict} = [$class->{defaultname}] if $class->{defaultname};
92 8 100       65 $class->{dict} = (ref $dict[0] ? $dict[0] : [@dict]) if scalar @dict;
    100          
93             }
94              
95             =head2 get
96              
97             Returns the phrase stored in the phrasebook, for a given keyword.
98              
99             my $value = $loader->get( $key );
100              
101             If one or more named dictionaries have been previously selected, they will be
102             searched in order, followed by the default dictionary. The first hit on
103             C will be returned, otherwise C is returned.
104              
105             =cut
106              
107             sub get {
108 23     23 1 11183 my ($class,$key) = @_;
109 23 100       77 return unless($key);
110 18 100       67 return unless($class->{yaml});
111              
112 17 100       56 my @dicts = (ref $class->{dict} ? @{$class->{dict}} : ());
  16         40  
113              
114 17         40 foreach ( @dicts ) {
115 12 100 100     89 return $class->{yaml}->{$_}->{$key}
116             if exists $class->{yaml}->{$_}
117             and exists $class->{yaml}->{$_}->{$key};
118             }
119              
120 13 100 100     3166 return $class->{default}->{$key}
121             if ref $class->{default} eq 'HASH'
122             and exists $class->{default}->{$key};
123              
124 8         22 return;
125             }
126              
127             =head2 dicts
128              
129             Returns the list of dictionaries available.
130              
131             my @dicts = $loader->dicts();
132              
133             This is the list of all dictionaries available in the source file. If multiple
134             dictionaries are not being used, then an empty list will be returned.
135              
136             =cut
137              
138             sub dicts {
139 15     15 1 1869 my $class = shift;
140              
141 15         71 my @keys = keys %{$class->{yaml}};
  15         81  
142 15 100       30 if ( scalar @keys ==
  36         106  
143 15         46 scalar grep {ref $_ eq 'HASH'} values %{$class->{yaml}} ) {
144             # data source looks like it has multiple dictionaries
145 11         104 return (sort @keys);
146             }
147              
148 4         69 return ();
149             }
150              
151             =head2 keywords
152              
153             Returns the list of keywords available. List is lexically sorted.
154              
155             my @keywords = $loader->keywords( $dict );
156              
157             If one or more named dictionaries have been previously selected, they will be
158             farmed for keywords, followed by the default dictionary.
159              
160             The C argument is optional, and may be used to override the search to a
161             single named dictionary, or a list of dictionaries if passed by reference,
162             plus the default dictionary of course.
163              
164             To find all available keywords in all available dictionaries, use the
165             following:
166              
167             $loader->keywords( [ $loader->dicts ] );
168              
169             =cut
170              
171             sub keywords {
172 18     18 1 1170 my ($class, $dict) = @_;
173 18         22 my (%keywords, @dicts);
174              
175 18 100       89 @dicts = ( (not $dict) ? (ref $class->{dict} ? @{$class->{dict}} : ())
  6 100       19  
    100          
176             : (ref $dict) ? @$dict : ($dict) );
177              
178 18         41 foreach my $d (@dicts) {
179             next unless
180 23 100 66     149 exists $class->{yaml}->{$d}
181             and ref $class->{yaml}->{$d} eq 'HASH';
182 21         26 map { $keywords{$_} = 1 } keys %{$class->{yaml}->{$d}};
  63         247  
  21         79  
183             }
184              
185 18 100       63 if (ref $class->{default} eq 'HASH') {
186 17         23 map { $keywords{$_} = 1 } keys %{$class->{default}};
  44         86  
  17         48  
187             }
188              
189 18         111 my @keywords = sort keys %keywords;
190 18         176 return @keywords;
191             }
192              
193             =head2 set_default
194              
195             If a requested phrase is not found in the named dictionary an attempt is made
196             to find it in the I dictionary. L loaders normally
197             use the first dictionary in the phrasebook as the default, but as mentioned in
198             L this does not make sense because the dictionaries in
199             YAML phrasebooks are not ordered.
200              
201             To override the automatically selected default dictionary use this method, and
202             pass it a C. This value is only reset at phrasebook
203             load time, so you'll probably need to trigger a reload:
204              
205             $q->loader->set_default( $default_dictionary_name );
206             $q->loader->load( $file );
207              
208             To reset the loader's behaviour to automatic default dictionary selection,
209             pass this method an undefined value, and then reload.
210              
211             =cut
212              
213             sub set_default {
214 2     2 1 950 $_[0]->{defaultname} = $_[1];
215             }
216              
217             1;
218              
219             __END__