File Coverage

blib/lib/Module/Generic.pm
Criterion Covered Total %
statement 1847 3742 49.3
branch 504 1834 27.4
condition 196 988 19.8
subroutine 406 594 68.3
pod 42 50 84.0
total 2995 7208 41.5


line stmt bran cond sub pod time code
1             ## -*- perl -*-
2             ##----------------------------------------------------------------------------
3             ## Module Generic - ~/lib/Module/Generic.pm
4             ## Version v0.12.16
5             ## Copyright(c) 2020 DEGUEST Pte. Ltd.
6             ## Author: Jacques Deguest <@sitael.tokyo.deguest.jp>
7             ## Created 2019/08/24
8             ## Modified 2020/06/19
9             ##
10             ##----------------------------------------------------------------------------
11             package Module::Generic;
12             BEGIN
13 0         0 {
14 6     6   79 require 5.6.0;
15 6     6   612373 use strict;
  6         62  
  6         191  
16 6     6   38 use warnings::register;
  6         13  
  6         789  
17 6     6   40 use Scalar::Util qw( openhandle );
  6         11  
  6         316  
18 6     6   2763 use Sub::Util ();
  6         1531  
  6         132  
19 6     6   2511 use Clone ();
  6         15380  
  6         162  
20 6     6   3719 use Data::Dumper;
  6         40728  
  6         621  
21             use Data::Printer
22             {
23             sort_keys => 1,
24             filters =>
25             {
26 0         0 'DateTime' => sub{ $_[0]->stringify },
27             }
28 6     6   4014 };
  6         241997  
  6         91  
29 6     6   11428 use Devel::StackTrace;
  6         32499  
  6         220  
30 6     6   3701 use Number::Format;
  6         38737  
  6         301  
31 6     6   3626 use Nice::Try;
  6         669991  
  6         48  
32 6     6   69591739 use B;
  6         20  
  6         534  
33             ## To get some context on what the caller expect. This is used in our error() method to allow chaining without breaking
34 6     6   4353 use Want;
  6         11128  
  6         414  
35 6     6   2846 use Class::Load ();
  6         37152  
  6         240  
36 6     6   3161 use Encode ();
  6         83258  
  6         745  
37 6         22 our( @ISA, @EXPORT_OK, @EXPORT, %EXPORT_TAGS, $AUTOLOAD );
38 6         9 our( $VERSION, $ERROR, $SILENT_AUTOLOAD, $VERBOSE, $DEBUG, $MOD_PERL );
39 6         11 our( $PARAM_CHECKER_LOAD_ERROR, $PARAM_CHECKER_LOADED, $CALLER_LEVEL );
40 6         10 our( $OPTIMIZE_MESG_SUB, $COLOUR_NAME_TO_RGB );
41 6     6   51 use Exporter ();
  6         14  
  6         466  
42 6         142 @ISA = qw( Exporter );
43 6         24 @EXPORT = qw( );
44 6         16 @EXPORT_OK = qw( subclasses );
45 6         82 %EXPORT_TAGS = ();
46 6         13 $VERSION = 'v0.12.16';
47 6         11 $VERBOSE = 0;
48 6         40 $DEBUG = 0;
49 6         10 $SILENT_AUTOLOAD = 1;
50 6         9 $PARAM_CHECKER_LOADED = 0;
51 6         10 $CALLER_LEVEL = 0;
52 6         9 $OPTIMIZE_MESG_SUB = 0;
53 6         4485 $COLOUR_NAME_TO_RGB = {};
54             # local $^W;
55 6     6   34 no strict qw(refs);
  6         12  
  6         190  
56 6     6   32 use constant COLOUR_OPEN => '<';
  6         14  
  6         337  
57 6     6   36 use constant COLOUR_CLOSE => '>';
  6         13  
  6         287  
58             };
59              
60             INIT
61             {
62 6     6   739 our $true = ${"Module::Generic::Boolean::true"};
  6         49  
63 6         15 our $false = ${"Module::Generic::Boolean::false"};
  6         31  
64 6         187 while( <DATA> )
65             {
66 0         0 chomp;
67 0         0 print( "INIT: found colour data: '$_'\n" );
68             }
69             };
70              
71             {
72             ## mod_perl/2.0.10
73             if( exists( $ENV{ 'MOD_PERL' } )
74             &&
75             ( $MOD_PERL = $ENV{ 'MOD_PERL' } =~ /^mod_perl\/\d+\.[\d\.]+/ ) )
76             {
77             select( ( select( STDOUT ), $| = 1 )[ 0 ] );
78             require Apache2::Log;
79             require Apache2::ServerUtil;
80             require Apache2::RequestUtil;
81             require Apache2::ServerRec;
82             }
83            
84             our $DEBUG_LOG_IO = undef();
85            
86             our $DB_NAME = $DATABASE;
87             our $DB_HOST = $SQL_SERVER;
88             our $DB_USER = $DB_LOGIN;
89             our $DB_PWD = $DB_PASSWD;
90             our $DB_RAISE_ERROR = $SQL_RAISE_ERROR;
91             our $DB_AUTO_COMMIT = $SQL_AUTO_COMMIT;
92             }
93              
94             sub import
95             {
96 6     6   88 my $self = shift( @_ );
97 6         34 my( $pkg, $file, $line ) = caller();
98 6         35 local $Exporter::ExportLevel = 1;
99             ## local $Exporter::Verbose = $VERBOSE;
100 6         161 Exporter::import( $self, @_ );
101            
102             ##print( STDERR "Module::Generic::import(): called from package '$pkg' in file '$file' at line '$line'.\n" ) if( $DEBUG );
103 6         34 ( my $dir = $pkg ) =~ s/::/\//g;
104 6         25 my $path = $INC{ $dir . '.pm' };
105             ##print( STDERR "Module::Generic::import(): using primary path of '$path'.\n" ) if( $DEBUG );
106 6 50       109 if( defined( $path ) )
107             {
108             ## Try absolute path name
109 0         0 $path =~ s/^(.*)$dir\.pm$/$1auto\/$dir\/autosplit.ix/;
110             ##print( STDERR "Module::Generic::import(): using treated path of '$path'.\n" ) if( $DEBUG );
111             eval
112 0         0 {
113 0     0   0 local $SIG{ '__DIE__' } = sub{ };
114 0     0   0 local $SIG{ '__WARN__' } = sub{ };
115 0         0 require $path;
116             };
117 0 0       0 if( $@ )
118             {
119 0         0 $path = "auto/$dir/autosplit.ix";
120             eval
121 0         0 {
122 0     0   0 local $SIG{ '__DIE__' } = sub{ };
123 0     0   0 local $SIG{ '__WARN__' } = sub{ };
124 0         0 require $path;
125             };
126             }
127 0 0       0 if( $@ )
128             {
129 0 0       0 CORE::warn( $@ ) unless( $SILENT_AUTOLOAD );
130             }
131             ##print( STDERR "Module::Generic::import(): '$path' ", $@ ? 'not ' : '', "loaded.\n" ) if( $DEBUG );
132             }
133             }
134              
135             sub new
136             {
137 133     133 1 426 my $that = shift( @_ );
138 133   66     722 my $class = ref( $that ) || $that;
139             ## my $pkg = ( caller() )[ 0 ];
140             ## print( STDERR __PACKAGE__ . "::new(): our calling package is '", ( caller() )[ 0 ], "', our class is '$class'.\n" );
141 133         358 my $self = {};
142             ## print( STDERR "${class}::OBJECT_READONLY: ", ${ "${class}\::OBJECT_READONLY" }, "\n" );
143 133 50       435 if( defined( ${ "${class}\::OBJECT_PERMS" } ) )
  133         1535  
144             {
145 0         0 my %hash = ();
146             my $obj = tie(
147             %hash,
148             'Module::Generic::Tie',
149             'pkg' => [ __PACKAGE__, $class ],
150 0         0 'perms' => ${ "${class}::OBJECT_PERMS" },
  0         0  
151             );
152 0         0 $self = \%hash;
153             }
154 133         419 bless( $self, $class );
155 133 50       574 if( $MOD_PERL )
156             {
157 0         0 my $r = Apache2::RequestUtil->request;
158             $r->pool->cleanup_register
159             (
160             sub
161             {
162             ## my( $pkg, $file, $line ) = caller();
163             ## print( STDERR "Apache procedure: Deleting all the object keys for object '$self' and package '$class' called within package '$pkg' in file '$file' at line '$line'.\n" );
164 0     0   0 map{ delete( $self->{ $_ } ) } keys( %$self );
  0         0  
165 0         0 undef( %$self );
166             }
167 0         0 );
168             }
169 133 50       293 if( defined( ${ "${class}\::LOG_DEBUG" } ) )
  133         933  
170             {
171 0         0 $self->{ 'log_debug' } = ${ "${class}::LOG_DEBUG" };
  0         0  
172             }
173 133         680 return( $self->init( @_ ) );
174             }
175              
176             ## This is used to transform package data set into hash refer suitable for api calls
177             ## If package use AUTOLOAD, those AUtILOAD should make sure to create methods on the fly so they become defined
178             sub as_hash
179             {
180 0     0 1 0 my $self = shift( @_ );
181 0         0 my $this = $self->_obj2h;
182 0         0 my $p = {};
183 0 0 0     0 $p = shift( @_ ) if( scalar( @_ ) == 1 && ref( $_[0] ) eq 'HASH' );
184             # $self->message( 3, "Parameters are: ", sub{ $self->dumper( $p ) } );
185 0         0 my $class = ref( $self );
186 6     6   51 no strict 'refs';
  6         13  
  6         439  
187 0         0 my @methods = grep{ defined &{"${class}::$_"} } keys( %{"${class}::"} );
  0         0  
  0         0  
  0         0  
188             # $self->messagef( 3, "The following methods found in package $class: '%s'.", join( "', '", sort( @methods ) ) );
189 6     6   35 use strict 'refs';
  6         14  
  6         528  
190 0         0 my $ref = {};
191 0         0 foreach my $meth ( sort( @methods ) )
192             {
193 0 0       0 next if( substr( $meth, 0, 1 ) eq '_' );
194 0         0 my $rv = eval{ $self->$meth };
  0         0  
195 0 0       0 if( $@ )
196             {
197 0         0 warn( "An error occured while accessing method $meth: $@\n" );
198 0         0 next;
199             }
200 6     6   43 no overloading;
  6         12  
  6         228  
201             # $self->message( 3, "Value for method '$meth' is '$rv'." );
202 6     6   31 use overloading;
  6         12  
  6         10861  
203 0 0 0     0 if( $p->{json} && ( ref( $rv ) eq 'JSON::PP::Boolean' || ref( $rv ) eq 'Module::Generic::Boolean' ) )
    0 0        
204             {
205             # $self->message( 3, "Encoding boolean to true or false for method '$meth'." );
206 0         0 $ref->{ $meth } = Module::Generic::Boolean::TO_JSON( $ref->{ $meth } );
207 0         0 next;
208             }
209             elsif( $self->_is_object( $rv ) )
210             {
211 0 0 0     0 if( $rv->can( 'as_hash' ) && overload::Overloaded( $rv ) && overload::Method( $rv, '""' ) )
    0 0        
212             {
213 0         0 $rv = $rv . '';
214             }
215             elsif( $rv->can( 'as_hash' ) )
216             {
217             # $self->message( 3, "$rv is an object (", ref( $rv ), ") capable of as_hash, calling it." );
218 0         0 $rv = $rv->as_hash( $p );
219             }
220             }
221            
222             ## $self->message( 3, "Checking field '$meth' with value '$rv'." );
223            
224 0 0       0 if( ref( $rv ) eq 'HASH' )
    0          
    0          
    0          
225             {
226 0 0       0 $ref->{ $meth } = $rv if( scalar( keys( %$rv ) ) );
227             }
228             ## If method call returned an array, like array of string or array of object such as in data from Net::API::Stripe::List
229             elsif( ref( $rv ) eq 'ARRAY' )
230             {
231 0         0 my $arr = [];
232 0         0 foreach my $this_ref ( @$rv )
233             {
234 0 0 0     0 my $that_ref = ( $self->_is_object( $this_ref ) && $this_ref->can( 'as_hash' ) ) ? $this_ref->as_hash : $this_ref;
235 0         0 CORE::push( @$arr, $that_ref );
236             }
237 0 0       0 $ref->{ $meth } = $arr if( scalar( @$arr ) );
238             }
239             elsif( !ref( $rv ) )
240             {
241 0 0       0 $ref->{ $meth } = $rv if( CORE::length( $rv ) );
242             }
243             elsif( CORE::length( "$rv" ) )
244             {
245 0         0 $self->message( 3, "Adding value '$rv' to field '$meth' in hash \$ref" );
246 0         0 $ref->{ $meth } = $rv;
247             }
248             }
249 0         0 return( $ref );
250             }
251              
252             sub clear
253             {
254 0     0 0 0 goto( &clear_error );
255             }
256              
257             sub clear_error
258             {
259 0     0 1 0 my $self = shift( @_ );
260 0   0     0 my $class = ref( $self ) || $self;
261 0         0 my $this = $self->_obj2h;
262 0         0 $this->{error} = ${ "$class\::ERROR" } = '';
  0         0  
263 0         0 return( 1 );
264             }
265              
266             # sub clone
267             # {
268             # my $self = shift( @_ );
269             # if( Scalar::Util::reftype( $self ) eq 'HASH' )
270             # {
271             # return( bless( { %$self } => ( ref( $self ) || $self ) ) );
272             # }
273             # elsif( Scalar::Util::reftype( $self ) eq 'ARRAY' )
274             # {
275             # return( bless( [ @$self ] => ( ref( $self ) || $self ) ) );
276             # }
277             # else
278             # {
279             # return( $self->error( "Cloning is unsupported for type \"", ref( $self ), "\". Only hash or array references are supported." ) );
280             # }
281             # }
282              
283             sub clone
284             {
285 0     0 1 0 my $self = shift( @_ );
286 0         0 try
287 0     0   0 {
288 0         0 $self->message( 3, "Cloning object '", overload::StrVal( $self ), "'." );
289 0         0 return( Clone::clone( $self ) );
290             }
291 0 0       0 catch( $e )
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
292 0     0   0 {
293 0         0 return( $self->error( "Error cloning object \"", overload::StrVal( $self ), "\": $e" ) );
294 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
295             }
296              
297 2     2 0 7 sub colour_close { return( shift->_set_get( 'colour_close', @_ ) ); }
298              
299             sub colour_closest
300             {
301 0     0 1 0 my $self = shift( @_ );
302 0         0 my $colour = uc( shift( @_ ) );
303 0         0 my $this = $self->_obj2h;
304 0         0 my $colours =
305             {
306             '000000000' => 'black',
307             '000000255' => 'blue',
308             '000255000' => 'green',
309             '000255255' => 'cyan',
310             '255000000' => 'red',
311             '255000255' => 'magenta',
312             '255255000' => 'yellow',
313             '255255255' => 'white',
314             };
315 0         0 my( $red, $green, $blue ) = ( '', '', '' );
316 0 0       0 if( $colour =~ /^[A-Z]+([A-Z\s]+)*$/ )
    0          
    0          
317             {
318 0 0       0 if( !scalar( keys( %$COLOUR_NAME_TO_RGB ) ) )
319             {
320             ## $self->message( 3, "Processing colour map in <DATA> section." );
321 0         0 while( <DATA> )
322             {
323 0         0 chomp;
324 0 0       0 next if( /^[[:blank:]]*$/ );
325 0 0       0 last if( /^\=/ );
326 0         0 my( $r, $g, $b, $name ) = split( /[[:blank:]]+/, $_, 4 );
327 0         0 $COLOUR_NAME_TO_RGB->{ lc( $name ) } = [ $r, $g, $b ];
328             }
329 0         0 close( DATA );
330             }
331 0 0       0 if( CORE::exists( $COLOUR_NAME_TO_RGB->{ lc( $colour ) } ) )
332             {
333 0         0 ( $red, $green, $blue ) = @{$COLOUR_NAME_TO_RGB->{ lc( $colour ) }};
  0         0  
334             }
335             }
336             ## Colour all in decimal??
337             elsif( $colour =~ /^\d{9}$/ )
338             {
339             ## $self->message( 3, "Got colour all in decimal. Less work to do..." );
340 0         0 $red = substr( $colour, 0, 3 );
341 0         0 $green = substr( $colour, 3, 3 );
342 0         0 $blue = substr( $colour, 6, 3 );
343             }
344             ## Colour in hexadecimal, convert it
345             elsif( $colour =~ /^[A-F0-9]+$/ )
346             {
347 0         0 $red = hex( substr( $colour, 0, 2 ) );
348 0         0 $green = hex( substr( $colour, 2, 2 ) );
349 0         0 $blue = hex( substr( $colour, 4, 2 ) );
350             }
351             ## Clueless
352             else
353             {
354             ## Not undef, but rather empty string. Undef is associated with an error
355 0         0 return( '' );
356             }
357 0         0 my $dec_colour = CORE::sprintf( '%3d%3d%3d', $red, $green, $blue );
358 0         0 my $last = '';
359 0         0 my @colours = reverse( sort( keys( %$colours ) ) );
360 0         0 $red = CORE::sprintf( '%03d', $red );
361 0         0 $green = CORE::sprintf( '%03d', $green );
362 0         0 $blue = CORE::sprintf( '%03d', $blue );
363 0         0 my $cur = CORE::sprintf( '%03d%03d%03d', $red, $green, $blue );
364 0         0 my( $red_ok, $green_ok, $blue_ok ) = ( 0, 0, 0 );
365             ## $self->message( 3, "Current colour: '$cur'." );
366 0         0 for( my $i = 0; $i < scalar( @colours ); $i++ )
367             {
368 0         0 my $r = CORE::sprintf( '%03d', substr( $colours[ $i ], 0, 3 ) );
369 0         0 my $g = CORE::sprintf( '%03d', substr( $colours[ $i ], 3, 3 ) );
370 0         0 my $b = CORE::sprintf( '%03d', substr( $colours[ $i ], 6, 3 ) );
371            
372 0         0 my $r_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 0, 3 ) );
373 0         0 my $g_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 3, 3 ) );
374 0         0 my $b_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 6, 3 ) );
375            
376             ## $self->message( 3, "$r ($red), $g ($green), $b ($blue)" );
377 0 0 0     0 if( $red == $r ||
      0        
      0        
      0        
      0        
      0        
378             ( $red < $r && $red > int( $r / 2 ) ) ||
379             ( $red > $r && $red < int( $r_p / 2 ) && $r_p ) ||
380             $red > $r )
381             {
382 0         0 $red_ok++;
383             }
384            
385 0 0       0 if( $red_ok )
386             {
387 0 0 0     0 if( $green == $g ||
      0        
      0        
      0        
      0        
      0        
388             ( $green < $g && $green > int( $g / 2 ) ) ||
389             ( $green > $g && $green < int( $g_p / 2 ) && $g_p ) ||
390             $green > $g )
391             {
392 0         0 $blue_ok++;
393             }
394             }
395            
396 0 0       0 if( $blue_ok )
397             {
398 0 0 0     0 if( $blue == $b ||
      0        
      0        
      0        
      0        
      0        
399             ( $blue < $b && $blue > int( $b / 2 ) ) ||
400             ( $blue > $b && $blue < int( $b_p / 2 ) && $b_p ) ||
401             $blue > $b )
402             {
403 0         0 $last = $colours[ $i ];
404 0         0 last;
405             }
406             }
407             }
408 0         0 return( $colours->{ $last } );
409             }
410              
411             sub colour_format
412             {
413 12     12 1 20 my $self = shift( @_ );
414             ## style, colour or color and text
415 12         15 my $opts = shift( @_ );
416 12 50       26 return( $self->error( "Parameter hash provided is not an hash reference." ) ) if( !$self->_is_hash( $opts ) );
417 12         22 my $this = $self->_obj2h;
418             ## To make it possible to use either text or message property
419 12 50 33     32 $opts->{text} = CORE::delete( $opts->{message} ) if( CORE::length( $opts->{message} ) && !CORE::length( $opts->{text} ) );
420 12 50       23 return( $self->error( "No text was provided to format." ) ) if( !CORE::length( $opts->{text} ) );
421            
422 12   0     35 $opts->{colour} //= CORE::delete( $opts->{color} ) || CORE::delete( $opts->{fg_colour} ) || CORE::delete( $opts->{fg_color} ) || CORE::delete( $opts->{fgcolour} ) || CORE::delete( $opts->{fgcolor} );
      66        
423 12   66     79 $opts->{bgcolour} //= CORE::delete( $opts->{bgcolor} ) || CORE::delete( $opts->{bg_colour} ) || CORE::delete( $opts->{bg_color} );
      66        
424            
425 12         16 my $bold = "\e[1m";
426 12         17 my $underline = "\e[4m";
427 12         14 my $reverse = "\e[7m";
428 12         13 my $normal = "\e[m";
429 12         14 my $cls = "\e[H\e[2J";
430 12         117 my $styles =
431             {
432             # Bold
433             b => 1,
434             bold => 1,
435             strong => 1,
436             # Italic
437             i => 3,
438             italic => 3,
439             # Underline
440             u => 4,
441             underline => 4,
442             underlined => 4,
443             blink => 5,
444             # Reverse
445             r => 7,
446             reverse => 7,
447             reversed => 7,
448             # Concealed
449             c => 8,
450             conceal => 8,
451             concealed => 8,
452             strike => 9,
453             striked => 9,
454             striken => 9,
455             };
456            
457             local $convert_24_To_8bits = sub
458             {
459 17     17   35 my( $r, $g, $b ) = @_;
460 17         58 $self->message( 9, "Converting $r, $g, $b to 8 bits" );
461 17         168 return( ( POSIX::floor( $r * 7 / 255 ) << 5 ) +
462             ( POSIX::floor( $g * 7 / 255 ) << 2 ) +
463             ( POSIX::floor( $b * 3 / 255 ) )
464             );
465 12         54 };
466            
467             ## opacity * original + (1-opacity)*background = resulting pixel
468             ## https://stackoverflow.com/a/746934/4814971
469             local $colour_with_alpha = sub
470             {
471 1     1   3 my( $r, $g, $b, $a, $bg ) = @_;
472             ## Assuming a white background (255)
473 1         2 my( $bg_r, $bg_g, $bg_b ) = ( 255, 255, 255 );
474 1 50       4 if( ref( $bg ) eq 'HASH' )
475             {
476 1         3 ( $bg_r, $bg_g, $bg_b ) = @$bg{qw( red green blue )};
477             }
478 1         7 $r = POSIX::round( ( $a * $r ) + ( ( 1 - $a ) * $bg_r ) );
479 1         4 $g = POSIX::round( ( $a * $g ) + ( ( 1 - $a ) * $bg_g ) );
480 1         3 $b = POSIX::round( ( $a * $b ) + ( ( 1 - $a ) * $bg_b ) );
481 1         3 return( [$r, $g, $b] );
482 12         43 };
483            
484             local $check_colour = sub
485             {
486 18     18   26 my $col = shift( @_ );
487             ## $self->message( 3, "Checking colour '$col'." );
488             ## $colours or $bg_colours
489 18         26 my $map = shift( @_ );
490 18         27 my $code;
491             my $light;
492             ## Example: 'light red' or 'light_red'
493 18 100       108 if( $col =~ /^(?:(?<light>bright|light)[[:blank:]\_]+)?
    50          
494             (?<colour>
495             (?:[a-zA-Z]+)(?:[[:blank:]]+\w+)?
496             |
497             (?<rgb_type>rgb[a]?)\([[:blank:]]*(?<red>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<green>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<blue>\d{1,3})
498             (?:[[:blank:]]*\,[[:blank:]]*(?<opacity>\d(?:\.\d+)?))?[[:blank:]]*
499             \)
500             )$/xi )
501             {
502 6     6   2994 my %regexp = %+;
  6         2456  
  6         37148  
  17         168  
503 17         100 $self->message( 9, "Light colour request '$col'. Capture: ", sub{ $self->dumper( \%regexp ) } );
  0         0  
504 17         124 ( $light, $col ) = ( $+{light}, $+{colour} );
505 17 100 66     97 if( CORE::length( $+{rgb_type} ) &&
      66        
      33        
506             CORE::length( $+{red} ) &&
507             CORE::length( $+{green} ) &&
508             CORE::length( $+{blue} ) )
509             {
510 3 100 66     20 if( $+{opacity} || $light )
511             {
512             my $opacity = CORE::length( $+{opacity} )
513             ? $+{opacity}
514 1 0       6 : $light
    50          
515             ? 0.5
516             : 1;
517 1         21 $col = CORE::sprintf( 'rgba(%03d%03d%03d,%.1f)', $+{red}, $+{green}, $+{blue}, $opacity );
518             }
519             else
520             {
521 2         24 $col = CORE::sprintf( 'rgb(%03d%03d%03d)', $+{red}, $+{green}, $+{blue} );
522             }
523             }
524             else
525             {
526 14         41 $self->message( 9, "Colour '$col' is not rgb[a]" );
527             }
528             }
529             elsif( $col =~ /^(?<rgb_type>rgb[a]?)\([[:blank:]]*(?<red>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<green>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<blue>\d{1,3})[[:blank:]]*(?:\,[[:blank:]]*(?<opacity>\d(?:\.\d+)?))?[[:blank:]]*\)$/i )
530             {
531 0 0       0 if( $+{opacity} )
532             {
533 0         0 $col = CORE::sprintf( 'rgba(%03d%03d%03d,%.1f)', $+{red}, $+{green}, $+{blue}, $+{opacity} );
534             }
535             else
536             {
537 0         0 $col = CORE::sprintf( '%03d%03d%03d', $+{red}, $+{green}, $+{blue} );
538             }
539             }
540             else
541             {
542 1         6 $self->message( 9, "Colour '$col' failed to match our rgba regexp." );
543             }
544            
545 18         33 my $col_ref;
546 18 100 66     78 if( $col =~ /^rgb[a]?\((?<red>\d{3})(?<green>\d{3})(?<blue>\d{3})\)$/i )
    100          
    100          
547             {
548 3         6 $col_ref = {};
549 3         54 %$col_ref = %+;
550 3         39 $self->message( 9, "Rgb colour '$+{red}', '$+{green}' and '$+{blue}' found: ", sub{ $self->dumper( $col_ref ) });
  0         0  
551             return({
552             _24bits => [@$col_ref{qw( red green blue )}],
553 3         22 _8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} )
554             });
555             }
556             ## Treating opacity to make things lighter; not ideal, but standard scheme
557             elsif( $col =~ /^rgba\((?<red>\d{3})(?<green>\d{3})(?<blue>\d{3})[[:blank:]]*\,[[:blank:]]*(?<opacity>\d(?:\.\d)?)\)$/i )
558             {
559 1         2 $col_ref = {};
560 1         11 %$col_ref = %+;
561 1         13 $self->message( 9, "Rgba colour '$+{red}', '$+{green}' and '$+{blue}' found with opacity $+{opacity}: ", sub{ $self->dumper( $col_ref ) });
  0         0  
562 1 50       8 if( $+{opacity} )
563             {
564 1         4 my $opacity = $+{opacity};
565 1         5 $self->message( 9, "Opacity of $opacity found, applying the factor to the colour." );
566 1         1 my $bg;
567 1 50       3 if( $opts->{bgcolour} )
568             {
569 1         4 $bg = $self->colour_to_rgb( $opts->{bgcolour} );
570 1         5 $self->message( 9, "Calculating new rgb with opacity and background information: ", sub{ $self->dumper( $bg ) });
  0         0  
571             }
572 1         5 my $new_col = $colour_with_alpha->( @$col_ref{qw( red green blue )}, $opacity, $bg );
573 1         6 $self->message( 9, "New colour with opacity applied: ", sub{ $self->dumper( $new_col ) });
  0         0  
574 1         4 @$col_ref{qw( red green blue )} = @$new_col;
575 1         17 $self->message( 9, "Colour $+{red}, $+{green}, $+{blue} * $opacity => $col_ref->{red}, $col_red->{green}, $col_ref->{blue}" );
576             }
577             return({
578             _24bits => [@$col_ref{qw( red green blue )}],
579 1         6 _8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} )
580             });
581             }
582             elsif( $self->message( 9, "Checking if rgb value exists for colour '$col'" ) &&
583             ( $col_ref = $self->colour_to_rgb( $col ) ) )
584             {
585 13         62 $self->message( 9, "Setting up colour '$col' with data: ", sub{ $self->dumper( $col_ref ) });
  0         0  
586             ## $code = $map->{ $col };
587             return({
588             _24bits => [@$col_ref{qw( red green blue )}],
589 13         57 _8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} )
590             });
591             }
592             else
593             {
594 1         4 $self->message( 9, "Could not find a match for colour '$col'." );
595 1         3 return( {} );
596             }
597             # my $is_bg = ( CORE::substr( $code, 0, 1 ) == 4 );
598             # if( CORE::length( $code ) && $light )
599             # {
600             # ## If the colour is a background colour, replace 4 by 10 (e.g.: 42 becomes 103)
601             # ## and if foreground colour, replace 3 by 9
602             # CORE::substr( $code, 0, 1 ) = ( $is_bg ? 10 : 9 );
603             # }
604             # return( $code );
605 12         77 };
606 12         20 my $data = [];
607 12         17 my $params = [];
608             ## 8 bits parameters compatible
609 12         16 my $params8 = [];
610 12 0 33     25 if( $opts->{colour} || $opts->{color} || $opts->{fgcolour} || $opts->{fgcolor} || $opts->{fg_colour} || $opts->{fg_color} )
      0        
      0        
      0        
      0        
611             {
612 12   0     24 $opts->{colour} ||= CORE::delete( $opts->{color} ) || CORE::delete( $opts->{fg_colour} ) || CORE::delete( $opts->{fg_color} ) || CORE::delete( $opts->{fgcolour} ) || CORE::delete( $opts->{fgcolor} );
      33        
613 12         25 my $col_ref = $check_colour->( $opts->{colour}, $colours );
614             ## CORE::push( @$params, $col ) if( CORE::length( $col ) );
615 12 100       34 if( scalar( keys( %$col_ref ) ) )
616             {
617 11     0   58 $self->message( 9, "Foreground colour '$opts->{colour}' data are: ", sub{ $self->dumper( $col_ref ) });
  0         0  
618 11         54 CORE::push( @$params8, sprintf( '38;5;%d', $col_ref->{_8bits} ) );
619 11         17 CORE::push( @$params, sprintf( '38;2;%d;%d;%d', @{$col_ref->{_24bits}} ) );
  11         49  
620             }
621             else
622             {
623 1         5 $self->message( 9, "Could not resolve the foreground colour '$opts->{colour}'." );
624             }
625             }
626 12 50 66     59 if( $opts->{bgcolour} || $opts->{bgcolor} || $opts->{bg_colour} || $opts->{bg_color} )
      33        
      33        
627             {
628 6   0     14 $opts->{bgcolour} ||= CORE::delete( $opts->{bgcolor} ) || CORE::delete( $opts->{bg_colour} ) || CORE::delete( $opts->{bg_color} );
      33        
629 6         14 my $col_ref = $check_colour->( $opts->{bgcolour}, $bg_colours );
630             ## CORE::push( @$params, $col ) if( CORE::length( $col ) );
631 6 50       16 if( scalar( keys( %$col_ref ) ) )
632             {
633 6     0   32 $self->message( 9, "Foreground colour '$opts->{bgcolour}' data are: ", sub{ $self->dumper( $col_ref ) });
  0         0  
634 6         30 CORE::push( @$params8, sprintf( '48;5;%d', $col_ref->{_8bits} ) );
635 6         8 CORE::push( @$params, sprintf( '48;2;%d;%d;%d', @{$col_ref->{_24bits}} ) );
  6         26  
636             }
637             else
638             {
639 0         0 $self->message( 9, "Could not resolve the background colour '$opts->{colour}'." );
640             }
641             }
642 12 100       29 if( $opts->{style} )
643             {
644             ## $self->message( 9, "Style '$opts->{style}' provided." );
645 11         33 my $those_styles = [CORE::split( /\|/, $opts->{style} )];
646             ## $self->message( 9, "Split styles: ", sub{ $self->dumper( $those_styles ) } );
647 11         23 foreach my $s ( @$those_styles )
648             {
649             ## $self->message( 9, "Adding style '$s'" ) if( CORE::exists( $styles->{lc($s)} ) );
650 12 50       31 if( CORE::exists( $styles->{lc($s)} ) )
651             {
652 12         21 CORE::push( @$params, $styles->{lc($s)} );
653             ## We add the 8 bits compliant version only if any colour was provided, i.e.
654             ## This is not just a style definition
655 12 50       32 CORE::push( @$params8, $styles->{lc($s)} ) if( scalar( @$params8 ) );
656             }
657             }
658             }
659 12 100       43 CORE::push( @$data, "\e[" . CORE::join( ';', @$params8 ) . "m" ) if( scalar( @$params8 ) );
660 12 100       49 CORE::push( @$data, "\e[" . CORE::join( ';', @$params ) . "m" ) if( scalar( @$params ) );
661 12     0   48 $self->message( 9, "Pre final colour data contains: ", sub{ $self->dumper( $data ) });
  0         0  
662             ## If the text contains libe breaks, we must stop the formatting before, or else there would be an ugly formatting on the entire screen following the line break
663 12 100 100     59 if( scalar( @$params ) && $opts->{text} =~ /\n+/ )
664             {
665 1         5 my $text_parts = [CORE::split( /\n/, $opts->{text} )];
666 1         4 my $fmt = CORE::join( '', @$data );
667 1         2 my $fmt8 = CORE::join( '', @$data8 );
668 1         6 for( my $i = 0; $i < scalar( @$text_parts ); $i++ )
669             {
670             ## Empty due to \n repeated
671 2 50       6 next if( !CORE::length( $text_parts->[$i] ) );
672 2         7 $text_parts->[$i] = $fmt . $text_parts->[$i] . $normal;
673             }
674 1         3 $opts->{text} = CORE::join( "\n", @$text_parts );
675 1         4 CORE::push( @$data, $opts->{text} );
676             }
677             else
678             {
679 11         19 CORE::push( @$data, $opts->{text} );
680 11 100       25 CORE::push( @$data, $normal, $normal ) if( scalar( @$params ) );
681             }
682             ## $self->message( "Returning '", quotemeta( CORE::join( '', @$data ) ), "'" );
683 12         369 return( CORE::join( '', @$data ) );
684             }
685              
686 2     2 0 12 sub colour_open { return( shift->_set_get( 'colour_open', @_ ) ); }
687              
688             sub colour_parse
689             {
690 5     5 1 15 my $self = shift( @_ );
691 5         16 my $txt = join( '', @_ );
692 5         11 my $this = $self->_obj2h;
693 5   50     16 my $open = $this->{colour_open} || COLOUR_OPEN;
694 5   50     13 my $close = $this->{colour_close} || COLOUR_CLOSE;
695 5         23 $self->message( 9, "Color open is '${open}' and close is '${close}'." );
696             ## $self->message( 3, "Parsing text '$txt'" );
697 5         17 my $colour_re = qr/(?:(?:bright|light)[[:blank:]])?(?:[a-zA-Z]+(?:[[:blank:]]+[\w\-]+)?|rgb[a]?\([[:blank:]]*\d{1,3}[[:blank:]]*\,[[:blank:]]*\d{1,3}[[:blank:]]*\,[[:blank:]]*\d{1,3}[[:blank:]]*(?:\,[[:blank:]]*\d(?:\.\d)?)?[[:blank:]]*\))/;
698 5         14 my $style_re = qr/(?:bold|faint|italic|underline|blink|reverse|conceal|strike)/;
699             local $parse = sub
700             {
701 7     7   12 my $opts = shift( @_ );
702 7         12 my $chunk = $opts->{text};
703 7   100     22 my $start = $opts->{start} || 0;
704 7         10 my $buff = '';
705 7         8 my $in = 0;
706 7         8 my $this_def = '';
707 7         9 my $def = {};
708 7         12 my $err = '';
709 7         9 my $data = [];
710 7         10 my $chunk_len = CORE::length( $$chunk );
711 7         9 my $i;
712 7         30 $self->message( 9, "Parsing text $$chunk starting from position $start" );
713 7         20 for( $i = $start; $i < $chunk_len; $i++ )
714             {
715 214         255 my $c = CORE::substr( $$chunk, $i, 1 );
716             # $self->message( 9, "Checking character '$c' at position $i" );
717 214 100       329 if( $c eq $open )
    100          
718             {
719             ## Is this the closing element?
720 20 100       55 if( CORE::substr( $$chunk, $i, 3 ) eq "${open}/${close}" )
    100          
721             {
722 9         53 $self->message( 9, "Found closing element and buffered text '$def->{text}' and definition is: ", sub{ $self->dumper( $def ) } );
  0         0  
723             ## $def includes the property text containing concatenated text
724 9 50       41 my $res = CORE::length( $def->{text} ) ? $self->colour_format( $def ) : '';
725 9         73 $self->message( 9, "Resulting formatted text is: '$res'." );
726             ## If this is a child, we return right now, the section we processed
727 9 100       21 if( $opts->{is_child} )
728             {
729 2         12 $self->message( 9, "Being a child, return formatted text '$res' and position ", $i + 3, " for text '$$chunk'" );
730 2         13 return({ text => $res, position => $i + 3 });
731             }
732             ## Otherwise we push it to the data stack
733             else
734             {
735 7 50       19 CORE::push( @$data, $res ) if( CORE::length( $res ) );
736 7         10 $i += 2;
737 7         20 $def = {};
738 7         18 next;
739             }
740             }
741             ## If we have a style definition already and we find an open style curly bracket,
742             ## this means this is an embedded text, we call $parse recursively
743             elsif( CORE::scalar( keys( %$def ) ) )
744             {
745 2         15 $self->message( 9, "Found a sub style, calling parse recursively starting from position $i. \$def has ", sub{ $self->dumper( $def ) } );
  0         0  
746 2         27 my $res = $parse->({ text => $chunk, start => $i, is_child => 1 });
747 2         7 $def->{text} .= $res->{text};
748             ## $self->message( 9, "Resuming parsing at position $res->{position} in text '$$chunk'." );
749 2         3 $i = $res->{position};
750 2         3 $i--;
751 2         5 next;
752             }
753            
754 9         15 my $j;
755 9         24 for( $j = $i; $j < CORE::length( $$chunk ); $j++ )
756             {
757 265 100       456 next unless( CORE::substr( $$chunk, $j, 1 ) eq $close );
758 9         21 $this_def = CORE::substr( $$chunk, $i, ( $j + 1 ) - $i );
759 9         40 $self->message( 9, "Found a style at position $i, ending at position ", ( $j + 1 ), ": '$this_def'" );
760            
761 9 100       475 if( $this_def =~ /^\Q${open}\E[[:blank:]]*(?:(?<style1>$style_re)[[:blank:]]+)?(?<fg_colour>$colour_re)(?:[[:blank:]]+(?<style2>$style_re))?(?:[[:blank:]]+on[[:blank:]]+(?<bg_colour>$colour_re))?[[:blank:]]*\Q${close}\E$/i )
762             {
763 5   66     41 $style = $+{style1} || $+{style2};
764 5         21 $fg = $+{fg_colour};
765 5         14 $bg = $+{bg_colour};
766 5         22 $self->message( 9, "Found style '$style', colour '$fg' and background colour '$bg'." );
767 5         19 $def =
768             {
769             style => $style,
770             colour => $fg,
771             bg_colour => $bg,
772             };
773             }
774             else
775             {
776 4         19 $self->message( 9, "Evaluating the styling '$this_def'." );
777 4         211 $def = eval( $this_def );
778 4 50 33     27 if( $@ || ref( $def ) ne 'HASH' )
779             {
780 0   0     0 $err = $@ || "Invalid styling \"${this_def}\"";
781             }
782             else
783             {
784 4         8 $err = '';
785             }
786             }
787 9 50       22 unless( $err )
788             {
789 9         16 $def->{start} = $i;
790             }
791 9         17 last;
792             }
793 9 50       20 if( !CORE::length( $this_def ) )
794             {
795 0         0 $self->message( 9, "Reaching the end of the string and could not find a closing curly bracket \"${close}\"." );
796 0         0 $self->error( "Failed to find a closing curly bracket for opening style." );
797 0         0 $def->{error} = 'no closeing curly bracket';
798             }
799 9         10 $i = $j;
800 9         20 next;
801             }
802             ## We are inside a formatting
803             elsif( scalar( keys( %$def ) ) )
804             {
805 147         211 $def->{text} .= $c;
806             ## $self->message( 9, "Text buffer now is '$def->{text}'." );
807             }
808             else
809             {
810 47         89 CORE::push( @$data, $c );
811             ## $self->message( 9, "Adding text outside formatting. \$data now is: '", join( '', @$data ), "'." );
812             }
813             }
814             ## Return the text with replacement performed
815 5         27 $self->message( 9, "Final formatted text is: ", quotemeta( CORE::join( '', @$data ) ) );
816 5 50       153 return( $opts->{is_child} ? { text => CORE::join( '', @$data ), position => $i } : CORE::join( '', @$data ) );
817 5         45 };
818 5         19 return( $parse->({ text => \$txt }) );
819             }
820              
821             sub colour_to_rgb
822             {
823 15     15 0 27 my $self = shift( @_ );
824 15         26 my $colour = lc( shift( @_ ) );
825 15         38 my $this = $self->_obj2h;
826 15         28 my( $red, $green, $blue ) = ( '', '', '' );
827 15         137 $self->message( 9, "Checking rgb value for '$colour'. Called from line ", (caller)[2] );
828 15 50       63 if( $colour =~ /^[A-Za-z]+([\w\-]+)*([[:blank:]]+\w+)?$/ )
    0          
    0          
829             {
830 15         44 $self->message( 9, "Checking colour '$colour' as string. Looking up its rgb value." );
831 15 100       37 if( !scalar( keys( %$COLOUR_NAME_TO_RGB ) ) )
832             {
833 1         3 $self->message( 9, "Processing colour map in <DATA> section." );
834 1         4 my $colour_data = $self->__colour_data;
835 1         3002 $COLOUR_NAME_TO_RGB = eval( $colour_data );
836 1 50       9 if( $@ )
837             {
838 0         0 return( $self->error( "An error occurred loading data from __colour_data: $@" ) );
839             }
840             }
841 15 100       37 if( CORE::exists( $COLOUR_NAME_TO_RGB->{ $colour } ) )
842             {
843 14         16 ( $red, $green, $blue ) = @{$COLOUR_NAME_TO_RGB->{ $colour }};
  14         37  
844 14         37 $self->message( 9, "Found rgb '$red, $green, $blue' for colour '$colour'." );
845             }
846             else
847             {
848 1         5 $self->message( 9, "Could not find colour '$colour' in our colour map." );
849 1         3 return( '' );
850             }
851             }
852             ## Colour all in decimal??
853             elsif( $colour =~ /^\d{9}$/ )
854             {
855             ## $self->message( 9, "Got colour all in decimal. Less work to do..." );
856 0         0 $red = substr( $colour, 0, 3 );
857 0         0 $green = substr( $colour, 3, 3 );
858 0         0 $blue = substr( $colour, 6, 3 );
859             }
860             ## Colour in hexadecimal, convert it
861             elsif( $colour =~ /^[A-F0-9]+$/ )
862             {
863 0         0 $red = hex( substr( $colour, 0, 2 ) );
864 0         0 $green = hex( substr( $colour, 2, 2 ) );
865 0         0 $blue = hex( substr( $colour, 4, 2 ) );
866             }
867             ## Clueless
868             else
869             {
870 0         0 $self->message( 9, "Clueless about what to do with colour '$colour'." );
871             ## Not undef, but rather empty string. Undef is associated with an error
872 0         0 return( '' );
873             }
874 14         66 return({ red => $red, green => $green, blue => $blue });
875             }
876              
877             sub coloured
878             {
879 3     3 1 6 my $self = shift( @_ );
880 3         8 my $pref = shift( @_ );
881 3         9 my $text = CORE::join( '', @_ );
882 3         8 my $this = $self->_obj2h;
883 3         7 my( $style, $fg, $bg );
884             ## my $colour_re = qr/(?:(?:bright|light)[[:blank:]])?[a-zA-Z]+/;
885 3         12 my $colour_re = qr/(?:(?:bright|light)[[:blank:]])?(?:[a-zA-Z]+(?:[[:blank:]]+[\w\-]+)?|rgb[a]?\([[:blank:]]*\d{1,3}[[:blank:]]*\,[[:blank:]]*\d{1,3}[[:blank:]]*\,[[:blank:]]*\d{1,3}[[:blank:]]*(?:\,[[:blank:]]*\d(?:\.\d)?)?[[:blank:]]*\))/;
886 3         8 my $style_re = qr/(?:bold|faint|italic|underline|blink|reverse|conceal|strike)/;
887 3 50       212 if( $pref =~ /^(?:(?<style1>$style_re)[[:blank:]]+)?(?<fg_colour>$colour_re)(?:[[:blank:]]+(?<style2>$style_re))?(?:[[:blank:]]+on[[:blank:]]+(?<bg_colour>$colour_re))?$/i )
888             {
889 3   33     57 $style = $+{style1} || $+{style2};
890 3         14 $fg = $+{fg_colour};
891 3         10 $bg = $+{bg_colour};
892             ## $self->message( 9, "Found style '$style', colour '$fg' and background colour '$bg'." );
893 3         19 return( $self->colour_format({ text => $text, style => $style, colour => $fg, bg_colour => $bg }) );
894             }
895             else
896             {
897 0         0 $self->message( 9, "No match." );
898 0         0 return( '' );
899             }
900             }
901              
902             sub debug
903             {
904 135     135 1 269 my $self = shift( @_ );
905 135         329 my $class = ref( $self );
906 135         299 my $this = $self->_obj2h;
907 135 50       463 if( @_ )
908             {
909 135         377 my $flag = shift( @_ );
910 135         317 $this->{debug} = $flag;
911 135 50       373 $self->message_switch( $flag ) if( $OPTIMIZE_MESG_SUB );
912 135 100 66     444 if( $this->{debug} &&
913             !$this->{debug_level} )
914             {
915 1         4 $this->{debug_level} = $this->{debug};
916             }
917             }
918 135   66     422 return( $this->{debug} || ${"$class\:\:DEBUG"} );
919             }
920              
921 0     0 1 0 sub dump { return( shift->printer( @_ ) ); }
922              
923             ## For backward compatibility and traceability
924 0     0 1 0 sub dump_print { return( shift->dumpto_printer( @_ ) ); }
925              
926             sub dumper
927             {
928 0     0 1 0 my $self = shift( @_ );
929 0         0 my $opts = {};
930 0 0 0     0 $opts = pop( @_ ) if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' );
931             # local $Data::Dumper::Sortkeys = 1;
932 0         0 local $Data::Dumper::Terse = 1;
933 0         0 local $Data::Dumper::Indent = 1;
934 0         0 local $Data::Dumper::Useqq = 1;
935 0 0       0 local $Data::Dumper::Maxdepth = $opts->{depth} if( CORE::length( $opts->{depth} ) );
936             local $Data::Dumper::Sortkeys = sub
937             {
938 0     0   0 my $h = shift( @_ );
939 0         0 return( [ sort( grep{ ref( $h->{ $_ } ) !~ /^(DateTime|DateTime\:\:)/ } keys( %$h ) ) ] );
  0         0  
940 0         0 };
941 0         0 return( Data::Dumper::Dumper( @_ ) );
942             }
943              
944             sub printer
945             {
946 0     0 1 0 my $self = shift( @_ );
947 0         0 my $opts = {};
948 0 0 0     0 $opts = pop( @_ ) if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' );
949 0     0   0 local $SIG{__WARN__} = sub{ };
950 0 0       0 if( scalar( keys( %$opts ) ) )
951             {
952 0         0 return( Data::Printer::np( @_, %$opts ) );
953             }
954             else
955             {
956 0         0 return( Data::Printer::np( @_ ) );
957             }
958             }
959              
960             *dumpto = \&dumpto_dumper;
961              
962             sub dumpto_printer
963             {
964 0     0 1 0 my $self = shift( @_ );
965 0         0 my( $data, $file ) = @_;
966 0   0     0 my $fh = IO::File->new( ">$file" ) || die( "Unable to create file '$file': $!\n" );
967 0         0 $fh->binmode( ':utf8' );
968 0         0 $fh->print( Data::Printer::np( $data ), "\n" );
969 0         0 $fh->close;
970             ## 666 so it can work under command line and web alike
971 0         0 chmod( 0666, $file );
972 0         0 return( 1 );
973             }
974              
975             sub dumpto_dumper
976             {
977 0     0 1 0 my $self = shift( @_ );
978 0         0 my( $data, $file ) = @_;
979 0         0 local $Data::Dumper::Sortkeys = 1;
980 0         0 local $Data::Dumper::Terse = 1;
981 0         0 local $Data::Dumper::Indent = 1;
982 0         0 local $Data::Dumper::Useqq = 1;
983 0   0     0 my $fh = IO::File->new( ">$file" ) || die( "Unable to create file '$file': $!\n" );
984 0 0       0 if( ref( $data ) )
985             {
986 0         0 $fh->print( Data::Dumper::Dumper( $data ), "\n" );
987             }
988             else
989             {
990 0         0 $fh->binmode( ':utf8' );
991 0         0 $fh->print( $data );
992             }
993 0         0 $fh->close;
994             ## 666 so it can work under command line and web alike
995 0         0 chmod( 0666, $file );
996 0         0 return( 1 );
997             }
998              
999             sub errno
1000             {
1001 0     0 0 0 my $self = shift( @_ );
1002 0         0 my $this = $self->_obj2h;
1003 0 0       0 if( @_ )
1004             {
1005 0 0       0 $this->{errno} = shift( @_ ) if( $_[ 0 ] =~ /^\-?\d+$/ );
1006 0 0       0 return( $self->error( @_ ) ) if( @_ );
1007             }
1008 0         0 return( $this->{errno} );
1009             }
1010              
1011             sub error
1012             {
1013 1     1 1 3 my $self = shift( @_ );
1014 1   33     5 my $class = ref( $self ) || $self;
1015 1         4 my $this = $self->_obj2h;
1016 1 50       5 if( @_ )
1017             {
1018 1         3 my $args = {};
1019 1 50 33     10 if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic::Exception' ) )
    50          
1020             {
1021 0         0 $args->{object} = shift( @_ );
1022             }
1023             elsif( ref( $_[0] ) eq 'HASH' )
1024             {
1025 0         0 $args = shift( @_ );
1026             }
1027             else
1028             {
1029 1 50 33     14 $args->{message} = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @_ ) );
1030             }
1031 1 50 33     27 $args->{message} = substr( $args->{message}, 0, $this->{error_max_length} ) if( $this->{error_max_length} > 0 && length( $args->{message} ) > $this->{error_max_length} );
1032             # Reset it
1033 1         5 $this->{_msg_no_exec_sub} = 0;
1034 1         2 my $n = 1;
1035             # $n++ while( ( caller( $n ) )[0] eq 'Module::Generic' );
1036 1         3 $args->{skip_frames} = $n + 1;
1037             ## my( $p, $f, $l ) = caller( $n );
1038             ## my( $sub ) = ( caller( $n + 1 ) )[3];
1039 1         19 my $o = $this->{error} = ${ $class . '::ERROR' } = Module::Generic::Exception->new( $args );
  1         8  
1040             ## printf( STDERR "%s::error() called from package %s ($p) in file %s ($f) at line %d ($l) from sub %s ($sub)\n", __PACKAGE__, $o->package, $o->file, $o->line, $o->subroutine );
1041            
1042             ## Get the warnings status of the caller. We use caller(1) to skip one frame further, ie our caller's caller
1043             ## This can be changed by using 'no warnings'
1044 1         4 my $should_display_warning = 0;
1045 1         2 my $no_use_warnings = 1;
1046             ## Try to get the warnings status if is enabled at all.
1047 1         2 try
1048 1     1   2 {
1049 1         9 $should_display_warning = $self->_warnings_is_enabled;
1050 1         3 $no_use_warnings = 0;
1051             }
1052 1 50       7 catch( $e )
  1 50       3  
  1 50       3  
  1 0       3  
  1 50       3  
  1         2  
  1         2  
  1         2  
  1         7  
  0         0  
  1         4  
  0         0  
  1         6  
  1         3  
  1         3  
  1         4  
  0         0  
  0         0  
  0         0  
  0         0  
1053 0     0   0 {
1054             #
1055 0 0 33     0 }
  0 0 33     0  
  0 0       0  
  0 50       0  
  0         0  
  0         0  
  1         18  
  0         0  
1056            
1057 1 50       5 if( $no_use_warnings )
1058             {
1059 0         0 my $call_offset = 0;
1060 0         0 while( my @call_data = caller( $call_offset ) )
1061             {
1062             ## printf( STDERR "[$call_offset] In file $call_data[1] at line $call_data[2] from subroutine %s has bitmask $call_data[9]\n", (caller($call_offset+1))[3] );
1063 0 0 0     0 unless( $call_offset > 0 && $call_data[0] ne $class && (caller($call_offset-1))[0] eq $class )
      0        
1064             {
1065             ## print( STDERR "Skipping package $call_data[0]\n" );
1066 0         0 $call_offset++;
1067 0         0 next;
1068             }
1069 0 0 0     0 last if( $call_data[9] || ( $call_offset > 0 && (caller($call_offset-1))[0] ne $class ) );
      0        
1070 0         0 $call_offset++;
1071             }
1072             ## print( STDERR "Using offset $call_offset with bitmask ", ( caller( $call_offset ) )[9], "\n" );
1073 0         0 my $bitmask = ( caller( $call_offset ) )[9];
1074 0         0 my $offset = $warnings::Offsets{uninitialized};
1075             ## $self->message( 3, "Caller (2)'s bitmask is '$bitmask', warnings offset is '$offset' and vector is '", vec( $bitmask, $offset, 1 ), "'." );
1076 0         0 $should_display_warning = vec( $bitmask, $offset, 1 );
1077             }
1078            
1079 1         3 my $r;
1080 1 50       4 $r = Apache2::RequestUtil->request if( $MOD_PERL );
1081             # $r->log_error( "Called for error $o" ) if( $r );
1082 1 50       4 $r->warn( $o->as_string ) if( $r );
1083 1         7 my $err_handler = $self->error_handler;
1084 1 50 33     21 if( $err_handler && ref( $err_handler ) eq 'CODE' )
    50 33        
    50          
    50          
1085             {
1086             # $r->log_error( "Module::Generic::error(): called for object error hanler" ) if( $r );
1087 0         0 $err_handler->( $o );
1088             }
1089             elsif( $r )
1090             {
1091             # $r->log_error( "Module::Generic::error(): called for Apache mod_perl error hanler" ) if( $r );
1092 0 0       0 if( my $log_handler = $r->get_handlers( 'PerlPrivateErrorHandler' ) )
1093             {
1094 0         0 $log_handler->( $o );
1095             }
1096             else
1097             {
1098             # $r->log_error( "Module::Generic::error(): No Apache mod_perl error handler set, reverting to log_error" ) if( $r );
1099             # $r->log_error( "$o" );
1100 0 0       0 $r->warn( $o->as_string ) if( $should_display_warning );
1101             }
1102             }
1103             elsif( $this->{fatal} )
1104             {
1105             ## die( sprintf( "Within package %s in file %s at line %d: %s\n", $o->package, $o->file, $o->line, $o->message ) );
1106             # $r->log_error( "Module::Generic::error(): called calling die" ) if( $r );
1107 0         0 my $enc_str = eval{ Encode::encode( 'UTF-8', "$o", Encode::FB_CROAK ) };
  0         0  
1108 0 0       0 die( $@ ? $o : $enc_str );
1109             }
1110             elsif( !exists( $this->{quiet} ) || !$this->{quiet} )
1111             {
1112             # $r->log_error( "Module::Generic::error(): calling warn" ) if( $r );
1113 1 50       4 if( $r )
1114             {
1115 0 0       0 $r->warn( $o->as_string ) if( $should_display_warning );
1116             }
1117             else
1118             {
1119 1         3 my $enc_str = eval{ Encode::encode( 'UTF-8', "$o", Encode::FB_CROAK ) };
  1         4  
1120 1 0       272 warn( $@ ? $o : $enc_str ) if( $should_display_warning );
    50          
1121             }
1122             }
1123            
1124 1 50       7 if( overload::Overloaded( $self ) )
1125             {
1126 1         54 my $overload_meth_ref = overload::Method( $self, '""' );
1127 1         111 my $overload_meth_name = Sub::Util::subname( $overload_meth_ref );
1128             ## use Sub::Identify ();
1129             ## my( $over_file, $over_line ) = Sub::Identify::get_code_location( $overload_meth_ref );
1130             # my( $over_call_pack, $over_call_file, $over_call_line ) = caller();
1131 1         7 my $call_sub = (caller(1))[3];
1132             # my $call_hash = (caller(0))[10];
1133             # my @call_keys = CORE::keys( %$call_hash );
1134             # print( STDERR "\$self is overloaded and stringification method is '$overload_meth', its sub name is '$overload_meth_name' from file '$over_file' at line '$over_line' and our caller subroutine is '$call_sub' from file '$over_call_file' at line '$over_call_line' with hint hash keys '@call_keys'.\n" );
1135             ## overloaded method name can be, for example: My::Package::as_string
1136             ## or, for anonymous sub: My::Package::__ANON__[lib/My/Package.pm:12]
1137             ## caller sub will reliably be the same, so we use it to check if we are called from an overloaded stringification and return undef right here.
1138             ## Want::want check of being called in an OBJECT context triggers a perl segmentation fault
1139 1 50       6 if( $overload_meth_name eq $call_sub )
1140             {
1141 1         7 return;
1142             }
1143             }
1144            
1145             ## https://metacpan.org/pod/Perl::Critic::Policy::Subroutines::ProhibitExplicitReturnUndef
1146             ## https://perlmonks.org/index.pl?node_id=741847
1147             ## Because in list context this would create a lit with one element undef()
1148             ## A bare return will return an empty list or an undef scalar
1149             ## return( undef() );
1150             ## return;
1151             ## As of 2019-10-13, Module::Generic version 0.6, we use this special package Module::Generic::Null to be returned in chain without perl causing the error that a method was called on an undefined value
1152             ## 2020-05-12: Added the no_return_null_object to instruct not to return a null object
1153             ## This is especially needed when an error is called from TIEHASH that returns a special object.
1154             ## A Null object would trigger a fatal perl segmentation fault
1155 0 0 0     0 if( !$args->{no_return_null_object} && want( 'OBJECT' ) )
1156             {
1157 0         0 my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 });
1158 0         0 rreturn( $null );
1159             }
1160 0         0 return;
1161             }
1162 0 0       0 return( ref( $self ) ? $this->{error} : ${ $class . '::ERROR' } );
  0         0  
1163             }
1164              
1165 1     1 0 8 sub error_handler { return( shift->_set_get_code( '_error_handler', @_ ) ); }
1166              
1167             *errstr = \&error;
1168              
1169             sub get
1170             {
1171 0     0 1 0 my $self = shift( @_ );
1172 0         0 my $this = $self->_obj2h;
1173 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
1174 0         0 my @data = map{ $data->{ $_ } } @_;
  0         0  
1175 0 0       0 return( wantarray() ? @data : $data[ 0 ] );
1176             }
1177              
1178             sub init
1179             {
1180 264     264 1 619 my $self = shift( @_ );
1181 264         612 my $pkg = ref( $self );
1182 264         795 my $this = $self->_obj2h;
1183 264 50       1554 $this->{verbose} = ${ $pkg . '::VERBOSE' } if( !length( $this->{verbose} ) );
  264         1770  
1184 264 100       983 $this->{debug} = ${ $pkg . '::DEBUG' } if( !length( $this->{debug} ) );
  130         587  
1185 264 50       1009 $this->{version} = ${ $pkg . '::VERSION' } if( !defined( $this->{version} ) );
  264         1351  
1186 264         897 $this->{level} = 0;
1187 264         861 $self->{colour_open} = COLOUR_OPEN;
1188 264         857 $self->{colour_close} = COLOUR_CLOSE;
1189             ## If no debug level was provided when calling message, this level will be assumed
1190             ## Example: message( "Hello" );
1191             ## If _message_default_level was set to 3, this would be equivalent to message( 3, "Hello" )
1192 264         802 $this->{ '_message_default_level' } = 0;
1193 264         670 my $data = $this;
1194 264 50       809 if( $this->{_data_repo} )
1195             {
1196 0 0       0 $this->{ $this->{_data_repo} } = {} if( !$this->{ $this->{_data_repo} } );
1197 0         0 $data = $this->{ $this->{_data_repo} };
1198             }
1199 264 50 66     1335 @_ = () if( @_ == 1 && !defined( $_[0] ) );
1200 264 100       794 if( @_ )
1201             {
1202 70         230 my @args = @_;
1203 70         176 my $vals;
1204 70 100 33     450 if( ref( $args[0] ) eq 'HASH' ||
    50 66        
    50 33        
    50          
1205             ( Scalar::Util::blessed( $args[0] ) && $args[0]->isa( 'Module::Generic::Hash' ) ) )
1206             {
1207             ## $self->_message( 3, "Got an hash ref" );
1208 68         161 my $h = shift( @args );
1209 68         150 my $debug_value;
1210 68 50       351 $debug_value = $h->{debug} if( CORE::exists( $h->{debug} ) );
1211 68         633 $vals = [ %$h ];
1212 68 100       474 unshift( @$vals, debug => $debug_value ) if( CORE::defined( $debug_value ) );
1213             ## $vals = [ %{$_[0]} ];
1214             }
1215             elsif( ref( $args[0] ) eq 'ARRAY' )
1216             {
1217             ## $self->_message( 3, "Got an array ref" );
1218 0         0 $vals = $args[0];
1219             }
1220             ## Special case when there is an undefined value passed (null) even though it is declared as a hash or object
1221             elsif( scalar( @args ) == 1 && !defined( $args[0] ) )
1222             {
1223             # return( undef() );
1224 0         0 return;
1225             }
1226             elsif( ( scalar( @args ) % 2 ) )
1227             {
1228 0         0 return( $self->error( sprintf( "Uneven number of parameters provided (%d). Should receive key => value pairs. Parameters provideds are: %s", scalar( @args ), join( ', ', @args ) ) ) );
1229             }
1230             else
1231             {
1232             ## $self->message( 3, "Got an array: ", sub{ $self->dumper( \@args ) } );
1233 2         7 $vals = \@args;
1234             }
1235             ## Check if there is a debug parameter, and if we find one, set it first so that that
1236             ## calls to the package subroutines can produce verbose feedback as necessary
1237 70         379 for( my $i = 0; $i < scalar( @$vals ); $i++ )
1238             {
1239 1895 100       4132 if( $vals->[$i] eq 'debug' )
1240             {
1241 131         311 my $v = $vals->[$i + 1];
1242 131         563 $self->debug( $v );
1243 131         502 CORE::splice( @$vals, $i, 2 );
1244             }
1245             }
1246            
1247 70         365 for( my $i = 0; $i < scalar( @$vals ); $i++ )
1248             {
1249 947         1795 my $name = $vals->[ $i ];
1250 947         1682 my $val = $vals->[ ++$i ];
1251 947         2862 my $meth = $self->can( $name );
1252             # $self->message( 3, "Does the object from class (", ref( $self ), ") has a method $name? ", ( defined( $meth ) ? 'yes' : 'no' ) );
1253 947 50       2035 if( defined( $meth ) )
    0          
    0          
1254             {
1255 947         2785 $self->$name( $val );
1256 947         3766 next;
1257             }
1258             elsif( $this->{_init_strict_use_sub} )
1259             {
1260             # $self->message( 3, "Checking if method $name exist in class ", ref( $self ), ": ", $self->can( $name ) ? 'yes' : 'no' );
1261             #if( !defined( $meth = $self->can( $name ) ) )
1262             #{
1263 0         0 $self->error( "Unknown method $name in class $pkg" );
1264 0         0 next;
1265             #}
1266             # $self->message( 3, "Calling method $name with value $val" );
1267             # $self->$meth( $val );
1268             # $meth->( $self, $val );
1269             #$self->$name( $val );
1270             #next;
1271             }
1272             elsif( exists( $data->{ $name } ) )
1273             {
1274             ## Pre-existing field value looks like a module package and that package is already loaded
1275 0 0 0     0 if( ( index( $data->{ $name }, '::' ) != -1 || $data->{ $name } =~ /^[a-zA-Z][a-zA-Z\_]*[a-zA-Z]$/ ) &&
    0 0        
1276             $self->_is_class_loaded( $data->{ $name } ) )
1277             {
1278 0         0 my $thisPack = $data->{ $name };
1279 0 0       0 if( !Scalar::Util::blessed( $val ) )
    0          
1280             {
1281 0         0 return( $self->error( "$name parameter expects a package $thisPack object, but instead got '$val'." ) );
1282             }
1283             elsif( !$val->isa( $thisPack ) )
1284             {
1285 0         0 return( $self->error( "$name parameter expects a package $thisPack object, but instead got an object from package '", ref( $val ), "'." ) );
1286             }
1287             }
1288             elsif( $this->{_init_strict} )
1289             {
1290 0 0       0 if( ref( $data->{ $name } ) eq 'ARRAY' )
    0          
    0          
1291             {
1292 0 0       0 return( $self->error( "$name parameter expects an array reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'ARRAY' );
1293             }
1294             elsif( ref( $data->{ $name } ) eq 'HASH' )
1295             {
1296 0 0       0 return( $self->error( "$name parameter expects an hash reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'HASH' );
1297             }
1298             elsif( ref( $data->{ $name } ) eq 'SCALAR' )
1299             {
1300 0 0       0 return( $self->error( "$name parameter expects a scalar reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'SCALAR' );
1301             }
1302             }
1303             }
1304             ## The name parameter does not exist
1305             else
1306             {
1307             ## If we are strict, we reject
1308 0 0       0 next if( $this->{_init_strict} );
1309             }
1310             ## We passed all tests
1311 0         0 $data->{ $name } = $val;
1312             }
1313             }
1314 264 0 33     936 if( $OPTIMIZE_MESG_SUB && !$this->{verbose} && !$this->{debug} )
      33        
1315             {
1316 0 0       0 if( defined( &{ "$pkg\::message" } ) )
  0         0  
1317             {
1318 0 0       0 *{ "$pkg\::message_off" } = \&{ "$pkg\::message" } unless( defined( &{ "$pkg\::message_off" } ) );
  0         0  
  0         0  
  0         0  
1319 0     0   0 *{ "$pkg\::message" } = sub { 1 };
  0         0  
  0         0  
1320             }
1321             }
1322 264         572 return( $self );
1323             }
1324              
1325 0     0 1 0 sub log_handler { return( shift->_set_get_code( '_log_handler', @_ ) ); }
1326              
1327             # sub log4perl
1328             # {
1329             # my $self = shift( @_ );
1330             # if( @_ )
1331             # {
1332             # require Log::Log4perl;
1333             # my $ref = shift( @_ );
1334             # Log::Log4perl::init( $ref->{ 'config_file' } );
1335             # my $log = Log::Log4perl->get_logger( $ref->{ 'domain' } );
1336             # $self->{ 'log4perl' } = $log;
1337             # }
1338             # else
1339             # {
1340             # $self->{ 'log4perl' };
1341             # }
1342             # }
1343              
1344             sub message
1345             {
1346 218     218 1 282 my $self = shift( @_ );
1347 218   33     418 my $class = ref( $self ) || $self;
1348             ## my( $pack, $file, $line ) = caller;
1349 218         328 my $this = $self->_obj2h;
1350             ## print( STDERR __PACKAGE__ . "::message(): Called from package $pack in file $file at line $line with debug value '$hash->{debug}', package DEBUG value '", ${ $class . '::DEBUG' }, "' and params '", join( "', '", @_ ), "'\n" );
1351 218         243 my $r;
1352 218 50       310 $r = Apache2::RequestUtil->request if( $MOD_PERL );
1353 218 50 33     655 if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
  0   33     0  
1354             {
1355             # $r->log_error( "Got here in Module::Generic::message before checking message." ) if( $r );
1356 218         226 my $ref;
1357 218         310 $ref = $self->message_check( @_ );
1358             ## print( STDERR __PACKAGE__ . "::message(): message_check() returns '$ref' (", join( '', @$ref ), ")\n" );
1359             ## return( 1 ) if( !( $ref = $self->message_check( @_ ) ) );
1360 218 50       426 return( 1 ) if( !$ref );
1361            
1362 0         0 my $opts = {};
1363 0 0       0 $opts = pop( @$ref ) if( ref( $ref->[-1] ) eq 'HASH' );
1364             ## print( STDERR __PACKAGE__ . "::message(): \$opts contains: ", $self->dumper( $opts ), "\n" );
1365            
1366             ## By now, we should have a reference to @_ in $ref
1367             ## my $class = ref( $self ) || $self;
1368             ## print( STDERR __PACKAGE__ . "::message(): caller at 0 is ", (caller(0))[3], " and at 1 is ", (caller(1))[3], "\n" );
1369             ## $r->log_error( "Got here in Module::Generic::message checking frames stack." ) if( $r );
1370 0   0     0 my $stackFrame = $self->message_frame( (caller(1))[3] ) || 1;
1371 0 0       0 $stackFrame = 1 unless( $stackFrame =~ /^\d+$/ );
1372 0 0       0 $stackFrame-- if( $stackFrame );
1373 0 0 0     0 $stackFrame++ if( (caller(1))[3] eq 'Module::Generic::messagef' ||
1374             (caller(1))[3] eq 'Module::Generic::message_colour' );
1375 0 0       0 $stackFrame++ if( (caller(2))[3] eq 'Module::Generic::messagef_colour' );
1376 0         0 my( $pkg, $file, $line, @otherInfo ) = caller( $stackFrame );
1377 0         0 my $sub = ( caller( $stackFrame + 1 ) )[3];
1378 0         0 my $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
1379 0 0       0 if( ref( $this->{_message_frame} ) eq 'HASH' )
1380             {
1381 0 0       0 if( exists( $this->{_message_frame}->{ $sub2 } ) )
1382             {
1383 0         0 my $frameNo = int( $this->{_message_frame}->{ $sub2 } );
1384 0 0       0 if( $frameNo > 0 )
1385             {
1386 0         0 ( $pkg, $file, $line, $sub ) = caller( $frameNo );
1387 0         0 $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
1388             }
1389             }
1390             }
1391             ## $r->log_error( "Called from package $pkg in file $file at line $line from sub $sub2 ($sub)" ) if( $r );
1392 0 0       0 if( $sub2 eq 'message' )
1393             {
1394 0         0 $stackFrame++;
1395 0         0 ( $pkg, $file, $line, @otherInfo ) = caller( $stackFrame );
1396 0         0 my $sub = ( caller( $stackFrame + 1 ) )[3];
1397 0         0 $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
1398             }
1399             ## $r->log_error( "Got here in Module::Generic::message building the message string." ) if( $r );
1400 0         0 my $txt;
1401 0 0       0 if( $opts->{message} )
1402             {
1403 0 0       0 if( ref( $opts->{message} ) eq 'ARRAY' )
1404             {
1405 0 0 0     0 $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @{$opts->{message}} ) );
  0         0  
1406             }
1407             else
1408             {
1409 0         0 $txt = $opts->{message};
1410             }
1411             }
1412             else
1413             {
1414 0 0 0     0 $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) );
1415             }
1416             ## Reset it
1417 0         0 $this->{_msg_no_exec_sub} = 0;
1418             ## $r->log_error( "Got here in Module::Generic::message with message string '$txt'." ) if( $r );
1419 6     6   95 no overloading;
  6         15  
  6         27439  
1420 0         0 my $mesg = "${pkg}::${sub2}( $self ) [$line]: " . $txt;
1421 0         0 $mesg =~ s/\n$//gs;
1422 0         0 $mesg = '## ' . join( "\n## ", split( /\n/, $mesg ) );
1423            
1424             my $info =
1425             {
1426             'formatted' => $mesg,
1427             'message' => $txt,
1428             'file' => $file,
1429             'line' => $line,
1430             'package' => $class,
1431             'sub' => $sub2,
1432 0 0       0 'level' => ( $_[0] =~ /^\d+$/ ? $_[0] : CORE::exists( $opts->{level} ) ? $opts->{level} : 0 ),
    0          
1433             };
1434 0 0       0 $info->{type} = $opts->{type} if( $opts->{type} );
1435            
1436             ## $r->log_error( "Got here in Module::Generic::message checkin if we run under ModPerl." ) if( $r );
1437             ## If Mod perl is activated AND we are not using a private log
1438             ## my $r;
1439             ## if( $MOD_PERL && !${ "${class}::LOG_DEBUG" } && ( $r = eval{ require Apache2::RequestUtil; Apache2::RequestUtil->request; } ) )
1440 0 0 0     0 if( $r && !${ "${class}::LOG_DEBUG" } )
  0 0 0     0  
    0 0        
    0 0        
    0 0        
      0        
1441             {
1442             ## $r->log_error( "Got here in Module::Generic::message, going to call our log handler." );
1443 0 0       0 if( my $log_handler = $r->get_handlers( 'PerlPrivateLogHandler' ) )
1444             {
1445             # my $meta = B::svref_2object( $log_handler );
1446             # $r->log_error( "Module::Generic::message(): Log handler code routine name is " . $meta->GV->NAME . " called in file " . $meta->GV->FILE . " at line " . $meta->GV->LINE );
1447 0         0 $log_handler->( $mesg );
1448             }
1449             else
1450             {
1451 0         0 $r->log_error( $mesg );
1452             }
1453             }
1454             ## Using ModPerl Server to log
1455 0         0 elsif( $MOD_PERL && !${ "${class}::LOG_DEBUG" } )
1456             {
1457 0         0 require Apache2::ServerUtil;
1458 0         0 my $s = Apache2::ServerUtil->server;
1459 0         0 $s->log_error( $mesg );
1460             }
1461             ## e.g. in our package, we could set the handler using the curry module like $self->{_log_handler} = $self->curry::log
1462             elsif( !-t( STDIN ) && $this->{_log_handler} && ref( $this->{_log_handler} ) eq 'CODE' )
1463             {
1464             # $r = Apache2::RequestUtil->request;
1465             # $r->log_error( "Got here in Module::Generic::message, going to call our log handler without using Apache callbacks." );
1466             # my $meta = B::svref_2object( $self->{_log_handler} );
1467             # $r->log_error( "Log handler code routine name is " . $meta->GV->NAME . " called in file " . $meta->GV->FILE . " at line " . $meta->GV->LINE );
1468 0         0 $this->{_log_handler}->( $info );
1469             }
1470 0         0 elsif( !-t( STDIN ) && ${ $class . '::MESSAGE_HANDLER' } && ref( ${ $class . '::MESSAGE_HANDLER' } ) eq 'CODE' )
  0         0  
1471             {
1472 0         0 my $h = ${ $class . '::MESSAGE_HANDLER' };
  0         0  
1473 0         0 $h->( $info );
1474             }
1475             ## Or maybe then into a private log file?
1476             ## This way, even if the log method is superseeded, we can keep using ours without interfering with the other one
1477             elsif( $self->message_log( $mesg, "\n" ) )
1478             {
1479 0         0 return( 1 );
1480             }
1481             ## Otherwise just on the stderr
1482             else
1483             {
1484 0         0 my $err = IO::File->new;
1485 0         0 $err->fdopen( fileno( STDERR ), 'w' );
1486 0 0       0 $err->binmode( ":utf8" ) unless( $opts->{no_encoding} );
1487 0         0 $err->autoflush( 1 );
1488 0         0 $err->print( $mesg, "\n" );
1489             }
1490             }
1491 0         0 return( 1 );
1492             }
1493              
1494             *message_color = \&message_colour;
1495              
1496             sub message_colour
1497             {
1498 0     0 1 0 my $self = shift( @_ );
1499 0   0     0 my $class = ref( $self ) || $self;
1500 0         0 my $this = $self->_obj2h;
1501 0 0 0     0 if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
  0   0     0  
1502             {
1503 0 0       0 my $level = ( $_[0] =~ /^\d+$/ ? shift( @_ ) : undef() );
1504 0         0 my $opts = {};
1505 0 0 0     0 if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' && ( CORE::exists( $_[-1]->{level} ) || CORE::exists( $_[-1]->{type} ) || CORE::exists( $_[-1]->{message} ) ) )
      0        
      0        
1506             {
1507 0         0 $opts = pop( @_ );
1508             }
1509 0         0 my $ref = [@_];
1510 0 0 0     0 $level = $opts->{level} if( !defined( $level ) && CORE::exists( $opts->{level} ) );
1511 0         0 my $txt;
1512 0 0       0 if( $opts->{message} )
1513             {
1514 0 0       0 if( ref( $opts->{message} ) eq 'ARRAY' )
1515             {
1516 0 0 0     0 $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @{$opts->{message}} ) );
  0         0  
1517             }
1518             else
1519             {
1520 0         0 $txt = $opts->{message};
1521             }
1522             }
1523             else
1524             {
1525 0 0 0     0 $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) );
1526             }
1527 0         0 $txt = $self->colour_parse( $txt );
1528 0         0 $opts->{message} = $txt;
1529 0 0       0 $opts->{level} = $level if( defined( $level ) );
1530 0   0     0 return( $self->message( ( $level || 0 ), $opts ) );
1531             }
1532 0         0 return( 1 );
1533             }
1534              
1535             sub messagef
1536             {
1537 0     0 1 0 my $self = shift( @_ );
1538             ## print( STDERR "got here: ", ref( $self ), "::messagef\n" );
1539 0   0     0 my $class = ref( $self ) || $self;
1540 0         0 my $this = $self->_obj2h;
1541 0 0 0     0 if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
  0   0     0  
1542             {
1543 0 0       0 my $level = ( $_[0] =~ /^\d+$/ ? shift( @_ ) : undef() );
1544 0         0 my $opts = {};
1545 0 0 0     0 if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' && ( CORE::exists( $_[-1]->{level} ) || CORE::exists( $_[-1]->{type} ) || CORE::exists( $_[-1]->{message} ) || CORE::exists( $_[-1]->{colour} ) ) )
      0        
      0        
1546             {
1547 0         0 $opts = pop( @_ );
1548             }
1549 0 0 0     0 $level = $opts->{level} if( !defined( $level ) && CORE::exists( $opts->{level} ) );
1550 0         0 my( $ref, $fmt );
1551 0 0       0 if( $opts->{message} )
1552             {
1553 0 0       0 if( ref( $opts->{message} ) eq 'ARRAY' )
1554             {
1555 0         0 $ref = $opts->{message};
1556 0         0 $fmt = shift( @$ref );
1557             }
1558             else
1559             {
1560 0         0 $fmt = $opts->{message};
1561 0         0 $ref = \@_;
1562             }
1563             }
1564             else
1565             {
1566 0         0 $ref = \@_;
1567 0         0 $fmt = shift( @$ref );
1568             }
1569 0 0 0     0 my $txt = sprintf( $fmt, map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) );
1570             ## $self->message( 3, "Option colour set? '$opts->{colour}'. Text is: '$txt'" );
1571 0 0       0 $txt = $self->colour_parse( $txt ) if( $opts->{colour} );
1572             ## print( STDERR ref( $self ), "::messagef \$txt is '$txt'\n" );
1573 0         0 $opts->{message} = $txt;
1574 0 0       0 $opts->{level} = $level if( defined( $level ) );
1575             # return( $self->message( defined( $level ) ? ( $level, $txt ) : $txt ) );
1576 0   0     0 return( $self->message( ( $level || 0 ), $opts ) );
1577             }
1578 0         0 return( 1 );
1579             }
1580              
1581             sub messagef_colour
1582             {
1583 0     0 0 0 my $self = shift( @_ );
1584 0         0 my $this = $self->_obj2h;
1585 0 0 0     0 if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
  0   0     0  
1586             {
1587 0         0 my @args = @_;
1588 0         0 my $opts = {};
1589 0 0 0     0 if( scalar( @args ) > 1 && ref( $args[-1] ) eq 'HASH' && ( CORE::exists( $args[-1]->{level} ) || CORE::exists( $args[-1]->{type} ) || CORE::exists( $args[-1]->{message} ) ) )
      0        
      0        
1590             {
1591 0         0 $opts = pop( @args );
1592             }
1593 0         0 $opts->{colour} = 1;
1594 0         0 CORE::push( @args, $opts );
1595             ## $self->message( 0, "Sending arguments: ", sub{ $self->dumper( \@args ) } );
1596 0         0 return( $this->messagef( @args ) );
1597             }
1598 0         0 return( 1 );
1599             }
1600              
1601             sub message_check
1602             {
1603 218     218 1 253 my $self = shift( @_ );
1604 218   33     357 my $class = ref( $self ) || $self;
1605 218         279 my $this = $self->_obj2h;
1606             ## printf( STDERR "Our class is $class and DEBUG_TARGET contains: '%s' and debug value is %s\n", join( ', ', @${ "${class}::DEBUG_TARGET" } ), $hash->{ 'debug' } );
1607 218 50       362 if( @_ )
1608             {
1609 218 50       484 if( $_[0] !~ /^\d/ )
1610             {
1611             ## The last parameter is an options parameter which has the level property set
1612 0 0 0     0 if( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) )
    0 0        
1613             {
1614             ## Then let's use this
1615             }
1616             elsif( $this->{ '_message_default_level' } =~ /^\d+$/ &&
1617             $this->{ '_message_default_level' } > 0 )
1618             {
1619 0         0 unshift( @_, $this->{ '_message_default_level' } );
1620             }
1621             else
1622             {
1623 0         0 unshift( @_, 1 );
1624             }
1625             }
1626             ## If the first argument looks line a number, and there is more than 1 argument
1627             ## and it is greater than 1, and greater than our current debug level
1628             ## well, we do not output anything then...
1629 218 50 33     791 if( ( $_[ 0 ] =~ /^\d+$/ || ( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) ) ) &&
      33        
1630             @_ > 1 )
1631             {
1632 218         255 my $message_level;
1633 218 50 0     365 if( $_[ 0 ] =~ /^\d+$/ )
    0          
1634             {
1635 218         291 $message_level = shift( @_ );
1636             }
1637             elsif( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) )
1638             {
1639 0         0 $message_level = $_[-1]->{level};
1640             }
1641 218         255 my $target_re = '';
1642 218 50       231 if( ref( ${ "${class}::DEBUG_TARGET" } ) eq 'ARRAY' )
  218         536  
1643             {
1644 0 0       0 $target_re = scalar( @${ "${class}::DEBUG_TARGET" } ) ? join( '|', @${ "${class}::DEBUG_TARGET" } ) : '';
  0         0  
  0         0  
1645             }
1646 218 50 33     601 if( $this->{debug} >= $message_level ||
      33        
      33        
      33        
      33        
      33        
      33        
1647             $this->{verbose} >= $message_level ||
1648 218         1219 ${ $class . '::DEBUG' } >= $message_level ||
1649             $this->{debug_level} >= $message_level ||
1650             $this->{debug} >= 100 ||
1651 0         0 ( length( $target_re ) && $class =~ /^$target_re$/ && ${ $class . '::GLOBAL_DEBUG' } >= $message_level ) )
1652             {
1653             ## print( STDERR ref( $self ) . "::message_check(): debug is '$hash->{debug}', verbose '$hash->{verbose}', DEBUG '", ${ $class . '::DEBUG' }, "', debug_level = $hash->{debug_level}\n" );
1654 0         0 return( [ @_ ] );
1655             }
1656             else
1657             {
1658 218         379 return( 0 );
1659             }
1660             }
1661             }
1662 0         0 return( 0 );
1663             }
1664              
1665             sub message_frame
1666             {
1667 0     0 0 0 my $self = shift( @_ );
1668 0         0 my $this = $self->_obj2h;
1669 0 0       0 $this->{_message_frame } = {} if( !exists( $this->{_message_frame} ) );
1670 0         0 my $mf = $this->{_message_frame};
1671 0 0       0 if( @_ )
1672             {
1673 0         0 my $args = {};
1674 0 0       0 if( ref( $_[0] ) eq 'HASH' )
    0          
    0          
1675             {
1676 0         0 $args = shift( @_ );
1677 0         0 my @k = keys( %$args );
1678 0         0 @$mf{ @k } = @$args{ @k };
1679             }
1680             elsif( !( @_ % 2 ) )
1681             {
1682 0         0 $args = { @_ };
1683 0         0 my @k = keys( %$args );
1684 0         0 @$mf{ @k } = @$args{ @k };
1685             }
1686             elsif( scalar( @_ ) == 1 )
1687             {
1688 0         0 my $sub = shift( @_ );
1689 0 0       0 $sub = substr( $sub, rindex( $sub, '::' ) + 2 ) if( index( $sub, '::' ) != -1 );
1690 0         0 return( $mf->{ $sub } );
1691             }
1692             else
1693             {
1694 0         0 return( $self->error( "I was expecting a key => value pair such as routine => stack frame (integer)" ) );
1695             }
1696             }
1697 0         0 return( $mf );
1698             }
1699              
1700             sub message_log
1701             {
1702 0     0 1 0 my $self = shift( @_ );
1703 0         0 my $io = $self->message_log_io;
1704             #print( STDERR "Module::Generic::log: \$io now is '$io'\n" );
1705 0 0       0 return( undef() ) if( !$io );
1706             #print( STDERR "Module::Generic::log: \$io is not an open handle\n" ) if( !openhandle( $io ) && $io );
1707 0 0 0     0 return( undef() ) if( !Scalar::Util::openhandle( $io ) && $io );
1708             ## 2019-06-14: I decided to remove this test, because if a log is provided it should print to it
1709             ## If we are on the command line, we can easily just do tail -f log_file.txt for example and get the same result as
1710             ## if it were printed directly on the console
1711             # my $rc = CORE::print( $io @_ ) || return( $self->error( "Unable to print to log file: $!" ) );
1712 0   0     0 my $rc = $io->print( scalar( localtime( time() ) ), " [$$]: ", @_ ) || return( $self->error( "Unable to print to log file: $!" ) );
1713             ## print( STDERR "Module::Generic::log (", ref( $self ), "): successfully printed to debug log file. \$rc is $rc, \$io is '$io' and message is: ", join( '', @_ ), "\n" );
1714 0         0 return( $rc );
1715             }
1716              
1717             sub message_log_io
1718             {
1719             #return( shift->_set_get( 'log_io', @_ ) );
1720 0     0 1 0 my $self = shift( @_ );
1721 0         0 my $class = ref( $self );
1722 0         0 my $this = $self->_obj2h;
1723 0 0 0     0 if( @_ )
    0 0        
1724             {
1725 0         0 my $io = shift( @_ );
1726 0         0 $self->_set_get( 'log_io', $io );
1727             }
1728 0         0 elsif( ${ "${class}::LOG_DEBUG" } &&
1729             !$self->_set_get( 'log_io' ) &&
1730 0         0 ${ "${class}::DEB_LOG" } )
1731             {
1732 0         0 our $DEB_LOG = ${ "${class}::DEB_LOG" };
  0         0  
1733 0 0       0 unless( $DEBUG_LOG_IO )
1734             {
1735 0   0     0 $DEBUG_LOG_IO = IO::File->new( ">>$DEB_LOG" ) || die( "Unable to open debug log file $DEB_LOG in append mode: $!\n" );
1736 0         0 $DEBUG_LOG_IO->binmode( ':utf8' );
1737 0         0 $DEBUG_LOG_IO->autoflush( 1 );
1738             }
1739 0         0 $self->_set_get( 'log_io', $DEBUG_LOG_IO );
1740             }
1741 0         0 return( $self->_set_get( 'log_io' ) );
1742             }
1743              
1744             sub message_switch
1745             {
1746 0     0 1 0 my $self = shift( @_ );
1747 0   0     0 my $pkg = ref( $self ) || $self;
1748 0         0 my $this = $self->_obj2h;
1749 0 0       0 if( @_ )
1750             {
1751 0         0 my $flag = shift( @_ );
1752 0 0 0     0 if( $flag )
    0          
1753             {
1754 0 0       0 if( defined( &{ "$pkg\::message_off" } ) )
  0         0  
1755             {
1756             ## Restore previous backup
1757 0         0 *{ "${pkg}::message" } = \&{ "${pkg}::message_off" };
  0         0  
  0         0  
1758             }
1759             else
1760             {
1761 0         0 *{ "${pkg}::message" } = \&{ "Module::Generic::message" };
  0         0  
  0         0  
1762             }
1763             }
1764             ## We switch it down if nobody is going to use it
1765             elsif( !$flag && !$this->{verbose} && !$this->{debug} )
1766             {
1767 0 0       0 *{ "${pkg}::message_off" } = \&{ "${pkg}::message" } unless( defined( &{ "${pkg}::message_off" } ) );
  0         0  
  0         0  
  0         0  
1768 0     0   0 *{ "${pkg}::message" } = sub { 1 };
  0         0  
  0         0  
1769             }
1770             }
1771 0         0 return( 1 );
1772             }
1773              
1774             sub new_array
1775             {
1776 0     0 1 0 my $self = shift( @_ );
1777 0         0 return( Module::Generic::Array->new( @_ ) );
1778             }
1779              
1780             sub new_hash
1781             {
1782 0     0 1 0 my $self = shift( @_ );
1783 0         0 return( Module::Generic::Hash->new( @_ ) );
1784             }
1785              
1786             sub new_number
1787             {
1788 0     0 1 0 my $self = shift( @_ );
1789 0         0 return( Module::Generic::Number->new( @_ ) );
1790             }
1791              
1792             sub new_scalar
1793             {
1794 0     0 1 0 my $self = shift( @_ );
1795 0         0 return( Module::Generic::Scalar->new( @_ ) );
1796             }
1797              
1798 0     0 1 0 sub noexec { $_[0]->{_msg_no_exec_sub} = 1; return( $_[0] ); }
  0         0  
1799              
1800             ## Purpose is to get an error object thrown from another package, and make it ours and pass it along
1801             sub pass_error
1802             {
1803 0     0 1 0 my $self = shift( @_ );
1804 0         0 my $this = $self->_obj2h;
1805 0         0 my $err = shift( @_ );
1806 0 0 0     0 return if( !ref( $err ) || !Scalar::Util::blessed( $err ) );
1807 0         0 $this->{error} = ${ $class . '::ERROR' } = $err;
  0         0  
1808 0 0       0 if( want( 'OBJECT' ) )
1809             {
1810 0         0 my $null = Module::Generic::Null->new( $err, { debug => $this->{debug}, has_error => 1 });
1811 0         0 rreturn( $null );
1812             }
1813 0         0 return;
1814             }
1815              
1816 0     0 1 0 sub quiet { return( shift->_set_get( 'quiet', @_ ) ); }
1817              
1818             sub save
1819             {
1820 0     0 1 0 my $self = shift( @_ );
1821 0         0 my $this = $self->_obj2h;
1822 0         0 my $opts = {};
1823 0 0       0 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
1824 0         0 my( $file, $data );
1825 0 0       0 if( @_ == 2 )
1826             {
1827 0         0 $opts->{data} = shift( @_ );
1828 0         0 $opts->{file} = shift( @_ );
1829             }
1830 0 0       0 return( $self->error( "No file was provided to save data to." ) ) if( !$opts->{file} );
1831 0   0     0 my $fh = IO::File->new( ">$opts->{file}" ) || return( $self->error( "Unable to open file \"$opts->{file}\" in write mode: $!" ) );
1832 0 0       0 $fh->binmode( ':' . $opts->{encoding} ) if( $opts->{encoding} );
1833 0         0 $fh->autoflush( 1 );
1834 0 0       0 if( !defined( $fh->print( ref( $opts->{data} ) eq 'SCALAR' ? ${$opts->{data}} : $opts->{data} ) ) )
  0 0       0  
1835             {
1836 0         0 return( $self->error( "Unable to write data to file \"$opts->{file}\": $!" ) )
1837             }
1838 0         0 $fh->close;
1839 0         0 my $bytes = -s( $opts->{file} );
1840 0         0 return( $bytes );
1841             }
1842              
1843             sub set
1844             {
1845 0     0 1 0 my $self = shift( @_ );
1846 0         0 my %arg = ();
1847 0 0       0 if( @_ )
1848             {
1849 0         0 %arg = ( @_ );
1850 0         0 my $this = $self->_obj2h;
1851 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
1852 0         0 my @keys = keys( %arg );
1853 0         0 @$data{ @keys } = @arg{ @keys };
1854             }
1855 0         0 return( scalar( keys( %arg ) ) );
1856             }
1857              
1858             sub subclasses
1859             {
1860 0     0 1 0 my $self = shift( @_ );
1861 0         0 my $that = '';
1862 0 0       0 $that = @_ ? shift( @_ ) : $self;
1863 0   0     0 my $base = ref( $that ) || $that;
1864 0         0 $base =~ s,::,/,g;
1865 0         0 $base .= '.pm';
1866            
1867 0         0 require IO::Dir;
1868             ## remove '.pm'
1869 0         0 my $dir = substr( $INC{ $base }, 0, ( length( $INC{ $base } ) ) - 3 );
1870            
1871 0         0 my @packages = ();
1872 0         0 my $io = IO::Dir->open( $dir );
1873 0 0       0 if( defined( $io ) )
1874             {
1875 0 0       0 @packages = map{ substr( $_, 0, length( $_ ) - 3 ) } grep{ substr( $_, -3 ) eq '.pm' && -f( "$dir/$_" ) } $io->read();
  0         0  
  0         0  
1876 0 0       0 $io->close ||
1877             warn( "Unable to close directory \"$dir\": $!\n" );
1878             }
1879             else
1880             {
1881 0         0 warn( "Unable to open directory \"$dir\": $!\n" );
1882             }
1883 0 0       0 return( wantarray() ? @packages : \@packages );
1884             }
1885              
1886 97     97 1 209 sub true { ${"Module::Generic::Boolean::true"} }
  97         1967  
1887              
1888 4     4 1 17 sub false { ${"Module::Generic::Boolean::false"} }
  4         64  
1889              
1890             sub verbose
1891             {
1892 0     0 1 0 my $self = shift( @_ );
1893 0         0 my $this = $self->_obj2h;
1894 0 0       0 if( @_ )
1895             {
1896 0         0 my $flag = shift( @_ );
1897 0         0 $this->{verbose} = $flag;
1898 0 0       0 $self->message_switch( $flag ) if( $OPTIMIZE_MESG_SUB );
1899             }
1900 0         0 return( $this->{verbose} );
1901             }
1902              
1903             sub will
1904             {
1905 0 0 0 0 1 0 ( @_ >= 2 && @_ <= 3 ) || die( 'Usage: $obj->can( "method" ) or Module::Generic::will( $obj, "method" )' );
1906 0         0 my( $obj, $meth, $level );
1907             ## $obj->will( $other_obj, 'method' );
1908 0 0 0     0 if( @_ == 3 && ref( $_[ 1 ] ) )
1909             {
1910 0         0 $obj = $_[ 1 ];
1911 0         0 $meth = $_[ 2 ];
1912             }
1913             else
1914             {
1915 0         0 ( $obj, $meth, $level ) = @_;
1916             }
1917 0 0 0     0 return( undef() ) if( !ref( $obj ) && index( $obj, '::' ) == -1 );
1918             ## Give a chance to UNIVERSAL::can
1919 0         0 my $ref = undef;
1920 0 0 0     0 if( Scalar::Util::blessed( $obj ) && ( $ref = $obj->can( $meth ) ) )
1921             {
1922 0         0 return( $ref );
1923             }
1924 0   0     0 my $class = ref( $obj ) || $obj;
1925 0         0 my $origi = $class;
1926 0 0       0 if( index( $meth, '::' ) != -1 )
1927             {
1928 0         0 $origi = substr( $meth, 0, rindex( $meth, '::' ) );
1929 0         0 $meth = substr( $meth, rindex( $meth, '::' ) + 2 );
1930             }
1931 0 0       0 $ref = \&{ "$class\::$meth" } if( defined( &{ "$class\::$meth" } ) );
  0         0  
  0         0  
1932             ## print( $err "\t" x $level, "UNIVERSAL::can ", defined( $ref ) ? "succeeded" : "failed", " in finding the method \"$meth\" in object/class $obj.\n" );
1933             ## print( $err "\t" x $level, defined( $ref ) ? "succeeded" : "failed", " in finding the method \"$meth\" in object/class $obj.\n" );
1934 0 0       0 return( $ref ) if( defined( $ref ) );
1935             ## We do not go further down the rabbit hole if level is greater or equal to 10
1936 0   0     0 $level ||= 0;
1937 0 0       0 return( undef() ) if( $level >= 10 );
1938 0         0 $level++;
1939             ## Let's see what Alice has got for us... :-)
1940             ## We look in the @ISA to see if the method exists in the package from which we
1941             ## possibly inherited
1942 0 0       0 if( @{ "$class\::ISA" } )
  0         0  
1943             {
1944             ## print( STDERR "\t" x $level, "Checking ", scalar( @{ "$class\::ISA" } ), " entries in \"\@${class}\:\:ISA\".\n" );
1945 0         0 foreach my $pack ( @{ "$class\::ISA" } )
  0         0  
1946             {
1947             ## print( STDERR "\t" x $level, "Looking up method \"$meth\" in inherited package \"$pack\".\n" );
1948 0         0 my $ref = &will( $pack, "$origi\::$meth", $level );
1949 0 0       0 return( $ref ) if( defined( $ref ) );
1950             }
1951             }
1952             ## Then, maybe there is an AUTOLOAD to trap undefined routine?
1953             ## But, we do not want any loop, do we?
1954             ## Since will() is called from Module::Generic::AUTOLOAD to check if EXTRA_AUTOLOAD exists
1955             ## we are not going to call Module::Generic::AUTOLOAD for EXTRA_AUTOLOAD...
1956 0 0 0     0 if( $class ne 'Module::Generic' && $meth ne 'EXTRA_AUTOLOAD' && defined( &{ "$class\::AUTOLOAD" } ) )
  0   0     0  
1957             {
1958             ## print( STDERR "\t" x ( $level - 1 ), "Found an AUTOLOAD in class \"$class\". Ok.\n" );
1959             my $sub = sub
1960             {
1961 0     0   0 $class::AUTOLOAD = "$origi\::$meth";
1962 0         0 &{ "$class::AUTOLOAD" }( @_ );
  0         0  
1963 0         0 };
1964 0         0 return( $sub );
1965             }
1966 0         0 return( undef() );
1967             }
1968              
1969             ## Initially those data were stored after the __END__, but it seems some module is interfering with <DATA>
1970             ## and so those data could not be loaded reliably
1971             ## This is called once by colour_to_rgb to generate the hash reference COLOUR_NAME_TO_RGB
1972             sub __colour_data
1973             {
1974 1     1   4 my $colour_data = <<EOT;
1975             {'alice blue' => ['240','248','255'],'aliceblue' => ['240','248','255'],'antique white' => ['250','235','215'],'antiquewhite' => ['250','235','215'],'antiquewhite1' => ['255','239','219'],'antiquewhite2' => ['238','223','204'],'antiquewhite3' => ['205','192','176'],'antiquewhite4' => ['139','131','120'],'aquamarine' => ['127','255','212'],'aquamarine1' => ['127','255','212'],'aquamarine2' => ['118','238','198'],'aquamarine3' => ['102','205','170'],'aquamarine4' => ['69','139','116'],'azure' => ['240','255','255'],'azure1' => ['240','255','255'],'azure2' => ['224','238','238'],'azure3' => ['193','205','205'],'azure4' => ['131','139','139'],'beige' => ['245','245','220'],'bisque' => ['255','228','196'],'bisque1' => ['255','228','196'],'bisque2' => ['238','213','183'],'bisque3' => ['205','183','158'],'bisque4' => ['139','125','107'],'black' => ['0','0','0'],'blanched almond' => ['255','235','205'],'blanchedalmond' => ['255','235','205'],'blue' => ['0','0','255'],'blue violet' => ['138','43','226'],'blue1' => ['0','0','255'],'blue2' => ['0','0','238'],'blue3' => ['0','0','205'],'blue4' => ['0','0','139'],'blueviolet' => ['138','43','226'],'brown' => ['165','42','42'],'brown1' => ['255','64','64'],'brown2' => ['238','59','59'],'brown3' => ['205','51','51'],'brown4' => ['139','35','35'],'burlywood' => ['222','184','135'],'burlywood1' => ['255','211','155'],'burlywood2' => ['238','197','145'],'burlywood3' => ['205','170','125'],'burlywood4' => ['139','115','85'],'cadet blue' => ['95','158','160'],'cadetblue' => ['95','158','160'],'cadetblue1' => ['152','245','255'],'cadetblue2' => ['142','229','238'],'cadetblue3' => ['122','197','205'],'cadetblue4' => ['83','134','139'],'chartreuse' => ['127','255','0'],'chartreuse1' => ['127','255','0'],'chartreuse2' => ['118','238','0'],'chartreuse3' => ['102','205','0'],'chartreuse4' => ['69','139','0'],'chocolate' => ['210','105','30'],'chocolate1' => ['255','127','36'],'chocolate2' => ['238','118','33'],'chocolate3' => ['205','102','29'],'chocolate4' => ['139','69','19'],'coral' => ['255','127','80'],'coral1' => ['255','114','86'],'coral2' => ['238','106','80'],'coral3' => ['205','91','69'],'coral4' => ['139','62','47'],'cornflower blue' => ['100','149','237'],'cornflowerblue' => ['100','149','237'],'cornsilk' => ['255','248','220'],'cornsilk1' => ['255','248','220'],'cornsilk2' => ['238','232','205'],'cornsilk3' => ['205','200','177'],'cornsilk4' => ['139','136','120'],'cyan' => ['0','255','255'],'cyan1' => ['0','255','255'],'cyan2' => ['0','238','238'],'cyan3' => ['0','205','205'],'cyan4' => ['0','139','139'],'dark blue' => ['0','0','139'],'dark cyan' => ['0','139','139'],'dark goldenrod' => ['184','134','11'],'dark gray' => ['169','169','169'],'dark green' => ['0','100','0'],'dark grey' => ['169','169','169'],'dark khaki' => ['189','183','107'],'dark magenta' => ['139','0','139'],'dark olive green' => ['85','107','47'],'dark orange' => ['255','140','0'],'dark orchid' => ['153','50','204'],'dark red' => ['139','0','0'],'dark salmon' => ['233','150','122'],'dark sea green' => ['143','188','143'],'dark slate blue' => ['72','61','139'],'dark slate gray' => ['47','79','79'],'dark slate grey' => ['47','79','79'],'dark turquoise' => ['0','206','209'],'dark violet' => ['148','0','211'],'darkblue' => ['0','0','139'],'darkcyan' => ['0','139','139'],'darkgoldenrod' => ['184','134','11'],'darkgoldenrod1' => ['255','185','15'],'darkgoldenrod2' => ['238','173','14'],'darkgoldenrod3' => ['205','149','12'],'darkgoldenrod4' => ['139','101','8'],'darkgray' => ['169','169','169'],'darkgreen' => ['0','100','0'],'darkgrey' => ['169','169','169'],'darkkhaki' => ['189','183','107'],'darkmagenta' => ['139','0','139'],'darkolivegreen' => ['85','107','47'],'darkolivegreen1' => ['202','255','112'],'darkolivegreen2' => ['188','238','104'],'darkolivegreen3' => ['162','205','90'],'darkolivegreen4' => ['110','139','61'],'darkorange' => ['255','140','0'],'darkorange1' => ['255','127','0'],'darkorange2' => ['238','118','0'],'darkorange3' => ['205','102','0'],'darkorange4' => ['139','69','0'],'darkorchid' => ['153','50','204'],'darkorchid1' => ['191','62','255'],'darkorchid2' => ['178','58','238'],'darkorchid3' => ['154','50','205'],'darkorchid4' => ['104','34','139'],'darkred' => ['139','0','0'],'darksalmon' => ['233','150','122'],'darkseagreen' => ['143','188','143'],'darkseagreen1' => ['193','255','193'],'darkseagreen2' => ['180','238','180'],'darkseagreen3' => ['155','205','155'],'darkseagreen4' => ['105','139','105'],'darkslateblue' => ['72','61','139'],'darkslategray' => ['47','79','79'],'darkslategray1' => ['151','255','255'],'darkslategray2' => ['141','238','238'],'darkslategray3' => ['121','205','205'],'darkslategray4' => ['82','139','139'],'darkslategrey' => ['47','79','79'],'darkturquoise' => ['0','206','209'],'darkviolet' => ['148','0','211'],'deep pink' => ['255','20','147'],'deep sky blue' => ['0','191','255'],'deeppink' => ['255','20','147'],'deeppink1' => ['255','20','147'],'deeppink2' => ['238','18','137'],'deeppink3' => ['205','16','118'],'deeppink4' => ['139','10','80'],'deepskyblue' => ['0','191','255'],'deepskyblue1' => ['0','191','255'],'deepskyblue2' => ['0','178','238'],'deepskyblue3' => ['0','154','205'],'deepskyblue4' => ['0','104','139'],'dim gray' => ['105','105','105'],'dim grey' => ['105','105','105'],'dimgray' => ['105','105','105'],'dimgrey' => ['105','105','105'],'dodger blue' => ['30','144','255'],'dodgerblue' => ['30','144','255'],'dodgerblue1' => ['30','144','255'],'dodgerblue2' => ['28','134','238'],'dodgerblue3' => ['24','116','205'],'dodgerblue4' => ['16','78','139'],'firebrick' => ['178','34','34'],'firebrick1' => ['255','48','48'],'firebrick2' => ['238','44','44'],'firebrick3' => ['205','38','38'],'firebrick4' => ['139','26','26'],'floral white' => ['255','250','240'],'floralwhite' => ['255','250','240'],'forest green' => ['34','139','34'],'forestgreen' => ['34','139','34'],'gainsboro' => ['220','220','220'],'ghost white' => ['248','248','255'],'ghostwhite' => ['248','248','255'],'gold' => ['255','215','0'],'gold1' => ['255','215','0'],'gold2' => ['238','201','0'],'gold3' => ['205','173','0'],'gold4' => ['139','117','0'],'goldenrod' => ['218','165','32'],'goldenrod1' => ['255','193','37'],'goldenrod2' => ['238','180','34'],'goldenrod3' => ['205','155','29'],'goldenrod4' => ['139','105','20'],'gray' => ['190','190','190'],'gray0' => ['0','0','0'],'gray1' => ['3','3','3'],'gray10' => ['26','26','26'],'gray100' => ['255','255','255'],'gray11' => ['28','28','28'],'gray12' => ['31','31','31'],'gray13' => ['33','33','33'],'gray14' => ['36','36','36'],'gray15' => ['38','38','38'],'gray16' => ['41','41','41'],'gray17' => ['43','43','43'],'gray18' => ['46','46','46'],'gray19' => ['48','48','48'],'gray2' => ['5','5','5'],'gray20' => ['51','51','51'],'gray21' => ['54','54','54'],'gray22' => ['56','56','56'],'gray23' => ['59','59','59'],'gray24' => ['61','61','61'],'gray25' => ['64','64','64'],'gray26' => ['66','66','66'],'gray27' => ['69','69','69'],'gray28' => ['71','71','71'],'gray29' => ['74','74','74'],'gray3' => ['8','8','8'],'gray30' => ['77','77','77'],'gray31' => ['79','79','79'],'gray32' => ['82','82','82'],'gray33' => ['84','84','84'],'gray34' => ['87','87','87'],'gray35' => ['89','89','89'],'gray36' => ['92','92','92'],'gray37' => ['94','94','94'],'gray38' => ['97','97','97'],'gray39' => ['99','99','99'],'gray4' => ['10','10','10'],'gray40' => ['102','102','102'],'gray41' => ['105','105','105'],'gray42' => ['107','107','107'],'gray43' => ['110','110','110'],'gray44' => ['112','112','112'],'gray45' => ['115','115','115'],'gray46' => ['117','117','117'],'gray47' => ['120','120','120'],'gray48' => ['122','122','122'],'gray49' => ['125','125','125'],'gray5' => ['13','13','13'],'gray50' => ['127','127','127'],'gray51' => ['130','130','130'],'gray52' => ['133','133','133'],'gray53' => ['135','135','135'],'gray54' => ['138','138','138'],'gray55' => ['140','140','140'],'gray56' => ['143','143','143'],'gray57' => ['145','145','145'],'gray58' => ['148','148','148'],'gray59' => ['150','150','150'],'gray6' => ['15','15','15'],'gray60' => ['153','153','153'],'gray61' => ['156','156','156'],'gray62' => ['158','158','158'],'gray63' => ['161','161','161'],'gray64' => ['163','163','163'],'gray65' => ['166','166','166'],'gray66' => ['168','168','168'],'gray67' => ['171','171','171'],'gray68' => ['173','173','173'],'gray69' => ['176','176','176'],'gray7' => ['18','18','18'],'gray70' => ['179','179','179'],'gray71' => ['181','181','181'],'gray72' => ['184','184','184'],'gray73' => ['186','186','186'],'gray74' => ['189','189','189'],'gray75' => ['191','191','191'],'gray76' => ['194','194','194'],'gray77' => ['196','196','196'],'gray78' => ['199','199','199'],'gray79' => ['201','201','201'],'gray8' => ['20','20','20'],'gray80' => ['204','204','204'],'gray81' => ['207','207','207'],'gray82' => ['209','209','209'],'gray83' => ['212','212','212'],'gray84' => ['214','214','214'],'gray85' => ['217','217','217'],'gray86' => ['219','219','219'],'gray87' => ['222','222','222'],'gray88' => ['224','224','224'],'gray89' => ['227','227','227'],'gray9' => ['23','23','23'],'gray90' => ['229','229','229'],'gray91' => ['232','232','232'],'gray92' => ['235','235','235'],'gray93' => ['237','237','237'],'gray94' => ['240','240','240'],'gray95' => ['242','242','242'],'gray96' => ['245','245','245'],'gray97' => ['247','247','247'],'gray98' => ['250','250','250'],'gray99' => ['252','252','252'],'green' => ['0','255','0'],'green yellow' => ['173','255','47'],'green1' => ['0','255','0'],'green2' => ['0','238','0'],'green3' => ['0','205','0'],'green4' => ['0','139','0'],'greenyellow' => ['173','255','47'],'grey' => ['190','190','190'],'grey0' => ['0','0','0'],'grey1' => ['3','3','3'],'grey10' => ['26','26','26'],'grey100' => ['255','255','255'],'grey11' => ['28','28','28'],'grey12' => ['31','31','31'],'grey13' => ['33','33','33'],'grey14' => ['36','36','36'],'grey15' => ['38','38','38'],'grey16' => ['41','41','41'],'grey17' => ['43','43','43'],'grey18' => ['46','46','46'],'grey19' => ['48','48','48'],'grey2' => ['5','5','5'],'grey20' => ['51','51','51'],'grey21' => ['54','54','54'],'grey22' => ['56','56','56'],'grey23' => ['59','59','59'],'grey24' => ['61','61','61'],'grey25' => ['64','64','64'],'grey26' => ['66','66','66'],'grey27' => ['69','69','69'],'grey28' => ['71','71','71'],'grey29' => ['74','74','74'],'grey3' => ['8','8','8'],'grey30' => ['77','77','77'],'grey31' => ['79','79','79'],'grey32' => ['82','82','82'],'grey33' => ['84','84','84'],'grey34' => ['87','87','87'],'grey35' => ['89','89','89'],'grey36' => ['92','92','92'],'grey37' => ['94','94','94'],'grey38' => ['97','97','97'],'grey39' => ['99','99','99'],'grey4' => ['10','10','10'],'grey40' => ['102','102','102'],'grey41' => ['105','105','105'],'grey42' => ['107','107','107'],'grey43' => ['110','110','110'],'grey44' => ['112','112','112'],'grey45' => ['115','115','115'],'grey46' => ['117','117','117'],'grey47' => ['120','120','120'],'grey48' => ['122','122','122'],'grey49' => ['125','125','125'],'grey5' => ['13','13','13'],'grey50' => ['127','127','127'],'grey51' => ['130','130','130'],'grey52' => ['133','133','133'],'grey53' => ['135','135','135'],'grey54' => ['138','138','138'],'grey55' => ['140','140','140'],'grey56' => ['143','143','143'],'grey57' => ['145','145','145'],'grey58' => ['148','148','148'],'grey59' => ['150','150','150'],'grey6' => ['15','15','15'],'grey60' => ['153','153','153'],'grey61' => ['156','156','156'],'grey62' => ['158','158','158'],'grey63' => ['161','161','161'],'grey64' => ['163','163','163'],'grey65' => ['166','166','166'],'grey66' => ['168','168','168'],'grey67' => ['171','171','171'],'grey68' => ['173','173','173'],'grey69' => ['176','176','176'],'grey7' => ['18','18','18'],'grey70' => ['179','179','179'],'grey71' => ['181','181','181'],'grey72' => ['184','184','184'],'grey73' => ['186','186','186'],'grey74' => ['189','189','189'],'grey75' => ['191','191','191'],'grey76' => ['194','194','194'],'grey77' => ['196','196','196'],'grey78' => ['199','199','199'],'grey79' => ['201','201','201'],'grey8' => ['20','20','20'],'grey80' => ['204','204','204'],'grey81' => ['207','207','207'],'grey82' => ['209','209','209'],'grey83' => ['212','212','212'],'grey84' => ['214','214','214'],'grey85' => ['217','217','217'],'grey86' => ['219','219','219'],'grey87' => ['222','222','222'],'grey88' => ['224','224','224'],'grey89' => ['227','227','227'],'grey9' => ['23','23','23'],'grey90' => ['229','229','229'],'grey91' => ['232','232','232'],'grey92' => ['235','235','235'],'grey93' => ['237','237','237'],'grey94' => ['240','240','240'],'grey95' => ['242','242','242'],'grey96' => ['245','245','245'],'grey97' => ['247','247','247'],'grey98' => ['250','250','250'],'grey99' => ['252','252','252'],'honeydew' => ['240','255','240'],'honeydew1' => ['240','255','240'],'honeydew2' => ['224','238','224'],'honeydew3' => ['193','205','193'],'honeydew4' => ['131','139','131'],'hot pink' => ['255','105','180'],'hotpink' => ['255','105','180'],'hotpink1' => ['255','110','180'],'hotpink2' => ['238','106','167'],'hotpink3' => ['205','96','144'],'hotpink4' => ['139','58','98'],'indian red' => ['205','92','92'],'indianred' => ['205','92','92'],'indianred1' => ['255','106','106'],'indianred2' => ['238','99','99'],'indianred3' => ['205','85','85'],'indianred4' => ['139','58','58'],'ivory' => ['255','255','240'],'ivory1' => ['255','255','240'],'ivory2' => ['238','238','224'],'ivory3' => ['205','205','193'],'ivory4' => ['139','139','131'],'khaki' => ['240','230','140'],'khaki1' => ['255','246','143'],'khaki2' => ['238','230','133'],'khaki3' => ['205','198','115'],'khaki4' => ['139','134','78'],'lavender' => ['230','230','250'],'lavender blush' => ['255','240','245'],'lavenderblush' => ['255','240','245'],'lavenderblush1' => ['255','240','245'],'lavenderblush2' => ['238','224','229'],'lavenderblush3' => ['205','193','197'],'lavenderblush4' => ['139','131','134'],'lawn green' => ['124','252','0'],'lawngreen' => ['124','252','0'],'lemon chiffon' => ['255','250','205'],'lemonchiffon' => ['255','250','205'],'lemonchiffon1' => ['255','250','205'],'lemonchiffon2' => ['238','233','191'],'lemonchiffon3' => ['205','201','165'],'lemonchiffon4' => ['139','137','112'],'light blue' => ['173','216','230'],'light coral' => ['240','128','128'],'light cyan' => ['224','255','255'],'light goldenrod' => ['238','221','130'],'light goldenrod yellow' => ['250','250','210'],'light gray' => ['211','211','211'],'light green' => ['144','238','144'],'light grey' => ['211','211','211'],'light pink' => ['255','182','193'],'light salmon' => ['255','160','122'],'light sea green' => ['32','178','170'],'light sky blue' => ['135','206','250'],'light slate blue' => ['132','112','255'],'light slate gray' => ['119','136','153'],'light slate grey' => ['119','136','153'],'light steel blue' => ['176','196','222'],'light yellow' => ['255','255','224'],'lightblue' => ['173','216','230'],'lightblue1' => ['191','239','255'],'lightblue2' => ['178','223','238'],'lightblue3' => ['154','192','205'],'lightblue4' => ['104','131','139'],'lightcoral' => ['240','128','128'],'lightcyan' => ['224','255','255'],'lightcyan1' => ['224','255','255'],'lightcyan2' => ['209','238','238'],'lightcyan3' => ['180','205','205'],'lightcyan4' => ['122','139','139'],'lightgoldenrod' => ['238','221','130'],'lightgoldenrod1' => ['255','236','139'],'lightgoldenrod2' => ['238','220','130'],'lightgoldenrod3' => ['205','190','112'],'lightgoldenrod4' => ['139','129','76'],'lightgoldenrodyellow' => ['250','250','210'],'lightgray' => ['211','211','211'],'lightgreen' => ['144','238','144'],'lightgrey' => ['211','211','211'],'lightpink' => ['255','182','193'],'lightpink1' => ['255','174','185'],'lightpink2' => ['238','162','173'],'lightpink3' => ['205','140','149'],'lightpink4' => ['139','95','101'],'lightsalmon' => ['255','160','122'],'lightsalmon1' => ['255','160','122'],'lightsalmon2' => ['238','149','114'],'lightsalmon3' => ['205','129','98'],'lightsalmon4' => ['139','87','66'],'lightseagreen' => ['32','178','170'],'lightskyblue' => ['135','206','250'],'lightskyblue1' => ['176','226','255'],'lightskyblue2' => ['164','211','238'],'lightskyblue3' => ['141','182','205'],'lightskyblue4' => ['96','123','139'],'lightslateblue' => ['132','112','255'],'lightslategray' => ['119','136','153'],'lightslategrey' => ['119','136','153'],'lightsteelblue' => ['176','196','222'],'lightsteelblue1' => ['202','225','255'],'lightsteelblue2' => ['188','210','238'],'lightsteelblue3' => ['162','181','205'],'lightsteelblue4' => ['110','123','139'],'lightyellow' => ['255','255','224'],'lightyellow1' => ['255','255','224'],'lightyellow2' => ['238','238','209'],'lightyellow3' => ['205','205','180'],'lightyellow4' => ['139','139','122'],'lime green' => ['50','205','50'],'limegreen' => ['50','205','50'],'linen' => ['250','240','230'],'magenta' => ['255','0','255'],'magenta1' => ['255','0','255'],'magenta2' => ['238','0','238'],'magenta3' => ['205','0','205'],'magenta4' => ['139','0','139'],'maroon' => ['176','48','96'],'maroon1' => ['255','52','179'],'maroon2' => ['238','48','167'],'maroon3' => ['205','41','144'],'maroon4' => ['139','28','98'],'medium aquamarine' => ['102','205','170'],'medium blue' => ['0','0','205'],'medium orchid' => ['186','85','211'],'medium purple' => ['147','112','219'],'medium sea green' => ['60','179','113'],'medium slate blue' => ['123','104','238'],'medium spring green' => ['0','250','154'],'medium turquoise' => ['72','209','204'],'medium violet red' => ['199','21','133'],'mediumaquamarine' => ['102','205','170'],'mediumblue' => ['0','0','205'],'mediumorchid' => ['186','85','211'],'mediumorchid1' => ['224','102','255'],'mediumorchid2' => ['209','95','238'],'mediumorchid3' => ['180','82','205'],'mediumorchid4' => ['122','55','139'],'mediumpurple' => ['147','112','219'],'mediumpurple1' => ['171','130','255'],'mediumpurple2' => ['159','121','238'],'mediumpurple3' => ['137','104','205'],'mediumpurple4' => ['93','71','139'],'mediumseagreen' => ['60','179','113'],'mediumslateblue' => ['123','104','238'],'mediumspringgreen' => ['0','250','154'],'mediumturquoise' => ['72','209','204'],'mediumvioletred' => ['199','21','133'],'midnight blue' => ['25','25','112'],'midnightblue' => ['25','25','112'],'mint cream' => ['245','255','250'],'mintcream' => ['245','255','250'],'misty rose' => ['255','228','225'],'mistyrose' => ['255','228','225'],'mistyrose1' => ['255','228','225'],'mistyrose2' => ['238','213','210'],'mistyrose3' => ['205','183','181'],'mistyrose4' => ['139','125','123'],'moccasin' => ['255','228','181'],'navajo white' => ['255','222','173'],'navajowhite' => ['255','222','173'],'navajowhite1' => ['255','222','173'],'navajowhite2' => ['238','207','161'],'navajowhite3' => ['205','179','139'],'navajowhite4' => ['139','121','94'],'navy' => ['0','0','128'],'navy blue' => ['0','0','128'],'navyblue' => ['0','0','128'],'old lace' => ['253','245','230'],'oldlace' => ['253','245','230'],'olive drab' => ['107','142','35'],'olivedrab' => ['107','142','35'],'olivedrab1' => ['192','255','62'],'olivedrab2' => ['179','238','58'],'olivedrab3' => ['154','205','50'],'olivedrab4' => ['105','139','34'],'orange' => ['255','165','0'],'orange red' => ['255','69','0'],'orange1' => ['255','165','0'],'orange2' => ['238','154','0'],'orange3' => ['205','133','0'],'orange4' => ['139','90','0'],'orangered' => ['255','69','0'],'orangered1' => ['255','69','0'],'orangered2' => ['238','64','0'],'orangered3' => ['205','55','0'],'orangered4' => ['139','37','0'],'orchid' => ['218','112','214'],'orchid1' => ['255','131','250'],'orchid2' => ['238','122','233'],'orchid3' => ['205','105','201'],'orchid4' => ['139','71','137'],'pale goldenrod' => ['238','232','170'],'pale green' => ['152','251','152'],'pale turquoise' => ['175','238','238'],'pale violet red' => ['219','112','147'],'palegoldenrod' => ['238','232','170'],'palegreen' => ['152','251','152'],'palegreen1' => ['154','255','154'],'palegreen2' => ['144','238','144'],'palegreen3' => ['124','205','124'],'palegreen4' => ['84','139','84'],'paleturquoise' => ['175','238','238'],'paleturquoise1' => ['187','255','255'],'paleturquoise2' => ['174','238','238'],'paleturquoise3' => ['150','205','205'],'paleturquoise4' => ['102','139','139'],'palevioletred' => ['219','112','147'],'palevioletred1' => ['255','130','171'],'palevioletred2' => ['238','121','159'],'palevioletred3' => ['205','104','137'],'palevioletred4' => ['139','71','93'],'papaya whip' => ['255','239','213'],'papayawhip' => ['255','239','213'],'peach puff' => ['255','218','185'],'peachpuff' => ['255','218','185'],'peachpuff1' => ['255','218','185'],'peachpuff2' => ['238','203','173'],'peachpuff3' => ['205','175','149'],'peachpuff4' => ['139','119','101'],'peru' => ['205','133','63'],'pink' => ['255','192','203'],'pink1' => ['255','181','197'],'pink2' => ['238','169','184'],'pink3' => ['205','145','158'],'pink4' => ['139','99','108'],'plum' => ['221','160','221'],'plum1' => ['255','187','255'],'plum2' => ['238','174','238'],'plum3' => ['205','150','205'],'plum4' => ['139','102','139'],'powder blue' => ['176','224','230'],'powderblue' => ['176','224','230'],'purple' => ['160','32','240'],'purple1' => ['155','48','255'],'purple2' => ['145','44','238'],'purple3' => ['125','38','205'],'purple4' => ['85','26','139'],'red' => ['255','0','0'],'red1' => ['255','0','0'],'red2' => ['238','0','0'],'red3' => ['205','0','0'],'red4' => ['139','0','0'],'rosy brown' => ['188','143','143'],'rosybrown' => ['188','143','143'],'rosybrown1' => ['255','193','193'],'rosybrown2' => ['238','180','180'],'rosybrown3' => ['205','155','155'],'rosybrown4' => ['139','105','105'],'royal blue' => ['65','105','225'],'royalblue' => ['65','105','225'],'royalblue1' => ['72','118','255'],'royalblue2' => ['67','110','238'],'royalblue3' => ['58','95','205'],'royalblue4' => ['39','64','139'],'saddle brown' => ['139','69','19'],'saddlebrown' => ['139','69','19'],'salmon' => ['250','128','114'],'salmon1' => ['255','140','105'],'salmon2' => ['238','130','98'],'salmon3' => ['205','112','84'],'salmon4' => ['139','76','57'],'sandy brown' => ['244','164','96'],'sandybrown' => ['244','164','96'],'sea green' => ['46','139','87'],'seagreen' => ['46','139','87'],'seagreen1' => ['84','255','159'],'seagreen2' => ['78','238','148'],'seagreen3' => ['67','205','128'],'seagreen4' => ['46','139','87'],'seashell' => ['255','245','238'],'seashell1' => ['255','245','238'],'seashell2' => ['238','229','222'],'seashell3' => ['205','197','191'],'seashell4' => ['139','134','130'],'sienna' => ['160','82','45'],'sienna1' => ['255','130','71'],'sienna2' => ['238','121','66'],'sienna3' => ['205','104','57'],'sienna4' => ['139','71','38'],'sky blue' => ['135','206','235'],'skyblue' => ['135','206','235'],'skyblue1' => ['135','206','255'],'skyblue2' => ['126','192','238'],'skyblue3' => ['108','166','205'],'skyblue4' => ['74','112','139'],'slate blue' => ['106','90','205'],'slate gray' => ['112','128','144'],'slate grey' => ['112','128','144'],'slateblue' => ['106','90','205'],'slateblue1' => ['131','111','255'],'slateblue2' => ['122','103','238'],'slateblue3' => ['105','89','205'],'slateblue4' => ['71','60','139'],'slategray' => ['112','128','144'],'slategray1' => ['198','226','255'],'slategray2' => ['185','211','238'],'slategray3' => ['159','182','205'],'slategray4' => ['108','123','139'],'slategrey' => ['112','128','144'],'snow' => ['255','250','250'],'snow1' => ['255','250','250'],'snow2' => ['238','233','233'],'snow3' => ['205','201','201'],'snow4' => ['139','137','137'],'spring green' => ['0','255','127'],'springgreen' => ['0','255','127'],'springgreen1' => ['0','255','127'],'springgreen2' => ['0','238','118'],'springgreen3' => ['0','205','102'],'springgreen4' => ['0','139','69'],'steel blue' => ['70','130','180'],'steelblue' => ['70','130','180'],'steelblue1' => ['99','184','255'],'steelblue2' => ['92','172','238'],'steelblue3' => ['79','148','205'],'steelblue4' => ['54','100','139'],'tan' => ['210','180','140'],'tan1' => ['255','165','79'],'tan2' => ['238','154','73'],'tan3' => ['205','133','63'],'tan4' => ['139','90','43'],'thistle' => ['216','191','216'],'thistle1' => ['255','225','255'],'thistle2' => ['238','210','238'],'thistle3' => ['205','181','205'],'thistle4' => ['139','123','139'],'tomato' => ['255','99','71'],'tomato1' => ['255','99','71'],'tomato2' => ['238','92','66'],'tomato3' => ['205','79','57'],'tomato4' => ['139','54','38'],'turquoise' => ['64','224','208'],'turquoise1' => ['0','245','255'],'turquoise2' => ['0','229','238'],'turquoise3' => ['0','197','205'],'turquoise4' => ['0','134','139'],'violet' => ['238','130','238'],'violet red' => ['208','32','144'],'violetred' => ['208','32','144'],'violetred1' => ['255','62','150'],'violetred2' => ['238','58','140'],'violetred3' => ['205','50','120'],'violetred4' => ['139','34','82'],'wheat' => ['245','222','179'],'wheat1' => ['255','231','186'],'wheat2' => ['238','216','174'],'wheat3' => ['205','186','150'],'wheat4' => ['139','126','102'],'white' => ['255','255','255'],'white smoke' => ['245','245','245'],'whitesmoke' => ['245','245','245'],'yellow' => ['255','255','0'],'yellow green' => ['154','205','50'],'yellow1' => ['255','255','0'],'yellow2' => ['238','238','0'],'yellow3' => ['205','205','0'],'yellow4' => ['139','139','0'],'yellowgreen' => ['154','205','50']}
1976             EOT
1977             }
1978              
1979             sub __instantiate_object
1980             {
1981 0     0   0 my $self = shift( @_ );
1982 0         0 my $field = shift( @_ );
1983 0         0 my $class = shift( @_ );
1984 0         0 my $this = $self->_obj2h;
1985 0         0 my $o;
1986 0         0 try
1987 0     0   0 {
1988             ## https://stackoverflow.com/questions/32608504/how-to-check-if-perl-module-is-available#comment53081298_32608860
1989             ## require $class unless( defined( *{"${class}::"} ) );
1990 0         0 my $rc = eval{ Class::Load::load_class( $class ); };
  0         0  
1991 0 0       0 return( $self->error( "Unable to load class $class: $@" ) ) if( $@ );
1992             # $self->message( 3, "Called with args: ", sub{ $self->dumper( \@_ ) } );
1993 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
1994 0 0       0 $o = @_ ? $class->new( @_ ) : $class->new;
1995 0 0       0 $o->debug( $this->{debug} ) if( $o->can( 'debug' ) );
1996 0 0       0 return( $self->pass_error( "Unable to instantiate an object of class $class: ", $class->error ) ) if( !defined( $o ) );
1997             }
1998 0 0       0 catch( $e )
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
1999 0     0   0 {
2000 0         0 return( $self->error({ code => 500, message => $e }) );
2001 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
2002 0         0 return( $o );
2003             }
2004              
2005             ## Call to the actual method doing the work
2006             ## The reason for doing so is because _instantiate_object() may be inherited, but
2007             ## _set_get_class or _set_get_hash_as_object created dynamic class which requires to call _instantiate_object
2008             ## If _instantiate_object is inherited, it will yield unpredictable results
2009 0     0   0 sub _instantiate_object { return( shift->__instantiate_object( @_ ) ); }
2010              
2011             sub _is_a
2012             {
2013 0     0   0 my $self = shift( @_ );
2014 0         0 my $obj = shift( @_ );
2015 0         0 my $pkg = shift( @_ );
2016 6     6   58 no overloading;
  6         16  
  6         29166  
2017 0 0 0     0 return if( !$obj || !$pkg );
2018 0 0       0 return if( !$self->_is_object( $obj ) );
2019 0         0 return( $obj->isa( $pkg ) );
2020             }
2021              
2022 0     0   0 sub _is_class_loaded { shift( @_ ); return( Class::Load::is_class_loaded( @_ ) ); }
  0         0  
2023              
2024             ## UNIVERSAL::isa works for both array or array as objects
2025             ## sub _is_array { return( UNIVERSAL::isa( $_[1], 'ARRAY' ) ); }
2026 0     0   0 sub _is_array { return( Scalar::Util::reftype( $_[1] ) eq 'ARRAY' ); }
2027              
2028             ## sub _is_hash { return( UNIVERSAL::isa( $_[1], 'HASH' ) ); }
2029 12     12   40 sub _is_hash { return( Scalar::Util::reftype( $_[1] ) eq 'HASH' ); }
2030              
2031 113025     113025   501790 sub _is_object { return( Scalar::Util::blessed( $_[1] ) ); }
2032              
2033 0     0   0 sub _is_scalar{ return( Scalar::Util::reftype( $_[1] ) eq 'SCALAR' ); }
2034              
2035             sub _load_class
2036             {
2037 0     0   0 my $self = shift( @_ );
2038 0   0     0 my $class = shift( @_ ) || return( $self->error( "No package name was provided to load." ) );
2039 0         0 try
2040 0     0   0 {
2041 0         0 return( Class::Load::load_class( "$class" ) );
2042             }
2043 0 0       0 catch( $e )
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
2044 0     0   0 {
2045 0         0 return( $self->error( $e ) );
2046 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
2047             }
2048              
2049             sub _obj2h
2050             {
2051 60449     60449   87821 my $self = shift( @_ );
2052             ## print( STDERR "_obj2h(): Getting a hash refernece out of the object '$self'\n" );
2053 60449 50       156575 if( Scalar::Util::reftype( $self ) eq 'HASH' )
    0          
    0          
2054             {
2055 60449         105155 return( $self );
2056             }
2057             elsif( Scalar::Util::reftype( $self ) eq 'GLOB' )
2058             {
2059             ## print( STDERR "Returning a reference to an hash for glob $self\n" );
2060 0         0 return( \%{*$self} );
  0         0  
2061             }
2062             ## The method that called message was itself called using the package name like My::Package->some_method
2063             ## We are going to check if global $DEBUG or $VERBOSE variables are set and create the related debug and verbose entry into the hash we return
2064             elsif( !ref( $self ) )
2065             {
2066 0         0 my $class = $self;
2067             my $hash =
2068             {
2069 0         0 'debug' => ${ "${class}\::DEBUG" },
2070 0         0 'verbose' => ${ "${class}\::VERBOSE" },
2071 0         0 'error' => ${ "${class}\::ERROR" },
  0         0  
2072             };
2073             ## XXX
2074             ## print( STDERR "Called with '$self' with debug value '$hash->{debug}' and verbose '$hash->{verbose}'\n" );
2075 0         0 return( bless( $hash => $class ) );
2076             }
2077             ## Because object may be accessed as My::Package->method or My::Package::method
2078             ## there is not always an object available, so we need to fake it to avoid error
2079             ## This is primarly itended for generic methods error(), errstr() to work under any conditions.
2080             else
2081             {
2082 0         0 return( {} );
2083             }
2084             }
2085              
2086             sub _parse_timestamp
2087             {
2088 0     0   0 my $self = shift( @_ );
2089 0         0 my $str = shift( @_ );
2090             ## No value was actually provided
2091 0 0       0 return( undef() ) if( !length( $str ) );
2092 0         0 my $this = $self->_obj2h;
2093 0         0 my $tz = DateTime::TimeZone->new( name => 'local' );
2094 0         0 my $error = 0;
2095             my $opt =
2096             {
2097             pattern => '%Y-%m-%d %T',
2098             locale => 'en_GB',
2099             time_zone => $tz->name,
2100 0     0   0 on_error => sub{ $error++ },
2101 0         0 };
2102             # $self->message( 3, "Checking timestamp string '$str' for appropriate pattern" );
2103             ## 2019-06-19 23:23:57.000000000+0900
2104             ## From PostgreSQL: 2019-06-20 11:02:36.306917+09
2105             ## ISO 8601: 2019-06-20T11:08:27
2106 0 0       0 if( $str =~ /(\d{4})[-|\/](\d{1,2})[-|\/](\d{1,2})(?:[[:blank:]]+|T)(\d{1,2}:\d{1,2}:\d{1,2})(?:\.\d+)?((?:\+|\-)\d{2,4})?/ )
    0          
    0          
2107             {
2108 0         0 my( $date, $time, $zone ) = ( "$1-$2-$3", $4, $5 );
2109 0 0       0 if( !length( $zone ) )
2110             {
2111 0         0 my $dt = DateTime->now( time_zone => $tz );
2112 0         0 my $offset = $dt->offset;
2113             ## e.g. 9 or possibly 9.5
2114 0         0 my $offset_hour = ( $offset / 3600 );
2115             ## e.g. 9.5 => 0.5 * 60 = 30
2116 0         0 my $offset_min = ( $offset_hour - CORE::int( $offset_hour ) ) * 60;
2117 0         0 $zone = sprintf( '%+03d%02d', $offset_hour, $offset_min );
2118             }
2119             # $self->message( 3, "\tMatched pattern #1 with date '$date', time '$time' and time zone '$zone'." );
2120 0         0 $date =~ tr/\//-/;
2121 0 0       0 $zone .= '00' if( length( $zone ) == 3 );
2122 0         0 $str = "$date $time$zone";
2123 0         0 $self->message( 3, "\tChanging string to '$str'" );
2124 0         0 $opt->{pattern} = '%Y-%m-%d %T%z';
2125             }
2126             ## From SQLite: 2019-06-20 02:03:14
2127             ## From MySQL: 2019-06-20 11:04:01
2128             elsif( $str =~ /(\d{4})[-|\/](\d{1,2})[-|\/](\d{1,2})(?:[[:blank:]]+|T)(\d{1,2}:\d{1,2}:\d{1,2})/ )
2129             {
2130 0         0 my( $date, $time ) = ( "$1-$2-$3", $4 );
2131             # $self->message( 3, "\tMatched pattern #2 with date '$date', time '$time' and without time zone." );
2132 0         0 my $dt = DateTime->now( time_zone => $tz );
2133 0         0 my $offset = $dt->offset;
2134             ## e.g. 9 or possibly 9.5
2135 0         0 my $offset_hour = ( $offset / 3600 );
2136             ## e.g. 9.5 => 0.5 * 60 = 30
2137 0         0 my $offset_min = ( $offset_hour - CORE::int( $offset_hour ) ) * 60;
2138 0         0 my $offset_str = sprintf( '%+03d%02d', $offset_hour, $offset_min );
2139 0         0 $date =~ tr/\//-/;
2140 0         0 $str = "$date $time$offset_str";
2141 0         0 $self->message( 3, "\tAdding time zone '", $tz->name, "' offset of $offset_str with result: '$str'." );
2142 0         0 $opt->{pattern} = '%Y-%m-%d %T%z';
2143             }
2144             elsif( $str =~ /^(\d{4})[-|\/](\d{1,2})[-|\/](\d{1,2})$/ )
2145             {
2146 0         0 $str = "$1-$2-$3";
2147             # $self->message( 3, "\tMatched pattern #3 with date '$date' only." );
2148 0         0 $opt->{pattern} = '%Y-%m-%d';
2149             }
2150             else
2151             {
2152 0         0 return( '' );
2153             }
2154 0         0 my $strp = DateTime::Format::Strptime->new( %$opt );
2155 0         0 my $dt = $strp->parse_datetime( $str );
2156 0         0 return( $dt );
2157             }
2158              
2159             sub _set_get
2160             {
2161 4     4   6 my $self = shift( @_ );
2162 4         8 my $field = shift( @_ );
2163 4         78 my $this = $self->_obj2h;
2164 4 50       13 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2165 4 50       9 if( @_ )
2166             {
2167 4 50       12 my $val = ( @_ == 1 ) ? shift( @_ ) : [ @_ ];
2168 4         8 $data->{ $field } = $val;
2169             }
2170 4 50       9 if( wantarray() )
2171             {
2172 0 0       0 if( ref( $data->{ $field } ) eq 'ARRAY' )
    0          
2173             {
2174 0         0 return( @{ $data->{ $field } } );
  0         0  
2175             }
2176             elsif( ref( $data->{ $field } ) eq 'HASH' )
2177             {
2178 0         0 return( %{ $data->{ $field } } );
  0         0  
2179             }
2180             else
2181             {
2182 0         0 return( ( $data->{ $field } ) );
2183             }
2184             }
2185             else
2186             {
2187 4         8 return( $data->{ $field } );
2188             }
2189             }
2190              
2191             sub _set_get_array
2192             {
2193 0     0   0 my $self = shift( @_ );
2194 0         0 my $field = shift( @_ );
2195 0         0 my $this = $self->_obj2h;
2196 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2197 0 0       0 if( @_ )
2198             {
2199 0 0 0     0 my $val = ( @_ == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? shift( @_ ) : [ @_ ];
2200 0         0 $data->{ $field } = $val;
2201             }
2202 0         0 return( $data->{ $field } );
2203             }
2204              
2205             sub _set_get_array_as_object
2206             {
2207 0     0   0 my $self = shift( @_ );
2208 0         0 my $field = shift( @_ );
2209 0         0 my $this = $self->_obj2h;
2210 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2211 0 0       0 if( @_ )
2212             {
2213 0 0 0     0 my $val = ( @_ == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? shift( @_ ) : [ @_ ];
2214 0         0 my $o = $data->{ $field };
2215             ## Some existing data, like maybe default value
2216 0 0       0 if( $o )
2217             {
2218 0 0       0 if( !$self->_is_object( $o ) )
2219             {
2220 0         0 my $tmp = $o;
2221 0         0 $o = Module::Generic::Array->new( $tmp );
2222             }
2223 0         0 $o->set( $val );
2224             }
2225             else
2226             {
2227 0         0 $o = Module::Generic::Array->new( $val );
2228 0         0 $data->{ $field } = $o;
2229             }
2230             }
2231 0 0 0     0 if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) )
2232             {
2233 0         0 my $o = Module::Generic::Array->new( $data->{ $field } );
2234 0         0 $data->{ $field } = $o;
2235             }
2236 0         0 return( $data->{ $field } );
2237             }
2238              
2239             sub _set_get_boolean
2240             {
2241 430     430   839 my $self = shift( @_ );
2242 430         799 my $field = shift( @_ );
2243 430         994 my $this = $self->_obj2h;
2244 430 50       1146 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2245 430 50       1085 if( @_ )
2246             {
2247 430         756 my $val = shift( @_ );
2248             # $self->message( 3, "Value provided for field '$field' is '$val' of reference (", ref( $val ), ")." );
2249 430 50 0     3203 if( Scalar::Util::blessed( $val ) &&
    50 33        
    50 33        
2250             ( $val->isa( 'JSON::PP::Boolean' ) || $val->isa( 'Module::Generic::Boolean' ) ) )
2251             {
2252 0         0 $data->{ $field } = $val;
2253             }
2254             elsif( Scalar::Util::reftype( $val ) eq 'SCALAR' )
2255             {
2256 0 0       0 $data->{ $field } = $$val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2257             }
2258             elsif( lc( $val ) eq 'true' || lc( $val ) eq 'false' )
2259             {
2260 0 0       0 $data->{ $field } = lc( $val ) eq 'true' ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2261             }
2262             else
2263             {
2264 430 100       2141 $data->{ $field } = $val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2265             }
2266             # $self->message( 3, "Boolean field now has value $self->{$field} (", ref( $self->{ $field } ), ")." );
2267             }
2268             ## If there is a value set, like a default value and it is not an object or at least not one we recognise
2269             ## We transform it into a Module::Generic::Boolean object
2270 430 50 33     1462 if( CORE::length( $data->{ $field } ) &&
      33        
2271             (
2272             !Scalar::Util::blessed( $data->{ $field } ) ||
2273             (
2274             Scalar::Util::blessed( $data->{ $field } ) &&
2275             !$data->{ $field }->isa( 'Module::Generic::Boolean' ) &&
2276             !$data->{ $field }->isa( 'JSON::PP::Boolean' )
2277             )
2278             ) )
2279             {
2280 0         0 my $val = $data->{ $field };
2281 0 0       0 $data->{ $field } = $val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2282             }
2283 430         1326 return( $data->{ $field } );
2284             }
2285              
2286             sub __create_class
2287             {
2288 0     0   0 my $self = shift( @_ );
2289 0   0     0 my $field = shift( @_ ) || return( $self->error( "No field was provided to create a dynamic class." ) );
2290 0         0 my $def = shift( @_ );
2291 0         0 my $class;
2292 0 0       0 if( $def->{_class} )
2293             {
2294 0         0 $class = $def->{_class};
2295             }
2296             else
2297             {
2298 0         0 my $new_class = $field;
2299 0         0 $new_class =~ tr/-/_/;
2300 0         0 $new_class =~ s/\_{2,}/_/g;
2301 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
2302 0         0 $class = ref( $self ) . "\::${new_class}";
2303             }
2304 0 0       0 unless( Class::Load::is_class_loaded( $class ) )
2305             {
2306             # $self->message( 3, "Class '$class' is not created yet, creating it." );
2307 0         0 my $type2func =
2308             {
2309             array => '_set_get_array',
2310             array_as_object => '_set_get_array_as_object',
2311             boolean => '_set_get_boolean',
2312             class => '_set_get_class',
2313             class_array => '_set_get_class_array',
2314             datetime => '_set_get_datetime',
2315             hash => '_set_get_hash',
2316             number => '_set_get_number',
2317             object => '_set_get_object',
2318             object_array => '_set_get_object_array',
2319             object_array_object => '_set_get_object_array_object',
2320             scalar => '_set_get_scalar',
2321             scalar_or_object => '_set_get_scalar_or_object',
2322             uri => '_set_get_uri',
2323             };
2324             ## Alias
2325 0         0 $type2func->{string} = $type2func->{scalar};
2326            
2327 0         0 my $perl = <<EOT;
2328             package $class;
2329             BEGIN
2330             {
2331             use strict;
2332             use Module::Generic;
2333             use parent -norequire, qw( Module::Generic );
2334             };
2335              
2336             EOT
2337 0         0 my $call_sub = ( split( /::/, ( caller(1) )[3] ) )[-1];
2338 0 0       0 my $call_frame = $call_sub eq '_set_get_class' ? 1 : 0;
2339 0         0 my( $pack, $file, $line ) = caller( $call_frame );
2340 0         0 my $code_lines = [];
2341 0         0 foreach my $f ( sort( keys( %$def ) ) )
2342             {
2343             # $self->message( 3, "Checking field '$f'." );
2344 0         0 my $info = $def->{ $f };
2345 0         0 my $type = lc( $info->{type} );
2346 0 0       0 if( !CORE::exists( $type2func->{ $type } ) )
2347             {
2348 0         0 warn( "Warning only: _set_get_class was called from package $pack at line $line in file $file, but the type provided \"$type\" is unknown to us, so we are skipping this field \"$f\" in the creation of our virtual class.\n" );
2349 0         0 next;
2350             }
2351 0         0 my $func = $type2func->{ $type };
2352 0 0 0     0 if( $type eq 'object' ||
    0 0        
      0        
2353             $type eq 'scalar_or_object' ||
2354             $type eq 'object_array' )
2355             {
2356 0 0       0 if( !$info->{class} )
2357             {
2358 0         0 warn( "Warning only: _set_get_class was called from package $pack at line $line in file $file, and class \"$class\" field \"$f\" is to require an object, but no object class name was provided. Use the \"class\" property parameter. So we are skipping this field \"$f\" in the creation of our virtual class.\n" );
2359 0         0 next;
2360             }
2361 0         0 my $this_class = $info->{class};
2362 0         0 CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', '$this_class', \@_ ) ); }" );
2363             }
2364             elsif( $type eq 'class' || $type eq 'class_array' )
2365             {
2366 0         0 my $this_def = $info->{definition};
2367 0 0       0 if( !CORE::exists( $info->{definition} ) )
    0          
2368             {
2369 0         0 warn( "Warning only: No dynamic class fields definition was provided for this field \"$f\". Skipping this field.\n" );
2370 0         0 next;
2371             }
2372             elsif( ref( $this_def ) ne 'HASH' )
2373             {
2374 0         0 warn( "Warning only: I was expecting a fields definition hash reference for dynamic class field \"$f\", but instead got '$this_def'. Skipping this field.\n" );
2375 0         0 next;
2376             }
2377 0         0 my $d = Data::Dumper->new( [ $this_def ] );
2378 0         0 $d->Indent( 0 );
2379 0         0 $d->Purity( 1 );
2380 0         0 $d->Pad( '' );
2381 0         0 $d->Terse( 1 );
2382 0         0 $d->Sortkeys( 1 );
2383 0         0 my $hash_str = $d->Dump;
2384 0         0 CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', $hash_str, \@_ ) ); }" );
2385             }
2386             else
2387             {
2388 0         0 CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', \@_ ) ); }" );
2389             }
2390             }
2391 0         0 $perl .= join( "\n\n", @$code_lines );
2392              
2393 0         0 $perl .= <<EOT;
2394              
2395              
2396             1;
2397              
2398             EOT
2399             # $self->message( 3, "Evaluating code:\n$perl" );
2400             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" );
2401 0         0 my $rc = eval( $perl );
2402             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" );
2403 0 0       0 die( "Unable to dynamically create module $class: $@" ) if( $@ );
2404             }
2405 0         0 return( $class );
2406             }
2407              
2408             ## $self->_set_get_class( 'my_field', {
2409             ## _class => 'My::Class',
2410             ## field1 => { type => 'datetime' },
2411             ## field2 => { type => 'scalar' },
2412             ## field3 => { type => 'boolean' },
2413             ## field4 => { type => 'object', class => 'Some::Class' },
2414             ## }, @_ );
2415             sub _set_get_class
2416             {
2417 0     0   0 my $self = shift( @_ );
2418             # $self->message( 3, "Got here with arguments: '", join( "', '", @_ ), "'." );
2419 0         0 my $field = shift( @_ );
2420 0         0 my $def = shift( @_ );
2421 0         0 my $this = $self->_obj2h;
2422 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2423 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2424 0 0       0 if( ref( $def ) ne 'HASH' )
2425             {
2426 0         0 CORE::warn( "Warning only: dynamic class field definition hash ($def) for field \"$field\" is not a hash reference.\n" );
2427 0         0 return;
2428             }
2429            
2430 0   0     0 my $class = $self->__create_class( $field, $def ) || die( "Failed to create the dynamic class for field \"$field\".\n" );
2431            
2432 0 0       0 if( @_ )
2433             {
2434 0         0 my $hash = shift( @_ );
2435             # my $o = $class->new( $hash );
2436 0         0 $self->messagef( 3, "Instantiating object of class '$class' with hash '$hash' containing %d elements: '%s'", scalar( keys( %$hash ) ), join( "', '", map{ "$_ => $hash->{$_}" } sort( keys( %$hash ) ) ) );
  0         0  
2437             ## $self->messagef( 3, "Instantiating object of class '$class' with hash '$hash' containing %d elements: '%s'", scalar( keys( %$hash ) ), $self->dumper( $hash ) );
2438 0         0 my $o = $self->__instantiate_object( $field, $class, $hash );
2439             # $self->message( 3, "\tReturning object for field '$field' and class '$class': '$o'." );
2440 0         0 $data->{ $field } = $o;
2441             }
2442            
2443 0 0       0 if( !$data->{ $field } )
2444             {
2445 0         0 my $o = $self->__instantiate_object( $field, $class );
2446 0         0 $data->{ $field } = $o;
2447             }
2448 0         0 return( $data->{ $field } );
2449             }
2450              
2451             sub _set_get_class_array
2452             {
2453 0     0   0 my $self = shift( @_ );
2454 0         0 my $field = shift( @_ );
2455 0         0 my $def = shift( @_ );
2456 0         0 my $this = $self->_obj2h;
2457 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2458 0 0       0 if( ref( $def ) ne 'HASH' )
2459             {
2460 0         0 CORE::warn( "Warning only: dynamic class field definition hash ($def) for field \"$field\" is not a hash reference.\n" );
2461 0         0 return;
2462             }
2463 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2464 0   0     0 my $class = $self->__create_class( $field, $def ) || die( "Failed to create the dynamic class for field \"$field\".\n" );
2465             ## return( $self->_set_get_object_array( $field, $class, @_ ) );
2466 0 0       0 if( @_ )
2467             {
2468 0         0 my $ref = shift( @_ );
2469 0 0       0 return( $self->error( "I was expecting an array ref, but instead got '$ref'. _is_array returned: '", $self->_is_array( $ref ), "'" ) ) if( !$self->_set_get_array( $ref ) );
2470 0         0 my $arr = [];
2471 0         0 for( my $i = 0; $i < scalar( @$ref ); $i++ )
2472             {
2473 0 0       0 if( ref( $ref->[$i] ) ne 'HASH' )
2474             {
2475 0         0 return( $self->error( "Array offset $i is not a hash reference. I was expecting a hash reference to instantiate an object of class $class." ) );
2476             }
2477 0         0 my $o = $self->__instantiate_object( $field, $class, $ref->[$i] );
2478 0         0 CORE::push( @$arr, $o );
2479             }
2480 0         0 $data->{ $field } = $arr;
2481             }
2482 0         0 return( $data->{ $field } );
2483             }
2484              
2485             sub _set_get_code
2486             {
2487 1     1   3 my $self = shift( @_ );
2488 1         3 my $field = shift( @_ );
2489 1         4 my $this = $self->_obj2h;
2490 1 50       4 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2491 1 50       4 if( @_ )
2492             {
2493 0         0 my $v = shift( @_ );
2494 0 0       0 return( $self->error( "Value provided for \"$field\" ($v) is not an anonymous subroutine (code). You can pass as argument something like \$self->curry::my_sub or something like sub { some_code_here; }" ) ) if( ref( $v ) ne 'CODE' );
2495 0         0 $data->{ $field } = $v;
2496             }
2497 1         4 return( $data->{ $field } );
2498             }
2499              
2500             sub _set_get_datetime
2501             {
2502 0     0   0 my $self = shift( @_ );
2503 0         0 my $field = shift( @_ );
2504 0         0 my $this = $self->_obj2h;
2505 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2506 0 0       0 if( @_ )
2507             {
2508 0         0 my $time = shift( @_ );
2509             # $self->message( 3, "Processing time stamp $time possibly of ref (", ref( $time ), ")." );
2510 0         0 my $now;
2511 0 0 0     0 if( !defined( $time ) )
    0          
    0          
    0          
2512             {
2513 0         0 $data->{ $field } = $time;
2514 0         0 return( $data->{ $field } );
2515             }
2516             elsif( Scalar::Util::blessed( $time ) )
2517             {
2518 0 0       0 return( $self->error( "Object provided as value for $field, but this is not a DateTime object" ) ) if( !$time->isa( 'DateTime' ) );
2519 0         0 $data->{ $field } = $time;
2520 0         0 return( $data->{ $field } );
2521             }
2522             elsif( $time =~ /^\d+$/ && $time !~ /^\d{10}$/ )
2523             {
2524 0         0 return( $self->error( "DateTime value ($time) provided for field $field does not look like a unix timestamp" ) );
2525             }
2526             elsif( $now = $self->_parse_timestamp( $time ) )
2527             {
2528             ## Found a parsed datetime value
2529 0         0 $data->{ $field } = $now;
2530 0         0 return( $now );
2531             }
2532            
2533             # $self->message( 3, "Creating a DateTime object out of $time\n" );
2534             eval
2535 0         0 {
2536 0         0 require DateTime;
2537 0         0 require DateTime::Format::Strptime;
2538 0         0 $now = DateTime->from_epoch(
2539             epoch => $time,
2540             time_zone => 'local',
2541             );
2542 0         0 my $strp = DateTime::Format::Strptime->new(
2543             pattern => '%s',
2544             locale => 'en_GB',
2545             time_zone => 'local',
2546             );
2547 0         0 $now->set_formatter( $strp );
2548             };
2549 0 0       0 if( $@ )
2550             {
2551 0         0 $self->message( "Error while trying to get the DateTime object for field $k with value $time" );
2552             }
2553             else
2554             {
2555             # $self->message( 3, "Returning the DateTime object '$now'" );
2556 0         0 $data->{ $field } = $now;
2557             }
2558             }
2559             ## So that a call to this field will not trigger an error: "Can't call method "xxx" on an undefined value"
2560 0 0 0     0 if( !$data->{ $field } && want( 'OBJECT' ) )
2561             {
2562 0         0 my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 });
2563 0         0 rreturn( $null );
2564             }
2565 0         0 return( $data->{ $field } );
2566             }
2567              
2568             sub _set_get_hash
2569             {
2570 0     0   0 my $self = shift( @_ );
2571 0         0 my $field = shift( @_ );
2572 0         0 my $this = $self->_obj2h;
2573 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2574             # $self->message( 3, "Called for field '$field' with data '", join( "', '", @_ ), "'." );
2575 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2576 0 0       0 if( @_ )
2577             {
2578 0         0 my $val;
2579 0 0       0 if( ref( $_[0] ) eq 'HASH' )
    0          
2580             {
2581 0         0 $val = shift( @_ );
2582             }
2583             elsif( ( @_ % 2 ) )
2584             {
2585 0         0 $val = { @_ };
2586             }
2587             else
2588             {
2589 0         0 my $val = shift( @_ );
2590 0         0 return( $self->error( "Method $field takes only a hash or reference to a hash, but value provided ($val) is not supported" ) );
2591             }
2592             # $self->message( 3, "Setting value $val for field $field" );
2593 0         0 $data->{ $field } = $val;
2594             }
2595 0         0 return( $data->{ $field } );
2596             }
2597              
2598             sub _set_get_hash_as_mix_object
2599             {
2600 129     129   360 my $self = shift( @_ );
2601 129         308 my $field = shift( @_ );
2602 129         437 my $this = $self->_obj2h;
2603 129 50       506 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2604             # $self->message( 3, "Called for field '$field' with data '", join( "', '", @_ ), "'." );
2605 129 50 33     571 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2606 129 50       440 if( @_ )
2607             {
2608 0         0 my $val;
2609 0 0       0 if( ref( $_[0] ) eq 'HASH' )
    0          
2610             {
2611 0         0 $val = shift( @_ );
2612             }
2613             elsif( ( @_ % 2 ) )
2614             {
2615 0         0 $val = { @_ };
2616             }
2617             else
2618             {
2619 0         0 my $val = shift( @_ );
2620 0         0 return( $self->error( "Method $field takes only a hash or reference to a hash, but value provided ($val) is not supported" ) );
2621             }
2622             # $self->message( 3, "Setting value $val for field $field" );
2623 0         0 $data->{ $field } = Module::Generic::Hash->new( $val );
2624             }
2625 129 50 33     808 if( $data->{ $field } && !$self->_is_object( $data->{ $field } ) )
2626             {
2627 129         874 my $o = Module::Generic::Hash->new( $data->{ $field } );
2628 129         446 $data->{ $field } = $o;
2629             }
2630 129         463 return( $data->{ $field } );
2631             }
2632              
2633             sub _set_get_hash_as_object
2634             {
2635 0     0   0 my $self = shift( @_ );
2636 0         0 my $this = $self->_obj2h;
2637             # $self->message( 3, "Called with args: ", $self->dumper( \@_ ) );
2638 0   0     0 my $field = shift( @_ ) || return( $self->error( "No field provided for _set_get_hash_as_object" ) );
2639 0         0 my $class;
2640 0 0 0     0 @_ = () if( @_ == 1 && !defined( $_[0] ) );
2641 0 0       0 if( @_ )
2642             {
2643             ## No class was provided
2644             # if( ref( $_[0] ) eq 'HASH' )
2645 0 0       0 if( Scalar::Util::reftype( $_[0] ) eq 'HASH' )
    0          
2646             {
2647 0         0 my $new_class = $field;
2648 0         0 $new_class =~ tr/-/_/;
2649 0         0 $new_class =~ s/\_{2,}/_/g;
2650 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
2651 0         0 $class = ref( $self ) . "\::${new_class}";
2652             }
2653             elsif( ref( $_[0] ) )
2654             {
2655 0         0 return( $self->error( "Class name in _set_get_hash_as_object helper method cannot be a reference. Received: \"", overload::StrVal( $_[0] ), "\"." ) );
2656             }
2657             else
2658             {
2659 0         0 $class = shift( @_ );
2660             }
2661             }
2662             else
2663             {
2664 0         0 my $new_class = $field;
2665 0         0 $new_class =~ tr/-/_/;
2666 0         0 $new_class =~ s/\_{2,}/_/g;
2667 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
2668 0         0 $class = ref( $self ) . "\::${new_class}";
2669             }
2670             # my $class = shift( @_ );
2671 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2672 0 0       0 unless( Class::Load::is_class_loaded( $class ) )
2673             {
2674 0         0 my $perl = <<EOT;
2675             package $class;
2676             BEGIN
2677             {
2678             use strict;
2679             use warnings::register;
2680             use Module::Generic;
2681             use parent -norequire, qw( Module::Generic::Dynamic );
2682             };
2683              
2684             1;
2685              
2686             EOT
2687             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" );
2688 0         0 my $rc = eval( $perl );
2689             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" );
2690 0 0       0 die( "Unable to dynamically create module \"$class\" for field \"$field\" based on our own class \"", ref( $self ), "\": $@" ) if( $@ );
2691             }
2692            
2693 0 0       0 if( @_ )
2694             {
2695 0         0 my $hash = shift( @_ );
2696             # my $o = $class->new( $hash );
2697             # print( STDERR ref( $self ), "::_set_get_hash_as_object instantiating hash with ref (", ref( $hash ), ") ", overload::StrVal( $hash ), "\n" );
2698 0         0 my $o = $self->__instantiate_object( $field, $class, $hash );
2699 0     0   0 $self->message( 3, "Resulting object contains: ", sub{ $self->dumper( $o ) } );
  0         0  
2700 0         0 $data->{ $field } = $o;
2701             }
2702            
2703 0 0 0     0 if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) )
2704             {
2705 0         0 my $o = $data->{ $field } = $self->__instantiate_object( $field, $class, $data->{ $field } );
2706             }
2707 0         0 return( $data->{ $field } );
2708             }
2709              
2710             sub _set_get_number
2711             {
2712 4     4   11 my $self = shift( @_ );
2713 4         10 my $field = shift( @_ );
2714 4         9 my $this = $self->_obj2h;
2715 4 50       18 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2716 4 50 66     29 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2717 4 100       11 if( @_ )
2718             {
2719 3         20 $data->{ $field } = Module::Generic::Number->new( shift( @_ ) );
2720             }
2721 4         20 return( $data->{ $field } );
2722             }
2723              
2724             sub _set_get_number_or_object
2725             {
2726 0     0   0 my $self = shift( @_ );
2727 0         0 my $field = shift( @_ );
2728 0         0 my $class = shift( @_ );
2729 0         0 my $this = $self->_obj2h;
2730 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2731 0 0       0 if( @_ )
2732             {
2733 0 0 0     0 if( ref( $_[0] ) eq 'HASH' || Scalar::Util::blessed( $_[0] ) )
2734             {
2735 0         0 return( $self->_set_get_object( $field, $class, @_ ) );
2736             }
2737             else
2738             {
2739 0         0 return( $self->_set_get_number( $field, @_ ) );
2740             }
2741             }
2742 0         0 return( $data->{ $field } );
2743             }
2744              
2745             sub _set_get_object
2746             {
2747 3564     3564   5992 my $self = shift( @_ );
2748 3564         5607 my $field = shift( @_ );
2749 3564         5693 my $class = shift( @_ );
2750 3564         8378 my $this = $self->_obj2h;
2751 3564 50       9227 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2752 6     6   63 no overloading;
  6         14  
  6         17938  
2753             # $self->message( 3, "Called for field '$field' and class '$class'." );
2754 3564 100       7617 if( @_ )
2755             {
2756 3563 50       7820 if( scalar( @_ ) == 1 )
2757             {
2758             ## User removed the value by passing it an undefined value
2759 3563 50       13307 if( !defined( $_[0] ) )
    50          
2760             {
2761 0         0 $data->{ $field } = undef();
2762             }
2763             ## User pass an object
2764             elsif( Scalar::Util::blessed( $_[0] ) )
2765             {
2766 3563         5927 my $o = shift( @_ );
2767 3563 50       12602 return( $self->error( "Object provided (", ref( $o ), ") for $field is not a valid $class object" ) ) if( !$o->isa( "$class" ) );
2768             ## XXX Bad idea:
2769             ## $o->debug( $this->{debug} ) if( $o->can( 'debug' ) );
2770 3563         19438 $data->{ $field } = $o;
2771             }
2772             else
2773             {
2774 0   0     0 my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) );
2775             # $self->message( 3, "Setting field $field value to $o" );
2776 0         0 $data->{ $field } = $o;
2777             }
2778             }
2779             else
2780             {
2781 0   0     0 my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) );
2782             # $self->message( 3, "Setting field $field value to $o" );
2783 0         0 $data->{ $field } = $o;
2784             }
2785             }
2786             ## If nothing has been set for this field, ie no object, but we are called in chain
2787             ## we set a dummy object that will just call itself to avoid perl complaining about undefined value calling a method
2788 3564 50 33     12111 if( !$data->{ $field } && want( 'OBJECT' ) )
2789             {
2790             # print( STDERR __PACKAGE__, "::_set_get_object(): Called in a chain for field $field and class $class, but no object is set, reverting to dummy object\n" );
2791             # $self->message( 3, "Called in a chain, but no object is set, reverting to dummy object." );
2792             ## my $null = Module::Generic::Null->new( $o, { debug => $self->{debug}, has_error => 1 });
2793             ## rreturn( $null );
2794 0   0     0 my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) );
2795 0         0 $data->{ $field } = $o;
2796 0         0 return( $o );
2797             }
2798             # $self->message( 3, "Returning for field '$field' value: ", $self->{ $field } );
2799 3564         10965 return( $data->{ $field } );
2800             }
2801              
2802             sub _set_get_object_array2
2803             {
2804 0     0   0 my $self = shift( @_ );
2805 0         0 my $field = shift( @_ );
2806 0         0 my $class = shift( @_ );
2807 0         0 my $this = $self->_obj2h;
2808 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2809 0 0       0 if( @_ )
2810             {
2811 0         0 my $data_to_process = shift( @_ );
2812 0 0       0 return( $self->error( "I was expecting an array ref, but instead got '$this'. _is_array returned: '", $self->_is_array( $ref ), "'" ) ) if( !$self->_is_array( $data_to_process ) );
2813 0         0 my $arr1 = [];
2814 0         0 foreach my $ref ( @$data_to_process )
2815             {
2816 0 0       0 return( $self->error( "I was expecting an embeded array ref, but instead got '$ref'." ) ) if( ref( $ref ) ne 'ARRAY' );
2817 0         0 my $arr = [];
2818 0         0 for( my $i = 0; $i < scalar( @$ref ); $i++ )
2819             {
2820 0         0 my $o;
2821 0 0       0 if( defined( $ref->[$i] ) )
2822             {
2823 0 0       0 return( $self->error( "Parameter provided for adding object of class $class is not a reference." ) ) if( !ref( $ref->[$i] ) );
2824 0 0       0 if( Scalar::Util::blessed( $ref->[$i] ) )
    0          
2825             {
2826 0 0       0 return( $self->error( "Array offset $i contains an object from class $pack, but was expecting an object of class $class." ) ) if( !$ref->[$i]->isa( $class ) );
2827 0         0 $o = $ref->[$i];
2828             }
2829             elsif( ref( $ref->[$i] ) eq 'HASH' )
2830             {
2831             #$o = $class->new( $h, $ref->[$i] );
2832 0         0 $o = $self->_instantiate_object( $field, $class, $ref->[$i] );
2833             }
2834             else
2835             {
2836 0         0 $self->error( "Warning only: data provided to instaantiate object of class $class is not a hash reference" );
2837             }
2838             }
2839             else
2840             {
2841             #$o = $class->new( $h );
2842 0         0 $o = $self->_instantiate_object( $field, $class );
2843             }
2844 0 0       0 return( $self->error( "Unable to instantiate an object of class $class: ", $class->error ) ) if( !defined( $o ) );
2845             # $o->{ '_parent' } = $self->{ '_parent' };
2846 0         0 push( @$arr, $o );
2847             }
2848 0         0 push( @$arr1, $arr );
2849             }
2850 0         0 $data->{ $field } = $arr1;
2851             }
2852 0         0 return( $data->{ $field } );
2853             }
2854              
2855             sub _set_get_object_array
2856             {
2857 0     0   0 my $self = shift( @_ );
2858 0         0 my $field = shift( @_ );
2859 0         0 my $class = shift( @_ );
2860 0         0 my $this = $self->_obj2h;
2861 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2862 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2863 0 0       0 if( @_ )
2864             {
2865 0         0 my $ref = shift( @_ );
2866 0 0       0 return( $self->error( "I was expecting an array ref, but instead got '$ref'. _is_array returned: '", $self->_is_array( $ref ), "'" ) ) if( !$self->_is_array( $ref ) );
2867 0         0 my $arr = [];
2868 0         0 for( my $i = 0; $i < scalar( @$ref ); $i++ )
2869             {
2870 0 0       0 if( defined( $ref->[$i] ) )
2871             {
2872 0 0       0 return( $self->error( "Array offset $i is not a reference. I was expecting an object of class $class or an hash reference to instantiate an object." ) ) if( !ref( $ref->[$i] ) );
2873 0 0       0 if( Scalar::Util::blessed( $ref->[$i] ) )
    0          
2874             {
2875 0 0       0 return( $self->error( "Array offset $i contains an object from class $pack, but was expecting an object of class $class." ) ) if( !$ref->[$i]->isa( $class ) );
2876 0         0 push( @$arr, $ref->[$i] );
2877             }
2878             elsif( ref( $ref->[$i] ) eq 'HASH' )
2879             {
2880             #$o = $class->new( $h, $ref->[$i] );
2881 0   0     0 $o = $self->_instantiate_object( $field, $class, $ref->[$i] ) || return;
2882 0         0 push( @$arr, $o );
2883             }
2884             else
2885             {
2886 0         0 $self->error( "Warning only: data provided to instantiate object of class $class is not a hash reference" );
2887             }
2888             }
2889             else
2890             {
2891 0         0 return( $self->error( "Array offset $i contains an undefined value. I was expecting an object of class $class." ) );
2892 0   0     0 $o = $self->_instantiate_object( $field, $class ) || return;
2893 0         0 push( @$arr, $o );
2894             }
2895             }
2896 0         0 $data->{ $field } = $arr;
2897             }
2898 0         0 return( $data->{ $field } );
2899             }
2900              
2901             sub _set_get_object_array_object
2902             {
2903 0     0   0 my $self = shift( @_ );
2904 0   0     0 my $field = shift( @_ ) || return( $self->error( "No field name was provided for this array of object." ) );
2905 0   0     0 my $class = shift( @_ ) || return( $self->error( "No class was provided for this array of objects." ) );
2906 0         0 my $this = $self->_obj2h;
2907 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2908 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2909 0 0       0 if( @_ )
2910             {
2911 0 0 0     0 my $that = ( scalar( @_ ) == 1 && UNIVERSAL::isa( $_[0], 'ARRAY' ) ) ? shift( @_ ) : [ @_ ];
2912             ## $self->message( 3, "Received following data to store as array object: ", sub{ $self->dump( $that ) } );
2913 0   0     0 my $ref = $self->_set_get_object_array( $field, $class, $that ) || return;
2914             ## $self->message( 3, "Object array returned is: ", sub{ $self->dump( $ref ) } );
2915 0         0 $data->{ $field } = Module::Generic::Array->new( $ref );
2916             ## $self->message( 3, "Now value for field '$field' is: ", $data->{ $field }, " which contains: '", $data->{ $field }->join( "', '" ), "'." );
2917             }
2918             ## Default value so that call to the caller's method like my_sub->length will not produce something like "Can't call method "length" on an undefined value"
2919             ## Also, this will make i possible to set default value in caller's object and we would turn it into array object.
2920 0 0 0     0 if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) )
2921             {
2922 0         0 my $o = Module::Generic::Array->new( $data->{ $field } );
2923 0         0 $data->{ $field } = $o;
2924             }
2925 0         0 return( $data->{ $field } );
2926             }
2927              
2928             sub _set_get_object_variant
2929             {
2930 0     0   0 my $self = shift( @_ );
2931 0         0 my $field = shift( @_ );
2932             ## The class precisely depends on what we find looking ahead
2933 0         0 my $class = shift( @_ );
2934 0         0 my $this = $self->_obj2h;
2935 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2936 0 0       0 if( @_ )
2937             {
2938 0 0       0 if( ref( $_[0] ) eq 'HASH' )
    0          
2939             {
2940 0         0 my $o = $self->_instantiate_object( $field, $class, @_ );
2941             }
2942             ## AN array of objects hash
2943             elsif( ref( $_[0] ) eq 'ARRAY' )
2944             {
2945 0         0 my $arr = shift( @_ );
2946 0         0 my $res = [];
2947 0         0 foreach my $data ( @$arr )
2948             {
2949 0   0     0 my $o = $self->_instantiate_object( $field, $class, $data ) || return( $self->error( "Unable to create object: ", $self->error ) );
2950 0         0 push( @$res, $o );
2951             }
2952 0         0 $data->{ $field } = $res;
2953             }
2954             }
2955 0         0 return( $data->{ $field } );
2956             }
2957              
2958             sub _set_get_scalar
2959             {
2960 4     4   8 my $self = shift( @_ );
2961 4         7 my $field = shift( @_ );
2962 4         10 my $this = $self->_obj2h;
2963 4 50       10 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2964 4 50       10 if( @_ )
2965             {
2966 0 0       0 my $val = ( @_ == 1 ) ? shift( @_ ) : join( '', @_ );
2967             ## Just in case, we force stringification
2968             ## $val = "$val" if( defined( $val ) );
2969 0 0 0     0 return( $self->error( "Method $field takes only a scalar, but value provided ($val) is a reference" ) ) if( ref( $val ) eq 'HASH' || ref( $val ) eq 'ARRAY' );
2970 0         0 $data->{ $field } = $val;
2971             }
2972 4         18 return( $data->{ $field } );
2973             }
2974              
2975             sub _set_get_scalar_as_object
2976             {
2977 55442     55442   78704 my $self = shift( @_ );
2978 55442         78857 my $field = shift( @_ );
2979 55442         98550 my $this = $self->_obj2h;
2980 55442 50       118332 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2981 55442 100       107792 if( @_ )
2982             {
2983 3630         5214 my $val;
2984 3630 50 33     16537 if( ref( $val ) eq 'SCALAR' || UNIVERSAL::isa( $val, 'SCALAR' ) )
    50          
2985             {
2986 0         0 $val = $$_[0];
2987             }
2988             elsif( ref( $val ) )
2989             {
2990 0         0 return( $self->error( "I was expecting a string or a scalar reference, but instead got '$val'" ) );
2991             }
2992             else
2993             {
2994 3630         6673 $val = shift( @_ );
2995             }
2996 3630         6175 my $o = $data->{ $field };
2997             # $self->message( 3, "Value to use is '$val' and current object is '", ref( $o ), "'." );
2998 3630 100       8097 if( ref( $o ) )
2999             {
3000 3434         8761 $o->set( $val );
3001             }
3002             else
3003             {
3004 196         687 $data->{ $field } = Module::Generic::Scalar->new( $val );
3005             }
3006             # $self->message( 3, "Object now is: '", ref( $data->{ $field } ), "'." );
3007             }
3008             # $self->message( 3, "Checking if object '", ref( $data->{ $field } ), "' is set. Is it an object? ", $self->_is_object( $data->{ $field } ) ? 'yes' : 'no', " and its stringified value is '", $data->{ $field }, "'." );
3009 55442 50 33     116378 if( !$self->_is_object( $data->{ $field } ) || ( $self->_is_object( $data->{ $field } ) && ref( $data->{ $field } ) ne ref( $self ) ) )
      66        
3010             {
3011             # $self->message( 3, "No object is set yet, initiating one." );
3012 55442         132474 $data->{ $field } = Module::Generic::Scalar->new( $data->{ $field } );
3013             }
3014 55442         110791 my $v = $data->{ $field };
3015 55442 100       120765 if( !$v->defined )
3016             {
3017 49053 100       119100 if( Want::want( 'OBJECT' ) )
3018             {
3019 1444         88926 return( Module::Generic::Null->new );
3020             }
3021             else
3022             {
3023 47609         2795677 return;
3024             }
3025             }
3026             else
3027             {
3028 6389         21641 return( $v );
3029             }
3030             }
3031              
3032             sub _set_get_scalar_or_object
3033             {
3034 0     0   0 my $self = shift( @_ );
3035 0         0 my $field = shift( @_ );
3036 0         0 my $class = shift( @_ );
3037 0         0 my $this = $self->_obj2h;
3038 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
3039 0 0       0 if( @_ )
3040             {
3041 0 0 0     0 if( ref( $_[0] ) eq 'HASH' || Scalar::Util::blessed( $_[0] ) )
3042             {
3043 0         0 return( $self->_set_get_object( $field, $class, @_ ) );
3044             }
3045             else
3046             {
3047 0         0 return( $self->_set_get_scalar( $field, @_ ) );
3048             }
3049             }
3050 0 0 0     0 if( !$data->{ $field } && want( 'OBJECT' ) )
3051             {
3052             # $self->message( 3, "Called in a chain for field $field and class $class, but no object is set, reverting to dummy object." );
3053             # $self->messagef( 3, "Expecting void? '%s'. Want scalar? '%s'. Want hash? '%s', wantref: '%s'", want('VOID'), want('SCALAR'), Want::want('HASH'), Want::wantref() );
3054 0         0 my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 });
3055 0         0 rreturn( $null );
3056             }
3057 0         0 return( $data->{ $field } );
3058             }
3059              
3060             sub _set_get_uri
3061             {
3062 0     0   0 my $self = shift( @_ );
3063 0         0 my $field = shift( @_ );
3064 0         0 my $this = $self->_obj2h;
3065 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
3066 0 0       0 if( @_ )
3067             {
3068 0         0 try
3069 0     0   0 {
3070 0 0       0 require URI if( !$self->_is_class_loaded( 'URI' ) );
3071             }
3072 0 0       0 catch( $e )
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
3073 0     0   0 {
3074 0         0 return( $self->error( "Error trying to load module URI: $e" ) );
3075 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
3076            
3077 0         0 my $str = shift( @_ );
3078 0 0 0     0 if( Scalar::Util::blessed( $str ) && $str->isa( 'URI' ) )
    0 0        
    0 0        
    0          
3079             {
3080 0         0 $data->{ $field } = $str;
3081             }
3082             elsif( defined( $str ) && ( $str =~ /^[a-zA-Z]+:\/{2}/ || $str =~ /^urn\:[a-z]+\:/ || $str =~ /^[a-z]+\:/ ) )
3083             {
3084 0         0 $data->{ $field } = URI->new( $str );
3085 0 0       0 warn( "URI subclass is missing to handle this specific URI '$str'\n" ) if( !$data->{ $field }->has_recognized_scheme );
3086             }
3087             ## Is it an absolute path?
3088             elsif( substr( $str, 0, 1 ) eq '/' )
3089             {
3090 0         0 $data->{ $field } = URI->new( $str );
3091             }
3092             elsif( defined( $str ) )
3093             {
3094 0         0 return( $self->error( "URI value provided '$str' does not look like an URI, so I do not know what to do with it." ) );
3095             }
3096             else
3097             {
3098 0         0 $data->{ $field } = undef();
3099             }
3100             }
3101 0         0 return( $data->{ $field } );
3102             }
3103              
3104 1   33 1   167 sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); }
3105              
3106             sub __dbh
3107             {
3108 0     0   0 my $self = shift( @_ );
3109 0   0     0 my $class = ref( $self ) || $self;
3110 0         0 my $this = $self->_obj2h;
3111 0 0       0 if( !$this->{ '__dbh' } )
3112             {
3113 0 0       0 return( '' ) if( !${ "$class\::DB_DSN" } );
  0         0  
3114 0         0 require DBI;
3115             ## Connecting to database
3116 0         0 my $db_opt = {};
3117 0 0       0 $db_opt->{RaiseError} = ${ "$class\::DB_RAISE_ERROR" } if( length( ${ "$class\::DB_RAISE_ERROR" } ) );
  0         0  
  0         0  
3118 0 0       0 $db_opt->{AutoCommit} = ${ "$class\::DB_AUTO_COMMIT" } if( length( ${ "$class\::DB_AUTO_COMMIT" } ) );
  0         0  
  0         0  
3119 0 0       0 $db_opt->{PrintError} = ${ "$class\::DB_PRINT_ERROR" } if( length( ${ "$class\::DB_PRINT_ERROR" } ) );
  0         0  
  0         0  
3120 0 0       0 $db_opt->{ShowErrorStatement} = ${ "$class\::DB_SHOW_ERROR_STATEMENT" } if( length( ${ "$class\::DB_SHOW_ERROR_STATEMENT" } ) );
  0         0  
  0         0  
3121 0 0       0 $db_opt->{client_encoding} = ${ "$class\::DB_CLIENT_ENCODING" } if( length( ${ "$class\::DB_CLIENT_ENCODING" } ) );
  0         0  
  0         0  
3122             my $dbh = DBI->connect_cached( ${ "$class\::DB_DSN" } ) ||
3123 0   0     0 die( "Unable to connect to sql database with dsn '", ${ "$class\::DB_DSN" }, "'\n" );
3124 0 0       0 $dbh->{pg_server_prepare} = 1 if( ${ "$class\::DB_SERVER_PREPARE" } );
  0         0  
3125 0         0 $this->{ '__dbh' } = $dbh;
3126             }
3127 0         0 return( $this->{ '__dbh' } );
3128             }
3129              
3130             sub DEBUG
3131             {
3132 0     0 1 0 my $self = shift( @_ );
3133 0   0     0 my $pkg = ref( $self ) || $self;
3134 0         0 my $this = $self->_obj2h;
3135 0         0 return( ${ $pkg . '::DEBUG' } );
  0         0  
3136             }
3137              
3138             sub VERBOSE
3139             {
3140 0     0 1 0 my $self = shift( @_ );
3141 0   0     0 my $pkg = ref( $self ) || $self;
3142 0         0 my $this = $self->_obj2h;
3143 0         0 return( ${ $pkg . '::VERBOSE' } );
  0         0  
3144             }
3145              
3146             AUTOLOAD
3147             {
3148 0     0   0 my $self;
3149             # $self = shift( @_ ) if( ref( $_[ 0 ] ) && index( ref( $_[ 0 ] ), 'Module::' ) != -1 );
3150 0 0 0     0 $self = shift( @_ ) if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic' ) );
3151 0         0 my( $class, $meth );
3152 0   0     0 $class = ref( $self ) || $self;
3153             ## Leave this commented out as we need it a little bit lower
3154 0         0 my( $pkg, $file, $line ) = caller();
3155 0         0 my $sub = ( caller( 1 ) )[ 3 ];
3156 6     6   63 no overloading;
  6         15  
  6         2351  
3157 0 0       0 if( $sub eq 'Module::Generic::AUTOLOAD' )
3158             {
3159 0         0 my $mesg = "Module::Generic::AUTOLOAD (called at line '$line') is looping for autoloadable method '$AUTOLOAD' and args '" . join( "', '", @_ ) . "'.";
3160 0 0       0 if( $MOD_PERL )
3161             {
3162 0         0 my $r = Apache2::RequestUtil->request;
3163 0         0 $r->log_error( $mesg );
3164             }
3165             else
3166             {
3167 0         0 print( $err $mesg, "\n" );
3168             }
3169 0         0 exit( 0 );
3170             }
3171 0         0 $meth = $AUTOLOAD;
3172 0 0       0 if( CORE::index( $meth, '::' ) != -1 )
3173             {
3174 0         0 my $idx = rindex( $meth, '::' );
3175 0         0 $class = substr( $meth, 0, $idx );
3176 0         0 $meth = substr( $meth, $idx + 2 );
3177             }
3178            
3179 0 0 0     0 if( $self && $self->can( 'autoload' ) )
3180             {
3181 0 0       0 if( my $code = $self->autoload( $meth ) )
3182             {
3183 0 0       0 return( $code->( $self ) ) if( $code );
3184             }
3185             }
3186            
3187 0         0 $meth = lc( $meth );
3188 0         0 my $this;
3189 0 0       0 $this = $self->_obj2h if( defined( $self ) );
3190 0         0 my $data;
3191 0 0       0 if( $this )
3192             {
3193 0 0       0 $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
3194             }
3195             ## CORE::print( STDERR "Storing '$meth' with value ", join( ', ', @_ ), "\n" );
3196 0 0 0     0 if( $data && CORE::exists( $data->{ $meth } ) )
    0 0        
    0 0        
3197             {
3198 0 0       0 if( @_ )
3199             {
3200 0 0       0 my $val = ( @_ == 1 ) ? shift( @_ ) : [ @_ ];
3201 0         0 $data->{ $meth } = $val;
3202             }
3203 0 0       0 if( wantarray() )
3204             {
3205 0 0       0 if( ref( $data->{ $meth } ) eq 'ARRAY' )
    0          
3206             {
3207 0         0 return( @{ $data->{ $meth } } );
  0         0  
3208             }
3209             elsif( ref( $data->{ $meth } ) eq 'HASH' )
3210             {
3211 0         0 return( %{ $data->{ $meth } } );
  0         0  
3212             }
3213             else
3214             {
3215 0         0 return( ( $data->{ $meth } ) );
3216             }
3217             }
3218             else
3219             {
3220 0         0 return( $data->{ $meth } );
3221             }
3222             }
3223             ## Because, if it does not exist in the caller's package,
3224             ## calling the method will get us here infinitly,
3225             ## since UNIVERSAL::can will somehow return true even if it does not exist
3226 0         0 elsif( $self && $self->can( $meth ) && defined( &{ "$class\::$meth" } ) )
3227             {
3228 0         0 return( $self->$meth( @_ ) );
3229             }
3230             elsif( defined( &$meth ) )
3231             {
3232 6     6   53 no strict 'refs';
  6         15  
  6         5152  
3233 0         0 *$meth = \&$meth;
3234 0         0 return( &$meth( @_ ) );
3235             }
3236             else
3237             {
3238 0         0 my $sub = $AUTOLOAD;
3239 0         0 my( $pkg, $func ) = ( $sub =~ /(.*)::([^:]+)$/ );
3240 0         0 my $mesg = "Module::Generic::AUTOLOAD(): Searching for routine '$func' from package '$pkg'.";
3241 0 0       0 if( $MOD_PERL )
3242             {
3243 0         0 my $r = Apache2::RequestUtil->request;
3244 0         0 $r->log_error( $mesg );
3245             }
3246             else
3247             {
3248 0 0       0 print( STDERR $mesg . "\n" ) if( $DEBUG );
3249             }
3250 0         0 $pkg =~ s/::/\//g;
3251 0 0       0 if( defined( $filename = $INC{ "$pkg.pm" } ) )
3252             {
3253 0         0 $filename =~ s/^(.*)$pkg\.pm\z/$1auto\/$pkg\/$func.al/s;
3254             ## print( STDERR "Found possible autoloadable file '$filename'.\n" );
3255 0 0       0 if( -r( $filename ) )
3256             {
3257 0 0       0 unless( $filename =~ m|^/|s )
3258             {
3259 0         0 $filename = "./$filename";
3260             }
3261             }
3262             else
3263             {
3264 0         0 $filename = undef();
3265             }
3266             }
3267 0 0       0 if( !defined( $filename ) )
3268             {
3269 0         0 $filename = "auto/$sub.al";
3270 0         0 $filename =~ s/::/\//g;
3271             }
3272 0         0 my $save = $@;
3273             eval
3274 0         0 {
3275 0     0   0 local $SIG{ '__DIE__' } = sub{ };
3276 0     0   0 local $SIG{ '__WARN__' } = sub{ };
3277 0         0 require $filename;
3278             };
3279 0 0       0 if( $@ )
3280             {
3281 0 0       0 if( substr( $sub, -9 ) eq '::DESTROY' )
3282             {
3283 0     0   0 *$sub = sub {};
3284             }
3285             else
3286             {
3287             # The load might just have failed because the filename was too
3288             # long for some old SVR3 systems which treat long names as errors.
3289             # If we can succesfully truncate a long name then it's worth a go.
3290             # There is a slight risk that we could pick up the wrong file here
3291             # but autosplit should have warned about that when splitting.
3292 0 0       0 if( $filename =~ s/(\w{12,})\.al$/substr( $1, 0, 11 ) . ".al"/e )
  0         0  
3293             {
3294             eval
3295 0         0 {
3296 0     0   0 local $SIG{ '__DIE__' } = sub{ };
3297 0     0   0 local $SIG{ '__WARN__' } = sub{ };
3298 0         0 require $filename
3299             };
3300             }
3301 0 0       0 if( $@ )
3302             {
3303             #$@ =~ s/ at .*\n//;
3304             #my $error = $@;
3305             #CORE::die( $error );
3306             ## die( "Method $meth() is not defined in class $class and not autoloadable.\n" );
3307             ## print( $err "EXTRA_AUTOLOAD is ", defined( &{ "${class}::EXTRA_AUTOLOAD" } ) ? "defined" : "not defined", " in package '$class'.\n" );
3308             ## if( $self && defined( &{ "${class}::EXTRA_AUTOLOAD" } ) )
3309             ## Look up in our caller's @ISA to see if there is any package that has this special
3310             ## EXTRA_AUTOLOAD() sub routine
3311 0         0 my $sub_ref = '';
3312 0 0       0 die( "EXTRA_AUTOLOAD: ", join( "', '", @_ ), "\n" ) if( $func eq 'EXTRA_AUTOLOAD' );
3313 0 0 0     0 if( $self && $func ne 'EXTRA_AUTOLOAD' && ( $sub_ref = $self->will( 'EXTRA_AUTOLOAD' ) ) )
      0        
3314             {
3315             ## return( &{ "${class}::EXTRA_AUTOLOAD" }( $self, $meth ) );
3316             ## return( $self->EXTRA_AUTOLOAD( $AUTOLOAD, @_ ) );
3317 0         0 return( $sub_ref->( $self, $AUTOLOAD, @_ ) );
3318             }
3319             else
3320             {
3321 0         0 my $keys = CORE::join( ',', keys( %$data ) );
3322 0         0 my $msg = "Method $func() is not defined in class $class and not autoloadable in package $pkg in file $file at line $line.\n";
3323 0         0 $msg .= "There are actually the following fields in the object '$self': '$keys'\n";
3324 0         0 die( $msg );
3325             }
3326             }
3327             }
3328             }
3329 0         0 $@ = $save;
3330 0 0       0 if( $DEBUG )
3331             {
3332 0         0 my $mesg = "unshifting '$self' to args for sub '$sub'.";
3333 0 0       0 if( $MOD_PERL )
3334             {
3335 0         0 my $r = Apache2::RequestUtil->request;
3336 0         0 $r->log_error( $mesg );
3337             }
3338             else
3339             {
3340 0         0 print( $err "$mesg\n" );
3341             }
3342             }
3343 0 0       0 unshift( @_, $self ) if( $self );
3344             #use overloading;
3345 0         0 goto &$sub;
3346             ## die( "Method $meth() is not defined in class $class and not autoloadable.\n" );
3347             ## my $mesg = "Method $meth() is not defined in class $class and not autoloadable.";
3348             ## $self->{ 'fatal' } ? die( $mesg ) : return( $self->error( $mesg ) );
3349             }
3350             };
3351              
3352             DESTROY
3353       0     {
3354             ## Do nothing
3355             };
3356              
3357             package Module::Generic::Exception;
3358             BEGIN
3359             {
3360 6     6   55 use strict;
  6         12  
  6         181  
3361 6     6   35 use parent qw( Module::Generic );
  6         60  
  6         60  
3362 6     6   514 use Scalar::Util;
  6         18  
  6         429  
3363 6     6   62 use Devel::StackTrace;
  6         13  
  6         527  
3364             use overload ('""' => 'as_string',
3365 0     0   0 '==' => sub { _obj_eq(@_) },
3366 0     0   0 '!=' => sub { !_obj_eq(@_) },
3367 6         79 fallback => 1,
3368 6     6   45 );
  6         14  
3369 6     6   4077 our( $VERSION ) = '0.1.0';
3370             };
3371              
3372             sub init
3373             {
3374 1     1   4 my $self = shift( @_ );
3375             # require Data::Dumper::Concise;
3376             # print( STDERR __PACKAGE__, "::init() Got here with args: ", Data::Dumper::Concise::Dumper( \@_ ), "\n" );
3377 1         95 $self->{code} = '';
3378 1         5 $self->{type} = '';
3379 1         3 $self->{file} = '';
3380 1         4 $self->{line} = '';
3381 1         4 $self->{message} = '';
3382 1         3 $self->{package} = '';
3383 1         3 $self->{retry_after} = '';
3384 1         4 $self->{subroutine} = '';
3385 1         4 my $args = {};
3386 1 50       5 if( @_ )
3387             {
3388 1 50 33     11 if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic::Exception' ) )
    50          
3389             {
3390 0         0 $args->{object} = shift( @_ );
3391             }
3392             elsif( ref( $_[0] ) eq 'HASH' )
3393             {
3394 1         5 $args = shift( @_ );
3395             }
3396             else
3397             {
3398 0 0       0 $args->{message} = join( '', map( ref( $_ ) eq 'CODE' ? $_->() : $_, @_ ) );
3399             }
3400             }
3401             # $self->SUPER::init( @_ );
3402 1   50     3 my $skip_frame = $args->{skip_frames} || 0;
3403             ## Skip one frame to exclude us
3404 1         4 $skip_frame++;
3405 1         12 my $trace = Devel::StackTrace->new( skip_frames => $skip_frame, indent => 1 );
3406 1         288 my $frame = $trace->next_frame;
3407 1         393 my $frame2 = $trace->next_frame;
3408 1         20 $trace->reset_pointer;
3409 1 50 33     12 if( ref( $args->{object} ) && Scalar::Util::blessed( $args->{object} ) && $args->{object}->isa( 'Module::Generic::Exception' ) )
      33        
3410             {
3411 0         0 my $o = $args->{object};
3412 0         0 $self->{message} = $o->message;
3413 0         0 $self->{code} = $o->code;
3414 0         0 $self->{type} = $o->type;
3415 0         0 $self->{retry_after} = $o->retry_after;
3416             }
3417             else
3418             {
3419             # print( STDERR __PACKAGE__, "::init() Got here with args: ", Data::Dumper::Concise::Dumper( $args ), "\n" );
3420 1   50     5 $self->{message} = $args->{message} || '';
3421 1 50       4 $self->{code} = $args->{code} if( exists( $args->{code} ) );
3422 1 50       5 $self->{type} = $args->{type} if( exists( $args->{type} ) );
3423 1 50       5 $self->{retry_after} = $args->{retry_after} if( exists( $args->{retry_after} ) );
3424             ## I do not want to alter the original hash reference, which may adversely affect the calling code if they depend on its content for further execution for example.
3425 1         3 my $copy = {};
3426 1         6 %$copy = %$args;
3427 1         5 CORE::delete( @$copy{ qw( message code type retry_after skip_frames ) } );
3428             # print( STDERR __PACKAGE__, "::init() Following non-standard keys to set up: '", join( "', '", sort( keys( %$copy ) ) ), "'\n" );
3429             ## Do we have some non-standard parameters?
3430 1         5 foreach my $p ( keys( %$copy ) )
3431             {
3432 0         0 my $p2 = $p;
3433 0         0 $p2 =~ tr/-/_/;
3434 0         0 $p2 =~ s/[^a-zA-Z0-9\_]+//g;
3435 0         0 $p2 =~ s/^\d+//g;
3436 0         0 $self->$p2( $copy->{ $p } );
3437             }
3438             }
3439 1         6 $self->{file} = $frame->filename;
3440 1         9 $self->{line} = $frame->line;
3441             ## The caller sub routine ( caller( n ) )[3] returns the sub called by our caller instead of the sub that called our caller, so we go one frame back to get it
3442 1         10 $self->{subroutine} = $frame2->subroutine;
3443 1         9 $self->{package} = $frame->package;
3444 1         7 $self->{trace} = $trace;
3445 1         4 return( $self );
3446             }
3447              
3448             #sub as_string { return( $_[0]->{message} ); }
3449             ## This is important as stringification is called by die, so as per the manual page, we need to end with new line
3450             ## And will add the stack trace
3451             sub as_string
3452             {
3453 6     6   58 no overloading;
  6         16  
  6         2641  
3454 1     1   4 my $self = shift( @_ );
3455 1         4 my $str = $self->message;
3456 1         4 $str =~ s/\r?\n$//g;
3457 1         5 $str .= sprintf( " within package %s at line %d in file %s\n%s", $self->package, $self->line, $self->file, $self->trace->as_string );
3458 1         334 return( $str );
3459             }
3460              
3461             ## if( Module::Generic::Exception->caught( $e ) ) { # do something, it's ours }
3462             sub caught
3463             {
3464 0     0   0 my( $class, $e ) = @_;
3465 0 0       0 return if( ref( $class ) );
3466 0 0 0     0 return unless( Scalar::Util::blessed( $e ) && $e->isa( $class ) );
3467 0         0 return( $e );
3468             }
3469              
3470 0     0   0 sub code { return( shift->_set_get_scalar( 'code', @_ ) ); }
3471              
3472 1     1   24 sub file { return( shift->_set_get_scalar( 'file', @_ ) ); }
3473              
3474 1     1   3 sub line { return( shift->_set_get_scalar( 'line', @_ ) ); }
3475              
3476 1     1   8 sub message { return( shift->_set_get_scalar( 'message', @_ ) ); }
3477              
3478 1     1   4 sub package { return( shift->_set_get_scalar( 'package', @_ ) ); }
3479              
3480             sub rethrow
3481             {
3482 0     0   0 my $self = shift( @_ );
3483 0 0       0 return if( !Scalar::Util::blessed( $self ) );
3484 0         0 die( $self );
3485             }
3486              
3487 0     0   0 sub retry_after { return( shift->_set_get_scalar( 'retry_after', @_ ) ); }
3488              
3489 0     0   0 sub subroutine { return( shift->_set_get_scalar( 'subroutine', @_ ) ); }
3490              
3491             sub throw
3492             {
3493 0     0   0 my $self = shift( @_ );
3494 0         0 my $msg = shift( @_ );
3495 0         0 my $e = $self->new({
3496             skip_frames => 1,
3497             message => $msg,
3498             });
3499 0         0 die( $e );
3500             }
3501              
3502             ## Devel::StackTrace has a stringification overloaded so users can use the object to get more information or simply use it as a string to get the stack trace equivalent of doing $trace->as_string
3503 1     1   7 sub trace { return( shift->_set_get_object( 'trace', 'Devel::StackTrace', @_ ) ); }
3504              
3505 0     0   0 sub type { return( shift->_set_get_scalar( 'type', @_ ) ); }
3506              
3507             sub _obj_eq
3508             {
3509             ##return overload::StrVal( $_[0] ) eq overload::StrVal( $_[1] );
3510 6     6   45 no overloading;
  6         15  
  6         1120  
3511 0     0   0 my $self = shift( @_ );
3512 0         0 my $other = shift( @_ );
3513 0         0 my $me;
3514 0 0 0     0 if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Exception' ) )
    0          
3515             {
3516 0 0 0     0 if( $self->message eq $other->message &&
      0        
3517             $self->file eq $other->file &&
3518             $self->line == $other->line )
3519             {
3520 0         0 return( 1 );
3521             }
3522             else
3523             {
3524 0         0 return( 0 );
3525             }
3526             }
3527             ## Compare error message
3528             elsif( !ref( $other ) )
3529             {
3530 0         0 my $me = $self->message;
3531 0         0 return( $me eq $other );
3532             }
3533             ## Otherwise some reference data to which we cannot compare
3534 0         0 return( 0 ) ;
3535             }
3536              
3537             AUTOLOAD
3538             {
3539 0     0   0 my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
3540             # my( $class, $method ) = our $AUTOLOAD =~ /^(.*?)::([^\:]+)$/;
3541 6     6   44 no overloading;
  6         15  
  6         830  
3542 0         0 my $self = shift( @_ );
3543 0   0     0 my $class = ref( $self ) || $self;
3544 0         0 my $code;
3545             # print( STDERR __PACKAGE__, "::$method(): Called with value '$_[0]'\n" );
3546 0 0       0 if( $code = $self->can( $method ) )
3547             {
3548 0         0 return( $code->( @_ ) );
3549             }
3550             ## elsif( CORE::exists( $self->{ $method } ) )
3551             else
3552             {
3553 0         0 eval( "sub ${class}::${method} { return( shift->_set_get_scalar( '$method', \@_ ) ); }" );
3554 0 0       0 die( $@ ) if( $@ );
3555 0         0 return( $self->$method( @_ ) );
3556             }
3557             };
3558              
3559             ## Purpose of this package is to provide an object that will be invoked in chain without breaking and then return undef at the end
3560             ## Normally if a method in the chain returns undef, perl will then complain that the following method in the chain was called on an undefined value. This Null package alleviate this problem.
3561             ## This is an original idea from https://stackoverflow.com/users/2766176/brian-d-foy as document in this Stackoverflow thread here: https://stackoverflow.com/a/7068271/4814971
3562             ## And also by user "particle" in this perl monks discussion here: https://www.perlmonks.org/?node_id=265214
3563             package Module::Generic::Null;
3564             BEGIN
3565             {
3566 6     6   41 use strict;
  6         12  
  6         143  
3567 6     6   34 use Want;
  6         14  
  6         819  
3568 0     0   0 use overload ('""' => sub{ '' },
3569 0     0   0 'eq' => sub { _obj_eq(@_) },
3570 0     0   0 'ne' => sub { !_obj_eq(@_) },
3571 6         58 fallback => 1,
3572 6     6   45 );
  6         14  
3573 6     6   552 use Want;
  6         14  
  6         336  
3574 6     6   621 our( $VERSION ) = '0.2.0';
3575             };
3576              
3577             sub new
3578             {
3579 1444     1444   2627 my $this = shift( @_ );
3580 1444   33     4912 my $class = ref( $this ) || $this;
3581 1444         2345 my $error_object = shift( @_ );
3582 1444 50 33     4568 my $hash = ( @_ == 1 && ref( $_[0] ) ? shift( @_ ) : { @_ } );
3583 1444         3295 $hash->{has_error} = $error_object;
3584 1444         9490 return( bless( $hash => $class ) );
3585             }
3586              
3587             sub _obj_eq
3588             {
3589             ##return overload::StrVal( $_[0] ) eq overload::StrVal( $_[1] );
3590 6     6   39 no overloading;
  6         12  
  6         1235  
3591 0     0   0 my $self = shift( @_ );
3592 0         0 my $other = shift( @_ );
3593 0         0 my $me;
3594 0 0 0     0 if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Null' ) )
    0          
3595             {
3596 0         0 return( $self eq $other );
3597             }
3598             ## Compare error message
3599             elsif( !ref( $other ) )
3600             {
3601 0         0 return( '' eq $other );
3602             }
3603             ## Otherwise some reference data to which we cannot compare
3604 0         0 return( 0 ) ;
3605             }
3606              
3607             AUTOLOAD
3608             {
3609 1444     1444   10282 my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
3610             # my $debug = $_[0]->{debug};
3611             # my( $pack, $file, $file ) = caller;
3612             # my $sub = ( caller( 1 ) )[3];
3613             # print( STDERR __PACKAGE__, ": Method $method called in package $pack in file $file at line $line from subroutine $sub (AUTOLOAD = $AUTOLOAD)\n" ) if( $debug );
3614             ## If we are chained, return our null object, so the chain continues to work
3615 1444 50       3956 if( want( 'OBJECT' ) )
3616             {
3617             ## No, this is NOT a typo. rreturn() is a function of module Want
3618 0         0 rreturn( $_[0] );
3619             }
3620             ## Otherwise, we return undef; Empty return returns undef in scalar context and empty list in list context
3621 1444         67293 return;
3622             };
3623              
3624       0     DESTROY {};
3625              
3626             package Module::Generic::Dynamic;
3627             BEGIN
3628             {
3629 6     6   58 use strict;
  6         13  
  6         156  
3630 6     6   30 use parent qw( Module::Generic );
  6         14  
  6         29  
3631 6     6   350 use warnings::register;
  6         13  
  6         801  
3632 6     6   41 use Scalar::Util ();
  6         12  
  6         157  
3633             # use Class::ISA;
3634 6     6   5270 our( $VERSION ) = '0.1.0';
3635             };
3636              
3637             sub new
3638             {
3639 0     0   0 my $this = shift( @_ );
3640 0   0     0 my $class = ref( $this ) || $this;
3641 0         0 my $self = bless( {} => $class );
3642 0         0 my $data = $self->{_data} = {};
3643             ## A Module::Generic object standard parameter
3644 0         0 $self->{_data_repo} = '_data';
3645 0         0 my $hash = {};
3646 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
3647 0 0 0     0 if( scalar( @_ ) == 1 && Scalar::Util::reftype( $_[0] ) eq 'HASH' )
    0          
3648             {
3649 0         0 $hash = shift( @_ );
3650             }
3651             elsif( @_ )
3652             {
3653 0 0       0 CORE::warn( "Parameter provided is not an hash reference: '", join( "', '", @_ ), "'\n" ) if( $this->_warnings_is_enabled );
3654             }
3655             ## $self->message( 3, "Data provided are: ", sub{ $self->dumper( $hash ) } );
3656             ## print( STDERR __PACKAGE__, "::new(): Got for hash: '", join( "', '", sort( keys( %$hash ) ) ), "'\n" );
3657             local $make_class = sub
3658             {
3659 0     0   0 my $k = shift( @_ );
3660 0         0 my $new_class = $k;
3661 0         0 $new_class =~ tr/-/_/;
3662 0         0 $new_class =~ s/\_{2,}/_/g;
3663 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
3664 0         0 $new_class = "${class}\::${new_class}";
3665             ## Sanitise the key which will serve as a method name
3666 0         0 my $clean_field = $k;
3667 0         0 $clean_field =~ tr/-/_/;
3668 0         0 $clean_field =~ s/\_{2,}/_/g;
3669 0         0 $clean_field =~ s/[^a-zA-Z0-9\_]+//g;
3670 0         0 $clean_field =~ s/^\d+//g;
3671             ## print( STDERR __PACKAGE__, "::new(): \$clean_field now is '$clean_field'\n" );
3672 0         0 my $perl = <<EOT;
3673             package $new_class;
3674             BEGIN
3675             {
3676             use strict;
3677             use Module::Generic;
3678             use parent -norequire, qw( Module::Generic::Dynamic );
3679             };
3680              
3681             1;
3682              
3683             EOT
3684             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" );
3685 0         0 my $rc = eval( $perl );
3686             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" );
3687 0 0       0 die( "Unable to dynamically create module $new_class: $@" ) if( $@ );
3688 0         0 return( $new_class, $clean_field );
3689 0         0 };
3690            
3691 0         0 foreach my $k ( sort( keys( %$hash ) ) )
3692             {
3693 0 0       0 if( ref( $hash->{ $k } ) eq 'HASH' )
    0          
    0          
3694             {
3695 0         0 my $clean_field = $k;
3696 0         0 $clean_field =~ tr/-/_/;
3697 0         0 $clean_field =~ s/\_{2,}/_/g;
3698 0         0 $clean_field =~ s/[^a-zA-Z0-9\_]+//g;
3699 0         0 $clean_field =~ s/^\d+//g;
3700             # my( $new_class, $clean_field ) = $make_class->( $k );
3701             # print( STDERR __PACKAGE__, "::new(): Is hash looping? ", ( $hash->{ $k }->{_looping} ? 'yes' : 'no' ), " (", ref( $hash->{ $k }->{_looping} ), ")\n" );
3702             # my $o = $hash->{ $k }->{_looping} ? $hash->{ $k }->{_looping} : $new_class->new( $hash->{ $k } );
3703             # $data->{ $clean_field } = $o;
3704             # $hash->{ $k }->{_looping} = $o;
3705 0         0 eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_object( $clean_field, '$new_class', \@_ ) ); }" );
3706 0 0       0 die( $@ ) if( $@ );
3707 0         0 $self->$clean_field( $hash->{ $k } );
3708             }
3709             elsif( ref( $hash->{ $k } ) eq 'ARRAY' )
3710             {
3711 0         0 my( $new_class, $clean_field ) = $make_class->( $k );
3712             # print( STDERR __PACKAGE__, "::new() found an array for key $k, creating objects for class $new_class\n" );
3713             ## We take a peek at what we have to determine how we will handle the data
3714 0 0       0 my $mode = lc( scalar( @{$hash->{ $k }} ) ? ref( $hash->{ $k }->[0] ) : '' );
  0         0  
3715 0 0       0 if( $mode eq 'hash' )
3716             {
3717 0         0 my $all = [];
3718 0         0 foreach my $this ( @{$hash->{ $k }} )
  0         0  
3719             {
3720 0 0       0 my $o = $this->{_looping} ? $this->{_looping} : $new_class->new( $this );
3721 0         0 $this->{_looping} = $o;
3722 0         0 CORE::push( @$all, $o );
3723             }
3724             # $data->{ $clean_field } = $all;
3725 0         0 eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_object_array_object( '$clean_field', '$new_class', \@_ ) ); }" );
3726             }
3727             else
3728             {
3729             # $data->{ $clean_field } = $hash->{ $k };
3730 0         0 eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_array_as_object( '$clean_field', \@_ ) ); }" );
3731             }
3732 0 0       0 die( $@ ) if( $@ );
3733 0         0 $self->$clean_field( $hash->{ $k } );
3734             }
3735             elsif( !ref( $hash->{ $k } ) )
3736             {
3737 0         0 my $clean_field = $k;
3738 0         0 $clean_field =~ tr/-/_/;
3739 0         0 $clean_field =~ s/\_{2,}/_/g;
3740 0         0 $clean_field =~ s/[^a-zA-Z0-9\_]+//g;
3741 0         0 $clean_field =~ s/^\d+//g;
3742 0         0 eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_scalar_as_object( '$clean_field', \@_ ) ); }" );
3743 0         0 $self->$clean_field( $hash->{ $k } );
3744             }
3745             else
3746             {
3747 0         0 $self->$k( $hash->{ $k } );
3748             }
3749             }
3750 0         0 return( $self );
3751             }
3752              
3753             AUTOLOAD
3754             {
3755 0     0   0 my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
3756             # my( $class, $method ) = our $AUTOLOAD =~ /^(.*?)::([^\:]+)$/;
3757 6     6   52 no overloading;
  6         19  
  6         1445  
3758 0         0 my $self = shift( @_ );
3759 0   0     0 my $class = ref( $self ) || $self;
3760 0         0 my $code;
3761             # print( STDERR __PACKAGE__, "::$method(): Called\n" );
3762 0 0       0 if( $code = $self->can( $method ) )
3763             {
3764 0         0 return( $code->( @_ ) );
3765             }
3766             ## elsif( CORE::exists( $self->{ $method } ) )
3767             else
3768             {
3769 0         0 my $ref = lc( ref( $_[0] ) );
3770 0         0 my $handler = '_set_get_scalar_as_object';
3771             # if( @_ && ( $ref eq 'hash' || $ref eq 'array' ) )
3772 0 0 0     0 if( $ref eq 'hash' || $ref eq 'array' )
    0 0        
      0        
      0        
      0        
3773             {
3774             # print( STDERR __PACKAGE__, "::$method(): using handler $handler for type $ref\n" );
3775 0         0 $handler = "_set_get_${ref}_as_object";
3776             }
3777             elsif( $ref eq 'json::pp::boolean' ||
3778             $ref eq 'module::generic::boolean' ||
3779             ( $ref eq 'scalar' && ( $$ref == 1 || $$ref == 0 ) ) )
3780             {
3781 0         0 $handler = '_set_get_boolean';
3782             }
3783 0         0 eval( "sub ${class}::${method} { return( shift->$handler( '$method', \@_ ) ); }" );
3784 0 0       0 die( $@ ) if( $@ );
3785             ## $self->message( 3, "Calling method '$method' with data: ", sub{ $self->printer( @_ ) } );
3786 0         0 return( $self->$method( @_ ) );
3787             }
3788             };
3789              
3790             package Module::Generic::Boolean;
3791             BEGIN
3792             {
3793 6     6   4308 use common::sense;
  6         95  
  6         33  
3794             use overload
3795 3736     3736   16211 "0+" => sub { ${$_[0]} },
  3736         14614  
3796 0     0   0 "++" => sub { $_[0] = ${$_[0]} + 1 },
  0         0  
3797 0     0   0 "--" => sub { $_[0] = ${$_[0]} - 1 },
  0         0  
3798 6     6   1247 fallback => 1;
  6         13  
  6         65  
3799             # *Module::Generic::Boolean:: = *JSON::PP::Boolean::;
3800 6     6   2485 our( $VERSION ) = '0.1.0';
3801             };
3802              
3803 7 100   7   61 sub new { return( $_[1] ? $true : $false ); }
3804              
3805 0     0   0 sub defined { return( 1 ); }
3806              
3807             our $true = do{ bless( \( my $dummy = 1 ) => Module::Generic::Boolean ) };
3808             our $false = do{ bless( \( my $dummy = 0 ) => Module::Generic::Boolean ) };
3809              
3810 282     282   709 sub true () { $true }
3811 148     148   402 sub false () { $false }
3812              
3813 0     0   0 sub is_bool ($) { UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) }
3814 0 0   0   0 sub is_true ($) { $_[0] && UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) }
3815 0 0   0   0 sub is_false ($) { !$_[0] && UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) }
3816              
3817             sub TO_JSON
3818             {
3819             ## JSON does not check that the value is a proper true or false. It stupidly assumes this is a string
3820             ## The only way to make it understand is to return a scalar ref of 1 or 0
3821             # return( $_[0] ? 'true' : 'false' );
3822 0 0   0   0 return( $_[0] ? \1 : \0 );
3823             }
3824              
3825             package Module::Generic::Array;
3826             BEGIN
3827             {
3828 6     6   46 use common::sense;
  6         12  
  6         26  
3829 6     6   313 use warnings;
  6         14  
  6         195  
3830 6     6   32 use warnings::register;
  6         13  
  6         603  
3831 6     6   38 use Scalar::Util ();
  6         17  
  6         109  
3832 6     6   30 use Want;
  6         12  
  6         1029  
3833             ## use Data::Dumper;
3834             use overload (
3835             # Turned out to be not such a good ide as it create unexpected results, especially when this is an array of overloaded objects
3836             # '""' => 'as_string',
3837 0     0   0 '==' => sub { _obj_eq(@_) },
3838 0     0   0 '!=' => sub { !_obj_eq(@_) },
3839 2     2   661 'eq' => sub { _obj_eq(@_) },
3840 1     1   10 'ne' => sub { !_obj_eq(@_) },
3841 6         63 '%{}' => 'as_hash',
3842             fallback => 1,
3843 6     6   40 );
  6         13  
3844 6     6   12635 our( $VERSION ) = 'v0.1.1';
3845             };
3846              
3847             sub new
3848             {
3849 37     37   770 my $this = CORE::shift( @_ );
3850 37         77 my $init = [];
3851 37 50 33     403 $init = CORE::shift( @_ ) if( @_ && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) );
      66        
3852 37   66     246 return( bless( $init => ( ref( $this ) || $this ) ) );
3853             }
3854              
3855             sub as_hash
3856             {
3857 2     2   429 my $self = CORE::shift( @_ );
3858             ## print( STDERR ref( $self ), "::as_hash\n" );
3859 2         4 my $ref = {};
3860 2         10 my( @offsets ) = $self->keys;
3861 2         26 @$ref{ @$self } = @offsets;
3862             ## print( ref( $self ), "::as_hash -> dump: ", Data::Dumper::Dumper( $ref ), "\n" );
3863 2         11 return( Module::Generic::Hash->new( $ref ) );
3864             }
3865              
3866             sub as_string
3867             {
3868 19     19   45 my $self = CORE::shift( @_ );
3869 19         33 my $sort = 0;
3870 19 100       48 $sort = CORE::shift( @_ ) if( @_ );
3871 19 100       55 return( $self->sort->as_string ) if( $sort );
3872 13         82 return( "@$self" );
3873             }
3874              
3875 5     5   17 sub clone { return( $_[0]->new( [ @{$_[0]} ] ) ); }
  5         38  
3876              
3877             sub delete
3878             {
3879 4     4   12 my $self = CORE::shift( @_ );
3880 4         11 my( $offset, $length ) = @_;
3881 4 50       13 if( defined( $offset ) )
3882             {
3883 4 100       30 if( $offset !~ /^\-?\d+$/ )
3884             {
3885 1 50       7 warn( "Non integer offset \"$offset\" provided to delete array element\n" ) if( $self->_warnings_is_enabled );
3886 1         6 return( $self );
3887             }
3888 3 50 66     21 if( CORE::defined( $length ) && $length !~ /^\-?\d+$/ )
3889             {
3890 0 0       0 warn( $self, "Non integer length \"$length\" provided to delete array element\n" ) if( $self->_warnings_is_enabled );
3891 0         0 return( $self );
3892             }
3893 3 100       18 my @removed = CORE::splice( @$self, $offset, CORE::defined( $length ) ? CORE::int( $length ) : 1 );
3894 3 50       14 if( Want::want( 'LIST' ) )
3895             {
3896 0         0 rreturn( @removed );
3897             }
3898             else
3899             {
3900 3         196 rreturn( $self->new( \@removed ) );
3901             }
3902             # Required to make the compiler happy, as per Want documentation
3903 0         0 return;
3904             }
3905 0         0 return( $self );
3906             }
3907              
3908             sub each
3909             {
3910 1     1   3 my $self = CORE::shift( @_ );
3911             my $code = CORE::shift( @_ ) || do
3912 1   33     5 {
3913             warn( "No subroutine callback as provided for each\n" ) if( $self->_warnings_is_enabled );
3914             return;
3915             };
3916 1 50       5 if( ref( $code ) ne 'CODE' )
3917             {
3918 0 0       0 warn( "I was expecting a reference to a subroutine for the callback to each, but got '$code' instead.\n" ) if( $self->_warnings_is_enabled );
3919 0         0 return;
3920             }
3921             ## Index starts from 0
3922 1         8 while( my( $i, $v ) = CORE::each( @$self ) )
3923             {
3924 18         680 local $_ = $v;
3925 18 50       35 CORE::defined( $code->( $i, $v ) ) || CORE::last;
3926             }
3927 1         8 return( $self );
3928             }
3929              
3930             sub exists
3931             {
3932 4     4   12 my $self = CORE::shift( @_ );
3933 4         11 my $this = CORE::shift( @_ );
3934 4         221 return( $self->_number( CORE::scalar( CORE::grep( /^$this$/, @$self ) ) ) );
3935             }
3936              
3937             sub first
3938             {
3939 0     0   0 my $self = shift( @_ );
3940 0 0       0 return( $self->[0] ) if( CORE::length( $self->[0] ) );
3941 0 0       0 if( Want::want( 'OBJECT' ) )
3942             {
3943 0         0 rreturn( Module::Generic::Null->new );
3944             }
3945 0         0 return( $self->[0] );
3946             }
3947              
3948             sub for
3949             {
3950 1     1   726 my $self = CORE::shift( @_ );
3951 1         3 my $code = CORE::shift( @_ );
3952 1 50       20 return if( ref( $code ) ne 'CODE' );
3953 1         7 CORE::for( my $i = 0; $i < scalar( @$self ); $i++ )
3954             {
3955 18         796 local $_ = $self->[ $i ];
3956 18 50       34 CORE::defined( $code->( $i, $self->[ $i ] ) ) || CORE::last;
3957             }
3958 1         8 return( $self );
3959             }
3960              
3961             sub foreach
3962             {
3963 1     1   41 my $self = CORE::shift( @_ );
3964 1         3 my $code = CORE::shift( @_ );
3965 1 50       5 return if( ref( $code ) ne 'CODE' );
3966 1         4 CORE::foreach my $v ( @$self )
3967             {
3968 18         83 local $_ = $v;
3969 18 50       26 CORE::defined( $code->( $v ) ) || CORE::last;
3970             }
3971 1         7 return( $self );
3972             }
3973              
3974             sub get
3975             {
3976 1     1   364 my $self = CORE::shift( @_ );
3977 1         2 my $offset = CORE::shift( @_ );
3978 1         7 return( $self->[ CORE::int( $offset ) ] );
3979             }
3980              
3981             sub grep
3982             {
3983 3     3   9 my $self = CORE::shift( @_ );
3984 3         7 my $expr = CORE::shift( @_ );
3985 3         5 my $ref;
3986 3 100       15 if( ref( $expr ) eq 'CODE' )
3987             {
3988 1         8 $ref = [CORE::grep( $expr->( $_ ), @$self )];
3989             }
3990             else
3991             {
3992 2 100       29 $expr = ref( $expr ) eq 'Regexp'
3993             ? $expr
3994             : qr/\Q$expr\E/;
3995 2         45 $ref = [ CORE::grep( $_ =~ /$expr/, @$self ) ];
3996             }
3997 3 50       56 if( Want::want( 'LIST' ) )
3998             {
3999 0         0 return( @$ref );
4000             }
4001             else
4002             {
4003 3         213 return( $self->new( $ref ) );
4004             }
4005             }
4006              
4007             sub join
4008             {
4009 4     4   1539 my $self = CORE::shift( @_ );
4010 4         35 return( $self->_scalar( CORE::join( $_[0], @$self ) ) );
4011             }
4012              
4013             sub keys
4014             {
4015 5     5   345 my $self = CORE::shift( @_ );
4016 5         31 return( $self->new( [ CORE::keys( @$self ) ] ) );
4017             }
4018              
4019             sub last
4020             {
4021 0     0   0 my $self = shift( @_ );
4022 0 0       0 return( $self->[-1] ) if( CORE::length( $self->[-1] ) );
4023 0 0       0 if( Want::want( 'OBJECT' ) )
4024             {
4025 0         0 rreturn( Module::Generic::Null->new );
4026             }
4027 0         0 return( $self->[-1] );
4028             }
4029              
4030 14     14   1080 sub length { return( $_[0]->_number( scalar( @{$_[0]} ) ) ); }
  14         128  
4031              
4032 1     1   3 sub list { return( @{$_[0]} ); }
  1         16  
4033              
4034             sub map
4035             {
4036 3     3   354 my $self = CORE::shift( @_ );
4037 3         4 my $code = CORE::shift( @_ );
4038 3 50       12 return if( ref( $code ) ne 'CODE' );
4039 3         15 my $ref = [ CORE::map( $code->( $_ ), @$self ) ];
4040 3 100       71 if( Want::want( 'OBJECT' ) )
    100          
4041             {
4042 1         58 return( $self->new( $ref ) );
4043             }
4044             elsif( Want::want( 'LIST' ) )
4045             {
4046 1         107 return( @$ref );
4047             }
4048             else
4049             {
4050 1         110 return( $self->new( $ref ) );
4051             }
4052             }
4053              
4054             sub pop
4055             {
4056 2     2   582 my $self = CORE::shift( @_ );
4057 2         11 return( CORE::pop( @$self ) );
4058             }
4059              
4060             sub push
4061             {
4062 1     1   4 my $self = CORE::shift( @_ );
4063 1         6 CORE::push( @$self, @_ );
4064 1         5 return( $self );
4065             }
4066              
4067             sub push_arrayref
4068             {
4069 1     1   3 my $self = CORE::shift( @_ );
4070 1         3 my $ref = CORE::shift( @_ );
4071 1 50       5 return( $self->error( "Data provided ($ref) is not an array reference." ) ) if( !UNIVERSAL::isa( $ref, 'ARRAY' ) );
4072 1         10 CORE::push( @$self, @$ref );
4073 1         5 return( $self );
4074             }
4075              
4076             sub reset
4077             {
4078 1     1   3 my $self = CORE::shift( @_ );
4079 1         3 @$self = ();
4080 1         6 return( $self );
4081             }
4082              
4083             sub reverse
4084             {
4085 1     1   3 my $self = CORE::shift( @_ );
4086 1         7 my $ref = [ CORE::reverse( @$self ) ];
4087 1 50       14 if( wantarray() )
4088             {
4089 0         0 return( @$ref );
4090             }
4091             else
4092             {
4093 1         7 return( $self->new( $ref ) );
4094             }
4095             }
4096              
4097 0     0   0 sub scalar { return( shift->length ); }
4098              
4099             sub set
4100             {
4101 1     1   3 my $self = CORE::shift( @_ );
4102 1 50 33     17 my $ref = ( scalar( @_ ) == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? CORE::shift( @_ ) : [ @_ ];
4103 1         5 @$self = @$ref;
4104 1         3 return( $self );
4105             }
4106              
4107             sub shift
4108             {
4109 1     1   3 my $self = CORE::shift( @_ );
4110 1         5 return( CORE::shift( @$self ) );
4111             }
4112              
4113 1     1   7 sub size { return( $_[0]->_number( $_[0]->length ) ); }
4114              
4115             sub sort
4116             {
4117 8     8   19 my $self = CORE::shift( @_ );
4118 8         16 my $code = CORE::shift( @_ );
4119 8         13 my $ref;
4120 8 100       24 if( ref( $code ) eq 'CODE' )
4121             {
4122             $ref = [sort
4123             {
4124 1         10 $code->( $a, $b );
  53         130  
4125             } @$self];
4126             }
4127             else
4128             {
4129 7         63 $ref = [ CORE::sort( @$self ) ];
4130             }
4131 8 50       33 if( Want::want( 'LIST' ) )
4132             {
4133 0         0 return( @$ref );
4134             }
4135             else
4136             {
4137 8         505 return( $self->new( $ref ) );
4138             }
4139             }
4140              
4141             sub splice
4142             {
4143 2     2   6 my $self = CORE::shift( @_ );
4144 2         8 my( $offset, $length, @list ) = @_;
4145 2 50 66     18 if( defined( $offset ) && $offset !~ /^\-?\d+$/ )
4146             {
4147 0 0       0 warn( "Offset provided for splice \"$offset\" is not an integer.\n" ) if( $self->_warnings_is_enabled );
4148             ## If a list was provided, the user is not looking to get an element removed, but add it, so we return out object
4149 0 0       0 return( $self ) if( scalar( @list ) );
4150 0         0 return;
4151             }
4152 2 50 66     15 if( defined( $length ) && $length !~ /^\-?\d+$/ )
4153             {
4154 0 0       0 warn( "Length provided for splice \"$length\" is not an integer.\n" ) if( $self->_warnings_is_enabled );
4155 0 0       0 return( $self ) if( scalar( @list ) );
4156 0         0 return;
4157             }
4158             ## Adding elements, so we return our object and allow chaining
4159             ## @_ = offset, length, replacement list
4160 2 100       9 if( scalar( @_ ) > 2 )
    50          
4161             {
4162 1         6 CORE::splice( @$self, $offset, $length, @list );
4163 1         6 return( $self );
4164             }
4165             elsif( !scalar( @_ ) )
4166             {
4167 1         3 CORE::splice( @$self );
4168 1         7 return( $self );
4169             }
4170             else
4171             {
4172 0 0 0     0 return( CORE::splice( @$self, $offset, $length ) ) if( CORE::defined( $offset ) && CORE::defined( $length ) );
4173 0 0       0 return( CORE::splice( @$self, $offset ) ) if( CORE::defined( $offset ) );
4174             }
4175             }
4176              
4177             sub undef
4178             {
4179 1     1   4 my $self = CORE::shift( @_ );
4180 1         5 @$self = ();
4181 1         6 return( $self );
4182             }
4183              
4184             sub unshift
4185             {
4186 1     1   4 my $self = CORE::shift( @_ );
4187 1         4 CORE::unshift( @$self, @_ );
4188 1         5 return( $self );
4189             }
4190              
4191             sub values
4192             {
4193 1     1   3 my $self = CORE::shift( @_ );
4194 1         7 my $ref = [ CORE::values( @$self ) ];
4195 1 50       5 if( Want::want( 'LIST' ) )
4196             {
4197 0         0 return( @$ref );
4198             }
4199             else
4200             {
4201 1         70 return( $self->new( $ref ) );
4202             }
4203             }
4204              
4205             sub _number
4206             {
4207 19     19   74 my $self = CORE::shift( @_ );
4208 19         59 my $num = CORE::shift( @_ );
4209 19 50       77 return if( !defined( $num ) );
4210 19 50       72 return( $num ) if( !CORE::length( $num ) );
4211 19         95 return( Module::Generic::Number->new( $num ) );
4212             }
4213              
4214             sub _obj_eq
4215             {
4216 6     6   66 no overloading;
  6         13  
  6         1481  
4217 3     3   7 my $self = CORE::shift( @_ );
4218 3         37 my $other = CORE::shift( @_ );
4219             ## Sorted
4220 3         16 my $strA = $self->as_string(1);
4221 3         13 my $strB;
4222 3 100 66     26 if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Array' ) )
    50          
4223             {
4224 1         4 $strB = $other->as_string(1);
4225             }
4226             ## Compare error message
4227             elsif( Scalar::Util::reftype( $other ) eq 'ARRAY' )
4228             {
4229 2         6 $strB = $self->new( $other )->as_string(1);
4230             }
4231             else
4232             {
4233 0         0 return( 0 );
4234             }
4235             ## print( STDERR ref( $self ), "::_obj_eq: Comparing array A (", CORE::scalar( @$self ), ") with '$strA' to array B (", CORE::scalar( @$other ), ") with '$strB'\n" );
4236 3         36 return( $strA eq $strB ) ;
4237             }
4238              
4239             sub _scalar
4240             {
4241 4     4   11 my $self = CORE::shift( @_ );
4242 4         12 my $str = CORE::shift( @_ );
4243 4 50       19 return if( !defined( $str ) );
4244             ## Whether empty or not, return an object
4245 4         18 return( Module::Generic::Scalar->new( $str ) );
4246             }
4247              
4248 1   33 1   107 sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); }
4249              
4250             package Module::Generic::Scalar;
4251             BEGIN
4252             {
4253 6     6   51 use common::sense;
  6         15  
  6         26  
4254 6     6   479 use warnings;
  6         15  
  6         184  
4255 6     6   98 use warnings::register;
  6         14  
  6         679  
4256             ## So that the user can say $obj->isa( 'Module::Generic::Scalar' ) and it would return true
4257             ## use parent -norequire, qw( Module::Generic::Scalar );
4258 6     6   42 use Scalar::Util ();
  6         13  
  6         110  
4259 6     6   28 use Want;
  6         12  
  6         545  
4260             use overload (
4261             '""' => 'as_string',
4262             '.=' => sub
4263             {
4264 3     3   16 my( $self, $other, $swap ) = @_;
4265 6     6   71 no warnings 'uninitialized';
  6         21  
  6         1141  
4266 3 50       18 if( !CORE::defined( $$self ) )
    50          
4267             {
4268 0         0 return( $other );
4269             }
4270             elsif( !CORE::defined( $other ) )
4271             {
4272 0         0 return( $$self );
4273             }
4274             ## print( STDERR ref( $self ), "::concatenate: Got here with other = '$other', and swap = '$swap'\n" );
4275             ## print( STDERR "Module::Generic::Scalar::overload->.=: Received arguments '", join( "', '", @_ ), "'\n" );
4276 3         7 my $expr;
4277 3 50       10 if( $swap )
4278             {
4279 0         0 $expr = "\$other .= \$$self";
4280 0         0 return( $other );
4281             }
4282             else
4283             {
4284 3         11 $$self .= $other;
4285 3         11 return( $self );
4286             }
4287             },
4288             'x' => sub
4289             {
4290 1     1   8 my( $self, $other, $swap ) = @_;
4291 6     6   38 no warnings 'uninitialized';
  6         13  
  6         975  
4292             ## print( STDERR "Module::Generic::Scalar::overload->x: Received arguments '", join( "', '", @_ ), "'\n" );
4293 1 50       7 my $expr = $swap ? "\"$other" x \"$$self\"" : "\"$$self\" x \"$other\"";
4294 1         78 my $res = eval( $expr );
4295 1 50       10 if( $@ )
4296             {
4297 0         0 CORE::warn( $@ );
4298 0         0 return;
4299             }
4300 1         28 return( $self->new( $res ) );
4301             },
4302             'eq' => sub
4303             {
4304 3238     3238   718127 my( $self, $other, $swap ) = @_;
4305 6     6   38 no warnings 'uninitialized';
  6         14  
  6         644  
4306 3238 100 66     11108 if( Scalar::Util::blessed( $other ) && ref( $other ) eq ref( $self ) )
4307             {
4308 1         13 return( $$self eq $$other );
4309             }
4310             else
4311             {
4312 3237         11518 return( $$self eq "$other" );
4313             }
4314             },
4315 6         75 fallback => 1,
4316 6     6   37 );
  6         10  
4317 6     6   17829 our( $VERSION ) = 'v0.2.3';
4318             };
4319              
4320             ## sub new { return( shift->_new( @_ ) ); }
4321             sub new
4322             {
4323 55698     55698   85400 my $this = shift( @_ );
4324 55698         89802 my $init = '';
4325 55698 100 66     222859 if( ref( $_[0] ) eq 'SCALAR' || UNIVERSAL::isa( $_[0], 'SCALAR' ) )
    50 33        
    50          
    50          
4326             {
4327 53957         81707 $init = ${$_[0]};
  53957         98895  
4328             }
4329             elsif( ref( $_[0] ) eq 'ARRAY' || UNIVERSAL::isa( $_[0], 'ARRAY' ) )
4330             {
4331 0         0 $init = CORE::join( '', @{$_[0]} );
  0         0  
4332             }
4333             elsif( ref( $_[0] ) )
4334             {
4335 0 0       0 warn( "I do not know what to do with \"", $_[0], "\"\n" ) if( $this->_warnings_is_enabled );
4336 0         0 return;
4337             }
4338             elsif( @_ )
4339             {
4340 1741         3026 $init = $_[0];
4341             }
4342             else
4343             {
4344 0         0 $init = undef();
4345             }
4346             ## print( STDERR __PACKAGE__, "::new: got here for value '$init' (defined? ", CORE::defined( $init ) ? 'yes' : 'no', ")\n" );
4347             # CORE::tie( $self, 'Module::Generic::Scalar::Tie', $init );
4348 55698   66     210091 return( bless( \$init => ( ref( $this ) || $this ) ) );
4349             }
4350              
4351 3 100   3   4 sub as_boolean { return( Module::Generic::Boolean->new( ${$_[0]} ? 1 : 0 ) ); }
  3         18  
4352              
4353             ## sub as_string { CORE::defined( ${$_[0]} ) ? return( ${$_[0]} ) : return; }
4354 6756     6756   12264 sub as_string { return( ${$_[0]} ); }
  6756         25738  
4355              
4356             ## Credits: John Gruber, Aristotle Pagaltzis
4357             ## https://gist.github.com/gruber/9f9e8650d68b13ce4d78
4358             sub capitalise
4359             {
4360 1     1   4 my $self = CORE::shift( @_ );
4361 1         9 my @small_words = qw( (?<!q&)a an and as at(?!&t) but by en for if in of on or the to v[.]? via vs[.]? );
4362 1         6 my $small_re = CORE::join( '|', @small_words );
4363              
4364 1         5 my $apos = qr/ (?: ['’] [[:lower:]]* )? /x;
4365            
4366 1         4 my $copy = $$self;
4367 1         6 $copy =~ s{\A\s+}{}, s{\s+\z}{};
4368 1 50       7 $copy = CORE::lc( $copy ) if( not /[[:lower:]]/ );
4369 1         276 $copy =~ s{
4370             \b (_*) (?:
4371             ( (?<=[ ][/\\]) [[:alpha:]]+ [-_[:alpha:]/\\]+ | # file path or
4372             [-_[:alpha:]]+ [@.:] [-_[:alpha:]@.:/]+ $apos ) # URL, domain, or email
4373             |
4374             ( (?i: $small_re ) $apos ) # or small word (case-insensitive)
4375             |
4376             ( [[:alpha:]] [[:lower:]'’()\[\]{}]* $apos ) # or word w/o internal caps
4377             |
4378             ( [[:alpha:]] [[:alpha:]'’()\[\]{}]* $apos ) # or some other word
4379             ) (_*) \b
4380             }{
4381 18 50       187 $1 . (
    100          
    50          
4382             defined $2 ? $2 # preserve URL, domain, or email
4383             : defined $3 ? "\L$3" # lowercase small word
4384             : defined $4 ? "\u\L$4" # capitalize word w/o internal caps
4385             : $5 # preserve other kinds of word
4386             ) . $6
4387             }xeg;
4388              
4389              
4390             # Exceptions for small words: capitalize at start and end of title
4391 1         157 $copy =~ s{
4392             ( \A [[:punct:]]* # start of title...
4393             | [:.;?!][ ]+ # or of subsentence...
4394             | [ ]['"“‘(\[][ ]* ) # or of inserted subphrase...
4395             ( $small_re ) \b # ... followed by small word
4396             }{$1\u\L$2}xig;
4397              
4398 1         97 $copy =~ s{
4399             \b ( $small_re ) # small word...
4400             (?= [[:punct:]]* \Z # ... at the end of the title...
4401             | ['"’”)\]] [ ] ) # ... or of an inserted subphrase?
4402             }{\u\L$1}xig;
4403              
4404             # Exceptions for small words in hyphenated compound words
4405             ## e.g. "in-flight" -> In-Flight
4406 1         62 $copy =~ s{
4407             \b
4408             (?<! -) # Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (in-flight)
4409             ( $small_re )
4410             (?= -[[:alpha:]]+) # lookahead for "-someword"
4411             }{\u\L$1}xig;
4412              
4413             ## # e.g. "Stand-in" -> "Stand-In" (Stand is already capped at this point)
4414 1         50 $copy =~ s{
4415             \b
4416             (?<!…) # Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (stand-in)
4417             ( [[:alpha:]]+- ) # $1 = first word and hyphen, should already be properly capped
4418             ( $small_re ) # ... followed by small word
4419             (?! - ) # Negative lookahead for another '-'
4420             }{$1\u$2}xig;
4421              
4422 1         9 return( $self->_new( $copy ) );
4423             }
4424              
4425 1     1   3 sub chomp { return( CORE::chomp( ${$_[0]} ) ); }
  1         7  
4426              
4427 1     1   3 sub chop { return( CORE::chop( ${$_[0]} ) ); }
  1         4  
4428              
4429             sub clone
4430             {
4431 5     5   889 my $self = shift( @_ );
4432 5 100       23 if( @_ )
4433             {
4434 1         4 return( $self->_new( @_ ) );
4435             }
4436             else
4437             {
4438 4         13 return( $self->_new( ${$self} ) );
  4         25  
4439             }
4440             }
4441              
4442 1     1   2 sub crypt { return( __PACKAGE__->_new( CORE::crypt( ${$_[0]}, $_[1] ) ) ); }
  1         618  
4443              
4444 55678     55678   76172 sub defined { return( CORE::defined( ${$_[0]} ) ); }
  55678         147233  
4445              
4446 1     1   322 sub fc { return( CORE::fc( ${$_[0]} ) eq CORE::fc( $_[1] ) ); }
  1         8  
4447              
4448 2     2   6 sub hex { return( $_[0]->_number( CORE::hex( ${$_[0]} ) ) ); }
  2         18  
4449              
4450             sub index
4451             {
4452 2     2   7 my $self = shift( @_ );
4453 2         7 my( $substr, $pos ) = @_;
4454 2 50       7 return( $self->_number( CORE::index( ${$self}, $substr, $pos ) ) ) if( CORE::defined( $pos ) );
  0         0  
4455 2         5 return( $self->_number( CORE::index( ${$self}, $substr ) ) );
  2         10  
4456             }
4457              
4458 2     2   5 sub is_alpha { return( ${$_[0]} =~ /^[[:alpha:]]+$/ ); }
  2         19  
4459              
4460 1     1   2 sub is_alpha_numeric { return( ${$_[0]} =~ /^[[:alnum:]]+$/ ); }
  1         11  
4461              
4462 1     1   3 sub is_empty { return( CORE::length( ${$_[0]} ) == 0 ); }
  1         5  
4463              
4464 1     1   4 sub is_lower { return( ${$_[0]} =~ /^[[:lower:]]+$/ ); }
  1         10  
4465              
4466 1     1   4 sub is_numeric { return( Scalar::Util::looks_like_number( ${$_[0]} ) ); }
  1         9  
4467              
4468 1     1   3 sub is_upper { return( ${$_[0]} =~ /^[[:upper:]]+$/ ); }
  1         12  
4469              
4470 1     1   2 sub lc { return( __PACKAGE__->_new( CORE::lc( ${$_[0]} ) ) ); }
  1         6  
4471              
4472 1     1   4 sub lcfirst { return( __PACKAGE__->_new( CORE::lcfirst( ${$_[0]} ) ) ); }
  1         7  
4473              
4474 1     1   3 sub left { return( $_[0]->_new( CORE::substr( ${$_[0]}, 0, CORE::int( $_[1] ) ) ) ); }
  1         7  
4475              
4476 2     2   8 sub length { return( $_[0]->_number( CORE::length( ${$_[0]} ) ) ); }
  2         10  
4477              
4478             sub like
4479             {
4480 1     1   4 my $self = shift( @_ );
4481 1         2 my $str = shift( @_ );
4482 1 50       8 $str = CORE::defined( $str )
    50          
4483             ? ref( $str ) eq 'Regexp'
4484             ? $str
4485             : qr/(?:\Q$str\E)+/
4486             : qr/[[:blank:]\r\n]*/;
4487 1         15 return( $$self =~ /$str/ );
4488             }
4489              
4490             sub ltrim
4491             {
4492 1     1   3 my $self = shift( @_ );
4493 1         3 my $str = shift( @_ );
4494 1 0       7 $str = CORE::defined( $str )
    50          
4495             ? ref( $str ) eq 'Regexp'
4496             ? $str
4497             : qr/(?:\Q$str\E)+/
4498             : qr/[[:blank:]\r\n]*/;
4499 1         31 $$self =~ s/^$str//g;
4500 1         8 return( $self );
4501             }
4502              
4503             sub match
4504             {
4505 1     1   4 my( $self, $re ) = @_;
4506 1 50       7 $re = CORE::defined( $re )
    50          
4507             ? ref( $re ) eq 'Regexp'
4508             ? $re
4509             : qr/(?:\Q$re\E)+/
4510             : $re;
4511 1         13 return( $$self =~ /$re/ );
4512             }
4513              
4514 1     1   3 sub ord { return( $_[0]->_number( CORE::ord( ${$_[0]} ) ) ); }
  1         6  
4515              
4516             sub pad
4517             {
4518 2     2   5 my $self = shift( @_ );
4519 2         6 my( $n, $str ) = @_;
4520 2   50     8 $str //= ' ';
4521 2 50       16 if( !CORE::length( $n ) )
    50          
4522             {
4523 0 0       0 warn( "No number provided to pad the string object.\n" ) if( $self->_warnings_is_enabled );
4524             }
4525             elsif( $n !~ /^\-?\d+$/ )
4526             {
4527 0 0       0 warn( "Number provided \"$n\" to pad string is not an integer.\n" ) if( $self->_warnings_is_enabled );
4528             }
4529            
4530 2 100       8 if( $n < 0 )
4531             {
4532 1         6 $$self .= ( "$str" x CORE::abs( $n ) );
4533             }
4534             else
4535             {
4536 1         6 CORE::substr( $$self, 0, 0 ) = ( "$str" x $n );
4537             }
4538 2         29 return( $self );
4539             }
4540              
4541 0 0   0   0 sub pos { return( $_[0]->_number( @_ > 1 ? ( CORE::pos( ${$_[0]} ) = $_[1] ) : CORE::pos( ${$_[0]} ) ) ); }
  0         0  
  0         0  
4542              
4543 1     1   3 sub quotemeta { return( __PACKAGE__->_new( CORE::quotemeta( ${$_[0]} ) ) ); }
  1         8  
4544              
4545 0     0   0 sub right { return( $_[0]->_new( CORE::substr( ${$_[0]}, ( CORE::int( $_[1] ) * -1 ) ) ) ); }
  0         0  
4546              
4547             sub replace
4548             {
4549 4     4   678 my( $self, $re, $replacement ) = @_;
4550 4 100       109 $re = CORE::defined( $re )
    50          
4551             ? ref( $re ) eq 'Regexp'
4552             ? $re
4553             : qr/(?:\Q$re\E)+/
4554             : $re;
4555 4         76 return( $$self =~ s/$re/$replacement/gs );
4556             }
4557              
4558 1     1   5 sub reset { ${$_[0]} = ''; return( $_[0] ); }
  1         5  
  1         5  
4559              
4560 1     1   12 sub reverse { return( __PACKAGE__->_new( CORE::scalar( CORE::reverse( ${$_[0]} ) ) ) ); }
  1         9  
4561              
4562             sub rindex
4563             {
4564 2     2   7 my $self = shift( @_ );
4565 2         8 my( $substr, $pos ) = @_;
4566 2 100       9 return( $self->_number( CORE::rindex( ${$self}, $substr, $pos ) ) ) if( CORE::defined( $pos ) );
  1         7  
4567 1         3 return( $self->_number( CORE::rindex( ${$self}, $substr ) ) );
  1         6  
4568             }
4569              
4570             sub rtrim
4571             {
4572 1     1   3 my $self = shift( @_ );
4573 1         3 my $str = shift( @_ );
4574 1 50       37 $str = CORE::defined( $str )
    50          
4575             ? ref( $str ) eq 'Regexp'
4576             ? $str
4577             : qr/(?:\Q$str\E)+/
4578             : qr/[[:blank:]\r\n]*/;
4579 1         18 $$self =~ s/${str}$//g;
4580 1         7 return( $self );
4581             }
4582              
4583 872     872   2958 sub scalar { return( shift->as_string ); }
4584              
4585             sub set
4586             {
4587 3435     3435   5181 my $self = CORE::shift( @_ );
4588 3435         4994 my $init;
4589 3435 50 33     22738 if( ref( $_[0] ) eq 'SCALAR' || UNIVERSAL::isa( $_[0], 'SCALAR' ) )
    50 33        
    50          
4590             {
4591 0         0 $init = ${$_[0]};
  0         0  
4592             }
4593             elsif( ref( $_[0] ) eq 'ARRAY' || UNIVERSAL::isa( $_[0], 'ARRAY' ) )
4594             {
4595 0         0 $init = CORE::join( '', @{$_[0]} );
  0         0  
4596             }
4597             elsif( ref( $_[0] ) )
4598             {
4599 0 0       0 warn( "I do not know what to do with \"", $_[0], "\"\n" ) if( $self->_warnings_is_enabled );
4600 0         0 return;
4601             }
4602             else
4603             {
4604 3435         5802 $init = shift( @_ );
4605             }
4606 3435         5470 $$self = $init;
4607 3435         5701 return( $self );
4608             }
4609              
4610             sub split
4611             {
4612 2     2   18 my $self = CORE::shift( @_ );
4613 2         8 my( $expr, $limit ) = @_;
4614 2         4 my $ref;
4615 2         5 $limit = "$limit";
4616 2 50 33     15 if( CORE::defined( $limit ) && $limit =~ /^\d+$/ )
4617             {
4618 0         0 $ref = [ CORE::split( $expr, $$self, $limit ) ];
4619             }
4620             else
4621             {
4622 2         80 $ref = [ CORE::split( $expr, $$self ) ];
4623             }
4624 2 50 33     15 if( Want::want( 'OBJECT' ) ||
    0          
4625             Want::want( 'SCALAR' ) )
4626             {
4627 2         281 rreturn( $self->_array( $ref ) );
4628             }
4629             elsif( Want::want( 'LIST' ) )
4630             {
4631 0         0 rreturn( @$ref );
4632             }
4633 0         0 return;
4634             }
4635              
4636 1     1   3 sub sprintf { return( __PACKAGE__->_new( CORE::sprintf( ${$_[0]}, @_[1..$#_] ) ) ); }
  1         13  
4637              
4638             sub substr
4639             {
4640 2     2   6 my $self = CORE::shift( @_ );
4641 2         7 my( $offset, $length, $replacement ) = @_;
4642 2 100 66     17 return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset, $length, $replacement ) ) ) if( CORE::defined( $length ) && CORE::defined( $replacement ) );
  1         7  
4643 1 50       5 return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset, $length ) ) ) if( CORE::defined( $length ) );
  1         6  
4644 0         0 return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset ) ) );
  0         0  
4645             }
4646              
4647             ## The 3 dash here are just so my editor does not get confused with colouring
4648             sub tr ###
4649             {
4650 1     1   7 my $self = CORE::shift( @_ );
4651 1         4 my( $search, $replace, $opts ) = @_;
4652 1         78 eval( "\$\$self =~ CORE::tr/$search/$replace/$opts" );
4653 1         7 return( $self );
4654             }
4655              
4656             sub trim
4657             {
4658 2     2   7 my $self = shift( @_ );
4659 2         5 my $str = shift( @_ );
4660 2 50       27 $str = CORE::defined( $str ) ? CORE::quotemeta( $str ) : qr/[[:blank:]\r\n]*/;
4661 2         81 $$self =~ s/^$str|$str$//gs;
4662 2         13 return( $self );
4663             }
4664              
4665 2     2   5 sub uc { return( __PACKAGE__->_new( CORE::uc( ${$_[0]} ) ) ); }
  2         13  
4666              
4667 0     0   0 sub ucfirst { return( __PACKAGE__->_new( CORE::ucfirst( ${$_[0]} ) ) ); }
  0         0  
4668              
4669             sub undef
4670             {
4671 1     1   5 my $self = shift( @_ );
4672 1         2 $$self = undef;
4673 1         3 return( $self );
4674             }
4675              
4676             sub _array
4677             {
4678 2     2   8 my $self = shift( @_ );
4679 2         4 my $arr = shift( @_ );
4680 2 50       9 return if( !defined( $arr ) );
4681 2 50       14 return( $arr ) if( Scalar::Util::reftype( $arr ) ne 'ARRAY' );
4682 2         20 return( Module::Generic::Array->new( $arr ) );
4683             }
4684              
4685             sub _number
4686             {
4687 9     9   36 my $self = shift( @_ );
4688 9         25 my $num = shift( @_ );
4689 9 50       45 return if( !defined( $num ) );
4690 9 50       33 return( $num ) if( !CORE::length( $num ) );
4691 9         62 return( Module::Generic::Number->new( $num ) );
4692             }
4693              
4694 17     17   71 sub _new { return( shift->Module::Generic::Scalar::new( @_ ) ); }
4695              
4696 0   0 0   0 sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); }
4697              
4698             package Module::Generic::Number;
4699             BEGIN
4700             {
4701 6     6   60 use strict;
  6         46  
  6         240  
4702 6     6   36 use parent -norequire, qw( Module::Generic );
  6         27  
  6         46  
4703 6     6   317 use warnings::register;
  6         13  
  6         672  
4704 6     6   74 use Number::Format;
  6         14  
  6         287  
4705 6     6   33 use Nice::Try;
  6         12  
  6         61  
4706 6     6   23773448 use Regexp::Common qw( number );
  6         14221  
  6         23  
4707 6     6   16729 use POSIX ();
  6         18  
  6         177  
4708 6     6   4716 our( $VERSION ) = 'v0.3.3';
4709             };
4710              
4711             use overload (
4712             ## I know there is the nomethod feature, but I need to provide return_object set to true or false
4713             ## And I do not necessarily want to catch all the operation.
4714 55     55   13290 '""' => sub { return( shift->{_number} ); },
4715 3     3   49 '-' => sub { return( shift->compute( @_, { op => '-', return_object => 1 }) ); },
4716 5     5   65 '+' => sub { return( shift->compute( @_, { op => '+', return_object => 1 }) ); },
4717 3     3   49 '*' => sub { return( shift->compute( @_, { op => '*', return_object => 1 }) ); },
4718 4     4   70 '/' => sub { return( shift->compute( @_, { op => '/', return_object => 1 }) ); },
4719 2     2   30 '%' => sub { return( shift->compute( @_, { op => '%', return_object => 1 }) ); },
4720             ## Exponent
4721 3     3   46 '**' => sub { return( shift->compute( @_, { op => '**', return_object => 1 }) ); },
4722             ## Bitwise AND
4723 1     1   25 '&' => sub { return( shift->compute( @_, { op => '&', return_object => 1 }) ); },
4724             ## Bitwise OR
4725 1     1   17 '|' => sub { return( shift->compute( @_, { op => '|', return_object => 1 }) ); },
4726             ## Bitwise XOR
4727 1     1   9 '^' => sub { return( shift->compute( @_, { op => '^', return_object => 1 }) ); },
4728             ## Bitwise shift left
4729 1     1   23 '<<' => sub { return( shift->compute( @_, { op => '<<', return_object => 1 }) ); },
4730             ## Bitwise shift right
4731 1     1   19 '>>' => sub { return( shift->compute( @_, { op => '>>', return_object => 1 }) ); },
4732 1     1   19 'x' => sub { return( shift->compute( @_, { op => 'x', return_object => 1, type => 'scalar' }) ); },
4733 2     2   26 '+=' => sub { return( shift->compute( @_, { op => '+=', return_object => 1 }) ); },
4734 1     1   24 '-=' => sub { return( shift->compute( @_, { op => '-=', return_object => 1 }) ); },
4735 2     2   1198 '*=' => sub { return( shift->compute( @_, { op => '*=', return_object => 1 }) ); },
4736 1     1   22 '/=' => sub { return( shift->compute( @_, { op => '/=', return_object => 1 }) ); },
4737 1     1   19 '%=' => sub { return( shift->compute( @_, { op => '%=', return_object => 1 }) ); },
4738 1     1   36 '**=' => sub { return( shift->compute( @_, { op => '**=', return_object => 1 }) ); },
4739 1     1   21 '<<=' => sub { return( shift->compute( @_, { op => '<<=', return_object => 1 }) ); },
4740 1     1   25 '>>=' => sub { return( shift->compute( @_, { op => '>>=', return_object => 1 }) ); },
4741 1     1   20 'x=' => sub { return( shift->compute( @_, { op => 'x=', return_object => 1 }) ); },
4742             ## '.=' => sub { return( shift->compute( @_, { op => '.=', return_object => 1 }) ); },
4743             '.=' => sub
4744             {
4745 2     2   8 my( $self, $other, $swap ) = @_;
4746 2         14 my $op = '.=';
4747 2 50       26 my $operation = $swap ? "${other} ${op} \$self->{_number}" : "\$self->{_number} ${op} ${other}";
4748 2         142 my $res = eval( $operation );
4749 2 50 33     28 warn( "Error with formula \"$operation\": $@" ) if( $@ && $self->_warnings_is_enabled );
4750 2 50       9 return if( $@ );
4751             ## Concatenated something. If it still look like a number, we return it as an object
4752 2 100       17 if( $res =~ /^$RE{num}{real}$/ )
4753             {
4754 1         274 return( $self->clone( $res ) );
4755             }
4756             ## Otherwise we pass it to the scalar module
4757             else
4758             {
4759 1         182 return( Module::Generic::Scalar->new( "$res" ) );
4760             }
4761             },
4762 2     2   22 '<' => sub { return( shift->compute( @_, { op => '<', boolean => 1 }) ); },
4763 2     2   26 '<=' => sub { return( shift->compute( @_, { op => '<=', boolean => 1 }) ); },
4764 1     1   26 '>' => sub { return( shift->compute( @_, { op => '>', boolean => 1 }) ); },
4765 1     1   20 '>=' => sub { return( shift->compute( @_, { op => '>=', boolean => 1 }) ); },
4766 3     3   25 '<=>' => sub { return( shift->compute( @_, { op => '<=>', return_object => 0 }) ); },
4767 6     6   70 '==' => sub { return( shift->compute( @_, { op => '==', boolean => 1 }) ); },
4768 7     7   75 '!=' => sub { return( shift->compute( @_, { op => '!=', boolean => 1 }) ); },
4769 81     81   34983 'eq' => sub { return( shift->compute( @_, { op => 'eq', boolean => 1 }) ); },
4770 1     1   16 'ne' => sub { return( shift->compute( @_, { op => 'ne', boolean => 1 }) ); },
4771             '++' => sub
4772             {
4773 3     3   441 my( $self ) = @_;
4774 3         21 return( ++$self->{_number} );
4775             },
4776             '--' => sub
4777             {
4778 2     2   6 my( $self ) = @_;
4779 2         17 return( --$self->{_number} );
4780             },
4781 6         256 'fallback' => 1,
4782 6     6   45 );
  6         16  
4783              
4784             our $SUPPORTED_LOCALES =
4785             {
4786             aa_DJ => [qw( aa_DJ.UTF-8 aa_DJ.ISO-8859-1 aa_DJ.ISO8859-1 )],
4787             aa_ER => [qw( aa_ER.UTF-8 )],
4788             aa_ET => [qw( aa_ET.UTF-8 )],
4789             af_ZA => [qw( af_ZA.UTF-8 af_ZA.ISO-8859-1 af_ZA.ISO8859-1 )],
4790             ak_GH => [qw( ak_GH.UTF-8 )],
4791             am_ET => [qw( am_ET.UTF-8 )],
4792             an_ES => [qw( an_ES.UTF-8 an_ES.ISO-8859-15 an_ES.ISO8859-15 )],
4793             anp_IN => [qw( anp_IN.UTF-8 )],
4794             ar_AE => [qw( ar_AE.UTF-8 ar_AE.ISO-8859-6 ar_AE.ISO8859-6 )],
4795             ar_BH => [qw( ar_BH.UTF-8 ar_BH.ISO-8859-6 ar_BH.ISO8859-6 )],
4796             ar_DZ => [qw( ar_DZ.UTF-8 ar_DZ.ISO-8859-6 ar_DZ.ISO8859-6 )],
4797             ar_EG => [qw( ar_EG.UTF-8 ar_EG.ISO-8859-6 ar_EG.ISO8859-6 )],
4798             ar_IN => [qw( ar_IN.UTF-8 )],
4799             ar_IQ => [qw( ar_IQ.UTF-8 ar_IQ.ISO-8859-6 ar_IQ.ISO8859-6 )],
4800             ar_JO => [qw( ar_JO.UTF-8 ar_JO.ISO-8859-6 ar_JO.ISO8859-6 )],
4801             ar_KW => [qw( ar_KW.UTF-8 ar_KW.ISO-8859-6 ar_KW.ISO8859-6 )],
4802             ar_LB => [qw( ar_LB.UTF-8 ar_LB.ISO-8859-6 ar_LB.ISO8859-6 )],
4803             ar_LY => [qw( ar_LY.UTF-8 ar_LY.ISO-8859-6 ar_LY.ISO8859-6 )],
4804             ar_MA => [qw( ar_MA.UTF-8 ar_MA.ISO-8859-6 ar_MA.ISO8859-6 )],
4805             ar_OM => [qw( ar_OM.UTF-8 ar_OM.ISO-8859-6 ar_OM.ISO8859-6 )],
4806             ar_QA => [qw( ar_QA.UTF-8 ar_QA.ISO-8859-6 ar_QA.ISO8859-6 )],
4807             ar_SA => [qw( ar_SA.UTF-8 ar_SA.ISO-8859-6 ar_SA.ISO8859-6 )],
4808             ar_SD => [qw( ar_SD.UTF-8 ar_SD.ISO-8859-6 ar_SD.ISO8859-6 )],
4809             ar_SS => [qw( ar_SS.UTF-8 )],
4810             ar_SY => [qw( ar_SY.UTF-8 ar_SY.ISO-8859-6 ar_SY.ISO8859-6 )],
4811             ar_TN => [qw( ar_TN.UTF-8 ar_TN.ISO-8859-6 ar_TN.ISO8859-6 )],
4812             ar_YE => [qw( ar_YE.UTF-8 ar_YE.ISO-8859-6 ar_YE.ISO8859-6 )],
4813             as_IN => [qw( as_IN.UTF-8 )],
4814             ast_ES => [qw( ast_ES.UTF-8 ast_ES.ISO-8859-15 ast_ES.ISO8859-15 )],
4815             ayc_PE => [qw( ayc_PE.UTF-8 )],
4816             az_AZ => [qw( az_AZ.UTF-8 )],
4817             be_BY => [qw( be_BY.UTF-8 be_BY.CP1251 )],
4818             bem_ZM => [qw( bem_ZM.UTF-8 )],
4819             ber_DZ => [qw( ber_DZ.UTF-8 )],
4820             ber_MA => [qw( ber_MA.UTF-8 )],
4821             bg_BG => [qw( bg_BG.UTF-8 bg_BG.CP1251 )],
4822             bhb_IN => [qw( bhb_IN.UTF-8 )],
4823             bho_IN => [qw( bho_IN.UTF-8 )],
4824             bn_BD => [qw( bn_BD.UTF-8 )],
4825             bn_IN => [qw( bn_IN.UTF-8 )],
4826             bo_CN => [qw( bo_CN.UTF-8 )],
4827             bo_IN => [qw( bo_IN.UTF-8 )],
4828             br_FR => [qw( br_FR.UTF-8 br_FR.ISO-8859-1 br_FR.ISO8859-1 br_FR.ISO-8859-15 br_FR.ISO8859-15 )],
4829             brx_IN => [qw( brx_IN.UTF-8 )],
4830             bs_BA => [qw( bs_BA.UTF-8 bs_BA.ISO-8859-2 bs_BA.ISO8859-2 )],
4831             byn_ER => [qw( byn_ER.UTF-8 )],
4832             ca_AD => [qw( ca_AD.UTF-8 ca_AD.ISO-8859-15 ca_AD.ISO8859-15 )],
4833             ca_ES => [qw( ca_ES.UTF-8 ca_ES.ISO-8859-1 ca_ES.ISO8859-1 ca_ES.ISO-8859-15 ca_ES.ISO8859-15 )],
4834             ca_FR => [qw( ca_FR.UTF-8 ca_FR.ISO-8859-15 ca_FR.ISO8859-15 )],
4835             ca_IT => [qw( ca_IT.UTF-8 ca_IT.ISO-8859-15 ca_IT.ISO8859-15 )],
4836             ce_RU => [qw( ce_RU.UTF-8 )],
4837             ckb_IQ => [qw( ckb_IQ.UTF-8 )],
4838             cmn_TW => [qw( cmn_TW.UTF-8 )],
4839             crh_UA => [qw( crh_UA.UTF-8 )],
4840             cs_CZ => [qw( cs_CZ.UTF-8 cs_CZ.ISO-8859-2 cs_CZ.ISO8859-2 )],
4841             csb_PL => [qw( csb_PL.UTF-8 )],
4842             cv_RU => [qw( cv_RU.UTF-8 )],
4843             cy_GB => [qw( cy_GB.UTF-8 cy_GB.ISO-8859-14 cy_GB.ISO8859-14 )],
4844             da_DK => [qw( da_DK.UTF-8 da_DK.ISO-8859-1 da_DK.ISO8859-1 )],
4845             de_AT => [qw( de_AT.UTF-8 de_AT.ISO-8859-1 de_AT.ISO8859-1 de_AT.ISO-8859-15 de_AT.ISO8859-15 )],
4846             de_BE => [qw( de_BE.UTF-8 de_BE.ISO-8859-1 de_BE.ISO8859-1 de_BE.ISO-8859-15 de_BE.ISO8859-15 )],
4847             de_CH => [qw( de_CH.UTF-8 de_CH.ISO-8859-1 de_CH.ISO8859-1 )],
4848             de_DE => [qw( de_DE.UTF-8 de_DE.ISO-8859-1 de_DE.ISO8859-1 de_DE.ISO-8859-15 de_DE.ISO8859-15 )],
4849             de_LI => [qw( de_LI.UTF-8 )],
4850             de_LU => [qw( de_LU.UTF-8 de_LU.ISO-8859-1 de_LU.ISO8859-1 de_LU.ISO-8859-15 de_LU.ISO8859-15 )],
4851             doi_IN => [qw( doi_IN.UTF-8 )],
4852             dv_MV => [qw( dv_MV.UTF-8 )],
4853             dz_BT => [qw( dz_BT.UTF-8 )],
4854             el_CY => [qw( el_CY.UTF-8 el_CY.ISO-8859-7 el_CY.ISO8859-7 )],
4855             el_GR => [qw( el_GR.UTF-8 el_GR.ISO-8859-7 el_GR.ISO8859-7 )],
4856             en_AG => [qw( en_AG.UTF-8 )],
4857             en_AU => [qw( en_AU.UTF-8 en_AU.ISO-8859-1 en_AU.ISO8859-1 )],
4858             en_BW => [qw( en_BW.UTF-8 en_BW.ISO-8859-1 en_BW.ISO8859-1 )],
4859             en_CA => [qw( en_CA.UTF-8 en_CA.ISO-8859-1 en_CA.ISO8859-1 )],
4860             en_DK => [qw( en_DK.UTF-8 en_DK.ISO-8859-15 en_DK.ISO8859-15 )],
4861             en_GB => [qw( en_GB.UTF-8 en_GB.ISO-8859-1 en_GB.ISO8859-1 en_GB.ISO-8859-15 en_GB.ISO8859-15 )],
4862             en_HK => [qw( en_HK.UTF-8 en_HK.ISO-8859-1 en_HK.ISO8859-1 )],
4863             en_IE => [qw( en_IE.UTF-8 en_IE.ISO-8859-1 en_IE.ISO8859-1 en_IE.ISO-8859-15 en_IE.ISO8859-15 )],
4864             en_IN => [qw( en_IN.UTF-8 )],
4865             en_NG => [qw( en_NG.UTF-8 )],
4866             en_NZ => [qw( en_NZ.UTF-8 en_NZ.ISO-8859-1 en_NZ.ISO8859-1 )],
4867             en_PH => [qw( en_PH.UTF-8 en_PH.ISO-8859-1 en_PH.ISO8859-1 )],
4868             en_SG => [qw( en_SG.UTF-8 en_SG.ISO-8859-1 en_SG.ISO8859-1 )],
4869             en_US => [qw( en_US.UTF-8 en_US.ISO-8859-1 en_US.ISO8859-1 en_US.ISO-8859-15 en_US.ISO8859-15 )],
4870             en_ZA => [qw( en_ZA.UTF-8 en_ZA.ISO-8859-1 en_ZA.ISO8859-1 )],
4871             en_ZM => [qw( en_ZM.UTF-8 )],
4872             en_ZW => [qw( en_ZW.UTF-8 en_ZW.ISO-8859-1 en_ZW.ISO8859-1 )],
4873             eo => [qw( eo.UTF-8 eo.ISO-8859-3 eo.ISO8859-3 )],
4874             eo_US => [qw( eo_US.UTF-8 )],
4875             es_AR => [qw( es_AR.UTF-8 es_AR.ISO-8859-1 es_AR.ISO8859-1 )],
4876             es_BO => [qw( es_BO.UTF-8 es_BO.ISO-8859-1 es_BO.ISO8859-1 )],
4877             es_CL => [qw( es_CL.UTF-8 es_CL.ISO-8859-1 es_CL.ISO8859-1 )],
4878             es_CO => [qw( es_CO.UTF-8 es_CO.ISO-8859-1 es_CO.ISO8859-1 )],
4879             es_CR => [qw( es_CR.UTF-8 es_CR.ISO-8859-1 es_CR.ISO8859-1 )],
4880             es_CU => [qw( es_CU.UTF-8 )],
4881             es_DO => [qw( es_DO.UTF-8 es_DO.ISO-8859-1 es_DO.ISO8859-1 )],
4882             es_EC => [qw( es_EC.UTF-8 es_EC.ISO-8859-1 es_EC.ISO8859-1 )],
4883             es_ES => [qw( es_ES.UTF-8 es_ES.ISO-8859-1 es_ES.ISO8859-1 es_ES.ISO-8859-15 es_ES.ISO8859-15 )],
4884             es_GT => [qw( es_GT.UTF-8 es_GT.ISO-8859-1 es_GT.ISO8859-1 )],
4885             es_HN => [qw( es_HN.UTF-8 es_HN.ISO-8859-1 es_HN.ISO8859-1 )],
4886             es_MX => [qw( es_MX.UTF-8 es_MX.ISO-8859-1 es_MX.ISO8859-1 )],
4887             es_NI => [qw( es_NI.UTF-8 es_NI.ISO-8859-1 es_NI.ISO8859-1 )],
4888             es_PA => [qw( es_PA.UTF-8 es_PA.ISO-8859-1 es_PA.ISO8859-1 )],
4889             es_PE => [qw( es_PE.UTF-8 es_PE.ISO-8859-1 es_PE.ISO8859-1 )],
4890             es_PR => [qw( es_PR.UTF-8 es_PR.ISO-8859-1 es_PR.ISO8859-1 )],
4891             es_PY => [qw( es_PY.UTF-8 es_PY.ISO-8859-1 es_PY.ISO8859-1 )],
4892             es_SV => [qw( es_SV.UTF-8 es_SV.ISO-8859-1 es_SV.ISO8859-1 )],
4893             es_US => [qw( es_US.UTF-8 es_US.ISO-8859-1 es_US.ISO8859-1 )],
4894             es_UY => [qw( es_UY.UTF-8 es_UY.ISO-8859-1 es_UY.ISO8859-1 )],
4895             es_VE => [qw( es_VE.UTF-8 es_VE.ISO-8859-1 es_VE.ISO8859-1 )],
4896             et_EE => [qw( et_EE.UTF-8 et_EE.ISO-8859-1 et_EE.ISO8859-1 et_EE.ISO-8859-15 et_EE.ISO8859-15 )],
4897             eu_ES => [qw( eu_ES.UTF-8 eu_ES.ISO-8859-1 eu_ES.ISO8859-1 eu_ES.ISO-8859-15 eu_ES.ISO8859-15 )],
4898             eu_FR => [qw( eu_FR.UTF-8 eu_FR.ISO-8859-1 eu_FR.ISO8859-1 eu_FR.ISO-8859-15 eu_FR.ISO8859-15 )],
4899             fa_IR => [qw( fa_IR.UTF-8 )],
4900             ff_SN => [qw( ff_SN.UTF-8 )],
4901             fi_FI => [qw( fi_FI.UTF-8 fi_FI.ISO-8859-1 fi_FI.ISO8859-1 fi_FI.ISO-8859-15 fi_FI.ISO8859-15 )],
4902             fil_PH => [qw( fil_PH.UTF-8 )],
4903             fo_FO => [qw( fo_FO.UTF-8 fo_FO.ISO-8859-1 fo_FO.ISO8859-1 )],
4904             fr_BE => [qw( fr_BE.UTF-8 fr_BE.ISO-8859-1 fr_BE.ISO8859-1 fr_BE.ISO-8859-15 fr_BE.ISO8859-15 )],
4905             fr_CA => [qw( fr_CA.UTF-8 fr_CA.ISO-8859-1 fr_CA.ISO8859-1 )],
4906             fr_CH => [qw( fr_CH.UTF-8 fr_CH.ISO-8859-1 fr_CH.ISO8859-1 )],
4907             fr_FR => [qw( fr_FR.UTF-8 fr_FR.ISO-8859-1 fr_FR.ISO8859-1 fr_FR.ISO-8859-15 fr_FR.ISO8859-15 )],
4908             fr_LU => [qw( fr_LU.UTF-8 fr_LU.ISO-8859-1 fr_LU.ISO8859-1 fr_LU.ISO-8859-15 fr_LU.ISO8859-15 )],
4909             fur_IT => [qw( fur_IT.UTF-8 )],
4910             fy_DE => [qw( fy_DE.UTF-8 )],
4911             fy_NL => [qw( fy_NL.UTF-8 )],
4912             ga_IE => [qw( ga_IE.UTF-8 ga_IE.ISO-8859-1 ga_IE.ISO8859-1 ga_IE.ISO-8859-15 ga_IE.ISO8859-15 )],
4913             gd_GB => [qw( gd_GB.UTF-8 gd_GB.ISO-8859-15 gd_GB.ISO8859-15 )],
4914             gez_ER => [qw( gez_ER.UTF-8 )],
4915             gez_ET => [qw( gez_ET.UTF-8 )],
4916             gl_ES => [qw( gl_ES.UTF-8 gl_ES.ISO-8859-1 gl_ES.ISO8859-1 gl_ES.ISO-8859-15 gl_ES.ISO8859-15 )],
4917             gu_IN => [qw( gu_IN.UTF-8 )],
4918             gv_GB => [qw( gv_GB.UTF-8 gv_GB.ISO-8859-1 gv_GB.ISO8859-1 )],
4919             ha_NG => [qw( ha_NG.UTF-8 )],
4920             hak_TW => [qw( hak_TW.UTF-8 )],
4921             he_IL => [qw( he_IL.UTF-8 he_IL.ISO-8859-8 he_IL.ISO8859-8 )],
4922             hi_IN => [qw( hi_IN.UTF-8 )],
4923             hne_IN => [qw( hne_IN.UTF-8 )],
4924             hr_HR => [qw( hr_HR.UTF-8 hr_HR.ISO-8859-2 hr_HR.ISO8859-2 )],
4925             hsb_DE => [qw( hsb_DE.UTF-8 hsb_DE.ISO-8859-2 hsb_DE.ISO8859-2 )],
4926             ht_HT => [qw( ht_HT.UTF-8 )],
4927             hu_HU => [qw( hu_HU.UTF-8 hu_HU.ISO-8859-2 hu_HU.ISO8859-2 )],
4928             hy_AM => [qw( hy_AM.UTF-8 hy_AM.ARMSCII-8 hy_AM.ARMSCII8 )],
4929             ia_FR => [qw( ia_FR.UTF-8 )],
4930             id_ID => [qw( id_ID.UTF-8 id_ID.ISO-8859-1 id_ID.ISO8859-1 )],
4931             ig_NG => [qw( ig_NG.UTF-8 )],
4932             ik_CA => [qw( ik_CA.UTF-8 )],
4933             is_IS => [qw( is_IS.UTF-8 is_IS.ISO-8859-1 is_IS.ISO8859-1 )],
4934             it_CH => [qw( it_CH.UTF-8 it_CH.ISO-8859-1 it_CH.ISO8859-1 )],
4935             it_IT => [qw( it_IT.UTF-8 it_IT.ISO-8859-1 it_IT.ISO8859-1 it_IT.ISO-8859-15 it_IT.ISO8859-15 )],
4936             iu_CA => [qw( iu_CA.UTF-8 )],
4937             iw_IL => [qw( iw_IL.UTF-8 iw_IL.ISO-8859-8 iw_IL.ISO8859-8 )],
4938             ja_JP => [qw( ja_JP.UTF-8 ja_JP.EUC-JP ja_JP.EUCJP )],
4939             ka_GE => [qw( ka_GE.UTF-8 ka_GE.GEORGIAN-PS ka_GE.GEORGIANPS )],
4940             kk_KZ => [qw( kk_KZ.UTF-8 kk_KZ.PT154 kk_KZ.RK1048 )],
4941             kl_GL => [qw( kl_GL.UTF-8 kl_GL.ISO-8859-1 kl_GL.ISO8859-1 )],
4942             km_KH => [qw( km_KH.UTF-8 )],
4943             kn_IN => [qw( kn_IN.UTF-8 )],
4944             ko_KR => [qw( ko_KR.UTF-8 ko_KR.EUC-KR ko_KR.EUCKR )],
4945             kok_IN => [qw( kok_IN.UTF-8 )],
4946             ks_IN => [qw( ks_IN.UTF-8 )],
4947             ku_TR => [qw( ku_TR.UTF-8 ku_TR.ISO-8859-9 ku_TR.ISO8859-9 )],
4948             kw_GB => [qw( kw_GB.UTF-8 kw_GB.ISO-8859-1 kw_GB.ISO8859-1 )],
4949             ky_KG => [qw( ky_KG.UTF-8 )],
4950             lb_LU => [qw( lb_LU.UTF-8 )],
4951             lg_UG => [qw( lg_UG.UTF-8 lg_UG.ISO-8859-10 lg_UG.ISO8859-10 )],
4952             li_BE => [qw( li_BE.UTF-8 )],
4953             li_NL => [qw( li_NL.UTF-8 )],
4954             lij_IT => [qw( lij_IT.UTF-8 )],
4955             ln_CD => [qw( ln_CD.UTF-8 )],
4956             lo_LA => [qw( lo_LA.UTF-8 )],
4957             lt_LT => [qw( lt_LT.UTF-8 lt_LT.ISO-8859-13 lt_LT.ISO8859-13 )],
4958             lv_LV => [qw( lv_LV.UTF-8 lv_LV.ISO-8859-13 lv_LV.ISO8859-13 )],
4959             lzh_TW => [qw( lzh_TW.UTF-8 )],
4960             mag_IN => [qw( mag_IN.UTF-8 )],
4961             mai_IN => [qw( mai_IN.UTF-8 )],
4962             mg_MG => [qw( mg_MG.UTF-8 mg_MG.ISO-8859-15 mg_MG.ISO8859-15 )],
4963             mhr_RU => [qw( mhr_RU.UTF-8 )],
4964             mi_NZ => [qw( mi_NZ.UTF-8 mi_NZ.ISO-8859-13 mi_NZ.ISO8859-13 )],
4965             mk_MK => [qw( mk_MK.UTF-8 mk_MK.ISO-8859-5 mk_MK.ISO8859-5 )],
4966             ml_IN => [qw( ml_IN.UTF-8 )],
4967             mn_MN => [qw( mn_MN.UTF-8 )],
4968             mni_IN => [qw( mni_IN.UTF-8 )],
4969             mr_IN => [qw( mr_IN.UTF-8 )],
4970             ms_MY => [qw( ms_MY.UTF-8 ms_MY.ISO-8859-1 ms_MY.ISO8859-1 )],
4971             mt_MT => [qw( mt_MT.UTF-8 mt_MT.ISO-8859-3 mt_MT.ISO8859-3 )],
4972             my_MM => [qw( my_MM.UTF-8 )],
4973             nan_TW => [qw( nan_TW.UTF-8 )],
4974             nb_NO => [qw( nb_NO.UTF-8 nb_NO.ISO-8859-1 nb_NO.ISO8859-1 )],
4975             nds_DE => [qw( nds_DE.UTF-8 )],
4976             nds_NL => [qw( nds_NL.UTF-8 )],
4977             ne_NP => [qw( ne_NP.UTF-8 )],
4978             nhn_MX => [qw( nhn_MX.UTF-8 )],
4979             niu_NU => [qw( niu_NU.UTF-8 )],
4980             niu_NZ => [qw( niu_NZ.UTF-8 )],
4981             nl_AW => [qw( nl_AW.UTF-8 )],
4982             nl_BE => [qw( nl_BE.UTF-8 nl_BE.ISO-8859-1 nl_BE.ISO8859-1 nl_BE.ISO-8859-15 nl_BE.ISO8859-15 )],
4983             nl_NL => [qw( nl_NL.UTF-8 nl_NL.ISO-8859-1 nl_NL.ISO8859-1 nl_NL.ISO-8859-15 nl_NL.ISO8859-15 )],
4984             nn_NO => [qw( nn_NO.UTF-8 nn_NO.ISO-8859-1 nn_NO.ISO8859-1 )],
4985             nr_ZA => [qw( nr_ZA.UTF-8 )],
4986             nso_ZA => [qw( nso_ZA.UTF-8 )],
4987             oc_FR => [qw( oc_FR.UTF-8 oc_FR.ISO-8859-1 oc_FR.ISO8859-1 )],
4988             om_ET => [qw( om_ET.UTF-8 )],
4989             om_KE => [qw( om_KE.UTF-8 om_KE.ISO-8859-1 om_KE.ISO8859-1 )],
4990             or_IN => [qw( or_IN.UTF-8 )],
4991             os_RU => [qw( os_RU.UTF-8 )],
4992             pa_IN => [qw( pa_IN.UTF-8 )],
4993             pa_PK => [qw( pa_PK.UTF-8 )],
4994             pap_AN => [qw( pap_AN.UTF-8 )],
4995             pap_AW => [qw( pap_AW.UTF-8 )],
4996             pap_CW => [qw( pap_CW.UTF-8 )],
4997             pl_PL => [qw( pl_PL.UTF-8 pl_PL.ISO-8859-2 pl_PL.ISO8859-2 )],
4998             ps_AF => [qw( ps_AF.UTF-8 )],
4999             pt_BR => [qw( pt_BR.UTF-8 pt_BR.ISO-8859-1 pt_BR.ISO8859-1 )],
5000             pt_PT => [qw( pt_PT.UTF-8 pt_PT.ISO-8859-1 pt_PT.ISO8859-1 pt_PT.ISO-8859-15 pt_PT.ISO8859-15 )],
5001             quz_PE => [qw( quz_PE.UTF-8 )],
5002             raj_IN => [qw( raj_IN.UTF-8 )],
5003             ro_RO => [qw( ro_RO.UTF-8 ro_RO.ISO-8859-2 ro_RO.ISO8859-2 )],
5004             ru_RU => [qw( ru_RU.UTF-8 ru_RU.KOI8-R ru_RU.KOI8R ru_RU.ISO-8859-5 ru_RU.ISO8859-5 ru_RU.CP1251 )],
5005             ru_UA => [qw( ru_UA.UTF-8 ru_UA.KOI8-U ru_UA.KOI8U )],
5006             rw_RW => [qw( rw_RW.UTF-8 )],
5007             sa_IN => [qw( sa_IN.UTF-8 )],
5008             sat_IN => [qw( sat_IN.UTF-8 )],
5009             sc_IT => [qw( sc_IT.UTF-8 )],
5010             sd_IN => [qw( sd_IN.UTF-8 )],
5011             sd_PK => [qw( sd_PK.UTF-8 )],
5012             se_NO => [qw( se_NO.UTF-8 )],
5013             shs_CA => [qw( shs_CA.UTF-8 )],
5014             si_LK => [qw( si_LK.UTF-8 )],
5015             sid_ET => [qw( sid_ET.UTF-8 )],
5016             sk_SK => [qw( sk_SK.UTF-8 sk_SK.ISO-8859-2 sk_SK.ISO8859-2 )],
5017             sl_SI => [qw( sl_SI.UTF-8 sl_SI.ISO-8859-2 sl_SI.ISO8859-2 )],
5018             so_DJ => [qw( so_DJ.UTF-8 so_DJ.ISO-8859-1 so_DJ.ISO8859-1 )],
5019             so_ET => [qw( so_ET.UTF-8 )],
5020             so_KE => [qw( so_KE.UTF-8 so_KE.ISO-8859-1 so_KE.ISO8859-1 )],
5021             so_SO => [qw( so_SO.UTF-8 so_SO.ISO-8859-1 so_SO.ISO8859-1 )],
5022             sq_AL => [qw( sq_AL.UTF-8 sq_AL.ISO-8859-1 sq_AL.ISO8859-1 )],
5023             sq_MK => [qw( sq_MK.UTF-8 )],
5024             sr_ME => [qw( sr_ME.UTF-8 )],
5025             sr_RS => [qw( sr_RS.UTF-8 )],
5026             ss_ZA => [qw( ss_ZA.UTF-8 )],
5027             st_ZA => [qw( st_ZA.UTF-8 st_ZA.ISO-8859-1 st_ZA.ISO8859-1 )],
5028             sv_FI => [qw( sv_FI.UTF-8 sv_FI.ISO-8859-1 sv_FI.ISO8859-1 sv_FI.ISO-8859-15 sv_FI.ISO8859-15 )],
5029             sv_SE => [qw( sv_SE.UTF-8 sv_SE.ISO-8859-1 sv_SE.ISO8859-1 sv_SE.ISO-8859-15 sv_SE.ISO8859-15 )],
5030             sw_KE => [qw( sw_KE.UTF-8 )],
5031             sw_TZ => [qw( sw_TZ.UTF-8 )],
5032             szl_PL => [qw( szl_PL.UTF-8 )],
5033             ta_IN => [qw( ta_IN.UTF-8 )],
5034             ta_LK => [qw( ta_LK.UTF-8 )],
5035             tcy_IN => [qw( tcy_IN.UTF-8 )],
5036             te_IN => [qw( te_IN.UTF-8 )],
5037             tg_TJ => [qw( tg_TJ.UTF-8 tg_TJ.KOI8-T tg_TJ.KOI8T )],
5038             th_TH => [qw( th_TH.UTF-8 th_TH.TIS-620 th_TH.TIS620 )],
5039             the_NP => [qw( the_NP.UTF-8 )],
5040             ti_ER => [qw( ti_ER.UTF-8 )],
5041             ti_ET => [qw( ti_ET.UTF-8 )],
5042             tig_ER => [qw( tig_ER.UTF-8 )],
5043             tk_TM => [qw( tk_TM.UTF-8 )],
5044             tl_PH => [qw( tl_PH.UTF-8 tl_PH.ISO-8859-1 tl_PH.ISO8859-1 )],
5045             tn_ZA => [qw( tn_ZA.UTF-8 )],
5046             tr_CY => [qw( tr_CY.UTF-8 tr_CY.ISO-8859-9 tr_CY.ISO8859-9 )],
5047             tr_TR => [qw( tr_TR.UTF-8 tr_TR.ISO-8859-9 tr_TR.ISO8859-9 )],
5048             ts_ZA => [qw( ts_ZA.UTF-8 )],
5049             tt_RU => [qw( tt_RU.UTF-8 )],
5050             ug_CN => [qw( ug_CN.UTF-8 )],
5051             uk_UA => [qw( uk_UA.UTF-8 uk_UA.KOI8-U uk_UA.KOI8U )],
5052             unm_US => [qw( unm_US.UTF-8 )],
5053             ur_IN => [qw( ur_IN.UTF-8 )],
5054             ur_PK => [qw( ur_PK.UTF-8 )],
5055             uz_UZ => [qw( uz_UZ.UTF-8 uz_UZ.ISO-8859-1 uz_UZ.ISO8859-1 )],
5056             ve_ZA => [qw( ve_ZA.UTF-8 )],
5057             vi_VN => [qw( vi_VN.UTF-8 )],
5058             wa_BE => [qw( wa_BE.UTF-8 wa_BE.ISO-8859-1 wa_BE.ISO8859-1 wa_BE.ISO-8859-15 wa_BE.ISO8859-15 )],
5059             wae_CH => [qw( wae_CH.UTF-8 )],
5060             wal_ET => [qw( wal_ET.UTF-8 )],
5061             wo_SN => [qw( wo_SN.UTF-8 )],
5062             xh_ZA => [qw( xh_ZA.UTF-8 xh_ZA.ISO-8859-1 xh_ZA.ISO8859-1 )],
5063             yi_US => [qw( yi_US.UTF-8 yi_US.CP1255 )],
5064             yo_NG => [qw( yo_NG.UTF-8 )],
5065             yue_HK => [qw( yue_HK.UTF-8 )],
5066             zh_CN => [qw( zh_CN.UTF-8 zh_CN.GB18030 zh_CN.GBK zh_CN.GB2312 )],
5067             zh_HK => [qw( zh_HK.UTF-8 zh_HK.BIG5-HKSCS zh_HK.BIG5HKSCS )],
5068             zh_SG => [qw( zh_SG.UTF-8 zh_SG.GBK zh_SG.GB2312 )],
5069             zh_TW => [qw( zh_TW.UTF-8 zh_TW.EUC-TW zh_TW.EUCTW zh_TW.BIG5 )],
5070             zu_ZA => [qw( zu_ZA.UTF-8 zu_ZA.ISO-8859-1 zu_ZA.ISO8859-1 )],
5071             };
5072              
5073             our $DEFAULT =
5074             {
5075             ## The local currency symbol.
5076             currency_symbol => '€',
5077             ## The decimal point character, except for currency values, cannot be an empty string
5078             decimal_point => '.',
5079             ## The number of digits after the decimal point in the local style for currency values.
5080             frac_digits => 2,
5081             ## The sizes of the groups of digits, except for currency values. unpack( "C*", $grouping ) will give the number
5082             grouping => (CORE::chr(3) x 2),
5083             ## The standardized international currency symbol.
5084             int_curr_symbol => '€',
5085             ## The number of digits after the decimal point in an international-style currency value.
5086             int_frac_digits => 2,
5087             ## Same as n_cs_precedes, but for internationally formatted monetary quantities.
5088             int_n_cs_precedes => '',
5089             ## Same as n_sep_by_space, but for internationally formatted monetary quantities.
5090             int_n_sep_by_space => '',
5091             ## Same as n_sign_posn, but for internationally formatted monetary quantities.
5092             int_n_sign_posn => 1,
5093             ## Same as p_cs_precedes, but for internationally formatted monetary quantities.
5094             int_p_cs_precedes => 1,
5095             ## Same as p_sep_by_space, but for internationally formatted monetary quantities.
5096             int_p_sep_by_space => 0,
5097             ## Same as p_sign_posn, but for internationally formatted monetary quantities.
5098             int_p_sign_posn => 1,
5099             ## The decimal point character for currency values.
5100             mon_decimal_point => '.',
5101             ## Like grouping but for currency values.
5102             mon_grouping => (CORE::chr(3) x 2),
5103             ## The separator for digit groups in currency values.
5104             mon_thousands_sep => ',',
5105             ## Like p_cs_precedes but for negative values.
5106             n_cs_precedes => 1,
5107             ## Like p_sep_by_space but for negative values.
5108             n_sep_by_space => 0,
5109             ## Like p_sign_posn but for negative currency values.
5110             n_sign_posn => 1,
5111             ## The character used to denote negative currency values, usually a minus sign.
5112             negative_sign => '-',
5113             ## 1 if the currency symbol precedes the currency value for nonnegative values, 0 if it follows.
5114             p_cs_precedes => 1,
5115             ## 1 if a space is inserted between the currency symbol and the currency value for nonnegative values, 0 otherwise.
5116             p_sep_by_space => 0,
5117             ## The location of the positive_sign with respect to a nonnegative quantity and the currency_symbol, coded as follows:
5118             ## 0 Parentheses around the entire string.
5119             ## 1 Before the string.
5120             ## 2 After the string.
5121             ## 3 Just before currency_symbol.
5122             ## 4 Just after currency_symbol.
5123             p_sign_posn => 1,
5124             ## The character used to denote nonnegative currency values, usually the empty string.
5125             positive_sign => '',
5126             ## The separator between groups of digits before the decimal point, except for currency values
5127             thousands_sep => ',',
5128             };
5129              
5130             my $map =
5131             {
5132             decimal => [qw( decimal_point mon_decimal_point )],
5133             grouping => [qw( grouping mon_grouping )],
5134             position_neg => [qw( n_sign_posn int_n_sign_posn )],
5135             position_pos => [qw( n_sign_posn int_p_sign_posn )],
5136             precede => [qw( p_cs_precedes int_p_cs_precedes )],
5137             precede_neg => [qw( n_cs_precedes int_n_cs_precedes )],
5138             precision => [qw( frac_digits int_frac_digits )],
5139             sign_neg => [qw( negative_sign )],
5140             sign_pos => [qw( positive_sign )],
5141             space_pos => [qw( p_sep_by_space int_p_sep_by_space )],
5142             space_neg => [qw( n_sep_by_space int_n_sep_by_space )],
5143             symbol => [qw( currency_symbol int_curr_symbol )],
5144             thousand => [qw( thousands_sep mon_thousands_sep )],
5145             };
5146              
5147             sub init
5148             {
5149 131     131   355 my $self = shift( @_ );
5150 131         410 my $num = shift( @_ );
5151 131 50       706 return( $self->error( "No number was provided." ) ) if( !CORE::length( $num ) );
5152 131 100       813 return( Module::Generic::Infinity->new( $num ) ) if( POSIX::isinf( $num ) );
5153 130 100       581 return( Module::Generic::Nan->new( $num ) ) if( POSIX::isnan( $num ) );
5154 6     6   9491 use utf8;
  6         44  
  6         52  
5155 129         840 my @k = keys( %$map );
5156 129         1374 @$self{ @k } = ( '' x scalar( @k ) );
5157 129         523 $self->{lang} = '';
5158 129         359 $self->{default} = $DEFAULT;
5159 129         533 $self->{_init_strict_use_sub} = 1;
5160 129         847 $self->SUPER::init( @_ );
5161 129         616 my $default = $self->default;
5162             # $self->message( 3, "Getting current locale" );
5163 129         961 my $curr_locale = POSIX::setlocale( &POSIX::LC_ALL );
5164             ## $self->message( 3, "Current locale is '$curr_locale'" );
5165 129 100 33     1117 if( $self->{lang} )
    50          
5166             {
5167             # $self->message( 3, "Language requested '$self->{lang}'." );
5168 67         158 try
5169 67     67   133 {
5170             # $self->message( 3, "Current locale found is '$curr_locale'" );
5171             local $try_locale = sub
5172             {
5173 67         125 my $loc;
5174             # $self->message( 3, "Checking language '$_[0]'" );
5175             ## The user provided only a language code such as fr_FR. We try it, and also other known combination like fr_FR.UTF-8 and fr_FR.ISO-8859-1, fr_FR.ISO8859-1
5176             ## Try several possibilities
5177             ## RT https://rt.cpan.org/Public/Bug/Display.html?id=132664
5178 67 50       214 if( index( $_[0], '.' ) == -1 )
5179             {
5180             # $self->message( 3, "Language '$_[0]' is a bareword, check if it works as is." );
5181 67         294 $loc = POSIX::setlocale( &POSIX::LC_ALL, $_[0] );
5182             # $self->message( 3, "Succeeded to set up locale for language '$_[0]'" ) if( $loc );
5183 67         246 $_[0] =~ s/^(?<locale>[a-z]{2,3})_(?<country>[a-z]{2})$/$+{locale}_\U$+{country}\E/;
5184 67 50 33     323 if( !$loc && CORE::exists( $SUPPORTED_LOCALES->{ $_[0] } ) )
5185             {
5186             # $self->message( 3, "Language '$_[0]' is supported, let's check for right variation" );
5187 0         0 foreach my $supported ( @{$SUPPORTED_LOCALES->{ $_[0] }} )
  0         0  
5188             {
5189 0 0       0 if( ( $loc = POSIX::setlocale( &POSIX::LC_ALL, $supported ) ) )
5190             {
5191 0         0 $_[0] = $supported;
5192             # $self->message( "-> Language variation '$supported' found." );
5193 0         0 last;
5194             }
5195             }
5196             }
5197             }
5198             ## We got something like fr_FR.ISO-8859
5199             ## The user is specific, so we try as is
5200             else
5201             {
5202             # $self->message( 3, "Language '$_[0]' is specific enough, let's try it." );
5203 0         0 $loc = POSIX::setlocale( &POSIX::LC_ALL, $_[0] );
5204             }
5205 67         300 return( $loc );
5206 67         378 };
5207            
5208             ## $self->message( 3, "Current locale is: '$curr_locale'" );
5209 67 50       258 if( my $loc = $try_locale->( $self->{lang} ) )
5210             {
5211             # $self->message( 3, "Succeeded in setting locale for language '$self->{lang}'" );
5212             ## $self->message( 3, "Succeeded in setting locale to '$self->{lang}'." );
5213 67         507 my $lconv = POSIX::localeconv();
5214             ## Set back the LC_ALL to what it was, because we do not want to disturb the user environment
5215 67         767 POSIX::setlocale( &POSIX::LC_ALL, $curr_locale );
5216             ## $self->messagef( 3, "POSIX::localeconv() returned %d items", scalar( keys( %$lconv ) ) );
5217 67 50 50     1158 $default = $lconv if( $lconv && scalar( keys( %$lconv ) ) );
5218             }
5219             else
5220             {
5221 0         0 return( $self->error( "Language \"$self->{lang}\" is not supported by your system." ) );
5222             }
5223             }
5224 67 50       550 catch( $e )
  67 50       233  
  67 50       277  
  67 0       169  
  67 50       172  
  67         171  
  67         135  
  67         134  
  67         304  
  0         0  
  67         144  
  0         0  
  67         293  
  67         148  
  67         173  
  67         256  
  0         0  
  0         0  
  0         0  
  0         0  
5225 0     0   0 {
5226 0         0 return( $self->error( "An error occurred while getting the locale information for \"$self->{lang}\": $e" ) );
5227 0 0 33     0 }
  0 0 33     0  
  0 0       0  
  0 50       0  
  0         0  
  0         0  
  67         1190  
  0         0  
5228             }
5229             elsif( $curr_locale && ( my $lconv = POSIX::localeconv() ) )
5230             {
5231 62 50       336 $default = $lconv if( scalar( keys( %$lconv ) ) );
5232             ## To simulate running on Windows
5233             # my $fail = [qw(
5234             # frac_digits
5235             # int_frac_digits
5236             # n_cs_precedes
5237             # n_sep_by_space
5238             # n_sign_posn
5239             # p_cs_precedes
5240             # p_sep_by_space
5241             # p_sign_posn
5242             # )];
5243             # @$lconv{ @$fail } = ( -1 ) x scalar( @$fail );
5244             ## $self->message( 3, "No language provided, but current locale '$curr_locale' found" );
5245 62         204 $self->{lang} = $curr_locale;
5246             }
5247              
5248             ## This serves 2 purposes:
5249             ## 1) to silence warnings issued from Number::Format when it uses an empty string when evaluating a number, e.g. '' == 1
5250             ## 2) to ensure that blank numerical values are not interpreted to anything else than equivalent of empty
5251             ## For example, an empty frac_digits will default to 2 in Number::Format even if the user does not want any. Of course, said user could also have set it to 0
5252             ## So here we use this hash reference of numeric properties to ensure the option parameters are set to a numeric value (0) when they are empty.
5253 129         1677 my $numerics =
5254             {
5255             grouping => 0,
5256             frac_digits => 0,
5257             int_frac_digits => 0,
5258             int_n_cs_precedes => 0,
5259             int_p_cs_precedes => 0,
5260             int_n_sep_by_space => 0,
5261             int_p_sep_by_space => 0,
5262             int_n_sign_posn => 1,
5263             int_p_sign_posn => 1,
5264             mon_grouping => 0,
5265             n_cs_precedes => 0,
5266             n_sep_by_space => 0,
5267             n_sign_posn => 1,
5268             p_cs_precedes => 0,
5269             p_sep_by_space => 0,
5270             ## Position of positive sign. 1 = before (0 = parentheses)
5271             p_sign_posn => 1,
5272             };
5273            
5274 129         713 foreach my $prop ( keys( %$map ) )
5275             {
5276 1677         3953 my $ref = $map->{ $prop };
5277             ## Already set by user
5278 1677 100       5136 next if( CORE::length( $self->{ $prop } ) );
5279 1505         3752 foreach my $lconv_prop ( @$ref )
5280             {
5281 2690 100       6617 if( CORE::defined( $default->{ $lconv_prop } ) )
5282             {
5283             ## Number::Format bug RT #71044 when running on Windows
5284             ## https://rt.cpan.org/Ticket/Display.html?id=71044
5285             ## This is a workaround when values are lower than 0 (i.e. -1)
5286 62 0 33     380 if( CORE::exists( $numerics->{ $lconv_prop } ) &&
      33        
5287             CORE::length( $default->{ $lconv_prop } ) &&
5288             $default->{ $lconv_prop } < 0 )
5289             {
5290 0         0 $default->{ $lconv_prop } = $numerics->{ $lconv_prop };
5291             }
5292 62         289 $self->$prop( $default->{ $lconv_prop } );
5293 62         253 last;
5294             }
5295             else
5296             {
5297 2628         10753 $self->$prop( $default->{ $lconv_prop } );
5298             }
5299             }
5300             }
5301            
5302             # $Number::Format::DEFAULT_LOCALE->{int_curr_symbol} = 'EUR';
5303 129         607 try
5304 0         0 {
5305             ## Those are unsupported by Number::Format
5306 129         991 my $skip =
5307             {
5308             int_n_cs_precedes => 1,
5309             int_p_cs_precedes => 1,
5310             int_n_sep_by_space => 1,
5311             int_p_sep_by_space => 1,
5312             int_n_sign_posn => 1,
5313             int_p_sign_posn => 1,
5314             };
5315 129         305 my $opts = {};
5316 129         662 foreach my $prop ( CORE::keys( %$map ) )
5317             {
5318             ## $self->message( 3, "Checking property \"$prop\" value \"", overload::StrVal( $self->{ $prop } ), "\" (", $self->$prop->defined ? 'defined' : 'undefined', ")." );
5319 1677         2496 my $prop_val;
5320 1677 100       4843 if( $self->$prop->defined )
5321             {
5322 234         612 $prop_val = $self->$prop;
5323             }
5324             ## To prevent Number::Format from defaulting to property values not in sync with ours
5325             ## Because it seems the POSIX::setlocale only affect one module
5326             else
5327             {
5328 1443         2520 $prop_val = '';
5329             }
5330             ## $self->message( 3, "Using property \"$prop\" value \"$prop_val\" (", CORE::defined( $prop_val ) ? 'defined' : 'undefined', ") [ref=", ref( $prop_val ), "]." );
5331             ## Need to set all the localeconv properties for Number::Format, because it uses mon_thousand_sep intsead of just thousand_sep
5332 1677         3747 foreach my $lconv_prop ( @{$map->{ $prop }} )
  1677         4501  
5333             {
5334 3096 100       7342 CORE::next if( CORE::exists( $skip->{ $lconv_prop } ) );
5335             ## Cannot be undefined, but can be empty string
5336 2322         5467 $opts->{ $lconv_prop } = "$prop_val";
5337 2322 100 100     9637 if( !CORE::length( $opts->{ $lconv_prop } ) && CORE::exists( $numerics->{ $lconv_prop } ) )
5338             {
5339 1156         2884 $opts->{ $lconv_prop } = $numerics->{ $lconv_prop };
5340             }
5341             }
5342             }
5343             ## $self->message( 3, "Using following options for Number::Format: ", sub{ $self->dumper( $opts ) } );
5344 6     6   5654 no warnings qw( uninitialized );
  6         13  
  6         324  
5345 129         1333 $self->{_fmt} = Number::Format->new( %$opts );
5346 6     6   36 use warnings;
  6         11  
  6         6212  
5347 129     129   292 }
5348 129 100       1149 catch( $e )
  129 50       39710  
  129 50       457  
  129 0       316  
  129 50       376  
  129         257  
  129         283  
  129         328  
  129         635  
  2         10  
  127         335  
  0         0  
  129         631  
  129         352  
  129         375  
  129         491  
  0         0  
  0         0  
  0         0  
  0         0  
5349 0     0   0 {
5350             ## $self->message( 3, "Error trapped in creating a Number::Format object: '$e'" );
5351 0         0 return( $self->error( "Unable to create a Number::Format object: $e" ) );
5352 0 0 33     0 }
  0 0 33     0  
  0 0       0  
  0 50       0  
  0         0  
  0         0  
  129         2780  
  0         0  
5353 129         623 $self->{_original} = $num;
5354 129         257 try
5355 129     129   284 {
5356 129 100       1820 if( $num !~ /^$RE{num}{real}$/ )
5357             {
5358 1         241 $self->{_number} = $self->{_fmt}->unformat_number( $num );
5359             }
5360             else
5361             {
5362 128         30741 $self->{_number} = $num;
5363             }
5364             ## $self->message( 3, "Unformatted number is: '$self->{_number}'" );
5365 129 100       1921 return( $self->error( "Invalid number: $num" ) ) if( !defined( $self->{_number} ) );
5366             }
5367 129 100       872 catch( $e )
  128 50       479  
  129 50       432  
  129 0       325  
  129 50       345  
  129         266  
  129         242  
  129         347  
  129         566  
  2         7  
  127         362  
  0         0  
  129         499  
  129         307  
  129         342  
  129         435  
  0         0  
  0         0  
  0         0  
  0         0  
5368 0     0   0 {
5369 0         0 return( $self->error( "Invalid number: $num" ) );
5370 0 0 66     0 }
  0 0 66     0  
  0 50       0  
  0 100       0  
  0         0  
  0         0  
  129         2254  
  1         49  
5371 128         3774 return( $self );
5372             }
5373              
5374 3     3   20 sub abs { return( shift->_func( 'abs' ) ); }
5375              
5376             # sub asin { return( shift->_func( 'asin', { posix => 1 } ) ); }
5377              
5378 1     1   372 sub atan { return( shift->_func( 'atan', { posix => 1 } ) ); }
5379              
5380 1     1   14 sub atan2 { return( shift->_func( 'atan2', @_ ) ); }
5381              
5382 4 100   4   43 sub as_boolean { return( Module::Generic::Boolean->new( shift->{_number} ? 1 : 0 ) ); }
5383              
5384 0     0   0 sub as_string { return( shift->{_number} ) }
5385              
5386 1     1   17 sub cbrt { return( shift->_func( 'cbrt', { posix => 1 } ) ); }
5387              
5388 1     1   7 sub ceil { return( shift->_func( 'ceil', { posix => 1 } ) ); }
5389              
5390 1     1   7 sub chr { return( Module::Generic::Scalar->new( CORE::chr( $_[0]->{_number} ) ) ); }
5391              
5392             sub clone
5393             {
5394 67     67   214 my $self = shift( @_ );
5395 67 100       295 my $num = @_ ? shift( @_ ) : $self->{_number};
5396 67 50       309 return( Module::Generic::Infinity->new( $num ) ) if( POSIX::isinf( $num ) );
5397 67 50       245 return( Module::Generic::Nan->new( $num ) ) if( POSIX::isnan( $num ) );
5398 67         467 my @keys = keys( %$map );
5399 67         270 push( @keys, qw( lang debug ) );
5400 67         162 my $hash = {};
5401 67         818 @$hash{ @keys } = @$self{ @keys };
5402 67         346 return( $self->new( $num, $hash ) );
5403             }
5404              
5405             sub compute
5406             {
5407 141     141   630 my( $self, $other, $swap, $opts ) = @_;
5408 141 100       928 my $other_val = Scalar::Util::blessed( $other ) ? $other : "\"$other\"";
5409 141 100       839 my $operation = $swap ? "${other_val} $opts->{op} \$self->{_number}" : "\$self->{_number} $opts->{op} ${other_val}";
5410 141 100       686 if( $opts->{return_object} )
    100          
5411             {
5412 37         2921 my $res = eval( $operation );
5413 6     6   55 no overloading;
  6         16  
  6         770  
5414 37 50 33     287 warn( "Error with return formula \"$operation\" using object $self having number '$self->{_number}': $@" ) if( $@ && $self->_warnings_is_enabled );
5415 37 50       117 return if( $@ );
5416 37 100       185 return( Module::Generic::Scalar->new( $res ) ) if( $opts->{type} eq 'scalar' );
5417 36 100       250 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
5418 31 100       167 return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
5419             ## undef may be returned for example on platform supporting NaN when using <=>
5420 27 50       180 return( $self->clone( $res ) ) if( defined( $res ) );
5421 0         0 return;
5422             }
5423             elsif( $opts->{boolean} )
5424             {
5425 101         8067 my $res = eval( $operation );
5426 6     6   40 no overloading;
  6         50  
  6         1667  
5427 101 50 33     730 warn( "Error with boolean formula \"$operation\" using object $self having number '$self->{_number}': $@" ) if( $@ && $self->_warnings_is_enabled );
5428 101 50       363 return if( $@ );
5429 101 100       682 return( $res ? $self->true : $self->false );
5430             }
5431             else
5432             {
5433 3         211 return( eval( $operation ) );
5434             }
5435             }
5436              
5437 1     1   15 sub cos { return( shift->_func( 'cos' ) ); }
5438              
5439 4     4   19 sub currency { return( shift->_set_get_prop( 'symbol', @_ ) ); }
5440              
5441 3951     3951   9202 sub decimal { return( shift->_set_get_prop( 'decimal', @_ ) ); }
5442              
5443 129     129   665 sub default { return( shift->_set_get_hash_as_mix_object( 'default', @_ ) ); }
5444              
5445 1     1   17 sub exp { return( shift->_func( 'exp' ) ); }
5446              
5447 2     2   18 sub floor { return( shift->_func( 'floor', { posix => 1 } ) ); }
5448              
5449             sub format
5450             {
5451 2     2   5 my $self = shift( @_ );
5452 2 50 33     16 my $precision = ( @_ && $_[0] =~ /^\d+$/ ) ? shift( @_ ) : $self->precision;
5453 6     6   52 no overloading;
  6         12  
  6         8484  
5454 2         14 my $num = $self->{_number};
5455             ## If value provided was undefined, we leave it undefined, otherwise we would be at risk of returning 0, and 0 is very different from undefined
5456 2 50       10 return( $num ) if( !defined( $num ) );
5457 2         8 my $fmt = $self->{_fmt};
5458 2         5 try
5459 2     2   6 {
5460             ## Amazingly enough, when a precision > 0 is provided, format_number will discard it if the number, before formatting, did not have decimals... Then, what is the point of formatting a number then?
5461             ## To circumvent this, we provide the precision along with the "add trailing zeros" parameter expected by Number::Format
5462             ## return( $fmt->format_number( $num, $precision, 1 ) );
5463 2         19 my $res = $fmt->format_number( "$num", $precision, 1 );
5464 2 50       70 return if( !defined( $res ) );
5465 2         19 return( Module::Generic::Scalar->new( $res ) );
5466             }
5467 2 50       29 catch( $e )
  0 50       0  
  2 50       8  
  2 0       10  
  2 50       13  
  2         9  
  2         6  
  2         7  
  2         10  
  0         0  
  2         6  
  0         0  
  2         8  
  2         5  
  2         7  
  2         7  
  0         0  
  0         0  
  0         0  
  0         0  
5468 0     0   0 {
5469 0         0 return( $self->error( "Error formatting number \"$num\": $e" ) );
5470 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  2         44  
  2         26  
5471             }
5472              
5473 2     2   21 sub format_binary { return( Module::Generic::Scalar->new( CORE::sprintf( '%b', shift->{_number} ) ) ); }
5474              
5475             sub format_bytes
5476             {
5477 1     1   4 my $self = shift( @_ );
5478             # no overloading;
5479 1         5 my $num = $self->{_number};
5480             ## See comment in format() method
5481 1 50       5 return( $num ) if( !defined( $num ) );
5482 1         5 my $fmt = $self->{_fmt};
5483 1         1 try
5484 1     1   2 {
5485             ## return( $fmt->format_bytes( $num, @_ ) );
5486 1         8 my $res = $fmt->format_bytes( "$num", @_ );
5487 1 50       252 return if( !defined( $res ) );
5488 1         5 return( Module::Generic::Scalar->new( $res ) );
5489             }
5490 1 50       21 catch( $e )
  0 50       0  
  1 50       4  
  1 0       4  
  1 50       4  
  1         2  
  1         4  
  1         2  
  1         6  
  0         0  
  1         4  
  0         0  
  1         5  
  1         5  
  1         3  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
5491 0     0   0 {
5492 0         0 return( $self->error( "Error formatting number \"$num\": $e" ) );
5493 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         33  
  1         19  
5494             }
5495              
5496 2     2   17 sub format_hex { return( Module::Generic::Scalar->new( CORE::sprintf( '0x%X', shift->{_number} ) ) ); }
5497              
5498             sub format_money
5499             {
5500 1     1   4 my $self = shift( @_ );
5501 1 50 33     22 my $precision = ( @_ && $_[0] =~ /^\d+$/ ) ? shift( @_ ) : $self->precision;
5502 1 50       6 my $currency_symbol = @_ ? shift( @_ ) : $self->currency;
5503             # no overloading;
5504 1         5 my $num = $self->{_number};
5505             ## See comment in format() method
5506 1 50       10 return( $num ) if( !defined( $num ) );
5507 1         7 my $fmt = $self->{_fmt};
5508 1         21 try
5509 1     1   2 {
5510             ## Even though the Number::Format instantiated is set with a currency symbol,
5511             ## Number::Format will not respect it, and revert to USD if nothing was provided as argument
5512             ## This highlights that Number::Format is designed to be used more for exporting function rather than object methods
5513             ## $self->message( 3, "Passing Number = '$num', precision = '$precision', currency symbol = '$currency_symbol'." );
5514             ## return( $fmt->format_price( $num, $precision, $currency_symbol ) );
5515 1         11 my $res = $fmt->format_price( "$num", "$precision", "$currency_symbol" );
5516 1 50       241 return if( !defined( $res ) );
5517 1         6 return( Module::Generic::Scalar->new( $res ) );
5518             }
5519 1 50       13 catch( $e )
  0 50       0  
  1 50       2  
  1 0       3  
  1 50       5  
  1         8  
  1         5  
  1         3  
  1         10  
  0         0  
  1         6  
  0         0  
  1         6  
  1         11  
  1         5  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
5520 0     0   0 {
5521 0         0 return( $self->error( "Error formatting number \"$num\": $e" ) );
5522 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         25  
  1         18  
5523             }
5524              
5525             sub format_negative
5526             {
5527 1     1   406 my $self = shift( @_ );
5528             # no overloading;
5529 1         3 my $num = $self->{_number};
5530             ## See comment in format() method
5531 1 50       11 return( $num ) if( !defined( $num ) );
5532 1         9 my $fmt = $self->{_fmt};
5533 1         4 try
5534 1     1   2 {
5535 1         5 my $new = $self->format;
5536             ## $self->message( 3, "Formatted number '$self->{_number}' now is '$new'" );
5537             ## return( $fmt->format_negative( $new, @_ ) );
5538 1         5 my $res = $fmt->format_negative( "$new", @_ );
5539             ## $self->message( 3, "Result is '$res'" );
5540 1 50       23 return if( !defined( $res ) );
5541 1         4 return( Module::Generic::Scalar->new( $res ) );
5542             }
5543 1 50       17 catch( $e )
  0 50       0  
  1 50       4  
  1 0       2  
  1 50       3  
  1         2  
  1         3  
  1         2  
  1         12  
  0         0  
  1         10  
  0         0  
  1         15  
  1         15  
  1         4  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
5544 0     0   0 {
5545 0         0 return( $self->error( "Error formatting number \"$num\": $e" ) );
5546 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         31  
  1         64  
5547             }
5548              
5549             sub format_picture
5550             {
5551 0     0   0 my $self = shift( @_ );
5552 6     6   53 no overloading;
  6         14  
  6         12468  
5553 0         0 my $num = $self->{_number};
5554             ## See comment in format() method
5555 0 0       0 return( $num ) if( !defined( $num ) );
5556 0         0 my $fmt = $self->{_fmt};
5557 0         0 try
5558 0     0   0 {
5559             ## return( $fmt->format_picture( $num, @_ ) );
5560 0         0 my $res = $fmt->format_picture( "$num", @_ );
5561 0 0       0 return if( !defined( $res ) );
5562 0         0 return( Module::Generic::Scalar->new( $res ) );
5563             }
5564 0 0       0 catch( $e )
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
5565 0     0   0 {
5566 0         0 return( $self->error( "Error formatting number \"$num\": $e" ) );
5567 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
5568             }
5569              
5570 3563     3563   10393 sub formatter { return( shift->_set_get_object( 'formatter', 'Number::Format', @_ ) ); }
5571              
5572             ## https://stackoverflow.com/a/483708/4814971
5573             sub from_binary
5574             {
5575 1     1   3 my $self = shift( @_ );
5576 1         3 my $binary = shift( @_ );
5577 1 50 33     15 return if( !defined( $binary ) || !CORE::length( $binary ) );
5578 1         3 try
5579 1     1   2 {
5580             ## Nice trick to convert from binary to decimal. See perlfunc -> oct
5581 1         4 my $res = CORE::oct( "0b${binary}" );
5582 1 50       4 return if( !defined( $res ) );
5583 1         5 return( $self->clone( $res ) );
5584             }
5585 1 50       18 catch( $e )
  0 50       0  
  1 50       4  
  1 0       2  
  1 50       4  
  1         3  
  1         3  
  1         4  
  1         5  
  0         0  
  1         4  
  0         0  
  1         5  
  1         4  
  1         4  
  1         4  
  0         0  
  0         0  
  0         0  
  0         0  
5586 0     0   0 {
5587 0         0 return( $self->error( "Error while getting number from hexadecimal value \"$hex\": $e" ) );
5588 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         32  
  1         20  
5589             }
5590              
5591             sub from_hex
5592             {
5593 1     1   4 my $self = shift( @_ );
5594 1         3 my $hex = shift( @_ );
5595 1 50 33     16 return if( !defined( $hex ) || !CORE::length( $hex ) );
5596 1         3 try
5597 1     1   2 {
5598 1         3 my $res = CORE::hex( $hex );
5599 1 50       4 return if( !defined( $res ) );
5600 1         6 return( $self->clone( $res ) );
5601             }
5602 1 50       18 catch( $e )
  0 50       0  
  1 50       4  
  1 0       3  
  1 50       3  
  1         3  
  1         3  
  1         2  
  1         7  
  0         0  
  1         4  
  0         0  
  1         6  
  1         3  
  1         3  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
5603 0     0   0 {
5604 0         0 return( $self->error( "Error while getting number from hexadecimal value \"$hex\": $e" ) );
5605 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         33  
  1         20  
5606             }
5607              
5608 4017     4017   9742 sub grouping { return( shift->_set_get_prop( 'grouping', @_ ) ); }
5609              
5610 1     1   445 sub int { return( shift->_func( 'int' ) ); }
5611              
5612             *is_decimal = \&is_float;
5613              
5614 1     1   8 sub is_finite { return( shift->_func( 'isfinite', { posix => 1 }) ); }
5615              
5616 1     1   17 sub is_float { return( (POSIX::modf( shift->{_number} ))[0] != 0 ); }
5617              
5618             # sub is_infinite { return( !(shift->is_finite) ); }
5619 0     0   0 sub is_infinite { return( shift->_func( 'isinf', { posix => 1 }) ); }
5620              
5621 1     1   12 sub is_int { return( (POSIX::modf( shift->{_number} ))[0] == 0 ); }
5622              
5623 1     1   7 sub is_nan { return( shift->_func( 'isnan', { posix => 1}) ); }
5624              
5625             *is_neg = \&is_negative;
5626              
5627 4     4   304 sub is_negative { return( shift->_func( 'signbit', { posix => 1 }) != 0 ); }
5628              
5629 1     1   8 sub is_normal { return( shift->_func( 'isnormal', { posix => 1}) ); }
5630              
5631             *is_pos = \&is_positive;
5632              
5633 4     4   28 sub is_positive { return( shift->_func( 'signbit', { posix => 1 }) == 0 ); }
5634              
5635 68     68   262 sub lang { return( shift->_set_get_scalar_as_object( 'lang', @_ ) ); }
5636              
5637 1     1   16 sub length { return( $_[0]->clone( CORE::length( $_[0]->{_number} ) ) ); }
5638              
5639 1     1   12 sub locale { return( shift->_set_get_scalar_as_object( 'lang', @_ ) ); }
5640              
5641 1     1   6 sub log { return( shift->_func( 'log' ) ); }
5642              
5643 1     1   7 sub log2 { return( shift->_func( 'log2', { posix => 1 } ) ); }
5644              
5645 1     1   7 sub log10 { return( shift->_func( 'log10', { posix => 1 } ) ); }
5646              
5647 3     3   30 sub max { return( shift->_func( 'fmax', @_, { posix => 1 } ) ); }
5648              
5649 2     2   16 sub min { return( shift->_func( 'fmin', @_, { posix => 1 } ) ); }
5650              
5651 1     1   8 sub mod { return( shift->_func( 'fmod', @_, { posix => 1 } ) ); }
5652              
5653             ## This is used so that we can change formatter when the user changes thousand separator, decimal separator, precision or currency
5654             sub new_formatter
5655             {
5656 3563     3563   6314 my $self = shift( @_ );
5657 3563         6384 my $hash = {};
5658 3563 50       7400 if( @_ )
5659             {
5660 0 0 0     0 if( @_ == 1 && $self->_is_hash( $_[0] ) )
    0          
5661             {
5662 0         0 $hash = shift( @_ );
5663             }
5664             elsif( !( @_ % 2 ) )
5665             {
5666 0         0 $hash = { @_ };
5667             }
5668             else
5669             {
5670 0         0 return( $self->error( "Invalid parameters provided: '", join( "', '", @_ ), "'." ) );
5671             }
5672             }
5673             else
5674             {
5675 3563         15170 my @keys = keys( %$map );
5676             # @$hash{ @keys } = @$self{ @keys };
5677 3563         7455 for( @keys )
5678             {
5679 46319         130654 $hash->{ $_ } = $self->$_();
5680             }
5681             }
5682 3563         5963 try
5683 3563     3563   4857 {
5684 3563         6425 my $opts = {};
5685 3563         17623 foreach my $prop ( keys( %$map ) )
5686             {
5687 46319 100       92038 $opts->{ $map->{ $prop }->[0] } = $hash->{ $prop } if( CORE::defined( $hash->{ $prop } ) );
5688             }
5689 3563         17820 return( Number::Format->new( %$opts ) );
5690             }
5691 3563 50       18423 catch( $e )
  0 0       0  
  3563 50       8978  
  3563 0       5533  
  3563 50       7201  
  3563         5147  
  3563         5138  
  3563         5991  
  3563         6563  
  3563         6898  
  0         0  
  0         0  
  3563         450943  
  3563         7130  
  3563         7565  
  3563         7984  
  0         0  
  0         0  
  0         0  
  0         0  
5692 0     0   0 {
5693 0         0 return( $self->error( "Error while trying to get a Number::Format object: $e" ) );
5694 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  3563         32171  
  3563         34670  
5695             }
5696              
5697 1     1   6 sub oct { return( shift->_func( 'oct' ) ); }
5698              
5699 4017     4017   9048 sub position_neg { return( shift->_set_get_prop( 'position_neg', @_ ) ); }
5700              
5701 4017     4017   9480 sub position_pos { return( shift->_set_get_prop( 'position_pos', @_ ) ); }
5702              
5703 0     0   0 sub pow { return( shift->_func( 'pow', @_, { posix => 1 } ) ); }
5704              
5705 4018     4018   9150 sub precede { return( shift->_set_get_prop( 'precede', @_ ) ); }
5706              
5707 4017     4017   9241 sub precede_neg { return( shift->_set_get_prop( 'precede_neg', @_ ) ); }
5708              
5709 0     0   0 sub precede_pos { return( shift->_set_get_prop( 'precede', @_ ) ); }
5710              
5711 3956     3956   8743 sub precision { return( shift->_set_get_prop( 'precision', @_ ) ); }
5712              
5713 0     0   0 sub rand { return( shift->_func( 'rand' ) ); }
5714              
5715 1 50   1   33 sub round { return( $_[0]->clone( CORE::sprintf( '%.*f', CORE::int( CORE::length( $_[1] ) ? $_[1] : 0 ), $_[0]->{_number} ) ) ); }
5716              
5717 0     0   0 sub round_zero { return( shift->_func( 'round', @_, { posix => 1 } ) ); }
5718              
5719             sub round2
5720             {
5721 0     0   0 my $self = shift( @_ );
5722 6     6   56 no overloading;
  6         15  
  6         9718  
5723 0         0 my $num = $self->{_number};
5724             ## See comment in format() method
5725 0 0       0 return( $num ) if( !defined( $num ) );
5726 0         0 my $fmt = $self->{_fmt};
5727 0         0 try
5728 0     0   0 {
5729             ## return( $fmt->round( $num, @_ ) );
5730 0         0 my $res = $fmt->round( $num, @_ );
5731 0 0       0 return if( !defined( $res ) );
5732 0         0 my $clone = $self->clone;
5733 0         0 $clone->{_number} = $res;
5734 0         0 return( $clone );
5735             }
5736 0 0       0 catch( $e )
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
5737 0     0   0 {
5738 0         0 return( $self->error( "Error rounding number \"$num\": $e" ) );
5739 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
5740             }
5741              
5742 0     0   0 sub scalar { return( shift->as_string ); }
5743              
5744 3888     3888   9135 sub sign_neg { return( shift->_set_get_prop( 'sign_neg', @_ ) ); }
5745              
5746 3888     3888   9260 sub sign_pos { return( shift->_set_get_prop( 'sign_pos', @_ ) ); }
5747              
5748 1     1   6 sub sin { return( shift->_func( 'sin' ) ); }
5749              
5750             *space = \&space_pos;
5751              
5752 4017     4017   9888 sub space_neg { return( shift->_set_get_prop( 'space_neg', @_ ) ); }
5753              
5754 4017     4017   9294 sub space_pos { return( shift->_set_get_prop( 'space_pos', @_ ) ); }
5755              
5756 1     1   5 sub sqrt { return( shift->_func( 'sqrt' ) ); }
5757              
5758 3980     3980   8891 sub symbol { return( shift->_set_get_prop( 'symbol', @_ ) ); }
5759              
5760 1     1   7 sub tan { return( shift->_func( 'tan', { posix => 1 } ) ); }
5761              
5762 4018     4018   9162 sub thousand { return( shift->_set_get_prop( 'thousand', @_ ) ); }
5763              
5764             sub unformat
5765             {
5766 1     1   12 my $self = shift( @_ );
5767 1         3 my $num = shift( @_ );
5768 1 50       6 return if( !defined( $num ) );
5769 1         8 try
5770 1     1   7 {
5771 1         29 my $num2 = $self->{_fmt}->unformat_number( $num );
5772 1         52 my $clone = $self->clone;
5773 1         5 $clone->{_original} = $num;
5774 1         3 $clone->{_number} = $num2;
5775 1         17 return( $clone );
5776             }
5777 1 50       20 catch( $e )
  0 50       0  
  1 50       11  
  1 0       4  
  1 50       3  
  1         2  
  1         2  
  1         2  
  1         11  
  0         0  
  1         5  
  0         0  
  1         10  
  1         4  
  1         4  
  1         4  
  0         0  
  0         0  
  0         0  
  0         0  
5778 0     0   0 {
5779 0         0 return( $self->error( "Unable to unformat the number \"$num\": $e" ) );
5780 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         41  
  1         16  
5781             }
5782              
5783             sub _func
5784             {
5785 29     29   98 my $self = shift( @_ );
5786 29   50     231 my $func = shift( @_ ) || return( $self->error( "No function was provided." ) );
5787             ## $self->message( 3, "Arguments received are: '", join( "', '", @_ ), "'." );
5788 29         103 my $opts = {};
5789 29 100       169 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
5790 29 100       154 my $namespace = $opts->{posix} ? 'POSIX' : 'CORE';
5791 29 100       135 my $val = @_ ? shift( @_ ) : undef;
5792 29 100       171 my $expr = defined( $val ) ? "${namespace}::${func}( \$self->{_number}, $val )" : "${namespace}::${func}( \$self->{_number} )";
5793             ## $self->message( 3, "Evaluating '$expr'" );
5794 29         2513 my $res = eval( $expr );
5795             ## $self->message( 3, "Result for number '$self->{_number}' is '$res'" );
5796 29 50       196 $self->message( 3, "Error: $@" ) if( $@ );
5797 29 50       106 return( $self->pass_error( $@ ) ) if( $@ );
5798 29 50       107 return if( !defined( $res ) );
5799 29 50       173 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
5800 29 50       134 return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
5801 29         164 return( $self->clone( $res ) );
5802             }
5803              
5804             sub _set_get_prop
5805             {
5806 51805     51805   78275 my $self = shift( @_ );
5807 51805         75323 my $prop = shift( @_ );
5808 51805 100       99550 if( @_ )
5809             {
5810 3563         7616 my $val = shift( @_ );
5811 3563 100 66     7869 $val = $val->scalar if( $self->_is_object( $val ) && $val->isa( 'Module::Generic::Scalar' ) );
5812             ## $self->message( 3, "Setting value \"$val\" (", defined( $val ) ? 'defined' : 'undefined', ") for property \"$prop\"." );
5813 3563 50 66     11600 if( $val ne $self->{ $prop } || !CORE::defined( $val ) )
5814             {
5815             # $self->{ $prop } = $val;
5816 3563         9415 $self->_set_get_scalar_as_object( $prop, $val );
5817             ## If an error was set, we return nothing
5818 3563 50       10682 $self->formatter( $self->new_formatter ) || return;
5819             }
5820             }
5821             # return( $self->{ $prop } );
5822 51805         95782 return( $self->_set_get_scalar_as_object( $prop ) );
5823             }
5824              
5825             AUTOLOAD
5826             {
5827 0     0   0 my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
5828 0   0     0 my $self = shift( @_ ) || return;
5829 0   0     0 my $fmt_obj = $self->{_fmt} || return;
5830 0         0 my $code = $fmt_obj->can( $method );
5831 0 0       0 if( $code )
5832             {
5833 0         0 try
5834 0     0   0 {
5835 0         0 return( $code->( $fmt_obj, @_ ) );
5836             }
5837 0 0       0 catch( $e )
  0 0       0  
  0 0       0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
5838 0     0   0 {
5839 0         0 CORE::warn( $e );
5840 0         0 return;
5841 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
5842             }
5843 0         0 return;
5844             };
5845              
5846             package Module::Generic::NumberSpecial;
5847             BEGIN
5848             {
5849 6     6   61 use strict;
  6         16  
  6         171  
5850 6     6   33 use warnings;
  6         12  
  6         275  
5851 6     6   41 use parent -norequire, qw( Module::Generic::Number );
  6         13  
  6         71  
5852 5     5   963 use overload ('""' => sub{ $_[0]->{_number} },
5853 0     0   0 '+=' => sub{ &_catchall( @_[0..2], '+' ) },
5854 0     0   0 '-=' => sub{ &_catchall( @_[0..2], '-' ) },
5855 1     1   8 '*=' => sub{ &_catchall( @_[0..2], '*' ) },
5856 0     0   0 '/=' => sub{ &_catchall( @_[0..2], '/' ) },
5857 0     0   0 '%=' => sub{ &_catchall( @_[0..2], '%' ) },
5858 0     0   0 '**=' => sub{ &_catchall( @_[0..2], '**' ) },
5859 0     0   0 '<<=' => sub{ &_catchall( @_[0..2], '<<' ) },
5860 0     0   0 '>>=' => sub{ &_catchall( @_[0..2], '>>' ) },
5861 0     0   0 'x=' => sub{ &_catchall( @_[0..2], 'x' ) },
5862 0     0   0 '.=' => sub{ &_catchall( @_[0..2], '.' ) },
5863 6         140 nomethod => \&_catchall,
5864             fallback => 1,
5865 6     6   2098 );
  6         13  
5866 6     6   1168 use Want;
  6         13  
  6         483  
5867 6     6   39 use POSIX ();
  6         21  
  6         154  
5868 6     6   3853 our( $VERSION ) = '0.1.0';
5869             };
5870              
5871             sub new
5872             {
5873 17     17   49 my $this = shift( @_ );
5874 17   66     201 return( bless( { _number => CORE::shift( @_ ) } => ( ref( $this ) || $this ) ) );
5875             }
5876              
5877 1     1   38 sub clone { return( shift->new( @_ ) ); }
5878              
5879 0     0   0 sub is_finite { return( 0 ); }
5880              
5881 0     0   0 sub is_float { return( 0 ); }
5882              
5883 0     0   0 sub is_infinite { return( 0 ); }
5884              
5885 0     0   0 sub is_int { return( 0 ); }
5886              
5887 0     0   0 sub is_nan { return( 0 ); }
5888              
5889 2     2   11 sub is_normal { return( 0 ); }
5890              
5891 0     0   0 sub length { return( CORE::length( $self->{_number} ) ); }
5892              
5893             sub _catchall
5894             {
5895 1     1   9 my( $self, $other, $swap, $op ) = @_;
5896 1 50       13 my $expr = $swap ? "$other $op $self->{_number}" : "$self->{_number} $op $other";
5897 1         70 my $res = eval( $expr );
5898             ## print( ref( $self ), "::_catchall: evaluating $expr => $res\n" );
5899 1 50       9 CORE::warn( "Error evaluating expression \"$expr\": $@" ) if( $@ );
5900 1 50       3 return if( $@ );
5901 1 50       7 return( Module::Generic::Number->new( $res ) ) if( POSIX::isnormal( $res ) );
5902 1 50       8 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
5903 0 0       0 return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
5904 0         0 return( $res );
5905             }
5906              
5907             sub _func
5908             {
5909 7     7   19 my $self = shift( @_ );
5910 7   50     30 my $func = shift( @_ ) || return( $self->error( "No function was provided." ) );
5911 7         14 my $opts = {};
5912 7 100       31 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
5913 7 100       25 my $namespace = $opts->{posix} ? 'POSIX' : 'CORE';
5914 7 100       23 my $val = @_ ? shift( @_ ) : undef;
5915 7 100       42 my $expr = defined( $val ) ? "${namespace}::${func}( $self->{_number}, $val )" : "${namespace}::${func}( $self->{_number} )";
5916 7         468 my $res = eval( $expr );
5917             ## $self->message( 3, "Error: $@" ) if( $@ );
5918             ## print( STDERR ref( $self ), "::_func -> evaluating '$expr' -> '$res'\n" );
5919 7 50       94 CORE::warn( $@ ) if( $@ );
5920 7 50       27 return if( !defined( $res ) );
5921 7 100       39 return( Module::Generic::Number->new( $res ) ) if( POSIX::isnormal( $res ) );
5922 4 50       21 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
5923 0 0       0 return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
5924 0         0 return( $res );
5925             }
5926              
5927             AUTOLOAD
5928             {
5929 0     0   0 my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
5930             ## print( STDERR "$AUTOLOAD: called for method \"$method\"\n" );
5931             ## If we are chained, return our null object, so the chain continues to work
5932 0 0       0 if( want( 'OBJECT' ) )
5933             {
5934             ## No, this is NOT a typo. rreturn() is a function of module Want
5935 0         0 print( STDERR "$AUTOLOAD: Returning the object itself (", ref( $_[0] ), ")\n" );
5936 0         0 rreturn( $_[0] );
5937             }
5938             ## Otherwise, we return infinity, whether positive or negative or NaN depending on what was set
5939             ## print( STDERR "$AUTOLOAD: returning '", $_[0]->{_number}, "'\n" );
5940 0         0 return( $_[0]->{_number} );
5941             };
5942              
5943       0     DESTROY {};
5944              
5945             ## Purpose is to allow chaining of methods when infinity is returned
5946             ## At the end of the chain, Inf or -Inf is returned
5947             package Module::Generic::Infinity;
5948             BEGIN
5949             {
5950 6     6   53 use strict;
  6         12  
  6         143  
5951 6     6   35 use warnings;
  6         22  
  6         217  
5952 6     6   32 use parent -norequire, qw( Module::Generic::NumberSpecial );
  6         15  
  6         29  
5953 6     6   563 our( $VERSION ) = '0.1.0';
5954             };
5955              
5956 1     1   6 sub is_infinite { return( 1 ); }
5957              
5958             package Module::Generic::Nan;
5959             BEGIN
5960             {
5961 6     6   35 use strict;
  6         13  
  6         185  
5962 6     6   29 use warnings;
  6         10  
  6         182  
5963 6     6   30 use parent -norequire, qw( Module::Generic::NumberSpecial );
  6         14  
  6         26  
5964 6     6   507 our( $VERSION ) = '0.1.0';
5965             };
5966              
5967 1     1   7 sub is_nan { return( 1 ); }
5968              
5969              
5970             package Module::Generic::Hash;
5971             BEGIN
5972             {
5973 6     6   34 use strict;
  6         15  
  6         127  
5974 6     6   31 use warnings::register;
  6         13  
  6         814  
5975 6     6   37 use parent -norequire, qw( Module::Generic );
  6         12  
  6         28  
5976             use overload (
5977             ## '""' => 'as_string',
5978 1     1   11 'eq' => sub { _obj_eq(@_) },
5979 1     1   4 'ne' => sub { !_obj_eq(@_) },
5980 4     4   21 '<' => sub { _obj_comp( @_, '<') },
5981 3     3   26 '>' => sub { _obj_comp( @_, '>') },
5982 1     1   6 '<=' => sub { _obj_comp( @_, '<=') },
5983 2     2   12 '>=' => sub { _obj_comp( @_, '>=') },
5984 0     0   0 '==' => sub { _obj_comp( @_, '>=') },
5985 0     0   0 '!=' => sub { _obj_comp( @_, '>=') },
5986 1     1   5 'lt' => sub { _obj_comp( @_, 'lt') },
5987 1     1   6 'gt' => sub { _obj_comp( @_, 'gt') },
5988 0     0   0 'le' => sub { _obj_comp( @_, 'le') },
5989 0     0   0 'ge' => sub { _obj_comp( @_, 'ge') },
5990 6         110 fallback => 1,
5991 6     6   1476 );
  6         12  
5992 6     6   1253 use Data::Dumper;
  6         15  
  6         342  
5993 6     6   4669 use JSON;
  6         55704  
  6         39  
5994 6     6   930 use Clone ();
  6         14  
  6         116  
5995 6     6   33 use Regexp::Common;
  6         12  
  6         59  
5996             };
5997              
5998             sub new
5999             {
6000 134     134   468 my $that = shift( @_ );
6001 134   66     647 my $class = ref( $that ) || $that;
6002 134   50     517 my $data = shift( @_ ) ||
6003             return( $that->error( "No hash was provided to initiate a $class hash object." ) );
6004 134 50       624 return( $that->error( "I was expecting an hash, but instead got '$data'." ) ) if( Scalar::Util::reftype( $data ) ne 'HASH' );
6005 134         343 my $tied = tied( %$data );
6006 134 50       356 return( $that->error( "Hash provided is already tied to ", ref( $tied ), " and our package $class cannot use it, or it would disrupt the tie." ) ) if( $tied );
6007 134         313 my %hash = ();
6008             ## This enables access to the hash just like a real hash while still the user an call our object methods
6009 134         1469 my $obj = tie( %hash, 'Module::Generic::TieHash', {
6010             disable => ['Module::Generic'],
6011             debug => 0,
6012             });
6013 134         564 my $self = bless( \%hash => $class );
6014 134         706 $obj->enable( 1 );
6015 134         1141 my @keys = CORE::keys( %$data );
6016 134         4744 @hash{ @keys } = @$data{ @keys };
6017 134         1310 $obj->enable( 0 );
6018 134         832 $self->SUPER::init( @_ );
6019 134         515 $obj->enable( 1 );
6020 134         748 return( $self );
6021             }
6022              
6023 1     1   6 sub as_string { return( shift->dump ); }
6024              
6025             sub clone
6026             {
6027 1     1   5 my $self = shift( @_ );
6028 1         5 $self->_tie_object->enable( 0 );
6029 1         5 my $data = $self->{data};
6030 1         31 my $clone = Clone::clone( $data );
6031 1         6 $self->_tie_object->enable( 1 );
6032 1         8 return( $self->new( $clone ) );
6033             }
6034              
6035 4     4   19 sub debug { return( shift->_internal( 'debug', '_set_get_number', @_ ) ); }
6036              
6037 2     2   583 sub defined { CORE::defined( $_[0]->{ $_[1] } ); }
6038              
6039 1     1   12 sub delete { return( CORE::delete( shift->{ shift( @_ ) } ) ); }
6040              
6041             sub dump
6042             {
6043 3     3   9 my $self = shift( @_ );
6044 3         10 return( $self->_dumper( $self ) );
6045             }
6046              
6047             sub each
6048             {
6049 1     1   3 my $self = shift( @_ );
6050 1   50     5 my $code = shift( @_ ) || return( $self->error( "No subroutine callback as provided for each" ) );
6051 1 50       6 return( $self->error( "I was expecting a reference to a subroutine for the callback to each, but got '$code' instead." ) ) if( ref( $code ) ne 'CODE' );
6052 1         5 while( my( $k, $v ) = CORE::each( %$self ) )
6053             {
6054 4 50       13 CORE::defined( $code->( $k, $v ) ) || CORE::last;
6055             }
6056 1         4 return( $self );
6057             }
6058              
6059 1     1   6 sub exists { return( CORE::exists( shift->{ shift( @_ ) } ) ); }
6060              
6061 1     1   6 sub for { return( shift->foreach( @_ ) ); }
6062              
6063             sub foreach
6064             {
6065 1     1   3 my $self = shift( @_ );
6066 1   50     5 my $code = shift( @_ ) || return( $self->error( "No subroutine callback as provided for each" ) );
6067 1 50       5 return( $self->error( "I was expecting a reference to a subroutine for the callback to each, but got '$code' instead." ) ) if( ref( $code ) ne 'CODE' );
6068 1         5 CORE::foreach my $k ( CORE::keys( %$self ) )
6069             {
6070 4         1742 local $_ = $self->{ $k };
6071 4 50       20 CORE::defined( $code->( $k, $self->{ $k } ) ) || CORE::last;
6072             }
6073 1         556 return( $self );
6074             }
6075              
6076 0     0   0 sub get { return( $_[0]->{ $_[1] } ); }
6077              
6078             sub json
6079             {
6080 2     2   4 my $self = shift( @_ );
6081 2         5 my $opts = {};
6082 2 100       10 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
6083 2         8 $self->_tie_object->enable( 0 );
6084 2         11 my $data = $self->{data};
6085 2         6 my $json;
6086 2 100       6 if( $opts->{pretty} )
6087             {
6088 1         60 $json = JSON->new->pretty->utf8->indent(1)->relaxed(1)->canonical(1)->allow_nonref->encode( $data );
6089             }
6090             else
6091             {
6092 1         17 $json = JSON->new->utf8->canonical(1)->allow_nonref->encode( $data );
6093             }
6094 2         30 $self->_tie_object->enable( 1 );
6095 2         9 return( Module::Generic::Scalar->new( $json ) );
6096             }
6097              
6098             # $h->keys->sort
6099 1     1   655 sub keys { return( Module::Generic::Array->new( [ CORE::keys( %{$_[0]} ) ] ) ); }
  1         7  
6100              
6101 21     21   53 sub length { return( Module::Generic::Number->new( CORE::scalar( CORE::keys( %{$_[0]} ) ) ) ); }
  21         155  
6102              
6103             sub merge
6104             {
6105 2     2   6 my $self = shift( @_ );
6106 2         4 my $hash = {};
6107 2         5 $hash = shift( @_ );
6108 2 50 33     21 return( $self->error( "No valid hash provided." ) ) if( !$hash || Scalar::Util::reftype( $hash ) ne 'HASH' );
6109             ## $self->message( 3, "Hash provided is: ", sub{ $self->dumper( $hash ) } );
6110 2         5 my $opts = {};
6111 2 100 66     12 $opts = pop( @_ ) if( @_ && ref( $_[-1] ) eq 'HASH' );
6112 2 100       7 $opts->{overwrite} = 1 unless( CORE::exists( $opts->{overwrite} ) );
6113 2         7 $self->_tie_object->enable( 0 );
6114 2         9 my $data = $self->{data};
6115 2         6 my $seen = {};
6116             local $copy = sub
6117             {
6118 4     4   8 my $this = shift( @_ );
6119 4         7 my $to = shift( @_ );
6120 4         7 my $p = {};
6121 4 100 66     18 $p = shift( @_ ) if( @_ && ref( $_[-1] ) eq 'HASH' );
6122             ## $self->message( 3, "Merging hash ", sub{ $self->dumper( $this ) }, " to hash ", sub{ $self->dumper( $to ) }, " and with parameters ", sub{ $self->dumper( $p ) } );
6123 4         16 CORE::foreach my $k ( CORE::keys( %$this ) )
6124             {
6125             # $self->message( 3, "Skipping existing property '$k'." ) if( CORE::exists( $to->{ $k } ) && !$p->{overwrite} );
6126 14 100 100     44 next if( CORE::exists( $to->{ $k } ) && !$p->{overwrite} );
6127 8 100 33     34 if( ref( $this->{ $k } ) eq 'HASH' ||
      66        
6128             ( Scalar::Util::blessed( $this->{ $k } ) && $this->{ $k }->isa( 'Module::Generic::Hash' ) ) )
6129             {
6130 2         9 my $addr = Scalar::Util::refaddr( $this->{ $k } );
6131             # $self->message( 3, "Checking if hash in property '$k' was already processed with address '$addr'." );
6132 2 50       8 if( CORE::exists( $seen->{ $addr } ) )
6133             {
6134 0         0 $to->{ $k } = $seen->{ $addr };
6135 0         0 next;
6136             }
6137             else
6138             {
6139 2 100       12 $to->{ $k } = {} unless( Scalar::Util::reftype( $to->{ $k } ) eq 'HASH' );
6140 2         11 $copy->( $this->{ $k }, $to->{ $k } );
6141             }
6142 2         6 $seen->{ $addr } = $this->{ $k };
6143             }
6144             else
6145             {
6146 6         19 $to->{ $k } = $this->{ $k };
6147             }
6148             }
6149 2         14 };
6150             ## $self->message( 3, "Propagating hash ", sub{ $self->dumper( $hash ) }, " to hash ", sub{ $self->dumper( $data ) } );
6151 2         8 $copy->( $hash, $data, $opts );
6152 2         8 $self->_tie_object->enable( 1 );
6153 2         26 return( $self );
6154             }
6155              
6156 0     0   0 sub reset { %{$_[0]} = () };
  0         0  
6157              
6158 0     0   0 sub set { $_[0]->{ $_[1] } = $_[2]; }
6159              
6160 0     0   0 sub undef { %{$_[0]} = () };
  0         0  
6161              
6162             sub values
6163             {
6164 1     1   3 my $self = shift( @_ );
6165 1         3 my $code;
6166 1 50 33     10 $code = shift( @_ ) if( @_ && ref( $_[0] ) eq 'CODE' );
6167 1         3 my $opts = {};
6168 1 50       8 $opts = pop( @_ ) if( Scalar::Util::reftype( $_[-1] ) eq 'HASH' );
6169 1 50       4 if( $code )
6170             {
6171 1 50       4 if( $opts->{sort} )
6172             {
6173 1         7 return( Module::Generic::Array->new( [ CORE::map( $code->( $_ ), CORE::sort( CORE::values( %$self ) ) ) ] ) );
6174             }
6175             else
6176             {
6177 0         0 return( Module::Generic::Array->new( [ CORE::map( $code->( $_ ), CORE::values( %$self ) ) ] ) );
6178             }
6179             }
6180             else
6181             {
6182 0 0       0 if( $opts->{sort} )
6183             {
6184 0         0 return( Module::Generic::Array->new( [ CORE::sort( CORE::values( %$self ) ) ] ) );
6185             }
6186             else
6187             {
6188 0         0 return( Module::Generic::Array->new( [ CORE::values( %$self ) ] ) );
6189             }
6190             }
6191             }
6192              
6193             # sub _dumper
6194             # {
6195             # my $self = shift( @_ );
6196             # if( !$self->{_dumper} )
6197             # {
6198             # my $d = Data::Dumper->new;
6199             # $d->Indent( 1 );
6200             # $d->Useqq( 1 );
6201             # $d->Terse( 1 );
6202             # $d->Sortkeys( 1 );
6203             # $self->{_dumper} = $d;
6204             # }
6205             # return( $self->{_dumper}->Dumper( @_ ) );
6206             # }
6207             #
6208             sub _dumper
6209             {
6210 5     5   10 my $self = shift( @_ );
6211 5         12 $self->_tie_object->enable( 0 );
6212 5         28 my $data = $self->{data};
6213 5         36 my $d = Data::Dumper->new( [ $data ] );
6214 5         179 $d->Indent( 1 );
6215 5         77 $d->Useqq( 1 );
6216 5         83 $d->Terse( 1 );
6217 5         36 $d->Sortkeys( 1 );
6218             # $d->Freezer( '' );
6219 5         36 $d->Bless( '' );
6220             # return( $d->Dump );
6221 5         34 my $str = $d->Dump;
6222 5         259 $self->_tie_object->enable( 1 );
6223 5         52 return( $str );
6224             }
6225              
6226             sub _internal
6227             {
6228 4     4   11 my $self = shift( @_ );
6229 4         10 my $field = shift( @_ );
6230 4         8 my $meth = shift( @_ );
6231             # print( STDERR ref( $self ), "::_internal -> Caling method '$meth' for field '$field' with value '", join( "', '", @_ ), "'\n" );
6232 4         15 $self->_tie_object->enable( 0 );
6233 4         12 my( @resA, $resB );
6234 4 50       12 if( wantarray )
6235             {
6236 0         0 @resA = $self->$meth( $field, @_ );
6237             # $self->message( "Resturn list value is: '@resA'" );
6238             }
6239             else
6240             {
6241 4         21 $resB = $self->$meth( $field, @_ );
6242             # $self->message( "Resturn scalar value is: '$resB'" );
6243             }
6244 4         14 $self->_tie_object->enable( 1 );
6245 4 50       26 return( wantarray ? @resA : $resB );
6246             }
6247              
6248             sub _obj_comp
6249             {
6250 12     12   47 my( $self, $other, $swap, $op ) = @_;
6251 12         32 my( $lA, $lB );
6252 12         48 $lA = $self->length;
6253 12 100 66     153 if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Hash' ) )
    50          
6254             {
6255 7         35 $lB = $other->length;
6256             }
6257             elsif( $other =~ /^$RE{num}{real}$/ )
6258             {
6259 5         764 $lB = $other;
6260             }
6261             else
6262             {
6263 0         0 return;
6264             }
6265 12 100       129 my $expr = $swap ? "$lB $op $lA" : "$lA $op $lB";
6266 12         1316 return( eval( $expr ) );
6267             }
6268              
6269 0     0   0 sub _printer { return( shift->printer( @_ ) ); }
6270              
6271             sub _obj_eq
6272             {
6273 6     6   919920 no overloading;
  6         18  
  6         1027  
6274 2     2   6 my $self = shift( @_ );
6275 2         4 my $other = shift( @_ );
6276 2         10 my $strA = $self->_dumper( $self );
6277 2         5 my $strB;
6278 2 50 33     17 if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Hash' ) )
    0          
6279             {
6280 2         8 $strB = $other->dump;
6281             }
6282             elsif( Scalar::Util::reftype( $other ) eq 'HASH' )
6283             {
6284 0         0 $strB = $self->_dumper( $other )
6285             }
6286             else
6287             {
6288 0         0 return( 0 );
6289             }
6290 2         17 return( $strA eq $strB );
6291             }
6292              
6293             sub _tie_object
6294             {
6295 28     28   51 my $self = shift( @_ );
6296 28         111 return( tied( %$self ) );
6297             }
6298              
6299             package Module::Generic::TieHash;
6300             BEGIN
6301             {
6302 6     6   47 use strict;
  6         16  
  6         153  
6303 6     6   38 use warnings::register;
  6         15  
  6         910  
6304 6     6   45 use parent -norequire, qw( Module::Generic );
  6         19  
  6         68  
6305 6     6   348 use Scalar::Util ();
  6         17  
  6         156  
6306 6     6   4217 our( $VERSION ) = '0.1.0';
6307             };
6308              
6309             sub TIEHASH
6310             {
6311 134     134   480 my $self = shift( @_ );
6312 134         288 my $opts = {};
6313 134 50       584 $opts = shift( @_ ) if( @_ );
6314 134 50       675 if( Scalar::Util::reftype( $opts ) ne 'HASH' )
6315             {
6316 0 0       0 warn( "Parameters provided ($opts) is not an hash reference.\n" ) if( $self->_warnings_is_enabled );
6317 0         0 return;
6318             }
6319 134         308 my $disable = [];
6320 134 50       811 $disable = $opts->{disable} if( Scalar::Util::reftype( $opts->{disable} ) );
6321 134         309 my $list = {};
6322 134         718 @$list{ @$disable } = ( 1 ) x scalar( @$disable );
6323             my $hash =
6324             {
6325             ## The caller sets this to its class, so we can differentiate calls from inside and outside our caller's package
6326             disable => $list,
6327             debug => $opts->{debug},
6328             ## When disabled, the Tie::Hash system will return hash key values directly under $self instead of $self->{data}
6329             ## Disabled by default so the new() method can access its setup data directly under $self
6330             ## Then new() can call enable to active it
6331 134         808 enable => 0,
6332             ## Where to store the actual hash data
6333             data => {},
6334             };
6335 134   33     770 my $class = ref( $self ) || $self;
6336 134         625 return( bless( $hash => $class ) );
6337             }
6338              
6339             sub CLEAR
6340             {
6341 0     0   0 my $self = shift( @_ );
6342 0         0 my $data = $self->{data};
6343 0         0 %$data = ();
6344             }
6345              
6346             sub DELETE
6347             {
6348 1     1   3 my $self = shift( @_ );
6349 1         3 my $data = $self->{data};
6350 1         3 my $key = shift( @_ );
6351 1         5 my $caller = caller;
6352 1 50 33     4 if( $self->_exclude( $caller ) || !$self->{enable} )
6353             # if( !$self->{enable} )
6354             {
6355 0         0 CORE::delete( $self->{ $key } );
6356             }
6357             else
6358             {
6359 1         8 CORE::delete( $data->{ $key } );
6360             }
6361             }
6362              
6363             sub EXISTS
6364             {
6365 3     3   8 my $self = shift( @_ );
6366 3         8 my $data = $self->{data};
6367 3         8 my $key = shift( @_ );
6368 3         7 my $caller = caller;
6369 3 50 33     10 if( $self->_exclude( $caller ) || !$self->{enable} )
6370             # if( !$self->{enable} )
6371             {
6372 0         0 CORE::exists( $self->{ $key } );
6373             }
6374             else
6375             {
6376 3         24 CORE::exists( $data->{ $key } );
6377             }
6378             }
6379              
6380             sub FETCH
6381             {
6382 576     576   1124 my $self = shift( @_ );
6383 576         1027 my $data = $self->{data};
6384 576         956 my $key = shift( @_ );
6385 576         1020 my $caller = caller;
6386             ## print( STDERR "FETCH($caller)[enable=$self->{enable}] <- '$key''\n" );
6387 576 100 100     1152 if( $self->_exclude( $caller ) || !$self->{enable} )
6388             # if( !$self->{enable} )
6389             {
6390             #print( STDERR "FETCH($caller)[owner calling, enable=$self->{enable}] <- '$key' <- '$self->{$key}'\n" );
6391 554         2178 return( $self->{ $key } )
6392             }
6393             else
6394             {
6395             #print( STDERR "FETCH($caller)[enable=$self->{enable}] <- '$key' <- '$data->{$key}'\n" );
6396 22         104 return( $data->{ $key } );
6397             }
6398             }
6399              
6400             sub FIRSTKEY
6401             {
6402 26     26   73 my $self = shift( @_ );
6403 26         74 my $data = $self->{data};
6404 26         59 my @keys = ();
6405 26         80 my $caller = caller;
6406 26 50 33     112 if( $self->_exclude( $caller ) || !$self->{enable} )
6407             # if( !$self->{enable} )
6408             {
6409 0         0 @keys = keys( %$self );
6410             }
6411             else
6412             {
6413 26         125 @keys = keys( %$data );
6414             }
6415 26         89 $self->{ITERATOR} = \@keys;
6416 26         134 return( shift( @keys ) );
6417             }
6418              
6419             sub NEXTKEY
6420             {
6421 88     88   2428 my $self = shift( @_ );
6422 88         144 my $data = $self->{data};
6423 88 50       219 my $keys = ref( $self->{ITERATOR} ) ? $self->{ITERATOR} : [];
6424 88         244 return( shift( @$keys ) );
6425             }
6426              
6427             sub SCALAR
6428             {
6429 0     0   0 my $self = shift( @_ );
6430 0         0 my $data = $self->{data};
6431 0         0 my $caller = caller;
6432 0 0 0     0 if( $self->_exclude( $caller ) || !$self->{enable} )
6433             # if( !$self->{enable} )
6434             {
6435 0         0 return( scalar( keys( %$self ) ) );
6436             }
6437             else
6438             {
6439 0         0 return( scalar( keys( %$data ) ) );
6440             }
6441             }
6442              
6443             sub STORE
6444             {
6445 3947     3947   6450 my $self = shift( @_ );
6446 3947         5631 my $data = $self->{data};
6447 3947         6916 my( $key, $val ) = @_;
6448 3947         5967 my $caller = caller;
6449 3947 100 66     6436 if( $self->_exclude( $caller ) || !$self->{enable} )
6450             # if( !$self->{enable} )
6451             {
6452             #print( STDERR "STORE($caller)[owner calling] <- '$key' -> '$val'\n" );
6453 807         2574 $self->{ $key } = $val;
6454             }
6455             else
6456             {
6457             #print( STDERR "STORE($caller)[enable=$self->{enable}] <- '$key' -> '$val'\n" );
6458 3140         11819 $data->{ $key } = $val;
6459             }
6460             }
6461              
6462 430     430   1448 sub enable { return( shift->_set_get_boolean( 'enable', @_ ) ); }
6463              
6464             sub _exclude
6465             {
6466 4553     4553   6317 my $self = shift( @_ );
6467 4553         5977 my $caller = shift( @_ );
6468             ## $self->message( 3, "Disable hash contains: ", sub{ $self->dump( $self->{disable} ) });
6469 4553         13296 return( CORE::exists( $self->{disable}->{ $caller } ) );
6470             }
6471              
6472             package Module::Generic::Tie;
6473             BEGIN
6474             {
6475 6     6   49 use Tie::Hash;
  6         14  
  6         314  
6476 6     6   118 our( @ISA ) = qw( Tie::Hash );
6477 6         5902 our( $VERSION ) = '0.1.0';
6478             };
6479              
6480             sub TIEHASH
6481             {
6482 0     0     my $self = shift( @_ );
6483 0           my $pkg = ( caller() )[ 0 ];
6484             ## print( STDERR __PACKAGE__ . "::TIEHASH() called with following arguments: '", join( ', ', @_ ), "'.\n" );
6485 0           my %arg = ( @_ );
6486 0           my $auth = [ $pkg, __PACKAGE__ ];
6487 0 0         if( $arg{ 'pkg' } )
6488             {
6489 0           my $ok = delete( $arg{ 'pkg' } );
6490 0 0         push( @$auth, ref( $ok ) eq 'ARRAY' ? @$ok : $ok );
6491             }
6492 0           my $priv = { 'pkg' => $auth };
6493 0           my $data = { '__priv__' => $priv };
6494 0           my @keys = keys( %arg );
6495 0           @$priv{ @keys } = @arg{ @keys };
6496 0   0       return( bless( $data, ref( $self ) || $self ) );
6497             }
6498              
6499             sub CLEAR
6500             {
6501 0     0     my $self = shift( @_ );
6502 0           my $pkg = ( caller() )[ 0 ];
6503             ## print( $err __PACKAGE__ . "::CLEAR() called by package '$pkg'.\n" );
6504 0           my $data = $self->{ '__priv__' };
6505 0 0 0       return() if( $data->{ 'readonly' } && $pkg ne __PACKAGE__ );
6506             ## if( $data->{ 'readonly' } || $data->{ 'protect' } )
6507 0 0         if( !( $data->{ 'perms' } & 2 ) )
6508             {
6509 0 0         return if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
  0            
6510             }
6511 0           my $key = $self->FIRSTKEY( @_ );
6512 0           my @keys = ();
6513 0           while( defined( $key ) )
6514             {
6515 0           push( @keys, $key );
6516 0           $key = $self->NEXTKEY( @_, $key );
6517             }
6518 0           foreach $key ( @keys )
6519             {
6520 0           $self->DELETE( @_, $key );
6521             }
6522             }
6523              
6524             sub DELETE
6525             {
6526 0     0     my $self = shift( @_ );
6527 0           my $pkg = ( caller() )[ 0 ];
6528 0 0         $pkg = ( caller( 1 ) )[ 0 ] if( $pkg eq 'Module::Generic' );
6529             ## print( STDERR __PACKAGE__ . "::DELETE() package '$pkg' tries to delete '$_[ 0 ]'\n" );
6530 0           my $data = $self->{ '__priv__' };
6531 0 0 0       return if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ );
6532             ## if( $data->{ 'readonly' } || $data->{ 'protect' } )
6533 0 0         if( !( $data->{ 'perms' } & 2 ) )
6534             {
6535 0 0         return() if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
  0            
6536             }
6537 0           return( delete( $self->{ shift( @_ ) } ) );
6538             }
6539              
6540             sub EXISTS
6541             {
6542 0     0     my $self = shift( @_ );
6543             ## print( STDERR __PACKAGE__ . "::EXISTS() called from package '", ( caller() )[ 0 ], "'.\n" );
6544 0 0 0       return( 0 ) if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ );
6545 0           my $data = $self->{ '__priv__' };
6546 0 0         if( !( $data->{ 'perms' } & 4 ) )
6547             {
6548 0           my $pkg = ( caller() )[ 0 ];
6549 0 0         return( 0 ) if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
  0            
6550             }
6551             ## print( STDERR __PACKAGE__ . "::EXISTS() returns: '", exists( $self->{ $_[ 0 ] } ), "'.\n" );
6552 0           return( exists( $self->{ shift( @_ ) } ) );
6553             }
6554              
6555             sub FETCH
6556             {
6557             ## return( shift->{ shift( @_ ) } );
6558             ## print( STDERR __PACKAGE__ . "::FETCH() called with arguments: '", join( ', ', @_ ), "'.\n" );
6559 0     0     my $self = shift( @_ );
6560             ## This is a hidden entry, we return nothing
6561 0 0 0       return() if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ );
6562 0           my $data = $self->{ '__priv__' };
6563             ## If we have to protect our object, we hide its inner content if our caller is not our creator
6564             ## if( $data->{ 'protect' } )
6565 0 0         if( !( $data->{ 'perms' } & 4 ) )
6566             {
6567 0           my $pkg = ( caller() )[ 0 ];
6568             ## print( STDERR __PACKAGE__ . "::FETCH() package '$pkg' wants to fetch the value of '$_[ 0 ]'\n" );
6569 0 0         return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
  0            
6570             }
6571 0           return( $self->{ shift( @_ ) } );
6572             }
6573              
6574             sub FIRSTKEY
6575             {
6576 0     0     my $self = shift( @_ );
6577             ## my $a = scalar( keys( %$hash ) );
6578             ## return( each( %$hash ) );
6579 0           my $data = $self->{ '__priv__' };
6580             ## if( $data->{ 'protect' } )
6581 0 0         if( !( $data->{ 'perms' } & 4 ) )
6582             {
6583 0           my $pkg = ( caller( 0 ) )[ 0 ];
6584             ## print( STDERR __PACKAGE__ . "::FIRSTKEY() called by package '$pkg'\n" );
6585 0 0         return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
  0            
6586             }
6587             ## print( STDERR __PACKAGE__ . "::FIRSTKEY(): gathering object's keys.\n" );
6588 0           my( @keys ) = grep( !/^__priv__$/, keys( %$self ) );
6589 0           $self->{ '__priv__' }->{ 'ITERATOR' } = \@keys;
6590             ## print( STDERR __PACKAGE__ . "::FIRSTKEY(): keys are: '", join( ', ', @keys ), "'.\n" );
6591             ## print( STDERR __PACKAGE__ . "::FIRSTKEY() returns '$keys[ 0 ]'.\n" );
6592 0           return( shift( @keys ) );
6593             }
6594              
6595             sub NEXTKEY
6596             {
6597 0     0     my $self = shift( @_ );
6598             ## return( each( %$hash ) );
6599 0           my $data = $self->{ '__priv__' };
6600             ## if( $data->{ 'protect' } )
6601 0 0         if( !( $data->{ 'perms' } & 4 ) )
6602             {
6603 0           my $pkg = ( caller( 0 ) )[ 0 ];
6604             ## print( STDERR __PACKAGE__ . "::NEXTKEY() called by package '$pkg'\n" );
6605 0 0         return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
  0            
6606             }
6607 0           my $keys = $self->{ '__priv__' }->{ 'ITERATOR' };
6608             ## print( STDERR __PACKAGE__ . "::NEXTKEY() returns '$_[ 0 ]'.\n" );
6609 0           return( shift( @$keys ) );
6610             }
6611              
6612             sub STORE
6613             {
6614 0     0     my $self = shift( @_ );
6615 0 0         return() if( $_[ 0 ] eq '__priv__' );
6616 0           my $data = $self->{ '__priv__' };
6617             #if( $data->{ 'readonly' } ||
6618             # $data->{ 'protect' } )
6619 0 0         if( !( $data->{ 'perms' } & 2 ) )
6620             {
6621 0           my $pkg = ( caller() )[ 0 ];
6622 0 0         $pkg = ( caller( 1 ) )[ 0 ] if( $pkg eq 'Module::Generic' );
6623             ## print( STDERR __PACKAGE__ . "::STORE() package '$pkg' is trying to STORE the value '$_[ 1 ]' to key '$_[ 0 ]'\n" );
6624 0 0         return if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
  0            
6625             }
6626             ## print( STDERR __PACKAGE__ . "::STORE() ", ( caller() )[ 0 ], " is storing value '$_[ 1 ]' for key '$_[ 0 ]'.\n" );
6627             ## $self->{ shift( @_ ) } = shift( @_ );
6628 0           $self->{ $_[ 0 ] } = $_[ 1 ];
6629             ## print( STDERR __PACKAGE__ . "::STORE(): object '$self' now contains: '", join( ', ', map{ "$_, $self->{ $_ }" } keys( %$self ) ), "'.\n" );
6630             }
6631              
6632             1;
6633              
6634             __END__
6635              
6636             =encoding utf8
6637              
6638             =head1 NAME
6639              
6640             Module::Generic - Generic Module to inherit from
6641              
6642             =head1 SYNOPSIS
6643              
6644             package MyModule;
6645             BEGIN
6646             {
6647             use strict;
6648             use Module::Generic;
6649             our( @ISA ) = qw( Module::Generic );
6650             };
6651              
6652             =head1 VERSION
6653              
6654             v0.12.16
6655              
6656             =head1 DESCRIPTION
6657              
6658             L<Module::Generic> as its name says it all, is a generic module to inherit from.
6659             It is designed to provide a useful framework and speed up coding and debugging.
6660             It contains standard and support methods that may be superseded by your the module using
6661             L<Module::Generic>.
6662              
6663             As an added benefit, it also contains a powerfull AUTOLOAD transforming any hash
6664             object key into dynamic methods and also recognize the dynamic routine a la AutoLoader
6665             from which I have shamelessly copied in the AUTOLOAD code. The reason is that while
6666             C<AutoLoader> provides the user with a convenient AUTOLOAD, I wanted a way to also
6667             keep the functionnality of L<Module::Generic> AUTOLOAD that were not included in
6668             C<AutoLoader>. So the only solution was a merger.
6669              
6670             =head1 METHODS
6671              
6672             =head2 import
6673              
6674             B<import>() is used for the AutoLoader mechanism and hence is not a public method.
6675             It is just mentionned here for info only.
6676              
6677             =head2 new
6678              
6679             B<new> will create a new object for the package, pass any argument it might receive
6680             to the special standard routine B<init> that I<must> exist.
6681             Then it returns what returns L</"init">.
6682              
6683             To protect object inner content from sneaking by third party, you can declare the
6684             package global variable I<OBJECT_PERMS> and give it a Unix permission, but only 1 digit.
6685             It will then work just like Unix permission. That is, if permission is 7, then only the
6686             module who generated the object may read/write content of the object. However, if
6687             you set 5, the, other may look into the content of the object, but may not modify it.
6688             7, as you would have guessed, allow other to modify the content of an object.
6689             If I<OBJECT_PERMS> is not defined, permissions system is not activated and hence anyone
6690             may access and possibly modify the content of your object.
6691              
6692             If the module runs under mod_perl, it is recognised and a clean up registered routine is
6693             declared to Apache to clean up the content of the object.
6694              
6695             =head2 as_hash
6696              
6697             This will recursively transform the object into an hash suitable to be encoded in json.
6698              
6699             It does this by calling each method of the object and build an hash reference with the
6700             method name as the key and the method returned value as the value.
6701              
6702             If the method returned value is an object, it will call its L</"as_hash"> method if it supports it.
6703              
6704             It returns the hash reference built
6705              
6706             =head2 clear_error
6707              
6708             Clear all error from the object and from the available global variable C<$ERROR>.
6709              
6710             This is a handy method to use at the beginning of other methods of calling package,
6711             so the end user may do a test such as:
6712              
6713             $obj->some_method( 'some arguments' );
6714             die( $obj->error() ) if( $obj->error() );
6715              
6716             ## some_method() would then contain something like:
6717             sub some_method
6718             {
6719             my $self = shift( @_ );
6720             ## Clear all previous error, so we may set our own later one eventually
6721             $self->clear_error();
6722             ## ...
6723             }
6724              
6725             This way the end user may be sure that if C<$obj->error()> returns true something
6726             wrong has occured.
6727              
6728             =head2 clone
6729              
6730             Clone the current object if it is of type hash or array reference. It returns an error if the type is neither.
6731              
6732             It returns the clone.
6733              
6734             =head2 colour_closest
6735              
6736             Provided with a colour, this returns the closest standard one supported by terminal.
6737              
6738             A colour provided can be a colour name, or a 9 digits rgb value or an hexadecimal value
6739              
6740             =head2 colour_format
6741              
6742             Provided with a hash reference of parameters, this will return a string properly formatted to display colours on the command line.
6743              
6744             Parameters are:
6745              
6746             =over 4
6747              
6748             =item I<text> or I<message>
6749              
6750             This is the text to be formatted in colour.
6751              
6752             =item I<bgcolour> or I<bgcolor> or I<bg_colour> or I<bg_color>
6753              
6754             The value for the background colour.
6755              
6756             =item I<colour> or I<color> or I<fg_colour> or I<fg_color> or I<fgcolour> or I<fgcolor>
6757              
6758             The value for the foreground colour.
6759              
6760             Valid value can be a colour name, an rgb value like C<255255255>, a rgb annotation like C<rgb(255, 255, 255)> or a rgba annotation like C<rgba(255,255,255,0.5)>
6761              
6762             A colour can be preceded by the words C<light> or C<bright> to provide slightly lighter colour where supported.
6763              
6764             Similarly, if an rgba value is provided, and the opacity is less than 1, this is equivalent to using the keyword C<light>
6765              
6766             It returns the text properly formatted to be outputted in a terminal.
6767              
6768             =item I<style>
6769              
6770             The possible values are: I<bold>, I<italic>, I<underline>, I<blink>, I<reverse>, I<conceal>, I<strike>
6771              
6772             =back
6773              
6774             =head2 colour_parse
6775              
6776             Provided with a string, this will parse the string for colour formatting. Formatting can be encapsulated in another formatting, and can be expressed in 2 different ways. For example:
6777              
6778             $self->colour_parse( "And {style => 'i|b', color => green}what about{/} {style => 'blink', color => yellow}me{/} ?" );
6779              
6780             would result with the words C<what about> in italic, bold and green colour and the word C<me> in yellow colour blinking (if supported).
6781              
6782             Another way is:
6783              
6784             $self->colour_parse( "And {bold light red on white}what about{/} {underline yellow}me too{/} ?" );
6785              
6786             would return a string with the words C<what about> in light red bold text on a white background, and the words C<me too> in yellow with an underline.
6787              
6788             $self->colour_parse( "Hello {bold red on white}everyone! This is {underline rgb(0,0,255)}embedded{/}{/} text..." );
6789              
6790             would return a string with the words C<everyone! This is> in bold red characters on white background and the word C<embedded> in underline blue color
6791              
6792             The idea for this syntax, not the code, is taken from L<Term::ANSIColor>
6793              
6794             =head2 coloured
6795              
6796             Provided with a colouring preference expressed as the first argument as string, and followed by 1 or more arguments that are concatenated to form the text string to format. For example:
6797              
6798             print( $o->coloured( 'bold white on red', "Hello it's me!\n" ) );
6799              
6800             A colour can be expressed as a rgb, such as :
6801              
6802             print( $o->coloured( 'underline rgb( 0, 0, 255 ) on white', "Hello everyone!" ), "\n" );
6803              
6804             rgb can also be rgba with the last decimal, normally an opacity used here to set light color if the value is less than 1. For example :
6805              
6806             print( $o->coloured( 'underline rgba(255, 0, 0, 0.5)', "Hello everyone!" ), "\n" );
6807              
6808             =head2 debug
6809              
6810             Set or get the debug level. This takes and return an integer.
6811              
6812             Based on the value, L</"message"> will or will not print out messages. For example :
6813              
6814             $self->debug( 2 );
6815             $self->message( 2, "Debugging message here." );
6816              
6817             Since C<2> used in L</"message"> is equal to the debug value, the debugging message is printed.
6818              
6819             If the debug value is switched to 1, the message will be silenced.
6820              
6821             =head2 dump
6822              
6823             Provided with some data, this will return a string representation of the data formatted by L<Data::Printer>
6824              
6825             =head2 dump_print
6826              
6827             Provided with a file to write to and some data, this will format the string representation of the data using L<Data::Printer> and save it to the given file.
6828              
6829             =head2 dumper
6830              
6831             Provided with some data, and optionally an hash reference of parameters as last argument, this will create a string representation of the data using L<Data::Dumper> and return it.
6832              
6833             This sets L<Data::Dumper> to be terse, to indent, to use C<qq> and optionally to not exceed a maximum I<depth> if it is provided in the argument hash reference.
6834              
6835             =head2 printer
6836              
6837             Same as L</"dumper">, but using L<Data::Printer> to format the data.
6838              
6839             =head2 dumpto_printer
6840              
6841             Same as L</"dump_print"> above that is an alias of this method.
6842              
6843             =head2 dumpto_dumper
6844              
6845             Same as L</"dumpto_printer"> above, but using L<Data::Dumper>
6846              
6847             =head2 error
6848              
6849             Set the current error issuing a L<Module::Generic::Exception> object, call L<perlfunc/"warn">, or C<$r->warn> under Apache2 modperl, and returns undef() or an empty list in list context:
6850              
6851             if( $some_condition )
6852             {
6853             return( $self->error( "Some error." ) );
6854             }
6855              
6856             Note that you do not have to worry about a trailing line feed sequence.
6857             B<error>() takes care of it.
6858              
6859             The script calling your module could write calls to your module methods like this:
6860              
6861             my $cust_name = $object->customer->name ||
6862             die( "Got an error in file ", $object->error->file, " at line ", $object->error->line, ": ", $object->error->trace, "\n" );
6863             # or simply:
6864             my $cust_name = $object->customer->name ||
6865             die( "Got an error: ", $object->error, "\n" );
6866              
6867             Note also that by calling B<error>() it will not clear the current error. For that
6868             you have to call B<clear_error>() explicitly.
6869              
6870             Also, when an error is set, the global variable I<ERROR> is set accordingly. This is
6871             especially usefull, when your initiating an object and that an error occured. At that
6872             time, since the object could not be initiated, the end user can not use the object to
6873             get the error message, and then can get it using the global module variable
6874             I<ERROR>, for example:
6875              
6876             my $obj = Some::Package->new ||
6877             die( $Some::Package::ERROR, "\n" );
6878              
6879             If the caller has disabled warnings using the pragma C<no warnings>, L</"error"> will
6880             respect it and not call B<warn>. Calling B<warn> can also be silenced if the object has
6881             a property I<quiet> set to true.
6882              
6883             The error message can be split in multiple argument. L</"error"> will concatenate each argument to form a complete string. An argument can even be a reference to a sub routine and will get called to get the resulting string, unless the object property I<_msg_no_exec_sub> is set to false. This can switched off with the method L</"noexec">
6884              
6885             If perl runs under Apache2 modperl, and an error handler is set with L</"error_handler">, this will call the error handler with the error string.
6886              
6887             If an Apache2 modperl log handler has been set, this will also be called to log the error.
6888              
6889             If the object property I<fatal> is set to true, this will call die instead of L<perlfunc/"warn">.
6890              
6891             Last, but not least since L</"error"> returns undef in scalar context or an empty list in list context, if the method that triggered the error is chained, it would normally generate a perl error that the following method cannot be called on an undefined value. To solve this, when an object is expected, L</"error"> returns a special object from module L<Module::Generic::Null> that will enable all the chained methods to be performed and return the error when requested to. For example :
6892              
6893             my $o = My::Package->new;
6894             my $total $o->get_customer(10)->products->total || die( $o->error, "\n" );
6895              
6896             Assuming this method here C<get_customer> returns an error, the chaining will continue, but produce nothing and ultimately returns undef.
6897              
6898             =head2 errors
6899              
6900             Used by B<error>() to store the error sent to him for history.
6901              
6902             It returns an array of all error that have occured in lsit context, and the last
6903             error in scalar context.
6904              
6905             =head2 errstr
6906              
6907             Set/get the error string, period. It does not produce any warning like B<error> would do.
6908              
6909             =head2 get
6910              
6911             Uset to get an object data key value:
6912              
6913             $obj->set( 'verbose' => 1, 'debug' => 0 );
6914             ## ...
6915             my $verbose = $obj->get( 'verbose' );
6916             my @vals = $obj->get( qw( verbose debug ) );
6917             print( $out "Verbose level is $vals[ 0 ] and debug level is $vals[ 1 ]\n" );
6918              
6919             This is no more needed, as it has been more conveniently bypassed by the AUTOLOAD
6920             generic routine with chich you may say:
6921              
6922             $obj->verbose( 1 );
6923             $obj->debug( 0 );
6924             ## ...
6925             my $verbose = $obj->verbose();
6926              
6927             Much better, no?
6928              
6929             =head2 init
6930              
6931             This is the L</"new"> package object initializer. It is called by L</"new">
6932             and is used to set up any parameter provided in a hash like fashion:
6933              
6934             my $obj My::Module->new( 'verbose' => 1, 'debug' => 0 );
6935              
6936             You may want to superseed L</"init"> to have suit your needs.
6937              
6938             L</"init"> needs to returns the object it received in the first place or an error if
6939             something went wrong, such as:
6940              
6941             sub init
6942             {
6943             my $self = shift( @_ );
6944             my $dbh = DB::Object->connect() ||
6945             return( $self->error( "Unable to connect to database server." ) );
6946             $self->{ 'dbh' } = $dbh;
6947             return( $self );
6948             }
6949              
6950             In this example, using L</"error"> will set the global variable C<$ERROR> that will
6951             contain the error, so user can say:
6952              
6953             my $obj = My::Module->new() || die( $My::Module::ERROR );
6954              
6955             If the global variable I<VERBOSE>, I<DEBUG>, I<VERSION> are defined in the module,
6956             and that they do not exist as an object key, they will be set automatically and
6957             accordingly to those global variable.
6958              
6959             The supported data type of the object generated by the L</"new"> method may either be
6960             a hash reference or a glob reference. Those supported data types may very well be
6961             extended to an array reference in a near future.
6962              
6963             When provided with an hash reference, and when object property I<_init_strict_use_sub> is set to true, L</"init"> will call each method corresponding to the key name and pass it the key value and it will set an error and skip it if the corresponding method does not exist. Otherwise if the object property I<_init_strict> is set to true, it will check the object property matching the hash key for the default value type and set an error and return undef if it does not match. Foe example, L</"init"> in your module could be like this:
6964              
6965             sub init
6966             {
6967             my $self = shift( @_ );
6968             $self->{_init_strict} = 1;
6969             $self->{products} = [];
6970             return( $self->SUPER::init( @_ ) );
6971             }
6972              
6973             Then, if init is called like this:
6974              
6975             $object->init({ products => $some_string_but_not_array }) || die( $object->error, "\n" );
6976              
6977             This would cause your script to die, because C<products> value is a string and not an array reference.
6978              
6979             Otherwise, if none of those special object properties are set, the init will create an object property matching the key of the hash and set its value accordingly. For example :
6980              
6981             sub init
6982             {
6983             my $self = shift( @_ );
6984             return( $self->SUPER::init( @_ ) );
6985             }
6986              
6987             Then, if init is called like this:
6988              
6989             $object->init( products => $array_ref, first_name => 'John', last_name => 'Doe' });
6990              
6991             The object would then contain the properties I<products>, I<first_name> and I<last_name> and can be accessed as methods, such as :
6992              
6993             my $fname = $object->first_name;
6994              
6995             =head2 log_handler
6996              
6997             Provided a reference to a sub routine or an anonymous sub routine, this will set the handler that is called by L</"message">
6998              
6999             It returns the current value set.
7000              
7001             =head2 message
7002              
7003             B<message>() is used to display verbose/debug output. It will display something
7004             to the extend that either I<verbose> or I<debug> are toggled on.
7005              
7006             If so, all debugging message will be prepended by C<## > to highlight the fact
7007             that this is a debugging message.
7008              
7009             Addionally, if a number is provided as first argument to B<message>(), it will be
7010             treated as the minimum required level of debugness. So, if the current debug
7011             state level is not equal or superior to the one provided as first argument, the
7012             message will not be displayed.
7013              
7014             For example:
7015              
7016             ## Set debugness to 3
7017             $obj->debug( 3 );
7018             ## This message will not be printed
7019             $obj->message( 4, "Some detailed debugging stuff that we might not want." );
7020             ## This will be displayed
7021             $obj->message( 2, "Some more common message we want the user to see." );
7022              
7023             Now, why debug is used and not verbose level? Well, because mostly, the verbose level
7024             needs only to be true, that is equal to 1 to be efficient. You do not really need to have
7025             a verbose level greater than 1. However, the debug level usually may have various level.
7026              
7027             Also, the text provided can be separated by comma, and even be a code reference, such as:
7028              
7029             $self->message( 2, "I have found", "something weird here:", sub{ $self->dumper( $data ) } );
7030              
7031             If the object has a property I<_msg_no_exec_sub> set to true, then a code reference will not be called and instead be added to the string as is. This can be done simply like this:
7032              
7033             $self->noexec->message( 2, "I have found", "something weird here:", sub{ $self->dumper( $data ) } );
7034              
7035             =head2 message_colour
7036              
7037             This is the same as L</"message">, except this will check for colour formatting, which
7038             L</"message"> does not do. For example:
7039              
7040             $self->message_colour( 3, "And {bold light white on red}what about{/} {underline green}me again{/} ?" );
7041              
7042             L</"message_colour"> can also be called as B<message_color>
7043              
7044             See also L</"colour_format"> and L</"colour_parse">
7045              
7046             =head2 messagef
7047              
7048             This works like L<perlfunc/"sprintf">, so provided with a format and a list of arguments, this print out the message. For example :
7049              
7050             $self->messagef( 1, "Customer name is %s", $cust->name );
7051              
7052             Where 1 is the debug level set with L</"debug">
7053              
7054             =head2 message_check
7055              
7056             This is called by L</"message">
7057              
7058             Provided with a list of arguments, this method will check if the first argument is an integer and find out if a debug message should be printed out or not. It returns the list of arguments as an array reference.
7059              
7060             =head2 message_log
7061              
7062             This is called from L</"message">.
7063              
7064             Provided with a message to log, this will check if L</"message_log_io"> returns a valid file handler, presumably to log file, and if so print the message to it.
7065              
7066             If no file handle is set, this returns undef, other it returns the value from C<$io->print>
7067              
7068             =head2 message_log_io
7069              
7070             Set or get the message log file handle. If set, L</"message_log"> will use it to print messages received from L</"message">
7071              
7072             If no argument is provided bu your module has a global variable C<LOG_DEBUG> set to true and global variable C<DEB_LOG> set presumably to the file path of a log file, then this attempts to open in write mode the log file.
7073              
7074             It returns the current log file handle, if any.
7075              
7076             =head2 message_switch
7077              
7078             Provided with a boolean value, this toggles on or off all the calls to L</"message"> by replacing the message method in your package with a dummy one that will ignore any call. Actually it aliases L</"message"> to L</"message_off">
7079              
7080             In reality this is not really needed, because L</"message"> will, at the beginning check if the object has the debug flag on and if not returns undef.
7081              
7082             =head2 new_array
7083              
7084             Instantiate a new L<Module::Generic::Array> object. If any arguments are provided, it will pass it to L<Module::Generic::Array/new> and return the object.
7085              
7086             =head2 new_hash
7087              
7088             Instantiate a new L<Module::Generic::Hash> object. If any arguments are provided, it will pass it to L<Module::Generic::Hash/new> and return the object.
7089              
7090             =head2 new_number
7091              
7092             Instantiate a new L<Module::Generic::Number> object. If any arguments are provided, it will pass it to L<Module::Generic::Number/new> and return the object.
7093              
7094             =head2 new_scalar
7095              
7096             Instantiate a new L<Module::Generic::Scalar> object. If any arguments are provided, it will pass it to L<Module::Generic::Scalar/new> and return the object.
7097              
7098             =head2 noexec
7099              
7100             Sets the module property I<_msg_no_exec_sub> to true, so that any call to L</"message"> whose arguments include a reference to a sub routine, will not try to execute the code. For example, imagine you have a sub routine such as:
7101              
7102             sub hello
7103             {
7104             return( "Hello !" );
7105             }
7106              
7107             And in your code, you write:
7108              
7109             $self->message( 2, "Someone said: ", \&hello );
7110              
7111             If I<_msg_no_exec_sub> is set to false (by default), then the above would print out the following message:
7112              
7113             Someone said Hello !
7114              
7115             But if I<_msg_no_exec_sub> is set to true, then the same would rather produce the following :
7116              
7117             Someone said CODE(0x7f9103801700)
7118              
7119             =head2 pass_error
7120              
7121             Provided with an error, typically a L<Module::Generic::Exception> object, but it could be anything as long as it is an object, hopefully an exception object, this will set the error value to the error provided, and without issuing any new warning nor creating a new L<Module::Generic::Exception> object.
7122              
7123             It makes it possible to pass the error along so the caller can retrieve it later. This is typically used by a method calling another one in another module that produced an error. For example :
7124              
7125             sub getCustomerInfo
7126             {
7127             my $self = shift( @_ );
7128             # Maybe a LWP::UserAgent sub class?
7129             my $client = $self->lwp_client_object;
7130             my $res = $client->get( $remote_api_endpoint ) ||
7131             return( $self->pass_error( $client->error ) );
7132             }
7133              
7134             Then :
7135              
7136             my $client_info = $object->getCustomerInfo || die( $object->error, "\n" );
7137              
7138             Which would return the http client error that has been passed along
7139              
7140             =head2 quiet
7141              
7142             Set or get the object property I<quiet> to true or false. If this is true, no warning will be issued when L</"error"> is called.
7143              
7144             =head2 save
7145              
7146             Provided with some data and a file path, or alternatively an hash reference of options with the properties I<data>, I<encoding> and I<file>, this will write to the given file the provided I<data> using the encoding I<encoding>.
7147              
7148             This is designed to simplify the tedious task of write to files.
7149              
7150             If it cannot open the file in write mode, or cannot print to it, this will set an error and return undef. Otherwise this returns the size of the file in bytes.
7151              
7152             =head2 set
7153              
7154             B<set>() sets object inner data type and takes arguments in a hash like fashion:
7155              
7156             $obj->set( 'verbose' => 1, 'debug' => 0 );
7157              
7158             =head2 subclasses
7159              
7160             Provided with a I<CLASS> value, this method try to guess all the existing sub classes of the provided I<CLASS>.
7161              
7162             If I<CLASS> is not provided, the class into which was blessed the calling object will
7163             be used instead.
7164              
7165             It returns an array of subclasses in list context and a reference to an array of those
7166             subclasses in scalar context.
7167              
7168             If an error occured, undef is returned and an error is set accordingly. The latter can
7169             be retrieved using the B<error> method.
7170              
7171             =head2 true
7172              
7173             Returns a C<true> variable from L<Module::Generic::Boolean>
7174              
7175             =head2 false
7176              
7177             Returns a C<false> variable from L<Module::Generic::Boolean>
7178              
7179             =head2 verbose
7180              
7181             Set or get the verbosity level with an integer.
7182              
7183             =head2 will
7184              
7185             This will try to find out if an object supports a given method call and returns the code reference to it or undef if none is found.
7186              
7187             =head2 AUTOLOAD
7188              
7189             The special B<AUTOLOAD>() routine is called by perl when no matching routine was found
7190             in the module.
7191              
7192             B<AUTOLOAD>() will then try hard to process the request.
7193             For example, let's assue we have a routine B<foo>.
7194              
7195             It will first, check if an equivalent entry of the routine name that was called exist in
7196             the hash reference of the object. If there is and that more than one argument were
7197             passed to this non existing routine, those arguments will be stored as a reference to an
7198             array as a value of the key in the object. Otherwise the single argument will simply be stored
7199             as the value of the key of the object.
7200              
7201             Then, if called in list context, it will return a array if the value of the key entry was an array
7202             reference, or a hash list if the value of the key entry was a hash reference, or finally the value
7203             of the key entry.
7204              
7205             If this non existing routine that was called is actually defined, the routine will be redeclared and
7206             the arguments passed to it.
7207              
7208             If this fails too, it will try to check for an AutoLoadable file in C<auto/PackageName/routine_name.al>
7209              
7210             If the filed exists, it will be required, the routine name linked into the package name space and finally
7211             called with the arguments.
7212              
7213             If the require process failed or if the AutoLoadable routine file did not exist, B<AUTOLOAD>() will
7214             check if the special routine B<EXTRA_AUTOLOAD>() exists in the module. If it does, it will call it and pass
7215             it the arguments. Otherwise, B<AUTOLOAD> will die with a message explaining that the called routine did
7216             not exist and could not be found in the current class.
7217              
7218             =head1 SPECIAL METHODS
7219              
7220             =head2 __instantiate_object
7221              
7222             Provided with an object property name, and a class/package name, this will attempt to load the module if it is not already loaded. It does so using L<Class::Load/"load_class">. Once loaded, it will init an object passing it the other arguments received. It returns the object instantiated upon success or undef and sets an L</"error">
7223              
7224             This is a support method used by L</"_instantiate_object">
7225              
7226             =head2 _instantiate_object
7227              
7228             This does the same thing as L</"__instantiate_object"> and the purpose is for this method to be potentially superseded in your own module. In your own module, you would call L</"__instantiate_object">
7229              
7230             =head2 _is_a
7231              
7232             Provided with an object and a package name and this will return true if the object is a blessed object from this package name (or a sub package of it), or false if not.
7233              
7234             The value of this is to reduce the burden of having to check whether the object actually exists, i.e. is not null or undef, if it is an object and if it is from that class. This allows to do it in just one method call like this:
7235              
7236             if( $self->_is_a( $obj, 'My::Package' ) )
7237             {
7238             # Do something
7239             }
7240              
7241             Of course, if you are sure the object is actually an object, then you can directly do:
7242              
7243             if( $obj->isa( 'My::Package' ) )
7244             {
7245             # Do something
7246             }
7247              
7248             =head2 _is_class_loaded
7249              
7250             Provided with a class/package name, this returns true if the module is already loaded or false otherwise.
7251              
7252             =head2 _is_array
7253              
7254             Provided with some data, this checks if the data is of type array, even if it is an object.
7255              
7256             This uses L<Scalar::Util/"reftype"> to achieve that purpose. So for example, an object such as :
7257              
7258             package My::Module;
7259              
7260             sub new
7261             {
7262             return( bless( [] => ( ref( $_[0] ) || $_[0] ) ) );
7263             }
7264              
7265             This would produce an object like :
7266              
7267             My::Module=ARRAY(0x7f8f3b035c20)
7268              
7269             When checked with L</"_is_array"> this, would return true just like an ordinary array.
7270              
7271             If you would use :
7272              
7273             ref( $object );
7274              
7275             It would rather return the module package name: C<My::Module>
7276              
7277             =head2 _is_hash
7278              
7279             Same as L</"_is_array">, but for hash reference.
7280              
7281             =head2 _is_object
7282              
7283             Provided with some data, this checks if the data is an object. It uses L<Scalar::Util/"blessed"> to achieve that purpose.
7284              
7285             =head2 _is_scalar
7286              
7287             Provided with some data, this checks if the data is of type scalar reference, e.g. C<SCALAR(0x7fc0d3b7cea0)>, even if it is an object.
7288              
7289             =head2 _load_class
7290              
7291             Provided with a class/package name and this will attempt to load the module. This uses L<Class::Load/"load_class"> to achieve that purpose and return whatever value L<Class::Load/"load_class"> returns.
7292              
7293             =head2 _obj2h
7294              
7295             This ensures the module object is an hash reference, such as when the module object is based on a file handle for example. This permits L<Module::Generic> to work no matter what is the underlying data type blessed into an object.
7296              
7297             =head2 _parse_timestamp
7298              
7299             Provided with a string representing a date or datetime, and this will try to parse it and return a L<DateTime> object. It will also create a L<DateTime::Format::Strptime> to preserve the original date/datetime string representation and assign it to the L<DateTime> object. So when the L<DateTime> object is stringified, it displays the same string that was originally parsed.
7300              
7301             =head2 _set_get
7302              
7303             Provided with an object property name and some value and this will set or get that value for that property.
7304              
7305             However, if the value stored is an array and is called in list context, it will return the array as a list and not the array reference. Same thing for an hash reference. It will return an hash in list context. In scalar context, it returns whatever the value is, such as array reference, hash reference or string, etc.
7306              
7307             =head2 _set_get_array
7308              
7309             Provided with an object property name and some data and this will store the data as an array reference.
7310              
7311             It returns the current value stored, such as an array reference notwithstanding it is called in list or scalar context.
7312              
7313             Example :
7314              
7315             sub products { return( shift->_set_get_array( 'products', @_ ) ); }
7316              
7317             =head2 _set_get_array_as_object
7318              
7319             Provided with an object property name and some data and this will store the data as an object of L<Module::Generic::Array>
7320              
7321             If this is called with no data set, an object is created with no data inside and returned
7322              
7323             Example :
7324              
7325             # In your module
7326             sub products { return( shift->_set_get_array_as_object( 'products', @_ ) ); }
7327              
7328             And using your method:
7329              
7330             printf( "There are %d products\n", $object->products->length );
7331             $object->products->push( $new_product );
7332              
7333             =head2 _set_get_boolean
7334              
7335             Provided with an object property name and some data and this will store the data as a boolean value.
7336              
7337             If the data provided is a L<JSON::PP::Boolean> or L<Module::Generic::Boolean> object, the data is stored as is.
7338              
7339             If the data is a scalar reference, its referenced value is check and L<Module::Generic::Boolean/"true"> or L<Module::Generic::Boolean/"false"> is set accordingly.
7340              
7341             If the data is a string with value of C<true> or C<val> L<Module::Generic::Boolean/"true"> or L<Module::Generic::Boolean/"false"> is set accordingly.
7342              
7343             Otherwise the data provided is checked if it is a true value or not and L<Module::Generic::Boolean/"true"> or L<Module::Generic::Boolean/"false"> is set accordingly.
7344              
7345             If no value is provided, and the object property has already been set, this performs the same checks as above and returns either a L<JSON::PP::Boolean> or a L<Module::Generic::Boolean> object.
7346              
7347             =head2 __create_class
7348              
7349             Provided with an object property name and an hash reference representing a dictionary and this will produce a dynamically created class/module.
7350              
7351             If a property I<_class> exists in the dictionary, it will be used as the class/package name, otherwise a name will be derived from the calling object class and the object property name. For example, in your module :
7352              
7353             sub products { return( 'products', shift->_set_get_class(
7354             {
7355             name => { type => 'scalar' },
7356             customer => { type => 'object', class => 'My::Customer' },
7357             orders => { type => 'array_as_object' },
7358             active => { type => 'boolean' },
7359             created => { type => 'datetime' },
7360             metadata => { type => 'hash' },
7361             stock => { type => 'number' },
7362             url => { type => 'uri' },
7363             }, @_ ) ); }
7364              
7365             Then calling your module method B<products> such as :
7366              
7367             my $prod = $object->products({
7368             name => 'Cool product',
7369             customer => { first_name => 'John', last_name => 'Doe', email => 'john.doe@example.com' },
7370             orders => [qw( 123 987 456 654 )],
7371             active => 1,
7372             metadata => { transaction_id => 123, api_call_id => 456 },
7373             stock => 10,
7374             uri => 'https://example.com/p/20'
7375             });
7376              
7377             Using the resulting object C<$prod>, we can access this dynamically created class/module such as :
7378              
7379             printf( <<EOT, $prod->name, $prod->orders->length, $prod->customer->last_name,, $prod->url->path )
7380             Product name: %s
7381             No of orders: %d
7382             Customer name: %s
7383             Product page path: %s
7384             EOT
7385              
7386             =head2 _set_get_class
7387              
7388             Given an object property name, a dynamic class fiels definition hash (dictionary), and optional arguments, this special method will create perl packages on the fly by calling the support method L</"__create_class">
7389              
7390             For example, consider the following:
7391              
7392             #!/usr/local/bin/perl
7393             BEGIN
7394             {
7395             use strict;
7396             use Data::Dumper;
7397             };
7398              
7399             {
7400             my $o = MyClass->new( debug => 3 );
7401             $o->setup->age( 42 );
7402             print( "Age is: ", $o->setup->age, "\n" );
7403             print( "Setup object is: ", $o->setup, "\n" );
7404             $o->setup->billing->interval( 'month' );
7405             print( "Billing interval is: ", $o->setup->billing->interval, "\n" );
7406             print( "Billing object is: ", $o->setup->billing, "\n" );
7407             $o->setup->rgb( 255, 122, 100 );
7408             print( "rgb: ", join( ', ', @{$o->setup->rgb} ), "\n" );
7409             exit( 0 );
7410             }
7411              
7412             package MyClass;
7413             BEGIN
7414             {
7415             use strict;
7416             use lib './lib';
7417             use parent qw( Module::Generic );
7418             };
7419              
7420             sub setup
7421             {
7422             return( shift->_set_get_class( 'setup',
7423             {
7424             name => { type => 'scalar' },
7425             age => { type => 'number' },
7426             metadata => { type => 'hash' },
7427             rgb => { type => 'array' },
7428             url => { type => 'uri' },
7429             online => { type => 'boolean' },
7430             created => { type => 'datetime' },
7431             billing => { type => 'class', definition =>
7432             {
7433             interval => { type => 'scalar' },
7434             frequency => { type => 'number' },
7435             nickname => { type => 'scalar' },
7436             }}
7437             }) );
7438             }
7439              
7440             1;
7441              
7442             __END__
7443              
7444             This will yield:
7445              
7446             Age is: 42
7447             Setup object is: MyClass::Setup=HASH(0x7fa805abcb20)
7448             Billing interval is: month
7449             Billing object is: MyClass::Setup::Billing=HASH(0x7fa804ec3f40)
7450             rgb: 255, 122, 100
7451              
7452             The advantage of this over B<_set_get_hash_as_object> is that here one controls what fields / method are supported and with which data type.
7453              
7454             =head2 _set_get_class_array
7455              
7456             Provided with an object property name, a dictionary to create a dynamic class with L</"__create_class"> and an array reference of hash references and this will create an array of object, each one matching a set of data provided in the array reference. So for example, imagine you had a method such as below in your module :
7457              
7458             sub products { return( shift->_set_get_class_array( 'products',
7459             {
7460             name => { type => 'scalar' },
7461             customer => { type => 'object', class => 'My::Customer' },
7462             orders => { type => 'array_as_object' },
7463             active => { type => 'boolean' },
7464             created => { type => 'datetime' },
7465             metadata => { type => 'hash' },
7466             stock => { type => 'number' },
7467             url => { type => 'uri' },
7468             }, @_ ) ); }
7469              
7470             Then your script would call this method like this :
7471              
7472             $object->products([
7473             { name => 'Cool product', customer => { first_name => 'John', last_name => 'Doe', email => 'john.doe@example.com' }, active => 1, stock => 10, created => '2020-04-12T07:10:30' },
7474             { name => 'Awesome tool', customer => { first_name => 'Mary', last_name => 'Donald', email => 'm.donald@example.com' }, active => 1, stock => 15, created => '2020-05-12T15:20:10' },
7475             ]);
7476              
7477             And this would store an array reference containing 2 objects with the above data.
7478              
7479             =head2 _set_get_code
7480              
7481             Provided with an object property name and some code reference and this stores and retrieve the current value.
7482              
7483             It returns under and set an error if the provided value is not a code reference.
7484              
7485             =head2 _set_get_datetime
7486              
7487             Provided with an object property name and asome date or datetime string and this will attempt to parse it and save it as a L<DateTime> object.
7488              
7489             If the data is a 10 digits integer, this will treat it as a unix timestamp.
7490              
7491             Parsing also recognise special word such as C<now>
7492              
7493             The created L<DateTime> object is associated a L<DateTime::Format::Strptime> object which enables the L<DateTime> object to be stringified as a unix timestamp using local time stamp, whatever it is.
7494              
7495             Even if there is no value set, and this method is called in chain, it returns a L<Module::Generic::Null> whose purpose is to enable chaining without doing anything meaningful. For example, assuming the property I<created> of your object is not set yet, but in your script you call it like this:
7496              
7497             $object->created->iso8601
7498              
7499             Of course, the value of C<iso8601> will be empty since this is a fake method produced by L<Module::Generic::Null>. The return value of a method should always be checked.
7500              
7501             =head2 _set_get_hash
7502              
7503             Provided with an object property name and an hash reference and this set the property name with this hash reference.
7504              
7505             You can even pass it an associative array, and it will be saved as a hash reference, such as :
7506              
7507             $object->metadata(
7508             transaction_id => 123,
7509             customer_id => 456
7510             );
7511              
7512             my $hash = $object->metadata;
7513              
7514             =head2 _set_get_hash_as_object
7515              
7516             Provided with an object property name, an optional class name and an hash reference and this does the same as in L</"_set_get_hash">, except it will create a class/package dynamically with a method for each of the hash keys, so that you can call the hash keys as method.
7517              
7518             Also it does this recursively while handling looping, in which case, it will reuse the object previously created, and also it takes care of adapting the hash key to a proper field name, so something like C<99more-options> would become C<more_options>. If the value itself is a hash, it processes it recursively transforming C<99more-options> to a proper package name C<MoreOptions> prepended by C<$class_name> provided as argument or whatever upper package was used in recursion processing.
7519              
7520             For example in your module :
7521              
7522             sub metadata { return( shift->_set_get_hash_as_object( 'metadata', @_ ) ); }
7523              
7524             Then populating the data :
7525              
7526             $object->metadata({
7527             first_name => 'John',
7528             last_name => 'Doe',
7529             email => 'john.doe@example.com',
7530             });
7531              
7532             printf( "Customer name is %s\n", $object->metadata->last_name );
7533              
7534             =head2 _set_get_number
7535              
7536             Provided with an object property name and a number, and this will create a L<Module::Generic::Number> object and return it.
7537              
7538             =head2 _set_get_number_or_object
7539              
7540             Provided with an object property name and a number or an object and this call the value using L</"_set_get_number"> or L</"_set_get_object"> respectively
7541              
7542             =head2 _set_get_object
7543              
7544             Provided with an object property name, a class/package name and some data and this will initiate a new object of the given class passing it the data.
7545              
7546             If you pass an undefined value, it will set the property as undefined, removing whatever was set before.
7547              
7548             You can also provide an existing object of the given class. L</"_set_get_object"> will check the object provided does belong to the specified class or it will set an error and return undef.
7549              
7550             It returns the object currently set, if any.
7551              
7552             =head2 _set_get_object_array2
7553              
7554             Provided with an object property name, a class/package name and some array reference itself containing array references each containing hash references or objects, and this will create an array of array of objects.
7555              
7556             =head2 _set_get_object_array
7557              
7558             Provided with an object property name and a class/package name and similar to L</"_set_get_object_array2"> this will create an array reference of objects.
7559              
7560             =head2 _set_get_object_array_object
7561              
7562             Provided with an object property name, a class/package name and some data and this will create an array of object similar to L</"_set_get_object_array">, except the array produced is a L<Module::Generic::Array>
7563              
7564             =head2 _set_get_object_variant
7565              
7566             Provided with an object property name, a class/package name and some data, and depending whether the data provided is an hash reference or an array reference, this will either instantiate an object for the given hash reference or an array of objects with the hash references in the given array.
7567              
7568             This means the value stored for the object property will vary between an hash or array reference.
7569              
7570             =head2 _set_get_scalar
7571              
7572             Provided with an object property name, and a string, possibly a number or anything really and this will set the property value accordingly. Very straightforward.
7573              
7574             It returns the currently value stored.
7575              
7576             =head2 _set_get_scalar_as_object
7577              
7578             Provided with an object property name, and a string or a scalar reference and this stores it as an object of L<Module::Generic::Scalar>
7579              
7580             If there is already an object set for this property, the value provided will be assigned to it using L<Module::Generic::Scalar/"set">
7581              
7582             If it is called and not value is set yet, this will instantiate a L<Module::Generic::Scalar> object with no value.
7583              
7584             So a call to this method can safely be chained to access the L<Module::Generic::Scalar> methods. For example :
7585              
7586             sub name { return( shift->_set_get_scalar_as_object( 'name', @_ ) ); }
7587              
7588             Then, calling it :
7589              
7590             $object->name( 'John Doe' );
7591              
7592             Getting the value :
7593              
7594             my $cust_name = $object->name;
7595             print( "Nothing set yet.\n" ) if( !$cust_name->length );
7596              
7597             =head2 _set_get_scalar_or_object
7598              
7599             Provided with an object property name, and a class/package name and this stores the value as an object calling L</"_set_get_object"> if the value is an object of class I<class> or as a string calling L</"_set_get_scalar">
7600              
7601             If no value has been set yet, this returns a L<Module::Generic::Null> object to enable chaining.
7602              
7603             =head2 _set_get_uri
7604              
7605             Provided with an object property name, and an uri and this creates a L<URI> object and sets the property value accordingly.
7606              
7607             It accepts an L<URI> object, an uri or urn string, or an absolute path, i.e. a string starting with C</>.
7608              
7609             It returns the current value, if any, so the return value could be undef, thus it cannot be chained. Maybe it should return a L<Module::Generic::Null> object ?
7610              
7611             =head2 __dbh
7612              
7613             if your module has the global variables C<DB_DSN>, this will create a database handler using L<DBI>
7614              
7615             It will also use the following global variables in your module to set the database object: C<DB_RAISE_ERROR>, C<DB_AUTO_COMMIT>, C<DB_PRINT_ERROR>, C<DB_SHOW_ERROR_STATEMENT>, C<DB_CLIENT_ENCODING>, C<DB_SERVER_PREPARE>
7616              
7617             If C<DB_SERVER_PREPARE> is provided and true, C<pg_server_prepare> will be set to true in the database handler.
7618              
7619             It returns the database handler object.
7620              
7621             =head2 DEBUG
7622              
7623             Return the value of your global variable I<DEBUG>, if any.
7624              
7625             =head2 VERBOSE
7626              
7627             Return the value of your global variable I<VERBOSE>, if any.
7628              
7629             =head1 SEE ALSO
7630              
7631             L<Module::Generic::Exception>, L<Module::Generic::Array>, L<Module::Generic::Scalar>, L<Module::Generic::Boolean>, L<Module::Generic::Number>, L<Module::Generic::Null>, L<Module::Generic::Dynamic> and L<Module::Generic::Tie>
7632              
7633             L<Number::Format>, L<Class::Load>, L<Scalar::Util>
7634              
7635             =head1 AUTHOR
7636              
7637             Jacques Deguest E<lt>F<jack@deguest.jp>E<gt>
7638              
7639             =head1 COPYRIGHT & LICENSE
7640              
7641             Copyright (c) 2000-2020 DEGUEST Pte. Ltd.
7642              
7643             You can use, copy, modify and redistribute this package and associated
7644             files under the same terms as Perl itself.
7645              
7646             =cut