File Coverage

blib/lib/Locale/MakePhrase/Print.pm
Criterion Covered Total %
statement 57 92 61.9
branch 12 46 26.0
condition 0 21 0.0
subroutine 14 21 66.6
pod 0 5 0.0
total 83 185 44.8


line stmt bran cond sub pod time code
1             package Locale::MakePhrase::Print;
2             our $VERSION = 0.1;
3             our $DEBUG = 0;
4              
5             =head1 NAME
6              
7             Locale::MakePhrase::Print - Overload of C to automate translations
8              
9             =head1 SYNOPSIS
10              
11             Using this module, it will override C statements so that your
12             application automatically gets translated into the target language.
13              
14             Example:
15              
16             Your application will have previously instantiated a L
17             object in some other module. Now you need to use that instantiation
18             within a particular module; from here:
19              
20             use Locale::MakePhrase::Print;
21             ...
22             print "Some text to be translated.";
23              
24             When C is called, the text is automatically fed into the
25             translation engine.
26              
27             =head1 DESCRIPTION
28              
29             The purpose of this module, is to de-couple the use of the translation
30             engine, from the API of the translation engine. This saves you from
31             littering your application code with translation-specific function
32             calls. The main benefits are:
33              
34             =over 2
35              
36             =item *
37              
38             makes the code easier to read
39              
40             =item *
41              
42             allows you to easily change to a different translation engine
43              
44             =item *
45              
46             decouples translation from application design
47              
48             =back
49              
50             =head1 API
51              
52             To use this module, you simply need to C it at the top of your
53             own module. You can optionally specify a specific filehandle to print
54             to (rather than STDOUT), eg:
55              
56             use Locale::MakePhrase::Print;
57             ...
58             print "Some text";
59              
60             or
61              
62             open(FH,">some_output_file.txt") or die;
63             use Locale::MakePhrase::Print \*FH;
64             ...
65             print "Some text";
66              
67             Will print B to STDOUT or the specified filehandle.
68              
69             To stop overriding C:
70              
71             no Locale::MakePhrase::Print;
72              
73             =cut
74              
75 1     1   910 use strict;
  1         1  
  1         52  
76 1     1   5 use warnings;
  1         2  
  1         35  
77 1     1   5 use utf8;
  1         3  
  1         7  
78 1     1   1167 use Symbol;
  1         1065  
  1         81  
79 1     1   6 use Exporter;
  1         2  
  1         37  
80 1     1   5 use base qw(Exporter);
  1         2  
  1         82  
81 1     1   5 use Locale::MakePhrase::Utils qw(die_from_caller);
  1         1  
  1         1918  
82             our $STDOUT;
83             our $filehandle;
84             our $print = 1;
85             our $println = 1;
86             our $this;
87              
88             #
89             # Install a println handler to handle println'ing to a filehandle
90             #
91             sub IO::Handle::println {
92 0     0 0 0 my $FH = shift;
93 0         0 print $FH (@_,$/);
94             }
95              
96             #
97             # Install a println handler to handle println'ing to a stdout
98             #
99             sub main::println {
100 0     0   0 CORE::print (@_,$/);
101             }
102              
103             #
104             # Handle use/no options
105             #
106             sub get_options {
107 0     0 0 0 my $func = shift;
108 0         0 my $options = shift;
109 0 0       0 $options = {} unless (defined $options);
110 0 0 0     0 if (@_ > 1 and not(@_ % 2)) {
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
      0        
111 0         0 %$options = @_;
112             } elsif (@_ == 1 and ref($_[0]) eq "HASH") {
113 0         0 %$options = %{$_[0]};
  0         0  
114             } elsif (@_ == 1 and ref($_[0]) eq "GLOB") {
115 0         0 $options->{filehandle} = shift;
116             } elsif (@_ == 1 and ref($_[0]) eq "" and $_[0] eq "print") {
117 0         0 $options->{print} = 1;
118             } elsif (@_ == 1 and ref($_[0]) eq "" and $_[0] eq "println") {
119 0         0 $options->{println} = 1;
120             } elsif (@_ > 0) {
121 0         0 die_from_caller "Unknown arguments to '$func ".__PACKAGE__." ...;' call";
122             }
123 0 0       0 $print = (exists $options->{print}) ? ($options->{print} ? 1 : 0) : $print;
    0          
124 0 0       0 $println = (exists $options->{println}) ? ($options->{println} ? 1 : 0) : $println;
    0          
125             }
126              
127             #
128             # On module import we override printing to STDOUT, by overriding
129             # the 'print' function, so that translations become automatic. We
130             # also export the translation-engine-enabled 'println' function.
131             #
132             sub import {
133 1     1   6 my $class = shift;
134 1         3 my $caller = caller;
135 1         4 my $sym = gensym;
136 1 50       18 $STDOUT = select unless (defined $STDOUT);
137              
138 1         1 my %options;
139 1 50       4 get_options('use',\%options,@_) if @_;
140 1 50       3 $filehandle = (exists $options{filehandle}) ? $options{filehandle} : (defined $filehandle ? $filehandle : $STDOUT);
    50          
141 1 50       3 die "Invalid filehandle specification" unless (defined $filehandle);
142              
143 1         7 $this = tie *$sym, $class, $filehandle;
144 1         3 bless $sym, $class;
145              
146             # Override 'print'
147 1 50       5 if ($print) {
148 0         0 select $sym;
149             }
150              
151             # Override 'println'
152 1 50       3 if ($println) {
153 1     1   6 no strict 'refs';
  1         3  
  1         133  
154 0         0 *{$caller."::println"} = \&{$class."::LM_println"};
  0         0  
  0         0  
155             }
156              
157 1         47 return $class;
158             }
159              
160             #
161             # On module unimport we reset printing to STDOUT so that it
162             # goes back to Perl's default behaviour. We also reset the exported
163             # 'println' function so as to not be bound to the translation-engine.
164             #
165             sub unimport {
166 1     1   9 my $class = shift;
167 1         2 my $caller = caller;
168 1 50       4 get_options('no',undef,@_) if @_;
169              
170             # Reset 'print'
171 1 50       3 if ($print) {
172 0         0 select $STDOUT;
173             }
174              
175             # Reset 'println'
176 1 50       2 if ($println) {
177 1     1   4 no strict 'refs';
  1         1  
  1         263  
178 0         0 *{$caller."::println"} = \&{$class."::CORE_println"};
  0         0  
  0         0  
179             }
180              
181 1         1684 return $class;
182             }
183              
184             #
185             # Automatically called when the module is imported due to overriding
186             # the import() sub.
187             #
188             sub TIEHANDLE {
189 1     1   2 my $class = shift;
190 1         3 my $self = bless {}, $class;
191 1 50       3 if (@_ > 0) {
192 1 50       9 $self->{fh} = shift or die "No filehandle specified in constructor.";
193             } else {
194 0         0 $self->{fh} = select;
195             }
196 1         4 return $self;
197             }
198              
199             #
200             # Install the appropriate mp() function to point to the correct
201             # implementation, based on debugging settings.
202             #
203             local *mp;
204             if ($DEBUG > 5) {
205             *mp = sub { __PACKAGE__.": ",@_ };
206             } else {
207             *mp = \&Locale::MakePhrase::mp;
208             }
209              
210             #
211             # Implement custom 'print' behaviour
212             #
213             sub PRINT {
214 0     0     my $self = shift;
215 0           my $fh = *{ $self->{fh} };
  0            
216 0           CORE::print $fh (mp(@_));
217             }
218              
219             #
220             # Implement custom 'println' behaviour
221             #
222             sub PRINTLN {
223 0     0 0   my $self = shift;
224 0           my $fh = *{ $self->{fh} };
  0            
225 0           CORE::print $fh (mp(@_).$/);
226             }
227              
228             #
229             # Setup object->method signatures
230             #
231 1     1   4 no warnings 'once';
  1         1  
  1         65  
232             *new = *TIEHANDLE;
233             *print = *PRINT;
234             *println = *PRINTLN;
235 1     1   5 use warnings 'once';
  1         17  
  1         130  
236              
237             #--------------------------------------------------------------------------
238              
239             #
240             # Implement generic 'println' behaviour
241             #
242             sub CORE_println {
243 0     0 0   CORE::print $STDOUT @_,$/;
244             }
245              
246             #
247             # Implement custom 'println' behaviour
248             #
249             sub LM_println {
250 0     0 0   PRINTLN $this, @_;
251             }
252              
253             =head2 println "..." [, ...]
254              
255             This function is explicatly exported so that users can avoid having
256             to specify the newline character in the translation key.
257              
258             Note: when C is in effect, C
259             simply prints out the un-translated string, including a the newline.
260              
261             =cut
262              
263             #
264             # 'println' is dyamically linked into the symbol table, based on the
265             # 'use'/'no' behaviour; see import() sub.
266             #
267              
268             1;
269             __END__