File Coverage

blib/lib/Module/Generic.pm
Criterion Covered Total %
statement 1817 3616 50.2
branch 500 1778 28.1
condition 197 975 20.2
subroutine 400 572 69.9
pod 38 46 82.6
total 2952 6987 42.2


line stmt bran cond sub pod time code
1             ## -*- perl -*-
2             ##----------------------------------------------------------------------------
3             ## Module Generic - ~/lib/Module/Generic.pm
4             ## Version v0.12.15
5             ## Copyright(c) 2020 DEGUEST Pte. Ltd.
6             ## Author: Jacques Deguest <@sitael.tokyo.deguest.jp>
7             ## Created 2019/08/24
8             ## Modified 2020/06/16
9             ##
10             ##----------------------------------------------------------------------------
11             package Module::Generic;
12             BEGIN
13 0         0 {
14 6     6   80 require 5.6.0;
15 6     6   628171 use strict;
  6         63  
  6         194  
16 6     6   34 use warnings::register;
  6         13  
  6         754  
17 6     6   42 use Scalar::Util qw( openhandle );
  6         17  
  6         304  
18 6     6   4153 use Data::Dumper;
  6         43335  
  6         593  
19             use Data::Printer
20             {
21             sort_keys => 1,
22             filters =>
23             {
24 0         0 'DateTime' => sub{ $_[0]->stringify },
25             }
26 6     6   4304 };
  6         253236  
  6         93  
27 6     6   11445 use Devel::StackTrace;
  6         33872  
  6         208  
28 6     6   3704 use Number::Format;
  6         39836  
  6         298  
29 6     6   3651 use Nice::Try;
  6         711722  
  6         46  
30 6     6   71051728 use B;
  6         29  
  6         505  
31             ## To get some context on what the caller expect. This is used in our error() method to allow chaining without breaking
32 6     6   4517 use Want;
  6         11488  
  6         425  
33 6     6   2931 use Class::Load ();
  6         38200  
  6         217  
34 6     6   3236 use Encode ();
  6         85223  
  6         795  
35 6         19 our( @ISA, @EXPORT_OK, @EXPORT, %EXPORT_TAGS, $AUTOLOAD );
36 6         12 our( $VERSION, $ERROR, $SILENT_AUTOLOAD, $VERBOSE, $DEBUG, $MOD_PERL );
37 6         10 our( $PARAM_CHECKER_LOAD_ERROR, $PARAM_CHECKER_LOADED, $CALLER_LEVEL );
38 6         11 our( $OPTIMIZE_MESG_SUB, $COLOUR_NAME_TO_RGB );
39 6     6   48 use Exporter ();
  6         12  
  6         482  
40 6         126 @ISA = qw( Exporter );
41 6         24 @EXPORT = qw( );
42 6         14 @EXPORT_OK = qw( subclasses );
43 6         16 %EXPORT_TAGS = ();
44 6         12 $VERSION = 'v0.12.15';
45 6         12 $VERBOSE = 0;
46 6         12 $DEBUG = 0;
47 6         11 $SILENT_AUTOLOAD = 1;
48 6         15 $PARAM_CHECKER_LOADED = 0;
49 6         82 $CALLER_LEVEL = 0;
50 6         9 $OPTIMIZE_MESG_SUB = 0;
51 6         4702 $COLOUR_NAME_TO_RGB = {};
52             # local $^W;
53 6     6   35 no strict qw(refs);
  6         16  
  6         211  
54 6     6   30 use constant COLOUR_OPEN => '<';
  6         13  
  6         359  
55 6     6   35 use constant COLOUR_CLOSE => '>';
  6         16  
  6         366  
56             };
57              
58             INIT
59             {
60 6     6   731 our $true = ${"Module::Generic::Boolean::true"};
  6         50  
61 6         17 our $false = ${"Module::Generic::Boolean::false"};
  6         27  
62 6         176 while( <DATA> )
63             {
64 0         0 chomp;
65 0         0 print( "INIT: found colour data: '$_'\n" );
66             }
67             };
68              
69             {
70             ## mod_perl/2.0.10
71             if( exists( $ENV{ 'MOD_PERL' } )
72             &&
73             ( $MOD_PERL = $ENV{ 'MOD_PERL' } =~ /^mod_perl\/\d+\.[\d\.]+/ ) )
74             {
75             select( ( select( STDOUT ), $| = 1 )[ 0 ] );
76             require Apache2::Log;
77             require Apache2::ServerUtil;
78             require Apache2::RequestUtil;
79             require Apache2::ServerRec;
80             }
81            
82             our $DEBUG_LOG_IO = undef();
83            
84             our $DB_NAME = $DATABASE;
85             our $DB_HOST = $SQL_SERVER;
86             our $DB_USER = $DB_LOGIN;
87             our $DB_PWD = $DB_PASSWD;
88             our $DB_RAISE_ERROR = $SQL_RAISE_ERROR;
89             our $DB_AUTO_COMMIT = $SQL_AUTO_COMMIT;
90             }
91              
92             sub import
93             {
94 6     6   94 my $self = shift( @_ );
95 6         33 my( $pkg, $file, $line ) = caller();
96 6         36 local $Exporter::ExportLevel = 1;
97             ## local $Exporter::Verbose = $VERBOSE;
98 6         160 Exporter::import( $self, @_ );
99            
100             ##print( STDERR "Module::Generic::import(): called from package '$pkg' in file '$file' at line '$line'.\n" ) if( $DEBUG );
101 6         40 ( my $dir = $pkg ) =~ s/::/\//g;
102 6         26 my $path = $INC{ $dir . '.pm' };
103             ##print( STDERR "Module::Generic::import(): using primary path of '$path'.\n" ) if( $DEBUG );
104 6 50       117 if( defined( $path ) )
105             {
106             ## Try absolute path name
107 0         0 $path =~ s/^(.*)$dir\.pm$/$1auto\/$dir\/autosplit.ix/;
108             ##print( STDERR "Module::Generic::import(): using treated path of '$path'.\n" ) if( $DEBUG );
109             eval
110 0         0 {
111 0     0   0 local $SIG{ '__DIE__' } = sub{ };
112 0     0   0 local $SIG{ '__WARN__' } = sub{ };
113 0         0 require $path;
114             };
115 0 0       0 if( $@ )
116             {
117 0         0 $path = "auto/$dir/autosplit.ix";
118             eval
119 0         0 {
120 0     0   0 local $SIG{ '__DIE__' } = sub{ };
121 0     0   0 local $SIG{ '__WARN__' } = sub{ };
122 0         0 require $path;
123             };
124             }
125 0 0       0 if( $@ )
126             {
127 0 0       0 CORE::warn( $@ ) unless( $SILENT_AUTOLOAD );
128             }
129             ##print( STDERR "Module::Generic::import(): '$path' ", $@ ? 'not ' : '', "loaded.\n" ) if( $DEBUG );
130             }
131             }
132              
133             sub new
134             {
135 132     132 1 397 my $that = shift( @_ );
136 132   66     647 my $class = ref( $that ) || $that;
137             ## my $pkg = ( caller() )[ 0 ];
138             ## print( STDERR __PACKAGE__ . "::new(): our calling package is '", ( caller() )[ 0 ], "', our class is '$class'.\n" );
139 132         307 my $self = {};
140             ## print( STDERR "${class}::OBJECT_READONLY: ", ${ "${class}\::OBJECT_READONLY" }, "\n" );
141 132 50       284 if( defined( ${ "${class}\::OBJECT_PERMS" } ) )
  132         1356  
142             {
143 0         0 my %hash = ();
144             my $obj = tie(
145             %hash,
146             'Module::Generic::Tie',
147             'pkg' => [ __PACKAGE__, $class ],
148 0         0 'perms' => ${ "${class}::OBJECT_PERMS" },
  0         0  
149             );
150 0         0 $self = \%hash;
151             }
152 132         381 bless( $self, $class );
153 132 50       467 if( $MOD_PERL )
154             {
155 0         0 my $r = Apache2::RequestUtil->request;
156             $r->pool->cleanup_register
157             (
158             sub
159             {
160             ## my( $pkg, $file, $line ) = caller();
161             ## 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" );
162 0     0   0 map{ delete( $self->{ $_ } ) } keys( %$self );
  0         0  
163 0         0 undef( %$self );
164             }
165 0         0 );
166             }
167 132 50       228 if( defined( ${ "${class}\::LOG_DEBUG" } ) )
  132         830  
168             {
169 0         0 $self->{ 'log_debug' } = ${ "${class}::LOG_DEBUG" };
  0         0  
170             }
171 132         566 return( $self->init( @_ ) );
172             }
173              
174             ## This is used to transform package data set into hash refer suitable for api calls
175             ## If package use AUTOLOAD, those AUtILOAD should make sure to create methods on the fly so they become defined
176             sub as_hash
177             {
178 0     0 1 0 my $self = shift( @_ );
179 0         0 my $this = $self->_obj2h;
180 0         0 my $p = {};
181 0 0 0     0 $p = shift( @_ ) if( scalar( @_ ) == 1 && ref( $_[0] ) eq 'HASH' );
182             # $self->message( 3, "Parameters are: ", sub{ $self->dumper( $p ) } );
183 0         0 my $class = ref( $self );
184 6     6   97 no strict 'refs';
  6         13  
  6         465  
185 0         0 my @methods = grep{ defined &{"${class}::$_"} } keys( %{"${class}::"} );
  0         0  
  0         0  
  0         0  
186             # $self->messagef( 3, "The following methods found in package $class: '%s'.", join( "', '", sort( @methods ) ) );
187 6     6   36 use strict 'refs';
  6         21  
  6         571  
188 0         0 my $ref = {};
189 0         0 foreach my $meth ( sort( @methods ) )
190             {
191 0 0       0 next if( substr( $meth, 0, 1 ) eq '_' );
192 0         0 my $rv = eval{ $self->$meth };
  0         0  
193 0 0       0 if( $@ )
194             {
195 0         0 warn( "An error occured while accessing method $meth: $@\n" );
196 0         0 next;
197             }
198 6     6   39 no overloading;
  6         15  
  6         239  
199             # $self->message( 3, "Value for method '$meth' is '$rv'." );
200 6     6   37 use overloading;
  6         13  
  6         10217  
201 0 0 0     0 if( $p->{json} && ( ref( $rv ) eq 'JSON::PP::Boolean' || ref( $rv ) eq 'Module::Generic::Boolean' ) )
    0 0        
202             {
203             # $self->message( 3, "Encoding boolean to true or false for method '$meth'." );
204 0         0 $ref->{ $meth } = Module::Generic::Boolean::TO_JSON( $ref->{ $meth } );
205 0         0 next;
206             }
207             elsif( $self->_is_object( $rv ) )
208             {
209 0 0 0     0 if( $rv->can( 'as_hash' ) && overload::Overloaded( $rv ) && overload::Method( $rv, '""' ) )
    0 0        
210             {
211 0         0 $rv = $rv . '';
212             }
213             elsif( $rv->can( 'as_hash' ) )
214             {
215             # $self->message( 3, "$rv is an object (", ref( $rv ), ") capable of as_hash, calling it." );
216 0         0 $rv = $rv->as_hash( $p );
217             }
218             }
219            
220             ## $self->message( 3, "Checking field '$meth' with value '$rv'." );
221            
222 0 0       0 if( ref( $rv ) eq 'HASH' )
    0          
    0          
    0          
223             {
224 0 0       0 $ref->{ $meth } = $rv if( scalar( keys( %$rv ) ) );
225             }
226             ## If method call returned an array, like array of string or array of object such as in data from Net::API::Stripe::List
227             elsif( ref( $rv ) eq 'ARRAY' )
228             {
229 0         0 my $arr = [];
230 0         0 foreach my $this_ref ( @$rv )
231             {
232 0 0 0     0 my $that_ref = ( $self->_is_object( $this_ref ) && $this_ref->can( 'as_hash' ) ) ? $this_ref->as_hash : $this_ref;
233 0         0 CORE::push( @$arr, $that_ref );
234             }
235 0 0       0 $ref->{ $meth } = $arr if( scalar( @$arr ) );
236             }
237             elsif( !ref( $rv ) )
238             {
239 0 0       0 $ref->{ $meth } = $rv if( CORE::length( $rv ) );
240             }
241             elsif( CORE::length( "$rv" ) )
242             {
243 0         0 $self->message( 3, "Adding value '$rv' to field '$meth' in hash \$ref" );
244 0         0 $ref->{ $meth } = $rv;
245             }
246             }
247 0         0 return( $ref );
248             }
249              
250             sub clear
251             {
252 0     0 0 0 goto( &clear_error );
253             }
254              
255             sub clear_error
256             {
257 0     0 1 0 my $self = shift( @_ );
258 0   0     0 my $class = ref( $self ) || $self;
259 0         0 my $this = $self->_obj2h;
260 0         0 $this->{error} = ${ "$class\::ERROR" } = '';
  0         0  
261 0         0 return( 1 );
262             }
263              
264             sub clone
265             {
266 0     0 1 0 my $self = shift( @_ );
267 0 0       0 if( Scalar::Util::reftype( $self ) eq 'HASH' )
    0          
268             {
269 0   0     0 return( bless( { %$self } => ( ref( $self ) || $self ) ) );
270             }
271             elsif( Scalar::Util::reftype( $self ) eq 'ARRAY' )
272             {
273 0   0     0 return( bless( [ @$self ] => ( ref( $self ) || $self ) ) );
274             }
275             else
276             {
277 0         0 return( $self->error( "Cloning is unsupported for type \"", ref( $self ), "\". Only hash or array references are supported." ) );
278             }
279             }
280              
281 2     2 0 20 sub colour_close { return( shift->_set_get( 'colour_close', @_ ) ); }
282              
283             sub colour_closest
284             {
285 0     0 1 0 my $self = shift( @_ );
286 0         0 my $colour = uc( shift( @_ ) );
287 0         0 my $this = $self->_obj2h;
288 0         0 my $colours =
289             {
290             '000000000' => 'black',
291             '000000255' => 'blue',
292             '000255000' => 'green',
293             '000255255' => 'cyan',
294             '255000000' => 'red',
295             '255000255' => 'magenta',
296             '255255000' => 'yellow',
297             '255255255' => 'white',
298             };
299 0         0 my( $red, $green, $blue ) = ( '', '', '' );
300 0 0       0 if( $colour =~ /^[A-Z]+([A-Z\s]+)*$/ )
    0          
    0          
301             {
302 0 0       0 if( !scalar( keys( %$COLOUR_NAME_TO_RGB ) ) )
303             {
304             ## $self->message( 3, "Processing colour map in <DATA> section." );
305 0         0 while( <DATA> )
306             {
307 0         0 chomp;
308 0 0       0 next if( /^[[:blank:]]*$/ );
309 0 0       0 last if( /^\=/ );
310 0         0 my( $r, $g, $b, $name ) = split( /[[:blank:]]+/, $_, 4 );
311 0         0 $COLOUR_NAME_TO_RGB->{ lc( $name ) } = [ $r, $g, $b ];
312             }
313 0         0 close( DATA );
314             }
315 0 0       0 if( CORE::exists( $COLOUR_NAME_TO_RGB->{ lc( $colour ) } ) )
316             {
317 0         0 ( $red, $green, $blue ) = @{$COLOUR_NAME_TO_RGB->{ lc( $colour ) }};
  0         0  
318             }
319             }
320             ## Colour all in decimal??
321             elsif( $colour =~ /^\d{9}$/ )
322             {
323             ## $self->message( 3, "Got colour all in decimal. Less work to do..." );
324 0         0 $red = substr( $colour, 0, 3 );
325 0         0 $green = substr( $colour, 3, 3 );
326 0         0 $blue = substr( $colour, 6, 3 );
327             }
328             ## Colour in hexadecimal, convert it
329             elsif( $colour =~ /^[A-F0-9]+$/ )
330             {
331 0         0 $red = hex( substr( $colour, 0, 2 ) );
332 0         0 $green = hex( substr( $colour, 2, 2 ) );
333 0         0 $blue = hex( substr( $colour, 4, 2 ) );
334             }
335             ## Clueless
336             else
337             {
338             ## Not undef, but rather empty string. Undef is associated with an error
339 0         0 return( '' );
340             }
341 0         0 my $dec_colour = CORE::sprintf( '%3d%3d%3d', $red, $green, $blue );
342 0         0 my $last = '';
343 0         0 my @colours = reverse( sort( keys( %$colours ) ) );
344 0         0 $red = CORE::sprintf( '%03d', $red );
345 0         0 $green = CORE::sprintf( '%03d', $green );
346 0         0 $blue = CORE::sprintf( '%03d', $blue );
347 0         0 my $cur = CORE::sprintf( '%03d%03d%03d', $red, $green, $blue );
348 0         0 my( $red_ok, $green_ok, $blue_ok ) = ( 0, 0, 0 );
349             ## $self->message( 3, "Current colour: '$cur'." );
350 0         0 for( my $i = 0; $i < scalar( @colours ); $i++ )
351             {
352 0         0 my $r = CORE::sprintf( '%03d', substr( $colours[ $i ], 0, 3 ) );
353 0         0 my $g = CORE::sprintf( '%03d', substr( $colours[ $i ], 3, 3 ) );
354 0         0 my $b = CORE::sprintf( '%03d', substr( $colours[ $i ], 6, 3 ) );
355            
356 0         0 my $r_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 0, 3 ) );
357 0         0 my $g_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 3, 3 ) );
358 0         0 my $b_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 6, 3 ) );
359            
360             ## $self->message( 3, "$r ($red), $g ($green), $b ($blue)" );
361 0 0 0     0 if( $red == $r ||
      0        
      0        
      0        
      0        
      0        
362             ( $red < $r && $red > int( $r / 2 ) ) ||
363             ( $red > $r && $red < int( $r_p / 2 ) && $r_p ) ||
364             $red > $r )
365             {
366 0         0 $red_ok++;
367             }
368            
369 0 0       0 if( $red_ok )
370             {
371 0 0 0     0 if( $green == $g ||
      0        
      0        
      0        
      0        
      0        
372             ( $green < $g && $green > int( $g / 2 ) ) ||
373             ( $green > $g && $green < int( $g_p / 2 ) && $g_p ) ||
374             $green > $g )
375             {
376 0         0 $blue_ok++;
377             }
378             }
379            
380 0 0       0 if( $blue_ok )
381             {
382 0 0 0     0 if( $blue == $b ||
      0        
      0        
      0        
      0        
      0        
383             ( $blue < $b && $blue > int( $b / 2 ) ) ||
384             ( $blue > $b && $blue < int( $b_p / 2 ) && $b_p ) ||
385             $blue > $b )
386             {
387 0         0 $last = $colours[ $i ];
388 0         0 last;
389             }
390             }
391             }
392 0         0 return( $colours->{ $last } );
393             }
394              
395             sub colour_format
396             {
397 12     12 1 35 my $self = shift( @_ );
398             ## style, colour or color and text
399 12         19 my $opts = shift( @_ );
400 12 50       31 return( $self->error( "Parameter hash provided is not an hash reference." ) ) if( !$self->_is_hash( $opts ) );
401 12         27 my $this = $self->_obj2h;
402             ## To make it possible to use either text or message property
403 12 50 33     37 $opts->{text} = CORE::delete( $opts->{message} ) if( CORE::length( $opts->{message} ) && !CORE::length( $opts->{text} ) );
404 12 50       29 return( $self->error( "No text was provided to format." ) ) if( !CORE::length( $opts->{text} ) );
405            
406 12   0     43 $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        
407 12   66     102 $opts->{bgcolour} //= CORE::delete( $opts->{bgcolor} ) || CORE::delete( $opts->{bg_colour} ) || CORE::delete( $opts->{bg_color} );
      66        
408            
409 12         22 my $bold = "\e[1m";
410 12         18 my $underline = "\e[4m";
411 12         19 my $reverse = "\e[7m";
412 12         17 my $normal = "\e[m";
413 12         15 my $cls = "\e[H\e[2J";
414 12         126 my $styles =
415             {
416             # Bold
417             b => 1,
418             bold => 1,
419             strong => 1,
420             # Italic
421             i => 3,
422             italic => 3,
423             # Underline
424             u => 4,
425             underline => 4,
426             underlined => 4,
427             blink => 5,
428             # Reverse
429             r => 7,
430             reverse => 7,
431             reversed => 7,
432             # Concealed
433             c => 8,
434             conceal => 8,
435             concealed => 8,
436             strike => 9,
437             striked => 9,
438             striken => 9,
439             };
440            
441             local $convert_24_To_8bits = sub
442             {
443 17     17   53 my( $r, $g, $b ) = @_;
444 17         70 $self->message( 9, "Converting $r, $g, $b to 8 bits" );
445 17         234 return( ( POSIX::floor( $r * 7 / 255 ) << 5 ) +
446             ( POSIX::floor( $g * 7 / 255 ) << 2 ) +
447             ( POSIX::floor( $b * 3 / 255 ) )
448             );
449 12         75 };
450            
451             ## opacity * original + (1-opacity)*background = resulting pixel
452             ## https://stackoverflow.com/a/746934/4814971
453             local $colour_with_alpha = sub
454             {
455 1     1   4 my( $r, $g, $b, $a, $bg ) = @_;
456             ## Assuming a white background (255)
457 1         4 my( $bg_r, $bg_g, $bg_b ) = ( 255, 255, 255 );
458 1 50       3 if( ref( $bg ) eq 'HASH' )
459             {
460 1         5 ( $bg_r, $bg_g, $bg_b ) = @$bg{qw( red green blue )};
461             }
462 1         9 $r = POSIX::round( ( $a * $r ) + ( ( 1 - $a ) * $bg_r ) );
463 1         5 $g = POSIX::round( ( $a * $g ) + ( ( 1 - $a ) * $bg_g ) );
464 1         4 $b = POSIX::round( ( $a * $b ) + ( ( 1 - $a ) * $bg_b ) );
465 1         4 return( [$r, $g, $b] );
466 12         46 };
467            
468             local $check_colour = sub
469             {
470 18     18   34 my $col = shift( @_ );
471             ## $self->message( 3, "Checking colour '$col'." );
472             ## $colours or $bg_colours
473 18         24 my $map = shift( @_ );
474 18         33 my $code;
475             my $light;
476             ## Example: 'light red' or 'light_red'
477 18 100       183 if( $col =~ /^(?:(?<light>bright|light)[[:blank:]\_]+)?
    50          
478             (?<colour>
479             (?:[a-zA-Z]+)(?:[[:blank:]]+\w+)?
480             |
481             (?<rgb_type>rgb[a]?)\([[:blank:]]*(?<red>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<green>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<blue>\d{1,3})
482             (?:[[:blank:]]*\,[[:blank:]]*(?<opacity>\d(?:\.\d+)?))?[[:blank:]]*
483             \)
484             )$/xi )
485             {
486 6     6   2978 my %regexp = %+;
  6         2352  
  6         37305  
  17         213  
487 17         132 $self->message( 9, "Light colour request '$col'. Capture: ", sub{ $self->dumper( \%regexp ) } );
  0         0  
488 17         160 ( $light, $col ) = ( $+{light}, $+{colour} );
489 17 100 66     117 if( CORE::length( $+{rgb_type} ) &&
      66        
      33        
490             CORE::length( $+{red} ) &&
491             CORE::length( $+{green} ) &&
492             CORE::length( $+{blue} ) )
493             {
494 3 100 66     20 if( $+{opacity} || $light )
495             {
496             my $opacity = CORE::length( $+{opacity} )
497             ? $+{opacity}
498 1 0       8 : $light
    50          
499             ? 0.5
500             : 1;
501 1         44 $col = CORE::sprintf( 'rgba(%03d%03d%03d,%.1f)', $+{red}, $+{green}, $+{blue}, $opacity );
502             }
503             else
504             {
505 2         28 $col = CORE::sprintf( 'rgb(%03d%03d%03d)', $+{red}, $+{green}, $+{blue} );
506             }
507             }
508             else
509             {
510 14         49 $self->message( 9, "Colour '$col' is not rgb[a]" );
511             }
512             }
513             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 )
514             {
515 0 0       0 if( $+{opacity} )
516             {
517 0         0 $col = CORE::sprintf( 'rgba(%03d%03d%03d,%.1f)', $+{red}, $+{green}, $+{blue}, $+{opacity} );
518             }
519             else
520             {
521 0         0 $col = CORE::sprintf( '%03d%03d%03d', $+{red}, $+{green}, $+{blue} );
522             }
523             }
524             else
525             {
526 1         6 $self->message( 9, "Colour '$col' failed to match our rgba regexp." );
527             }
528            
529 18         44 my $col_ref;
530 18 100 66     94 if( $col =~ /^rgb[a]?\((?<red>\d{3})(?<green>\d{3})(?<blue>\d{3})\)$/i )
    100          
    100          
531             {
532 3         7 $col_ref = {};
533 3         57 %$col_ref = %+;
534 3         45 $self->message( 9, "Rgb colour '$+{red}', '$+{green}' and '$+{blue}' found: ", sub{ $self->dumper( $col_ref ) });
  0         0  
535             return({
536             _24bits => [@$col_ref{qw( red green blue )}],
537 3         36 _8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} )
538             });
539             }
540             ## Treating opacity to make things lighter; not ideal, but standard scheme
541             elsif( $col =~ /^rgba\((?<red>\d{3})(?<green>\d{3})(?<blue>\d{3})[[:blank:]]*\,[[:blank:]]*(?<opacity>\d(?:\.\d)?)\)$/i )
542             {
543 1         4 $col_ref = {};
544 1         15 %$col_ref = %+;
545 1         17 $self->message( 9, "Rgba colour '$+{red}', '$+{green}' and '$+{blue}' found with opacity $+{opacity}: ", sub{ $self->dumper( $col_ref ) });
  0         0  
546 1 50       10 if( $+{opacity} )
547             {
548 1         4 my $opacity = $+{opacity};
549 1         6 $self->message( 9, "Opacity of $opacity found, applying the factor to the colour." );
550 1         2 my $bg;
551 1 50       3 if( $opts->{bgcolour} )
552             {
553 1         3 $bg = $self->colour_to_rgb( $opts->{bgcolour} );
554 1         5 $self->message( 9, "Calculating new rgb with opacity and background information: ", sub{ $self->dumper( $bg ) });
  0         0  
555             }
556 1         8 my $new_col = $colour_with_alpha->( @$col_ref{qw( red green blue )}, $opacity, $bg );
557 1         7 $self->message( 9, "New colour with opacity applied: ", sub{ $self->dumper( $new_col ) });
  0         0  
558 1         5 @$col_ref{qw( red green blue )} = @$new_col;
559 1         22 $self->message( 9, "Colour $+{red}, $+{green}, $+{blue} * $opacity => $col_ref->{red}, $col_red->{green}, $col_ref->{blue}" );
560             }
561             return({
562             _24bits => [@$col_ref{qw( red green blue )}],
563 1         7 _8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} )
564             });
565             }
566             elsif( $self->message( 9, "Checking if rgb value exists for colour '$col'" ) &&
567             ( $col_ref = $self->colour_to_rgb( $col ) ) )
568             {
569 13         99 $self->message( 9, "Setting up colour '$col' with data: ", sub{ $self->dumper( $col_ref ) });
  0         0  
570             ## $code = $map->{ $col };
571             return({
572             _24bits => [@$col_ref{qw( red green blue )}],
573 13         75 _8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} )
574             });
575             }
576             else
577             {
578 1         6 $self->message( 9, "Could not find a match for colour '$col'." );
579 1         3 return( {} );
580             }
581             # my $is_bg = ( CORE::substr( $code, 0, 1 ) == 4 );
582             # if( CORE::length( $code ) && $light )
583             # {
584             # ## If the colour is a background colour, replace 4 by 10 (e.g.: 42 becomes 103)
585             # ## and if foreground colour, replace 3 by 9
586             # CORE::substr( $code, 0, 1 ) = ( $is_bg ? 10 : 9 );
587             # }
588             # return( $code );
589 12         93 };
590 12         25 my $data = [];
591 12         19 my $params = [];
592             ## 8 bits parameters compatible
593 12         20 my $params8 = [];
594 12 0 33     31 if( $opts->{colour} || $opts->{color} || $opts->{fgcolour} || $opts->{fgcolor} || $opts->{fg_colour} || $opts->{fg_color} )
      0        
      0        
      0        
      0        
595             {
596 12   0     26 $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        
597 12         29 my $col_ref = $check_colour->( $opts->{colour}, $colours );
598             ## CORE::push( @$params, $col ) if( CORE::length( $col ) );
599 12 100       43 if( scalar( keys( %$col_ref ) ) )
600             {
601 11     0   76 $self->message( 9, "Foreground colour '$opts->{colour}' data are: ", sub{ $self->dumper( $col_ref ) });
  0         0  
602 11         79 CORE::push( @$params8, sprintf( '38;5;%d', $col_ref->{_8bits} ) );
603 11         23 CORE::push( @$params, sprintf( '38;2;%d;%d;%d', @{$col_ref->{_24bits}} ) );
  11         61  
604             }
605             else
606             {
607 1         7 $self->message( 9, "Could not resolve the foreground colour '$opts->{colour}'." );
608             }
609             }
610 12 50 66     76 if( $opts->{bgcolour} || $opts->{bgcolor} || $opts->{bg_colour} || $opts->{bg_color} )
      33        
      33        
611             {
612 6   0     14 $opts->{bgcolour} ||= CORE::delete( $opts->{bgcolor} ) || CORE::delete( $opts->{bg_colour} ) || CORE::delete( $opts->{bg_color} );
      33        
613 6         15 my $col_ref = $check_colour->( $opts->{bgcolour}, $bg_colours );
614             ## CORE::push( @$params, $col ) if( CORE::length( $col ) );
615 6 50       23 if( scalar( keys( %$col_ref ) ) )
616             {
617 6     0   39 $self->message( 9, "Foreground colour '$opts->{bgcolour}' data are: ", sub{ $self->dumper( $col_ref ) });
  0         0  
618 6         32 CORE::push( @$params8, sprintf( '48;5;%d', $col_ref->{_8bits} ) );
619 6         12 CORE::push( @$params, sprintf( '48;2;%d;%d;%d', @{$col_ref->{_24bits}} ) );
  6         30  
620             }
621             else
622             {
623 0         0 $self->message( 9, "Could not resolve the background colour '$opts->{colour}'." );
624             }
625             }
626 12 100       34 if( $opts->{style} )
627             {
628             ## $self->message( 9, "Style '$opts->{style}' provided." );
629 11         45 my $those_styles = [CORE::split( /\|/, $opts->{style} )];
630             ## $self->message( 9, "Split styles: ", sub{ $self->dumper( $those_styles ) } );
631 11         26 foreach my $s ( @$those_styles )
632             {
633             ## $self->message( 9, "Adding style '$s'" ) if( CORE::exists( $styles->{lc($s)} ) );
634 12 50       42 if( CORE::exists( $styles->{lc($s)} ) )
635             {
636 12         25 CORE::push( @$params, $styles->{lc($s)} );
637             ## We add the 8 bits compliant version only if any colour was provided, i.e.
638             ## This is not just a style definition
639 12 50       38 CORE::push( @$params8, $styles->{lc($s)} ) if( scalar( @$params8 ) );
640             }
641             }
642             }
643 12 100       51 CORE::push( @$data, "\e[" . CORE::join( ';', @$params8 ) . "m" ) if( scalar( @$params8 ) );
644 12 100       41 CORE::push( @$data, "\e[" . CORE::join( ';', @$params ) . "m" ) if( scalar( @$params ) );
645 12     0   61 $self->message( 9, "Pre final colour data contains: ", sub{ $self->dumper( $data ) });
  0         0  
646             ## 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
647 12 100 100     91 if( scalar( @$params ) && $opts->{text} =~ /\n+/ )
648             {
649 1         6 my $text_parts = [CORE::split( /\n/, $opts->{text} )];
650 1         4 my $fmt = CORE::join( '', @$data );
651 1         5 my $fmt8 = CORE::join( '', @$data8 );
652 1         5 for( my $i = 0; $i < scalar( @$text_parts ); $i++ )
653             {
654             ## Empty due to \n repeated
655 2 50       6 next if( !CORE::length( $text_parts->[$i] ) );
656 2         8 $text_parts->[$i] = $fmt . $text_parts->[$i] . $normal;
657             }
658 1         4 $opts->{text} = CORE::join( "\n", @$text_parts );
659 1         3 CORE::push( @$data, $opts->{text} );
660             }
661             else
662             {
663 11         46 CORE::push( @$data, $opts->{text} );
664 11 100       31 CORE::push( @$data, $normal, $normal ) if( scalar( @$params ) );
665             }
666             ## $self->message( "Returning '", quotemeta( CORE::join( '', @$data ) ), "'" );
667 12         446 return( CORE::join( '', @$data ) );
668             }
669              
670 2     2 0 14 sub colour_open { return( shift->_set_get( 'colour_open', @_ ) ); }
671              
672             sub colour_parse
673             {
674 5     5 1 19 my $self = shift( @_ );
675 5         29 my $txt = join( '', @_ );
676 5         11 my $this = $self->_obj2h;
677 5   50     19 my $open = $this->{colour_open} || COLOUR_OPEN;
678 5   50     28 my $close = $this->{colour_close} || COLOUR_CLOSE;
679 5         30 $self->message( 9, "Color open is '${open}' and close is '${close}'." );
680             ## $self->message( 3, "Parsing text '$txt'" );
681 5         24 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:]]*\))/;
682 5         14 my $style_re = qr/(?:bold|faint|italic|underline|blink|reverse|conceal|strike)/;
683             local $parse = sub
684             {
685 7     7   13 my $opts = shift( @_ );
686 7         14 my $chunk = $opts->{text};
687 7   100     67 my $start = $opts->{start} || 0;
688 7         15 my $buff = '';
689 7         10 my $in = 0;
690 7         14 my $this_def = '';
691 7         10 my $def = {};
692 7         11 my $err = '';
693 7         12 my $data = [];
694 7         13 my $chunk_len = CORE::length( $$chunk );
695 7         11 my $i;
696 7         39 $self->message( 9, "Parsing text $$chunk starting from position $start" );
697 7         29 for( $i = $start; $i < $chunk_len; $i++ )
698             {
699 214         329 my $c = CORE::substr( $$chunk, $i, 1 );
700             # $self->message( 9, "Checking character '$c' at position $i" );
701 214 100       421 if( $c eq $open )
    100          
702             {
703             ## Is this the closing element?
704 20 100       75 if( CORE::substr( $$chunk, $i, 3 ) eq "${open}/${close}" )
    100          
705             {
706 9         79 $self->message( 9, "Found closing element and buffered text '$def->{text}' and definition is: ", sub{ $self->dumper( $def ) } );
  0         0  
707             ## $def includes the property text containing concatenated text
708 9 50       54 my $res = CORE::length( $def->{text} ) ? $self->colour_format( $def ) : '';
709 9         47 $self->message( 9, "Resulting formatted text is: '$res'." );
710             ## If this is a child, we return right now, the section we processed
711 9 100       23 if( $opts->{is_child} )
712             {
713 2         16 $self->message( 9, "Being a child, return formatted text '$res' and position ", $i + 3, " for text '$$chunk'" );
714 2         14 return({ text => $res, position => $i + 3 });
715             }
716             ## Otherwise we push it to the data stack
717             else
718             {
719 7 50       26 CORE::push( @$data, $res ) if( CORE::length( $res ) );
720 7         12 $i += 2;
721 7         23 $def = {};
722 7         23 next;
723             }
724             }
725             ## If we have a style definition already and we find an open style curly bracket,
726             ## this means this is an embedded text, we call $parse recursively
727             elsif( CORE::scalar( keys( %$def ) ) )
728             {
729 2         22 $self->message( 9, "Found a sub style, calling parse recursively starting from position $i. \$def has ", sub{ $self->dumper( $def ) } );
  0         0  
730 2         27 my $res = $parse->({ text => $chunk, start => $i, is_child => 1 });
731 2         9 $def->{text} .= $res->{text};
732             ## $self->message( 9, "Resuming parsing at position $res->{position} in text '$$chunk'." );
733 2         5 $i = $res->{position};
734 2         4 $i--;
735 2         7 next;
736             }
737            
738 9         16 my $j;
739 9         27 for( $j = $i; $j < CORE::length( $$chunk ); $j++ )
740             {
741 265 100       572 next unless( CORE::substr( $$chunk, $j, 1 ) eq $close );
742 9         25 $this_def = CORE::substr( $$chunk, $i, ( $j + 1 ) - $i );
743 9         50 $self->message( 9, "Found a style at position $i, ending at position ", ( $j + 1 ), ": '$this_def'" );
744            
745 9 100       600 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 )
746             {
747 5   66     48 $style = $+{style1} || $+{style2};
748 5         26 $fg = $+{fg_colour};
749 5         17 $bg = $+{bg_colour};
750 5         27 $self->message( 9, "Found style '$style', colour '$fg' and background colour '$bg'." );
751 5         25 $def =
752             {
753             style => $style,
754             colour => $fg,
755             bg_colour => $bg,
756             };
757             }
758             else
759             {
760 4         23 $self->message( 9, "Evaluating the styling '$this_def'." );
761 4         278 $def = eval( $this_def );
762 4 50 33     32 if( $@ || ref( $def ) ne 'HASH' )
763             {
764 0   0     0 $err = $@ || "Invalid styling \"${this_def}\"";
765             }
766             else
767             {
768 4         8 $err = '';
769             }
770             }
771 9 50       32 unless( $err )
772             {
773 9         19 $def->{start} = $i;
774             }
775 9         20 last;
776             }
777 9 50       23 if( !CORE::length( $this_def ) )
778             {
779 0         0 $self->message( 9, "Reaching the end of the string and could not find a closing curly bracket \"${close}\"." );
780 0         0 $self->error( "Failed to find a closing curly bracket for opening style." );
781 0         0 $def->{error} = 'no closeing curly bracket';
782             }
783 9         17 $i = $j;
784 9         20 next;
785             }
786             ## We are inside a formatting
787             elsif( scalar( keys( %$def ) ) )
788             {
789 147         281 $def->{text} .= $c;
790             ## $self->message( 9, "Text buffer now is '$def->{text}'." );
791             }
792             else
793             {
794 47         118 CORE::push( @$data, $c );
795             ## $self->message( 9, "Adding text outside formatting. \$data now is: '", join( '', @$data ), "'." );
796             }
797             }
798             ## Return the text with replacement performed
799 5         32 $self->message( 9, "Final formatted text is: ", quotemeta( CORE::join( '', @$data ) ) );
800 5 50       172 return( $opts->{is_child} ? { text => CORE::join( '', @$data ), position => $i } : CORE::join( '', @$data ) );
801 5         47 };
802 5         19 return( $parse->({ text => \$txt }) );
803             }
804              
805             sub colour_to_rgb
806             {
807 15     15 0 32 my $self = shift( @_ );
808 15         32 my $colour = lc( shift( @_ ) );
809 15         26 my $this = $self->_obj2h;
810 15         39 my( $red, $green, $blue ) = ( '', '', '' );
811 15         198 $self->message( 9, "Checking rgb value for '$colour'. Called from line ", (caller)[2] );
812 15 50       82 if( $colour =~ /^[A-Za-z]+([\w\-]+)*([[:blank:]]+\w+)?$/ )
    0          
    0          
813             {
814 15         56 $self->message( 9, "Checking colour '$colour' as string. Looking up its rgb value." );
815 15 100       57 if( !scalar( keys( %$COLOUR_NAME_TO_RGB ) ) )
816             {
817 1         5 $self->message( 9, "Processing colour map in <DATA> section." );
818 1         4 my $colour_data = $self->__colour_data;
819 1         3875 $COLOUR_NAME_TO_RGB = eval( $colour_data );
820 1 50       12 if( $@ )
821             {
822 0         0 return( $self->error( "An error occurred loading data from __colour_data: $@" ) );
823             }
824             }
825 15 100       41 if( CORE::exists( $COLOUR_NAME_TO_RGB->{ $colour } ) )
826             {
827 14         18 ( $red, $green, $blue ) = @{$COLOUR_NAME_TO_RGB->{ $colour }};
  14         42  
828 14         52 $self->message( 9, "Found rgb '$red, $green, $blue' for colour '$colour'." );
829             }
830             else
831             {
832 1         6 $self->message( 9, "Could not find colour '$colour' in our colour map." );
833 1         5 return( '' );
834             }
835             }
836             ## Colour all in decimal??
837             elsif( $colour =~ /^\d{9}$/ )
838             {
839             ## $self->message( 9, "Got colour all in decimal. Less work to do..." );
840 0         0 $red = substr( $colour, 0, 3 );
841 0         0 $green = substr( $colour, 3, 3 );
842 0         0 $blue = substr( $colour, 6, 3 );
843             }
844             ## Colour in hexadecimal, convert it
845             elsif( $colour =~ /^[A-F0-9]+$/ )
846             {
847 0         0 $red = hex( substr( $colour, 0, 2 ) );
848 0         0 $green = hex( substr( $colour, 2, 2 ) );
849 0         0 $blue = hex( substr( $colour, 4, 2 ) );
850             }
851             ## Clueless
852             else
853             {
854 0         0 $self->message( 9, "Clueless about what to do with colour '$colour'." );
855             ## Not undef, but rather empty string. Undef is associated with an error
856 0         0 return( '' );
857             }
858 14         81 return({ red => $red, green => $green, blue => $blue });
859             }
860              
861             sub coloured
862             {
863 3     3 1 7 my $self = shift( @_ );
864 3         8 my $pref = shift( @_ );
865 3         10 my $text = CORE::join( '', @_ );
866 3         11 my $this = $self->_obj2h;
867 3         6 my( $style, $fg, $bg );
868             ## my $colour_re = qr/(?:(?:bright|light)[[:blank:]])?[a-zA-Z]+/;
869 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:]]*\))/;
870 3         8 my $style_re = qr/(?:bold|faint|italic|underline|blink|reverse|conceal|strike)/;
871 3 50       245 if( $pref =~ /^(?:(?<style1>$style_re)[[:blank:]]+)?(?<fg_colour>$colour_re)(?:[[:blank:]]+(?<style2>$style_re))?(?:[[:blank:]]+on[[:blank:]]+(?<bg_colour>$colour_re))?$/i )
872             {
873 3   33     28 $style = $+{style1} || $+{style2};
874 3         14 $fg = $+{fg_colour};
875 3         13 $bg = $+{bg_colour};
876             ## $self->message( 9, "Found style '$style', colour '$fg' and background colour '$bg'." );
877 3         20 return( $self->colour_format({ text => $text, style => $style, colour => $fg, bg_colour => $bg }) );
878             }
879             else
880             {
881 0         0 $self->message( 9, "No match." );
882 0         0 return( '' );
883             }
884             }
885              
886             sub debug
887             {
888 69     69 1 184 my $self = shift( @_ );
889 69         155 my $class = ref( $self );
890 69         176 my $this = $self->_obj2h;
891 69 50       355 if( @_ )
892             {
893 69         145 my $flag = shift( @_ );
894 69         185 $this->{debug} = $flag;
895 69 50       262 $self->message_switch( $flag ) if( $OPTIMIZE_MESG_SUB );
896 69 100 66     277 if( $this->{debug} &&
897             !$this->{debug_level} )
898             {
899 1         30 $this->{debug_level} = $this->{debug};
900             }
901             }
902 69   66     278 return( $this->{debug} || ${"$class\:\:DEBUG"} );
903             }
904              
905 0     0 1 0 sub dump { return( shift->printer( @_ ) ); }
906              
907             ## For backward compatibility and traceability
908 0     0 1 0 sub dump_print { return( shift->dumpto_printer( @_ ) ); }
909              
910             sub dumper
911             {
912 0     0 1 0 my $self = shift( @_ );
913 0         0 my $opts = {};
914 0 0 0     0 $opts = pop( @_ ) if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' );
915             # local $Data::Dumper::Sortkeys = 1;
916 0         0 local $Data::Dumper::Terse = 1;
917 0         0 local $Data::Dumper::Indent = 1;
918 0         0 local $Data::Dumper::Useqq = 1;
919 0 0       0 local $Data::Dumper::Maxdepth = $opts->{depth} if( CORE::length( $opts->{depth} ) );
920             local $Data::Dumper::Sortkeys = sub
921             {
922 0     0   0 my $h = shift( @_ );
923 0         0 return( [ sort( grep{ ref( $h->{ $_ } ) !~ /^(DateTime|DateTime\:\:)/ } keys( %$h ) ) ] );
  0         0  
924 0         0 };
925 0         0 return( Data::Dumper::Dumper( @_ ) );
926             }
927              
928             sub printer
929             {
930 0     0 1 0 my $self = shift( @_ );
931 0         0 my $opts = {};
932 0 0 0     0 $opts = pop( @_ ) if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' );
933 0     0   0 local $SIG{__WARN__} = sub{ };
934 0 0       0 if( scalar( keys( %$opts ) ) )
935             {
936 0         0 return( Data::Printer::np( @_, %$opts ) );
937             }
938             else
939             {
940 0         0 return( Data::Printer::np( @_ ) );
941             }
942             }
943              
944             *dumpto = \&dumpto_dumper;
945              
946             sub dumpto_printer
947             {
948 0     0 1 0 my $self = shift( @_ );
949 0         0 my( $data, $file ) = @_;
950 0   0     0 my $fh = IO::File->new( ">$file" ) || die( "Unable to create file '$file': $!\n" );
951 0         0 $fh->binmode( ':utf8' );
952 0         0 $fh->print( Data::Printer::np( $data ), "\n" );
953 0         0 $fh->close;
954             ## 666 so it can work under command line and web alike
955 0         0 chmod( 0666, $file );
956 0         0 return( 1 );
957             }
958              
959             sub dumpto_dumper
960             {
961 0     0 1 0 my $self = shift( @_ );
962 0         0 my( $data, $file ) = @_;
963 0         0 local $Data::Dumper::Sortkeys = 1;
964 0         0 local $Data::Dumper::Terse = 1;
965 0         0 local $Data::Dumper::Indent = 1;
966 0         0 local $Data::Dumper::Useqq = 1;
967 0   0     0 my $fh = IO::File->new( ">$file" ) || die( "Unable to create file '$file': $!\n" );
968 0 0       0 if( ref( $data ) )
969             {
970 0         0 $fh->print( Data::Dumper::Dumper( $data ), "\n" );
971             }
972             else
973             {
974 0         0 $fh->binmode( ':utf8' );
975 0         0 $fh->print( $data );
976             }
977 0         0 $fh->close;
978             ## 666 so it can work under command line and web alike
979 0         0 chmod( 0666, $file );
980 0         0 return( 1 );
981             }
982              
983             sub errno
984             {
985 0     0 0 0 my $self = shift( @_ );
986 0         0 my $this = $self->_obj2h;
987 0 0       0 if( @_ )
988             {
989 0 0       0 $this->{errno} = shift( @_ ) if( $_[ 0 ] =~ /^\-?\d+$/ );
990 0 0       0 return( $self->error( @_ ) ) if( @_ );
991             }
992 0         0 return( $this->{errno} );
993             }
994              
995             sub error
996             {
997 1     1 1 4 my $self = shift( @_ );
998 1   33     7 my $class = ref( $self ) || $self;
999 1         5 my $this = $self->_obj2h;
1000 1 50       8 if( @_ )
1001             {
1002 1         2 my $args = {};
1003 1 50 33     9 if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic::Exception' ) )
    50          
1004             {
1005 0         0 $args->{object} = shift( @_ );
1006             }
1007             elsif( ref( $_[0] ) eq 'HASH' )
1008             {
1009 0         0 $args = shift( @_ );
1010             }
1011             else
1012             {
1013 1 50 33     13 $args->{message} = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @_ ) );
1014             }
1015 1 50 33     8 $args->{message} = substr( $args->{message}, 0, $this->{error_max_length} ) if( $this->{error_max_length} > 0 && length( $args->{message} ) > $this->{error_max_length} );
1016             # Reset it
1017 1         5 $this->{_msg_no_exec_sub} = 0;
1018 1         2 my $n = 1;
1019             # $n++ while( ( caller( $n ) )[0] eq 'Module::Generic' );
1020 1         6 $args->{skip_frames} = $n + 1;
1021             ## my( $p, $f, $l ) = caller( $n );
1022             ## my( $sub ) = ( caller( $n + 1 ) )[3];
1023 1         25 my $o = $this->{error} = ${ $class . '::ERROR' } = Module::Generic::Exception->new( $args );
  1         9  
1024             ## 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 );
1025            
1026             ## Get the warnings status of the caller. We use caller(1) to skip one frame further, ie our caller's caller
1027             ## This can be changed by using 'no warnings'
1028 1         5 my $should_display_warning = 0;
1029 1         2 my $no_use_warnings = 1;
1030             ## Try to get the warnings status if is enabled at all.
1031 1         3 try
1032 1     1   2 {
1033 1         10 $should_display_warning = $self->_warnings_is_enabled;
1034 1         3 $no_use_warnings = 0;
1035             }
1036 1 50       6 catch( $e )
  1 50       4  
  1 50       4  
  1 0       3  
  1 50       3  
  1         2  
  1         3  
  1         2  
  1         6  
  0         0  
  1         4  
  0         0  
  1         5  
  1         3  
  1         3  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
1037 0     0   0 {
1038             #
1039 0 0 33     0 }
  0 0 33     0  
  0 0       0  
  0 50       0  
  0         0  
  0         0  
  1         20  
  0         0  
1040            
1041 1 50       6 if( $no_use_warnings )
1042             {
1043 0         0 my $call_offset = 0;
1044 0         0 while( my @call_data = caller( $call_offset ) )
1045             {
1046             ## 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] );
1047 0 0 0     0 unless( $call_offset > 0 && $call_data[0] ne $class && (caller($call_offset-1))[0] eq $class )
      0        
1048             {
1049             ## print( STDERR "Skipping package $call_data[0]\n" );
1050 0         0 $call_offset++;
1051 0         0 next;
1052             }
1053 0 0 0     0 last if( $call_data[9] || ( $call_offset > 0 && (caller($call_offset-1))[0] ne $class ) );
      0        
1054 0         0 $call_offset++;
1055             }
1056             ## print( STDERR "Using offset $call_offset with bitmask ", ( caller( $call_offset ) )[9], "\n" );
1057 0         0 my $bitmask = ( caller( $call_offset ) )[9];
1058 0         0 my $offset = $warnings::Offsets{uninitialized};
1059             ## $self->message( 3, "Caller (2)'s bitmask is '$bitmask', warnings offset is '$offset' and vector is '", vec( $bitmask, $offset, 1 ), "'." );
1060 0         0 $should_display_warning = vec( $bitmask, $offset, 1 );
1061             }
1062            
1063 1         4 my $r;
1064 1 50       4 $r = Apache2::RequestUtil->request if( $MOD_PERL );
1065             # $r->log_error( "Called for error $o" ) if( $r );
1066 1 50       4 $r->warn( $o->as_string ) if( $r );
1067 1         10 my $err_handler = $self->error_handler;
1068 1 50 33     21 if( $err_handler && ref( $err_handler ) eq 'CODE' )
    50 33        
    50          
    50          
1069             {
1070             # $r->log_error( "Module::Generic::error(): called for object error hanler" ) if( $r );
1071 0         0 $err_handler->( $o );
1072             }
1073             elsif( $r )
1074             {
1075             # $r->log_error( "Module::Generic::error(): called for Apache mod_perl error hanler" ) if( $r );
1076 0 0       0 if( my $log_handler = $r->get_handlers( 'PerlPrivateErrorHandler' ) )
1077             {
1078 0         0 $log_handler->( $o );
1079             }
1080             else
1081             {
1082             # $r->log_error( "Module::Generic::error(): No Apache mod_perl error handler set, reverting to log_error" ) if( $r );
1083             # $r->log_error( "$o" );
1084 0 0       0 $r->warn( $o->as_string ) if( $should_display_warning );
1085             }
1086             }
1087             elsif( $this->{fatal} )
1088             {
1089             ## die( sprintf( "Within package %s in file %s at line %d: %s\n", $o->package, $o->file, $o->line, $o->message ) );
1090             # $r->log_error( "Module::Generic::error(): called calling die" ) if( $r );
1091 0         0 my $enc_str = eval{ Encode::encode( 'UTF-8', "$o", Encode::FB_CROAK ) };
  0         0  
1092 0 0       0 die( $@ ? $o : $enc_str );
1093             }
1094             elsif( !exists( $this->{quiet} ) || !$this->{quiet} )
1095             {
1096             # $r->log_error( "Module::Generic::error(): calling warn" ) if( $r );
1097 1 50       5 if( $r )
1098             {
1099 0 0       0 $r->warn( $o->as_string ) if( $should_display_warning );
1100             }
1101             else
1102             {
1103 1         2 my $enc_str = eval{ Encode::encode( 'UTF-8', "$o", Encode::FB_CROAK ) };
  1         6  
1104 1 0       273 warn( $@ ? $o : $enc_str ) if( $should_display_warning );
    50          
1105             }
1106             }
1107             ## https://metacpan.org/pod/Perl::Critic::Policy::Subroutines::ProhibitExplicitReturnUndef
1108             ## https://perlmonks.org/index.pl?node_id=741847
1109             ## Because in list context this would create a lit with one element undef()
1110             ## A bare return will return an empty list or an undef scalar
1111             ## return( undef() );
1112             ## return;
1113             ## 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
1114             ## 2020-05-12: Added the no_return_null_object to instruct not to return a null object
1115             ## This is especially needed when an error is called from TIEHASH that returns a special object.
1116             ## A Null object would trigger a fatal perl segmentation fault
1117 1 50 33     11 if( !$args->{no_return_null_object} && want( 'OBJECT' ) )
1118             {
1119 0         0 my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 });
1120 0         0 rreturn( $null );
1121             }
1122 1         80 return;
1123             }
1124 0 0       0 return( ref( $self ) ? $this->{error} : ${ $class . '::ERROR' } );
  0         0  
1125             }
1126              
1127 1     1 0 9 sub error_handler { return( shift->_set_get_code( '_error_handler', @_ ) ); }
1128              
1129             *errstr = \&error;
1130              
1131             sub get
1132             {
1133 0     0 1 0 my $self = shift( @_ );
1134 0         0 my $this = $self->_obj2h;
1135 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
1136 0         0 my @data = map{ $data->{ $_ } } @_;
  0         0  
1137 0 0       0 return( wantarray() ? @data : $data[ 0 ] );
1138             }
1139              
1140             sub init
1141             {
1142 262     262 1 489 my $self = shift( @_ );
1143 262         579 my $pkg = ref( $self );
1144 262         812 my $this = $self->_obj2h;
1145 262 50       1481 $this->{verbose} = ${ $pkg . '::VERBOSE' } if( !length( $this->{verbose} ) );
  262         1632  
1146 262 100       1007 $this->{debug} = ${ $pkg . '::DEBUG' } if( !length( $this->{debug} ) );
  129         508  
1147 262 50       871 $this->{version} = ${ $pkg . '::VERSION' } if( !defined( $this->{version} ) );
  262         1150  
1148 262         795 $this->{level} = 0;
1149 262         737 $self->{colour_open} = COLOUR_OPEN;
1150 262         770 $self->{colour_close} = COLOUR_CLOSE;
1151             ## If no debug level was provided when calling message, this level will be assumed
1152             ## Example: message( "Hello" );
1153             ## If _message_default_level was set to 3, this would be equivalent to message( 3, "Hello" )
1154 262         693 $this->{ '_message_default_level' } = 0;
1155 262         508 my $data = $this;
1156 262 50       673 if( $this->{_data_repo} )
1157             {
1158 0 0       0 $this->{ $this->{_data_repo} } = {} if( !$this->{ $this->{_data_repo} } );
1159 0         0 $data = $this->{ $this->{_data_repo} };
1160             }
1161 262 50 66     1077 @_ = () if( @_ == 1 && !defined( $_[0] ) );
1162 262 100       670 if( @_ )
1163             {
1164 70         268 my @args = @_;
1165 70         131 my $vals;
1166 70 100 33     337 if( ref( $args[0] ) eq 'HASH' ||
    50 66        
    50 33        
    50          
1167             ( Scalar::Util::blessed( $args[0] ) && $args[0]->isa( 'Module::Generic::Hash' ) ) )
1168             {
1169             ## $self->_message( 3, "Got an hash ref" );
1170 68         170 my $h = shift( @args );
1171 68         599 $vals = [ %$h ];
1172             ## $vals = [ %{$_[0]} ];
1173             }
1174             elsif( ref( $args[0] ) eq 'ARRAY' )
1175             {
1176             ## $self->_message( 3, "Got an array ref" );
1177 0         0 $vals = $args[0];
1178             }
1179             ## Special case when there is an undefined value passed (null) even though it is declared as a hash or object
1180             elsif( scalar( @args ) == 1 && !defined( $args[0] ) )
1181             {
1182             # return( undef() );
1183 0         0 return;
1184             }
1185             elsif( ( scalar( @args ) % 2 ) )
1186             {
1187 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 ) ) ) );
1188             }
1189             else
1190             {
1191             ## $self->message( 3, "Got an array: ", sub{ $self->dumper( \@args ) } );
1192 2         7 $vals = \@args;
1193             }
1194             ## Check if there is a debug parameter, and if we find one, set it first so that that
1195             ## calls to the package subroutines can produce verbose feedback as necessary
1196 70         425 for( my $i = 0; $i < scalar( @$vals ); $i++ )
1197             {
1198 1886 100       4064 if( $vals->[$i] eq 'debug' )
1199             {
1200 70         176 my $v = $vals->[$i + 1];
1201 70         382 $self->debug( $v );
1202 70         261 CORE::splice( @$vals, $i, 2 );
1203             }
1204             }
1205            
1206 70         267 for( my $i = 0; $i < scalar( @$vals ); $i++ )
1207             {
1208 941         1734 my $name = $vals->[ $i ];
1209 941         1597 my $val = $vals->[ ++$i ];
1210 941         2775 my $meth = $self->can( $name );
1211             # $self->message( 3, "Does the object from class (", ref( $self ), ") has a method $name? ", ( defined( $meth ) ? 'yes' : 'no' ) );
1212 941 50       1859 if( defined( $meth ) )
    0          
    0          
1213             {
1214 941         2589 $self->$name( $val );
1215 941         3368 next;
1216             }
1217             elsif( $this->{_init_strict_use_sub} )
1218             {
1219             # $self->message( 3, "Checking if method $name exist in class ", ref( $self ), ": ", $self->can( $name ) ? 'yes' : 'no' );
1220             #if( !defined( $meth = $self->can( $name ) ) )
1221             #{
1222 0         0 $self->error( "Unknown method $name in class $pkg" );
1223 0         0 next;
1224             #}
1225             # $self->message( 3, "Calling method $name with value $val" );
1226             # $self->$meth( $val );
1227             # $meth->( $self, $val );
1228             #$self->$name( $val );
1229             #next;
1230             }
1231             elsif( exists( $data->{ $name } ) )
1232             {
1233             ## Pre-existing field value looks like a module package and that package is already loaded
1234 0 0 0     0 if( ( index( $data->{ $name }, '::' ) != -1 || $data->{ $name } =~ /^[a-zA-Z][a-zA-Z\_]*[a-zA-Z]$/ ) &&
    0 0        
1235             $self->_is_class_loaded( $data->{ $name } ) )
1236             {
1237 0         0 my $thisPack = $data->{ $name };
1238 0 0       0 if( !Scalar::Util::blessed( $val ) )
    0          
1239             {
1240 0         0 return( $self->error( "$name parameter expects a package $thisPack object, but instead got '$val'." ) );
1241             }
1242             elsif( !$val->isa( $thisPack ) )
1243             {
1244 0         0 return( $self->error( "$name parameter expects a package $thisPack object, but instead got an object from package '", ref( $val ), "'." ) );
1245             }
1246             }
1247             elsif( $this->{_init_strict} )
1248             {
1249 0 0       0 if( ref( $data->{ $name } ) eq 'ARRAY' )
    0          
    0          
1250             {
1251 0 0       0 return( $self->error( "$name parameter expects an array reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'ARRAY' );
1252             }
1253             elsif( ref( $data->{ $name } ) eq 'HASH' )
1254             {
1255 0 0       0 return( $self->error( "$name parameter expects an hash reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'HASH' );
1256             }
1257             elsif( ref( $data->{ $name } ) eq 'SCALAR' )
1258             {
1259 0 0       0 return( $self->error( "$name parameter expects a scalar reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'SCALAR' );
1260             }
1261             }
1262             }
1263             ## The name parameter does not exist
1264             else
1265             {
1266             ## If we are strict, we reject
1267 0 0       0 next if( $this->{_init_strict} );
1268             }
1269             ## We passed all tests
1270 0         0 $data->{ $name } = $val;
1271             }
1272             }
1273 262 0 33     854 if( $OPTIMIZE_MESG_SUB && !$this->{verbose} && !$this->{debug} )
      33        
1274             {
1275 0 0       0 if( defined( &{ "$pkg\::message" } ) )
  0         0  
1276             {
1277 0 0       0 *{ "$pkg\::message_off" } = \&{ "$pkg\::message" } unless( defined( &{ "$pkg\::message_off" } ) );
  0         0  
  0         0  
  0         0  
1278 0     0   0 *{ "$pkg\::message" } = sub { 1 };
  0         0  
  0         0  
1279             }
1280             }
1281 262         502 return( $self );
1282             }
1283              
1284 0     0 1 0 sub log_handler { return( shift->_set_get_code( '_log_handler', @_ ) ); }
1285              
1286             # sub log4perl
1287             # {
1288             # my $self = shift( @_ );
1289             # if( @_ )
1290             # {
1291             # require Log::Log4perl;
1292             # my $ref = shift( @_ );
1293             # Log::Log4perl::init( $ref->{ 'config_file' } );
1294             # my $log = Log::Log4perl->get_logger( $ref->{ 'domain' } );
1295             # $self->{ 'log4perl' } = $log;
1296             # }
1297             # else
1298             # {
1299             # $self->{ 'log4perl' };
1300             # }
1301             # }
1302              
1303             sub message
1304             {
1305 218     218 1 356 my $self = shift( @_ );
1306 218   33     496 my $class = ref( $self ) || $self;
1307             ## my( $pack, $file, $line ) = caller;
1308 218         417 my $this = $self->_obj2h;
1309             ## 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" );
1310 218         406 my $r;
1311 218 50       405 $r = Apache2::RequestUtil->request if( $MOD_PERL );
1312 218 50 33     818 if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
  0   33     0  
1313             {
1314             # $r->log_error( "Got here in Module::Generic::message before checking message." ) if( $r );
1315 218         347 my $ref;
1316 218         412 $ref = $self->message_check( @_ );
1317             ## print( STDERR __PACKAGE__ . "::message(): message_check() returns '$ref' (", join( '', @$ref ), ")\n" );
1318             ## return( 1 ) if( !( $ref = $self->message_check( @_ ) ) );
1319 218 50       512 return( 1 ) if( !$ref );
1320            
1321 0         0 my $opts = {};
1322 0 0       0 $opts = pop( @$ref ) if( ref( $ref->[-1] ) eq 'HASH' );
1323             ## print( STDERR __PACKAGE__ . "::message(): \$opts contains: ", $self->dumper( $opts ), "\n" );
1324            
1325             ## By now, we should have a reference to @_ in $ref
1326             ## my $class = ref( $self ) || $self;
1327             ## print( STDERR __PACKAGE__ . "::message(): caller at 0 is ", (caller(0))[3], " and at 1 is ", (caller(1))[3], "\n" );
1328             ## $r->log_error( "Got here in Module::Generic::message checking frames stack." ) if( $r );
1329 0   0     0 my $stackFrame = $self->message_frame( (caller(1))[3] ) || 1;
1330 0 0       0 $stackFrame = 1 unless( $stackFrame =~ /^\d+$/ );
1331 0 0       0 $stackFrame-- if( $stackFrame );
1332 0 0 0     0 $stackFrame++ if( (caller(1))[3] eq 'Module::Generic::messagef' ||
1333             (caller(1))[3] eq 'Module::Generic::message_colour' );
1334 0 0       0 $stackFrame++ if( (caller(2))[3] eq 'Module::Generic::messagef_colour' );
1335 0         0 my( $pkg, $file, $line, @otherInfo ) = caller( $stackFrame );
1336 0         0 my $sub = ( caller( $stackFrame + 1 ) )[3];
1337 0         0 my $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
1338 0 0       0 if( ref( $this->{_message_frame} ) eq 'HASH' )
1339             {
1340 0 0       0 if( exists( $this->{_message_frame}->{ $sub2 } ) )
1341             {
1342 0         0 my $frameNo = int( $this->{_message_frame}->{ $sub2 } );
1343 0 0       0 if( $frameNo > 0 )
1344             {
1345 0         0 ( $pkg, $file, $line, $sub ) = caller( $frameNo );
1346 0         0 $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
1347             }
1348             }
1349             }
1350             ## $r->log_error( "Called from package $pkg in file $file at line $line from sub $sub2 ($sub)" ) if( $r );
1351 0 0       0 if( $sub2 eq 'message' )
1352             {
1353 0         0 $stackFrame++;
1354 0         0 ( $pkg, $file, $line, @otherInfo ) = caller( $stackFrame );
1355 0         0 my $sub = ( caller( $stackFrame + 1 ) )[3];
1356 0         0 $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
1357             }
1358             ## $r->log_error( "Got here in Module::Generic::message building the message string." ) if( $r );
1359 0         0 my $txt;
1360 0 0       0 if( $opts->{message} )
1361             {
1362 0 0       0 if( ref( $opts->{message} ) eq 'ARRAY' )
1363             {
1364 0 0 0     0 $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @{$opts->{message}} ) );
  0         0  
1365             }
1366             else
1367             {
1368 0         0 $txt = $opts->{message};
1369             }
1370             }
1371             else
1372             {
1373 0 0 0     0 $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) );
1374             }
1375             ## Reset it
1376 0         0 $this->{_msg_no_exec_sub} = 0;
1377             ## $r->log_error( "Got here in Module::Generic::message with message string '$txt'." ) if( $r );
1378 6     6   59 no overloading;
  6         20  
  6         54662  
1379 0         0 my $mesg = "${pkg}::${sub2}( $self ) [$line]: " . $txt;
1380 0         0 $mesg =~ s/\n$//gs;
1381 0         0 $mesg = '## ' . join( "\n## ", split( /\n/, $mesg ) );
1382            
1383             my $info =
1384             {
1385             'formatted' => $mesg,
1386             'message' => $txt,
1387             'file' => $file,
1388             'line' => $line,
1389             'package' => $class,
1390             'sub' => $sub2,
1391 0 0       0 'level' => ( $_[0] =~ /^\d+$/ ? $_[0] : CORE::exists( $opts->{level} ) ? $opts->{level} : 0 ),
    0          
1392             };
1393 0 0       0 $info->{type} = $opts->{type} if( $opts->{type} );
1394            
1395             ## $r->log_error( "Got here in Module::Generic::message checkin if we run under ModPerl." ) if( $r );
1396             ## If Mod perl is activated AND we are not using a private log
1397             ## my $r;
1398             ## if( $MOD_PERL && !${ "${class}::LOG_DEBUG" } && ( $r = eval{ require Apache2::RequestUtil; Apache2::RequestUtil->request; } ) )
1399 0 0 0     0 if( $r && !${ "${class}::LOG_DEBUG" } )
  0 0 0     0  
    0 0        
    0 0        
    0 0        
      0        
1400             {
1401             ## $r->log_error( "Got here in Module::Generic::message, going to call our log handler." );
1402 0 0       0 if( my $log_handler = $r->get_handlers( 'PerlPrivateLogHandler' ) )
1403             {
1404             # my $meta = B::svref_2object( $log_handler );
1405             # $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 );
1406 0         0 $log_handler->( $mesg );
1407             }
1408             else
1409             {
1410 0         0 $r->log_error( $mesg );
1411             }
1412             }
1413             ## Using ModPerl Server to log
1414 0         0 elsif( $MOD_PERL && !${ "${class}::LOG_DEBUG" } )
1415             {
1416 0         0 require Apache2::ServerUtil;
1417 0         0 my $s = Apache2::ServerUtil->server;
1418 0         0 $s->log_error( $mesg );
1419             }
1420             ## e.g. in our package, we could set the handler using the curry module like $self->{_log_handler} = $self->curry::log
1421             elsif( !-t( STDIN ) && $this->{_log_handler} && ref( $this->{_log_handler} ) eq 'CODE' )
1422             {
1423             # $r = Apache2::RequestUtil->request;
1424             # $r->log_error( "Got here in Module::Generic::message, going to call our log handler without using Apache callbacks." );
1425             # my $meta = B::svref_2object( $self->{_log_handler} );
1426             # $r->log_error( "Log handler code routine name is " . $meta->GV->NAME . " called in file " . $meta->GV->FILE . " at line " . $meta->GV->LINE );
1427 0         0 $this->{_log_handler}->( $info );
1428             }
1429 0         0 elsif( !-t( STDIN ) && ${ $class . '::MESSAGE_HANDLER' } && ref( ${ $class . '::MESSAGE_HANDLER' } ) eq 'CODE' )
  0         0  
1430             {
1431 0         0 my $h = ${ $class . '::MESSAGE_HANDLER' };
  0         0  
1432 0         0 $h->( $info );
1433             }
1434             ## Or maybe then into a private log file?
1435             ## This way, even if the log method is superseeded, we can keep using ours without interfering with the other one
1436             elsif( $self->message_log( $mesg, "\n" ) )
1437             {
1438 0         0 return( 1 );
1439             }
1440             ## Otherwise just on the stderr
1441             else
1442             {
1443 0         0 my $err = IO::File->new;
1444 0         0 $err->fdopen( fileno( STDERR ), 'w' );
1445 0 0       0 $err->binmode( ":utf8" ) unless( $opts->{no_encoding} );
1446 0         0 $err->autoflush( 1 );
1447 0         0 $err->print( $mesg, "\n" );
1448             }
1449             }
1450 0         0 return( 1 );
1451             }
1452              
1453             *message_color = \&message_colour;
1454              
1455             sub message_colour
1456             {
1457 0     0 1 0 my $self = shift( @_ );
1458 0   0     0 my $class = ref( $self ) || $self;
1459 0         0 my $this = $self->_obj2h;
1460 0 0 0     0 if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
  0   0     0  
1461             {
1462 0 0       0 my $level = ( $_[0] =~ /^\d+$/ ? shift( @_ ) : undef() );
1463 0         0 my $opts = {};
1464 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        
1465             {
1466 0         0 $opts = pop( @_ );
1467             }
1468 0         0 my $ref = [@_];
1469 0 0 0     0 $level = $opts->{level} if( !defined( $level ) && CORE::exists( $opts->{level} ) );
1470 0         0 my $txt;
1471 0 0       0 if( $opts->{message} )
1472             {
1473 0 0       0 if( ref( $opts->{message} ) eq 'ARRAY' )
1474             {
1475 0 0 0     0 $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @{$opts->{message}} ) );
  0         0  
1476             }
1477             else
1478             {
1479 0         0 $txt = $opts->{message};
1480             }
1481             }
1482             else
1483             {
1484 0 0 0     0 $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) );
1485             }
1486 0         0 $txt = $self->colour_parse( $txt );
1487 0         0 $opts->{message} = $txt;
1488 0 0       0 $opts->{level} = $level if( defined( $level ) );
1489 0   0     0 return( $self->message( ( $level || 0 ), $opts ) );
1490             }
1491 0         0 return( 1 );
1492             }
1493              
1494             sub messagef
1495             {
1496 0     0 1 0 my $self = shift( @_ );
1497             ## print( STDERR "got here: ", ref( $self ), "::messagef\n" );
1498 0   0     0 my $class = ref( $self ) || $self;
1499 0         0 my $this = $self->_obj2h;
1500 0 0 0     0 if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
  0   0     0  
1501             {
1502 0 0       0 my $level = ( $_[0] =~ /^\d+$/ ? shift( @_ ) : undef() );
1503 0         0 my $opts = {};
1504 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        
1505             {
1506 0         0 $opts = pop( @_ );
1507             }
1508 0 0 0     0 $level = $opts->{level} if( !defined( $level ) && CORE::exists( $opts->{level} ) );
1509 0         0 my( $ref, $fmt );
1510 0 0       0 if( $opts->{message} )
1511             {
1512 0 0       0 if( ref( $opts->{message} ) eq 'ARRAY' )
1513             {
1514 0         0 $ref = $opts->{message};
1515 0         0 $fmt = shift( @$ref );
1516             }
1517             else
1518             {
1519 0         0 $fmt = $opts->{message};
1520 0         0 $ref = \@_;
1521             }
1522             }
1523             else
1524             {
1525 0         0 $ref = \@_;
1526 0         0 $fmt = shift( @$ref );
1527             }
1528 0 0 0     0 my $txt = sprintf( $fmt, map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) );
1529             ## $self->message( 3, "Option colour set? '$opts->{colour}'. Text is: '$txt'" );
1530 0 0       0 $txt = $self->colour_parse( $txt ) if( $opts->{colour} );
1531             ## print( STDERR ref( $self ), "::messagef \$txt is '$txt'\n" );
1532 0         0 $opts->{message} = $txt;
1533 0 0       0 $opts->{level} = $level if( defined( $level ) );
1534             # return( $self->message( defined( $level ) ? ( $level, $txt ) : $txt ) );
1535 0   0     0 return( $self->message( ( $level || 0 ), $opts ) );
1536             }
1537 0         0 return( 1 );
1538             }
1539              
1540             sub messagef_colour
1541             {
1542 0     0 0 0 my $self = shift( @_ );
1543 0         0 my $this = $self->_obj2h;
1544 0 0 0     0 if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
  0   0     0  
1545             {
1546 0         0 my @args = @_;
1547 0         0 my $opts = {};
1548 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        
1549             {
1550 0         0 $opts = pop( @args );
1551             }
1552 0         0 $opts->{colour} = 1;
1553 0         0 CORE::push( @args, $opts );
1554             ## $self->message( 0, "Sending arguments: ", sub{ $self->dumper( \@args ) } );
1555 0         0 return( $this->messagef( @args ) );
1556             }
1557 0         0 return( 1 );
1558             }
1559              
1560             sub message_check
1561             {
1562 218     218 1 320 my $self = shift( @_ );
1563 218   33     459 my $class = ref( $self ) || $self;
1564 218         360 my $this = $self->_obj2h;
1565             ## printf( STDERR "Our class is $class and DEBUG_TARGET contains: '%s' and debug value is %s\n", join( ', ', @${ "${class}::DEBUG_TARGET" } ), $hash->{ 'debug' } );
1566 218 50       450 if( @_ )
1567             {
1568 218 50       674 if( $_[0] !~ /^\d/ )
1569             {
1570             ## The last parameter is an options parameter which has the level property set
1571 0 0 0     0 if( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) )
    0 0        
1572             {
1573             ## Then let's use this
1574             }
1575             elsif( $this->{ '_message_default_level' } =~ /^\d+$/ &&
1576             $this->{ '_message_default_level' } > 0 )
1577             {
1578 0         0 unshift( @_, $this->{ '_message_default_level' } );
1579             }
1580             else
1581             {
1582 0         0 unshift( @_, 1 );
1583             }
1584             }
1585             ## If the first argument looks line a number, and there is more than 1 argument
1586             ## and it is greater than 1, and greater than our current debug level
1587             ## well, we do not output anything then...
1588 218 50 33     983 if( ( $_[ 0 ] =~ /^\d+$/ || ( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) ) ) &&
      33        
1589             @_ > 1 )
1590             {
1591 218         313 my $message_level;
1592 218 50 0     498 if( $_[ 0 ] =~ /^\d+$/ )
    0          
1593             {
1594 218         348 $message_level = shift( @_ );
1595             }
1596             elsif( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) )
1597             {
1598 0         0 $message_level = $_[-1]->{level};
1599             }
1600 218         328 my $target_re = '';
1601 218 50       266 if( ref( ${ "${class}::DEBUG_TARGET" } ) eq 'ARRAY' )
  218         682  
1602             {
1603 0 0       0 $target_re = scalar( @${ "${class}::DEBUG_TARGET" } ) ? join( '|', @${ "${class}::DEBUG_TARGET" } ) : '';
  0         0  
  0         0  
1604             }
1605 218 50 33     772 if( $this->{debug} >= $message_level ||
      33        
      33        
      33        
      33        
      33        
      33        
1606             $this->{verbose} >= $message_level ||
1607 218         1458 ${ $class . '::DEBUG' } >= $message_level ||
1608             $this->{debug_level} >= $message_level ||
1609             $this->{debug} >= 100 ||
1610 0         0 ( length( $target_re ) && $class =~ /^$target_re$/ && ${ $class . '::GLOBAL_DEBUG' } >= $message_level ) )
1611             {
1612             ## print( STDERR ref( $self ) . "::message_check(): debug is '$hash->{debug}', verbose '$hash->{verbose}', DEBUG '", ${ $class . '::DEBUG' }, "', debug_level = $hash->{debug_level}\n" );
1613 0         0 return( [ @_ ] );
1614             }
1615             else
1616             {
1617 218         448 return( 0 );
1618             }
1619             }
1620             }
1621 0         0 return( 0 );
1622             }
1623              
1624             sub message_frame
1625             {
1626 0     0 0 0 my $self = shift( @_ );
1627 0         0 my $this = $self->_obj2h;
1628 0 0       0 $this->{_message_frame } = {} if( !exists( $this->{_message_frame} ) );
1629 0         0 my $mf = $this->{_message_frame};
1630 0 0       0 if( @_ )
1631             {
1632 0         0 my $args = {};
1633 0 0       0 if( ref( $_[0] ) eq 'HASH' )
    0          
    0          
1634             {
1635 0         0 $args = shift( @_ );
1636 0         0 my @k = keys( %$args );
1637 0         0 @$mf{ @k } = @$args{ @k };
1638             }
1639             elsif( !( @_ % 2 ) )
1640             {
1641 0         0 $args = { @_ };
1642 0         0 my @k = keys( %$args );
1643 0         0 @$mf{ @k } = @$args{ @k };
1644             }
1645             elsif( scalar( @_ ) == 1 )
1646             {
1647 0         0 my $sub = shift( @_ );
1648 0 0       0 $sub = substr( $sub, rindex( $sub, '::' ) + 2 ) if( index( $sub, '::' ) != -1 );
1649 0         0 return( $mf->{ $sub } );
1650             }
1651             else
1652             {
1653 0         0 return( $self->error( "I was expecting a key => value pair such as routine => stack frame (integer)" ) );
1654             }
1655             }
1656 0         0 return( $mf );
1657             }
1658              
1659             sub message_log
1660             {
1661 0     0 1 0 my $self = shift( @_ );
1662 0         0 my $io = $self->message_log_io;
1663             #print( STDERR "Module::Generic::log: \$io now is '$io'\n" );
1664 0 0       0 return( undef() ) if( !$io );
1665             #print( STDERR "Module::Generic::log: \$io is not an open handle\n" ) if( !openhandle( $io ) && $io );
1666 0 0 0     0 return( undef() ) if( !Scalar::Util::openhandle( $io ) && $io );
1667             ## 2019-06-14: I decided to remove this test, because if a log is provided it should print to it
1668             ## 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
1669             ## if it were printed directly on the console
1670             # my $rc = CORE::print( $io @_ ) || return( $self->error( "Unable to print to log file: $!" ) );
1671 0   0     0 my $rc = $io->print( scalar( localtime( time() ) ), " [$$]: ", @_ ) || return( $self->error( "Unable to print to log file: $!" ) );
1672             ## print( STDERR "Module::Generic::log (", ref( $self ), "): successfully printed to debug log file. \$rc is $rc, \$io is '$io' and message is: ", join( '', @_ ), "\n" );
1673 0         0 return( $rc );
1674             }
1675              
1676             sub message_log_io
1677             {
1678             #return( shift->_set_get( 'log_io', @_ ) );
1679 0     0 1 0 my $self = shift( @_ );
1680 0         0 my $class = ref( $self );
1681 0         0 my $this = $self->_obj2h;
1682 0 0 0     0 if( @_ )
    0 0        
1683             {
1684 0         0 my $io = shift( @_ );
1685 0         0 $self->_set_get( 'log_io', $io );
1686             }
1687 0         0 elsif( ${ "${class}::LOG_DEBUG" } &&
1688             !$self->_set_get( 'log_io' ) &&
1689 0         0 ${ "${class}::DEB_LOG" } )
1690             {
1691 0         0 our $DEB_LOG = ${ "${class}::DEB_LOG" };
  0         0  
1692 0 0       0 unless( $DEBUG_LOG_IO )
1693             {
1694 0   0     0 $DEBUG_LOG_IO = IO::File->new( ">>$DEB_LOG" ) || die( "Unable to open debug log file $DEB_LOG in append mode: $!\n" );
1695 0         0 $DEBUG_LOG_IO->binmode( ':utf8' );
1696 0         0 $DEBUG_LOG_IO->autoflush( 1 );
1697             }
1698 0         0 $self->_set_get( 'log_io', $DEBUG_LOG_IO );
1699             }
1700 0         0 return( $self->_set_get( 'log_io' ) );
1701             }
1702              
1703             sub message_switch
1704             {
1705 0     0 1 0 my $self = shift( @_ );
1706 0   0     0 my $pkg = ref( $self ) || $self;
1707 0         0 my $this = $self->_obj2h;
1708 0 0       0 if( @_ )
1709             {
1710 0         0 my $flag = shift( @_ );
1711 0 0 0     0 if( $flag )
    0          
1712             {
1713 0 0       0 if( defined( &{ "$pkg\::message_off" } ) )
  0         0  
1714             {
1715             ## Restore previous backup
1716 0         0 *{ "${pkg}::message" } = \&{ "${pkg}::message_off" };
  0         0  
  0         0  
1717             }
1718             else
1719             {
1720 0         0 *{ "${pkg}::message" } = \&{ "Module::Generic::message" };
  0         0  
  0         0  
1721             }
1722             }
1723             ## We switch it down if nobody is going to use it
1724             elsif( !$flag && !$this->{verbose} && !$this->{debug} )
1725             {
1726 0 0       0 *{ "${pkg}::message_off" } = \&{ "${pkg}::message" } unless( defined( &{ "${pkg}::message_off" } ) );
  0         0  
  0         0  
  0         0  
1727 0     0   0 *{ "${pkg}::message" } = sub { 1 };
  0         0  
  0         0  
1728             }
1729             }
1730 0         0 return( 1 );
1731             }
1732              
1733 0     0 1 0 sub noexec { $_[0]->{_msg_no_exec_sub} = 1; return( $_[0] ); }
  0         0  
1734              
1735             ## Purpose is to get an error object thrown from another package, and make it ours and pass it along
1736             sub pass_error
1737             {
1738 0     0 1 0 my $self = shift( @_ );
1739 0         0 my $this = $self->_obj2h;
1740 0         0 my $err = shift( @_ );
1741 0 0 0     0 return if( !ref( $err ) || !Scalar::Util::blessed( $err ) );
1742 0         0 $this->{error} = ${ $class . '::ERROR' } = $err;
  0         0  
1743 0 0       0 if( want( 'OBJECT' ) )
1744             {
1745 0         0 my $null = Module::Generic::Null->new( $err, { debug => $this->{debug}, has_error => 1 });
1746 0         0 rreturn( $null );
1747             }
1748 0         0 return;
1749             }
1750              
1751 0     0 1 0 sub quiet { return( shift->_set_get( 'quiet', @_ ) ); }
1752              
1753             sub save
1754             {
1755 0     0 1 0 my $self = shift( @_ );
1756 0         0 my $this = $self->_obj2h;
1757 0         0 my $opts = {};
1758 0 0       0 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
1759 0         0 my( $file, $data );
1760 0 0       0 if( @_ == 2 )
1761             {
1762 0         0 $opts->{data} = shift( @_ );
1763 0         0 $opts->{file} = shift( @_ );
1764             }
1765 0 0       0 return( $self->error( "No file was provided to save data to." ) ) if( !$opts->{file} );
1766 0   0     0 my $fh = IO::File->new( ">$opts->{file}" ) || return( $self->error( "Unable to open file \"$opts->{file}\" in write mode: $!" ) );
1767 0 0       0 $fh->binmode( ':' . $opts->{encoding} ) if( $opts->{encoding} );
1768 0         0 $fh->autoflush( 1 );
1769 0 0       0 if( !defined( $fh->print( ref( $opts->{data} ) eq 'SCALAR' ? ${$opts->{data}} : $opts->{data} ) ) )
  0 0       0  
1770             {
1771 0         0 return( $self->error( "Unable to write data to file \"$opts->{file}\": $!" ) )
1772             }
1773 0         0 $fh->close;
1774 0         0 my $bytes = -s( $opts->{file} );
1775 0         0 return( $bytes );
1776             }
1777              
1778             sub set
1779             {
1780 0     0 1 0 my $self = shift( @_ );
1781 0         0 my %arg = ();
1782 0 0       0 if( @_ )
1783             {
1784 0         0 %arg = ( @_ );
1785 0         0 my $this = $self->_obj2h;
1786 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
1787 0         0 my @keys = keys( %arg );
1788 0         0 @$data{ @keys } = @arg{ @keys };
1789             }
1790 0         0 return( scalar( keys( %arg ) ) );
1791             }
1792              
1793             sub subclasses
1794             {
1795 0     0 1 0 my $self = shift( @_ );
1796 0         0 my $that = '';
1797 0 0       0 $that = @_ ? shift( @_ ) : $self;
1798 0   0     0 my $base = ref( $that ) || $that;
1799 0         0 $base =~ s,::,/,g;
1800 0         0 $base .= '.pm';
1801            
1802 0         0 require IO::Dir;
1803             ## remove '.pm'
1804 0         0 my $dir = substr( $INC{ $base }, 0, ( length( $INC{ $base } ) ) - 3 );
1805            
1806 0         0 my @packages = ();
1807 0         0 my $io = IO::Dir->open( $dir );
1808 0 0       0 if( defined( $io ) )
1809             {
1810 0 0       0 @packages = map{ substr( $_, 0, length( $_ ) - 3 ) } grep{ substr( $_, -3 ) eq '.pm' && -f( "$dir/$_" ) } $io->read();
  0         0  
  0         0  
1811 0 0       0 $io->close ||
1812             warn( "Unable to close directory \"$dir\": $!\n" );
1813             }
1814             else
1815             {
1816 0         0 warn( "Unable to open directory \"$dir\": $!\n" );
1817             }
1818 0 0       0 return( wantarray() ? @packages : \@packages );
1819             }
1820              
1821 97     97 1 172 sub true { ${"Module::Generic::Boolean::true"} }
  97         1798  
1822              
1823 4     4 1 19 sub false { ${"Module::Generic::Boolean::false"} }
  4         60  
1824              
1825             sub verbose
1826             {
1827 0     0 1 0 my $self = shift( @_ );
1828 0         0 my $this = $self->_obj2h;
1829 0 0       0 if( @_ )
1830             {
1831 0         0 my $flag = shift( @_ );
1832 0         0 $this->{verbose} = $flag;
1833 0 0       0 $self->message_switch( $flag ) if( $OPTIMIZE_MESG_SUB );
1834             }
1835 0         0 return( $this->{verbose} );
1836             }
1837              
1838             sub will
1839             {
1840 0 0 0 0 1 0 ( @_ >= 2 && @_ <= 3 ) || die( 'Usage: $obj->can( "method" ) or Module::Generic::will( $obj, "method" )' );
1841 0         0 my( $obj, $meth, $level );
1842             ## $obj->will( $other_obj, 'method' );
1843 0 0 0     0 if( @_ == 3 && ref( $_[ 1 ] ) )
1844             {
1845 0         0 $obj = $_[ 1 ];
1846 0         0 $meth = $_[ 2 ];
1847             }
1848             else
1849             {
1850 0         0 ( $obj, $meth, $level ) = @_;
1851             }
1852 0 0 0     0 return( undef() ) if( !ref( $obj ) && index( $obj, '::' ) == -1 );
1853             ## Give a chance to UNIVERSAL::can
1854 0         0 my $ref = undef;
1855 0 0 0     0 if( Scalar::Util::blessed( $obj ) && ( $ref = $obj->can( $meth ) ) )
1856             {
1857 0         0 return( $ref );
1858             }
1859 0   0     0 my $class = ref( $obj ) || $obj;
1860 0         0 my $origi = $class;
1861 0 0       0 if( index( $meth, '::' ) != -1 )
1862             {
1863 0         0 $origi = substr( $meth, 0, rindex( $meth, '::' ) );
1864 0         0 $meth = substr( $meth, rindex( $meth, '::' ) + 2 );
1865             }
1866 0 0       0 $ref = \&{ "$class\::$meth" } if( defined( &{ "$class\::$meth" } ) );
  0         0  
  0         0  
1867             ## print( $err "\t" x $level, "UNIVERSAL::can ", defined( $ref ) ? "succeeded" : "failed", " in finding the method \"$meth\" in object/class $obj.\n" );
1868             ## print( $err "\t" x $level, defined( $ref ) ? "succeeded" : "failed", " in finding the method \"$meth\" in object/class $obj.\n" );
1869 0 0       0 return( $ref ) if( defined( $ref ) );
1870             ## We do not go further down the rabbit hole if level is greater or equal to 10
1871 0   0     0 $level ||= 0;
1872 0 0       0 return( undef() ) if( $level >= 10 );
1873 0         0 $level++;
1874             ## Let's see what Alice has got for us... :-)
1875             ## We look in the @ISA to see if the method exists in the package from which we
1876             ## possibly inherited
1877 0 0       0 if( @{ "$class\::ISA" } )
  0         0  
1878             {
1879             ## print( STDERR "\t" x $level, "Checking ", scalar( @{ "$class\::ISA" } ), " entries in \"\@${class}\:\:ISA\".\n" );
1880 0         0 foreach my $pack ( @{ "$class\::ISA" } )
  0         0  
1881             {
1882             ## print( STDERR "\t" x $level, "Looking up method \"$meth\" in inherited package \"$pack\".\n" );
1883 0         0 my $ref = &will( $pack, "$origi\::$meth", $level );
1884 0 0       0 return( $ref ) if( defined( $ref ) );
1885             }
1886             }
1887             ## Then, maybe there is an AUTOLOAD to trap undefined routine?
1888             ## But, we do not want any loop, do we?
1889             ## Since will() is called from Module::Generic::AUTOLOAD to check if EXTRA_AUTOLOAD exists
1890             ## we are not going to call Module::Generic::AUTOLOAD for EXTRA_AUTOLOAD...
1891 0 0 0     0 if( $class ne 'Module::Generic' && $meth ne 'EXTRA_AUTOLOAD' && defined( &{ "$class\::AUTOLOAD" } ) )
  0   0     0  
1892             {
1893             ## print( STDERR "\t" x ( $level - 1 ), "Found an AUTOLOAD in class \"$class\". Ok.\n" );
1894             my $sub = sub
1895             {
1896 0     0   0 $class::AUTOLOAD = "$origi\::$meth";
1897 0         0 &{ "$class::AUTOLOAD" }( @_ );
  0         0  
1898 0         0 };
1899 0         0 return( $sub );
1900             }
1901 0         0 return( undef() );
1902             }
1903              
1904             ## Initially those data were stored after the __END__, but it seems some module is interfering with <DATA>
1905             ## and so those data could not be loaded reliably
1906             ## This is called once by colour_to_rgb to generate the hash reference COLOUR_NAME_TO_RGB
1907             sub __colour_data
1908             {
1909 1     1   3 my $colour_data = <<EOT;
1910             {'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']}
1911             EOT
1912             }
1913              
1914             sub __instantiate_object
1915             {
1916 0     0   0 my $self = shift( @_ );
1917 0         0 my $field = shift( @_ );
1918 0         0 my $class = shift( @_ );
1919 0         0 my $this = $self->_obj2h;
1920 0         0 my $o;
1921 0         0 try
1922 0     0   0 {
1923             ## https://stackoverflow.com/questions/32608504/how-to-check-if-perl-module-is-available#comment53081298_32608860
1924             ## require $class unless( defined( *{"${class}::"} ) );
1925 0         0 my $rc = eval{ Class::Load::load_class( $class ); };
  0         0  
1926 0 0       0 return( $self->error( "Unable to load class $class: $@" ) ) if( $@ );
1927             # $self->message( 3, "Called with args: ", sub{ $self->dumper( \@_ ) } );
1928 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
1929 0 0       0 $o = @_ ? $class->new( @_ ) : $class->new;
1930 0 0       0 $o->debug( $this->{debug} ) if( $o->can( 'debug' ) );
1931 0 0       0 return( $self->pass_error( "Unable to instantiate an object of class $class: ", $class->error ) ) if( !defined( $o ) );
1932             }
1933 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  
1934 0     0   0 {
1935 0         0 return( $self->error({ code => 500, message => $e }) );
1936 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
1937 0         0 return( $o );
1938             }
1939              
1940             ## Call to the actual method doing the work
1941             ## The reason for doing so is because _instantiate_object() may be inherited, but
1942             ## _set_get_class or _set_get_hash_as_object created dynamic class which requires to call _instantiate_object
1943             ## If _instantiate_object is inherited, it will yield unpredictable results
1944 0     0   0 sub _instantiate_object { return( shift->__instantiate_object( @_ ) ); }
1945              
1946 0     0   0 sub _is_class_loaded { shift( @_ ); return( Class::Load::is_class_loaded( @_ ) ); }
  0         0  
1947              
1948             ## UNIVERSAL::isa works for both array or array as objects
1949             ## sub _is_array { return( UNIVERSAL::isa( $_[1], 'ARRAY' ) ); }
1950 0     0   0 sub _is_array { return( Scalar::Util::reftype( $_[1] ) eq 'ARRAY' ); }
1951              
1952             ## sub _is_hash { return( UNIVERSAL::isa( $_[1], 'HASH' ) ); }
1953 12     12   48 sub _is_hash { return( Scalar::Util::reftype( $_[1] ) eq 'HASH' ); }
1954              
1955 112293     112293   489193 sub _is_object { return( Scalar::Util::blessed( $_[1] ) ); }
1956              
1957 0     0   0 sub _is_scalar{ return( Scalar::Util::reftype( $_[1] ) eq 'SCALAR' ); }
1958              
1959 0     0   0 sub _load_class { shift( @_ ); return( Class::Load::load_class( @_ ) ); }
  0         0  
1960              
1961             sub _obj2h
1962             {
1963 59991     59991   97828 my $self = shift( @_ );
1964             ## print( STDERR "_obj2h(): Getting a hash refernece out of the object '$self'\n" );
1965 59991 50       156708 if( Scalar::Util::reftype( $self ) eq 'HASH' )
    0          
    0          
1966             {
1967 59991         102832 return( $self );
1968             }
1969             elsif( Scalar::Util::reftype( $self ) eq 'GLOB' )
1970             {
1971             ## print( STDERR "Returning a reference to an hash for glob $self\n" );
1972 0         0 return( \%{*$self} );
  0         0  
1973             }
1974             ## The method that called message was itself called using the package name like My::Package->some_method
1975             ## 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
1976             elsif( !ref( $self ) )
1977             {
1978 0         0 my $class = $self;
1979             my $hash =
1980             {
1981 0         0 'debug' => ${ "${class}\::DEBUG" },
1982 0         0 'verbose' => ${ "${class}\::VERBOSE" },
1983 0         0 'error' => ${ "${class}\::ERROR" },
  0         0  
1984             };
1985             ## XXX
1986             ## print( STDERR "Called with '$self' with debug value '$hash->{debug}' and verbose '$hash->{verbose}'\n" );
1987 0         0 return( bless( $hash => $class ) );
1988             }
1989             ## Because object may be accessed as My::Package->method or My::Package::method
1990             ## there is not always an object available, so we need to fake it to avoid error
1991             ## This is primarly itended for generic methods error(), errstr() to work under any conditions.
1992             else
1993             {
1994 0         0 return( {} );
1995             }
1996             }
1997              
1998             sub _parse_timestamp
1999             {
2000 0     0   0 my $self = shift( @_ );
2001 0         0 my $str = shift( @_ );
2002             ## No value was actually provided
2003 0 0       0 return( undef() ) if( !length( $str ) );
2004 0         0 my $this = $self->_obj2h;
2005 0         0 my $tz = DateTime::TimeZone->new( name => 'local' );
2006 0         0 my $error = 0;
2007             my $opt =
2008             {
2009             pattern => '%Y-%m-%d %T',
2010             locale => 'en_GB',
2011             time_zone => $tz->name,
2012 0     0   0 on_error => sub{ $error++ },
2013 0         0 };
2014             # $self->message( 3, "Checking timestamp string '$str' for appropriate pattern" );
2015             ## 2019-06-19 23:23:57.000000000+0900
2016             ## From PostgreSQL: 2019-06-20 11:02:36.306917+09
2017             ## ISO 8601: 2019-06-20T11:08:27
2018 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          
2019             {
2020 0         0 my( $date, $time, $zone ) = ( "$1-$2-$3", $4, $5 );
2021 0 0       0 if( !length( $zone ) )
2022             {
2023 0         0 my $dt = DateTime->now( time_zone => $tz );
2024 0         0 my $offset = $dt->offset;
2025             ## e.g. 9 or possibly 9.5
2026 0         0 my $offset_hour = ( $offset / 3600 );
2027             ## e.g. 9.5 => 0.5 * 60 = 30
2028 0         0 my $offset_min = ( $offset_hour - CORE::int( $offset_hour ) ) * 60;
2029 0         0 $zone = sprintf( '%+03d%02d', $offset_hour, $offset_min );
2030             }
2031             # $self->message( 3, "\tMatched pattern #1 with date '$date', time '$time' and time zone '$zone'." );
2032 0         0 $date =~ tr/\//-/;
2033 0 0       0 $zone .= '00' if( length( $zone ) == 3 );
2034 0         0 $str = "$date $time$zone";
2035 0         0 $self->message( 3, "\tChanging string to '$str'" );
2036 0         0 $opt->{pattern} = '%Y-%m-%d %T%z';
2037             }
2038             ## From SQLite: 2019-06-20 02:03:14
2039             ## From MySQL: 2019-06-20 11:04:01
2040             elsif( $str =~ /(\d{4})[-|\/](\d{1,2})[-|\/](\d{1,2})(?:[[:blank:]]+|T)(\d{1,2}:\d{1,2}:\d{1,2})/ )
2041             {
2042 0         0 my( $date, $time ) = ( "$1-$2-$3", $4 );
2043             # $self->message( 3, "\tMatched pattern #2 with date '$date', time '$time' and without time zone." );
2044 0         0 my $dt = DateTime->now( time_zone => $tz );
2045 0         0 my $offset = $dt->offset;
2046             ## e.g. 9 or possibly 9.5
2047 0         0 my $offset_hour = ( $offset / 3600 );
2048             ## e.g. 9.5 => 0.5 * 60 = 30
2049 0         0 my $offset_min = ( $offset_hour - CORE::int( $offset_hour ) ) * 60;
2050 0         0 my $offset_str = sprintf( '%+03d%02d', $offset_hour, $offset_min );
2051 0         0 $date =~ tr/\//-/;
2052 0         0 $str = "$date $time$offset_str";
2053 0         0 $self->message( 3, "\tAdding time zone '", $tz->name, "' offset of $offset_str with result: '$str'." );
2054 0         0 $opt->{pattern} = '%Y-%m-%d %T%z';
2055             }
2056             elsif( $str =~ /^(\d{4})[-|\/](\d{1,2})[-|\/](\d{1,2})$/ )
2057             {
2058 0         0 $str = "$1-$2-$3";
2059             # $self->message( 3, "\tMatched pattern #3 with date '$date' only." );
2060 0         0 $opt->{pattern} = '%Y-%m-%d';
2061             }
2062             else
2063             {
2064 0         0 return( '' );
2065             }
2066 0         0 my $strp = DateTime::Format::Strptime->new( %$opt );
2067 0         0 my $dt = $strp->parse_datetime( $str );
2068 0         0 return( $dt );
2069             }
2070              
2071             sub _set_get
2072             {
2073 4     4   9 my $self = shift( @_ );
2074 4         10 my $field = shift( @_ );
2075 4         8 my $this = $self->_obj2h;
2076 4 50       16 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2077 4 50       10 if( @_ )
2078             {
2079 4 50       25 my $val = ( @_ == 1 ) ? shift( @_ ) : [ @_ ];
2080 4         10 $data->{ $field } = $val;
2081             }
2082 4 50       9 if( wantarray() )
2083             {
2084 0 0       0 if( ref( $data->{ $field } ) eq 'ARRAY' )
    0          
2085             {
2086 0         0 return( @{ $data->{ $field } } );
  0         0  
2087             }
2088             elsif( ref( $data->{ $field } ) eq 'HASH' )
2089             {
2090 0         0 return( %{ $data->{ $field } } );
  0         0  
2091             }
2092             else
2093             {
2094 0         0 return( ( $data->{ $field } ) );
2095             }
2096             }
2097             else
2098             {
2099 4         9 return( $data->{ $field } );
2100             }
2101             }
2102              
2103             sub _set_get_array
2104             {
2105 0     0   0 my $self = shift( @_ );
2106 0         0 my $field = shift( @_ );
2107 0         0 my $this = $self->_obj2h;
2108 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2109 0 0       0 if( @_ )
2110             {
2111 0 0 0     0 my $val = ( @_ == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? shift( @_ ) : [ @_ ];
2112 0         0 $data->{ $field } = $val;
2113             }
2114 0         0 return( $data->{ $field } );
2115             }
2116              
2117             sub _set_get_array_as_object
2118             {
2119 0     0   0 my $self = shift( @_ );
2120 0         0 my $field = shift( @_ );
2121 0         0 my $this = $self->_obj2h;
2122 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2123 0 0       0 if( @_ )
2124             {
2125 0 0 0     0 my $val = ( @_ == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? shift( @_ ) : [ @_ ];
2126 0         0 my $o = $data->{ $field };
2127             ## Some existing data, like maybe default value
2128 0 0       0 if( $o )
2129             {
2130 0 0       0 if( !$self->_is_object( $o ) )
2131             {
2132 0         0 my $tmp = $o;
2133 0         0 $o = Module::Generic::Array->new( $tmp );
2134             }
2135 0         0 $o->set( $val );
2136             }
2137             else
2138             {
2139 0         0 $o = Module::Generic::Array->new( $val );
2140 0         0 $data->{ $field } = $o;
2141             }
2142             }
2143 0 0 0     0 if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) )
2144             {
2145 0         0 my $o = Module::Generic::Array->new( $data->{ $field } );
2146 0         0 $data->{ $field } = $o;
2147             }
2148 0         0 return( $data->{ $field } );
2149             }
2150              
2151             sub _set_get_boolean
2152             {
2153 425     425   691 my $self = shift( @_ );
2154 425         681 my $field = shift( @_ );
2155 425         947 my $this = $self->_obj2h;
2156 425 50       1159 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2157 425 50       973 if( @_ )
2158             {
2159 425         709 my $val = shift( @_ );
2160             # $self->message( 3, "Value provided for field '$field' is '$val' of reference (", ref( $val ), ")." );
2161 425 50 0     3034 if( Scalar::Util::blessed( $val ) &&
    50 33        
    50 33        
2162             ( $val->isa( 'JSON::PP::Boolean' ) || $val->isa( 'Module::Generic::Boolean' ) ) )
2163             {
2164 0         0 $data->{ $field } = $val;
2165             }
2166             elsif( Scalar::Util::reftype( $val ) eq 'SCALAR' )
2167             {
2168 0 0       0 $data->{ $field } = $$val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2169             }
2170             elsif( lc( $val ) eq 'true' || lc( $val ) eq 'false' )
2171             {
2172 0 0       0 $data->{ $field } = lc( $val ) eq 'true' ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2173             }
2174             else
2175             {
2176 425 100       2153 $data->{ $field } = $val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2177             }
2178             # $self->message( 3, "Boolean field now has value $self->{$field} (", ref( $self->{ $field } ), ")." );
2179             }
2180             ## If there is a value set, like a default value and it is not an object or at least not one we recognise
2181             ## We transform it into a Module::Generic::Boolean object
2182 425 50 33     1299 if( CORE::length( $data->{ $field } ) &&
      33        
2183             (
2184             !Scalar::Util::blessed( $data->{ $field } ) ||
2185             (
2186             Scalar::Util::blessed( $data->{ $field } ) &&
2187             !$data->{ $field }->isa( 'Module::Generic::Boolean' ) &&
2188             !$data->{ $field }->isa( 'JSON::PP::Boolean' )
2189             )
2190             ) )
2191             {
2192 0         0 my $val = $data->{ $field };
2193 0 0       0 $data->{ $field } = $val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2194             }
2195 425         1138 return( $data->{ $field } );
2196             }
2197              
2198             sub __create_class
2199             {
2200 0     0   0 my $self = shift( @_ );
2201 0   0     0 my $field = shift( @_ ) || return( $self->error( "No field was provided to create a dynamic class." ) );
2202 0         0 my $def = shift( @_ );
2203 0         0 my $class;
2204 0 0       0 if( $def->{_class} )
2205             {
2206 0         0 $class = $def->{_class};
2207             }
2208             else
2209             {
2210 0         0 my $new_class = $field;
2211 0         0 $new_class =~ tr/-/_/;
2212 0         0 $new_class =~ s/\_{2,}/_/g;
2213 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
2214 0         0 $class = ref( $self ) . "\::${new_class}";
2215             }
2216 0 0       0 unless( Class::Load::is_class_loaded( $class ) )
2217             {
2218             # $self->message( 3, "Class '$class' is not created yet, creating it." );
2219 0         0 my $type2func =
2220             {
2221             array => '_set_get_array',
2222             array_as_object => '_set_get_array_as_object',
2223             boolean => '_set_get_boolean',
2224             class => '_set_get_class',
2225             class_array => '_set_get_class_array',
2226             datetime => '_set_get_datetime',
2227             hash => '_set_get_hash',
2228             number => '_set_get_number',
2229             object => '_set_get_object',
2230             object_array => '_set_get_object_array',
2231             object_array_object => '_set_get_object_array_object',
2232             scalar => '_set_get_scalar',
2233             scalar_or_object => '_set_get_scalar_or_object',
2234             uri => '_set_get_uri',
2235             };
2236             ## Alias
2237 0         0 $type2func->{string} = $type2func->{scalar};
2238            
2239 0         0 my $perl = <<EOT;
2240             package $class;
2241             BEGIN
2242             {
2243             use strict;
2244             use Module::Generic;
2245             use parent -norequire, qw( Module::Generic );
2246             };
2247              
2248             EOT
2249 0         0 my $call_sub = ( split( /::/, ( caller(1) )[3] ) )[-1];
2250 0 0       0 my $call_frame = $call_sub eq '_set_get_class' ? 1 : 0;
2251 0         0 my( $pack, $file, $line ) = caller( $call_frame );
2252 0         0 my $code_lines = [];
2253 0         0 foreach my $f ( sort( keys( %$def ) ) )
2254             {
2255             # $self->message( 3, "Checking field '$f'." );
2256 0         0 my $info = $def->{ $f };
2257 0         0 my $type = lc( $info->{type} );
2258 0 0       0 if( !CORE::exists( $type2func->{ $type } ) )
2259             {
2260 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" );
2261 0         0 next;
2262             }
2263 0         0 my $func = $type2func->{ $type };
2264 0 0 0     0 if( $type eq 'object' ||
    0 0        
      0        
2265             $type eq 'scalar_or_object' ||
2266             $type eq 'object_array' )
2267             {
2268 0 0       0 if( !$info->{class} )
2269             {
2270 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" );
2271 0         0 next;
2272             }
2273 0         0 my $this_class = $info->{class};
2274 0         0 CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', '$this_class', \@_ ) ); }" );
2275             }
2276             elsif( $type eq 'class' || $type eq 'class_array' )
2277             {
2278 0         0 my $this_def = $info->{definition};
2279 0 0       0 if( !CORE::exists( $info->{definition} ) )
    0          
2280             {
2281 0         0 warn( "Warning only: No dynamic class fields definition was provided for this field \"$f\". Skipping this field.\n" );
2282 0         0 next;
2283             }
2284             elsif( ref( $this_def ) ne 'HASH' )
2285             {
2286 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" );
2287 0         0 next;
2288             }
2289 0         0 my $d = Data::Dumper->new( [ $this_def ] );
2290 0         0 $d->Indent( 0 );
2291 0         0 $d->Purity( 1 );
2292 0         0 $d->Pad( '' );
2293 0         0 $d->Terse( 1 );
2294 0         0 $d->Sortkeys( 1 );
2295 0         0 my $hash_str = $d->Dump;
2296 0         0 CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', $hash_str, \@_ ) ); }" );
2297             }
2298             else
2299             {
2300 0         0 CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', \@_ ) ); }" );
2301             }
2302             }
2303 0         0 $perl .= join( "\n\n", @$code_lines );
2304              
2305 0         0 $perl .= <<EOT;
2306              
2307              
2308             1;
2309              
2310             EOT
2311             # $self->message( 3, "Evaluating code:\n$perl" );
2312             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" );
2313 0         0 my $rc = eval( $perl );
2314             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" );
2315 0 0       0 die( "Unable to dynamically create module $class: $@" ) if( $@ );
2316             }
2317 0         0 return( $class );
2318             }
2319              
2320             ## $self->_set_get_class( 'my_field', {
2321             ## _class => 'My::Class',
2322             ## field1 => { type => 'datetime' },
2323             ## field2 => { type => 'scalar' },
2324             ## field3 => { type => 'boolean' },
2325             ## field4 => { type => 'object', class => 'Some::Class' },
2326             ## }, @_ );
2327             sub _set_get_class
2328             {
2329 0     0   0 my $self = shift( @_ );
2330             # $self->message( 3, "Got here with arguments: '", join( "', '", @_ ), "'." );
2331 0         0 my $field = shift( @_ );
2332 0         0 my $def = shift( @_ );
2333 0         0 my $this = $self->_obj2h;
2334 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2335 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2336 0 0       0 if( ref( $def ) ne 'HASH' )
2337             {
2338 0         0 CORE::warn( "Warning only: dynamic class field definition hash ($def) for field \"$field\" is not a hash reference.\n" );
2339 0         0 return;
2340             }
2341            
2342 0   0     0 my $class = $self->__create_class( $field, $def ) || die( "Failed to create the dynamic class for field \"$field\".\n" );
2343            
2344 0 0       0 if( @_ )
2345             {
2346 0         0 my $hash = shift( @_ );
2347             # my $o = $class->new( $hash );
2348 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  
2349             ## $self->messagef( 3, "Instantiating object of class '$class' with hash '$hash' containing %d elements: '%s'", scalar( keys( %$hash ) ), $self->dumper( $hash ) );
2350 0         0 my $o = $self->__instantiate_object( $field, $class, $hash );
2351             # $self->message( 3, "\tReturning object for field '$field' and class '$class': '$o'." );
2352 0         0 $data->{ $field } = $o;
2353             }
2354            
2355 0 0       0 if( !$data->{ $field } )
2356             {
2357 0         0 my $o = $self->__instantiate_object( $field, $class );
2358 0         0 $data->{ $field } = $o;
2359             }
2360 0         0 return( $data->{ $field } );
2361             }
2362              
2363             sub _set_get_class_array
2364             {
2365 0     0   0 my $self = shift( @_ );
2366 0         0 my $field = shift( @_ );
2367 0         0 my $def = shift( @_ );
2368 0         0 my $this = $self->_obj2h;
2369 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2370 0 0       0 if( ref( $def ) ne 'HASH' )
2371             {
2372 0         0 CORE::warn( "Warning only: dynamic class field definition hash ($def) for field \"$field\" is not a hash reference.\n" );
2373 0         0 return;
2374             }
2375 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2376 0   0     0 my $class = $self->__create_class( $field, $def ) || die( "Failed to create the dynamic class for field \"$field\".\n" );
2377             ## return( $self->_set_get_object_array( $field, $class, @_ ) );
2378 0 0       0 if( @_ )
2379             {
2380 0         0 my $ref = shift( @_ );
2381 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 ) );
2382 0         0 my $arr = [];
2383 0         0 for( my $i = 0; $i < scalar( @$ref ); $i++ )
2384             {
2385 0 0       0 if( ref( $ref->[$i] ) ne 'HASH' )
2386             {
2387 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." ) );
2388             }
2389 0         0 my $o = $self->__instantiate_object( $field, $class, $ref->[$i] );
2390 0         0 CORE::push( @$arr, $o );
2391             }
2392 0         0 $data->{ $field } = $arr;
2393             }
2394 0         0 return( $data->{ $field } );
2395             }
2396              
2397             sub _set_get_code
2398             {
2399 1     1   4 my $self = shift( @_ );
2400 1         3 my $field = shift( @_ );
2401 1         6 my $this = $self->_obj2h;
2402 1 50       8 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2403 1 50       5 if( @_ )
2404             {
2405 0         0 my $v = shift( @_ );
2406 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' );
2407 0         0 $data->{ $field } = $v;
2408             }
2409 1         4 return( $data->{ $field } );
2410             }
2411              
2412             sub _set_get_datetime
2413             {
2414 0     0   0 my $self = shift( @_ );
2415 0         0 my $field = shift( @_ );
2416 0         0 my $this = $self->_obj2h;
2417 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2418 0 0       0 if( @_ )
2419             {
2420 0         0 my $time = shift( @_ );
2421             # $self->message( 3, "Processing time stamp $time possibly of ref (", ref( $time ), ")." );
2422 0         0 my $now;
2423 0 0 0     0 if( !defined( $time ) )
    0          
    0          
    0          
2424             {
2425 0         0 $data->{ $field } = $time;
2426 0         0 return( $data->{ $field } );
2427             }
2428             elsif( Scalar::Util::blessed( $time ) )
2429             {
2430 0 0       0 return( $self->error( "Object provided as value for $field, but this is not a DateTime object" ) ) if( !$time->isa( 'DateTime' ) );
2431 0         0 $data->{ $field } = $time;
2432 0         0 return( $data->{ $field } );
2433             }
2434             elsif( $time =~ /^\d+$/ && $time !~ /^\d{10}$/ )
2435             {
2436 0         0 return( $self->error( "DateTime value ($time) provided for field $field does not look like a unix timestamp" ) );
2437             }
2438             elsif( $now = $self->_parse_timestamp( $time ) )
2439             {
2440             ## Found a parsed datetime value
2441 0         0 $data->{ $field } = $now;
2442 0         0 return( $now );
2443             }
2444            
2445             # $self->message( 3, "Creating a DateTime object out of $time\n" );
2446             eval
2447 0         0 {
2448 0         0 require DateTime;
2449 0         0 require DateTime::Format::Strptime;
2450 0         0 $now = DateTime->from_epoch(
2451             epoch => $time,
2452             time_zone => 'local',
2453             );
2454 0         0 my $strp = DateTime::Format::Strptime->new(
2455             pattern => '%s',
2456             locale => 'en_GB',
2457             time_zone => 'local',
2458             );
2459 0         0 $now->set_formatter( $strp );
2460             };
2461 0 0       0 if( $@ )
2462             {
2463 0         0 $self->message( "Error while trying to get the DateTime object for field $k with value $time" );
2464             }
2465             else
2466             {
2467             # $self->message( 3, "Returning the DateTime object '$now'" );
2468 0         0 $data->{ $field } = $now;
2469             }
2470             }
2471             ## So that a call to this field will not trigger an error: "Can't call method "xxx" on an undefined value"
2472 0 0 0     0 if( !$data->{ $field } && want( 'OBJECT' ) )
2473             {
2474 0         0 my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 });
2475 0         0 rreturn( $null );
2476             }
2477 0         0 return( $data->{ $field } );
2478             }
2479              
2480             sub _set_get_hash
2481             {
2482 0     0   0 my $self = shift( @_ );
2483 0         0 my $field = shift( @_ );
2484 0         0 my $this = $self->_obj2h;
2485 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2486             # $self->message( 3, "Called for field '$field' with data '", join( "', '", @_ ), "'." );
2487 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2488 0 0       0 if( @_ )
2489             {
2490 0         0 my $val;
2491 0 0       0 if( ref( $_[0] ) eq 'HASH' )
    0          
2492             {
2493 0         0 $val = shift( @_ );
2494             }
2495             elsif( ( @_ % 2 ) )
2496             {
2497 0         0 $val = { @_ };
2498             }
2499             else
2500             {
2501 0         0 my $val = shift( @_ );
2502 0         0 return( $self->error( "Method $field takes only a hash or reference to a hash, but value provided ($val) is not supported" ) );
2503             }
2504             # $self->message( 3, "Setting value $val for field $field" );
2505 0         0 $data->{ $field } = $val;
2506             }
2507 0         0 return( $data->{ $field } );
2508             }
2509              
2510             sub _set_get_hash_as_mix_object
2511             {
2512 128     128   281 my $self = shift( @_ );
2513 128         303 my $field = shift( @_ );
2514 128         302 my $this = $self->_obj2h;
2515 128 50       459 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2516             # $self->message( 3, "Called for field '$field' with data '", join( "', '", @_ ), "'." );
2517 128 50 33     525 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2518 128 50       348 if( @_ )
2519             {
2520 0         0 my $val;
2521 0 0       0 if( ref( $_[0] ) eq 'HASH' )
    0          
2522             {
2523 0         0 $val = shift( @_ );
2524             }
2525             elsif( ( @_ % 2 ) )
2526             {
2527 0         0 $val = { @_ };
2528             }
2529             else
2530             {
2531 0         0 my $val = shift( @_ );
2532 0         0 return( $self->error( "Method $field takes only a hash or reference to a hash, but value provided ($val) is not supported" ) );
2533             }
2534             # $self->message( 3, "Setting value $val for field $field" );
2535 0         0 $data->{ $field } = Module::Generic::Hash->new( $val );
2536             }
2537 128 50 33     615 if( $data->{ $field } && !$self->_is_object( $data->{ $field } ) )
2538             {
2539 128         705 my $o = Module::Generic::Hash->new( $data->{ $field } );
2540 128         407 $data->{ $field } = $o;
2541             }
2542 128         400 return( $data->{ $field } );
2543             }
2544              
2545             sub _set_get_hash_as_object
2546             {
2547 0     0   0 my $self = shift( @_ );
2548 0         0 my $this = $self->_obj2h;
2549             # $self->message( 3, "Called with args: ", $self->dumper( \@_ ) );
2550 0   0     0 my $field = shift( @_ ) || return( $self->error( "No field provided for _set_get_hash_as_object" ) );
2551 0         0 my $class;
2552 0 0 0     0 @_ = () if( @_ == 1 && !defined( $_[0] ) );
2553 0 0       0 if( @_ )
2554             {
2555             ## No class was provided
2556             # if( ref( $_[0] ) eq 'HASH' )
2557 0 0       0 if( Scalar::Util::reftype( $_[0] ) eq 'HASH' )
    0          
2558             {
2559 0         0 my $new_class = $field;
2560 0         0 $new_class =~ tr/-/_/;
2561 0         0 $new_class =~ s/\_{2,}/_/g;
2562 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
2563 0         0 $class = ref( $self ) . "\::${new_class}";
2564             }
2565             elsif( ref( $_[0] ) )
2566             {
2567 0         0 return( $self->error( "Class name in _set_get_hash_as_object helper method cannot be a reference. Received: \"", overload::StrVal( $_[0] ), "\"." ) );
2568             }
2569             else
2570             {
2571 0         0 $class = shift( @_ );
2572             }
2573             }
2574             else
2575             {
2576 0         0 my $new_class = $field;
2577 0         0 $new_class =~ tr/-/_/;
2578 0         0 $new_class =~ s/\_{2,}/_/g;
2579 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
2580 0         0 $class = ref( $self ) . "\::${new_class}";
2581             }
2582             # my $class = shift( @_ );
2583 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2584 0 0       0 unless( Class::Load::is_class_loaded( $class ) )
2585             {
2586 0         0 my $perl = <<EOT;
2587             package $class;
2588             BEGIN
2589             {
2590             use strict;
2591             use warnings::register;
2592             use Module::Generic;
2593             use parent -norequire, qw( Module::Generic::Dynamic );
2594             };
2595              
2596             1;
2597              
2598             EOT
2599             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" );
2600 0         0 my $rc = eval( $perl );
2601             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" );
2602 0 0       0 die( "Unable to dynamically create module \"$class\" for field \"$field\" based on our own class \"", ref( $self ), "\": $@" ) if( $@ );
2603             }
2604            
2605 0 0       0 if( @_ )
2606             {
2607 0         0 my $hash = shift( @_ );
2608             # my $o = $class->new( $hash );
2609             # print( STDERR ref( $self ), "::_set_get_hash_as_object instantiating hash with ref (", ref( $hash ), ") ", overload::StrVal( $hash ), "\n" );
2610 0         0 my $o = $self->__instantiate_object( $field, $class, $hash );
2611 0     0   0 $self->message( 3, "Resulting object contains: ", sub{ $self->dumper( $o ) } );
  0         0  
2612 0         0 $data->{ $field } = $o;
2613             }
2614            
2615 0 0 0     0 if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) )
2616             {
2617 0         0 my $o = $data->{ $field } = $self->__instantiate_object( $field, $class, $data->{ $field } );
2618             }
2619 0         0 return( $data->{ $field } );
2620             }
2621              
2622             sub _set_get_number
2623             {
2624 3     3   11 my $self = shift( @_ );
2625 3         8 my $field = shift( @_ );
2626 3         12 my $this = $self->_obj2h;
2627 3 50       16 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2628 3 50 66     24 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2629 3 100       10 if( @_ )
2630             {
2631 2         18 $data->{ $field } = Module::Generic::Number->new( shift( @_ ) );
2632             }
2633 3         13 return( $data->{ $field } );
2634             }
2635              
2636             sub _set_get_number_or_object
2637             {
2638 0     0   0 my $self = shift( @_ );
2639 0         0 my $field = shift( @_ );
2640 0         0 my $class = shift( @_ );
2641 0         0 my $this = $self->_obj2h;
2642 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2643 0 0       0 if( @_ )
2644             {
2645 0 0 0     0 if( ref( $_[0] ) eq 'HASH' || Scalar::Util::blessed( $_[0] ) )
2646             {
2647 0         0 return( $self->_set_get_object( $field, $class, @_ ) );
2648             }
2649             else
2650             {
2651 0         0 return( $self->_set_get_number( $field, @_ ) );
2652             }
2653             }
2654 0         0 return( $data->{ $field } );
2655             }
2656              
2657             sub _set_get_object
2658             {
2659 3541     3541   5914 my $self = shift( @_ );
2660 3541         5652 my $field = shift( @_ );
2661 3541         5669 my $class = shift( @_ );
2662 3541         8494 my $this = $self->_obj2h;
2663 3541 50       8624 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2664 6     6   60 no overloading;
  6         12  
  6         18609  
2665             # $self->message( 3, "Called for field '$field' and class '$class'." );
2666 3541 100       7668 if( @_ )
2667             {
2668 3540 50       6872 if( scalar( @_ ) == 1 )
2669             {
2670             ## User removed the value by passing it an undefined value
2671 3540 50       12635 if( !defined( $_[0] ) )
    50          
2672             {
2673 0         0 $data->{ $field } = undef();
2674             }
2675             ## User pass an object
2676             elsif( Scalar::Util::blessed( $_[0] ) )
2677             {
2678 3540         5570 my $o = shift( @_ );
2679 3540 50       12415 return( $self->error( "Object provided (", ref( $o ), ") for $field is not a valid $class object" ) ) if( !$o->isa( "$class" ) );
2680             ## XXX Bad idea:
2681             ## $o->debug( $this->{debug} ) if( $o->can( 'debug' ) );
2682 3540         18115 $data->{ $field } = $o;
2683             }
2684             else
2685             {
2686 0   0     0 my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) );
2687             # $self->message( 3, "Setting field $field value to $o" );
2688 0         0 $data->{ $field } = $o;
2689             }
2690             }
2691             else
2692             {
2693 0   0     0 my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) );
2694             # $self->message( 3, "Setting field $field value to $o" );
2695 0         0 $data->{ $field } = $o;
2696             }
2697             }
2698             ## If nothing has been set for this field, ie no object, but we are called in chain
2699             ## we set a dummy object that will just call itself to avoid perl complaining about undefined value calling a method
2700 3541 50 33     10364 if( !$data->{ $field } && want( 'OBJECT' ) )
2701             {
2702             # 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" );
2703             # $self->message( 3, "Called in a chain, but no object is set, reverting to dummy object." );
2704             ## my $null = Module::Generic::Null->new( $o, { debug => $self->{debug}, has_error => 1 });
2705             ## rreturn( $null );
2706 0   0     0 my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) );
2707 0         0 $data->{ $field } = $o;
2708 0         0 return( $o );
2709             }
2710             # $self->message( 3, "Returning for field '$field' value: ", $self->{ $field } );
2711 3541         10532 return( $data->{ $field } );
2712             }
2713              
2714             sub _set_get_object_array2
2715             {
2716 0     0   0 my $self = shift( @_ );
2717 0         0 my $field = shift( @_ );
2718 0         0 my $class = shift( @_ );
2719 0         0 my $this = $self->_obj2h;
2720 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2721 0 0       0 if( @_ )
2722             {
2723 0         0 my $data_to_process = shift( @_ );
2724 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 ) );
2725 0         0 my $arr1 = [];
2726 0         0 foreach my $ref ( @$data_to_process )
2727             {
2728 0 0       0 return( $self->error( "I was expecting an embeded array ref, but instead got '$ref'." ) ) if( ref( $ref ) ne 'ARRAY' );
2729 0         0 my $arr = [];
2730 0         0 for( my $i = 0; $i < scalar( @$ref ); $i++ )
2731             {
2732 0         0 my $o;
2733 0 0       0 if( defined( $ref->[$i] ) )
2734             {
2735 0 0       0 return( $self->error( "Parameter provided for adding object of class $class is not a reference." ) ) if( !ref( $ref->[$i] ) );
2736 0 0       0 if( Scalar::Util::blessed( $ref->[$i] ) )
    0          
2737             {
2738 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 ) );
2739 0         0 $o = $ref->[$i];
2740             }
2741             elsif( ref( $ref->[$i] ) eq 'HASH' )
2742             {
2743             #$o = $class->new( $h, $ref->[$i] );
2744 0         0 $o = $self->_instantiate_object( $field, $class, $ref->[$i] );
2745             }
2746             else
2747             {
2748 0         0 $self->error( "Warning only: data provided to instaantiate object of class $class is not a hash reference" );
2749             }
2750             }
2751             else
2752             {
2753             #$o = $class->new( $h );
2754 0         0 $o = $self->_instantiate_object( $field, $class );
2755             }
2756 0 0       0 return( $self->error( "Unable to instantiate an object of class $class: ", $class->error ) ) if( !defined( $o ) );
2757             # $o->{ '_parent' } = $self->{ '_parent' };
2758 0         0 push( @$arr, $o );
2759             }
2760 0         0 push( @$arr1, $arr );
2761             }
2762 0         0 $data->{ $field } = $arr1;
2763             }
2764 0         0 return( $data->{ $field } );
2765             }
2766              
2767             sub _set_get_object_array
2768             {
2769 0     0   0 my $self = shift( @_ );
2770 0         0 my $field = shift( @_ );
2771 0         0 my $class = shift( @_ );
2772 0         0 my $this = $self->_obj2h;
2773 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2774 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2775 0 0       0 if( @_ )
2776             {
2777 0         0 my $ref = shift( @_ );
2778 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 ) );
2779 0         0 my $arr = [];
2780 0         0 for( my $i = 0; $i < scalar( @$ref ); $i++ )
2781             {
2782 0 0       0 if( defined( $ref->[$i] ) )
2783             {
2784 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] ) );
2785 0 0       0 if( Scalar::Util::blessed( $ref->[$i] ) )
    0          
2786             {
2787 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 ) );
2788 0         0 push( @$arr, $ref->[$i] );
2789             }
2790             elsif( ref( $ref->[$i] ) eq 'HASH' )
2791             {
2792             #$o = $class->new( $h, $ref->[$i] );
2793 0   0     0 $o = $self->_instantiate_object( $field, $class, $ref->[$i] ) || return;
2794 0         0 push( @$arr, $o );
2795             }
2796             else
2797             {
2798 0         0 $self->error( "Warning only: data provided to instantiate object of class $class is not a hash reference" );
2799             }
2800             }
2801             else
2802             {
2803 0         0 return( $self->error( "Array offset $i contains an undefined value. I was expecting an object of class $class." ) );
2804 0   0     0 $o = $self->_instantiate_object( $field, $class ) || return;
2805 0         0 push( @$arr, $o );
2806             }
2807             }
2808 0         0 $data->{ $field } = $arr;
2809             }
2810 0         0 return( $data->{ $field } );
2811             }
2812              
2813             sub _set_get_object_array_object
2814             {
2815 0     0   0 my $self = shift( @_ );
2816 0   0     0 my $field = shift( @_ ) || return( $self->error( "No field name was provided for this array of object." ) );
2817 0   0     0 my $class = shift( @_ ) || return( $self->error( "No class was provided for this array of objects." ) );
2818 0         0 my $this = $self->_obj2h;
2819 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2820 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2821 0 0       0 if( @_ )
2822             {
2823 0 0 0     0 my $that = ( scalar( @_ ) == 1 && UNIVERSAL::isa( $_[0], 'ARRAY' ) ) ? shift( @_ ) : [ @_ ];
2824             ## $self->message( 3, "Received following data to store as array object: ", sub{ $self->dump( $that ) } );
2825 0         0 my $ref = $self->_set_get_object_array( $field, $class, $that );
2826             ## $self->message( 3, "Object array returned is: ", sub{ $self->dump( $ref ) } );
2827 0         0 $data->{ $field } = Module::Generic::Array->new( $ref );
2828             ## $self->message( 3, "Now value for field '$field' is: ", $data->{ $field }, " which contains: '", $data->{ $field }->join( "', '" ), "'." );
2829             }
2830             ## 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"
2831             ## Also, this will make i possible to set default value in caller's object and we would turn it into array object.
2832 0 0 0     0 if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) )
2833             {
2834 0         0 my $o = Module::Generic::Array->new( $data->{ $field } );
2835 0         0 $data->{ $field } = $o;
2836             }
2837 0         0 return( $data->{ $field } );
2838             }
2839              
2840             sub _set_get_object_variant
2841             {
2842 0     0   0 my $self = shift( @_ );
2843 0         0 my $field = shift( @_ );
2844             ## The class precisely depends on what we find looking ahead
2845 0         0 my $class = shift( @_ );
2846 0         0 my $this = $self->_obj2h;
2847 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2848 0 0       0 if( @_ )
2849             {
2850 0 0       0 if( ref( $_[0] ) eq 'HASH' )
    0          
2851             {
2852 0         0 my $o = $self->_instantiate_object( $field, $class, @_ );
2853             }
2854             ## AN array of objects hash
2855             elsif( ref( $_[0] ) eq 'ARRAY' )
2856             {
2857 0         0 my $arr = shift( @_ );
2858 0         0 my $res = [];
2859 0         0 foreach my $data ( @$arr )
2860             {
2861 0   0     0 my $o = $self->_instantiate_object( $field, $class, $data ) || return( $self->error( "Unable to create object: ", $self->error ) );
2862 0         0 push( @$res, $o );
2863             }
2864 0         0 $data->{ $field } = $res;
2865             }
2866             }
2867 0         0 return( $data->{ $field } );
2868             }
2869              
2870             sub _set_get_scalar
2871             {
2872 4     4   8 my $self = shift( @_ );
2873 4         7 my $field = shift( @_ );
2874 4         11 my $this = $self->_obj2h;
2875 4 50       11 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2876 4 50       11 if( @_ )
2877             {
2878 0 0       0 my $val = ( @_ == 1 ) ? shift( @_ ) : join( '', @_ );
2879             ## Just in case, we force stringification
2880             ## $val = "$val" if( defined( $val ) );
2881 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' );
2882 0         0 $data->{ $field } = $val;
2883             }
2884 4         55 return( $data->{ $field } );
2885             }
2886              
2887             sub _set_get_scalar_as_object
2888             {
2889 55082     55082   80809 my $self = shift( @_ );
2890 55082         76411 my $field = shift( @_ );
2891 55082         103120 my $this = $self->_obj2h;
2892 55082 50       110030 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2893 55082 100       101681 if( @_ )
2894             {
2895 3607         5606 my $val;
2896 3607 50 33     15131 if( ref( $val ) eq 'SCALAR' || UNIVERSAL::isa( $val, 'SCALAR' ) )
    50          
2897             {
2898 0         0 $val = $$_[0];
2899             }
2900             elsif( ref( $val ) )
2901             {
2902 0         0 return( $self->error( "I was expecting a string or a scalar reference, but instead got '$val'" ) );
2903             }
2904             else
2905             {
2906 3607         6257 $val = shift( @_ );
2907             }
2908 3607         6319 my $o = $data->{ $field };
2909             # $self->message( 3, "Value to use is '$val' and current object is '", ref( $o ), "'." );
2910 3607 100       7446 if( ref( $o ) )
2911             {
2912 3412         8160 $o->set( $val );
2913             }
2914             else
2915             {
2916 195         623 $data->{ $field } = Module::Generic::Scalar->new( $val );
2917             }
2918             # $self->message( 3, "Object now is: '", ref( $data->{ $field } ), "'." );
2919             }
2920             # $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 }, "'." );
2921 55082 50 33     119237 if( !$self->_is_object( $data->{ $field } ) || ( $self->_is_object( $data->{ $field } ) && ref( $data->{ $field } ) ne ref( $self ) ) )
      66        
2922             {
2923             # $self->message( 3, "No object is set yet, initiating one." );
2924 55082         131656 $data->{ $field } = Module::Generic::Scalar->new( $data->{ $field } );
2925             }
2926 55082         112358 my $v = $data->{ $field };
2927 55082 100       112801 if( !$v->defined )
2928             {
2929 48769 100       111273 if( Want::want( 'OBJECT' ) )
2930             {
2931 1432         86980 return( Module::Generic::Null->new );
2932             }
2933             else
2934             {
2935 47337         2723391 return;
2936             }
2937             }
2938 6313         18758 return( $v );
2939             }
2940              
2941             sub _set_get_scalar_or_object
2942             {
2943 0     0   0 my $self = shift( @_ );
2944 0         0 my $field = shift( @_ );
2945 0         0 my $class = shift( @_ );
2946 0         0 my $this = $self->_obj2h;
2947 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2948 0 0       0 if( @_ )
2949             {
2950 0 0 0     0 if( ref( $_[0] ) eq 'HASH' || Scalar::Util::blessed( $_[0] ) )
2951             {
2952 0         0 return( $self->_set_get_object( $field, $class, @_ ) );
2953             }
2954             else
2955             {
2956 0         0 return( $self->_set_get_scalar( $field, @_ ) );
2957             }
2958             }
2959 0 0 0     0 if( !$data->{ $field } && want( 'OBJECT' ) )
2960             {
2961             # $self->message( 3, "Called in a chain for field $field and class $class, but no object is set, reverting to dummy object." );
2962             # $self->messagef( 3, "Expecting void? '%s'. Want scalar? '%s'. Want hash? '%s', wantref: '%s'", want('VOID'), want('SCALAR'), Want::want('HASH'), Want::wantref() );
2963 0         0 my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 });
2964 0         0 rreturn( $null );
2965             }
2966 0         0 return( $data->{ $field } );
2967             }
2968              
2969             sub _set_get_uri
2970             {
2971 0     0   0 my $self = shift( @_ );
2972 0         0 my $field = shift( @_ );
2973 0         0 my $this = $self->_obj2h;
2974 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2975 0 0       0 if( @_ )
2976             {
2977 0         0 try
2978 0     0   0 {
2979 0 0       0 require URI if( !$self->_is_class_loaded( 'URI' ) );
2980             }
2981 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  
2982 0     0   0 {
2983 0         0 return( $self->error( "Error trying to load module URI: $e" ) );
2984 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
2985            
2986 0         0 my $str = shift( @_ );
2987 0 0 0     0 if( Scalar::Util::blessed( $str ) && $str->isa( 'URI' ) )
    0 0        
    0 0        
    0          
2988             {
2989 0         0 $data->{ $field } = $str;
2990             }
2991             elsif( defined( $str ) && ( $str =~ /^[a-zA-Z]+:\/{2}/ || $str =~ /^urn\:[a-z]+\:/ || $str =~ /^[a-z]+\:/ ) )
2992             {
2993 0         0 $data->{ $field } = URI->new( $str );
2994 0 0       0 warn( "URI subclass is missing to handle this specific URI '$str'\n" ) if( !$data->{ $field }->has_recognized_scheme );
2995             }
2996             ## Is it an absolute path?
2997             elsif( substr( $str, 0, 1 ) eq '/' )
2998             {
2999 0         0 $data->{ $field } = URI->new( $str );
3000             }
3001             elsif( defined( $str ) )
3002             {
3003 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." ) );
3004             }
3005             else
3006             {
3007 0         0 $data->{ $field } = undef();
3008             }
3009             }
3010 0         0 return( $data->{ $field } );
3011             }
3012              
3013 1   33 1   177 sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); }
3014              
3015             sub __dbh
3016             {
3017 0     0   0 my $self = shift( @_ );
3018 0   0     0 my $class = ref( $self ) || $self;
3019 0         0 my $this = $self->_obj2h;
3020 0 0       0 if( !$this->{ '__dbh' } )
3021             {
3022 0 0       0 return( '' ) if( !${ "$class\::DB_DSN" } );
  0         0  
3023 0         0 require DBI;
3024             ## Connecting to database
3025 0         0 my $db_opt = {};
3026 0 0       0 $db_opt->{RaiseError} = ${ "$class\::DB_RAISE_ERROR" } if( length( ${ "$class\::DB_RAISE_ERROR" } ) );
  0         0  
  0         0  
3027 0 0       0 $db_opt->{AutoCommit} = ${ "$class\::DB_AUTO_COMMIT" } if( length( ${ "$class\::DB_AUTO_COMMIT" } ) );
  0         0  
  0         0  
3028 0 0       0 $db_opt->{PrintError} = ${ "$class\::DB_PRINT_ERROR" } if( length( ${ "$class\::DB_PRINT_ERROR" } ) );
  0         0  
  0         0  
3029 0 0       0 $db_opt->{ShowErrorStatement} = ${ "$class\::DB_SHOW_ERROR_STATEMENT" } if( length( ${ "$class\::DB_SHOW_ERROR_STATEMENT" } ) );
  0         0  
  0         0  
3030 0 0       0 $db_opt->{client_encoding} = ${ "$class\::DB_CLIENT_ENCODING" } if( length( ${ "$class\::DB_CLIENT_ENCODING" } ) );
  0         0  
  0         0  
3031             my $dbh = DBI->connect_cached( ${ "$class\::DB_DSN" } ) ||
3032 0   0     0 die( "Unable to connect to sql database with dsn '", ${ "$class\::DB_DSN" }, "'\n" );
3033 0 0       0 $dbh->{pg_server_prepare} = 1 if( ${ "$class\::DB_SERVER_PREPARE" } );
  0         0  
3034 0         0 $this->{ '__dbh' } = $dbh;
3035             }
3036 0         0 return( $this->{ '__dbh' } );
3037             }
3038              
3039             sub DEBUG
3040             {
3041 0     0 1 0 my $self = shift( @_ );
3042 0   0     0 my $pkg = ref( $self ) || $self;
3043 0         0 my $this = $self->_obj2h;
3044 0         0 return( ${ $pkg . '::DEBUG' } );
  0         0  
3045             }
3046              
3047             sub VERBOSE
3048             {
3049 0     0 1 0 my $self = shift( @_ );
3050 0   0     0 my $pkg = ref( $self ) || $self;
3051 0         0 my $this = $self->_obj2h;
3052 0         0 return( ${ $pkg . '::VERBOSE' } );
  0         0  
3053             }
3054              
3055             AUTOLOAD
3056             {
3057 0     0   0 my $self;
3058             # $self = shift( @_ ) if( ref( $_[ 0 ] ) && index( ref( $_[ 0 ] ), 'Module::' ) != -1 );
3059 0 0 0     0 $self = shift( @_ ) if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic' ) );
3060 0         0 my( $class, $meth );
3061 0   0     0 $class = ref( $self ) || $self;
3062             ## Leave this commented out as we need it a little bit lower
3063 0         0 my( $pkg, $file, $line ) = caller();
3064 0         0 my $sub = ( caller( 1 ) )[ 3 ];
3065 6     6   52 no overloading;
  6         17  
  6         2544  
3066 0 0       0 if( $sub eq 'Module::Generic::AUTOLOAD' )
3067             {
3068 0         0 my $mesg = "Module::Generic::AUTOLOAD (called at line '$line') is looping for autoloadable method '$AUTOLOAD' and args '" . join( "', '", @_ ) . "'.";
3069 0 0       0 if( $MOD_PERL )
3070             {
3071 0         0 my $r = Apache2::RequestUtil->request;
3072 0         0 $r->log_error( $mesg );
3073             }
3074             else
3075             {
3076 0         0 print( $err $mesg, "\n" );
3077             }
3078 0         0 exit( 0 );
3079             }
3080 0         0 $meth = $AUTOLOAD;
3081 0 0       0 if( CORE::index( $meth, '::' ) != -1 )
3082             {
3083 0         0 my $idx = rindex( $meth, '::' );
3084 0         0 $class = substr( $meth, 0, $idx );
3085 0         0 $meth = substr( $meth, $idx + 2 );
3086             }
3087            
3088 0 0 0     0 if( $self && $self->can( 'autoload' ) )
3089             {
3090 0 0       0 if( my $code = $self->autoload( $meth ) )
3091             {
3092 0 0       0 return( $code->( $self ) ) if( $code );
3093             }
3094             }
3095            
3096 0         0 $meth = lc( $meth );
3097 0         0 my $this;
3098 0 0       0 $this = $self->_obj2h if( defined( $self ) );
3099 0         0 my $data;
3100 0 0       0 if( $this )
3101             {
3102 0 0       0 $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
3103             }
3104             ## CORE::print( STDERR "Storing '$meth' with value ", join( ', ', @_ ), "\n" );
3105 0 0 0     0 if( $data && CORE::exists( $data->{ $meth } ) )
    0 0        
    0 0        
3106             {
3107 0 0       0 if( @_ )
3108             {
3109 0 0       0 my $val = ( @_ == 1 ) ? shift( @_ ) : [ @_ ];
3110 0         0 $data->{ $meth } = $val;
3111             }
3112 0 0       0 if( wantarray() )
3113             {
3114 0 0       0 if( ref( $data->{ $meth } ) eq 'ARRAY' )
    0          
3115             {
3116 0         0 return( @{ $data->{ $meth } } );
  0         0  
3117             }
3118             elsif( ref( $data->{ $meth } ) eq 'HASH' )
3119             {
3120 0         0 return( %{ $data->{ $meth } } );
  0         0  
3121             }
3122             else
3123             {
3124 0         0 return( ( $data->{ $meth } ) );
3125             }
3126             }
3127             else
3128             {
3129 0         0 return( $data->{ $meth } );
3130             }
3131             }
3132             ## Because, if it does not exist in the caller's package,
3133             ## calling the method will get us here infinitly,
3134             ## since UNIVERSAL::can will somehow return true even if it does not exist
3135 0         0 elsif( $self && $self->can( $meth ) && defined( &{ "$class\::$meth" } ) )
3136             {
3137 0         0 return( $self->$meth( @_ ) );
3138             }
3139             elsif( defined( &$meth ) )
3140             {
3141 6     6   50 no strict 'refs';
  6         22  
  6         5235  
3142 0         0 *$meth = \&$meth;
3143 0         0 return( &$meth( @_ ) );
3144             }
3145             else
3146             {
3147 0         0 my $sub = $AUTOLOAD;
3148 0         0 my( $pkg, $func ) = ( $sub =~ /(.*)::([^:]+)$/ );
3149 0         0 my $mesg = "Module::Generic::AUTOLOAD(): Searching for routine '$func' from package '$pkg'.";
3150 0 0       0 if( $MOD_PERL )
3151             {
3152 0         0 my $r = Apache2::RequestUtil->request;
3153 0         0 $r->log_error( $mesg );
3154             }
3155             else
3156             {
3157 0 0       0 print( STDERR $mesg . "\n" ) if( $DEBUG );
3158             }
3159 0         0 $pkg =~ s/::/\//g;
3160 0 0       0 if( defined( $filename = $INC{ "$pkg.pm" } ) )
3161             {
3162 0         0 $filename =~ s/^(.*)$pkg\.pm\z/$1auto\/$pkg\/$func.al/s;
3163             ## print( STDERR "Found possible autoloadable file '$filename'.\n" );
3164 0 0       0 if( -r( $filename ) )
3165             {
3166 0 0       0 unless( $filename =~ m|^/|s )
3167             {
3168 0         0 $filename = "./$filename";
3169             }
3170             }
3171             else
3172             {
3173 0         0 $filename = undef();
3174             }
3175             }
3176 0 0       0 if( !defined( $filename ) )
3177             {
3178 0         0 $filename = "auto/$sub.al";
3179 0         0 $filename =~ s/::/\//g;
3180             }
3181 0         0 my $save = $@;
3182             eval
3183 0         0 {
3184 0     0   0 local $SIG{ '__DIE__' } = sub{ };
3185 0     0   0 local $SIG{ '__WARN__' } = sub{ };
3186 0         0 require $filename;
3187             };
3188 0 0       0 if( $@ )
3189             {
3190 0 0       0 if( substr( $sub, -9 ) eq '::DESTROY' )
3191             {
3192 0     0   0 *$sub = sub {};
3193             }
3194             else
3195             {
3196             # The load might just have failed because the filename was too
3197             # long for some old SVR3 systems which treat long names as errors.
3198             # If we can succesfully truncate a long name then it's worth a go.
3199             # There is a slight risk that we could pick up the wrong file here
3200             # but autosplit should have warned about that when splitting.
3201 0 0       0 if( $filename =~ s/(\w{12,})\.al$/substr( $1, 0, 11 ) . ".al"/e )
  0         0  
3202             {
3203             eval
3204 0         0 {
3205 0     0   0 local $SIG{ '__DIE__' } = sub{ };
3206 0     0   0 local $SIG{ '__WARN__' } = sub{ };
3207 0         0 require $filename
3208             };
3209             }
3210 0 0       0 if( $@ )
3211             {
3212             #$@ =~ s/ at .*\n//;
3213             #my $error = $@;
3214             #CORE::die( $error );
3215             ## die( "Method $meth() is not defined in class $class and not autoloadable.\n" );
3216             ## print( $err "EXTRA_AUTOLOAD is ", defined( &{ "${class}::EXTRA_AUTOLOAD" } ) ? "defined" : "not defined", " in package '$class'.\n" );
3217             ## if( $self && defined( &{ "${class}::EXTRA_AUTOLOAD" } ) )
3218             ## Look up in our caller's @ISA to see if there is any package that has this special
3219             ## EXTRA_AUTOLOAD() sub routine
3220 0         0 my $sub_ref = '';
3221 0 0       0 die( "EXTRA_AUTOLOAD: ", join( "', '", @_ ), "\n" ) if( $func eq 'EXTRA_AUTOLOAD' );
3222 0 0 0     0 if( $self && $func ne 'EXTRA_AUTOLOAD' && ( $sub_ref = $self->will( 'EXTRA_AUTOLOAD' ) ) )
      0        
3223             {
3224             ## return( &{ "${class}::EXTRA_AUTOLOAD" }( $self, $meth ) );
3225             ## return( $self->EXTRA_AUTOLOAD( $AUTOLOAD, @_ ) );
3226 0         0 return( $sub_ref->( $self, $AUTOLOAD, @_ ) );
3227             }
3228             else
3229             {
3230 0         0 my $keys = CORE::join( ',', keys( %$data ) );
3231 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";
3232 0         0 $msg .= "There are actually the following fields in the object '$self': '$keys'\n";
3233 0         0 die( $msg );
3234             }
3235             }
3236             }
3237             }
3238 0         0 $@ = $save;
3239 0 0       0 if( $DEBUG )
3240             {
3241 0         0 my $mesg = "unshifting '$self' to args for sub '$sub'.";
3242 0 0       0 if( $MOD_PERL )
3243             {
3244 0         0 my $r = Apache2::RequestUtil->request;
3245 0         0 $r->log_error( $mesg );
3246             }
3247             else
3248             {
3249 0         0 print( $err "$mesg\n" );
3250             }
3251             }
3252 0 0       0 unshift( @_, $self ) if( $self );
3253             #use overloading;
3254 0         0 goto &$sub;
3255             ## die( "Method $meth() is not defined in class $class and not autoloadable.\n" );
3256             ## my $mesg = "Method $meth() is not defined in class $class and not autoloadable.";
3257             ## $self->{ 'fatal' } ? die( $mesg ) : return( $self->error( $mesg ) );
3258             }
3259             };
3260              
3261             DESTROY
3262       0     {
3263             ## Do nothing
3264             };
3265              
3266             package Module::Generic::Exception;
3267             BEGIN
3268             {
3269 6     6   63 use strict;
  6         18  
  6         193  
3270 6     6   42 use parent qw( Module::Generic );
  6         13  
  6         36  
3271 6     6   442 use Scalar::Util;
  6         20  
  6         360  
3272 6     6   47 use Devel::StackTrace;
  6         17  
  6         504  
3273             use overload ('""' => 'as_string',
3274 0     0   0 '==' => sub { _obj_eq(@_) },
3275 0     0   0 '!=' => sub { !_obj_eq(@_) },
3276 6         82 fallback => 1,
3277 6     6   42 );
  6         12  
3278 6     6   4169 our( $VERSION ) = '0.1.0';
3279             };
3280              
3281             sub init
3282             {
3283 1     1   4 my $self = shift( @_ );
3284             # require Data::Dumper::Concise;
3285             # print( STDERR __PACKAGE__, "::init() Got here with args: ", Data::Dumper::Concise::Dumper( \@_ ), "\n" );
3286 1         86 $self->{code} = '';
3287 1         5 $self->{type} = '';
3288 1         4 $self->{file} = '';
3289 1         5 $self->{line} = '';
3290 1         4 $self->{message} = '';
3291 1         5 $self->{package} = '';
3292 1         3 $self->{retry_after} = '';
3293 1         5 $self->{subroutine} = '';
3294 1         3 my $args = {};
3295 1 50       19 if( @_ )
3296             {
3297 1 50 33     11 if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic::Exception' ) )
    50          
3298             {
3299 0         0 $args->{object} = shift( @_ );
3300             }
3301             elsif( ref( $_[0] ) eq 'HASH' )
3302             {
3303 1         3 $args = shift( @_ );
3304             }
3305             else
3306             {
3307 0 0       0 $args->{message} = join( '', map( ref( $_ ) eq 'CODE' ? $_->() : $_, @_ ) );
3308             }
3309             }
3310             # $self->SUPER::init( @_ );
3311 1   50     6 my $skip_frame = $args->{skip_frames} || 0;
3312             ## Skip one frame to exclude us
3313 1         3 $skip_frame++;
3314 1         15 my $trace = Devel::StackTrace->new( skip_frames => $skip_frame, indent => 1 );
3315 1         332 my $frame = $trace->next_frame;
3316 1         407 my $frame2 = $trace->next_frame;
3317 1         18 $trace->reset_pointer;
3318 1 50 33     13 if( ref( $args->{object} ) && Scalar::Util::blessed( $args->{object} ) && $args->{object}->isa( 'Module::Generic::Exception' ) )
      33        
3319             {
3320 0         0 my $o = $args->{object};
3321 0         0 $self->{message} = $o->message;
3322 0         0 $self->{code} = $o->code;
3323 0         0 $self->{type} = $o->type;
3324 0         0 $self->{retry_after} = $o->retry_after;
3325             }
3326             else
3327             {
3328             # print( STDERR __PACKAGE__, "::init() Got here with args: ", Data::Dumper::Concise::Dumper( $args ), "\n" );
3329 1   50     5 $self->{message} = $args->{message} || '';
3330 1 50       4 $self->{code} = $args->{code} if( exists( $args->{code} ) );
3331 1 50       4 $self->{type} = $args->{type} if( exists( $args->{type} ) );
3332 1 50       4 $self->{retry_after} = $args->{retry_after} if( exists( $args->{retry_after} ) );
3333             ## 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.
3334 1         3 my $copy = {};
3335 1         4 %$copy = %$args;
3336 1         6 CORE::delete( @$copy{ qw( message code type retry_after skip_frames ) } );
3337             # print( STDERR __PACKAGE__, "::init() Following non-standard keys to set up: '", join( "', '", sort( keys( %$copy ) ) ), "'\n" );
3338             ## Do we have some non-standard parameters?
3339 1         6 foreach my $p ( keys( %$copy ) )
3340             {
3341 0         0 my $p2 = $p;
3342 0         0 $p2 =~ tr/-/_/;
3343 0         0 $p2 =~ s/[^a-zA-Z0-9\_]+//g;
3344 0         0 $p2 =~ s/^\d+//g;
3345 0         0 $self->$p2( $copy->{ $p } );
3346             }
3347             }
3348 1         6 $self->{file} = $frame->filename;
3349 1         10 $self->{line} = $frame->line;
3350             ## 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
3351 1         14 $self->{subroutine} = $frame2->subroutine;
3352 1         12 $self->{package} = $frame->package;
3353 1         8 $self->{trace} = $trace;
3354 1         4 return( $self );
3355             }
3356              
3357             #sub as_string { return( $_[0]->{message} ); }
3358             ## This is important as stringification is called by die, so as per the manual page, we need to end with new line
3359             ## And will add the stack trace
3360             sub as_string
3361             {
3362 6     6   60 no overloading;
  6         14  
  6         2722  
3363 1     1   4 my $self = shift( @_ );
3364 1         5 my $str = $self->message;
3365 1         5 $str =~ s/\r?\n$//g;
3366 1         6 $str .= sprintf( " within package %s at line %d in file %s\n%s", $self->package, $self->line, $self->file, $self->trace->as_string );
3367 1         341 return( $str );
3368             }
3369              
3370             ## if( Module::Generic::Exception->caught( $e ) ) { # do something, it's ours }
3371             sub caught
3372             {
3373 0     0   0 my( $class, $e ) = @_;
3374 0 0       0 return if( ref( $class ) );
3375 0 0 0     0 return unless( Scalar::Util::blessed( $e ) && $e->isa( $class ) );
3376 0         0 return( $e );
3377             }
3378              
3379 0     0   0 sub code { return( shift->_set_get_scalar( 'code', @_ ) ); }
3380              
3381 1     1   13 sub file { return( shift->_set_get_scalar( 'file', @_ ) ); }
3382              
3383 1     1   11 sub line { return( shift->_set_get_scalar( 'line', @_ ) ); }
3384              
3385 1     1   10 sub message { return( shift->_set_get_scalar( 'message', @_ ) ); }
3386              
3387 1     1   19 sub package { return( shift->_set_get_scalar( 'package', @_ ) ); }
3388              
3389             sub rethrow
3390             {
3391 0     0   0 my $self = shift( @_ );
3392 0 0       0 return if( !Scalar::Util::blessed( $self ) );
3393 0         0 die( $self );
3394             }
3395              
3396 0     0   0 sub retry_after { return( shift->_set_get_scalar( 'retry_after', @_ ) ); }
3397              
3398 0     0   0 sub subroutine { return( shift->_set_get_scalar( 'subroutine', @_ ) ); }
3399              
3400             sub throw
3401             {
3402 0     0   0 my $self = shift( @_ );
3403 0         0 my $msg = shift( @_ );
3404 0         0 my $e = $self->new({
3405             skip_frames => 1,
3406             message => $msg,
3407             });
3408 0         0 die( $e );
3409             }
3410              
3411             ## 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
3412 1     1   8 sub trace { return( shift->_set_get_object( 'trace', 'Devel::StackTrace', @_ ) ); }
3413              
3414 0     0   0 sub type { return( shift->_set_get_scalar( 'type', @_ ) ); }
3415              
3416             sub _obj_eq
3417             {
3418             ##return overload::StrVal( $_[0] ) eq overload::StrVal( $_[1] );
3419 6     6   54 no overloading;
  6         12  
  6         1137  
3420 0     0   0 my $self = shift( @_ );
3421 0         0 my $other = shift( @_ );
3422 0         0 my $me;
3423 0 0 0     0 if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Exception' ) )
    0          
3424             {
3425 0 0 0     0 if( $self->message eq $other->message &&
      0        
3426             $self->file eq $other->file &&
3427             $self->line == $other->line )
3428             {
3429 0         0 return( 1 );
3430             }
3431             else
3432             {
3433 0         0 return( 0 );
3434             }
3435             }
3436             ## Compare error message
3437             elsif( !ref( $other ) )
3438             {
3439 0         0 my $me = $self->message;
3440 0         0 return( $me eq $other );
3441             }
3442             ## Otherwise some reference data to which we cannot compare
3443 0         0 return( 0 ) ;
3444             }
3445              
3446             AUTOLOAD
3447             {
3448 0     0   0 my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
3449             # my( $class, $method ) = our $AUTOLOAD =~ /^(.*?)::([^\:]+)$/;
3450 6     6   44 no overloading;
  6         15  
  6         867  
3451 0         0 my $self = shift( @_ );
3452 0   0     0 my $class = ref( $self ) || $self;
3453 0         0 my $code;
3454             # print( STDERR __PACKAGE__, "::$method(): Called with value '$_[0]'\n" );
3455 0 0       0 if( $code = $self->can( $method ) )
3456             {
3457 0         0 return( $code->( @_ ) );
3458             }
3459             ## elsif( CORE::exists( $self->{ $method } ) )
3460             else
3461             {
3462 0         0 eval( "sub ${class}::${method} { return( shift->_set_get_scalar( '$method', \@_ ) ); }" );
3463 0 0       0 die( $@ ) if( $@ );
3464 0         0 return( $self->$method( @_ ) );
3465             }
3466             };
3467              
3468             ## Purpose of this package is to provide an object that will be invoked in chain without breaking and then return undef at the end
3469             ## 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.
3470             ## 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
3471             ## And also by user "particle" in this perl monks discussion here: https://www.perlmonks.org/?node_id=265214
3472             package Module::Generic::Null;
3473             BEGIN
3474             {
3475 6     6   49 use strict;
  6         12  
  6         146  
3476 6     6   30 use Want;
  6         13  
  6         815  
3477 0     0   0 use overload ('""' => sub{ '' },
3478 0     0   0 'eq' => sub { _obj_eq(@_) },
3479 0     0   0 'ne' => sub { !_obj_eq(@_) },
3480 6         72 fallback => 1,
3481 6     6   41 );
  6         15  
3482 6     6   617 use Want;
  6         14  
  6         321  
3483 6     6   612 our( $VERSION ) = '0.2.0';
3484             };
3485              
3486             sub new
3487             {
3488 1432     1432   2578 my $this = shift( @_ );
3489 1432   33     4553 my $class = ref( $this ) || $this;
3490 1432         2126 my $error_object = shift( @_ );
3491 1432 50 33     4103 my $hash = ( @_ == 1 && ref( $_[0] ) ? shift( @_ ) : { @_ } );
3492 1432         3119 $hash->{has_error} = $error_object;
3493 1432         8604 return( bless( $hash => $class ) );
3494             }
3495              
3496             sub _obj_eq
3497             {
3498             ##return overload::StrVal( $_[0] ) eq overload::StrVal( $_[1] );
3499 6     6   39 no overloading;
  6         16  
  6         1237  
3500 0     0   0 my $self = shift( @_ );
3501 0         0 my $other = shift( @_ );
3502 0         0 my $me;
3503 0 0 0     0 if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Null' ) )
    0          
3504             {
3505 0         0 return( $self eq $other );
3506             }
3507             ## Compare error message
3508             elsif( !ref( $other ) )
3509             {
3510 0         0 return( '' eq $other );
3511             }
3512             ## Otherwise some reference data to which we cannot compare
3513 0         0 return( 0 ) ;
3514             }
3515              
3516             AUTOLOAD
3517             {
3518 1432     1432   9585 my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
3519             # my $debug = $_[0]->{debug};
3520             # my( $pack, $file, $file ) = caller;
3521             # my $sub = ( caller( 1 ) )[3];
3522             # print( STDERR __PACKAGE__, ": Method $method called in package $pack in file $file at line $line from subroutine $sub (AUTOLOAD = $AUTOLOAD)\n" ) if( $debug );
3523             ## If we are chained, return our null object, so the chain continues to work
3524 1432 50       3667 if( want( 'OBJECT' ) )
3525             {
3526             ## No, this is NOT a typo. rreturn() is a function of module Want
3527 0         0 rreturn( $_[0] );
3528             }
3529             ## Otherwise, we return undef; Empty return returns undef in scalar context and empty list in list context
3530 1432         66570 return;
3531             };
3532              
3533       0     DESTROY {};
3534              
3535             package Module::Generic::Dynamic;
3536             BEGIN
3537             {
3538 6     6   45 use strict;
  6         18  
  6         183  
3539 6     6   33 use parent qw( Module::Generic );
  6         14  
  6         29  
3540 6     6   378 use warnings::register;
  6         11  
  6         802  
3541 6     6   35 use Scalar::Util ();
  6         12  
  6         163  
3542             # use Class::ISA;
3543 6     6   5475 our( $VERSION ) = '0.1.0';
3544             };
3545              
3546             sub new
3547             {
3548 0     0   0 my $this = shift( @_ );
3549 0   0     0 my $class = ref( $this ) || $this;
3550 0         0 my $self = bless( {} => $class );
3551 0         0 my $data = $self->{_data} = {};
3552             ## A Module::Generic object standard parameter
3553 0         0 $self->{_data_repo} = '_data';
3554 0         0 my $hash = {};
3555 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
3556 0 0 0     0 if( scalar( @_ ) == 1 && Scalar::Util::reftype( $_[0] ) eq 'HASH' )
    0          
3557             {
3558 0         0 $hash = shift( @_ );
3559             }
3560             elsif( @_ )
3561             {
3562 0 0       0 CORE::warn( "Parameter provided is not an hash reference: '", join( "', '", @_ ), "'\n" ) if( $this->_warnings_is_enabled );
3563             }
3564             ## $self->message( 3, "Data provided are: ", sub{ $self->dumper( $hash ) } );
3565             ## print( STDERR __PACKAGE__, "::new(): Got for hash: '", join( "', '", sort( keys( %$hash ) ) ), "'\n" );
3566             local $make_class = sub
3567             {
3568 0     0   0 my $k = shift( @_ );
3569 0         0 my $new_class = $k;
3570 0         0 $new_class =~ tr/-/_/;
3571 0         0 $new_class =~ s/\_{2,}/_/g;
3572 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
3573 0         0 $new_class = "${class}\::${new_class}";
3574             ## Sanitise the key which will serve as a method name
3575 0         0 my $clean_field = $k;
3576 0         0 $clean_field =~ tr/-/_/;
3577 0         0 $clean_field =~ s/\_{2,}/_/g;
3578 0         0 $clean_field =~ s/[^a-zA-Z0-9\_]+//g;
3579 0         0 $clean_field =~ s/^\d+//g;
3580             ## print( STDERR __PACKAGE__, "::new(): \$clean_field now is '$clean_field'\n" );
3581 0         0 my $perl = <<EOT;
3582             package $new_class;
3583             BEGIN
3584             {
3585             use strict;
3586             use Module::Generic;
3587             use parent -norequire, qw( Module::Generic::Dynamic );
3588             };
3589              
3590             1;
3591              
3592             EOT
3593             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" );
3594 0         0 my $rc = eval( $perl );
3595             # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" );
3596 0 0       0 die( "Unable to dynamically create module $new_class: $@" ) if( $@ );
3597 0         0 return( $new_class, $clean_field );
3598 0         0 };
3599            
3600 0         0 foreach my $k ( sort( keys( %$hash ) ) )
3601             {
3602 0 0       0 if( ref( $hash->{ $k } ) eq 'HASH' )
    0          
    0          
3603             {
3604 0         0 my $clean_field = $k;
3605 0         0 $clean_field =~ tr/-/_/;
3606 0         0 $clean_field =~ s/\_{2,}/_/g;
3607 0         0 $clean_field =~ s/[^a-zA-Z0-9\_]+//g;
3608 0         0 $clean_field =~ s/^\d+//g;
3609             # my( $new_class, $clean_field ) = $make_class->( $k );
3610             # print( STDERR __PACKAGE__, "::new(): Is hash looping? ", ( $hash->{ $k }->{_looping} ? 'yes' : 'no' ), " (", ref( $hash->{ $k }->{_looping} ), ")\n" );
3611             # my $o = $hash->{ $k }->{_looping} ? $hash->{ $k }->{_looping} : $new_class->new( $hash->{ $k } );
3612             # $data->{ $clean_field } = $o;
3613             # $hash->{ $k }->{_looping} = $o;
3614 0         0 eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_object( $clean_field, '$new_class', \@_ ) ); }" );
3615 0 0       0 die( $@ ) if( $@ );
3616 0         0 $self->$clean_field( $hash->{ $k } );
3617             }
3618             elsif( ref( $hash->{ $k } ) eq 'ARRAY' )
3619             {
3620 0         0 my( $new_class, $clean_field ) = $make_class->( $k );
3621             # print( STDERR __PACKAGE__, "::new() found an array for key $k, creating objects for class $new_class\n" );
3622             ## We take a peek at what we have to determine how we will handle the data
3623 0 0       0 my $mode = lc( scalar( @{$hash->{ $k }} ) ? ref( $hash->{ $k }->[0] ) : '' );
  0         0  
3624 0 0       0 if( $mode eq 'hash' )
3625             {
3626 0         0 my $all = [];
3627 0         0 foreach my $this ( @{$hash->{ $k }} )
  0         0  
3628             {
3629 0 0       0 my $o = $this->{_looping} ? $this->{_looping} : $new_class->new( $this );
3630 0         0 $this->{_looping} = $o;
3631 0         0 CORE::push( @$all, $o );
3632             }
3633             # $data->{ $clean_field } = $all;
3634 0         0 eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_object_array_object( '$clean_field', '$new_class', \@_ ) ); }" );
3635             }
3636             else
3637             {
3638             # $data->{ $clean_field } = $hash->{ $k };
3639 0         0 eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_array_as_object( '$clean_field', \@_ ) ); }" );
3640             }
3641 0 0       0 die( $@ ) if( $@ );
3642 0         0 $self->$clean_field( $hash->{ $k } );
3643             }
3644             elsif( !ref( $hash->{ $k } ) )
3645             {
3646 0         0 my $clean_field = $k;
3647 0         0 $clean_field =~ tr/-/_/;
3648 0         0 $clean_field =~ s/\_{2,}/_/g;
3649 0         0 $clean_field =~ s/[^a-zA-Z0-9\_]+//g;
3650 0         0 $clean_field =~ s/^\d+//g;
3651 0         0 eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_scalar_as_object( '$clean_field', \@_ ) ); }" );
3652 0         0 $self->$clean_field( $hash->{ $k } );
3653             }
3654             else
3655             {
3656 0         0 $self->$k( $hash->{ $k } );
3657             }
3658             }
3659 0         0 return( $self );
3660             }
3661              
3662             AUTOLOAD
3663             {
3664 0     0   0 my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
3665             # my( $class, $method ) = our $AUTOLOAD =~ /^(.*?)::([^\:]+)$/;
3666 6     6   53 no overloading;
  6         13  
  6         1364  
3667 0         0 my $self = shift( @_ );
3668 0   0     0 my $class = ref( $self ) || $self;
3669 0         0 my $code;
3670             # print( STDERR __PACKAGE__, "::$method(): Called\n" );
3671 0 0       0 if( $code = $self->can( $method ) )
3672             {
3673 0         0 return( $code->( @_ ) );
3674             }
3675             ## elsif( CORE::exists( $self->{ $method } ) )
3676             else
3677             {
3678 0         0 my $ref = lc( ref( $_[0] ) );
3679 0         0 my $handler = '_set_get_scalar_as_object';
3680             # if( @_ && ( $ref eq 'hash' || $ref eq 'array' ) )
3681 0 0 0     0 if( $ref eq 'hash' || $ref eq 'array' )
    0 0        
      0        
      0        
      0        
3682             {
3683             # print( STDERR __PACKAGE__, "::$method(): using handler $handler for type $ref\n" );
3684 0         0 $handler = "_set_get_${ref}_as_object";
3685             }
3686             elsif( $ref eq 'json::pp::boolean' ||
3687             $ref eq 'module::generic::boolean' ||
3688             ( $ref eq 'scalar' && ( $$ref == 1 || $$ref == 0 ) ) )
3689             {
3690 0         0 $handler = '_set_get_boolean';
3691             }
3692 0         0 eval( "sub ${class}::${method} { return( shift->$handler( '$method', \@_ ) ); }" );
3693 0 0       0 die( $@ ) if( $@ );
3694             ## $self->message( 3, "Calling method '$method' with data: ", sub{ $self->printer( @_ ) } );
3695 0         0 return( $self->$method( @_ ) );
3696             }
3697             };
3698              
3699             package Module::Generic::Boolean;
3700             BEGIN
3701             {
3702 6     6   3581 use common::sense;
  6         94  
  6         31  
3703             use overload
3704 3703     3703   15383 "0+" => sub { ${$_[0]} },
  3703         13841  
3705 0     0   0 "++" => sub { $_[0] = ${$_[0]} + 1 },
  0         0  
3706 0     0   0 "--" => sub { $_[0] = ${$_[0]} - 1 },
  0         0  
3707 6     6   1168 fallback => 1;
  6         18  
  6         65  
3708             # *Module::Generic::Boolean:: = *JSON::PP::Boolean::;
3709 6     6   2270 our( $VERSION ) = '0.1.0';
3710             };
3711              
3712 7 100   7   45 sub new { return( $_[1] ? $true : $false ); }
3713              
3714 0     0   0 sub defined { return( 1 ); }
3715              
3716             our $true = do{ bless( \( my $dummy = 1 ) => Module::Generic::Boolean ) };
3717             our $false = do{ bless( \( my $dummy = 0 ) => Module::Generic::Boolean ) };
3718              
3719 279     279   649 sub true () { $true }
3720 146     146   419 sub false () { $false }
3721              
3722 0     0   0 sub is_bool ($) { UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) }
3723 0 0   0   0 sub is_true ($) { $_[0] && UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) }
3724 0 0   0   0 sub is_false ($) { !$_[0] && UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) }
3725              
3726             sub TO_JSON
3727             {
3728             ## JSON does not check that the value is a proper true or false. It stupidly assumes this is a string
3729             ## The only way to make it understand is to return a scalar ref of 1 or 0
3730             # return( $_[0] ? 'true' : 'false' );
3731 0 0   0   0 return( $_[0] ? \1 : \0 );
3732             }
3733              
3734             package Module::Generic::Array;
3735             BEGIN
3736             {
3737 6     6   42 use common::sense;
  6         18  
  6         35  
3738 6     6   290 use warnings;
  6         14  
  6         187  
3739 6     6   35 use warnings::register;
  6         12  
  6         563  
3740 6     6   35 use Scalar::Util ();
  6         14  
  6         112  
3741 6     6   26 use Want;
  6         11  
  6         1053  
3742             ## use Data::Dumper;
3743             use overload ('""' => 'as_string',
3744 0     0   0 '==' => sub { _obj_eq(@_) },
3745 0     0   0 '!=' => sub { !_obj_eq(@_) },
3746 2     2   677 'eq' => sub { _obj_eq(@_) },
3747 1     1   10 'ne' => sub { !_obj_eq(@_) },
3748 6         63 '%{}' => 'as_hash',
3749             fallback => 1,
3750 6     6   38 );
  6         15  
3751 6     6   11545 our( $VERSION ) = '0.1.0';
3752             };
3753              
3754             sub new
3755             {
3756 35     35   101 my $this = CORE::shift( @_ );
3757 35         78 my $init = [];
3758 35 50 33     380 $init = CORE::shift( @_ ) if( @_ && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) );
      66        
3759 35   66     249 return( bless( $init => ( ref( $this ) || $this ) ) );
3760             }
3761              
3762             sub as_hash
3763             {
3764 2     2   528 my $self = CORE::shift( @_ );
3765             ## print( STDERR ref( $self ), "::as_hash\n" );
3766 2         6 my $ref = {};
3767 2         7 my( @offsets ) = $self->keys;
3768 2         26 @$ref{ @$self } = @offsets;
3769             ## print( ref( $self ), "::as_hash -> dump: ", Data::Dumper::Dumper( $ref ), "\n" );
3770 2         10 return( Module::Generic::Hash->new( $ref ) );
3771             }
3772              
3773             sub as_string
3774             {
3775 26     26   73 my $self = CORE::shift( @_ );
3776 26         45 my $sort = 0;
3777 26 100       115 $sort = CORE::shift( @_ ) if( @_ );
3778 26 100       77 return( $self->sort->as_string ) if( $sort );
3779 20         158 return( "@$self" );
3780             }
3781              
3782 5     5   19 sub clone { return( $_[0]->new( [ @{$_[0]} ] ) ); }
  5         37  
3783              
3784             sub delete
3785             {
3786 4     4   13 my $self = CORE::shift( @_ );
3787 4         10 my( $offset, $length ) = @_;
3788 4 50       12 if( defined( $offset ) )
3789             {
3790 4 100       27 if( $offset !~ /^\-?\d+$/ )
3791             {
3792 1 50       7 warn( "Non integer offset \"$offset\" provided to delete array element\n" ) if( $self->_warnings_is_enabled );
3793 1         6 return( $self );
3794             }
3795 3 50 66     23 if( CORE::defined( $length ) && $length !~ /^\-?\d+$/ )
3796             {
3797 0 0       0 warn( $self, "Non integer length \"$length\" provided to delete array element\n" ) if( $self->_warnings_is_enabled );
3798 0         0 return( $self );
3799             }
3800 3 100       18 my @removed = CORE::splice( @$self, $offset, CORE::defined( $length ) ? CORE::int( $length ) : 1 );
3801 3 50       11 if( Want::want( 'LIST' ) )
3802             {
3803 0         0 rreturn( @removed );
3804             }
3805             else
3806             {
3807 3         194 rreturn( $self->new( \@removed ) );
3808             }
3809             # Required to make the compiler happy, as per Want documentation
3810 0         0 return;
3811             }
3812 0         0 return( $self );
3813             }
3814              
3815             sub each
3816             {
3817 1     1   4 my $self = CORE::shift( @_ );
3818             my $code = CORE::shift( @_ ) || do
3819 1   33     6 {
3820             warn( "No subroutine callback as provided for each\n" ) if( $self->_warnings_is_enabled );
3821             return;
3822             };
3823 1 50       6 if( ref( $code ) ne 'CODE' )
3824             {
3825 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 );
3826 0         0 return;
3827             }
3828             ## Index starts from 0
3829 1         7 while( my( $i, $v ) = CORE::each( @$self ) )
3830             {
3831 10 100       74 $code->( $i, $v ) || CORE::last;
3832             }
3833 1         696 return( $self );
3834             }
3835              
3836             sub exists
3837             {
3838 4     4   13 my $self = CORE::shift( @_ );
3839 4         14 my $this = CORE::shift( @_ );
3840 4         201 return( $self->_number( CORE::scalar( CORE::grep( /^$this$/, @$self ) ) ) );
3841             }
3842              
3843             sub for
3844             {
3845 1     1   967 my $self = CORE::shift( @_ );
3846 1         3 my $code = CORE::shift( @_ );
3847 1 50       8 return if( ref( $code ) ne 'CODE' );
3848 1         6 CORE::for( my $i = 0; $i < scalar( @$self ); $i++ )
3849             {
3850 15 100       84 $code->( $i, $self->[ $i ] ) || CORE::last;
3851             }
3852 1         799 return( $self );
3853             }
3854              
3855             sub foreach
3856             {
3857 1     1   42 my $self = CORE::shift( @_ );
3858 1         2 my $code = CORE::shift( @_ );
3859 1 50       6 return if( ref( $code ) ne 'CODE' );
3860 1         4 CORE::foreach my $v ( @$self )
3861             {
3862 18 50       83 $code->( $v ) || CORE::last;
3863             }
3864 1         6 return( $self );
3865             }
3866              
3867             sub grep
3868             {
3869 3     3   452 my $self = CORE::shift( @_ );
3870 3         7 my $expr = CORE::shift( @_ );
3871 3         7 my $ref;
3872 3 100       14 if( ref( $expr ) eq 'CODE' )
3873             {
3874 1         7 $ref = [CORE::grep( $expr->( $_ ), @$self )];
3875             }
3876             else
3877             {
3878 2 100       32 $expr = ref( $expr ) eq 'Regexp'
3879             ? $expr
3880             : qr/\Q$expr\E/;
3881 2         44 $ref = [ CORE::grep( $_ =~ /$expr/, @$self ) ];
3882             }
3883 3 50       56 if( Want::want( 'LIST' ) )
3884             {
3885 0         0 return( @$ref );
3886             }
3887             else
3888             {
3889 3         256 return( $self->new( $ref ) );
3890             }
3891             }
3892              
3893             sub join
3894             {
3895 3     3   940 my $self = CORE::shift( @_ );
3896 3         27 return( $self->_scalar( CORE::join( $_[0], @$self ) ) );
3897             }
3898              
3899             sub keys
3900             {
3901 5     5   456 my $self = CORE::shift( @_ );
3902 5         31 return( $self->new( [ CORE::keys( @$self ) ] ) );
3903             }
3904              
3905 14     14   1461 sub length { return( $_[0]->_number( scalar( @{$_[0]} ) ) ); }
  14         114  
3906              
3907             sub map
3908             {
3909 2     2   6 my $self = CORE::shift( @_ );
3910 2         4 my $code = CORE::shift( @_ );
3911 2 50       9 return if( ref( $code ) ne 'CODE' );
3912 2         11 my $ref = [ CORE::map( $code->( $_ ), @$self ) ];
3913 2 100       60 if( Want::want( 'LIST' ) )
3914             {
3915 1         64 return( @$ref );
3916             }
3917             else
3918             {
3919 1         69 return( $self->new( $ref ) );
3920             }
3921             }
3922              
3923             sub pop
3924             {
3925 2     2   701 my $self = CORE::shift( @_ );
3926 2         9 return( CORE::pop( @$self ) );
3927             }
3928              
3929             sub push
3930             {
3931 1     1   3 my $self = CORE::shift( @_ );
3932 1         6 CORE::push( @$self, @_ );
3933 1         7 return( $self );
3934             }
3935              
3936             sub push_arrayref
3937             {
3938 1     1   4 my $self = CORE::shift( @_ );
3939 1         2 my $ref = CORE::shift( @_ );
3940 1 50       7 return( $self->error( "Data provided ($ref) is not an array reference." ) ) if( !UNIVERSAL::isa( $ref, 'ARRAY' ) );
3941 1         7 CORE::push( @$self, @$ref );
3942 1         6 return( $self );
3943             }
3944              
3945             sub reset
3946             {
3947 1     1   3 my $self = CORE::shift( @_ );
3948 1         5 @$self = ();
3949 1         6 return( $self );
3950             }
3951              
3952             sub reverse
3953             {
3954 1     1   3 my $self = CORE::shift( @_ );
3955 1         6 my $ref = [ CORE::reverse( @$self ) ];
3956 1 50       5 if( wantarray() )
3957             {
3958 0         0 return( @$ref );
3959             }
3960             else
3961             {
3962 1         5 return( $self->new( $ref ) );
3963             }
3964             }
3965              
3966             sub set
3967             {
3968 1     1   4 my $self = CORE::shift( @_ );
3969 1 50 33     17 my $ref = ( scalar( @_ ) == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? CORE::shift( @_ ) : [ @_ ];
3970 1         5 @$self = @$ref;
3971 1         4 return( $self );
3972             }
3973              
3974             sub shift
3975             {
3976 1     1   4 my $self = CORE::shift( @_ );
3977 1         6 return( CORE::shift( @$self ) );
3978             }
3979              
3980 1     1   6 sub size { return( $_[0]->_number( $_[0]->length ) ); }
3981              
3982             sub sort
3983             {
3984 8     8   17 my $self = CORE::shift( @_ );
3985 8         14 my $code = CORE::shift( @_ );
3986 8         14 my $ref;
3987 8 100       25 if( ref( $code ) eq 'CODE' )
3988             {
3989             $ref = [sort
3990             {
3991 1         8 $code->( $a, $b );
  53         128  
3992             } @$self];
3993             }
3994             else
3995             {
3996 7         77 $ref = [ CORE::sort( @$self ) ];
3997             }
3998 8 50       31 if( Want::want( 'LIST' ) )
3999             {
4000 0         0 return( @$ref );
4001             }
4002             else
4003             {
4004 8         518 return( $self->new( $ref ) );
4005             }
4006             }
4007              
4008             sub splice
4009             {
4010 2     2   6 my $self = CORE::shift( @_ );
4011 2         9 my( $offset, $length, @list ) = @_;
4012 2 50 66     19 if( defined( $offset ) && $offset !~ /^\-?\d+$/ )
4013             {
4014 0 0       0 warn( "Offset provided for splice \"$offset\" is not an integer.\n" ) if( $self->_warnings_is_enabled );
4015             ## If a list was provided, the user is not looking to get an element removed, but add it, so we return out object
4016 0 0       0 return( $self ) if( scalar( @list ) );
4017 0         0 return;
4018             }
4019 2 50 66     14 if( defined( $length ) && $length !~ /^\-?\d+$/ )
4020             {
4021 0 0       0 warn( "Length provided for splice \"$length\" is not an integer.\n" ) if( $self->_warnings_is_enabled );
4022 0 0       0 return( $self ) if( scalar( @list ) );
4023 0         0 return;
4024             }
4025             ## Adding elements, so we return our object and allow chaining
4026             ## @_ = offset, length, replacement list
4027 2 100       10 if( scalar( @_ ) > 2 )
    50          
4028             {
4029 1         6 CORE::splice( @$self, $offset, $length, @list );
4030 1         5 return( $self );
4031             }
4032             elsif( !scalar( @_ ) )
4033             {
4034 1         3 CORE::splice( @$self );
4035 1         7 return( $self );
4036             }
4037             else
4038             {
4039 0 0 0     0 return( CORE::splice( @$self, $offset, $length ) ) if( CORE::defined( $offset ) && CORE::defined( $length ) );
4040 0 0       0 return( CORE::splice( @$self, $offset ) ) if( CORE::defined( $offset ) );
4041             }
4042             }
4043              
4044             sub undef
4045             {
4046 1     1   3 my $self = CORE::shift( @_ );
4047 1         4 @$self = ();
4048 1         7 return( $self );
4049             }
4050              
4051             sub unshift
4052             {
4053 1     1   4 my $self = CORE::shift( @_ );
4054 1         5 CORE::unshift( @$self, @_ );
4055 1         6 return( $self );
4056             }
4057              
4058             sub values
4059             {
4060 1     1   3 my $self = CORE::shift( @_ );
4061 1         7 my $ref = [ CORE::values( @$self ) ];
4062 1 50       4 if( Want::want( 'LIST' ) )
4063             {
4064 0         0 return( @$ref );
4065             }
4066             else
4067             {
4068 1         77 return( $self->new( $ref ) );
4069             }
4070             }
4071              
4072             sub _number
4073             {
4074 19     19   68 my $self = CORE::shift( @_ );
4075 19         60 my $num = CORE::shift( @_ );
4076 19 50       82 return if( !defined( $num ) );
4077 19 50       80 return( $num ) if( !CORE::length( $num ) );
4078 19         125 return( Module::Generic::Number->new( $num ) );
4079             }
4080              
4081             sub _obj_eq
4082             {
4083 6     6   58 no overloading;
  6         19  
  6         1354  
4084 3     3   9 my $self = CORE::shift( @_ );
4085 3         6 my $other = CORE::shift( @_ );
4086             ## Sorted
4087 3         11 my $strA = $self->as_string(1);
4088 3         19 my $strB;
4089 3 100 66     29 if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Array' ) )
    50          
4090             {
4091 1         6 $strB = $other->as_string(1);
4092             }
4093             ## Compare error message
4094             elsif( Scalar::Util::reftype( $other ) eq 'ARRAY' )
4095             {
4096 2         6 $strB = $self->new( $other )->as_string(1);
4097             }
4098             else
4099             {
4100 0         0 return( 0 );
4101             }
4102             ## print( STDERR ref( $self ), "::_obj_eq: Comparing array A (", CORE::scalar( @$self ), ") with '$strA' to array B (", CORE::scalar( @$other ), ") with '$strB'\n" );
4103 3         34 return( $strA eq $strB ) ;
4104             }
4105              
4106             sub _scalar
4107             {
4108 3     3   11 my $self = CORE::shift( @_ );
4109 3         8 my $str = CORE::shift( @_ );
4110 3 50       12 return if( !defined( $str ) );
4111             ## Whether empty or not, return an object
4112 3         12 return( Module::Generic::Scalar->new( $str ) );
4113             }
4114              
4115 1   33 1   109 sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); }
4116              
4117             package Module::Generic::Scalar;
4118             BEGIN
4119             {
4120 6     6   45 use common::sense;
  6         12  
  6         63  
4121 6     6   310 use warnings;
  6         13  
  6         158  
4122 6     6   31 use warnings::register;
  6         17  
  6         589  
4123             ## So that the user can say $obj->isa( 'Module::Generic::Scalar' ) and it would return true
4124             ## use parent -norequire, qw( Module::Generic::Scalar );
4125 6     6   37 use Scalar::Util ();
  6         12  
  6         110  
4126 6     6   113 use Want;
  6         17  
  6         604  
4127             use overload (
4128             '""' => 'as_string',
4129             '.=' => sub
4130             {
4131 3     3   15 my( $self, $other, $swap ) = @_;
4132 6     6   107 no warnings 'uninitialized';
  6         16  
  6         1160  
4133 3 50       17 if( !CORE::defined( $$self ) )
    50          
4134             {
4135 0         0 return( $other );
4136             }
4137             elsif( !CORE::defined( $other ) )
4138             {
4139 0         0 return( $$self );
4140             }
4141             ## print( STDERR ref( $self ), "::concatenate: Got here with other = '$other', and swap = '$swap'\n" );
4142             ## print( STDERR "Module::Generic::Scalar::overload->.=: Received arguments '", join( "', '", @_ ), "'\n" );
4143 3         6 my $expr;
4144 3 50       22 if( $swap )
4145             {
4146 0         0 $expr = "\$other .= \$$self";
4147 0         0 return( $other );
4148             }
4149             else
4150             {
4151 3         20 $$self .= $other;
4152 3         11 return( $self );
4153             }
4154             },
4155             'x' => sub
4156             {
4157 1     1   16 my( $self, $other, $swap ) = @_;
4158 6     6   41 no warnings 'uninitialized';
  6         13  
  6         935  
4159             ## print( STDERR "Module::Generic::Scalar::overload->x: Received arguments '", join( "', '", @_ ), "'\n" );
4160 1 50       8 my $expr = $swap ? "\"$other" x \"$$self\"" : "\"$$self\" x \"$other\"";
4161 1         79 my $res = eval( $expr );
4162 1 50       11 if( $@ )
4163             {
4164 0         0 CORE::warn( $@ );
4165 0         0 return;
4166             }
4167 1         6 return( $self->new( $res ) );
4168             },
4169             'eq' => sub
4170             {
4171 3199     3199   706663 my( $self, $other, $swap ) = @_;
4172 6     6   37 no warnings 'uninitialized';
  6         11  
  6         699  
4173 3199 100 66     10756 if( Scalar::Util::blessed( $other ) && ref( $other ) eq ref( $self ) )
4174             {
4175 1         14 return( $$self eq $$other );
4176             }
4177             else
4178             {
4179 3198         11152 return( $$self eq "$other" );
4180             }
4181             },
4182 6         77 fallback => 1,
4183 6     6   37 );
  6         12  
4184 6     6   17826 our( $VERSION ) = 'v0.2.2';
4185             };
4186              
4187             ## sub new { return( shift->_new( @_ ) ); }
4188             sub new
4189             {
4190 55335     55335   88005 my $this = shift( @_ );
4191 55335         80655 my $init = '';
4192 55335 100 66     211980 if( ref( $_[0] ) eq 'SCALAR' || UNIVERSAL::isa( $_[0], 'SCALAR' ) )
    50 33        
    50          
    50          
4193             {
4194 53609         75417 $init = ${$_[0]};
  53609         98956  
4195             }
4196             elsif( ref( $_[0] ) eq 'ARRAY' || UNIVERSAL::isa( $_[0], 'ARRAY' ) )
4197             {
4198 0         0 $init = CORE::join( '', @{$_[0]} );
  0         0  
4199             }
4200             elsif( ref( $_[0] ) )
4201             {
4202 0 0       0 warn( "I do not know what to do with \"", $_[0], "\"\n" ) if( $this->_warnings_is_enabled );
4203 0         0 return;
4204             }
4205             elsif( @_ )
4206             {
4207 1726         2851 $init = $_[0];
4208             }
4209             else
4210             {
4211 0         0 $init = undef();
4212             }
4213             ## print( STDERR __PACKAGE__, "::new: got here for value '$init' (defined? ", CORE::defined( $init ) ? 'yes' : 'no', ")\n" );
4214             # CORE::tie( $self, 'Module::Generic::Scalar::Tie', $init );
4215 55335   66     205151 return( bless( \$init => ( ref( $this ) || $this ) ) );
4216             }
4217              
4218 3 100   3   5 sub as_boolean { return( Module::Generic::Boolean->new( ${$_[0]} ? 1 : 0 ) ); }
  3         18  
4219              
4220             ## sub as_string { CORE::defined( ${$_[0]} ) ? return( ${$_[0]} ) : return; }
4221 6720     6720   11782 sub as_string { return( ${$_[0]} ); }
  6720         25198  
4222              
4223             ## Credits: John Gruber, Aristotle Pagaltzis
4224             ## https://gist.github.com/gruber/9f9e8650d68b13ce4d78
4225             sub capitalise
4226             {
4227 1     1   4 my $self = CORE::shift( @_ );
4228 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[.]? );
4229 1         6 my $small_re = CORE::join( '|', @small_words );
4230              
4231 1         6 my $apos = qr/ (?: ['’] [[:lower:]]* )? /x;
4232            
4233 1         2 my $copy = $$self;
4234 1         6 $copy =~ s{\A\s+}{}, s{\s+\z}{};
4235 1 50       5 $copy = CORE::lc( $copy ) if( not /[[:lower:]]/ );
4236 1         269 $copy =~ s{
4237             \b (_*) (?:
4238             ( (?<=[ ][/\\]) [[:alpha:]]+ [-_[:alpha:]/\\]+ | # file path or
4239             [-_[:alpha:]]+ [@.:] [-_[:alpha:]@.:/]+ $apos ) # URL, domain, or email
4240             |
4241             ( (?i: $small_re ) $apos ) # or small word (case-insensitive)
4242             |
4243             ( [[:alpha:]] [[:lower:]'’()\[\]{}]* $apos ) # or word w/o internal caps
4244             |
4245             ( [[:alpha:]] [[:alpha:]'’()\[\]{}]* $apos ) # or some other word
4246             ) (_*) \b
4247             }{
4248 18 50       168 $1 . (
    100          
    50          
4249             defined $2 ? $2 # preserve URL, domain, or email
4250             : defined $3 ? "\L$3" # lowercase small word
4251             : defined $4 ? "\u\L$4" # capitalize word w/o internal caps
4252             : $5 # preserve other kinds of word
4253             ) . $6
4254             }xeg;
4255              
4256              
4257             # Exceptions for small words: capitalize at start and end of title
4258 1         137 $copy =~ s{
4259             ( \A [[:punct:]]* # start of title...
4260             | [:.;?!][ ]+ # or of subsentence...
4261             | [ ]['"“‘(\[][ ]* ) # or of inserted subphrase...
4262             ( $small_re ) \b # ... followed by small word
4263             }{$1\u\L$2}xig;
4264              
4265 1         81 $copy =~ s{
4266             \b ( $small_re ) # small word...
4267             (?= [[:punct:]]* \Z # ... at the end of the title...
4268             | ['"’”)\]] [ ] ) # ... or of an inserted subphrase?
4269             }{\u\L$1}xig;
4270              
4271             # Exceptions for small words in hyphenated compound words
4272             ## e.g. "in-flight" -> In-Flight
4273 1         65 $copy =~ s{
4274             \b
4275             (?<! -) # Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (in-flight)
4276             ( $small_re )
4277             (?= -[[:alpha:]]+) # lookahead for "-someword"
4278             }{\u\L$1}xig;
4279              
4280             ## # e.g. "Stand-in" -> "Stand-In" (Stand is already capped at this point)
4281 1         53 $copy =~ s{
4282             \b
4283             (?<!…) # Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (stand-in)
4284             ( [[:alpha:]]+- ) # $1 = first word and hyphen, should already be properly capped
4285             ( $small_re ) # ... followed by small word
4286             (?! - ) # Negative lookahead for another '-'
4287             }{$1\u$2}xig;
4288              
4289 1         5 return( $self->_new( $copy ) );
4290             }
4291              
4292 1     1   4 sub chomp { return( CORE::chomp( ${$_[0]} ) ); }
  1         6  
4293              
4294 1     1   2 sub chop { return( CORE::chop( ${$_[0]} ) ); }
  1         42  
4295              
4296             sub clone
4297             {
4298 5     5   1015 my $self = shift( @_ );
4299 5 100       27 if( @_ )
4300             {
4301 1         11 return( $self->_new( @_ ) );
4302             }
4303             else
4304             {
4305 4         9 return( $self->_new( ${$self} ) );
  4         25  
4306             }
4307             }
4308              
4309 1     1   3 sub crypt { return( __PACKAGE__->_new( CORE::crypt( ${$_[0]}, $_[1] ) ) ); }
  1         649  
4310              
4311 55317     55317   74058 sub defined { return( CORE::defined( ${$_[0]} ) ); }
  55317         147993  
4312              
4313 1     1   3 sub fc { return( CORE::fc( ${$_[0]} ) eq CORE::fc( $_[1] ) ); }
  1         9  
4314              
4315 2     2   6 sub hex { return( $_[0]->_number( CORE::hex( ${$_[0]} ) ) ); }
  2         12  
4316              
4317             sub index
4318             {
4319 2     2   6 my $self = shift( @_ );
4320 2         7 my( $substr, $pos ) = @_;
4321 2 50       7 return( $self->_number( CORE::index( ${$self}, $substr, $pos ) ) ) if( CORE::defined( $pos ) );
  0         0  
4322 2         5 return( $self->_number( CORE::index( ${$self}, $substr ) ) );
  2         13  
4323             }
4324              
4325 2     2   5 sub is_alpha { return( ${$_[0]} =~ /^[[:alpha:]]+$/ ); }
  2         22  
4326              
4327 1     1   3 sub is_alpha_numeric { return( ${$_[0]} =~ /^[[:alnum:]]+$/ ); }
  1         10  
4328              
4329 1     1   3 sub is_empty { return( CORE::length( ${$_[0]} ) == 0 ); }
  1         6  
4330              
4331 1     1   5 sub is_lower { return( ${$_[0]} =~ /^[[:lower:]]+$/ ); }
  1         10  
4332              
4333 1     1   3 sub is_numeric { return( Scalar::Util::looks_like_number( ${$_[0]} ) ); }
  1         11  
4334              
4335 1     1   4 sub is_upper { return( ${$_[0]} =~ /^[[:upper:]]+$/ ); }
  1         24  
4336              
4337 1     1   3 sub lc { return( __PACKAGE__->_new( CORE::lc( ${$_[0]} ) ) ); }
  1         6  
4338              
4339 1     1   2 sub lcfirst { return( __PACKAGE__->_new( CORE::lcfirst( ${$_[0]} ) ) ); }
  1         9  
4340              
4341 1     1   4 sub left { return( $_[0]->_new( CORE::substr( ${$_[0]}, 0, CORE::int( $_[1] ) ) ) ); }
  1         7  
4342              
4343 2     2   5 sub length { return( $_[0]->_number( CORE::length( ${$_[0]} ) ) ); }
  2         9  
4344              
4345             sub like
4346             {
4347 1     1   4 my $self = shift( @_ );
4348 1         3 my $str = shift( @_ );
4349 1 50       7 $str = CORE::defined( $str )
    50          
4350             ? ref( $str ) eq 'Regexp'
4351             ? $str
4352             : qr/(?:\Q$str\E)+/
4353             : qr/[[:blank:]\r\n]*/;
4354 1         13 return( $$self =~ /$str/ );
4355             }
4356              
4357             sub ltrim
4358             {
4359 1     1   4 my $self = shift( @_ );
4360 1         6 my $str = shift( @_ );
4361 1 0       10 $str = CORE::defined( $str )
    50          
4362             ? ref( $str ) eq 'Regexp'
4363             ? $str
4364             : qr/(?:\Q$str\E)+/
4365             : qr/[[:blank:]\r\n]*/;
4366 1         35 $$self =~ s/^$str//g;
4367 1         7 return( $self );
4368             }
4369              
4370             sub match
4371             {
4372 1     1   5 my( $self, $re ) = @_;
4373 1 50       7 $re = CORE::defined( $re )
    50          
4374             ? ref( $re ) eq 'Regexp'
4375             ? $re
4376             : qr/(?:\Q$re\E)+/
4377             : $re;
4378 1         11 return( $$self =~ /$re/ );
4379             }
4380              
4381 1     1   4 sub ord { return( $_[0]->_number( CORE::ord( ${$_[0]} ) ) ); }
  1         6  
4382              
4383             sub pad
4384             {
4385 2     2   6 my $self = shift( @_ );
4386 2         8 my( $n, $str ) = @_;
4387 2   50     8 $str //= ' ';
4388 2 50       20 if( !CORE::length( $n ) )
    50          
4389             {
4390 0 0       0 warn( "No number provided to pad the string object.\n" ) if( $self->_warnings_is_enabled );
4391             }
4392             elsif( $n !~ /^\-?\d+$/ )
4393             {
4394 0 0       0 warn( "Number provided \"$n\" to pad string is not an integer.\n" ) if( $self->_warnings_is_enabled );
4395             }
4396            
4397 2 100       9 if( $n < 0 )
4398             {
4399 1         7 $$self .= ( "$str" x CORE::abs( $n ) );
4400             }
4401             else
4402             {
4403 1         6 CORE::substr( $$self, 0, 0 ) = ( "$str" x $n );
4404             }
4405 2         10 return( $self );
4406             }
4407              
4408 1     1   4 sub quotemeta { return( __PACKAGE__->_new( CORE::quotemeta( ${$_[0]} ) ) ); }
  1         7  
4409              
4410 0     0   0 sub right { return( $_[0]->_new( CORE::substr( ${$_[0]}, ( CORE::int( $_[1] ) * -1 ) ) ) ); }
  0         0  
4411              
4412             sub replace
4413             {
4414 4     4   1013 my( $self, $re, $replacement ) = @_;
4415 4 100       45 $re = CORE::defined( $re )
    50          
4416             ? ref( $re ) eq 'Regexp'
4417             ? $re
4418             : qr/(?:\Q$re\E)+/
4419             : $re;
4420 4         58 return( $$self =~ s/$re/$replacement/gs );
4421             }
4422              
4423 1     1   3 sub reset { ${$_[0]} = ''; return( $_[0] ); }
  1         4  
  1         5  
4424              
4425 1     1   4 sub reverse { return( __PACKAGE__->_new( CORE::scalar( CORE::reverse( ${$_[0]} ) ) ) ); }
  1         5  
4426              
4427             sub rindex
4428             {
4429 2     2   6 my $self = shift( @_ );
4430 2         5 my( $substr, $pos ) = @_;
4431 2 100       9 return( $self->_number( CORE::rindex( ${$self}, $substr, $pos ) ) ) if( CORE::defined( $pos ) );
  1         9  
4432 1         3 return( $self->_number( CORE::rindex( ${$self}, $substr ) ) );
  1         6  
4433             }
4434              
4435             sub rtrim
4436             {
4437 1     1   3 my $self = shift( @_ );
4438 1         3 my $str = shift( @_ );
4439 1 50       40 $str = CORE::defined( $str )
    50          
4440             ? ref( $str ) eq 'Regexp'
4441             ? $str
4442             : qr/(?:\Q$str\E)+/
4443             : qr/[[:blank:]\r\n]*/;
4444 1         17 $$self =~ s/${str}$//g;
4445 1         10 return( $self );
4446             }
4447              
4448 872     872   3265 sub scalar { return( shift->as_string ); }
4449              
4450             sub set
4451             {
4452 3413     3413   5033 my $self = CORE::shift( @_ );
4453 3413         5309 my $init;
4454 3413 50 33     21956 if( ref( $_[0] ) eq 'SCALAR' || UNIVERSAL::isa( $_[0], 'SCALAR' ) )
    50 33        
    50          
4455             {
4456 0         0 $init = ${$_[0]};
  0         0  
4457             }
4458             elsif( ref( $_[0] ) eq 'ARRAY' || UNIVERSAL::isa( $_[0], 'ARRAY' ) )
4459             {
4460 0         0 $init = CORE::join( '', @{$_[0]} );
  0         0  
4461             }
4462             elsif( ref( $_[0] ) )
4463             {
4464 0 0       0 warn( "I do not know what to do with \"", $_[0], "\"\n" ) if( $self->_warnings_is_enabled );
4465 0         0 return;
4466             }
4467             else
4468             {
4469 3413         6217 $init = shift( @_ );
4470             }
4471 3413         5707 $$self = $init;
4472 3413         5561 return( $self );
4473             }
4474              
4475             sub split
4476             {
4477 2     2   16 my $self = CORE::shift( @_ );
4478 2         8 my( $expr, $limit ) = @_;
4479 2         6 my $ref;
4480 2         4 $limit = "$limit";
4481 2 50 33     15 if( CORE::defined( $limit ) && $limit =~ /^\d+$/ )
4482             {
4483 0         0 $ref = [ CORE::split( $expr, $$self, $limit ) ];
4484             }
4485             else
4486             {
4487 2         83 $ref = [ CORE::split( $expr, $$self ) ];
4488             }
4489 2 50 33     15 if( Want::want( 'OBJECT' ) ||
    0          
4490             Want::want( 'SCALAR' ) )
4491             {
4492 2         302 rreturn( $self->_array( $ref ) );
4493             }
4494             elsif( Want::want( 'LIST' ) )
4495             {
4496 0         0 rreturn( @$ref );
4497             }
4498 0         0 return;
4499             }
4500              
4501 1     1   3 sub sprintf { return( __PACKAGE__->_new( CORE::sprintf( ${$_[0]}, @_[1..$#_] ) ) ); }
  1         12  
4502              
4503             sub substr
4504             {
4505 2     2   7 my $self = CORE::shift( @_ );
4506 2         7 my( $offset, $length, $replacement ) = @_;
4507 2 100 66     18 return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset, $length, $replacement ) ) ) if( CORE::defined( $length ) && CORE::defined( $replacement ) );
  1         9  
4508 1 50       5 return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset, $length ) ) ) if( CORE::defined( $length ) );
  1         6  
4509 0         0 return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset ) ) );
  0         0  
4510             }
4511              
4512             sub trim
4513             {
4514 2     2   6 my $self = shift( @_ );
4515 2         5 my $str = shift( @_ );
4516 2 50       18 $str = CORE::defined( $str ) ? CORE::quotemeta( $str ) : qr/[[:blank:]\r\n]*/;
4517 2         88 $$self =~ s/^$str|$str$//gs;
4518 2         26 return( $self );
4519             }
4520              
4521 2     2   10 sub uc { return( __PACKAGE__->_new( CORE::uc( ${$_[0]} ) ) ); }
  2         12  
4522              
4523 0     0   0 sub ucfirst { return( __PACKAGE__->_new( CORE::ucfirst( ${$_[0]} ) ) ); }
  0         0  
4524              
4525             sub undef
4526             {
4527 1     1   12 my $self = shift( @_ );
4528 1         2 $$self = undef;
4529 1         4 return( $self );
4530             }
4531              
4532             sub _array
4533             {
4534 2     2   6 my $self = shift( @_ );
4535 2         6 my $arr = shift( @_ );
4536 2 50       8 return if( !defined( $arr ) );
4537 2 50       16 return( $arr ) if( Scalar::Util::reftype( $arr ) ne 'ARRAY' );
4538 2         20 return( Module::Generic::Array->new( $arr ) );
4539             }
4540              
4541             sub _number
4542             {
4543 9     9   24 my $self = shift( @_ );
4544 9         20 my $num = shift( @_ );
4545 9 50       31 return if( !defined( $num ) );
4546 9 50       42 return( $num ) if( !CORE::length( $num ) );
4547 9         56 return( Module::Generic::Number->new( $num ) );
4548             }
4549              
4550 17     17   64 sub _new { return( shift->Module::Generic::Scalar::new( @_ ) ); }
4551              
4552 0   0 0   0 sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); }
4553              
4554             package Module::Generic::Number;
4555             BEGIN
4556             {
4557 6     6   57 use strict;
  6         17  
  6         213  
4558 6     6   34 use parent -norequire, qw( Module::Generic );
  6         12  
  6         38  
4559 6     6   292 use warnings::register;
  6         15  
  6         592  
4560 6     6   40 use Number::Format;
  6         26  
  6         288  
4561 6     6   39 use Nice::Try;
  6         26  
  6         50  
4562 6     6   24473714 use Regexp::Common qw( number );
  6         15120  
  6         28  
4563 6     6   17411 use POSIX ();
  6         20  
  6         186  
4564 6     6   4876 our( $VERSION ) = 'v0.3.3';
4565             };
4566              
4567             use overload (
4568             ## I know there is the nomethod feature, but I need to provide return_object set to true or false
4569             ## And I do not necessarily want to catch all the operation.
4570 55     55   18587 '""' => sub { return( shift->{_number} ); },
4571 3     3   43 '-' => sub { return( shift->compute( @_, { op => '-', return_object => 1 }) ); },
4572 5     5   62 '+' => sub { return( shift->compute( @_, { op => '+', return_object => 1 }) ); },
4573 3     3   49 '*' => sub { return( shift->compute( @_, { op => '*', return_object => 1 }) ); },
4574 4     4   91 '/' => sub { return( shift->compute( @_, { op => '/', return_object => 1 }) ); },
4575 2     2   34 '%' => sub { return( shift->compute( @_, { op => '%', return_object => 1 }) ); },
4576             ## Exponent
4577 3     3   43 '**' => sub { return( shift->compute( @_, { op => '**', return_object => 1 }) ); },
4578             ## Bitwise AND
4579 1     1   10 '&' => sub { return( shift->compute( @_, { op => '&', return_object => 1 }) ); },
4580             ## Bitwise OR
4581 1     1   19 '|' => sub { return( shift->compute( @_, { op => '|', return_object => 1 }) ); },
4582             ## Bitwise XOR
4583 1     1   26 '^' => sub { return( shift->compute( @_, { op => '^', return_object => 1 }) ); },
4584             ## Bitwise shift left
4585 1     1   16 '<<' => sub { return( shift->compute( @_, { op => '<<', return_object => 1 }) ); },
4586             ## Bitwise shift right
4587 1     1   21 '>>' => sub { return( shift->compute( @_, { op => '>>', return_object => 1 }) ); },
4588 1     1   19 'x' => sub { return( shift->compute( @_, { op => 'x', return_object => 1, type => 'scalar' }) ); },
4589 2     2   29 '+=' => sub { return( shift->compute( @_, { op => '+=', return_object => 1 }) ); },
4590 1     1   25 '-=' => sub { return( shift->compute( @_, { op => '-=', return_object => 1 }) ); },
4591 2     2   1305 '*=' => sub { return( shift->compute( @_, { op => '*=', return_object => 1 }) ); },
4592 1     1   22 '/=' => sub { return( shift->compute( @_, { op => '/=', return_object => 1 }) ); },
4593 1     1   16 '%=' => sub { return( shift->compute( @_, { op => '%=', return_object => 1 }) ); },
4594 1     1   34 '**=' => sub { return( shift->compute( @_, { op => '**=', return_object => 1 }) ); },
4595 1     1   17 '<<=' => sub { return( shift->compute( @_, { op => '<<=', return_object => 1 }) ); },
4596 1     1   22 '>>=' => sub { return( shift->compute( @_, { op => '>>=', return_object => 1 }) ); },
4597 1     1   18 'x=' => sub { return( shift->compute( @_, { op => 'x=', return_object => 1 }) ); },
4598             ## '.=' => sub { return( shift->compute( @_, { op => '.=', return_object => 1 }) ); },
4599             '.=' => sub
4600             {
4601 2     2   9 my( $self, $other, $swap ) = @_;
4602 2         11 my $op = '.=';
4603 2 50       20 my $operation = $swap ? "${other} ${op} \$self->{_number}" : "\$self->{_number} ${op} ${other}";
4604 2         153 my $res = eval( $operation );
4605 2 50 33     15 warn( "Error with formula \"$operation\": $@" ) if( $@ && $self->_warnings_is_enabled );
4606 2 50       7 return if( $@ );
4607             ## Concatenated something. If it still look like a number, we return it as an object
4608 2 100       23 if( $res =~ /^$RE{num}{real}$/ )
4609             {
4610 1         286 return( $self->clone( $res ) );
4611             }
4612             ## Otherwise we pass it to the scalar module
4613             else
4614             {
4615 1         204 return( Module::Generic::Scalar->new( "$res" ) );
4616             }
4617             },
4618 2     2   22 '<' => sub { return( shift->compute( @_, { op => '<', boolean => 1 }) ); },
4619 2     2   21 '<=' => sub { return( shift->compute( @_, { op => '<=', boolean => 1 }) ); },
4620 1     1   21 '>' => sub { return( shift->compute( @_, { op => '>', boolean => 1 }) ); },
4621 1     1   26 '>=' => sub { return( shift->compute( @_, { op => '>=', boolean => 1 }) ); },
4622 3     3   19 '<=>' => sub { return( shift->compute( @_, { op => '<=>', return_object => 0 }) ); },
4623 6     6   73 '==' => sub { return( shift->compute( @_, { op => '==', boolean => 1 }) ); },
4624 7     7   72 '!=' => sub { return( shift->compute( @_, { op => '!=', boolean => 1 }) ); },
4625 81     81   30321 'eq' => sub { return( shift->compute( @_, { op => 'eq', boolean => 1 }) ); },
4626 1     1   22 'ne' => sub { return( shift->compute( @_, { op => 'ne', boolean => 1 }) ); },
4627             '++' => sub
4628             {
4629 3     3   447 my( $self ) = @_;
4630 3         16 return( ++$self->{_number} );
4631             },
4632             '--' => sub
4633             {
4634 2     2   5 my( $self ) = @_;
4635 2         32 return( --$self->{_number} );
4636             },
4637 6         249 'fallback' => 1,
4638 6     6   53 );
  6         14  
4639              
4640             our $SUPPORTED_LOCALES =
4641             {
4642             aa_DJ => [qw( aa_DJ.UTF-8 aa_DJ.ISO-8859-1 aa_DJ.ISO8859-1 )],
4643             aa_ER => [qw( aa_ER.UTF-8 )],
4644             aa_ET => [qw( aa_ET.UTF-8 )],
4645             af_ZA => [qw( af_ZA.UTF-8 af_ZA.ISO-8859-1 af_ZA.ISO8859-1 )],
4646             ak_GH => [qw( ak_GH.UTF-8 )],
4647             am_ET => [qw( am_ET.UTF-8 )],
4648             an_ES => [qw( an_ES.UTF-8 an_ES.ISO-8859-15 an_ES.ISO8859-15 )],
4649             anp_IN => [qw( anp_IN.UTF-8 )],
4650             ar_AE => [qw( ar_AE.UTF-8 ar_AE.ISO-8859-6 ar_AE.ISO8859-6 )],
4651             ar_BH => [qw( ar_BH.UTF-8 ar_BH.ISO-8859-6 ar_BH.ISO8859-6 )],
4652             ar_DZ => [qw( ar_DZ.UTF-8 ar_DZ.ISO-8859-6 ar_DZ.ISO8859-6 )],
4653             ar_EG => [qw( ar_EG.UTF-8 ar_EG.ISO-8859-6 ar_EG.ISO8859-6 )],
4654             ar_IN => [qw( ar_IN.UTF-8 )],
4655             ar_IQ => [qw( ar_IQ.UTF-8 ar_IQ.ISO-8859-6 ar_IQ.ISO8859-6 )],
4656             ar_JO => [qw( ar_JO.UTF-8 ar_JO.ISO-8859-6 ar_JO.ISO8859-6 )],
4657             ar_KW => [qw( ar_KW.UTF-8 ar_KW.ISO-8859-6 ar_KW.ISO8859-6 )],
4658             ar_LB => [qw( ar_LB.UTF-8 ar_LB.ISO-8859-6 ar_LB.ISO8859-6 )],
4659             ar_LY => [qw( ar_LY.UTF-8 ar_LY.ISO-8859-6 ar_LY.ISO8859-6 )],
4660             ar_MA => [qw( ar_MA.UTF-8 ar_MA.ISO-8859-6 ar_MA.ISO8859-6 )],
4661             ar_OM => [qw( ar_OM.UTF-8 ar_OM.ISO-8859-6 ar_OM.ISO8859-6 )],
4662             ar_QA => [qw( ar_QA.UTF-8 ar_QA.ISO-8859-6 ar_QA.ISO8859-6 )],
4663             ar_SA => [qw( ar_SA.UTF-8 ar_SA.ISO-8859-6 ar_SA.ISO8859-6 )],
4664             ar_SD => [qw( ar_SD.UTF-8 ar_SD.ISO-8859-6 ar_SD.ISO8859-6 )],
4665             ar_SS => [qw( ar_SS.UTF-8 )],
4666             ar_SY => [qw( ar_SY.UTF-8 ar_SY.ISO-8859-6 ar_SY.ISO8859-6 )],
4667             ar_TN => [qw( ar_TN.UTF-8 ar_TN.ISO-8859-6 ar_TN.ISO8859-6 )],
4668             ar_YE => [qw( ar_YE.UTF-8 ar_YE.ISO-8859-6 ar_YE.ISO8859-6 )],
4669             as_IN => [qw( as_IN.UTF-8 )],
4670             ast_ES => [qw( ast_ES.UTF-8 ast_ES.ISO-8859-15 ast_ES.ISO8859-15 )],
4671             ayc_PE => [qw( ayc_PE.UTF-8 )],
4672             az_AZ => [qw( az_AZ.UTF-8 )],
4673             be_BY => [qw( be_BY.UTF-8 be_BY.CP1251 )],
4674             bem_ZM => [qw( bem_ZM.UTF-8 )],
4675             ber_DZ => [qw( ber_DZ.UTF-8 )],
4676             ber_MA => [qw( ber_MA.UTF-8 )],
4677             bg_BG => [qw( bg_BG.UTF-8 bg_BG.CP1251 )],
4678             bhb_IN => [qw( bhb_IN.UTF-8 )],
4679             bho_IN => [qw( bho_IN.UTF-8 )],
4680             bn_BD => [qw( bn_BD.UTF-8 )],
4681             bn_IN => [qw( bn_IN.UTF-8 )],
4682             bo_CN => [qw( bo_CN.UTF-8 )],
4683             bo_IN => [qw( bo_IN.UTF-8 )],
4684             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 )],
4685             brx_IN => [qw( brx_IN.UTF-8 )],
4686             bs_BA => [qw( bs_BA.UTF-8 bs_BA.ISO-8859-2 bs_BA.ISO8859-2 )],
4687             byn_ER => [qw( byn_ER.UTF-8 )],
4688             ca_AD => [qw( ca_AD.UTF-8 ca_AD.ISO-8859-15 ca_AD.ISO8859-15 )],
4689             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 )],
4690             ca_FR => [qw( ca_FR.UTF-8 ca_FR.ISO-8859-15 ca_FR.ISO8859-15 )],
4691             ca_IT => [qw( ca_IT.UTF-8 ca_IT.ISO-8859-15 ca_IT.ISO8859-15 )],
4692             ce_RU => [qw( ce_RU.UTF-8 )],
4693             ckb_IQ => [qw( ckb_IQ.UTF-8 )],
4694             cmn_TW => [qw( cmn_TW.UTF-8 )],
4695             crh_UA => [qw( crh_UA.UTF-8 )],
4696             cs_CZ => [qw( cs_CZ.UTF-8 cs_CZ.ISO-8859-2 cs_CZ.ISO8859-2 )],
4697             csb_PL => [qw( csb_PL.UTF-8 )],
4698             cv_RU => [qw( cv_RU.UTF-8 )],
4699             cy_GB => [qw( cy_GB.UTF-8 cy_GB.ISO-8859-14 cy_GB.ISO8859-14 )],
4700             da_DK => [qw( da_DK.UTF-8 da_DK.ISO-8859-1 da_DK.ISO8859-1 )],
4701             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 )],
4702             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 )],
4703             de_CH => [qw( de_CH.UTF-8 de_CH.ISO-8859-1 de_CH.ISO8859-1 )],
4704             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 )],
4705             de_LI => [qw( de_LI.UTF-8 )],
4706             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 )],
4707             doi_IN => [qw( doi_IN.UTF-8 )],
4708             dv_MV => [qw( dv_MV.UTF-8 )],
4709             dz_BT => [qw( dz_BT.UTF-8 )],
4710             el_CY => [qw( el_CY.UTF-8 el_CY.ISO-8859-7 el_CY.ISO8859-7 )],
4711             el_GR => [qw( el_GR.UTF-8 el_GR.ISO-8859-7 el_GR.ISO8859-7 )],
4712             en_AG => [qw( en_AG.UTF-8 )],
4713             en_AU => [qw( en_AU.UTF-8 en_AU.ISO-8859-1 en_AU.ISO8859-1 )],
4714             en_BW => [qw( en_BW.UTF-8 en_BW.ISO-8859-1 en_BW.ISO8859-1 )],
4715             en_CA => [qw( en_CA.UTF-8 en_CA.ISO-8859-1 en_CA.ISO8859-1 )],
4716             en_DK => [qw( en_DK.UTF-8 en_DK.ISO-8859-15 en_DK.ISO8859-15 )],
4717             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 )],
4718             en_HK => [qw( en_HK.UTF-8 en_HK.ISO-8859-1 en_HK.ISO8859-1 )],
4719             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 )],
4720             en_IN => [qw( en_IN.UTF-8 )],
4721             en_NG => [qw( en_NG.UTF-8 )],
4722             en_NZ => [qw( en_NZ.UTF-8 en_NZ.ISO-8859-1 en_NZ.ISO8859-1 )],
4723             en_PH => [qw( en_PH.UTF-8 en_PH.ISO-8859-1 en_PH.ISO8859-1 )],
4724             en_SG => [qw( en_SG.UTF-8 en_SG.ISO-8859-1 en_SG.ISO8859-1 )],
4725             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 )],
4726             en_ZA => [qw( en_ZA.UTF-8 en_ZA.ISO-8859-1 en_ZA.ISO8859-1 )],
4727             en_ZM => [qw( en_ZM.UTF-8 )],
4728             en_ZW => [qw( en_ZW.UTF-8 en_ZW.ISO-8859-1 en_ZW.ISO8859-1 )],
4729             eo => [qw( eo.UTF-8 eo.ISO-8859-3 eo.ISO8859-3 )],
4730             eo_US => [qw( eo_US.UTF-8 )],
4731             es_AR => [qw( es_AR.UTF-8 es_AR.ISO-8859-1 es_AR.ISO8859-1 )],
4732             es_BO => [qw( es_BO.UTF-8 es_BO.ISO-8859-1 es_BO.ISO8859-1 )],
4733             es_CL => [qw( es_CL.UTF-8 es_CL.ISO-8859-1 es_CL.ISO8859-1 )],
4734             es_CO => [qw( es_CO.UTF-8 es_CO.ISO-8859-1 es_CO.ISO8859-1 )],
4735             es_CR => [qw( es_CR.UTF-8 es_CR.ISO-8859-1 es_CR.ISO8859-1 )],
4736             es_CU => [qw( es_CU.UTF-8 )],
4737             es_DO => [qw( es_DO.UTF-8 es_DO.ISO-8859-1 es_DO.ISO8859-1 )],
4738             es_EC => [qw( es_EC.UTF-8 es_EC.ISO-8859-1 es_EC.ISO8859-1 )],
4739             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 )],
4740             es_GT => [qw( es_GT.UTF-8 es_GT.ISO-8859-1 es_GT.ISO8859-1 )],
4741             es_HN => [qw( es_HN.UTF-8 es_HN.ISO-8859-1 es_HN.ISO8859-1 )],
4742             es_MX => [qw( es_MX.UTF-8 es_MX.ISO-8859-1 es_MX.ISO8859-1 )],
4743             es_NI => [qw( es_NI.UTF-8 es_NI.ISO-8859-1 es_NI.ISO8859-1 )],
4744             es_PA => [qw( es_PA.UTF-8 es_PA.ISO-8859-1 es_PA.ISO8859-1 )],
4745             es_PE => [qw( es_PE.UTF-8 es_PE.ISO-8859-1 es_PE.ISO8859-1 )],
4746             es_PR => [qw( es_PR.UTF-8 es_PR.ISO-8859-1 es_PR.ISO8859-1 )],
4747             es_PY => [qw( es_PY.UTF-8 es_PY.ISO-8859-1 es_PY.ISO8859-1 )],
4748             es_SV => [qw( es_SV.UTF-8 es_SV.ISO-8859-1 es_SV.ISO8859-1 )],
4749             es_US => [qw( es_US.UTF-8 es_US.ISO-8859-1 es_US.ISO8859-1 )],
4750             es_UY => [qw( es_UY.UTF-8 es_UY.ISO-8859-1 es_UY.ISO8859-1 )],
4751             es_VE => [qw( es_VE.UTF-8 es_VE.ISO-8859-1 es_VE.ISO8859-1 )],
4752             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 )],
4753             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 )],
4754             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 )],
4755             fa_IR => [qw( fa_IR.UTF-8 )],
4756             ff_SN => [qw( ff_SN.UTF-8 )],
4757             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 )],
4758             fil_PH => [qw( fil_PH.UTF-8 )],
4759             fo_FO => [qw( fo_FO.UTF-8 fo_FO.ISO-8859-1 fo_FO.ISO8859-1 )],
4760             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 )],
4761             fr_CA => [qw( fr_CA.UTF-8 fr_CA.ISO-8859-1 fr_CA.ISO8859-1 )],
4762             fr_CH => [qw( fr_CH.UTF-8 fr_CH.ISO-8859-1 fr_CH.ISO8859-1 )],
4763             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 )],
4764             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 )],
4765             fur_IT => [qw( fur_IT.UTF-8 )],
4766             fy_DE => [qw( fy_DE.UTF-8 )],
4767             fy_NL => [qw( fy_NL.UTF-8 )],
4768             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 )],
4769             gd_GB => [qw( gd_GB.UTF-8 gd_GB.ISO-8859-15 gd_GB.ISO8859-15 )],
4770             gez_ER => [qw( gez_ER.UTF-8 )],
4771             gez_ET => [qw( gez_ET.UTF-8 )],
4772             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 )],
4773             gu_IN => [qw( gu_IN.UTF-8 )],
4774             gv_GB => [qw( gv_GB.UTF-8 gv_GB.ISO-8859-1 gv_GB.ISO8859-1 )],
4775             ha_NG => [qw( ha_NG.UTF-8 )],
4776             hak_TW => [qw( hak_TW.UTF-8 )],
4777             he_IL => [qw( he_IL.UTF-8 he_IL.ISO-8859-8 he_IL.ISO8859-8 )],
4778             hi_IN => [qw( hi_IN.UTF-8 )],
4779             hne_IN => [qw( hne_IN.UTF-8 )],
4780             hr_HR => [qw( hr_HR.UTF-8 hr_HR.ISO-8859-2 hr_HR.ISO8859-2 )],
4781             hsb_DE => [qw( hsb_DE.UTF-8 hsb_DE.ISO-8859-2 hsb_DE.ISO8859-2 )],
4782             ht_HT => [qw( ht_HT.UTF-8 )],
4783             hu_HU => [qw( hu_HU.UTF-8 hu_HU.ISO-8859-2 hu_HU.ISO8859-2 )],
4784             hy_AM => [qw( hy_AM.UTF-8 hy_AM.ARMSCII-8 hy_AM.ARMSCII8 )],
4785             ia_FR => [qw( ia_FR.UTF-8 )],
4786             id_ID => [qw( id_ID.UTF-8 id_ID.ISO-8859-1 id_ID.ISO8859-1 )],
4787             ig_NG => [qw( ig_NG.UTF-8 )],
4788             ik_CA => [qw( ik_CA.UTF-8 )],
4789             is_IS => [qw( is_IS.UTF-8 is_IS.ISO-8859-1 is_IS.ISO8859-1 )],
4790             it_CH => [qw( it_CH.UTF-8 it_CH.ISO-8859-1 it_CH.ISO8859-1 )],
4791             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 )],
4792             iu_CA => [qw( iu_CA.UTF-8 )],
4793             iw_IL => [qw( iw_IL.UTF-8 iw_IL.ISO-8859-8 iw_IL.ISO8859-8 )],
4794             ja_JP => [qw( ja_JP.UTF-8 ja_JP.EUC-JP ja_JP.EUCJP )],
4795             ka_GE => [qw( ka_GE.UTF-8 ka_GE.GEORGIAN-PS ka_GE.GEORGIANPS )],
4796             kk_KZ => [qw( kk_KZ.UTF-8 kk_KZ.PT154 kk_KZ.RK1048 )],
4797             kl_GL => [qw( kl_GL.UTF-8 kl_GL.ISO-8859-1 kl_GL.ISO8859-1 )],
4798             km_KH => [qw( km_KH.UTF-8 )],
4799             kn_IN => [qw( kn_IN.UTF-8 )],
4800             ko_KR => [qw( ko_KR.UTF-8 ko_KR.EUC-KR ko_KR.EUCKR )],
4801             kok_IN => [qw( kok_IN.UTF-8 )],
4802             ks_IN => [qw( ks_IN.UTF-8 )],
4803             ku_TR => [qw( ku_TR.UTF-8 ku_TR.ISO-8859-9 ku_TR.ISO8859-9 )],
4804             kw_GB => [qw( kw_GB.UTF-8 kw_GB.ISO-8859-1 kw_GB.ISO8859-1 )],
4805             ky_KG => [qw( ky_KG.UTF-8 )],
4806             lb_LU => [qw( lb_LU.UTF-8 )],
4807             lg_UG => [qw( lg_UG.UTF-8 lg_UG.ISO-8859-10 lg_UG.ISO8859-10 )],
4808             li_BE => [qw( li_BE.UTF-8 )],
4809             li_NL => [qw( li_NL.UTF-8 )],
4810             lij_IT => [qw( lij_IT.UTF-8 )],
4811             ln_CD => [qw( ln_CD.UTF-8 )],
4812             lo_LA => [qw( lo_LA.UTF-8 )],
4813             lt_LT => [qw( lt_LT.UTF-8 lt_LT.ISO-8859-13 lt_LT.ISO8859-13 )],
4814             lv_LV => [qw( lv_LV.UTF-8 lv_LV.ISO-8859-13 lv_LV.ISO8859-13 )],
4815             lzh_TW => [qw( lzh_TW.UTF-8 )],
4816             mag_IN => [qw( mag_IN.UTF-8 )],
4817             mai_IN => [qw( mai_IN.UTF-8 )],
4818             mg_MG => [qw( mg_MG.UTF-8 mg_MG.ISO-8859-15 mg_MG.ISO8859-15 )],
4819             mhr_RU => [qw( mhr_RU.UTF-8 )],
4820             mi_NZ => [qw( mi_NZ.UTF-8 mi_NZ.ISO-8859-13 mi_NZ.ISO8859-13 )],
4821             mk_MK => [qw( mk_MK.UTF-8 mk_MK.ISO-8859-5 mk_MK.ISO8859-5 )],
4822             ml_IN => [qw( ml_IN.UTF-8 )],
4823             mn_MN => [qw( mn_MN.UTF-8 )],
4824             mni_IN => [qw( mni_IN.UTF-8 )],
4825             mr_IN => [qw( mr_IN.UTF-8 )],
4826             ms_MY => [qw( ms_MY.UTF-8 ms_MY.ISO-8859-1 ms_MY.ISO8859-1 )],
4827             mt_MT => [qw( mt_MT.UTF-8 mt_MT.ISO-8859-3 mt_MT.ISO8859-3 )],
4828             my_MM => [qw( my_MM.UTF-8 )],
4829             nan_TW => [qw( nan_TW.UTF-8 )],
4830             nb_NO => [qw( nb_NO.UTF-8 nb_NO.ISO-8859-1 nb_NO.ISO8859-1 )],
4831             nds_DE => [qw( nds_DE.UTF-8 )],
4832             nds_NL => [qw( nds_NL.UTF-8 )],
4833             ne_NP => [qw( ne_NP.UTF-8 )],
4834             nhn_MX => [qw( nhn_MX.UTF-8 )],
4835             niu_NU => [qw( niu_NU.UTF-8 )],
4836             niu_NZ => [qw( niu_NZ.UTF-8 )],
4837             nl_AW => [qw( nl_AW.UTF-8 )],
4838             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 )],
4839             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 )],
4840             nn_NO => [qw( nn_NO.UTF-8 nn_NO.ISO-8859-1 nn_NO.ISO8859-1 )],
4841             nr_ZA => [qw( nr_ZA.UTF-8 )],
4842             nso_ZA => [qw( nso_ZA.UTF-8 )],
4843             oc_FR => [qw( oc_FR.UTF-8 oc_FR.ISO-8859-1 oc_FR.ISO8859-1 )],
4844             om_ET => [qw( om_ET.UTF-8 )],
4845             om_KE => [qw( om_KE.UTF-8 om_KE.ISO-8859-1 om_KE.ISO8859-1 )],
4846             or_IN => [qw( or_IN.UTF-8 )],
4847             os_RU => [qw( os_RU.UTF-8 )],
4848             pa_IN => [qw( pa_IN.UTF-8 )],
4849             pa_PK => [qw( pa_PK.UTF-8 )],
4850             pap_AN => [qw( pap_AN.UTF-8 )],
4851             pap_AW => [qw( pap_AW.UTF-8 )],
4852             pap_CW => [qw( pap_CW.UTF-8 )],
4853             pl_PL => [qw( pl_PL.UTF-8 pl_PL.ISO-8859-2 pl_PL.ISO8859-2 )],
4854             ps_AF => [qw( ps_AF.UTF-8 )],
4855             pt_BR => [qw( pt_BR.UTF-8 pt_BR.ISO-8859-1 pt_BR.ISO8859-1 )],
4856             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 )],
4857             quz_PE => [qw( quz_PE.UTF-8 )],
4858             raj_IN => [qw( raj_IN.UTF-8 )],
4859             ro_RO => [qw( ro_RO.UTF-8 ro_RO.ISO-8859-2 ro_RO.ISO8859-2 )],
4860             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 )],
4861             ru_UA => [qw( ru_UA.UTF-8 ru_UA.KOI8-U ru_UA.KOI8U )],
4862             rw_RW => [qw( rw_RW.UTF-8 )],
4863             sa_IN => [qw( sa_IN.UTF-8 )],
4864             sat_IN => [qw( sat_IN.UTF-8 )],
4865             sc_IT => [qw( sc_IT.UTF-8 )],
4866             sd_IN => [qw( sd_IN.UTF-8 )],
4867             sd_PK => [qw( sd_PK.UTF-8 )],
4868             se_NO => [qw( se_NO.UTF-8 )],
4869             shs_CA => [qw( shs_CA.UTF-8 )],
4870             si_LK => [qw( si_LK.UTF-8 )],
4871             sid_ET => [qw( sid_ET.UTF-8 )],
4872             sk_SK => [qw( sk_SK.UTF-8 sk_SK.ISO-8859-2 sk_SK.ISO8859-2 )],
4873             sl_SI => [qw( sl_SI.UTF-8 sl_SI.ISO-8859-2 sl_SI.ISO8859-2 )],
4874             so_DJ => [qw( so_DJ.UTF-8 so_DJ.ISO-8859-1 so_DJ.ISO8859-1 )],
4875             so_ET => [qw( so_ET.UTF-8 )],
4876             so_KE => [qw( so_KE.UTF-8 so_KE.ISO-8859-1 so_KE.ISO8859-1 )],
4877             so_SO => [qw( so_SO.UTF-8 so_SO.ISO-8859-1 so_SO.ISO8859-1 )],
4878             sq_AL => [qw( sq_AL.UTF-8 sq_AL.ISO-8859-1 sq_AL.ISO8859-1 )],
4879             sq_MK => [qw( sq_MK.UTF-8 )],
4880             sr_ME => [qw( sr_ME.UTF-8 )],
4881             sr_RS => [qw( sr_RS.UTF-8 )],
4882             ss_ZA => [qw( ss_ZA.UTF-8 )],
4883             st_ZA => [qw( st_ZA.UTF-8 st_ZA.ISO-8859-1 st_ZA.ISO8859-1 )],
4884             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 )],
4885             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 )],
4886             sw_KE => [qw( sw_KE.UTF-8 )],
4887             sw_TZ => [qw( sw_TZ.UTF-8 )],
4888             szl_PL => [qw( szl_PL.UTF-8 )],
4889             ta_IN => [qw( ta_IN.UTF-8 )],
4890             ta_LK => [qw( ta_LK.UTF-8 )],
4891             tcy_IN => [qw( tcy_IN.UTF-8 )],
4892             te_IN => [qw( te_IN.UTF-8 )],
4893             tg_TJ => [qw( tg_TJ.UTF-8 tg_TJ.KOI8-T tg_TJ.KOI8T )],
4894             th_TH => [qw( th_TH.UTF-8 th_TH.TIS-620 th_TH.TIS620 )],
4895             the_NP => [qw( the_NP.UTF-8 )],
4896             ti_ER => [qw( ti_ER.UTF-8 )],
4897             ti_ET => [qw( ti_ET.UTF-8 )],
4898             tig_ER => [qw( tig_ER.UTF-8 )],
4899             tk_TM => [qw( tk_TM.UTF-8 )],
4900             tl_PH => [qw( tl_PH.UTF-8 tl_PH.ISO-8859-1 tl_PH.ISO8859-1 )],
4901             tn_ZA => [qw( tn_ZA.UTF-8 )],
4902             tr_CY => [qw( tr_CY.UTF-8 tr_CY.ISO-8859-9 tr_CY.ISO8859-9 )],
4903             tr_TR => [qw( tr_TR.UTF-8 tr_TR.ISO-8859-9 tr_TR.ISO8859-9 )],
4904             ts_ZA => [qw( ts_ZA.UTF-8 )],
4905             tt_RU => [qw( tt_RU.UTF-8 )],
4906             ug_CN => [qw( ug_CN.UTF-8 )],
4907             uk_UA => [qw( uk_UA.UTF-8 uk_UA.KOI8-U uk_UA.KOI8U )],
4908             unm_US => [qw( unm_US.UTF-8 )],
4909             ur_IN => [qw( ur_IN.UTF-8 )],
4910             ur_PK => [qw( ur_PK.UTF-8 )],
4911             uz_UZ => [qw( uz_UZ.UTF-8 uz_UZ.ISO-8859-1 uz_UZ.ISO8859-1 )],
4912             ve_ZA => [qw( ve_ZA.UTF-8 )],
4913             vi_VN => [qw( vi_VN.UTF-8 )],
4914             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 )],
4915             wae_CH => [qw( wae_CH.UTF-8 )],
4916             wal_ET => [qw( wal_ET.UTF-8 )],
4917             wo_SN => [qw( wo_SN.UTF-8 )],
4918             xh_ZA => [qw( xh_ZA.UTF-8 xh_ZA.ISO-8859-1 xh_ZA.ISO8859-1 )],
4919             yi_US => [qw( yi_US.UTF-8 yi_US.CP1255 )],
4920             yo_NG => [qw( yo_NG.UTF-8 )],
4921             yue_HK => [qw( yue_HK.UTF-8 )],
4922             zh_CN => [qw( zh_CN.UTF-8 zh_CN.GB18030 zh_CN.GBK zh_CN.GB2312 )],
4923             zh_HK => [qw( zh_HK.UTF-8 zh_HK.BIG5-HKSCS zh_HK.BIG5HKSCS )],
4924             zh_SG => [qw( zh_SG.UTF-8 zh_SG.GBK zh_SG.GB2312 )],
4925             zh_TW => [qw( zh_TW.UTF-8 zh_TW.EUC-TW zh_TW.EUCTW zh_TW.BIG5 )],
4926             zu_ZA => [qw( zu_ZA.UTF-8 zu_ZA.ISO-8859-1 zu_ZA.ISO8859-1 )],
4927             };
4928              
4929             our $DEFAULT =
4930             {
4931             ## The local currency symbol.
4932             currency_symbol => '€',
4933             ## The decimal point character, except for currency values, cannot be an empty string
4934             decimal_point => '.',
4935             ## The number of digits after the decimal point in the local style for currency values.
4936             frac_digits => 2,
4937             ## The sizes of the groups of digits, except for currency values. unpack( "C*", $grouping ) will give the number
4938             grouping => (CORE::chr(3) x 2),
4939             ## The standardized international currency symbol.
4940             int_curr_symbol => '€',
4941             ## The number of digits after the decimal point in an international-style currency value.
4942             int_frac_digits => 2,
4943             ## Same as n_cs_precedes, but for internationally formatted monetary quantities.
4944             int_n_cs_precedes => '',
4945             ## Same as n_sep_by_space, but for internationally formatted monetary quantities.
4946             int_n_sep_by_space => '',
4947             ## Same as n_sign_posn, but for internationally formatted monetary quantities.
4948             int_n_sign_posn => 1,
4949             ## Same as p_cs_precedes, but for internationally formatted monetary quantities.
4950             int_p_cs_precedes => 1,
4951             ## Same as p_sep_by_space, but for internationally formatted monetary quantities.
4952             int_p_sep_by_space => 0,
4953             ## Same as p_sign_posn, but for internationally formatted monetary quantities.
4954             int_p_sign_posn => 1,
4955             ## The decimal point character for currency values.
4956             mon_decimal_point => '.',
4957             ## Like grouping but for currency values.
4958             mon_grouping => (CORE::chr(3) x 2),
4959             ## The separator for digit groups in currency values.
4960             mon_thousands_sep => ',',
4961             ## Like p_cs_precedes but for negative values.
4962             n_cs_precedes => 1,
4963             ## Like p_sep_by_space but for negative values.
4964             n_sep_by_space => 0,
4965             ## Like p_sign_posn but for negative currency values.
4966             n_sign_posn => 1,
4967             ## The character used to denote negative currency values, usually a minus sign.
4968             negative_sign => '-',
4969             ## 1 if the currency symbol precedes the currency value for nonnegative values, 0 if it follows.
4970             p_cs_precedes => 1,
4971             ## 1 if a space is inserted between the currency symbol and the currency value for nonnegative values, 0 otherwise.
4972             p_sep_by_space => 0,
4973             ## The location of the positive_sign with respect to a nonnegative quantity and the currency_symbol, coded as follows:
4974             ## 0 Parentheses around the entire string.
4975             ## 1 Before the string.
4976             ## 2 After the string.
4977             ## 3 Just before currency_symbol.
4978             ## 4 Just after currency_symbol.
4979             p_sign_posn => 1,
4980             ## The character used to denote nonnegative currency values, usually the empty string.
4981             positive_sign => '',
4982             ## The separator between groups of digits before the decimal point, except for currency values
4983             thousands_sep => ',',
4984             };
4985              
4986             my $map =
4987             {
4988             decimal => [qw( decimal_point mon_decimal_point )],
4989             grouping => [qw( grouping mon_grouping )],
4990             position_neg => [qw( n_sign_posn int_n_sign_posn )],
4991             position_pos => [qw( n_sign_posn int_p_sign_posn )],
4992             precede => [qw( p_cs_precedes int_p_cs_precedes )],
4993             precede_neg => [qw( n_cs_precedes int_n_cs_precedes )],
4994             precision => [qw( frac_digits int_frac_digits )],
4995             sign_neg => [qw( negative_sign )],
4996             sign_pos => [qw( positive_sign )],
4997             space_pos => [qw( p_sep_by_space int_p_sep_by_space )],
4998             space_neg => [qw( n_sep_by_space int_n_sep_by_space )],
4999             symbol => [qw( currency_symbol int_curr_symbol )],
5000             thousand => [qw( thousands_sep mon_thousands_sep )],
5001             };
5002              
5003             sub init
5004             {
5005 130     130   300 my $self = shift( @_ );
5006 130         348 my $num = shift( @_ );
5007 130 50       674 return( $self->error( "No number was provided." ) ) if( !CORE::length( $num ) );
5008 130 100       626 return( Module::Generic::Infinity->new( $num ) ) if( POSIX::isinf( $num ) );
5009 129 100       501 return( Module::Generic::Nan->new( $num ) ) if( POSIX::isnan( $num ) );
5010 6     6   9371 use utf8;
  6         49  
  6         50  
5011 128         631 my @k = keys( %$map );
5012 128         1269 @$self{ @k } = ( '' x scalar( @k ) );
5013 128         453 $self->{lang} = '';
5014 128         388 $self->{default} = $DEFAULT;
5015 128         461 $self->{_init_strict_use_sub} = 1;
5016 128         679 $self->SUPER::init( @_ );
5017 128         481 my $default = $self->default;
5018             # $self->message( 3, "Getting current locale" );
5019 128         841 my $curr_locale = POSIX::setlocale( &POSIX::LC_ALL );
5020             ## $self->message( 3, "Current locale is '$curr_locale'" );
5021 128 100 33     953 if( $self->{lang} )
    50          
5022             {
5023             # $self->message( 3, "Language requested '$self->{lang}'." );
5024 67         186 try
5025 67     67   105 {
5026             # $self->message( 3, "Current locale found is '$curr_locale'" );
5027             local $try_locale = sub
5028             {
5029 67         172 my $loc;
5030             # $self->message( 3, "Checking language '$_[0]'" );
5031             ## 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
5032             ## Try several possibilities
5033             ## RT https://rt.cpan.org/Public/Bug/Display.html?id=132664
5034 67 50       195 if( index( $_[0], '.' ) == -1 )
5035             {
5036             # $self->message( 3, "Language '$_[0]' is a bareword, check if it works as is." );
5037 67         254 $loc = POSIX::setlocale( &POSIX::LC_ALL, $_[0] );
5038             # $self->message( 3, "Succeeded to set up locale for language '$_[0]'" ) if( $loc );
5039 67         191 $_[0] =~ s/^(?<locale>[a-z]{2,3})_(?<country>[a-z]{2})$/$+{locale}_\U$+{country}\E/;
5040 67 50 33     305 if( !$loc && CORE::exists( $SUPPORTED_LOCALES->{ $_[0] } ) )
5041             {
5042             # $self->message( 3, "Language '$_[0]' is supported, let's check for right variation" );
5043 0         0 foreach my $supported ( @{$SUPPORTED_LOCALES->{ $_[0] }} )
  0         0  
5044             {
5045 0 0       0 if( ( $loc = POSIX::setlocale( &POSIX::LC_ALL, $supported ) ) )
5046             {
5047 0         0 $_[0] = $supported;
5048             # $self->message( "-> Language variation '$supported' found." );
5049 0         0 last;
5050             }
5051             }
5052             }
5053             }
5054             ## We got something like fr_FR.ISO-8859
5055             ## The user is specific, so we try as is
5056             else
5057             {
5058             # $self->message( 3, "Language '$_[0]' is specific enough, let's try it." );
5059 0         0 $loc = POSIX::setlocale( &POSIX::LC_ALL, $_[0] );
5060             }
5061 67         217 return( $loc );
5062 67         390 };
5063            
5064             ## $self->message( 3, "Current locale is: '$curr_locale'" );
5065 67 50       231 if( my $loc = $try_locale->( $self->{lang} ) )
5066             {
5067             # $self->message( 3, "Succeeded in setting locale for language '$self->{lang}'" );
5068             ## $self->message( 3, "Succeeded in setting locale to '$self->{lang}'." );
5069 67         413 my $lconv = POSIX::localeconv();
5070             ## Set back the LC_ALL to what it was, because we do not want to disturb the user environment
5071 67         689 POSIX::setlocale( &POSIX::LC_ALL, $curr_locale );
5072             ## $self->messagef( 3, "POSIX::localeconv() returned %d items", scalar( keys( %$lconv ) ) );
5073 67 50 50     1147 $default = $lconv if( $lconv && scalar( keys( %$lconv ) ) );
5074             }
5075             else
5076             {
5077 0         0 return( $self->error( "Language \"$self->{lang}\" is not supported by your system." ) );
5078             }
5079             }
5080 67 50       492 catch( $e )
  67 50       260  
  67 50       194  
  67 0       150  
  67 50       181  
  67         264  
  67         133  
  67         177  
  67         233  
  0         0  
  67         139  
  0         0  
  67         214  
  67         132  
  67         136  
  67         163  
  0         0  
  0         0  
  0         0  
  0         0  
5081 0     0   0 {
5082 0         0 return( $self->error( "An error occurred while getting the locale information for \"$self->{lang}\": $e" ) );
5083 0 0 33     0 }
  0 0 33     0  
  0 0       0  
  0 50       0  
  0         0  
  0         0  
  67         1050  
  0         0  
5084             }
5085             elsif( $curr_locale && ( my $lconv = POSIX::localeconv() ) )
5086             {
5087 61 50       248 $default = $lconv if( scalar( keys( %$lconv ) ) );
5088             ## To simulate running on Windows
5089             # my $fail = [qw(
5090             # frac_digits
5091             # int_frac_digits
5092             # n_cs_precedes
5093             # n_sep_by_space
5094             # n_sign_posn
5095             # p_cs_precedes
5096             # p_sep_by_space
5097             # p_sign_posn
5098             # )];
5099             # @$lconv{ @$fail } = ( -1 ) x scalar( @$fail );
5100             ## $self->message( 3, "No language provided, but current locale '$curr_locale' found" );
5101 61         173 $self->{lang} = $curr_locale;
5102             }
5103              
5104             ## This serves 2 purposes:
5105             ## 1) to silence warnings issued from Number::Format when it uses an empty string when evaluating a number, e.g. '' == 1
5106             ## 2) to ensure that blank numerical values are not interpreted to anything else than equivalent of empty
5107             ## 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
5108             ## 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.
5109 128         1514 my $numerics =
5110             {
5111             grouping => 0,
5112             frac_digits => 0,
5113             int_frac_digits => 0,
5114             int_n_cs_precedes => 0,
5115             int_p_cs_precedes => 0,
5116             int_n_sep_by_space => 0,
5117             int_p_sep_by_space => 0,
5118             int_n_sign_posn => 1,
5119             int_p_sign_posn => 1,
5120             mon_grouping => 0,
5121             n_cs_precedes => 0,
5122             n_sep_by_space => 0,
5123             n_sign_posn => 1,
5124             p_cs_precedes => 0,
5125             p_sep_by_space => 0,
5126             ## Position of positive sign. 1 = before (0 = parentheses)
5127             p_sign_posn => 1,
5128             };
5129            
5130 128         618 foreach my $prop ( keys( %$map ) )
5131             {
5132 1664         3861 my $ref = $map->{ $prop };
5133             ## Already set by user
5134 1664 100       4908 next if( CORE::length( $self->{ $prop } ) );
5135 1492         3419 foreach my $lconv_prop ( @$ref )
5136             {
5137 2667 100       6599 if( CORE::defined( $default->{ $lconv_prop } ) )
5138             {
5139             ## Number::Format bug RT #71044 when running on Windows
5140             ## https://rt.cpan.org/Ticket/Display.html?id=71044
5141             ## This is a workaround when values are lower than 0 (i.e. -1)
5142 61 0 33     324 if( CORE::exists( $numerics->{ $lconv_prop } ) &&
      33        
5143             CORE::length( $default->{ $lconv_prop } ) &&
5144             $default->{ $lconv_prop } < 0 )
5145             {
5146 0         0 $default->{ $lconv_prop } = $numerics->{ $lconv_prop };
5147             }
5148 61         284 $self->$prop( $default->{ $lconv_prop } );
5149 61         162 last;
5150             }
5151             else
5152             {
5153 2606         10087 $self->$prop( $default->{ $lconv_prop } );
5154             }
5155             }
5156             }
5157            
5158             # $Number::Format::DEFAULT_LOCALE->{int_curr_symbol} = 'EUR';
5159 128         512 try
5160 0         0 {
5161             ## Those are unsupported by Number::Format
5162 128         846 my $skip =
5163             {
5164             int_n_cs_precedes => 1,
5165             int_p_cs_precedes => 1,
5166             int_n_sep_by_space => 1,
5167             int_p_sep_by_space => 1,
5168             int_n_sign_posn => 1,
5169             int_p_sign_posn => 1,
5170             };
5171 128         314 my $opts = {};
5172 128         564 foreach my $prop ( CORE::keys( %$map ) )
5173             {
5174             ## $self->message( 3, "Checking property \"$prop\" value \"", overload::StrVal( $self->{ $prop } ), "\" (", $self->$prop->defined ? 'defined' : 'undefined', ")." );
5175 1664         2257 my $prop_val;
5176 1664 100       4534 if( $self->$prop->defined )
5177             {
5178 233         633 $prop_val = $self->$prop;
5179             }
5180             ## To prevent Number::Format from defaulting to property values not in sync with ours
5181             ## Because it seems the POSIX::setlocale only affect one module
5182             else
5183             {
5184 1431         2409 $prop_val = '';
5185             }
5186             ## $self->message( 3, "Using property \"$prop\" value \"$prop_val\" (", CORE::defined( $prop_val ) ? 'defined' : 'undefined', ") [ref=", ref( $prop_val ), "]." );
5187             ## Need to set all the localeconv properties for Number::Format, because it uses mon_thousand_sep intsead of just thousand_sep
5188 1664         3704 foreach my $lconv_prop ( @{$map->{ $prop }} )
  1664         4198  
5189             {
5190 3072 100       7374 CORE::next if( CORE::exists( $skip->{ $lconv_prop } ) );
5191             ## Cannot be undefined, but can be empty string
5192 2304         5027 $opts->{ $lconv_prop } = "$prop_val";
5193 2304 100 100     9069 if( !CORE::length( $opts->{ $lconv_prop } ) && CORE::exists( $numerics->{ $lconv_prop } ) )
5194             {
5195 1146         2853 $opts->{ $lconv_prop } = $numerics->{ $lconv_prop };
5196             }
5197             }
5198             }
5199             ## $self->message( 3, "Using following options for Number::Format: ", sub{ $self->dumper( $opts ) } );
5200 6     6   5871 no warnings qw( uninitialized );
  6         17  
  6         332  
5201 128         1328 $self->{_fmt} = Number::Format->new( %$opts );
5202 6     6   38 use warnings;
  6         17  
  6         6429  
5203 128     128   253 }
5204 128 100       1006 catch( $e )
  128 50       39843  
  128 50       368  
  128 0       269  
  128 50       350  
  128         224  
  128         255  
  128         284  
  128         480  
  2         7  
  126         309  
  0         0  
  128         509  
  128         351  
  128         341  
  128         415  
  0         0  
  0         0  
  0         0  
  0         0  
5205 0     0   0 {
5206             ## $self->message( 3, "Error trapped in creating a Number::Format object: '$e'" );
5207 0         0 return( $self->error( "Unable to create a Number::Format object: $e" ) );
5208 0 0 33     0 }
  0 0 33     0  
  0 0       0  
  0 50       0  
  0         0  
  0         0  
  128         2469  
  0         0  
5209 128         506 $self->{_original} = $num;
5210 128         240 try
5211 128     128   234 {
5212 128 100       1343 if( $num !~ /^$RE{num}{real}$/ )
5213             {
5214 1         246 $self->{_number} = $self->{_fmt}->unformat_number( $num );
5215             }
5216             else
5217             {
5218 127         25799 $self->{_number} = $num;
5219             }
5220             ## $self->message( 3, "Unformatted number is: '$self->{_number}'" );
5221 128 100       1427 return( $self->error( "Invalid number: $num" ) ) if( !defined( $self->{_number} ) );
5222             }
5223 128 100       817 catch( $e )
  127 50       431  
  128 50       346  
  128 0       254  
  128 50       287  
  128         236  
  128         233  
  128         228  
  128         477  
  2         7  
  126         270  
  0         0  
  128         404  
  128         303  
  128         358  
  128         392  
  0         0  
  0         0  
  0         0  
  0         0  
5224 0     0   0 {
5225 0         0 return( $self->error( "Invalid number: $num" ) );
5226 0 0 66     0 }
  0 0 66     0  
  0 50       0  
  0 100       0  
  0         0  
  0         0  
  128         1952  
  1         51  
5227 127         2903 return( $self );
5228             }
5229              
5230 3     3   24 sub abs { return( shift->_func( 'abs' ) ); }
5231              
5232             # sub asin { return( shift->_func( 'asin', { posix => 1 } ) ); }
5233              
5234 1     1   296 sub atan { return( shift->_func( 'atan', { posix => 1 } ) ); }
5235              
5236 1     1   13 sub atan2 { return( shift->_func( 'atan2', @_ ) ); }
5237              
5238 4 100   4   19 sub as_boolean { return( Module::Generic::Boolean->new( shift->{_number} ? 1 : 0 ) ); }
5239              
5240 0     0   0 sub as_string { return( shift->{_number} ) }
5241              
5242 1     1   6 sub cbrt { return( shift->_func( 'cbrt', { posix => 1 } ) ); }
5243              
5244 1     1   9 sub ceil { return( shift->_func( 'ceil', { posix => 1 } ) ); }
5245              
5246 1     1   7 sub chr { return( Module::Generic::Scalar->new( CORE::chr( $_[0]->{_number} ) ) ); }
5247              
5248             sub clone
5249             {
5250 67     67   200 my $self = shift( @_ );
5251 67 100       247 my $num = @_ ? shift( @_ ) : $self->{_number};
5252 67 50       317 return( Module::Generic::Infinity->new( $num ) ) if( POSIX::isinf( $num ) );
5253 67 50       229 return( Module::Generic::Nan->new( $num ) ) if( POSIX::isnan( $num ) );
5254 67         396 my @keys = keys( %$map );
5255 67         209 push( @keys, qw( lang debug ) );
5256 67         140 my $hash = {};
5257 67         776 @$hash{ @keys } = @$self{ @keys };
5258 67         290 return( $self->new( $num, $hash ) );
5259             }
5260              
5261             sub compute
5262             {
5263 141     141   564 my( $self, $other, $swap, $opts ) = @_;
5264 141 100       841 my $other_val = Scalar::Util::blessed( $other ) ? $other : "\"$other\"";
5265 141 100       677 my $operation = $swap ? "${other_val} $opts->{op} \$self->{_number}" : "\$self->{_number} $opts->{op} ${other_val}";
5266 141 100       594 if( $opts->{return_object} )
    100          
5267             {
5268 37         2835 my $res = eval( $operation );
5269 6     6   54 no overloading;
  6         18  
  6         774  
5270 37 50 33     291 warn( "Error with return formula \"$operation\" using object $self having number '$self->{_number}': $@" ) if( $@ && $self->_warnings_is_enabled );
5271 37 50       133 return if( $@ );
5272 37 100       183 return( Module::Generic::Scalar->new( $res ) ) if( $opts->{type} eq 'scalar' );
5273 36 100       239 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
5274 31 100       177 return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
5275             ## undef may be returned for example on platform supporting NaN when using <=>
5276 27 50       197 return( $self->clone( $res ) ) if( defined( $res ) );
5277 0         0 return;
5278             }
5279             elsif( $opts->{boolean} )
5280             {
5281 101         7607 my $res = eval( $operation );
5282 6     6   42 no overloading;
  6         15  
  6         1786  
5283 101 50 33     700 warn( "Error with boolean formula \"$operation\" using object $self having number '$self->{_number}': $@" ) if( $@ && $self->_warnings_is_enabled );
5284 101 50       320 return if( $@ );
5285 101 100       611 return( $res ? $self->true : $self->false );
5286             }
5287             else
5288             {
5289 3         211 return( eval( $operation ) );
5290             }
5291             }
5292              
5293 1     1   6 sub cos { return( shift->_func( 'cos' ) ); }
5294              
5295 4     4   17 sub currency { return( shift->_set_get_prop( 'symbol', @_ ) ); }
5296              
5297 3925     3925   9118 sub decimal { return( shift->_set_get_prop( 'decimal', @_ ) ); }
5298              
5299 128     128   519 sub default { return( shift->_set_get_hash_as_mix_object( 'default', @_ ) ); }
5300              
5301 1     1   5 sub exp { return( shift->_func( 'exp' ) ); }
5302              
5303 2     2   15 sub floor { return( shift->_func( 'floor', { posix => 1 } ) ); }
5304              
5305             sub format
5306             {
5307 2     2   8 my $self = shift( @_ );
5308 2 50 33     20 my $precision = ( @_ && $_[0] =~ /^\d+$/ ) ? shift( @_ ) : $self->precision;
5309 6     6   98 no overloading;
  6         17  
  6         9110  
5310 2         18 my $num = $self->{_number};
5311             ## 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
5312 2 50       6 return( $num ) if( !defined( $num ) );
5313 2         5 my $fmt = $self->{_fmt};
5314 2         5 try
5315 2     2   3 {
5316             ## 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?
5317             ## To circumvent this, we provide the precision along with the "add trailing zeros" parameter expected by Number::Format
5318             ## return( $fmt->format_number( $num, $precision, 1 ) );
5319 2         27 my $res = $fmt->format_number( "$num", $precision, 1 );
5320 2 50       56 return if( !defined( $res ) );
5321 2         10 return( Module::Generic::Scalar->new( $res ) );
5322             }
5323 2 50       25 catch( $e )
  0 50       0  
  2 50       7  
  2 0       11  
  2 50       11  
  2         4  
  2         5  
  2         5  
  2         7  
  0         0  
  2         9  
  0         0  
  2         9  
  2         10  
  2         12  
  2         6  
  0         0  
  0         0  
  0         0  
  0         0  
5324 0     0   0 {
5325 0         0 return( $self->error( "Error formatting number \"$num\": $e" ) );
5326 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  2         60  
  2         30  
5327             }
5328              
5329 2     2   18 sub format_binary { return( Module::Generic::Scalar->new( CORE::sprintf( '%b', shift->{_number} ) ) ); }
5330              
5331             sub format_bytes
5332             {
5333 1     1   3 my $self = shift( @_ );
5334             # no overloading;
5335 1         4 my $num = $self->{_number};
5336             ## See comment in format() method
5337 1 50       5 return( $num ) if( !defined( $num ) );
5338 1         4 my $fmt = $self->{_fmt};
5339 1         2 try
5340 1     1   2 {
5341             ## return( $fmt->format_bytes( $num, @_ ) );
5342 1         8 my $res = $fmt->format_bytes( "$num", @_ );
5343 1 50       253 return if( !defined( $res ) );
5344 1         6 return( Module::Generic::Scalar->new( $res ) );
5345             }
5346 1 50       19 catch( $e )
  0 50       0  
  1 50       4  
  1 0       2  
  1 50       2  
  1         3  
  1         2  
  1         3  
  1         5  
  0         0  
  1         4  
  0         0  
  1         5  
  1         3  
  1         3  
  1         4  
  0         0  
  0         0  
  0         0  
  0         0  
5347 0     0   0 {
5348 0         0 return( $self->error( "Error formatting number \"$num\": $e" ) );
5349 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         25  
  1         15  
5350             }
5351              
5352 2     2   16 sub format_hex { return( Module::Generic::Scalar->new( CORE::sprintf( '0x%X', shift->{_number} ) ) ); }
5353              
5354             sub format_money
5355             {
5356 1     1   4 my $self = shift( @_ );
5357 1 50 33     16 my $precision = ( @_ && $_[0] =~ /^\d+$/ ) ? shift( @_ ) : $self->precision;
5358 1 50       9 my $currency_symbol = @_ ? shift( @_ ) : $self->currency;
5359             # no overloading;
5360 1         19 my $num = $self->{_number};
5361             ## See comment in format() method
5362 1 50       6 return( $num ) if( !defined( $num ) );
5363 1         4 my $fmt = $self->{_fmt};
5364 1         3 try
5365 1     1   2 {
5366             ## Even though the Number::Format instantiated is set with a currency symbol,
5367             ## Number::Format will not respect it, and revert to USD if nothing was provided as argument
5368             ## This highlights that Number::Format is designed to be used more for exporting function rather than object methods
5369             ## $self->message( 3, "Passing Number = '$num', precision = '$precision', currency symbol = '$currency_symbol'." );
5370             ## return( $fmt->format_price( $num, $precision, $currency_symbol ) );
5371 1         11 my $res = $fmt->format_price( "$num", "$precision", "$currency_symbol" );
5372 1 50       227 return if( !defined( $res ) );
5373 1         10 return( Module::Generic::Scalar->new( $res ) );
5374             }
5375 1 50       19 catch( $e )
  0 50       0  
  1 50       5  
  1 0       2  
  1 50       3  
  1         4  
  1         2  
  1         2  
  1         6  
  0         0  
  1         3  
  0         0  
  1         18  
  1         3  
  1         4  
  1         15  
  0         0  
  0         0  
  0         0  
  0         0  
5376 0     0   0 {
5377 0         0 return( $self->error( "Error formatting number \"$num\": $e" ) );
5378 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         27  
  1         13  
5379             }
5380              
5381             sub format_negative
5382             {
5383 1     1   307 my $self = shift( @_ );
5384             # no overloading;
5385 1         4 my $num = $self->{_number};
5386             ## See comment in format() method
5387 1 50       5 return( $num ) if( !defined( $num ) );
5388 1         4 my $fmt = $self->{_fmt};
5389 1         3 try
5390 1     1   3 {
5391 1         3 my $new = $self->format;
5392             ## $self->message( 3, "Formatted number '$self->{_number}' now is '$new'" );
5393             ## return( $fmt->format_negative( $new, @_ ) );
5394 1         15 my $res = $fmt->format_negative( "$new", @_ );
5395             ## $self->message( 3, "Result is '$res'" );
5396 1 50       39 return if( !defined( $res ) );
5397 1         7 return( Module::Generic::Scalar->new( $res ) );
5398             }
5399 1 50       20 catch( $e )
  0 50       0  
  1 50       7  
  1 0       4  
  1 50       4  
  1         4  
  1         1  
  1         3  
  1         6  
  0         0  
  1         3  
  0         0  
  1         17  
  1         4  
  1         10  
  1         7  
  0         0  
  0         0  
  0         0  
  0         0  
5400 0     0   0 {
5401 0         0 return( $self->error( "Error formatting number \"$num\": $e" ) );
5402 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         26  
  1         47  
5403             }
5404              
5405             sub format_picture
5406             {
5407 0     0   0 my $self = shift( @_ );
5408 6     6   55 no overloading;
  6         17  
  6         13309  
5409 0         0 my $num = $self->{_number};
5410             ## See comment in format() method
5411 0 0       0 return( $num ) if( !defined( $num ) );
5412 0         0 my $fmt = $self->{_fmt};
5413 0         0 try
5414 0     0   0 {
5415             ## return( $fmt->format_picture( $num, @_ ) );
5416 0         0 my $res = $fmt->format_picture( "$num", @_ );
5417 0 0       0 return if( !defined( $res ) );
5418 0         0 return( Module::Generic::Scalar->new( $res ) );
5419             }
5420 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  
5421 0     0   0 {
5422 0         0 return( $self->error( "Error formatting number \"$num\": $e" ) );
5423 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
5424             }
5425              
5426 3540     3540   10210 sub formatter { return( shift->_set_get_object( 'formatter', 'Number::Format', @_ ) ); }
5427              
5428             ## https://stackoverflow.com/a/483708/4814971
5429             sub from_binary
5430             {
5431 1     1   3 my $self = shift( @_ );
5432 1         2 my $binary = shift( @_ );
5433 1 50 33     14 return if( !defined( $binary ) || !CORE::length( $binary ) );
5434 1         2 try
5435 1     1   2 {
5436             ## Nice trick to convert from binary to decimal. See perlfunc -> oct
5437 1         4 my $res = CORE::oct( "0b${binary}" );
5438 1 50       5 return if( !defined( $res ) );
5439 1         4 return( $self->clone( $res ) );
5440             }
5441 1 50       18 catch( $e )
  0 50       0  
  1 50       4  
  1 0       4  
  1 50       3  
  1         2  
  1         2  
  1         2  
  1         7  
  0         0  
  1         3  
  0         0  
  1         5  
  1         4  
  1         3  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
5442 0     0   0 {
5443 0         0 return( $self->error( "Error while getting number from hexadecimal value \"$hex\": $e" ) );
5444 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         28  
  1         13  
5445             }
5446              
5447             sub from_hex
5448             {
5449 1     1   4 my $self = shift( @_ );
5450 1         3 my $hex = shift( @_ );
5451 1 50 33     15 return if( !defined( $hex ) || !CORE::length( $hex ) );
5452 1         3 try
5453 1     1   2 {
5454 1         3 my $res = CORE::hex( $hex );
5455 1 50       5 return if( !defined( $res ) );
5456 1         7 return( $self->clone( $res ) );
5457             }
5458 1 50       18 catch( $e )
  0 50       0  
  1 50       4  
  1 0       2  
  1 50       4  
  1         2  
  1         3  
  1         3  
  1         5  
  0         0  
  1         3  
  0         0  
  1         7  
  1         3  
  1         3  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
5459 0     0   0 {
5460 0         0 return( $self->error( "Error while getting number from hexadecimal value \"$hex\": $e" ) );
5461 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         27  
  1         14  
5462             }
5463              
5464 3991     3991   9807 sub grouping { return( shift->_set_get_prop( 'grouping', @_ ) ); }
5465              
5466 1     1   397 sub int { return( shift->_func( 'int' ) ); }
5467              
5468             *is_decimal = \&is_float;
5469              
5470 1     1   7 sub is_finite { return( shift->_func( 'isfinite', { posix => 1 }) ); }
5471              
5472 1     1   16 sub is_float { return( (POSIX::modf( shift->{_number} ))[0] != 0 ); }
5473              
5474             # sub is_infinite { return( !(shift->is_finite) ); }
5475 0     0   0 sub is_infinite { return( shift->_func( 'isinf', { posix => 1 }) ); }
5476              
5477 1     1   11 sub is_int { return( (POSIX::modf( shift->{_number} ))[0] == 0 ); }
5478              
5479 1     1   7 sub is_nan { return( shift->_func( 'isnan', { posix => 1}) ); }
5480              
5481             *is_neg = \&is_negative;
5482              
5483 4     4   302 sub is_negative { return( shift->_func( 'signbit', { posix => 1 }) != 0 ); }
5484              
5485 1     1   6 sub is_normal { return( shift->_func( 'isnormal', { posix => 1}) ); }
5486              
5487             *is_pos = \&is_positive;
5488              
5489 4     4   27 sub is_positive { return( shift->_func( 'signbit', { posix => 1 }) == 0 ); }
5490              
5491 68     68   306 sub lang { return( shift->_set_get_scalar_as_object( 'lang', @_ ) ); }
5492              
5493 1     1   24 sub length { return( $_[0]->clone( CORE::length( $_[0]->{_number} ) ) ); }
5494              
5495 1     1   11 sub locale { return( shift->_set_get_scalar_as_object( 'lang', @_ ) ); }
5496              
5497 1     1   5 sub log { return( shift->_func( 'log' ) ); }
5498              
5499 1     1   6 sub log2 { return( shift->_func( 'log2', { posix => 1 } ) ); }
5500              
5501 1     1   9 sub log10 { return( shift->_func( 'log10', { posix => 1 } ) ); }
5502              
5503 3     3   21 sub max { return( shift->_func( 'fmax', @_, { posix => 1 } ) ); }
5504              
5505 2     2   15 sub min { return( shift->_func( 'fmin', @_, { posix => 1 } ) ); }
5506              
5507 1     1   6 sub mod { return( shift->_func( 'fmod', @_, { posix => 1 } ) ); }
5508              
5509             ## This is used so that we can change formatter when the user changes thousand separator, decimal separator, precision or currency
5510             sub new_formatter
5511             {
5512 3540     3540   5999 my $self = shift( @_ );
5513 3540         6021 my $hash = {};
5514 3540 50       6950 if( @_ )
5515             {
5516 0 0 0     0 if( @_ == 1 && $self->_is_hash( $_[0] ) )
    0          
5517             {
5518 0         0 $hash = shift( @_ );
5519             }
5520             elsif( !( @_ % 2 ) )
5521             {
5522 0         0 $hash = { @_ };
5523             }
5524             else
5525             {
5526 0         0 return( $self->error( "Invalid parameters provided: '", join( "', '", @_ ), "'." ) );
5527             }
5528             }
5529             else
5530             {
5531 3540         13992 my @keys = keys( %$map );
5532             # @$hash{ @keys } = @$self{ @keys };
5533 3540         7320 for( @keys )
5534             {
5535 46020         123096 $hash->{ $_ } = $self->$_();
5536             }
5537             }
5538 3540         5497 try
5539 3540     3540   4735 {
5540 3540         5918 my $opts = {};
5541 3540         18335 foreach my $prop ( keys( %$map ) )
5542             {
5543 46020 100       90150 $opts->{ $map->{ $prop }->[0] } = $hash->{ $prop } if( CORE::defined( $hash->{ $prop } ) );
5544             }
5545 3540         17747 return( Number::Format->new( %$opts ) );
5546             }
5547 3540 50       17396 catch( $e )
  0 0       0  
  3540 50       7783  
  3540 0       5368  
  3540 50       7622  
  3540         4731  
  3540         5397  
  3540         6073  
  3540         6729  
  3540         6429  
  0         0  
  0         0  
  3540         449069  
  3540         6723  
  3540         7098  
  3540         7912  
  0         0  
  0         0  
  0         0  
  0         0  
5548 0     0   0 {
5549 0         0 return( $self->error( "Error while trying to get a Number::Format object: $e" ) );
5550 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  3540         30087  
  3540         32163  
5551             }
5552              
5553 1     1   13 sub oct { return( shift->_func( 'oct' ) ); }
5554              
5555 3991     3991   8724 sub position_neg { return( shift->_set_get_prop( 'position_neg', @_ ) ); }
5556              
5557 3991     3991   8922 sub position_pos { return( shift->_set_get_prop( 'position_pos', @_ ) ); }
5558              
5559 0     0   0 sub pow { return( shift->_func( 'pow', @_, { posix => 1 } ) ); }
5560              
5561 3992     3992   8802 sub precede { return( shift->_set_get_prop( 'precede', @_ ) ); }
5562              
5563 3991     3991   9482 sub precede_neg { return( shift->_set_get_prop( 'precede_neg', @_ ) ); }
5564              
5565 0     0   0 sub precede_pos { return( shift->_set_get_prop( 'precede', @_ ) ); }
5566              
5567 3930     3930   9408 sub precision { return( shift->_set_get_prop( 'precision', @_ ) ); }
5568              
5569 0     0   0 sub rand { return( shift->_func( 'rand' ) ); }
5570              
5571 1 50   1   29 sub round { return( $_[0]->clone( CORE::sprintf( '%.*f', CORE::int( CORE::length( $_[1] ) ? $_[1] : 0 ), $_[0]->{_number} ) ) ); }
5572              
5573 0     0   0 sub round_zero { return( shift->_func( 'round', @_, { posix => 1 } ) ); }
5574              
5575             sub round2
5576             {
5577 0     0   0 my $self = shift( @_ );
5578 6     6   61 no overloading;
  6         14  
  6         9895  
5579 0         0 my $num = $self->{_number};
5580             ## See comment in format() method
5581 0 0       0 return( $num ) if( !defined( $num ) );
5582 0         0 my $fmt = $self->{_fmt};
5583 0         0 try
5584 0     0   0 {
5585             ## return( $fmt->round( $num, @_ ) );
5586 0         0 my $res = $fmt->round( $num, @_ );
5587 0 0       0 return if( !defined( $res ) );
5588 0         0 my $clone = $self->clone;
5589 0         0 $clone->{_number} = $res;
5590 0         0 return( $clone );
5591             }
5592 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  
5593 0     0   0 {
5594 0         0 return( $self->error( "Error rounding number \"$num\": $e" ) );
5595 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
5596             }
5597              
5598 3863     3863   9164 sub sign_neg { return( shift->_set_get_prop( 'sign_neg', @_ ) ); }
5599              
5600 3863     3863   8924 sub sign_pos { return( shift->_set_get_prop( 'sign_pos', @_ ) ); }
5601              
5602 1     1   5 sub sin { return( shift->_func( 'sin' ) ); }
5603              
5604             *space = \&space_pos;
5605              
5606 3991     3991   9259 sub space_neg { return( shift->_set_get_prop( 'space_neg', @_ ) ); }
5607              
5608 3991     3991   9467 sub space_pos { return( shift->_set_get_prop( 'space_pos', @_ ) ); }
5609              
5610 1     1   5 sub sqrt { return( shift->_func( 'sqrt' ) ); }
5611              
5612 3954     3954   10024 sub symbol { return( shift->_set_get_prop( 'symbol', @_ ) ); }
5613              
5614 1     1   6 sub tan { return( shift->_func( 'tan', { posix => 1 } ) ); }
5615              
5616 3992     3992   9007 sub thousand { return( shift->_set_get_prop( 'thousand', @_ ) ); }
5617              
5618             sub unformat
5619             {
5620 1     1   5 my $self = shift( @_ );
5621 1         3 my $num = shift( @_ );
5622 1 50       12 return if( !defined( $num ) );
5623 1         3 try
5624 1     1   2 {
5625 1         23 my $num2 = $self->{_fmt}->unformat_number( $num );
5626 1         45 my $clone = $self->clone;
5627 1         4 $clone->{_original} = $num;
5628 1         3 $clone->{_number} = $num2;
5629 1         5 return( $clone );
5630             }
5631 1 50       17 catch( $e )
  0 50       0  
  1 50       4  
  1 0       3  
  1 50       9  
  1         3  
  1         4  
  1         2  
  1         10  
  0         0  
  1         5  
  0         0  
  1         14  
  1         5  
  1         3  
  1         12  
  0         0  
  0         0  
  0         0  
  0         0  
5632 0     0   0 {
5633 0         0 return( $self->error( "Unable to unformat the number \"$num\": $e" ) );
5634 0 0 33     0 }
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         38  
  1         27  
5635             }
5636              
5637             sub _func
5638             {
5639 29     29   110 my $self = shift( @_ );
5640 29   50     193 my $func = shift( @_ ) || return( $self->error( "No function was provided." ) );
5641             ## $self->message( 3, "Arguments received are: '", join( "', '", @_ ), "'." );
5642 29         80 my $opts = {};
5643 29 100       148 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
5644 29 100       132 my $namespace = $opts->{posix} ? 'POSIX' : 'CORE';
5645 29 100       113 my $val = @_ ? shift( @_ ) : undef;
5646 29 100       143 my $expr = defined( $val ) ? "${namespace}::${func}( \$self->{_number}, $val )" : "${namespace}::${func}( \$self->{_number} )";
5647             ## $self->message( 3, "Evaluating '$expr'" );
5648 29         2371 my $res = eval( $expr );
5649             ## $self->message( 3, "Result for number '$self->{_number}' is '$res'" );
5650 29 50       183 $self->message( 3, "Error: $@" ) if( $@ );
5651 29 50       91 return( $self->pass_error( $@ ) ) if( $@ );
5652 29 50       100 return if( !defined( $res ) );
5653 29 50       154 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
5654 29 50       119 return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
5655 29         127 return( $self->clone( $res ) );
5656             }
5657              
5658             sub _set_get_prop
5659             {
5660 51469     51469   78814 my $self = shift( @_ );
5661 51469         75719 my $prop = shift( @_ );
5662 51469 100       102340 if( @_ )
5663             {
5664 3540         7850 my $val = shift( @_ );
5665 3540 100 66     8465 $val = $val->scalar if( $self->_is_object( $val ) && $val->isa( 'Module::Generic::Scalar' ) );
5666             ## $self->message( 3, "Setting value \"$val\" (", defined( $val ) ? 'defined' : 'undefined', ") for property \"$prop\"." );
5667 3540 50 66     11164 if( $val ne $self->{ $prop } || !CORE::defined( $val ) )
5668             {
5669             # $self->{ $prop } = $val;
5670 3540         9210 $self->_set_get_scalar_as_object( $prop, $val );
5671             ## If an error was set, we return nothing
5672 3540 50       9950 $self->formatter( $self->new_formatter ) || return;
5673             }
5674             }
5675             # return( $self->{ $prop } );
5676 51469         96427 return( $self->_set_get_scalar_as_object( $prop ) );
5677             }
5678              
5679             AUTOLOAD
5680             {
5681 0     0   0 my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
5682 0   0     0 my $self = shift( @_ ) || return;
5683 0   0     0 my $fmt_obj = $self->{_fmt} || return;
5684 0         0 my $code = $fmt_obj->can( $method );
5685 0 0       0 if( $code )
5686             {
5687 0         0 try
5688 0     0   0 {
5689 0         0 return( $code->( $fmt_obj, @_ ) );
5690             }
5691 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  
5692 0     0   0 {
5693 0         0 CORE::warn( $e );
5694 0         0 return;
5695 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
5696             }
5697 0         0 return;
5698             };
5699              
5700             package Module::Generic::NumberSpecial;
5701             BEGIN
5702             {
5703 6     6   58 use strict;
  6         14  
  6         145  
5704 6     6   31 use warnings;
  6         17  
  6         223  
5705 6     6   40 use parent -norequire, qw( Module::Generic::Number );
  6         15  
  6         60  
5706 5     5   1042 use overload ('""' => sub{ $_[0]->{_number} },
5707 0     0   0 '+=' => sub{ &_catchall( @_[0..2], '+' ) },
5708 0     0   0 '-=' => sub{ &_catchall( @_[0..2], '-' ) },
5709 1     1   8 '*=' => sub{ &_catchall( @_[0..2], '*' ) },
5710 0     0   0 '/=' => sub{ &_catchall( @_[0..2], '/' ) },
5711 0     0   0 '%=' => sub{ &_catchall( @_[0..2], '%' ) },
5712 0     0   0 '**=' => sub{ &_catchall( @_[0..2], '**' ) },
5713 0     0   0 '<<=' => sub{ &_catchall( @_[0..2], '<<' ) },
5714 0     0   0 '>>=' => sub{ &_catchall( @_[0..2], '>>' ) },
5715 0     0   0 'x=' => sub{ &_catchall( @_[0..2], 'x' ) },
5716 0     0   0 '.=' => sub{ &_catchall( @_[0..2], '.' ) },
5717 6         119 nomethod => \&_catchall,
5718             fallback => 1,
5719 6     6   1858 );
  6         13  
5720 6     6   1134 use Want;
  6         17  
  6         434  
5721 6     6   49 use POSIX ();
  6         14  
  6         162  
5722 6     6   3864 our( $VERSION ) = '0.1.0';
5723             };
5724              
5725             sub new
5726             {
5727 17     17   41 my $this = shift( @_ );
5728 17   66     221 return( bless( { _number => CORE::shift( @_ ) } => ( ref( $this ) || $this ) ) );
5729             }
5730              
5731 1     1   25 sub clone { return( shift->new( @_ ) ); }
5732              
5733 0     0   0 sub is_finite { return( 0 ); }
5734              
5735 0     0   0 sub is_float { return( 0 ); }
5736              
5737 0     0   0 sub is_infinite { return( 0 ); }
5738              
5739 0     0   0 sub is_int { return( 0 ); }
5740              
5741 0     0   0 sub is_nan { return( 0 ); }
5742              
5743 2     2   14 sub is_normal { return( 0 ); }
5744              
5745 0     0   0 sub length { return( CORE::length( $self->{_number} ) ); }
5746              
5747             sub _catchall
5748             {
5749 1     1   5 my( $self, $other, $swap, $op ) = @_;
5750 1 50       9 my $expr = $swap ? "$other $op $self->{_number}" : "$self->{_number} $op $other";
5751 1         74 my $res = eval( $expr );
5752             ## print( ref( $self ), "::_catchall: evaluating $expr => $res\n" );
5753 1 50       8 CORE::warn( "Error evaluating expression \"$expr\": $@" ) if( $@ );
5754 1 50       5 return if( $@ );
5755 1 50       8 return( Module::Generic::Number->new( $res ) ) if( POSIX::isnormal( $res ) );
5756 1 50       9 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
5757 0 0       0 return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
5758 0         0 return( $res );
5759             }
5760              
5761             sub _func
5762             {
5763 7     7   15 my $self = shift( @_ );
5764 7   50     22 my $func = shift( @_ ) || return( $self->error( "No function was provided." ) );
5765 7         11 my $opts = {};
5766 7 100       28 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
5767 7 100       27 my $namespace = $opts->{posix} ? 'POSIX' : 'CORE';
5768 7 100       21 my $val = @_ ? shift( @_ ) : undef;
5769 7 100       34 my $expr = defined( $val ) ? "${namespace}::${func}( $self->{_number}, $val )" : "${namespace}::${func}( $self->{_number} )";
5770 7         456 my $res = eval( $expr );
5771             ## $self->message( 3, "Error: $@" ) if( $@ );
5772             ## print( STDERR ref( $self ), "::_func -> evaluating '$expr' -> '$res'\n" );
5773 7 50       32 CORE::warn( $@ ) if( $@ );
5774 7 50       16 return if( !defined( $res ) );
5775 7 100       36 return( Module::Generic::Number->new( $res ) ) if( POSIX::isnormal( $res ) );
5776 4 50       18 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
5777 0 0       0 return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
5778 0         0 return( $res );
5779             }
5780              
5781             AUTOLOAD
5782             {
5783 0     0   0 my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
5784             ## print( STDERR "$AUTOLOAD: called for method \"$method\"\n" );
5785             ## If we are chained, return our null object, so the chain continues to work
5786 0 0       0 if( want( 'OBJECT' ) )
5787             {
5788             ## No, this is NOT a typo. rreturn() is a function of module Want
5789 0         0 print( STDERR "$AUTOLOAD: Returning the object itself (", ref( $_[0] ), ")\n" );
5790 0         0 rreturn( $_[0] );
5791             }
5792             ## Otherwise, we return infinity, whether positive or negative or NaN depending on what was set
5793             ## print( STDERR "$AUTOLOAD: returning '", $_[0]->{_number}, "'\n" );
5794 0         0 return( $_[0]->{_number} );
5795             };
5796              
5797       0     DESTROY {};
5798              
5799             ## Purpose is to allow chaining of methods when infinity is returned
5800             ## At the end of the chain, Inf or -Inf is returned
5801             package Module::Generic::Infinity;
5802             BEGIN
5803             {
5804 6     6   53 use strict;
  6         15  
  6         130  
5805 6     6   30 use warnings;
  6         13  
  6         199  
5806 6     6   45 use parent -norequire, qw( Module::Generic::NumberSpecial );
  6         14  
  6         29  
5807 6     6   588 our( $VERSION ) = '0.1.0';
5808             };
5809              
5810 1     1   5 sub is_infinite { return( 1 ); }
5811              
5812             package Module::Generic::Nan;
5813             BEGIN
5814             {
5815 6     6   38 use strict;
  6         14  
  6         116  
5816 6     6   33 use warnings;
  6         10  
  6         186  
5817 6     6   29 use parent -norequire, qw( Module::Generic::NumberSpecial );
  6         18  
  6         28  
5818 6     6   540 our( $VERSION ) = '0.1.0';
5819             };
5820              
5821 1     1   7 sub is_nan { return( 1 ); }
5822              
5823              
5824             package Module::Generic::Hash;
5825             BEGIN
5826             {
5827 6     6   35 use strict;
  6         21  
  6         128  
5828 6     6   32 use warnings::register;
  6         15  
  6         811  
5829 6     6   36 use parent -norequire, qw( Module::Generic );
  6         25  
  6         34  
5830             use overload (
5831             ## '""' => 'as_string',
5832 1     1   12 'eq' => sub { _obj_eq(@_) },
5833 1     1   6 'ne' => sub { !_obj_eq(@_) },
5834 4     4   20 '<' => sub { _obj_comp( @_, '<') },
5835 3     3   29 '>' => sub { _obj_comp( @_, '>') },
5836 1     1   5 '<=' => sub { _obj_comp( @_, '<=') },
5837 2     2   13 '>=' => sub { _obj_comp( @_, '>=') },
5838 0     0   0 '==' => sub { _obj_comp( @_, '>=') },
5839 0     0   0 '!=' => sub { _obj_comp( @_, '>=') },
5840 1     1   5 'lt' => sub { _obj_comp( @_, 'lt') },
5841 1     1   5 'gt' => sub { _obj_comp( @_, 'gt') },
5842 0     0   0 'le' => sub { _obj_comp( @_, 'le') },
5843 0     0   0 'ge' => sub { _obj_comp( @_, 'ge') },
5844 6         103 fallback => 1,
5845 6     6   1473 );
  6         15  
5846 6     6   1087 use Data::Dumper;
  6         16  
  6         340  
5847 6     6   4372 use JSON;
  6         56950  
  6         33  
5848 6     6   944 use Clone ();
  6         26  
  6         111  
5849 6     6   33 use Regexp::Common;
  6         21  
  6         52  
5850             };
5851              
5852             sub new
5853             {
5854 133     133   345 my $that = shift( @_ );
5855 133   66     535 my $class = ref( $that ) || $that;
5856 133   50     448 my $data = shift( @_ ) ||
5857             return( $that->error( "No hash was provided to initiate a $class hash object." ) );
5858 133 50       532 return( $that->error( "I was expecting an hash, but instead got '$data'." ) ) if( Scalar::Util::reftype( $data ) ne 'HASH' );
5859 133         326 my $tied = tied( %$data );
5860 133 50       351 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 );
5861 133         286 my %hash = ();
5862             ## This enables access to the hash just like a real hash while still the user an call our object methods
5863 133         1147 my $obj = tie( %hash, 'Module::Generic::TieHash', {
5864             disable => ['Module::Generic'],
5865             debug => 0,
5866             });
5867 133         492 my $self = bless( \%hash => $class );
5868 133         573 $obj->enable( 1 );
5869 133         1051 my @keys = CORE::keys( %$data );
5870 133         4091 @hash{ @keys } = @$data{ @keys };
5871 133         1195 $obj->enable( 0 );
5872 133         675 $self->SUPER::init( @_ );
5873 133         501 $obj->enable( 1 );
5874 133         674 return( $self );
5875             }
5876              
5877 1     1   5 sub as_string { return( shift->dump ); }
5878              
5879             sub clone
5880             {
5881 1     1   5 my $self = shift( @_ );
5882 1         6 $self->_tie_object->enable( 0 );
5883 1         8 my $data = $self->{data};
5884 1         32 my $clone = Clone::clone( $data );
5885 1         8 $self->_tie_object->enable( 1 );
5886 1         10 return( $self->new( $clone ) );
5887             }
5888              
5889 3     3   16 sub debug { return( shift->_internal( 'debug', '_set_get_number', @_ ) ); }
5890              
5891 2     2   622 sub defined { CORE::defined( $_[0]->{ $_[1] } ); }
5892              
5893 1     1   8 sub delete { return( CORE::delete( shift->{ shift( @_ ) } ) ); }
5894              
5895             sub dump
5896             {
5897 3     3   9 my $self = shift( @_ );
5898 3         10 return( $self->_dumper( $self ) );
5899             }
5900              
5901             sub each
5902             {
5903 1     1   4 my $self = shift( @_ );
5904 1   50     7 my $code = shift( @_ ) || return( $self->error( "No subroutine callback as provided for each" ) );
5905 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' );
5906 1         6 while( my( $k, $v ) = CORE::each( %$self ) )
5907             {
5908 4 50       17 $code->( $k, $v ) || CORE::last;
5909             }
5910 1         3 return( $self );
5911             }
5912              
5913 1     1   6 sub exists { return( CORE::exists( shift->{ shift( @_ ) } ) ); }
5914              
5915 1     1   7 sub for { return( shift->foreach( @_ ) ); }
5916              
5917             sub foreach
5918             {
5919 1     1   3 my $self = shift( @_ );
5920 1   50     5 my $code = shift( @_ ) || return( $self->error( "No subroutine callback as provided for each" ) );
5921 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' );
5922 1         4 CORE::foreach my $k ( CORE::keys( %$self ) )
5923             {
5924 4 50       1750 $code->( $k, $self->{ $k } ) || CORE::last;
5925             }
5926 1         570 return( $self );
5927             }
5928              
5929             sub json
5930             {
5931 2     2   5 my $self = shift( @_ );
5932 2         5 my $opts = {};
5933 2 100       10 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
5934 2         7 $self->_tie_object->enable( 0 );
5935 2         9 my $data = $self->{data};
5936 2         5 my $json;
5937 2 100       7 if( $opts->{pretty} )
5938             {
5939 1         51 $json = JSON->new->pretty->utf8->indent(1)->relaxed(1)->canonical(1)->allow_nonref->encode( $data );
5940             }
5941             else
5942             {
5943 1         23 $json = JSON->new->utf8->canonical(1)->allow_nonref->encode( $data );
5944             }
5945 2         14 $self->_tie_object->enable( 1 );
5946 2         8 return( Module::Generic::Scalar->new( $json ) );
5947             }
5948              
5949             # $h->keys->sort
5950 1     1   671 sub keys { return( Module::Generic::Array->new( [ CORE::keys( %{$_[0]} ) ] ) ); }
  1         8  
5951              
5952 21     21   40 sub length { return( Module::Generic::Number->new( CORE::scalar( CORE::keys( %{$_[0]} ) ) ) ); }
  21         112  
5953              
5954             sub merge
5955             {
5956 2     2   5 my $self = shift( @_ );
5957 2         6 my $hash = {};
5958 2         5 $hash = shift( @_ );
5959 2 50 33     17 return( $self->error( "No valid hash provided." ) ) if( !$hash || Scalar::Util::reftype( $hash ) ne 'HASH' );
5960             ## $self->message( 3, "Hash provided is: ", sub{ $self->dumper( $hash ) } );
5961 2         5 my $opts = {};
5962 2 100 66     11 $opts = pop( @_ ) if( @_ && ref( $_[-1] ) eq 'HASH' );
5963 2 100       7 $opts->{overwrite} = 1 unless( CORE::exists( $opts->{overwrite} ) );
5964 2         6 $self->_tie_object->enable( 0 );
5965 2         10 my $data = $self->{data};
5966 2         8 my $seen = {};
5967             local $copy = sub
5968             {
5969 4     4   7 my $this = shift( @_ );
5970 4         7 my $to = shift( @_ );
5971 4         7 my $p = {};
5972 4 100 66     19 $p = shift( @_ ) if( @_ && ref( $_[-1] ) eq 'HASH' );
5973             ## $self->message( 3, "Merging hash ", sub{ $self->dumper( $this ) }, " to hash ", sub{ $self->dumper( $to ) }, " and with parameters ", sub{ $self->dumper( $p ) } );
5974 4         13 CORE::foreach my $k ( CORE::keys( %$this ) )
5975             {
5976             # $self->message( 3, "Skipping existing property '$k'." ) if( CORE::exists( $to->{ $k } ) && !$p->{overwrite} );
5977 14 100 100     42 next if( CORE::exists( $to->{ $k } ) && !$p->{overwrite} );
5978 8 100 33     35 if( ref( $this->{ $k } ) eq 'HASH' ||
      66        
5979             ( Scalar::Util::blessed( $this->{ $k } ) && $this->{ $k }->isa( 'Module::Generic::Hash' ) ) )
5980             {
5981 2         7 my $addr = Scalar::Util::refaddr( $this->{ $k } );
5982             # $self->message( 3, "Checking if hash in property '$k' was already processed with address '$addr'." );
5983 2 50       13 if( CORE::exists( $seen->{ $addr } ) )
5984             {
5985 0         0 $to->{ $k } = $seen->{ $addr };
5986 0         0 next;
5987             }
5988             else
5989             {
5990 2 100       12 $to->{ $k } = {} unless( Scalar::Util::reftype( $to->{ $k } ) eq 'HASH' );
5991 2         10 $copy->( $this->{ $k }, $to->{ $k } );
5992             }
5993 2         7 $seen->{ $addr } = $this->{ $k };
5994             }
5995             else
5996             {
5997 6         15 $to->{ $k } = $this->{ $k };
5998             }
5999             }
6000 2         14 };
6001             ## $self->message( 3, "Propagating hash ", sub{ $self->dumper( $hash ) }, " to hash ", sub{ $self->dumper( $data ) } );
6002 2         7 $copy->( $hash, $data, $opts );
6003 2         6 $self->_tie_object->enable( 1 );
6004 2         26 return( $self );
6005             }
6006              
6007 0     0   0 sub reset { %{$_[0]} = () };
  0         0  
6008              
6009 0     0   0 sub undef { %{$_[0]} = () };
  0         0  
6010              
6011             sub values
6012             {
6013 1     1   4 my $self = shift( @_ );
6014 1         2 my $code;
6015 1 50 33     10 $code = shift( @_ ) if( @_ && ref( $_[0] ) eq 'CODE' );
6016 1         4 my $opts = {};
6017 1 50       8 $opts = pop( @_ ) if( Scalar::Util::reftype( $_[-1] ) eq 'HASH' );
6018 1 50       4 if( $code )
6019             {
6020 1 50       3 if( $opts->{sort} )
6021             {
6022 1         8 return( Module::Generic::Array->new( [ CORE::map( $code->( $_ ), CORE::sort( CORE::values( %$self ) ) ) ] ) );
6023             }
6024             else
6025             {
6026 0         0 return( Module::Generic::Array->new( [ CORE::map( $code->( $_ ), CORE::values( %$self ) ) ] ) );
6027             }
6028             }
6029             else
6030             {
6031 0 0       0 if( $opts->{sort} )
6032             {
6033 0         0 return( Module::Generic::Array->new( [ CORE::sort( CORE::values( %$self ) ) ] ) );
6034             }
6035             else
6036             {
6037 0         0 return( Module::Generic::Array->new( [ CORE::values( %$self ) ] ) );
6038             }
6039             }
6040             }
6041              
6042             # sub _dumper
6043             # {
6044             # my $self = shift( @_ );
6045             # if( !$self->{_dumper} )
6046             # {
6047             # my $d = Data::Dumper->new;
6048             # $d->Indent( 1 );
6049             # $d->Useqq( 1 );
6050             # $d->Terse( 1 );
6051             # $d->Sortkeys( 1 );
6052             # $self->{_dumper} = $d;
6053             # }
6054             # return( $self->{_dumper}->Dumper( @_ ) );
6055             # }
6056             #
6057             sub _dumper
6058             {
6059 5     5   11 my $self = shift( @_ );
6060 5         12 $self->_tie_object->enable( 0 );
6061 5         26 my $data = $self->{data};
6062 5         40 my $d = Data::Dumper->new( [ $data ] );
6063 5         224 $d->Indent( 1 );
6064 5         85 $d->Useqq( 1 );
6065 5         40 $d->Terse( 1 );
6066 5         36 $d->Sortkeys( 1 );
6067             # $d->Freezer( '' );
6068 5         40 $d->Bless( '' );
6069             # return( $d->Dump );
6070 5         38 my $str = $d->Dump;
6071 5         298 $self->_tie_object->enable( 1 );
6072 5         56 return( $str );
6073             }
6074              
6075             sub _internal
6076             {
6077 3     3   10 my $self = shift( @_ );
6078 3         8 my $field = shift( @_ );
6079 3         7 my $meth = shift( @_ );
6080             # print( STDERR ref( $self ), "::_internal -> Caling method '$meth' for field '$field' with value '", join( "', '", @_ ), "'\n" );
6081 3         13 $self->_tie_object->enable( 0 );
6082 3         74 my( @resA, $resB );
6083 3 50       12 if( wantarray )
6084             {
6085 0         0 @resA = $self->$meth( $field, @_ );
6086             # $self->message( "Resturn list value is: '@resA'" );
6087             }
6088             else
6089             {
6090 3         23 $resB = $self->$meth( $field, @_ );
6091             # $self->message( "Resturn scalar value is: '$resB'" );
6092             }
6093 3         11 $self->_tie_object->enable( 1 );
6094 3 50       23 return( wantarray ? @resA : $resB );
6095             }
6096              
6097             sub _obj_comp
6098             {
6099 12     12   48 my( $self, $other, $swap, $op ) = @_;
6100 12         28 my( $lA, $lB );
6101 12         46 $lA = $self->length;
6102 12 100 66     130 if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Hash' ) )
    50          
6103             {
6104 7         27 $lB = $other->length;
6105             }
6106             elsif( $other =~ /^$RE{num}{real}$/ )
6107             {
6108 5         776 $lB = $other;
6109             }
6110             else
6111             {
6112 0         0 return;
6113             }
6114 12 100       111 my $expr = $swap ? "$lB $op $lA" : "$lA $op $lB";
6115 12         1148 return( eval( $expr ) );
6116             }
6117              
6118 0     0   0 sub _printer { return( shift->printer( @_ ) ); }
6119              
6120             sub _obj_eq
6121             {
6122 6     6   961612 no overloading;
  6         22  
  6         1133  
6123 2     2   6 my $self = shift( @_ );
6124 2         5 my $other = shift( @_ );
6125 2         9 my $strA = $self->_dumper( $self );
6126 2         6 my $strB;
6127 2 50 33     19 if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Hash' ) )
    0          
6128             {
6129 2         97 $strB = $other->dump;
6130             }
6131             elsif( Scalar::Util::reftype( $other ) eq 'HASH' )
6132             {
6133 0         0 $strB = $self->_dumper( $other )
6134             }
6135             else
6136             {
6137 0         0 return( 0 );
6138             }
6139 2         15 return( $strA eq $strB );
6140             }
6141              
6142             sub _tie_object
6143             {
6144 26     26   48 my $self = shift( @_ );
6145 26         111 return( tied( %$self ) );
6146             }
6147              
6148             package Module::Generic::TieHash;
6149             BEGIN
6150             {
6151 6     6   50 use strict;
  6         15  
  6         150  
6152 6     6   35 use warnings::register;
  6         16  
  6         933  
6153 6     6   45 use parent -norequire, qw( Module::Generic );
  6         19  
  6         65  
6154 6     6   344 use Scalar::Util ();
  6         20  
  6         161  
6155 6     6   4335 our( $VERSION ) = '0.1.0';
6156             };
6157              
6158             sub TIEHASH
6159             {
6160 133     133   337 my $self = shift( @_ );
6161 133         318 my $opts = {};
6162 133 50       557 $opts = shift( @_ ) if( @_ );
6163 133 50       560 if( Scalar::Util::reftype( $opts ) ne 'HASH' )
6164             {
6165 0 0       0 warn( "Parameters provided ($opts) is not an hash reference.\n" ) if( $self->_warnings_is_enabled );
6166 0         0 return;
6167             }
6168 133         294 my $disable = [];
6169 133 50       628 $disable = $opts->{disable} if( Scalar::Util::reftype( $opts->{disable} ) );
6170 133         302 my $list = {};
6171 133         600 @$list{ @$disable } = ( 1 ) x scalar( @$disable );
6172             my $hash =
6173             {
6174             ## The caller sets this to its class, so we can differentiate calls from inside and outside our caller's package
6175             disable => $list,
6176             debug => $opts->{debug},
6177             ## When disabled, the Tie::Hash system will return hash key values directly under $self instead of $self->{data}
6178             ## Disabled by default so the new() method can access its setup data directly under $self
6179             ## Then new() can call enable to active it
6180 133         688 enable => 0,
6181             ## Where to store the actual hash data
6182             data => {},
6183             };
6184 133   33     594 my $class = ref( $self ) || $self;
6185 133         510 return( bless( $hash => $class ) );
6186             }
6187              
6188             sub CLEAR
6189             {
6190 0     0   0 my $self = shift( @_ );
6191 0         0 my $data = $self->{data};
6192 0         0 %$data = ();
6193             }
6194              
6195             sub DELETE
6196             {
6197 1     1   3 my $self = shift( @_ );
6198 1         2 my $data = $self->{data};
6199 1         3 my $key = shift( @_ );
6200 1         3 my $caller = caller;
6201 1 50 33     3 if( $self->_exclude( $caller ) || !$self->{enable} )
6202             # if( !$self->{enable} )
6203             {
6204 0         0 CORE::delete( $self->{ $key } );
6205             }
6206             else
6207             {
6208 1         6 CORE::delete( $data->{ $key } );
6209             }
6210             }
6211              
6212             sub EXISTS
6213             {
6214 3     3   10 my $self = shift( @_ );
6215 3         7 my $data = $self->{data};
6216 3         8 my $key = shift( @_ );
6217 3         7 my $caller = caller;
6218 3 50 33     10 if( $self->_exclude( $caller ) || !$self->{enable} )
6219             # if( !$self->{enable} )
6220             {
6221 0         0 CORE::exists( $self->{ $key } );
6222             }
6223             else
6224             {
6225 3         27 CORE::exists( $data->{ $key } );
6226             }
6227             }
6228              
6229             sub FETCH
6230             {
6231 566     566   1051 my $self = shift( @_ );
6232 566         859 my $data = $self->{data};
6233 566         926 my $key = shift( @_ );
6234 566         1018 my $caller = caller;
6235             ## print( STDERR "FETCH($caller)[enable=$self->{enable}] <- '$key''\n" );
6236 566 100 100     997 if( $self->_exclude( $caller ) || !$self->{enable} )
6237             # if( !$self->{enable} )
6238             {
6239             #print( STDERR "FETCH($caller)[owner calling, enable=$self->{enable}] <- '$key' <- '$self->{$key}'\n" );
6240 548         2099 return( $self->{ $key } )
6241             }
6242             else
6243             {
6244             #print( STDERR "FETCH($caller)[enable=$self->{enable}] <- '$key' <- '$data->{$key}'\n" );
6245 18         103 return( $data->{ $key } );
6246             }
6247             }
6248              
6249             sub FIRSTKEY
6250             {
6251 26     26   58 my $self = shift( @_ );
6252 26         70 my $data = $self->{data};
6253 26         58 my @keys = ();
6254 26         63 my $caller = caller;
6255 26 50 33     81 if( $self->_exclude( $caller ) || !$self->{enable} )
6256             # if( !$self->{enable} )
6257             {
6258 0         0 @keys = keys( %$self );
6259             }
6260             else
6261             {
6262 26         118 @keys = keys( %$data );
6263             }
6264 26         80 $self->{ITERATOR} = \@keys;
6265 26         118 return( shift( @keys ) );
6266             }
6267              
6268             sub NEXTKEY
6269             {
6270 88     88   2458 my $self = shift( @_ );
6271 88         134 my $data = $self->{data};
6272 88 50       203 my $keys = ref( $self->{ITERATOR} ) ? $self->{ITERATOR} : [];
6273 88         250 return( shift( @$keys ) );
6274             }
6275              
6276             sub SCALAR
6277             {
6278 0     0   0 my $self = shift( @_ );
6279 0         0 my $data = $self->{data};
6280 0         0 my $caller = caller;
6281 0 0 0     0 if( $self->_exclude( $caller ) || !$self->{enable} )
6282             # if( !$self->{enable} )
6283             {
6284 0         0 return( scalar( keys( %$self ) ) );
6285             }
6286             else
6287             {
6288 0         0 return( scalar( keys( %$data ) ) );
6289             }
6290             }
6291              
6292             sub STORE
6293             {
6294 3916     3916   5985 my $self = shift( @_ );
6295 3916         5572 my $data = $self->{data};
6296 3916         6590 my( $key, $val ) = @_;
6297 3916         5915 my $caller = caller;
6298 3916 100 66     6401 if( $self->_exclude( $caller ) || !$self->{enable} )
6299             # if( !$self->{enable} )
6300             {
6301             #print( STDERR "STORE($caller)[owner calling] <- '$key' -> '$val'\n" );
6302 800         2454 $self->{ $key } = $val;
6303             }
6304             else
6305             {
6306             #print( STDERR "STORE($caller)[enable=$self->{enable}] <- '$key' -> '$val'\n" );
6307 3116         11033 $data->{ $key } = $val;
6308             }
6309             }
6310              
6311 425     425   1204 sub enable { return( shift->_set_get_boolean( 'enable', @_ ) ); }
6312              
6313             sub _exclude
6314             {
6315 4512     4512   5923 my $self = shift( @_ );
6316 4512         5834 my $caller = shift( @_ );
6317             ## $self->message( 3, "Disable hash contains: ", sub{ $self->dump( $self->{disable} ) });
6318 4512         13023 return( CORE::exists( $self->{disable}->{ $caller } ) );
6319             }
6320              
6321             package Module::Generic::Tie;
6322             BEGIN
6323             {
6324 6     6   53 use Tie::Hash;
  6         22  
  6         373  
6325 6     6   123 our( @ISA ) = qw( Tie::Hash );
6326 6         6228 our( $VERSION ) = '0.1.0';
6327             };
6328              
6329             sub TIEHASH
6330             {
6331 0     0     my $self = shift( @_ );
6332 0           my $pkg = ( caller() )[ 0 ];
6333             ## print( STDERR __PACKAGE__ . "::TIEHASH() called with following arguments: '", join( ', ', @_ ), "'.\n" );
6334 0           my %arg = ( @_ );
6335 0           my $auth = [ $pkg, __PACKAGE__ ];
6336 0 0         if( $arg{ 'pkg' } )
6337             {
6338 0           my $ok = delete( $arg{ 'pkg' } );
6339 0 0         push( @$auth, ref( $ok ) eq 'ARRAY' ? @$ok : $ok );
6340             }
6341 0           my $priv = { 'pkg' => $auth };
6342 0           my $data = { '__priv__' => $priv };
6343 0           my @keys = keys( %arg );
6344 0           @$priv{ @keys } = @arg{ @keys };
6345 0   0       return( bless( $data, ref( $self ) || $self ) );
6346             }
6347              
6348             sub CLEAR
6349             {
6350 0     0     my $self = shift( @_ );
6351 0           my $pkg = ( caller() )[ 0 ];
6352             ## print( $err __PACKAGE__ . "::CLEAR() called by package '$pkg'.\n" );
6353 0           my $data = $self->{ '__priv__' };
6354 0 0 0       return() if( $data->{ 'readonly' } && $pkg ne __PACKAGE__ );
6355             ## if( $data->{ 'readonly' } || $data->{ 'protect' } )
6356 0 0         if( !( $data->{ 'perms' } & 2 ) )
6357             {
6358 0 0         return if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
  0            
6359             }
6360 0           my $key = $self->FIRSTKEY( @_ );
6361 0           my @keys = ();
6362 0           while( defined( $key ) )
6363             {
6364 0           push( @keys, $key );
6365 0           $key = $self->NEXTKEY( @_, $key );
6366             }
6367 0           foreach $key ( @keys )
6368             {
6369 0           $self->DELETE( @_, $key );
6370             }
6371             }
6372              
6373             sub DELETE
6374             {
6375 0     0     my $self = shift( @_ );
6376 0           my $pkg = ( caller() )[ 0 ];
6377 0 0         $pkg = ( caller( 1 ) )[ 0 ] if( $pkg eq 'Module::Generic' );
6378             ## print( STDERR __PACKAGE__ . "::DELETE() package '$pkg' tries to delete '$_[ 0 ]'\n" );
6379 0           my $data = $self->{ '__priv__' };
6380 0 0 0       return if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ );
6381             ## if( $data->{ 'readonly' } || $data->{ 'protect' } )
6382 0 0         if( !( $data->{ 'perms' } & 2 ) )
6383             {
6384 0 0         return() if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
  0            
6385             }
6386 0           return( delete( $self->{ shift( @_ ) } ) );
6387             }
6388              
6389             sub EXISTS
6390             {
6391 0     0     my $self = shift( @_ );
6392             ## print( STDERR __PACKAGE__ . "::EXISTS() called from package '", ( caller() )[ 0 ], "'.\n" );
6393 0 0 0       return( 0 ) if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ );
6394 0           my $data = $self->{ '__priv__' };
6395 0 0         if( !( $data->{ 'perms' } & 4 ) )
6396             {
6397 0           my $pkg = ( caller() )[ 0 ];
6398 0 0         return( 0 ) if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
  0            
6399             }
6400             ## print( STDERR __PACKAGE__ . "::EXISTS() returns: '", exists( $self->{ $_[ 0 ] } ), "'.\n" );
6401 0           return( exists( $self->{ shift( @_ ) } ) );
6402             }
6403              
6404             sub FETCH
6405             {
6406             ## return( shift->{ shift( @_ ) } );
6407             ## print( STDERR __PACKAGE__ . "::FETCH() called with arguments: '", join( ', ', @_ ), "'.\n" );
6408 0     0     my $self = shift( @_ );
6409             ## This is a hidden entry, we return nothing
6410 0 0 0       return() if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ );
6411 0           my $data = $self->{ '__priv__' };
6412             ## If we have to protect our object, we hide its inner content if our caller is not our creator
6413             ## if( $data->{ 'protect' } )
6414 0 0         if( !( $data->{ 'perms' } & 4 ) )
6415             {
6416 0           my $pkg = ( caller() )[ 0 ];
6417             ## print( STDERR __PACKAGE__ . "::FETCH() package '$pkg' wants to fetch the value of '$_[ 0 ]'\n" );
6418 0 0         return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
  0            
6419             }
6420 0           return( $self->{ shift( @_ ) } );
6421             }
6422              
6423             sub FIRSTKEY
6424             {
6425 0     0     my $self = shift( @_ );
6426             ## my $a = scalar( keys( %$hash ) );
6427             ## return( each( %$hash ) );
6428 0           my $data = $self->{ '__priv__' };
6429             ## if( $data->{ 'protect' } )
6430 0 0         if( !( $data->{ 'perms' } & 4 ) )
6431             {
6432 0           my $pkg = ( caller( 0 ) )[ 0 ];
6433             ## print( STDERR __PACKAGE__ . "::FIRSTKEY() called by package '$pkg'\n" );
6434 0 0         return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
  0            
6435             }
6436             ## print( STDERR __PACKAGE__ . "::FIRSTKEY(): gathering object's keys.\n" );
6437 0           my( @keys ) = grep( !/^__priv__$/, keys( %$self ) );
6438 0           $self->{ '__priv__' }->{ 'ITERATOR' } = \@keys;
6439             ## print( STDERR __PACKAGE__ . "::FIRSTKEY(): keys are: '", join( ', ', @keys ), "'.\n" );
6440             ## print( STDERR __PACKAGE__ . "::FIRSTKEY() returns '$keys[ 0 ]'.\n" );
6441 0           return( shift( @keys ) );
6442             }
6443              
6444             sub NEXTKEY
6445             {
6446 0     0     my $self = shift( @_ );
6447             ## return( each( %$hash ) );
6448 0           my $data = $self->{ '__priv__' };
6449             ## if( $data->{ 'protect' } )
6450 0 0         if( !( $data->{ 'perms' } & 4 ) )
6451             {
6452 0           my $pkg = ( caller( 0 ) )[ 0 ];
6453             ## print( STDERR __PACKAGE__ . "::NEXTKEY() called by package '$pkg'\n" );
6454 0 0         return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
  0            
6455             }
6456 0           my $keys = $self->{ '__priv__' }->{ 'ITERATOR' };
6457             ## print( STDERR __PACKAGE__ . "::NEXTKEY() returns '$_[ 0 ]'.\n" );
6458 0           return( shift( @$keys ) );
6459             }
6460              
6461             sub STORE
6462             {
6463 0     0     my $self = shift( @_ );
6464 0 0         return() if( $_[ 0 ] eq '__priv__' );
6465 0           my $data = $self->{ '__priv__' };
6466             #if( $data->{ 'readonly' } ||
6467             # $data->{ 'protect' } )
6468 0 0         if( !( $data->{ 'perms' } & 2 ) )
6469             {
6470 0           my $pkg = ( caller() )[ 0 ];
6471 0 0         $pkg = ( caller( 1 ) )[ 0 ] if( $pkg eq 'Module::Generic' );
6472             ## print( STDERR __PACKAGE__ . "::STORE() package '$pkg' is trying to STORE the value '$_[ 1 ]' to key '$_[ 0 ]'\n" );
6473 0 0         return if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
  0            
6474             }
6475             ## print( STDERR __PACKAGE__ . "::STORE() ", ( caller() )[ 0 ], " is storing value '$_[ 1 ]' for key '$_[ 0 ]'.\n" );
6476             ## $self->{ shift( @_ ) } = shift( @_ );
6477 0           $self->{ $_[ 0 ] } = $_[ 1 ];
6478             ## print( STDERR __PACKAGE__ . "::STORE(): object '$self' now contains: '", join( ', ', map{ "$_, $self->{ $_ }" } keys( %$self ) ), "'.\n" );
6479             }
6480              
6481             1;
6482              
6483             __END__
6484              
6485             =encoding utf8
6486              
6487             =head1 NAME
6488              
6489             Module::Generic - Generic Module to inherit from
6490              
6491             =head1 SYNOPSIS
6492              
6493             package MyModule;
6494             BEGIN
6495             {
6496             use strict;
6497             use Module::Generic;
6498             our( @ISA ) = qw( Module::Generic );
6499             };
6500              
6501             =head1 VERSION
6502              
6503             v0.12.15
6504              
6505             =head1 DESCRIPTION
6506              
6507             L<Module::Generic> as its name says it all, is a generic module to inherit from.
6508             It is designed to provide a useful framework and speed up coding and debugging.
6509             It contains standard and support methods that may be superseded by your the module using
6510             L<Module::Generic>.
6511              
6512             As an added benefit, it also contains a powerfull AUTOLOAD transforming any hash
6513             object key into dynamic methods and also recognize the dynamic routine a la AutoLoader
6514             from which I have shamelessly copied in the AUTOLOAD code. The reason is that while
6515             C<AutoLoader> provides the user with a convenient AUTOLOAD, I wanted a way to also
6516             keep the functionnality of L<Module::Generic> AUTOLOAD that were not included in
6517             C<AutoLoader>. So the only solution was a merger.
6518              
6519             =head1 METHODS
6520              
6521             =head2 import
6522              
6523             B<import>() is used for the AutoLoader mechanism and hence is not a public method.
6524             It is just mentionned here for info only.
6525              
6526             =head2 new
6527              
6528             B<new> will create a new object for the package, pass any argument it might receive
6529             to the special standard routine B<init> that I<must> exist.
6530             Then it returns what returns L</"init">.
6531              
6532             To protect object inner content from sneaking by third party, you can declare the
6533             package global variable I<OBJECT_PERMS> and give it a Unix permission, but only 1 digit.
6534             It will then work just like Unix permission. That is, if permission is 7, then only the
6535             module who generated the object may read/write content of the object. However, if
6536             you set 5, the, other may look into the content of the object, but may not modify it.
6537             7, as you would have guessed, allow other to modify the content of an object.
6538             If I<OBJECT_PERMS> is not defined, permissions system is not activated and hence anyone
6539             may access and possibly modify the content of your object.
6540              
6541             If the module runs under mod_perl, it is recognised and a clean up registered routine is
6542             declared to Apache to clean up the content of the object.
6543              
6544             =head2 as_hash
6545              
6546             This will recursively transform the object into an hash suitable to be encoded in json.
6547              
6548             It does this by calling each method of the object and build an hash reference with the
6549             method name as the key and the method returned value as the value.
6550              
6551             If the method returned value is an object, it will call its L</"as_hash"> method if it supports it.
6552              
6553             It returns the hash reference built
6554              
6555             =head2 clear_error
6556              
6557             Clear all error from the object and from the available global variable C<$ERROR>.
6558              
6559             This is a handy method to use at the beginning of other methods of calling package,
6560             so the end user may do a test such as:
6561              
6562             $obj->some_method( 'some arguments' );
6563             die( $obj->error() ) if( $obj->error() );
6564              
6565             ## some_method() would then contain something like:
6566             sub some_method
6567             {
6568             my $self = shift( @_ );
6569             ## Clear all previous error, so we may set our own later one eventually
6570             $self->clear_error();
6571             ## ...
6572             }
6573              
6574             This way the end user may be sure that if C<$obj->error()> returns true something
6575             wrong has occured.
6576              
6577             =head2 clone
6578              
6579             Clone the current object if it is of type hash or array reference. It returns an error if the type is neither.
6580              
6581             It returns the clone.
6582              
6583             =head2 colour_closest
6584              
6585             Provided with a colour, this returns the closest standard one supported by terminal.
6586              
6587             A colour provided can be a colour name, or a 9 digits rgb value or an hexadecimal value
6588              
6589             =head2 colour_format
6590              
6591             Provided with a hash reference of parameters, this will return a string properly formatted to display colours on the command line.
6592              
6593             Parameters are:
6594              
6595             =over 4
6596              
6597             =item I<text> or I<message>
6598              
6599             This is the text to be formatted in colour.
6600              
6601             =item I<bgcolour> or I<bgcolor> or I<bg_colour> or I<bg_color>
6602              
6603             The value for the background colour.
6604              
6605             =item I<colour> or I<color> or I<fg_colour> or I<fg_color> or I<fgcolour> or I<fgcolor>
6606              
6607             The value for the foreground colour.
6608              
6609             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)>
6610              
6611             A colour can be preceded by the words C<light> or C<bright> to provide slightly lighter colour where supported.
6612              
6613             Similarly, if an rgba value is provided, and the opacity is less than 1, this is equivalent to using the keyword C<light>
6614              
6615             It returns the text properly formatted to be outputted in a terminal.
6616              
6617             =item I<style>
6618              
6619             The possible values are: I<bold>, I<italic>, I<underline>, I<blink>, I<reverse>, I<conceal>, I<strike>
6620              
6621             =back
6622              
6623             =head2 colour_parse
6624              
6625             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:
6626              
6627             $self->colour_parse( "And {style => 'i|b', color => green}what about{/} {style => 'blink', color => yellow}me{/} ?" );
6628              
6629             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).
6630              
6631             Another way is:
6632              
6633             $self->colour_parse( "And {bold light red on white}what about{/} {underline yellow}me too{/} ?" );
6634              
6635             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.
6636              
6637             $self->colour_parse( "Hello {bold red on white}everyone! This is {underline rgb(0,0,255)}embedded{/}{/} text..." );
6638              
6639             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
6640              
6641             The idea for this syntax, not the code, is taken from L<Term::ANSIColor>
6642              
6643             =head2 coloured
6644              
6645             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:
6646              
6647             print( $o->coloured( 'bold white on red', "Hello it's me!\n" ) );
6648              
6649             A colour can be expressed as a rgb, such as :
6650              
6651             print( $o->coloured( 'underline rgb( 0, 0, 255 ) on white', "Hello everyone!" ), "\n" );
6652              
6653             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 :
6654              
6655             print( $o->coloured( 'underline rgba(255, 0, 0, 0.5)', "Hello everyone!" ), "\n" );
6656              
6657             =head2 debug
6658              
6659             Set or get the debug level. This takes and return an integer.
6660              
6661             Based on the value, L</"message"> will or will not print out messages. For example :
6662              
6663             $self->debug( 2 );
6664             $self->message( 2, "Debugging message here." );
6665              
6666             Since C<2> used in L</"message"> is equal to the debug value, the debugging message is printed.
6667              
6668             If the debug value is switched to 1, the message will be silenced.
6669              
6670             =head2 dump
6671              
6672             Provided with some data, this will return a string representation of the data formatted by L<Data::Printer>
6673              
6674             =head2 dump_print
6675              
6676             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.
6677              
6678             =head2 dumper
6679              
6680             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.
6681              
6682             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.
6683              
6684             =head2 printer
6685              
6686             Same as L</"dumper">, but using L<Data::Printer> to format the data.
6687              
6688             =head2 dumpto_printer
6689              
6690             Same as L</"dump_print"> above that is an alias of this method.
6691              
6692             =head2 dumpto_dumper
6693              
6694             Same as L</"dumpto_printer"> above, but using L<Data::Dumper>
6695              
6696             =head2 error
6697              
6698             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:
6699              
6700             if( $some_condition )
6701             {
6702             return( $self->error( "Some error." ) );
6703             }
6704              
6705             Note that you do not have to worry about a trailing line feed sequence.
6706             B<error>() takes care of it.
6707              
6708             The script calling your module could write calls to your module methods like this:
6709              
6710             my $cust_name = $object->customer->name ||
6711             die( "Got an error in file ", $object->error->file, " at line ", $object->error->line, ": ", $object->error->trace, "\n" );
6712             # or simply:
6713             my $cust_name = $object->customer->name ||
6714             die( "Got an error: ", $object->error, "\n" );
6715              
6716             Note also that by calling B<error>() it will not clear the current error. For that
6717             you have to call B<clear_error>() explicitly.
6718              
6719             Also, when an error is set, the global variable I<ERROR> is set accordingly. This is
6720             especially usefull, when your initiating an object and that an error occured. At that
6721             time, since the object could not be initiated, the end user can not use the object to
6722             get the error message, and then can get it using the global module variable
6723             I<ERROR>, for example:
6724              
6725             my $obj = Some::Package->new ||
6726             die( $Some::Package::ERROR, "\n" );
6727              
6728             If the caller has disabled warnings using the pragma C<no warnings>, L</"error"> will
6729             respect it and not call B<warn>. Calling B<warn> can also be silenced if the object has
6730             a property I<quiet> set to true.
6731              
6732             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">
6733              
6734             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.
6735              
6736             If an Apache2 modperl log handler has been set, this will also be called to log the error.
6737              
6738             If the object property I<fatal> is set to true, this will call die instead of L<perlfunc/"warn">.
6739              
6740             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 :
6741              
6742             my $o = My::Package->new;
6743             my $total $o->get_customer(10)->products->total || die( $o->error, "\n" );
6744              
6745             Assuming this method here C<get_customer> returns an error, the chaining will continue, but produce nothing and ultimately returns undef.
6746              
6747             =head2 errors
6748              
6749             Used by B<error>() to store the error sent to him for history.
6750              
6751             It returns an array of all error that have occured in lsit context, and the last
6752             error in scalar context.
6753              
6754             =head2 errstr
6755              
6756             Set/get the error string, period. It does not produce any warning like B<error> would do.
6757              
6758             =head2 get
6759              
6760             Uset to get an object data key value:
6761              
6762             $obj->set( 'verbose' => 1, 'debug' => 0 );
6763             ## ...
6764             my $verbose = $obj->get( 'verbose' );
6765             my @vals = $obj->get( qw( verbose debug ) );
6766             print( $out "Verbose level is $vals[ 0 ] and debug level is $vals[ 1 ]\n" );
6767              
6768             This is no more needed, as it has been more conveniently bypassed by the AUTOLOAD
6769             generic routine with chich you may say:
6770              
6771             $obj->verbose( 1 );
6772             $obj->debug( 0 );
6773             ## ...
6774             my $verbose = $obj->verbose();
6775              
6776             Much better, no?
6777              
6778             =head2 init
6779              
6780             This is the L</"new"> package object initializer. It is called by L</"new">
6781             and is used to set up any parameter provided in a hash like fashion:
6782              
6783             my $obj My::Module->new( 'verbose' => 1, 'debug' => 0 );
6784              
6785             You may want to superseed L</"init"> to have suit your needs.
6786              
6787             L</"init"> needs to returns the object it received in the first place or an error if
6788             something went wrong, such as:
6789              
6790             sub init
6791             {
6792             my $self = shift( @_ );
6793             my $dbh = DB::Object->connect() ||
6794             return( $self->error( "Unable to connect to database server." ) );
6795             $self->{ 'dbh' } = $dbh;
6796             return( $self );
6797             }
6798              
6799             In this example, using L</"error"> will set the global variable C<$ERROR> that will
6800             contain the error, so user can say:
6801              
6802             my $obj = My::Module->new() || die( $My::Module::ERROR );
6803              
6804             If the global variable I<VERBOSE>, I<DEBUG>, I<VERSION> are defined in the module,
6805             and that they do not exist as an object key, they will be set automatically and
6806             accordingly to those global variable.
6807              
6808             The supported data type of the object generated by the L</"new"> method may either be
6809             a hash reference or a glob reference. Those supported data types may very well be
6810             extended to an array reference in a near future.
6811              
6812             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:
6813              
6814             sub init
6815             {
6816             my $self = shift( @_ );
6817             $self->{_init_strict} = 1;
6818             $self->{products} = [];
6819             return( $self->SUPER::init( @_ ) );
6820             }
6821              
6822             Then, if init is called like this:
6823              
6824             $object->init({ products => $some_string_but_not_array }) || die( $object->error, "\n" );
6825              
6826             This would cause your script to die, because C<products> value is a string and not an array reference.
6827              
6828             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 :
6829              
6830             sub init
6831             {
6832             my $self = shift( @_ );
6833             return( $self->SUPER::init( @_ ) );
6834             }
6835              
6836             Then, if init is called like this:
6837              
6838             $object->init( products => $array_ref, first_name => 'John', last_name => 'Doe' });
6839              
6840             The object would then contain the properties I<products>, I<first_name> and I<last_name> and can be accessed as methods, such as :
6841              
6842             my $fname = $object->first_name;
6843              
6844             =head2 log_handler
6845              
6846             Provided a reference to a sub routine or an anonymous sub routine, this will set the handler that is called by L</"message">
6847              
6848             It returns the current value set.
6849              
6850             =head2 message
6851              
6852             B<message>() is used to display verbose/debug output. It will display something
6853             to the extend that either I<verbose> or I<debug> are toggled on.
6854              
6855             If so, all debugging message will be prepended by C<## > to highlight the fact
6856             that this is a debugging message.
6857              
6858             Addionally, if a number is provided as first argument to B<message>(), it will be
6859             treated as the minimum required level of debugness. So, if the current debug
6860             state level is not equal or superior to the one provided as first argument, the
6861             message will not be displayed.
6862              
6863             For example:
6864              
6865             ## Set debugness to 3
6866             $obj->debug( 3 );
6867             ## This message will not be printed
6868             $obj->message( 4, "Some detailed debugging stuff that we might not want." );
6869             ## This will be displayed
6870             $obj->message( 2, "Some more common message we want the user to see." );
6871              
6872             Now, why debug is used and not verbose level? Well, because mostly, the verbose level
6873             needs only to be true, that is equal to 1 to be efficient. You do not really need to have
6874             a verbose level greater than 1. However, the debug level usually may have various level.
6875              
6876             Also, the text provided can be separated by comma, and even be a code reference, such as:
6877              
6878             $self->message( 2, "I have found", "something weird here:", sub{ $self->dumper( $data ) } );
6879              
6880             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:
6881              
6882             $self->noexec->message( 2, "I have found", "something weird here:", sub{ $self->dumper( $data ) } );
6883              
6884             =head2 message_colour
6885              
6886             This is the same as L</"message">, except this will check for colour formatting, which
6887             L</"message"> does not do. For example:
6888              
6889             $self->message_colour( 3, "And {bold light white on red}what about{/} {underline green}me again{/} ?" );
6890              
6891             L</"message_colour"> can also be called as B<message_color>
6892              
6893             See also L</"colour_format"> and L</"colour_parse">
6894              
6895             =head2 messagef
6896              
6897             This works like L<perlfunc/"sprintf">, so provided with a format and a list of arguments, this print out the message. For example :
6898              
6899             $self->messagef( 1, "Customer name is %s", $cust->name );
6900              
6901             Where 1 is the debug level set with L</"debug">
6902              
6903             =head2 message_check
6904              
6905             This is called by L</"message">
6906              
6907             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.
6908              
6909             =head2 message_log
6910              
6911             This is called from L</"message">.
6912              
6913             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.
6914              
6915             If no file handle is set, this returns undef, other it returns the value from C<$io->print>
6916              
6917             =head2 message_log_io
6918              
6919             Set or get the message log file handle. If set, L</"message_log"> will use it to print messages received from L</"message">
6920              
6921             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.
6922              
6923             It returns the current log file handle, if any.
6924              
6925             =head2 message_switch
6926              
6927             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">
6928              
6929             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.
6930              
6931             =head2 noexec
6932              
6933             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:
6934              
6935             sub hello
6936             {
6937             return( "Hello !" );
6938             }
6939              
6940             And in your code, you write:
6941              
6942             $self->message( 2, "Someone said: ", \&hello );
6943              
6944             If I<_msg_no_exec_sub> is set to false (by default), then the above would print out the following message:
6945              
6946             Someone said Hello !
6947              
6948             But if I<_msg_no_exec_sub> is set to true, then the same would rather produce the following :
6949              
6950             Someone said CODE(0x7f9103801700)
6951              
6952             =head2 pass_error
6953              
6954             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.
6955              
6956             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 :
6957              
6958             sub getCustomerInfo
6959             {
6960             my $self = shift( @_ );
6961             # Maybe a LWP::UserAgent sub class?
6962             my $client = $self->lwp_client_object;
6963             my $res = $client->get( $remote_api_endpoint ) ||
6964             return( $self->pass_error( $client->error ) );
6965             }
6966              
6967             Then :
6968              
6969             my $client_info = $object->getCustomerInfo || die( $object->error, "\n" );
6970              
6971             Which would return the http client error that has been passed along
6972              
6973             =head2 quiet
6974              
6975             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.
6976              
6977             =head2 save
6978              
6979             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>.
6980              
6981             This is designed to simplify the tedious task of write to files.
6982              
6983             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.
6984              
6985             =head2 set
6986              
6987             B<set>() sets object inner data type and takes arguments in a hash like fashion:
6988              
6989             $obj->set( 'verbose' => 1, 'debug' => 0 );
6990              
6991             =head2 subclasses
6992              
6993             Provided with a I<CLASS> value, this method try to guess all the existing sub classes of the provided I<CLASS>.
6994              
6995             If I<CLASS> is not provided, the class into which was blessed the calling object will
6996             be used instead.
6997              
6998             It returns an array of subclasses in list context and a reference to an array of those
6999             subclasses in scalar context.
7000              
7001             If an error occured, undef is returned and an error is set accordingly. The latter can
7002             be retrieved using the B<error> method.
7003              
7004             =head2 true
7005              
7006             Returns a C<true> variable from L<Module::Generic::Boolean>
7007              
7008             =head2 false
7009              
7010             Returns a C<false> variable from L<Module::Generic::Boolean>
7011              
7012             =head2 verbose
7013              
7014             Set or get the verbosity level with an integer.
7015              
7016             =head2 will
7017              
7018             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.
7019              
7020             =head2 AUTOLOAD
7021              
7022             The special B<AUTOLOAD>() routine is called by perl when no matching routine was found
7023             in the module.
7024              
7025             B<AUTOLOAD>() will then try hard to process the request.
7026             For example, let's assue we have a routine B<foo>.
7027              
7028             It will first, check if an equivalent entry of the routine name that was called exist in
7029             the hash reference of the object. If there is and that more than one argument were
7030             passed to this non existing routine, those arguments will be stored as a reference to an
7031             array as a value of the key in the object. Otherwise the single argument will simply be stored
7032             as the value of the key of the object.
7033              
7034             Then, if called in list context, it will return a array if the value of the key entry was an array
7035             reference, or a hash list if the value of the key entry was a hash reference, or finally the value
7036             of the key entry.
7037              
7038             If this non existing routine that was called is actually defined, the routine will be redeclared and
7039             the arguments passed to it.
7040              
7041             If this fails too, it will try to check for an AutoLoadable file in C<auto/PackageName/routine_name.al>
7042              
7043             If the filed exists, it will be required, the routine name linked into the package name space and finally
7044             called with the arguments.
7045              
7046             If the require process failed or if the AutoLoadable routine file did not exist, B<AUTOLOAD>() will
7047             check if the special routine B<EXTRA_AUTOLOAD>() exists in the module. If it does, it will call it and pass
7048             it the arguments. Otherwise, B<AUTOLOAD> will die with a message explaining that the called routine did
7049             not exist and could not be found in the current class.
7050              
7051             =head1 SPECIAL METHODS
7052              
7053             =head2 __instantiate_object
7054              
7055             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">
7056              
7057             This is a support method used by L</"_instantiate_object">
7058              
7059             =head2 _instantiate_object
7060              
7061             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">
7062              
7063             =head2 _is_class_loaded
7064              
7065             Provided with a class/package name, this returns true if the module is already loaded or false otherwise.
7066              
7067             =head2 _is_array
7068              
7069             Provided with some data, this checks if the data is of type array, even if it is an object.
7070              
7071             This uses L<Scalar::Util/"reftype"> to achieve that purpose. So for example, an object such as :
7072              
7073             package My::Module;
7074              
7075             sub new
7076             {
7077             return( bless( [] => ( ref( $_[0] ) || $_[0] ) ) );
7078             }
7079              
7080             This would produce an object like :
7081              
7082             My::Module=ARRAY(0x7f8f3b035c20)
7083              
7084             When checked with L</"_is_array"> this, would return true just like an ordinary array.
7085              
7086             If you would use :
7087              
7088             ref( $object );
7089              
7090             It would rather return the module package name: C<My::Module>
7091              
7092             =head2 _is_hash
7093              
7094             Same as L</"_is_array">, but for hash reference.
7095              
7096             =head2 _is_object
7097              
7098             Provided with some data, this checks if the data is an object. It uses L<Scalar::Util/"blessed"> to achieve that purpose.
7099              
7100             =head2 _is_scalar
7101              
7102             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.
7103              
7104             =head2 _load_class
7105              
7106             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.
7107              
7108             =head2 _obj2h
7109              
7110             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.
7111              
7112             =head2 _parse_timestamp
7113              
7114             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.
7115              
7116             =head2 _set_get
7117              
7118             Provided with an object property name and some value and this will set or get that value for that property.
7119              
7120             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.
7121              
7122             =head2 _set_get_array
7123              
7124             Provided with an object property name and some data and this will store the data as an array reference.
7125              
7126             It returns the current value stored, such as an array reference notwithstanding it is called in list or scalar context.
7127              
7128             Example :
7129              
7130             sub products { return( shift->_set_get_array( 'products', @_ ) ); }
7131              
7132             =head2 _set_get_array_as_object
7133              
7134             Provided with an object property name and some data and this will store the data as an object of L<Module::Generic::Array>
7135              
7136             If this is called with no data set, an object is created with no data inside and returned
7137              
7138             Example :
7139              
7140             # In your module
7141             sub products { return( shift->_set_get_array_as_object( 'products', @_ ) ); }
7142              
7143             And using your method:
7144              
7145             printf( "There are %d products\n", $object->products->length );
7146             $object->products->push( $new_product );
7147              
7148             =head2 _set_get_boolean
7149              
7150             Provided with an object property name and some data and this will store the data as a boolean value.
7151              
7152             If the data provided is a L<JSON::PP::Boolean> or L<Module::Generic::Boolean> object, the data is stored as is.
7153              
7154             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.
7155              
7156             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.
7157              
7158             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.
7159              
7160             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.
7161              
7162             =head2 __create_class
7163              
7164             Provided with an object property name and an hash reference representing a dictionary and this will produce a dynamically created class/module.
7165              
7166             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 :
7167              
7168             sub products { return( 'products', shift->_set_get_class(
7169             {
7170             name => { type => 'scalar' },
7171             customer => { type => 'object', class => 'My::Customer' },
7172             orders => { type => 'array_as_object' },
7173             active => { type => 'boolean' },
7174             created => { type => 'datetime' },
7175             metadata => { type => 'hash' },
7176             stock => { type => 'number' },
7177             url => { type => 'uri' },
7178             }, @_ ) ); }
7179              
7180             Then calling your module method B<products> such as :
7181              
7182             my $prod = $object->products({
7183             name => 'Cool product',
7184             customer => { first_name => 'John', last_name => 'Doe', email => 'john.doe@example.com' },
7185             orders => [qw( 123 987 456 654 )],
7186             active => 1,
7187             metadata => { transaction_id => 123, api_call_id => 456 },
7188             stock => 10,
7189             uri => 'https://example.com/p/20'
7190             });
7191              
7192             Using the resulting object C<$prod>, we can access this dynamically created class/module such as :
7193              
7194             printf( <<EOT, $prod->name, $prod->orders->length, $prod->customer->last_name,, $prod->url->path )
7195             Product name: %s
7196             No of orders: %d
7197             Customer name: %s
7198             Product page path: %s
7199             EOT
7200              
7201             =head2 _set_get_class
7202              
7203             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">
7204              
7205             For example, consider the following:
7206              
7207             #!/usr/local/bin/perl
7208             BEGIN
7209             {
7210             use strict;
7211             use Data::Dumper;
7212             };
7213              
7214             {
7215             my $o = MyClass->new( debug => 3 );
7216             $o->setup->age( 42 );
7217             print( "Age is: ", $o->setup->age, "\n" );
7218             print( "Setup object is: ", $o->setup, "\n" );
7219             $o->setup->billing->interval( 'month' );
7220             print( "Billing interval is: ", $o->setup->billing->interval, "\n" );
7221             print( "Billing object is: ", $o->setup->billing, "\n" );
7222             $o->setup->rgb( 255, 122, 100 );
7223             print( "rgb: ", join( ', ', @{$o->setup->rgb} ), "\n" );
7224             exit( 0 );
7225             }
7226              
7227             package MyClass;
7228             BEGIN
7229             {
7230             use strict;
7231             use lib './lib';
7232             use parent qw( Module::Generic );
7233             };
7234              
7235             sub setup
7236             {
7237             return( shift->_set_get_class( 'setup',
7238             {
7239             name => { type => 'scalar' },
7240             age => { type => 'number' },
7241             metadata => { type => 'hash' },
7242             rgb => { type => 'array' },
7243             url => { type => 'uri' },
7244             online => { type => 'boolean' },
7245             created => { type => 'datetime' },
7246             billing => { type => 'class', definition =>
7247             {
7248             interval => { type => 'scalar' },
7249             frequency => { type => 'number' },
7250             nickname => { type => 'scalar' },
7251             }}
7252             }) );
7253             }
7254              
7255             1;
7256              
7257             __END__
7258              
7259             This will yield:
7260              
7261             Age is: 42
7262             Setup object is: MyClass::Setup=HASH(0x7fa805abcb20)
7263             Billing interval is: month
7264             Billing object is: MyClass::Setup::Billing=HASH(0x7fa804ec3f40)
7265             rgb: 255, 122, 100
7266              
7267             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.
7268              
7269             =head2 _set_get_class_array
7270              
7271             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 :
7272              
7273             sub products { return( shift->_set_get_class_array( 'products',
7274             {
7275             name => { type => 'scalar' },
7276             customer => { type => 'object', class => 'My::Customer' },
7277             orders => { type => 'array_as_object' },
7278             active => { type => 'boolean' },
7279             created => { type => 'datetime' },
7280             metadata => { type => 'hash' },
7281             stock => { type => 'number' },
7282             url => { type => 'uri' },
7283             }, @_ ) ); }
7284              
7285             Then your script would call this method like this :
7286              
7287             $object->products([
7288             { 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' },
7289             { 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' },
7290             ]);
7291              
7292             And this would store an array reference containing 2 objects with the above data.
7293              
7294             =head2 _set_get_code
7295              
7296             Provided with an object property name and some code reference and this stores and retrieve the current value.
7297              
7298             It returns under and set an error if the provided value is not a code reference.
7299              
7300             =head2 _set_get_datetime
7301              
7302             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.
7303              
7304             If the data is a 10 digits integer, this will treat it as a unix timestamp.
7305              
7306             Parsing also recognise special word such as C<now>
7307              
7308             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.
7309              
7310             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:
7311              
7312             $object->created->iso8601
7313              
7314             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.
7315              
7316             =head2 _set_get_hash
7317              
7318             Provided with an object property name and an hash reference and this set the property name with this hash reference.
7319              
7320             You can even pass it an associative array, and it will be saved as a hash reference, such as :
7321              
7322             $object->metadata(
7323             transaction_id => 123,
7324             customer_id => 456
7325             );
7326              
7327             my $hash = $object->metadata;
7328              
7329             =head2 _set_get_hash_as_object
7330              
7331             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.
7332              
7333             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.
7334              
7335             For example in your module :
7336              
7337             sub metadata { return( shift->_set_get_hash_as_object( 'metadata', @_ ) ); }
7338              
7339             Then populating the data :
7340              
7341             $object->metadata({
7342             first_name => 'John',
7343             last_name => 'Doe',
7344             email => 'john.doe@example.com',
7345             });
7346              
7347             printf( "Customer name is %s\n", $object->metadata->last_name );
7348              
7349             =head2 _set_get_number
7350              
7351             Provided with an object property name and a number, and this will create a L<Module::Generic::Number> object and return it.
7352              
7353             =head2 _set_get_number_or_object
7354              
7355             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
7356              
7357             =head2 _set_get_object
7358              
7359             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.
7360              
7361             If you pass an undefined value, it will set the property as undefined, removing whatever was set before.
7362              
7363             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.
7364              
7365             It returns the object currently set, if any.
7366              
7367             =head2 _set_get_object_array2
7368              
7369             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.
7370              
7371             =head2 _set_get_object_array
7372              
7373             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.
7374              
7375             =head2 _set_get_object_array_object
7376              
7377             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>
7378              
7379             =head2 _set_get_object_variant
7380              
7381             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.
7382              
7383             This means the value stored for the object property will vary between an hash or array reference.
7384              
7385             =head2 _set_get_scalar
7386              
7387             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.
7388              
7389             It returns the currently value stored.
7390              
7391             =head2 _set_get_scalar_as_object
7392              
7393             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>
7394              
7395             If there is already an object set for this property, the value provided will be assigned to it using L<Module::Generic::Scalar/"set">
7396              
7397             If it is called and not value is set yet, this will instantiate a L<Module::Generic::Scalar> object with no value.
7398              
7399             So a call to this method can safely be chained to access the L<Module::Generic::Scalar> methods. For example :
7400              
7401             sub name { return( shift->_set_get_scalar_as_object( 'name', @_ ) ); }
7402              
7403             Then, calling it :
7404              
7405             $object->name( 'John Doe' );
7406              
7407             Getting the value :
7408              
7409             my $cust_name = $object->name;
7410             print( "Nothing set yet.\n" ) if( !$cust_name->length );
7411              
7412             =head2 _set_get_scalar_or_object
7413              
7414             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">
7415              
7416             If no value has been set yet, this returns a L<Module::Generic::Null> object to enable chaining.
7417              
7418             =head2 _set_get_uri
7419              
7420             Provided with an object property name, and an uri and this creates a L<URI> object and sets the property value accordingly.
7421              
7422             It accepts an L<URI> object, an uri or urn string, or an absolute path, i.e. a string starting with C</>.
7423              
7424             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 ?
7425              
7426             =head2 __dbh
7427              
7428             if your module has the global variables C<DB_DSN>, this will create a database handler using L<DBI>
7429              
7430             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>
7431              
7432             If C<DB_SERVER_PREPARE> is provided and true, C<pg_server_prepare> will be set to true in the database handler.
7433              
7434             It returns the database handler object.
7435              
7436             =head2 DEBUG
7437              
7438             Return the value of your global variable I<DEBUG>, if any.
7439              
7440             =head2 VERBOSE
7441              
7442             Return the value of your global variable I<VERBOSE>, if any.
7443              
7444             =head1 SEE ALSO
7445              
7446             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>
7447              
7448             L<Number::Format>, L<Class::Load>, L<Scalar::Util>
7449              
7450             =head1 AUTHOR
7451              
7452             Jacques Deguest E<lt>F<jack@deguest.jp>E<gt>
7453              
7454             =head1 COPYRIGHT & LICENSE
7455              
7456             Copyright (c) 2000-2020 DEGUEST Pte. Ltd.
7457              
7458             You can use, copy, modify and redistribute this package and associated
7459             files under the same terms as Perl itself.
7460              
7461             =cut