line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::MessageLibrary;
|
2
|
|
|
|
|
|
|
$VERSION = "0.15";
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
=head1 NAME
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
Text::MessageLibrary - centrally manage lists of static and dynamic status,
|
7
|
|
|
|
|
|
|
error, or other messages, encapsulated in an object
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# create a list of messages
|
12
|
|
|
|
|
|
|
$error_messages = Text::MessageLibrary->new({
|
13
|
|
|
|
|
|
|
bad_file_format => 'File format not recognized!',
|
14
|
|
|
|
|
|
|
file_open_failed => sub{"Unable to open file $_[0]: $!"},
|
15
|
|
|
|
|
|
|
_default => sub{"Unknown message " . shift() .
|
16
|
|
|
|
|
|
|
" with params " . (join ",",@_)},
|
17
|
|
|
|
|
|
|
});
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# generate messages
|
20
|
|
|
|
|
|
|
print $error_messages->bad_file_format;
|
21
|
|
|
|
|
|
|
print $error_messages->file_open_failed('myfile');
|
22
|
|
|
|
|
|
|
print $error_messages->no_such_message; # falls back to _default
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# override default prefixes and suffixes
|
25
|
|
|
|
|
|
|
$error_messages->set_prefix("myprogram: ");
|
26
|
|
|
|
|
|
|
$error_messages->set_suffix("\n");
|
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head2 Overview
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
With the Text::MessageLibrary class, you can create objects that dynamically
|
33
|
|
|
|
|
|
|
construct status, error, or other messages on behalf of your programs.
|
34
|
|
|
|
|
|
|
Text::MessageLibrary is intended to be useful in larger projects, where it
|
35
|
|
|
|
|
|
|
can be used to create centralized collections of messages that are easier to
|
36
|
|
|
|
|
|
|
maintain and document than string literals scattered throughout the code.
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
To create a Text::MessageLibrary object, you'll need to create a hash containing
|
39
|
|
|
|
|
|
|
a set of keywords and a message associated with each keyword, then pass that
|
40
|
|
|
|
|
|
|
hash to the C constructor. The keywords you choose are then exposed as
|
41
|
|
|
|
|
|
|
methods of an individual Text::MessageLibrary object, so you can generate messages
|
42
|
|
|
|
|
|
|
with this syntax:
|
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
$messages->message_keyword(...with params too, if you want...)
|
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
The messages themselves may be either literal strings or anonymous subroutines
|
47
|
|
|
|
|
|
|
that can perform arbitrarily complex operations. For instance, if you create
|
48
|
|
|
|
|
|
|
an C<$error_messages> object like this:
|
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
$error_messages = Text::MessageLibrary->new({
|
51
|
|
|
|
|
|
|
file_open_failed => sub{"Unable to open file $_[0]: $!\n"}
|
52
|
|
|
|
|
|
|
});
|
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
You can then write this:
|
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
open INPUT, "/no/such/file"
|
57
|
|
|
|
|
|
|
or die $error_messages->file_open_failed('myfile');
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
And get this result:
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
Unable to open file myfile: No such file or directory
|
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
Notice that parameters to the method call are accessible to your subroutine
|
64
|
|
|
|
|
|
|
via C<@_>, and that the global C<$!> variable containing the error message
|
65
|
|
|
|
|
|
|
from the last file operation is available too.
|
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
When you're using static error messages -- i.e., where interpolation at the
|
68
|
|
|
|
|
|
|
moment of message generation is not required -- you can skip the anonymous
|
69
|
|
|
|
|
|
|
subroutine and simply provide a string literal:
|
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
$status_messages = Text::MessageLibrary->new(
|
72
|
|
|
|
|
|
|
new_record => 'loading new record',
|
73
|
|
|
|
|
|
|
all_done => 'processing complete',
|
74
|
|
|
|
|
|
|
);
|
75
|
|
|
|
|
|
|
...
|
76
|
|
|
|
|
|
|
print $status_messages->new_record;
|
77
|
|
|
|
|
|
|
...
|
78
|
|
|
|
|
|
|
print $status_messages->all_done;
|
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
=head2 Prefixes and Suffixes
|
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
Whether you're using static or dynamic messages, there's actually one more
|
83
|
|
|
|
|
|
|
thing that Text::MessageLibrary objects do when constructing messages: They
|
84
|
|
|
|
|
|
|
add a prefix and a suffix. By default, the prefix contains the name of the
|
85
|
|
|
|
|
|
|
current executable (stripped of path information if you're running on a
|
86
|
|
|
|
|
|
|
Windows or Unix variant), and the suffix is simply a newline. So in practice
|
87
|
|
|
|
|
|
|
you'll normally get messages that look more like this:
|
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
YourProgramName: Unable to open file myfile: No such file or directory\n
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
You can change this behavior by calling the C and C
|
92
|
|
|
|
|
|
|
methods:
|
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
$error_messages->set_prefix("Error: ");
|
95
|
|
|
|
|
|
|
$error_messages->set_suffix(".");
|
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
which would result instead in:
|
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
Error: Unable to open file myfile: No such file or directory.
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
The prefix and suffix that you set apply to all messages emitted by an
|
102
|
|
|
|
|
|
|
individual Text::MessageLibrary object. Note that the prefix and suffix are
|
103
|
|
|
|
|
|
|
expected to be fixed strings, not subroutines.
|
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
(Incidentally, you can retrieve the current prefix and suffix by using the
|
106
|
|
|
|
|
|
|
C and C methods, but I can't think of a particularly
|
107
|
|
|
|
|
|
|
compelling reason to actually do that.)
|
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
=head2 Defining Fallback Messages
|
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
What happens if you try to call a method for which no message was defined?
|
112
|
|
|
|
|
|
|
Text::MessageLibrary provides default behavior, so that:
|
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
print $status_messages->no_such_message('nice try', 'dude');
|
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
results in:
|
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
YourProgramName: message no_such_message(nice try,dude)\n
|
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
You can override this behavior by specifying a C<_default> key (and
|
121
|
|
|
|
|
|
|
associated message) in your constructor:
|
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
$error_messages = Text::MessageLibrary->new({
|
124
|
|
|
|
|
|
|
bad_file_format => 'File format not recognized!',
|
125
|
|
|
|
|
|
|
_default => sub{"Unknown message '$_[0]' received"},
|
126
|
|
|
|
|
|
|
});
|
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
With this C<_default> definition, the output would instead be:
|
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
YourProgramName: Unknown message 'no_such_message' received\n
|
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
=head2 Practical Uses
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
If you have a fairly large, multi-module program, you may want to centralize
|
135
|
|
|
|
|
|
|
many of your messages in a single module somewhere. For example:
|
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
package MyMessages;
|
138
|
|
|
|
|
|
|
@ISA = qw(Exporter);
|
139
|
|
|
|
|
|
|
@EXPORT = qw($error_messages $status_messages);
|
140
|
|
|
|
|
|
|
use vars qw($error_messages $status_messages);
|
141
|
|
|
|
|
|
|
use Text::MessageLibrary;
|
142
|
|
|
|
|
|
|
use strict;
|
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
{
|
145
|
|
|
|
|
|
|
my $verbose = 1;
|
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
$error_messages = Text::MessageLibrary->new(
|
148
|
|
|
|
|
|
|
file_open => sub {return qq{file open failed on $_[0]: $!}},
|
149
|
|
|
|
|
|
|
_default => sub {return "unknown error $_[0] reported"},
|
150
|
|
|
|
|
|
|
);
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
$status_messages = Text::MessageLibrary->new(
|
153
|
|
|
|
|
|
|
starting_parser => ($verbose ? "Starting parser\n" : ""),
|
154
|
|
|
|
|
|
|
starting_generator => ($verbose ? sub {"Starting generator $_[0]\n"} : ""),
|
155
|
|
|
|
|
|
|
);
|
156
|
|
|
|
|
|
|
$status_messages->set_prefix();
|
157
|
|
|
|
|
|
|
$status_messages->set_suffix();
|
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
1;
|
160
|
|
|
|
|
|
|
}
|
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
Then your other modules can simply C |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
print $status_messages->starting_parser;
|
165
|
|
|
|
|
|
|
print $status_messages->starting_generator('alpha');
|
166
|
|
|
|
|
|
|
print $status_messages->starting_generator('omega');
|
167
|
|
|
|
|
|
|
print $error_messages->unexpected_end_of_file;
|
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
Since all your messages are located in one module, it's a simple task to
|
170
|
|
|
|
|
|
|
change their wording, control their level of verbosity with a single
|
171
|
|
|
|
|
|
|
statement, and so on. You could also easily change the language of your
|
172
|
|
|
|
|
|
|
messages, though this package is not really intended as a substitute for
|
173
|
|
|
|
|
|
|
a dedicated module such as C.
|
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
Note that the methods generated are unique to each Text::MessageLibrary object,
|
176
|
|
|
|
|
|
|
so that given the definitions above, this statement:
|
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
print $status_messages->file_open('my_file');
|
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
would end up calling the C<_default> message generator for the
|
181
|
|
|
|
|
|
|
C<$status_messages> object. (C was defined only in the constructor
|
182
|
|
|
|
|
|
|
for C<$error_messages>, so no C method exists for
|
183
|
|
|
|
|
|
|
C<$status_messages>.) In effect, the method-call syntax is merely syntactic
|
184
|
|
|
|
|
|
|
sugar for a hypothetical method call like this:
|
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# there's not really a 'generate_message' method...
|
187
|
|
|
|
|
|
|
print $status_messages->generate_message('file_open','my_file');
|
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
On a separate note, if you wish to subclass Text::MessageLibrary, you can override
|
190
|
|
|
|
|
|
|
the default (empty) C<_init> function that the constructor calls and perform
|
191
|
|
|
|
|
|
|
further initialization tasks there.
|
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=head2 Performance Considerations
|
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
Not surprisingly, encapsulating your message generation within an object --
|
196
|
|
|
|
|
|
|
and, sometimes, an anonymous subroutine -- exacts a performance penalty. I've
|
197
|
|
|
|
|
|
|
found in small-scale experiments that the method call and anonymous-subroutine
|
198
|
|
|
|
|
|
|
execution is roughly an order of magnitude slower than using literal strings
|
199
|
|
|
|
|
|
|
and Perl's native interpolation. But it's still I fast in most cases,
|
200
|
|
|
|
|
|
|
and the reduced speed may be an acceptable tradeoff for improved
|
201
|
|
|
|
|
|
|
maintainability, particularly when it comes to things like error messages that
|
202
|
|
|
|
|
|
|
are (we hope!) generated only infrequently.
|
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=head2 Potential Enhancements
|
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
There's currently no way to modify or add messages once you've constructed the
|
207
|
|
|
|
|
|
|
object, nor a clone/copy method, but I haven't yet found a reason to
|
208
|
|
|
|
|
|
|
implement either capability. And Simple Is Beautiful.
|
209
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
=cut
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
############################## CODE STARTS HERE ##############################
|
214
|
|
|
|
|
|
|
|
215
|
1
|
|
|
1
|
|
7486
|
use vars qw($AUTOLOAD);
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
41
|
|
216
|
1
|
|
|
1
|
|
6
|
use strict;
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
32
|
|
217
|
1
|
|
|
1
|
|
4
|
use warnings;
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
32
|
|
218
|
1
|
|
|
1
|
|
4
|
use Carp;
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
770
|
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=head1 PUBLIC METHODS
|
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=over 4
|
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
=item Text::MessageLibrary->new(\%keyword_message_hash);
|
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
Construct a new Text::MessageLibrary object. The C<(key,value)> pairs in
|
228
|
|
|
|
|
|
|
C<%keyword_message_hash> are used to define the methods that the object will
|
229
|
|
|
|
|
|
|
expose and the messages that will be generated when those methods are called.
|
230
|
|
|
|
|
|
|
The keys should be names that would pass muster as Perl subroutine names,
|
231
|
|
|
|
|
|
|
because you'll likely be calling them using the OO arrow syntax:
|
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
$message_library->method_name;
|
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
The values (messages) may be either literal strings or blocks of code to be
|
236
|
|
|
|
|
|
|
interpreted each time the method is invoked. Parameters passed to the method
|
237
|
|
|
|
|
|
|
are accessible to the code block in C<@_> as if it were a normal subroutine.
|
238
|
|
|
|
|
|
|
For example:
|
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
$status_message = Text::MessageLibrary->new(
|
241
|
|
|
|
|
|
|
{general => sub{"You said: $_[0], $_[1], $_[2]."}};
|
242
|
|
|
|
|
|
|
);
|
243
|
|
|
|
|
|
|
print $status_message->general('zero', 'one', 'two');
|
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
results in:
|
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
You said: zero, one, two.
|
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
The key C<_default> has a special significance: It defines a message that is
|
250
|
|
|
|
|
|
|
used if an unknown method is called. In this case, C<$_[0]> contains the name
|
251
|
|
|
|
|
|
|
of the unknown method, and the rest of C<@_> contains the parameters. The
|
252
|
|
|
|
|
|
|
object will provide baseline (one might say 'default') C<_default> behavior
|
253
|
|
|
|
|
|
|
if no such key is explicitly provided in the constructor.
|
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
=cut
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub new {
|
258
|
2
|
|
|
2
|
1
|
98
|
my ($class, @args) = @_;
|
259
|
2
|
|
|
|
|
3
|
my $self = {};
|
260
|
2
|
|
|
|
|
5
|
bless $self, $class;
|
261
|
2
|
|
|
|
|
11
|
$self->_init(@args); # do the real work
|
262
|
2
|
|
|
|
|
4
|
return $self;
|
263
|
|
|
|
|
|
|
}
|
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
=item $messages->set_prefix($new_prefix)
|
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
Set the prefix that is prepended onto any message returned by this object. By
|
269
|
|
|
|
|
|
|
default, the prefix contains the name of the current executable (with path
|
270
|
|
|
|
|
|
|
stripped out if you're running under Windows and *nix OSs).
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
Omitting C<$new_prefix> is equivalent to specifying a null string.
|
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=cut
|
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
sub set_prefix {
|
277
|
3
|
50
|
|
3
|
1
|
10
|
croak "set_prefix expects a single optional param" unless @_ <= 2;
|
278
|
3
|
|
|
|
|
4
|
my ($self, $prefix) = @_;
|
279
|
3
|
100
|
|
|
|
8
|
$prefix = '' unless defined($prefix);
|
280
|
3
|
|
|
|
|
6
|
$self->{prefix} = $prefix;
|
281
|
3
|
|
|
|
|
4
|
return 1;
|
282
|
|
|
|
|
|
|
}
|
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
=item $messages->set_suffix($new_suffix)
|
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
Set the suffix that is appended onto any message returned by this object. By
|
288
|
|
|
|
|
|
|
default, the suffix is a single newline.
|
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
Omitting C<$new_suffix> is equivalent to specifying a null string.
|
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=cut
|
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
sub set_suffix {
|
295
|
3
|
50
|
|
3
|
1
|
9
|
croak "set_suffix expects a single optional param" unless @_ <= 2;
|
296
|
3
|
|
|
|
|
4
|
my ($self, $suffix) = @_;
|
297
|
3
|
50
|
|
|
|
6
|
$suffix = '' unless defined($suffix);
|
298
|
3
|
|
|
|
|
4
|
$self->{suffix} = $suffix;
|
299
|
3
|
|
|
|
|
8
|
return 1;
|
300
|
|
|
|
|
|
|
}
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
=item $messages->get_prefix
|
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
Return the currently defined prefix.
|
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
=cut
|
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
sub get_prefix {
|
310
|
6
|
50
|
|
6
|
1
|
11
|
croak "get_prefix expects no params" unless @_ == 1;
|
311
|
6
|
|
|
|
|
13
|
return $_[0]->{prefix};
|
312
|
|
|
|
|
|
|
}
|
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=item $messages->get_suffix
|
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
Return the currently defined suffix.
|
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=cut
|
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
sub get_suffix {
|
322
|
6
|
50
|
|
6
|
1
|
12
|
croak "get_suffix expects no params" unless @_ == 1;
|
323
|
6
|
|
|
|
|
10
|
return $_[0]->{suffix};
|
324
|
|
|
|
|
|
|
}
|
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=back
|
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=cut
|
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
##### PRIVATE METHODS (AND VARIABLES)
|
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
##### AUTOLOAD
|
333
|
|
|
|
|
|
|
# The AUTOLOAD method is called whenever a Text::MessageLibrary object receives a
|
334
|
|
|
|
|
|
|
# method call to generate a message. It does not cache methods in the symbol
|
335
|
|
|
|
|
|
|
# table for future access, because methods are unique to I
|
336
|
|
|
|
|
|
|
# Text::MessageLibrary objects. (Remember that we're using method calls merely as
|
337
|
|
|
|
|
|
|
# syntactic sugar to make the calling code more readable.)
|
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub AUTOLOAD {
|
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# figure out how we were called
|
342
|
|
|
|
|
|
|
|
343
|
6
|
|
|
6
|
|
165
|
my $self = shift;
|
344
|
6
|
|
|
|
|
21
|
$AUTOLOAD =~ /.*::(\w+)/;
|
345
|
6
|
|
|
|
|
10
|
my $message_name = $1;
|
346
|
6
|
50
|
|
|
|
10
|
return if $message_name eq 'DESTROY';
|
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
# look up the message for this method, or use the default message
|
349
|
|
|
|
|
|
|
|
350
|
6
|
|
|
|
|
14
|
my $message_generator = $self->{messages}->{$message_name};
|
351
|
6
|
100
|
|
|
|
11
|
if (!defined($message_generator)) {
|
352
|
2
|
|
|
|
|
3
|
$message_generator = $self->{messages}->{_default};
|
353
|
2
|
|
|
|
|
9
|
@_ = ($message_name, @_);
|
354
|
|
|
|
|
|
|
}
|
355
|
|
|
|
|
|
|
|
356
|
6
|
|
|
|
|
14
|
my $prefix = $self->get_prefix();
|
357
|
6
|
|
|
|
|
11
|
my $suffix = $self->get_suffix();
|
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
# construct a dynamic message if needed, or simply return a static one
|
360
|
|
|
|
|
|
|
|
361
|
6
|
100
|
|
|
|
14
|
if (ref $message_generator eq 'CODE') {
|
362
|
4
|
|
|
|
|
7
|
return $prefix . (&$message_generator) . $suffix;
|
363
|
|
|
|
|
|
|
} else {
|
364
|
2
|
|
|
|
|
19
|
return $prefix . $message_generator . $suffix;
|
365
|
|
|
|
|
|
|
}
|
366
|
|
|
|
|
|
|
}
|
367
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
##### $messages->_init(@_)
|
370
|
|
|
|
|
|
|
# does the actual initialization.
|
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub _init {
|
373
|
2
|
|
|
2
|
|
3
|
my ($self, @params) = @_;
|
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
# dereference the input hash, or provide an empty hash if none was sent
|
376
|
|
|
|
|
|
|
# and set default values
|
377
|
|
|
|
|
|
|
|
378
|
2
|
50
|
|
|
|
7
|
my %message_hash = defined $_[1] ? %{$_[1]} : ();
|
|
2
|
|
|
|
|
10
|
|
379
|
|
|
|
|
|
|
my %messages = (
|
380
|
|
|
|
|
|
|
_default => sub {
|
381
|
1
|
|
|
1
|
|
9
|
return "message " . $_[0] . "(" . (join ",", @_[1..$#_]) . ")"
|
382
|
|
|
|
|
|
|
},
|
383
|
2
|
|
|
|
|
15
|
%message_hash
|
384
|
|
|
|
|
|
|
);
|
385
|
2
|
|
|
|
|
12
|
$self->{messages} = \%messages;
|
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
# rule of thumb to figure out name of executable (sans path): eliminate
|
388
|
|
|
|
|
|
|
# everything after the last slash (*nix) or backslash (Win)
|
389
|
|
|
|
|
|
|
|
390
|
2
|
|
|
|
|
5
|
my $prefix = $0;
|
391
|
2
|
50
|
33
|
|
|
30
|
if ($^O eq 'MSWin32') {
|
|
|
50
|
33
|
|
|
|
|
392
|
0
|
|
|
|
|
0
|
$0 =~ m{(\\|\A)([^\\]*)$};
|
393
|
0
|
|
|
|
|
0
|
$prefix = $2;
|
394
|
|
|
|
|
|
|
} elsif ($^O ne 'Mac' && $^O ne 'VMS' && $^O ne 'OS2') {
|
395
|
2
|
|
|
|
|
11
|
$0 =~ m{(/|\A)([^/]*)$};
|
396
|
2
|
|
|
|
|
6
|
$prefix = $2;
|
397
|
|
|
|
|
|
|
}
|
398
|
|
|
|
|
|
|
|
399
|
2
|
|
|
|
|
8
|
$self->set_prefix("$prefix: ");
|
400
|
2
|
|
|
|
|
5
|
$self->set_suffix("\n");
|
401
|
|
|
|
|
|
|
}
|
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
##### Internal Data Structure
|
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
# A Text::MessageLibrary is a blessed hash containing the following keys:
|
406
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# A reference to the hash containing message keywords and message text/code
|
408
|
|
|
|
|
|
|
# that was passed into the constructor.
|
409
|
|
|
|
|
|
|
# prefix
|
410
|
|
|
|
|
|
|
# The current prefix, set with C.
|
411
|
|
|
|
|
|
|
# suffix
|
412
|
|
|
|
|
|
|
# The current suffix, set with C.
|
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
1;
|
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
=head1 REVISION HISTORY
|
417
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
0.15 (2002-10-30)
|
419
|
|
|
|
|
|
|
Minor documentation tweaks.
|
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
0.14 (2002-10-29)
|
422
|
|
|
|
|
|
|
Packaged for distribution on CPAN.
|
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
0.13 (2002-10-16)
|
425
|
|
|
|
|
|
|
Minor (mostly cosmetic) updates to documentation, code, and test suite.
|
426
|
|
|
|
|
|
|
Converted to Artistic License.
|
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
0.12 (2002-01-06)
|
429
|
|
|
|
|
|
|
First public beta. Changed constructor to expect hash to be passed by
|
430
|
|
|
|
|
|
|
reference. Split C<_init> out from C.
|
431
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
0.11 (2002-01-05)
|
433
|
|
|
|
|
|
|
Removed method caching (which caused conflicts when instantiating
|
434
|
|
|
|
|
|
|
multiple objects), rationalized code, completed POD.
|
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
0.10 (2001-12-17)
|
437
|
|
|
|
|
|
|
Initial implementation (not released).
|
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
=head1 AUTHOR
|
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
John Clyman (module-support@clyman.com)
|
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE
|
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
Copyright (C) 2002 John Clyman. All Rights Reserved.
|
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
This module is released under the Artistic License (see
|
448
|
|
|
|
|
|
|
http://www.perl.com/language/misc/Artistic.htmlZ<>).
|
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
451
|
|
|
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
452
|
|
|
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
453
|
|
|
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
454
|
|
|
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
455
|
|
|
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
456
|
|
|
|
|
|
|
SOFTWARE.
|
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
=cut
|