File Coverage

blib/lib/Class/Phrasebook/Perl.pm
Criterion Covered Total %
statement 30 38 78.9
branch 10 24 41.6
condition 3 5 60.0
subroutine 5 5 100.0
pod 0 3 0.0
total 48 75 64.0


line stmt bran cond sub pod time code
1             package Class::Phrasebook::Perl;
2              
3 1     1   36431 use warnings;
  1         2  
  1         41  
4 1     1   7 use strict;
  1         2  
  1         984  
5              
6             our $VERSION = '0.01';
7              
8             =head1 NAME
9              
10             Class::Phrasebook::Perl - Implements the Phrasebook pattern, using an all Perl dictionary file.
11              
12             =head1 SYNOPSIS
13              
14             use Class::Phrasebook::Perl;
15              
16             $pb = new Class::Phrasebook::Perl("phrasebook.pl");
17              
18             $pb->load("en");
19             $phrase = $pb->get("hello-world");
20             $phrase = $pb->get("the-hour", hour => "10:30");
21              
22             $pb->load("fr");
23             $phrase = $pb->get("hello-world");
24             $phrase = $pb->get("the-hour", hour => "10h30");
25              
26             =head1 DESCRIPTION
27              
28             This class implements the Phrasebook pattern, which allows us to create dictionaries of phrases. Each phrase is accessed via a unique key and may contain placeholders which are replaced when the phrase is retrieved. Groups of phrases are stored in dictionaries, with the default dictionary being the one that alphabetically occurs first. Phrases are stored in a Perl configuration file, which allows values to be scalars, arrays, hashes or even subroutines.
29              
30             =head1 CONSTRUCTOR
31              
32             $pb = new Class::Phrasebook::Perl($filename, Verbose => 1);
33              
34             The constructor accepts one required parameter, $filename, and a named hash of optional parameters. $filename is the name of the phrasebook configuration file to load and whose format is described below. The optional named hash recognizes the following values:
35              
36             Verbose - Enables debugging messages when set to 1. The default is 0.
37              
38             The constructor returns an instance of a Class::Phrasebook::Perl object upon success, and undef on failure. The default dictionary is set to the one which alphabetically occurs first.
39              
40             =head1 METHODS
41              
42             $pb->load($dictionary);
43              
44             The load method attempts to load the specified dictionary. It will return a true value on success, and false value on failure.
45              
46             $pb->get($phrase, %args);
47              
48             The get method retrieves the specified phrase from the currently loaded dictionary. It accepts an optional named hash of arguments which will be used to replace placeholder values in the phrase. The keys in the %args hash are assumed to be the names of the placeholders in the phrase. Placeholders are denoted by having a '%' in front of their name. For example, if we have the following phrase:
49              
50             "The time now is %hour"
51              
52             and we call the get method as follows:
53              
54             $pb->get('the-hour', hour => "10:30");
55              
56             Then the phrases' '%hour' placeholder will be replaced with the value of the 'hour' key in the named hash, which is "10:30".
57              
58             =head1 CONFIGURATION FILE
59              
60             The configuration file is written in Perl and is read in and eval()'d during object instantiation. The result of the eval() is expected to be a reference to a hash and contains keys which are considered to be the dictionary names. The dictionary keys point to another hash reference, whose keys are considered to be the phrase names and whose values are the phrases. While the term "phrase" may imply that the value is a string. arrays, hashes and subroutines are also allowable.
61              
62             An example configuration file follows:
63              
64             {
65             'en' => { 'hello-world' => 'Hello, World!',
66             'the-hour' => 'The time now is %hour.' }
67              
68             'fr' => { 'hello-world' => 'Bonjour le Monde!!!',
69             'the-hour' => 'Il est maintenant %hour.' }
70             }
71              
72             In this example, the phrasebook contains two dictionaries: 'en' and 'fr', which contain English and French versions of the same phrases, respectively. Each dictionary contains two phrases: 'hello-world' and 'the-hour'. The 'the-hour' phrase contains a placeholder, '%hour', which will be replaced with a supplied value when the phrase is retrieved.
73              
74             The above example contains string-only phrases - it is possible, however, to have arrays, hashes and subroutines as values:
75              
76             {
77             'example' => { 'array' => [ 'biff!', 'bam!', 'chicka-pow!' ],
78             'hash' => { sound => 'bork!', noise => 'bonk!' },
79             'code' => sub { return "ka-plooey!\n" } }
80             }
81              
82             In this example, loading the 'example' dictionary and retrieving the 'array', 'hash' and 'code' phrases would return an array reference, hash reference and a code reference, respectively.
83              
84             $pb->load('example');
85              
86             $array = $pb->get('array');
87             $hash = $pb->get('hash');
88             $code = $pb->get('code');
89              
90             Since place holders don't make much sense in array, hash or code contexts, any replacement values passed in to the get method will be ignored. To retrieve an array or a hash, instead of an array or hash reference, use @{..} and %{..} to force to the appropriate contexts:
91              
92             @array = @{$pb->get('array')};
93             %hash = %{$pb->get('hash')};
94              
95             Code values can be called in the standard fashion, passing it any arguments to the subroutine if applicable:
96              
97             $code->();
98             $code->(1, 'speelunk!', noise => 'whir!');
99              
100             =head1 AUTHOR
101              
102             Cory Spencer
103              
104             =head1 SEE ALSO
105              
106             Class::Phrasebook
107              
108             =head1 COPYRIGHT
109              
110             Copyright (c) 2004 Cory Spencer. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
111              
112             =cut
113              
114             sub new {
115 2     2 0 420 my ($class, $filename, %args) = @_;
116 2         8 my ($self) = bless({ }, $class);
117              
118 2   50     21 $self->{verbose} = $args{Verbose} || 0;
119              
120 2 50       97 if (open(PBOOK, "<$filename")) {
121 2         438 $self->{phrasebook} = eval(join('', ));
122 2         27 close(PBOOK);
123              
124 2 50       8 if ($@) {
125             # eval failed - return a null object.
126 0 0       0 print(STDERR "Error while loading phrasebook: $@\n") if
127             ($self->{verbose});
128 0         0 return undef;
129             }
130              
131 2 50       10 if (ref($self->{phrasebook}) ne "HASH") {
132             # we didn't get the format we were expecting.
133 0 0       0 print(STDERR "Error: phrasebook is not a hash reference\n") if
134             ($self->{verbose});
135 0         0 return undef;
136             }
137             } else {
138             # open failed - return a null object.
139 0 0       0 print(STDERR "Error: open $filename: $!\n") if ($self->{verbose});
140 0         0 return undef;
141             }
142              
143 2         5 $self->{dictionary} = (sort(keys(%{$self->{phrasebook}})))[0];
  2         14  
144              
145 2         8 return $self;
146             }
147              
148             sub load {
149 4     4 0 2018 my ($self, $dict) = @_;
150              
151             # Return an error if the dictionary doesn't exist.
152 4 100       17 if (! exists($self->{phrasebook}->{$dict})) {
153 1 50       5 print(STDERR "Error: dictionary '$dict' not found in phrasebook\n")
154             if ($self->{verbose});
155 1         3 return 0;
156             }
157              
158 3         5 $self->{dictionary} = $dict;
159              
160 3         7 return 1;
161             }
162              
163             sub get {
164 10     10 0 5451 my ($self, $phrase, %args) = @_;
165              
166 10 50       30 if (! defined($self->{dictionary})) {
167 0 0       0 print(STDERR "Error: no dictionary has been selected\n")
168             if ($self->{verbose});
169 0         0 return undef;
170             }
171              
172 10         23 my $value = $self->{phrasebook}->{$self->{dictionary}}->{$phrase};
173              
174 10 100 66     55 if ($value && (! ref($value))) {
175             # Value isn't a hash, array or code - interpolate any necessary values.
176 5 50       44 $value =~ s/%$_/$args{$_} || ''/ge for keys(%args);
  3         22  
177             }
178              
179 10         38 return $value;
180             }
181              
182             1;