File Coverage

blib/lib/Module/Generic.pm
Criterion Covered Total %
statement 1940 3929 49.3
branch 515 1904 27.0
condition 199 1038 19.1
subroutine 439 644 68.1
pod 43 50 86.0
total 3136 7565 41.4


line stmt bran cond sub pod time code
1             ## -*- perl -*-
2             ##----------------------------------------------------------------------------
3             ## Module Generic - ~/lib/Module/Generic.pm
4             ## Version v0.13.0
5             ## Copyright(c) 2020 DEGUEST Pte. Ltd.
6             ## Author: Jacques Deguest <@sitael.local>
7             ## Created 2019/08/24
8             ## Modified 2020/07/17
9             ##
10             ##----------------------------------------------------------------------------
11             package Module::Generic;
12             BEGIN
13 0         0 {
14 7     7   82 require 5.6.0;
15 7     7   697198 use strict;
  7         70  
  7         215  
16 7     7   37 use warnings::register;
  7         11  
  7         802  
17 7     7   45 use Scalar::Util qw( openhandle );
  7         13  
  7         321  
18 7     7   3180 use Sub::Util ();
  7         1782  
  7         154  
19 7     7   2896 use Clone ();
  7         17525  
  7         199  
20 7     7   4384 use Data::Dumper;
  7         46218  
  7         477  
21 7     7   3400 use Data::Dump;
  7         49476  
  7         429  
22 7     7   3451 use Devel::StackTrace;
  7         22405  
  7         253  
23 7     7   4127 use Number::Format;
  7         43705  
  7         375  
24 7     7   4118 use Nice::Try;
  7         766361  
  7         48  
25 7     7   81590969 use B;
  7         21  
  7         511  
26             ## To get some context on what the caller expect. This is used in our error() method to allow chaining without breaking
27 7     7   4647 use Want;
  7         11728  
  7         436  
28 7     7   3025 use Class::Load ();
  7         86255  
  7         216  
29 7     7   3401 use Encode ();
  7         87172  
  7         790  
30 7         23 our( @ISA, @EXPORT_OK, @EXPORT, %EXPORT_TAGS, $AUTOLOAD );
31 7         13 our( $VERSION, $ERROR, $SILENT_AUTOLOAD, $VERBOSE, $DEBUG, $MOD_PERL );
32 7         10 our( $PARAM_CHECKER_LOAD_ERROR, $PARAM_CHECKER_LOADED, $CALLER_LEVEL );
33 7         10 our( $OPTIMIZE_MESG_SUB, $COLOUR_NAME_TO_RGB );
34 7     7   71 use Exporter ();
  7         13  
  7         551  
35 7         117 @ISA = qw( Exporter );
36 7         29 @EXPORT = qw( );
37 7         17 @EXPORT_OK = qw( subclasses );
38 7         93 %EXPORT_TAGS = ();
39 7         13 $VERSION = 'v0.13.0';
40 7         12 $VERBOSE = 0;
41 7         44 $DEBUG = 0;
42 7         12 $SILENT_AUTOLOAD = 1;
43 7         9 $PARAM_CHECKER_LOADED = 0;
44 7         12 $CALLER_LEVEL = 0;
45 7         9 $OPTIMIZE_MESG_SUB = 0;
46 7         4769 $COLOUR_NAME_TO_RGB = {};
47             # local $^W;
48 7     7   39 no strict qw(refs);
  7         13  
  7         274  
49 7     7   40 use constant COLOUR_OPEN => '<';
  7         13  
  7         374  
50 7     7   43 use constant COLOUR_CLOSE => '>';
  7         14  
  7         312  
51             };
52              
53             INIT
54             {
55 7     7   807 our $true = ${"Module::Generic::Boolean::true"};
  7         258  
56 7         19 our $false = ${"Module::Generic::Boolean::false"};
  7         67  
57 7         171 while( <DATA> )
58             {
59 0         0 chomp;
60 0         0 print( "INIT: found colour data: '$_'\n" );
61             }
62             };
63              
64             {
65             ## mod_perl/2.0.10
66             if( exists( $ENV{ 'MOD_PERL' } )
67             &&
68             ( $MOD_PERL = $ENV{ 'MOD_PERL' } =~ /^mod_perl\/\d+\.[\d\.]+/ ) )
69             {
70             select( ( select( STDOUT ), $| = 1 )[ 0 ] );
71             require Apache2::Log;
72             require Apache2::ServerUtil;
73             require Apache2::RequestUtil;
74             require Apache2::ServerRec;
75             }
76            
77             our $DEBUG_LOG_IO = undef();
78            
79             our $DB_NAME = $DATABASE;
80             our $DB_HOST = $SQL_SERVER;
81             our $DB_USER = $DB_LOGIN;
82             our $DB_PWD = $DB_PASSWD;
83             our $DB_RAISE_ERROR = $SQL_RAISE_ERROR;
84             our $DB_AUTO_COMMIT = $SQL_AUTO_COMMIT;
85             }
86              
87             sub import
88             {
89 7     7   105 my $self = shift( @_ );
90 7         36 my( $pkg, $file, $line ) = caller();
91 7         38 local $Exporter::ExportLevel = 1;
92             ## local $Exporter::Verbose = $VERBOSE;
93 7         216 Exporter::import( $self, @_ );
94            
95             ##print( STDERR "Module::Generic::import(): called from package '$pkg' in file '$file' at line '$line'.\n" ) if( $DEBUG );
96 7         34 ( my $dir = $pkg ) =~ s/::/\//g;
97 7         28 my $path = $INC{ $dir . '.pm' };
98             ##print( STDERR "Module::Generic::import(): using primary path of '$path'.\n" ) if( $DEBUG );
99 7 50       118 if( defined( $path ) )
100             {
101             ## Try absolute path name
102 0         0 $path =~ s/^(.*)$dir\.pm$/$1auto\/$dir\/autosplit.ix/;
103             ##print( STDERR "Module::Generic::import(): using treated path of '$path'.\n" ) if( $DEBUG );
104             eval
105 0         0 {
106 0     0   0 local $SIG{ '__DIE__' } = sub{ };
107 0     0   0 local $SIG{ '__WARN__' } = sub{ };
108 0         0 require $path;
109             };
110 0 0       0 if( $@ )
111             {
112 0         0 $path = "auto/$dir/autosplit.ix";
113             eval
114 0         0 {
115 0     0   0 local $SIG{ '__DIE__' } = sub{ };
116 0     0   0 local $SIG{ '__WARN__' } = sub{ };
117 0         0 require $path;
118             };
119             }
120 0 0       0 if( $@ )
121             {
122 0 0       0 CORE::warn( $@ ) unless( $SILENT_AUTOLOAD );
123             }
124             ##print( STDERR "Module::Generic::import(): '$path' ", $@ ? 'not ' : '', "loaded.\n" ) if( $DEBUG );
125             }
126             }
127              
128             sub new
129             {
130 153     153 1 431 my $that = shift( @_ );
131 153   66     741 my $class = ref( $that ) || $that;
132             ## my $pkg = ( caller() )[ 0 ];
133             ## print( STDERR __PACKAGE__ . "::new(): our calling package is '", ( caller() )[ 0 ], "', our class is '$class'.\n" );
134 153         418 my $self = {};
135             ## print( STDERR "${class}::OBJECT_READONLY: ", ${ "${class}\::OBJECT_READONLY" }, "\n" );
136 153 50       342 if( defined( ${ "${class}\::OBJECT_PERMS" } ) )
  153         1596  
137             {
138 0         0 my %hash = ();
139             my $obj = tie(
140             %hash,
141             'Module::Generic::Tie',
142             'pkg' => [ __PACKAGE__, $class ],
143 0         0 'perms' => ${ "${class}::OBJECT_PERMS" },
  0         0  
144             );
145 0         0 $self = \%hash;
146             }
147 153         467 bless( $self, $class );
148 153 50       563 if( $MOD_PERL )
149             {
150 0         0 my $r = Apache2::RequestUtil->request;
151             $r->pool->cleanup_register
152             (
153             sub
154             {
155             ## my( $pkg, $file, $line ) = caller();
156             ## 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" );
157 0     0   0 map{ delete( $self->{ $_ } ) } keys( %$self );
  0         0  
158 0         0 undef( %$self );
159             }
160 0         0 );
161             }
162 153 50       328 if( defined( ${ "${class}\::LOG_DEBUG" } ) )
  153         990  
163             {
164 0         0 $self->{ 'log_debug' } = ${ "${class}::LOG_DEBUG" };
  0         0  
165             }
166 153         667 return( $self->init( @_ ) );
167             }
168              
169             ## This is used to transform package data set into hash refer suitable for api calls
170             ## If package use AUTOLOAD, those AUtILOAD should make sure to create methods on the fly so they become defined
171             sub as_hash
172             {
173 0     0 1 0 my $self = shift( @_ );
174 0         0 my $this = $self->_obj2h;
175 0         0 my $p = {};
176 0 0 0     0 $p = shift( @_ ) if( scalar( @_ ) == 1 && ref( $_[0] ) eq 'HASH' );
177             # $self->message( 3, "Parameters are: ", sub{ $self->dumper( $p ) } );
178 0         0 my $class = ref( $self );
179 7     7   52 no strict 'refs';
  7         14  
  7         463  
180 0         0 my @methods = grep{ defined &{"${class}::$_"} } keys( %{"${class}::"} );
  0         0  
  0         0  
  0         0  
181             # $self->messagef( 3, "The following methods found in package $class: '%s'.", join( "', '", sort( @methods ) ) );
182 7     7   38 use strict 'refs';
  7         13  
  7         566  
183 0         0 my $ref = {};
184 0         0 foreach my $meth ( sort( @methods ) )
185             {
186 0 0       0 next if( substr( $meth, 0, 1 ) eq '_' );
187 0         0 my $rv = eval{ $self->$meth };
  0         0  
188 0 0       0 if( $@ )
189             {
190 0         0 warn( "An error occured while accessing method $meth: $@\n" );
191 0         0 next;
192             }
193 7     7   46 no overloading;
  7         14  
  7         233  
194             # $self->message( 3, "Value for method '$meth' is '$rv'." );
195 7     7   34 use overloading;
  7         14  
  7         11519  
196 0 0 0     0 if( $p->{json} && ( ref( $rv ) eq 'JSON::PP::Boolean' || ref( $rv ) eq 'Module::Generic::Boolean' ) )
    0 0        
197             {
198             # $self->message( 3, "Encoding boolean to true or false for method '$meth'." );
199 0         0 $ref->{ $meth } = Module::Generic::Boolean::TO_JSON( $ref->{ $meth } );
200 0         0 next;
201             }
202             elsif( $self->_is_object( $rv ) )
203             {
204 0 0 0     0 if( $rv->can( 'as_hash' ) && overload::Overloaded( $rv ) && overload::Method( $rv, '""' ) )
    0 0        
205             {
206 0         0 $rv = $rv . '';
207             }
208             elsif( $rv->can( 'as_hash' ) )
209             {
210             # $self->message( 3, "$rv is an object (", ref( $rv ), ") capable of as_hash, calling it." );
211 0         0 $rv = $rv->as_hash( $p );
212             }
213             }
214            
215             ## $self->message( 3, "Checking field '$meth' with value '$rv'." );
216            
217 0 0       0 if( ref( $rv ) eq 'HASH' )
    0          
    0          
    0          
218             {
219 0 0       0 $ref->{ $meth } = $rv if( scalar( keys( %$rv ) ) );
220             }
221             ## If method call returned an array, like array of string or array of object such as in data from Net::API::Stripe::List
222             elsif( ref( $rv ) eq 'ARRAY' )
223             {
224 0         0 my $arr = [];
225 0         0 foreach my $this_ref ( @$rv )
226             {
227 0 0 0     0 my $that_ref = ( $self->_is_object( $this_ref ) && $this_ref->can( 'as_hash' ) ) ? $this_ref->as_hash : $this_ref;
228 0         0 CORE::push( @$arr, $that_ref );
229             }
230 0 0       0 $ref->{ $meth } = $arr if( scalar( @$arr ) );
231             }
232             elsif( !ref( $rv ) )
233             {
234 0 0       0 $ref->{ $meth } = $rv if( CORE::length( $rv ) );
235             }
236             elsif( CORE::length( "$rv" ) )
237             {
238 0         0 $self->message( 3, "Adding value '$rv' to field '$meth' in hash \$ref" );
239 0         0 $ref->{ $meth } = $rv;
240             }
241             }
242 0         0 return( $ref );
243             }
244              
245             sub clear
246             {
247 0     0 0 0 goto( &clear_error );
248             }
249              
250             sub clear_error
251             {
252 0     0 1 0 my $self = shift( @_ );
253 0   0     0 my $class = ref( $self ) || $self;
254 0         0 my $this = $self->_obj2h;
255 0         0 $this->{error} = ${ "$class\::ERROR" } = '';
  0         0  
256 0         0 return( 1 );
257             }
258              
259             # sub clone
260             # {
261             # my $self = shift( @_ );
262             # if( Scalar::Util::reftype( $self ) eq 'HASH' )
263             # {
264             # return( bless( { %$self } => ( ref( $self ) || $self ) ) );
265             # }
266             # elsif( Scalar::Util::reftype( $self ) eq 'ARRAY' )
267             # {
268             # return( bless( [ @$self ] => ( ref( $self ) || $self ) ) );
269             # }
270             # else
271             # {
272             # return( $self->error( "Cloning is unsupported for type \"", ref( $self ), "\". Only hash or array references are supported." ) );
273             # }
274             # }
275              
276             sub clone
277             {
278 0     0 1 0 my $self = shift( @_ );
279 0         0 try
280 0     0   0 {
281 0         0 $self->message( 3, "Cloning object '", overload::StrVal( $self ), "'." );
282 0         0 return( Clone::clone( $self ) );
283             }
284 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  
285 0     0   0 {
286 0         0 return( $self->error( "Error cloning object \"", overload::StrVal( $self ), "\": $e" ) );
287 0 0 0     0 }
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
288             }
289              
290 2     2 0 6 sub colour_close { return( shift->_set_get( 'colour_close', @_ ) ); }
291              
292             sub colour_closest
293             {
294 0     0 1 0 my $self = shift( @_ );
295 0         0 my $colour = uc( shift( @_ ) );
296 0         0 my $this = $self->_obj2h;
297 0         0 my $colours =
298             {
299             '000000000' => 'black',
300             '000000255' => 'blue',
301             '000255000' => 'green',
302             '000255255' => 'cyan',
303             '255000000' => 'red',
304             '255000255' => 'magenta',
305             '255255000' => 'yellow',
306             '255255255' => 'white',
307             };
308 0         0 my( $red, $green, $blue ) = ( '', '', '' );
309 0 0       0 if( $colour =~ /^[A-Z]+([A-Z\s]+)*$/ )
    0          
    0          
310             {
311 0 0       0 if( !scalar( keys( %$COLOUR_NAME_TO_RGB ) ) )
312             {
313             ## $self->message( 3, "Processing colour map in <DATA> section." );
314 0         0 while( <DATA> )
315             {
316 0         0 chomp;
317 0 0       0 next if( /^[[:blank:]]*$/ );
318 0 0       0 last if( /^\=/ );
319 0         0 my( $r, $g, $b, $name ) = split( /[[:blank:]]+/, $_, 4 );
320 0         0 $COLOUR_NAME_TO_RGB->{ lc( $name ) } = [ $r, $g, $b ];
321             }
322 0         0 close( DATA );
323             }
324 0 0       0 if( CORE::exists( $COLOUR_NAME_TO_RGB->{ lc( $colour ) } ) )
325             {
326 0         0 ( $red, $green, $blue ) = @{$COLOUR_NAME_TO_RGB->{ lc( $colour ) }};
  0         0  
327             }
328             }
329             ## Colour all in decimal??
330             elsif( $colour =~ /^\d{9}$/ )
331             {
332             ## $self->message( 3, "Got colour all in decimal. Less work to do..." );
333 0         0 $red = substr( $colour, 0, 3 );
334 0         0 $green = substr( $colour, 3, 3 );
335 0         0 $blue = substr( $colour, 6, 3 );
336             }
337             ## Colour in hexadecimal, convert it
338             elsif( $colour =~ /^[A-F0-9]+$/ )
339             {
340 0         0 $red = hex( substr( $colour, 0, 2 ) );
341 0         0 $green = hex( substr( $colour, 2, 2 ) );
342 0         0 $blue = hex( substr( $colour, 4, 2 ) );
343             }
344             ## Clueless
345             else
346             {
347             ## Not undef, but rather empty string. Undef is associated with an error
348 0         0 return( '' );
349             }
350 0         0 my $dec_colour = CORE::sprintf( '%3d%3d%3d', $red, $green, $blue );
351 0         0 my $last = '';
352 0         0 my @colours = reverse( sort( keys( %$colours ) ) );
353 0         0 $red = CORE::sprintf( '%03d', $red );
354 0         0 $green = CORE::sprintf( '%03d', $green );
355 0         0 $blue = CORE::sprintf( '%03d', $blue );
356 0         0 my $cur = CORE::sprintf( '%03d%03d%03d', $red, $green, $blue );
357 0         0 my( $red_ok, $green_ok, $blue_ok ) = ( 0, 0, 0 );
358             ## $self->message( 3, "Current colour: '$cur'." );
359 0         0 for( my $i = 0; $i < scalar( @colours ); $i++ )
360             {
361 0         0 my $r = CORE::sprintf( '%03d', substr( $colours[ $i ], 0, 3 ) );
362 0         0 my $g = CORE::sprintf( '%03d', substr( $colours[ $i ], 3, 3 ) );
363 0         0 my $b = CORE::sprintf( '%03d', substr( $colours[ $i ], 6, 3 ) );
364            
365 0         0 my $r_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 0, 3 ) );
366 0         0 my $g_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 3, 3 ) );
367 0         0 my $b_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 6, 3 ) );
368            
369             ## $self->message( 3, "$r ($red), $g ($green), $b ($blue)" );
370 0 0 0     0 if( $red == $r ||
      0        
      0        
      0        
      0        
      0        
371             ( $red < $r && $red > int( $r / 2 ) ) ||
372             ( $red > $r && $red < int( $r_p / 2 ) && $r_p ) ||
373             $red > $r )
374             {
375 0         0 $red_ok++;
376             }
377            
378 0 0       0 if( $red_ok )
379             {
380 0 0 0     0 if( $green == $g ||
      0        
      0        
      0        
      0        
      0        
381             ( $green < $g && $green > int( $g / 2 ) ) ||
382             ( $green > $g && $green < int( $g_p / 2 ) && $g_p ) ||
383             $green > $g )
384             {
385 0         0 $blue_ok++;
386             }
387             }
388            
389 0 0       0 if( $blue_ok )
390             {
391 0 0 0     0 if( $blue == $b ||
      0        
      0        
      0        
      0        
      0        
392             ( $blue < $b && $blue > int( $b / 2 ) ) ||
393             ( $blue > $b && $blue < int( $b_p / 2 ) && $b_p ) ||
394             $blue > $b )
395             {
396 0         0 $last = $colours[ $i ];
397 0         0 last;
398             }
399             }
400             }
401 0         0 return( $colours->{ $last } );
402             }
403              
404             sub colour_format
405             {
406 12     12 1 23 my $self = shift( @_ );
407             ## style, colour or color and text
408 12         22 my $opts = shift( @_ );
409 12 50       30 return( $self->error( "Parameter hash provided is not an hash reference." ) ) if( !$self->_is_hash( $opts ) );
410 12         29 my $this = $self->_obj2h;
411             ## To make it possible to use either text or message property
412 12 50 33     51 $opts->{text} = CORE::delete( $opts->{message} ) if( CORE::length( $opts->{message} ) && !CORE::length( $opts->{text} ) );
413 12 50       28 return( $self->error( "No text was provided to format." ) ) if( !CORE::length( $opts->{text} ) );
414            
415 12   0     42 $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        
416 12   66     104 $opts->{bgcolour} //= CORE::delete( $opts->{bgcolor} ) || CORE::delete( $opts->{bg_colour} ) || CORE::delete( $opts->{bg_color} );
      66        
417            
418 12         21 my $bold = "\e[1m";
419 12         18 my $underline = "\e[4m";
420 12         17 my $reverse = "\e[7m";
421 12         16 my $normal = "\e[m";
422 12         16 my $cls = "\e[H\e[2J";
423 12         120 my $styles =
424             {
425             # Bold
426             b => 1,
427             bold => 1,
428             strong => 1,
429             # Italic
430             i => 3,
431             italic => 3,
432             # Underline
433             u => 4,
434             underline => 4,
435             underlined => 4,
436             blink => 5,
437             # Reverse
438             r => 7,
439             reverse => 7,
440             reversed => 7,
441             # Concealed
442             c => 8,
443             conceal => 8,
444             concealed => 8,
445             strike => 9,
446             striked => 9,
447             striken => 9,
448             };
449            
450             local $convert_24_To_8bits = sub
451             {
452 17     17   38 my( $r, $g, $b ) = @_;
453 17         64 $self->message( 9, "Converting $r, $g, $b to 8 bits" );
454 17         198 return( ( POSIX::floor( $r * 7 / 255 ) << 5 ) +
455             ( POSIX::floor( $g * 7 / 255 ) << 2 ) +
456             ( POSIX::floor( $b * 3 / 255 ) )
457             );
458 12         59 };
459            
460             ## opacity * original + (1-opacity)*background = resulting pixel
461             ## https://stackoverflow.com/a/746934/4814971
462             local $colour_with_alpha = sub
463             {
464 1     1   3 my( $r, $g, $b, $a, $bg ) = @_;
465             ## Assuming a white background (255)
466 1         3 my( $bg_r, $bg_g, $bg_b ) = ( 255, 255, 255 );
467 1 50       4 if( ref( $bg ) eq 'HASH' )
468             {
469 1         3 ( $bg_r, $bg_g, $bg_b ) = @$bg{qw( red green blue )};
470             }
471 1         7 $r = POSIX::round( ( $a * $r ) + ( ( 1 - $a ) * $bg_r ) );
472 1         4 $g = POSIX::round( ( $a * $g ) + ( ( 1 - $a ) * $bg_g ) );
473 1         6 $b = POSIX::round( ( $a * $b ) + ( ( 1 - $a ) * $bg_b ) );
474 1         3 return( [$r, $g, $b] );
475 12         46 };
476            
477             local $check_colour = sub
478             {
479 18     18   33 my $col = shift( @_ );
480             ## $self->message( 3, "Checking colour '$col'." );
481             ## $colours or $bg_colours
482 18         27 my $map = shift( @_ );
483 18         30 my $code;
484             my $light;
485             ## Example: 'light red' or 'light_red'
486 18 100       139 if( $col =~ /^(?:(?<light>bright|light)[[:blank:]\_]+)?
    50          
487             (?<colour>
488             (?:[a-zA-Z]+)(?:[[:blank:]]+\w+)?
489             |
490             (?<rgb_type>rgb[a]?)\([[:blank:]]*(?<red>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<green>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<blue>\d{1,3})
491             (?:[[:blank:]]*\,[[:blank:]]*(?<opacity>\d(?:\.\d+)?))?[[:blank:]]*
492             \)
493             )$/xi )
494             {
495 7     7   3034 my %regexp = %+;
  7         2496  
  7         37355  
  17         245  
496 17         130 $self->message( 9, "Light colour request '$col'. Capture: ", sub{ $self->dumper( \%regexp ) } );
  0         0  
497 17         116 ( $light, $col ) = ( $+{light}, $+{colour} );
498 17 100 66     119 if( CORE::length( $+{rgb_type} ) &&
      66        
      33        
499             CORE::length( $+{red} ) &&
500             CORE::length( $+{green} ) &&
501             CORE::length( $+{blue} ) )
502             {
503 3 100 66     17 if( $+{opacity} || $light )
504             {
505             my $opacity = CORE::length( $+{opacity} )
506             ? $+{opacity}
507 1 0       8 : $light
    50          
508             ? 0.5
509             : 1;
510 1         24 $col = CORE::sprintf( 'rgba(%03d%03d%03d,%.1f)', $+{red}, $+{green}, $+{blue}, $opacity );
511             }
512             else
513             {
514 2         24 $col = CORE::sprintf( 'rgb(%03d%03d%03d)', $+{red}, $+{green}, $+{blue} );
515             }
516             }
517             else
518             {
519 14         44 $self->message( 9, "Colour '$col' is not rgb[a]" );
520             }
521             }
522             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 )
523             {
524 0 0       0 if( $+{opacity} )
525             {
526 0         0 $col = CORE::sprintf( 'rgba(%03d%03d%03d,%.1f)', $+{red}, $+{green}, $+{blue}, $+{opacity} );
527             }
528             else
529             {
530 0         0 $col = CORE::sprintf( '%03d%03d%03d', $+{red}, $+{green}, $+{blue} );
531             }
532             }
533             else
534             {
535 1         6 $self->message( 9, "Colour '$col' failed to match our rgba regexp." );
536             }
537            
538 18         35 my $col_ref;
539 18 100 66     89 if( $col =~ /^rgb[a]?\((?<red>\d{3})(?<green>\d{3})(?<blue>\d{3})\)$/i )
    100          
    100          
540             {
541 3         7 $col_ref = {};
542 3         37 %$col_ref = %+;
543 3         40 $self->message( 9, "Rgb colour '$+{red}', '$+{green}' and '$+{blue}' found: ", sub{ $self->dumper( $col_ref ) });
  0         0  
544             return({
545             _24bits => [@$col_ref{qw( red green blue )}],
546 3         20 _8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} )
547             });
548             }
549             ## Treating opacity to make things lighter; not ideal, but standard scheme
550             elsif( $col =~ /^rgba\((?<red>\d{3})(?<green>\d{3})(?<blue>\d{3})[[:blank:]]*\,[[:blank:]]*(?<opacity>\d(?:\.\d)?)\)$/i )
551             {
552 1         3 $col_ref = {};
553 1         12 %$col_ref = %+;
554 1         16 $self->message( 9, "Rgba colour '$+{red}', '$+{green}' and '$+{blue}' found with opacity $+{opacity}: ", sub{ $self->dumper( $col_ref ) });
  0         0  
555 1 50       8 if( $+{opacity} )
556             {
557 1         3 my $opacity = $+{opacity};
558 1         5 $self->message( 9, "Opacity of $opacity found, applying the factor to the colour." );
559 1         2 my $bg;
560 1 50       3 if( $opts->{bgcolour} )
561             {
562 1         3 $bg = $self->colour_to_rgb( $opts->{bgcolour} );
563 1         5 $self->message( 9, "Calculating new rgb with opacity and background information: ", sub{ $self->dumper( $bg ) });
  0         0  
564             }
565 1         5 my $new_col = $colour_with_alpha->( @$col_ref{qw( red green blue )}, $opacity, $bg );
566 1         5 $self->message( 9, "New colour with opacity applied: ", sub{ $self->dumper( $new_col ) });
  0         0  
567 1         4 @$col_ref{qw( red green blue )} = @$new_col;
568 1         19 $self->message( 9, "Colour $+{red}, $+{green}, $+{blue} * $opacity => $col_ref->{red}, $col_red->{green}, $col_ref->{blue}" );
569             }
570             return({
571             _24bits => [@$col_ref{qw( red green blue )}],
572 1         5 _8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} )
573             });
574             }
575             elsif( $self->message( 9, "Checking if rgb value exists for colour '$col'" ) &&
576             ( $col_ref = $self->colour_to_rgb( $col ) ) )
577             {
578 13         70 $self->message( 9, "Setting up colour '$col' with data: ", sub{ $self->dumper( $col_ref ) });
  0         0  
579             ## $code = $map->{ $col };
580             return({
581             _24bits => [@$col_ref{qw( red green blue )}],
582 13         56 _8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} )
583             });
584             }
585             else
586             {
587 1         4 $self->message( 9, "Could not find a match for colour '$col'." );
588 1         3 return( {} );
589             }
590             # my $is_bg = ( CORE::substr( $code, 0, 1 ) == 4 );
591             # if( CORE::length( $code ) && $light )
592             # {
593             # ## If the colour is a background colour, replace 4 by 10 (e.g.: 42 becomes 103)
594             # ## and if foreground colour, replace 3 by 9
595             # CORE::substr( $code, 0, 1 ) = ( $is_bg ? 10 : 9 );
596             # }
597             # return( $code );
598 12         84 };
599 12         21 my $data = [];
600 12         22 my $params = [];
601             ## 8 bits parameters compatible
602 12         16 my $params8 = [];
603 12 0 33     29 if( $opts->{colour} || $opts->{color} || $opts->{fgcolour} || $opts->{fgcolor} || $opts->{fg_colour} || $opts->{fg_color} )
      0        
      0        
      0        
      0        
604             {
605 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        
606 12         25 my $col_ref = $check_colour->( $opts->{colour}, $colours );
607             ## CORE::push( @$params, $col ) if( CORE::length( $col ) );
608 12 100       46 if( scalar( keys( %$col_ref ) ) )
609             {
610 11     0   69 $self->message( 9, "Foreground colour '$opts->{colour}' data are: ", sub{ $self->dumper( $col_ref ) });
  0         0  
611 11         54 CORE::push( @$params8, sprintf( '38;5;%d', $col_ref->{_8bits} ) );
612 11         22 CORE::push( @$params, sprintf( '38;2;%d;%d;%d', @{$col_ref->{_24bits}} ) );
  11         71  
613             }
614             else
615             {
616 1         4 $self->message( 9, "Could not resolve the foreground colour '$opts->{colour}'." );
617             }
618             }
619 12 50 66     74 if( $opts->{bgcolour} || $opts->{bgcolor} || $opts->{bg_colour} || $opts->{bg_color} )
      33        
      33        
620             {
621 6   0     14 $opts->{bgcolour} ||= CORE::delete( $opts->{bgcolor} ) || CORE::delete( $opts->{bg_colour} ) || CORE::delete( $opts->{bg_color} );
      33        
622 6         14 my $col_ref = $check_colour->( $opts->{bgcolour}, $bg_colours );
623             ## CORE::push( @$params, $col ) if( CORE::length( $col ) );
624 6 50       21 if( scalar( keys( %$col_ref ) ) )
625             {
626 6     0   33 $self->message( 9, "Foreground colour '$opts->{bgcolour}' data are: ", sub{ $self->dumper( $col_ref ) });
  0         0  
627 6         28 CORE::push( @$params8, sprintf( '48;5;%d', $col_ref->{_8bits} ) );
628 6         10 CORE::push( @$params, sprintf( '48;2;%d;%d;%d', @{$col_ref->{_24bits}} ) );
  6         29  
629             }
630             else
631             {
632 0         0 $self->message( 9, "Could not resolve the background colour '$opts->{colour}'." );
633             }
634             }
635 12 100       36 if( $opts->{style} )
636             {
637             ## $self->message( 9, "Style '$opts->{style}' provided." );
638 11         39 my $those_styles = [CORE::split( /\|/, $opts->{style} )];
639             ## $self->message( 9, "Split styles: ", sub{ $self->dumper( $those_styles ) } );
640 11         27 foreach my $s ( @$those_styles )
641             {
642             ## $self->message( 9, "Adding style '$s'" ) if( CORE::exists( $styles->{lc($s)} ) );
643 12 50       31 if( CORE::exists( $styles->{lc($s)} ) )
644             {
645 12         22 CORE::push( @$params, $styles->{lc($s)} );
646             ## We add the 8 bits compliant version only if any colour was provided, i.e.
647             ## This is not just a style definition
648 12 50       39 CORE::push( @$params8, $styles->{lc($s)} ) if( scalar( @$params8 ) );
649             }
650             }
651             }
652 12 100       54 CORE::push( @$data, "\e[" . CORE::join( ';', @$params8 ) . "m" ) if( scalar( @$params8 ) );
653 12 100       41 CORE::push( @$data, "\e[" . CORE::join( ';', @$params ) . "m" ) if( scalar( @$params ) );
654 12     0   52 $self->message( 9, "Pre final colour data contains: ", sub{ $self->dumper( $data ) });
  0         0  
655             ## 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
656 12 100 100     74 if( scalar( @$params ) && $opts->{text} =~ /\n+/ )
657             {
658 1         6 my $text_parts = [CORE::split( /\n/, $opts->{text} )];
659 1         4 my $fmt = CORE::join( '', @$data );
660 1         4 my $fmt8 = CORE::join( '', @$data8 );
661 1         5 for( my $i = 0; $i < scalar( @$text_parts ); $i++ )
662             {
663             ## Empty due to \n repeated
664 2 50       6 next if( !CORE::length( $text_parts->[$i] ) );
665 2         9 $text_parts->[$i] = $fmt . $text_parts->[$i] . $normal;
666             }
667 1         3 $opts->{text} = CORE::join( "\n", @$text_parts );
668 1         3 CORE::push( @$data, $opts->{text} );
669             }
670             else
671             {
672 11         24 CORE::push( @$data, $opts->{text} );
673 11 100       27 CORE::push( @$data, $normal, $normal ) if( scalar( @$params ) );
674             }
675             ## $self->message( "Returning '", quotemeta( CORE::join( '', @$data ) ), "'" );
676 12         393 return( CORE::join( '', @$data ) );
677             }
678              
679 2     2 0 8 sub colour_open { return( shift->_set_get( 'colour_open', @_ ) ); }
680              
681             sub colour_parse
682             {
683 5     5 1 17 my $self = shift( @_ );
684 5         17 my $txt = join( '', @_ );
685 5         13 my $this = $self->_obj2h;
686 5   50     49 my $open = $this->{colour_open} || COLOUR_OPEN;
687 5   50     16 my $close = $this->{colour_close} || COLOUR_CLOSE;
688 5         123 my $re = qr/
689             (?<all>
690             \Q$open\E(?!\/)(?<params>.*?)\Q$close\E
691             (?<content>
692             (?:
693             (?> [^$open$close]+ )
694             |
695             (?R)
696             )*+
697             )
698             \Q$open\E\/\Q$close\E
699             )
700             /x;
701 5         15 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:]]*\))/;
702 5         13 my $style_re = qr/(?:bold|faint|italic|underline|blink|reverse|conceal|strike)/;
703             local $parse = sub
704             {
705 7     7   15 my $str = shift( @_ );
706             ## $self->message( 9, "Parsing coloured text '$str'" );
707 7         91 $str =~ s{$re}
708 9         133 {
709 9         60 my $re = { %- };
710             my $catch = substr( $str, $-[0], $+[0] - $-[0] );
711 9         45 ## $self->message( 9, "Regexp is: ", sub{ $self->dump( $re ) } );
712 9         35 my $all = $+{all};
713 9         32 my $ct = $+{content};
714 9 100 66     43 my $params = $+{params};
715             if( index( $ct, $open ) != -1 && index( $ct, $close ) != -1 )
716 2         11 {
717             $ct = $parse->( $ct );
718 9         16 }
719 9 100       336 my $def = {};
720             if( $params =~ /^[[:blank:]]*(?:(?<style1>$style_re)[[:blank:]]+)?(?<fg_colour>$colour_re)(?:[[:blank:]]+(?<style2>$style_re))?(?:[[:blank:]]+on[[:blank:]]+(?<bg_colour>$colour_re))?[[:blank:]]*$/i )
721 5   66     36 {
722 5         22 $style = $+{style1} || $+{style2};
723 5         18 $fg = $+{fg_colour};
724             $bg = $+{bg_colour};
725 5         23 ## $self->message( 9, "Found style '$style', colour '$fg' and background colour '$bg'." );
726             $def =
727             {
728             style => $style,
729             colour => $fg,
730             bg_colour => $bg,
731             };
732             }
733             else
734             {
735 4         235 ## $self->message( 9, "Evaluating the styling '$params'." );
736             my @res = eval( $params );
737 4 50 33     41 ## $self->message( 9, "Evaluation result is: ", sub{ $self->dump( [ @res ] ) } );
738 4 50 33     28 $def = { @res } if( scalar( @res ) && !( scalar( @res ) % 2 ) );
739             if( $@ || ref( $def ) ne 'HASH' )
740 0   0     0 {
741 0         0 $err = $@ || "Invalid styling \"${params}\"";
742 0         0 $self->message( 9, "Error evaluating: $@" );
743             $def = {};
744             }
745 9 50       34 }
746             if( scalar( keys( %$def ) ) )
747 9         21 {
748 9         125 $def->{text} = $ct;
  0         0  
749 9         35 $self->message( 9, "Calling colour_parse with parameters: ", sub{ $self->dump( $def )} );
750 9 50       86 my $res = $self->colour_format( $def );
751             length( $res ) ? $res : $catch;
752             }
753             else
754 0         0 {
755 0         0 $self->message( 9, "Returning '$catch'" );
756             $catch;
757             }
758 7         77 }gex;
759 5         34 return( $str );
760 5         12 };
761             return( $parse->( $txt ) );
762             }
763              
764             sub colour_to_rgb
765 15     15 0 28 {
766 15         33 my $self = shift( @_ );
767 15         32 my $colour = lc( shift( @_ ) );
768 15         33 my $this = $self->_obj2h;
769 15         157 my( $red, $green, $blue ) = ( '', '', '' );
770 15 50       93 $self->message( 9, "Checking rgb value for '$colour'. Called from line ", (caller)[2] );
    0          
    0          
771             if( $colour =~ /^[A-Za-z]+([\w\-]+)*([[:blank:]]+\w+)?$/ )
772 15         50 {
773 15 100       45 $self->message( 9, "Checking colour '$colour' as string. Looking up its rgb value." );
774             if( !scalar( keys( %$COLOUR_NAME_TO_RGB ) ) )
775 1         4 {
776 1         4 $self->message( 9, "Processing colour map in <DATA> section." );
777 1         3597 my $colour_data = $self->__colour_data;
778 1 50       11 $COLOUR_NAME_TO_RGB = eval( $colour_data );
779             if( $@ )
780 0         0 {
781             return( $self->error( "An error occurred loading data from __colour_data: $@" ) );
782             }
783 15 100       38 }
784             if( CORE::exists( $COLOUR_NAME_TO_RGB->{ $colour } ) )
785 14         22 {
  14         36  
786 14         47 ( $red, $green, $blue ) = @{$COLOUR_NAME_TO_RGB->{ $colour }};
787             $self->message( 9, "Found rgb '$red, $green, $blue' for colour '$colour'." );
788             }
789             else
790 1         6 {
791 1         5 $self->message( 9, "Could not find colour '$colour' in our colour map." );
792             return( '' );
793             }
794             }
795             ## Colour all in decimal??
796             elsif( $colour =~ /^\d{9}$/ )
797             {
798 0         0 ## $self->message( 9, "Got colour all in decimal. Less work to do..." );
799 0         0 $red = substr( $colour, 0, 3 );
800 0         0 $green = substr( $colour, 3, 3 );
801             $blue = substr( $colour, 6, 3 );
802             }
803             ## Colour in hexadecimal, convert it
804             elsif( $colour =~ /^[A-F0-9]+$/ )
805 0         0 {
806 0         0 $red = hex( substr( $colour, 0, 2 ) );
807 0         0 $green = hex( substr( $colour, 2, 2 ) );
808             $blue = hex( substr( $colour, 4, 2 ) );
809             }
810             ## Clueless
811             else
812 0         0 {
813             $self->message( 9, "Clueless about what to do with colour '$colour'." );
814 0         0 ## Not undef, but rather empty string. Undef is associated with an error
815             return( '' );
816 14         78 }
817             return({ red => $red, green => $green, blue => $blue });
818             }
819              
820             sub coloured
821 3     3 1 8 {
822 3         8 my $self = shift( @_ );
823 3         9 my $pref = shift( @_ );
824 3         9 my $text = CORE::join( '', @_ );
825 3         7 my $this = $self->_obj2h;
826             my( $style, $fg, $bg );
827 3         14 ## my $colour_re = qr/(?:(?:bright|light)[[:blank:]])?[a-zA-Z]+/;
828 3         7 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:]]*\))/;
829 3 50       226 my $style_re = qr/(?:bold|faint|italic|underline|blink|reverse|conceal|strike)/;
830             if( $pref =~ /^(?:(?<style1>$style_re)[[:blank:]]+)?(?<fg_colour>$colour_re)(?:[[:blank:]]+(?<style2>$style_re))?(?:[[:blank:]]+on[[:blank:]]+(?<bg_colour>$colour_re))?$/i )
831 3   33     29 {
832 3         16 $style = $+{style1} || $+{style2};
833 3         11 $fg = $+{fg_colour};
834             $bg = $+{bg_colour};
835 3         18 ## $self->message( 9, "Found style '$style', colour '$fg' and background colour '$bg'." );
836             return( $self->colour_format({ text => $text, style => $style, colour => $fg, bg_colour => $bg }) );
837             }
838             else
839 0         0 {
840 0         0 $self->message( 9, "No match." );
841             return( '' );
842             }
843             }
844              
845             sub debug
846 153     153 1 267 {
847 153         277 my $self = shift( @_ );
848 153         340 my $class = ref( $self );
849 153 100       722 my $this = $self->_obj2h;
850             if( @_ )
851 148         306 {
852 148         280 my $flag = shift( @_ );
853 148 50       385 $this->{debug} = $flag;
854 148 50 33     487 $self->message_switch( $flag ) if( $OPTIMIZE_MESG_SUB );
855             if( $this->{debug} &&
856             !$this->{debug_level} )
857 0         0 {
858             $this->{debug_level} = $this->{debug};
859             }
860 153   33     411 }
861             return( $this->{debug} || ${"$class\:\:DEBUG"} );
862             }
863              
864             sub dump
865 0     0 1 0 {
866 0         0 my $self = shift( @_ );
867 0 0 0     0 my $opts = {};
      0        
      0        
868             if( @_ > 1 &&
869             ref( $_[-1] ) eq 'HASH' &&
870             exists( $_[-1]->{filter} ) &&
871             ref( $_[-1]->{filter} ) eq 'CODE' )
872 0         0 {
873 0         0 $opts = pop( @_ );
874             return( Data::Dump::dumpf( @_, $opts->{filter} ) );
875             }
876             else
877 0         0 {
878             return( Data::Dump::dump( @_ ) );
879             }
880             }
881              
882 0     0 1 0 ## For backward compatibility and traceability
883             sub dump_print { return( shift->dumpto_printer( @_ ) ); }
884              
885             sub dumper
886 0     0 1 0 {
887 0         0 my $self = shift( @_ );
888 0 0 0     0 my $opts = {};
889             $opts = pop( @_ ) if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' );
890 0         0 # local $Data::Dumper::Sortkeys = 1;
891 0         0 local $Data::Dumper::Terse = 1;
892 0         0 local $Data::Dumper::Indent = 1;
893 0 0       0 local $Data::Dumper::Useqq = 1;
894             local $Data::Dumper::Maxdepth = $opts->{depth} if( CORE::length( $opts->{depth} ) );
895             local $Data::Dumper::Sortkeys = sub
896 0     0   0 {
897 0         0 my $h = shift( @_ );
  0         0  
898 0         0 return( [ sort( grep{ ref( $h->{ $_ } ) !~ /^(DateTime|DateTime\:\:)/ } keys( %$h ) ) ] );
899 0         0 };
900             return( Data::Dumper::Dumper( @_ ) );
901             }
902              
903             sub printer
904 0     0 1 0 {
905 0         0 my $self = shift( @_ );
906 0 0 0     0 my $opts = {};
907 0     0   0 $opts = pop( @_ ) if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' );
908             local $SIG{__WARN__} = sub{ };
909 0         0 eval
910 0         0 {
911             require Data::Printer;
912 0 0       0 };
913             unless( $@ )
914 0 0       0 {
915             if( scalar( keys( %$opts ) ) )
916 0         0 {
917             return( Data::Printer::np( @_, %$opts ) );
918             }
919             else
920 0         0 {
921             return( Data::Printer::np( @_ ) );
922             }
923             }
924             }
925              
926             *dumpto = \&dumpto_dumper;
927              
928             sub dumpto_printer
929 0     0 1 0 {
930 0         0 my $self = shift( @_ );
931 0   0     0 my( $data, $file ) = @_;
932 0         0 my $fh = IO::File->new( ">$file" ) || die( "Unable to create file '$file': $!\n" );
933 0         0 $fh->binmode( ':utf8' );
934 0         0 $fh->print( Data::Dump::dump( $data ), "\n" );
935             $fh->close;
936 0         0 ## 666 so it can work under command line and web alike
937 0         0 chmod( 0666, $file );
938             return( 1 );
939             }
940              
941             sub dumpto_dumper
942 0     0 1 0 {
943 0         0 my $self = shift( @_ );
944 0         0 my( $data, $file ) = @_;
945 0         0 local $Data::Dumper::Sortkeys = 1;
946 0         0 local $Data::Dumper::Terse = 1;
947 0         0 local $Data::Dumper::Indent = 1;
948 0   0     0 local $Data::Dumper::Useqq = 1;
949 0 0       0 my $fh = IO::File->new( ">$file" ) || die( "Unable to create file '$file': $!\n" );
950             if( ref( $data ) )
951 0         0 {
952             $fh->print( Data::Dumper::Dumper( $data ), "\n" );
953             }
954             else
955 0         0 {
956 0         0 $fh->binmode( ':utf8' );
957             $fh->print( $data );
958 0         0 }
959             $fh->close;
960 0         0 ## 666 so it can work under command line and web alike
961 0         0 chmod( 0666, $file );
962             return( 1 );
963             }
964              
965             sub errno
966 0     0 0 0 {
967 0         0 my $self = shift( @_ );
968 0 0       0 my $this = $self->_obj2h;
969             if( @_ )
970 0 0       0 {
971 0 0       0 $this->{errno} = shift( @_ ) if( $_[ 0 ] =~ /^\-?\d+$/ );
972             return( $self->error( @_ ) ) if( @_ );
973 0         0 }
974             return( $this->{errno} );
975             }
976              
977             sub error
978 1     1 1 3 {
979 1   33     4 my $self = shift( @_ );
980 1         5 my $class = ref( $self ) || $self;
981 1 50       4 my $this = $self->_obj2h;
982             if( @_ )
983 1         2 {
984 1 50 33     8 my $args = {};
    50          
985             if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic::Exception' ) )
986 0         0 {
987             $args->{object} = shift( @_ );
988             }
989             elsif( ref( $_[0] ) eq 'HASH' )
990 0         0 {
991             $args = shift( @_ );
992             }
993             else
994 1 50 33     12 {
995             $args->{message} = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @_ ) );
996 1 50 33     8 }
997             $args->{message} = substr( $args->{message}, 0, $this->{error_max_length} ) if( $this->{error_max_length} > 0 && length( $args->{message} ) > $this->{error_max_length} );
998 1         3 # Reset it
999 1         2 $this->{_msg_no_exec_sub} = 0;
1000             my $n = 1;
1001 1         4 # $n++ while( ( caller( $n ) )[0] eq 'Module::Generic' );
1002             $args->{skip_frames} = $n + 1;
1003             ## my( $p, $f, $l ) = caller( $n );
1004 1         19 ## my( $sub ) = ( caller( $n + 1 ) )[3];
  1         6  
1005             my $o = $this->{error} = ${ $class . '::ERROR' } = Module::Generic::Exception->new( $args );
1006             ## 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 );
1007            
1008             ## Get the warnings status of the caller. We use caller(1) to skip one frame further, ie our caller's caller
1009 1         3 ## This can be changed by using 'no warnings'
1010 1         2 my $should_display_warning = 0;
1011             my $no_use_warnings = 1;
1012 1         2 ## Try to get the warnings status if is enabled at all.
1013 1     1   2 try
1014 1         26 {
1015 1         3 $should_display_warning = $self->_warnings_is_enabled;
1016             $no_use_warnings = 0;
1017 1 50       5 }
  1 50       3  
  1 50       3  
  1 0       2  
  1 50       2  
  1         2  
  1         2  
  1         2  
  1         5  
  0         0  
  1         3  
  0         0  
  1         4  
  1         2  
  1         2  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
1018 0     0   0 catch( $e )
1019             {
1020 0 0 33     0 #
  0 0 33     0  
  0 0       0  
  0 50       0  
  0         0  
  0         0  
  1         13  
  0         0  
1021             }
1022 1 50       3
1023             if( $no_use_warnings )
1024 0         0 {
1025 0         0 my $call_offset = 0;
1026             while( my @call_data = caller( $call_offset ) )
1027             {
1028 0 0 0     0 ## 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] );
      0        
1029             unless( $call_offset > 0 && $call_data[0] ne $class && (caller($call_offset-1))[0] eq $class )
1030             {
1031 0         0 ## print( STDERR "Skipping package $call_data[0]\n" );
1032 0         0 $call_offset++;
1033             next;
1034 0 0 0     0 }
      0        
1035 0         0 last if( $call_data[9] || ( $call_offset > 0 && (caller($call_offset-1))[0] ne $class ) );
1036             $call_offset++;
1037             }
1038 0         0 ## print( STDERR "Using offset $call_offset with bitmask ", ( caller( $call_offset ) )[9], "\n" );
1039 0         0 my $bitmask = ( caller( $call_offset ) )[9];
1040             my $offset = $warnings::Offsets{uninitialized};
1041 0         0 ## $self->message( 3, "Caller (2)'s bitmask is '$bitmask', warnings offset is '$offset' and vector is '", vec( $bitmask, $offset, 1 ), "'." );
1042             $should_display_warning = vec( $bitmask, $offset, 1 );
1043             }
1044 1         3
1045 1 50       2 my $r;
1046             $r = Apache2::RequestUtil->request if( $MOD_PERL );
1047 1 50       3 # $r->log_error( "Called for error $o" ) if( $r );
1048 1         6 $r->warn( $o->as_string ) if( $r );
1049 1 50 33     10 my $err_handler = $self->error_handler;
    50 33        
    50          
    50          
1050             if( $err_handler && ref( $err_handler ) eq 'CODE' )
1051             {
1052 0         0 # $r->log_error( "Module::Generic::error(): called for object error hanler" ) if( $r );
1053             $err_handler->( $o );
1054             }
1055             elsif( $r )
1056             {
1057 0 0       0 # $r->log_error( "Module::Generic::error(): called for Apache mod_perl error hanler" ) if( $r );
1058             if( my $log_handler = $r->get_handlers( 'PerlPrivateErrorHandler' ) )
1059 0         0 {
1060             $log_handler->( $o );
1061             }
1062             else
1063             {
1064             # $r->log_error( "Module::Generic::error(): No Apache mod_perl error handler set, reverting to log_error" ) if( $r );
1065 0 0       0 # $r->log_error( "$o" );
1066             $r->warn( $o->as_string ) if( $should_display_warning );
1067             }
1068             }
1069             elsif( $this->{fatal} )
1070             {
1071             ## die( sprintf( "Within package %s in file %s at line %d: %s\n", $o->package, $o->file, $o->line, $o->message ) );
1072 0         0 # $r->log_error( "Module::Generic::error(): called calling die" ) if( $r );
  0         0  
1073 0 0       0 my $enc_str = eval{ Encode::encode( 'UTF-8', "$o", Encode::FB_CROAK ) };
1074             die( $@ ? $o : $enc_str );
1075             }
1076             elsif( !exists( $this->{quiet} ) || !$this->{quiet} )
1077             {
1078 1 50       2 # $r->log_error( "Module::Generic::error(): calling warn" ) if( $r );
1079             if( $r )
1080 0 0       0 {
1081             $r->warn( $o->as_string ) if( $should_display_warning );
1082             }
1083             else
1084 1         2 {
  1         4  
1085 1 0       214 my $enc_str = eval{ Encode::encode( 'UTF-8', "$o", Encode::FB_CROAK ) };
    50          
1086             warn( $@ ? $o : $enc_str ) if( $should_display_warning );
1087             }
1088             }
1089 1 50       5
1090             if( overload::Overloaded( $self ) )
1091 1         39 {
1092 1         56 my $overload_meth_ref = overload::Method( $self, '""' );
1093 1 50       9 my $overload_meth_name = '';
1094             $overload_meth_name = Sub::Util::subname( $overload_meth_ref ) if( ref( $overload_meth_ref ) );
1095             ## use Sub::Identify ();
1096             ## my( $over_file, $over_line ) = Sub::Identify::get_code_location( $overload_meth_ref );
1097 1         6 # my( $over_call_pack, $over_call_file, $over_call_line ) = caller();
1098             my $call_sub = (caller(1))[3];
1099             # my $call_hash = (caller(0))[10];
1100             # my @call_keys = CORE::keys( %$call_hash );
1101             # print( STDERR "\$self is overloaded and stringification method is '$overload_meth', its sub name is '$overload_meth_name' from file '$over_file' at line '$over_line' and our caller subroutine is '$call_sub' from file '$over_call_file' at line '$over_call_line' with hint hash keys '@call_keys'.\n" );
1102             ## overloaded method name can be, for example: My::Package::as_string
1103             ## or, for anonymous sub: My::Package::__ANON__[lib/My/Package.pm:12]
1104             ## caller sub will reliably be the same, so we use it to check if we are called from an overloaded stringification and return undef right here.
1105 1 50 33     7 ## Want::want check of being called in an OBJECT context triggers a perl segmentation fault
1106             if( length( $overload_meth_name ) && $overload_meth_name eq $call_sub )
1107 1         6 {
1108             return;
1109             }
1110             }
1111            
1112             ## https://metacpan.org/pod/Perl::Critic::Policy::Subroutines::ProhibitExplicitReturnUndef
1113             ## https://perlmonks.org/index.pl?node_id=741847
1114             ## Because in list context this would create a lit with one element undef()
1115             ## A bare return will return an empty list or an undef scalar
1116             ## return( undef() );
1117             ## return;
1118             ## 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
1119             ## 2020-05-12: Added the no_return_null_object to instruct not to return a null object
1120             ## This is especially needed when an error is called from TIEHASH that returns a special object.
1121 0 0 0     0 ## A Null object would trigger a fatal perl segmentation fault
1122             if( !$args->{no_return_null_object} && want( 'OBJECT' ) )
1123 0         0 {
1124 0         0 my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 });
1125             rreturn( $null );
1126 0         0 }
1127             return;
1128 0 0       0 }
  0         0  
1129             return( ref( $self ) ? $this->{error} : ${ $class . '::ERROR' } );
1130             }
1131 1     1 0 6  
1132             sub error_handler { return( shift->_set_get_code( '_error_handler', @_ ) ); }
1133              
1134             *errstr = \&error;
1135              
1136             sub get
1137 0     0 1 0 {
1138 0         0 my $self = shift( @_ );
1139 0 0       0 my $this = $self->_obj2h;
1140 0         0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
  0         0  
1141 0 0       0 my @data = map{ $data->{ $_ } } @_;
1142             return( wantarray() ? @data : $data[ 0 ] );
1143             }
1144              
1145             sub init
1146 298     298 1 618 {
1147 298         671 my $self = shift( @_ );
1148 298         811 my $pkg = ref( $self );
1149 298 50       7383 my $this = $self->_obj2h;
  298         1827  
1150 298 100       1152 $this->{verbose} = ${ $pkg . '::VERBOSE' } if( !length( $this->{verbose} ) );
  150         643  
1151 298 50       1034 $this->{debug} = ${ $pkg . '::DEBUG' } if( !length( $this->{debug} ) );
  298         1265  
1152 298         791 $this->{version} = ${ $pkg . '::VERSION' } if( !defined( $this->{version} ) );
1153 298 50       1136 $this->{level} = 0;
1154 298 50       1270 $this->{colour_open} = COLOUR_OPEN if( !length( $this->{colour_open} ) );
1155             $this->{colour_close} = COLOUR_CLOSE if( !length( $this->{colour_close} ) );
1156             ## If no debug level was provided when calling message, this level will be assumed
1157             ## Example: message( "Hello" );
1158 298         815 ## If _message_default_level was set to 3, this would be equivalent to message( 3, "Hello" )
1159 298         595 $this->{ '_message_default_level' } = 0;
1160 298 50       846 my $data = $this;
1161             if( $this->{_data_repo} )
1162 0 0       0 {
1163 0         0 $this->{ $this->{_data_repo} } = {} if( !$this->{ $this->{_data_repo} } );
1164             $data = $this->{ $this->{_data_repo} };
1165 298 50 66     1564 }
1166 298 100       897 @_ = () if( @_ == 1 && !defined( $_[0] ) );
1167             if( @_ )
1168 82         203 {
1169 82         168 my @args = @_;
1170 82 100 33     433 my $vals;
    50 66        
    50 33        
    50          
1171             if( ref( $args[0] ) eq 'HASH' ||
1172             ( Scalar::Util::blessed( $args[0] ) && $args[0]->isa( 'Module::Generic::Hash' ) ) )
1173             {
1174 80         201 ## $self->_message( 3, "Got an hash ref" );
1175 80         217 my $h = shift( @args );
1176 80 50       303 my $debug_value;
1177 80         672 $debug_value = $h->{debug} if( CORE::exists( $h->{debug} ) );
1178 80 100       435 $vals = [ %$h ];
1179             unshift( @$vals, debug => $debug_value ) if( CORE::defined( $debug_value ) );
1180             ## $vals = [ %{$_[0]} ];
1181             }
1182             elsif( ref( $args[0] ) eq 'ARRAY' )
1183             {
1184 0         0 ## $self->_message( 3, "Got an array ref" );
1185             $vals = $args[0];
1186             }
1187             ## Special case when there is an undefined value passed (null) even though it is declared as a hash or object
1188             elsif( scalar( @args ) == 1 && !defined( $args[0] ) )
1189             {
1190 0         0 # return( undef() );
1191             return;
1192             }
1193             elsif( ( scalar( @args ) % 2 ) )
1194 0         0 {
1195             return( $self->error( sprintf( "Uneven number of parameters provided (%d). Should receive key => value pairs. Parameters provideds are: %s", scalar( @args ), join( ', ', @args ) ) ) );
1196             }
1197             else
1198             {
1199 2         5 ## $self->message( 3, "Got an array: ", sub{ $self->dumper( \@args ) } );
1200             $vals = \@args;
1201             }
1202             ## Check if there is a debug parameter, and if we find one, set it first so that that
1203 82         418 ## calls to the package subroutines can produce verbose feedback as necessary
1204             for( my $i = 0; $i < scalar( @$vals ); $i++ )
1205 2089 100       3743 {
1206             if( $vals->[$i] eq 'debug' )
1207 138         315 {
1208 138         518 my $v = $vals->[$i + 1];
1209 138         487 $self->debug( $v );
1210             CORE::splice( @$vals, $i, 2 );
1211             }
1212             }
1213 82         321
1214             for( my $i = 0; $i < scalar( @$vals ); $i++ )
1215 1042         1645 {
1216 1042         1713 my $name = $vals->[ $i ];
1217 1042         2832 my $val = $vals->[ ++$i ];
1218             my $meth = $self->can( $name );
1219 1042 50       1818 # $self->message( 3, "Does the object from class (", ref( $self ), ") has a method $name? ", ( defined( $meth ) ? 'yes' : 'no' ) );
    0          
    0          
1220             if( defined( $meth ) )
1221 1042         2590 {
1222 1042         3282 $self->$name( $val );
1223             next;
1224             }
1225             elsif( $this->{_init_strict_use_sub} )
1226             {
1227             # $self->message( 3, "Checking if method $name exist in class ", ref( $self ), ": ", $self->can( $name ) ? 'yes' : 'no' );
1228             #if( !defined( $meth = $self->can( $name ) ) )
1229 0         0 #{
1230 0         0 $self->error( "Unknown method $name in class $pkg" );
1231             next;
1232             #}
1233             # $self->message( 3, "Calling method $name with value $val" );
1234             # $self->$meth( $val );
1235             # $meth->( $self, $val );
1236             #$self->$name( $val );
1237             #next;
1238             }
1239             elsif( exists( $data->{ $name } ) )
1240             {
1241 0 0 0     0 ## Pre-existing field value looks like a module package and that package is already loaded
    0 0        
1242             if( ( index( $data->{ $name }, '::' ) != -1 || $data->{ $name } =~ /^[a-zA-Z][a-zA-Z\_]*[a-zA-Z]$/ ) &&
1243             $self->_is_class_loaded( $data->{ $name } ) )
1244 0         0 {
1245 0 0       0 my $thisPack = $data->{ $name };
    0          
1246             if( !Scalar::Util::blessed( $val ) )
1247 0         0 {
1248             return( $self->error( "$name parameter expects a package $thisPack object, but instead got '$val'." ) );
1249             }
1250             elsif( !$val->isa( $thisPack ) )
1251 0         0 {
1252             return( $self->error( "$name parameter expects a package $thisPack object, but instead got an object from package '", ref( $val ), "'." ) );
1253             }
1254             }
1255             elsif( $this->{_init_strict} )
1256 0 0       0 {
    0          
    0          
1257             if( ref( $data->{ $name } ) eq 'ARRAY' )
1258 0 0       0 {
1259             return( $self->error( "$name parameter expects an array reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'ARRAY' );
1260             }
1261             elsif( ref( $data->{ $name } ) eq 'HASH' )
1262 0 0       0 {
1263             return( $self->error( "$name parameter expects an hash reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'HASH' );
1264             }
1265             elsif( ref( $data->{ $name } ) eq 'SCALAR' )
1266 0 0       0 {
1267             return( $self->error( "$name parameter expects a scalar reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'SCALAR' );
1268             }
1269             }
1270             }
1271             ## The name parameter does not exist
1272             else
1273             {
1274 0 0       0 ## If we are strict, we reject
1275             next if( $this->{_init_strict} );
1276             }
1277 0         0 ## We passed all tests
1278             $data->{ $name } = $val;
1279             }
1280 298         1421 }
1281             $self->message_switch( $this->{debug} );
1282             # if( $OPTIMIZE_MESG_SUB && !$this->{verbose} && !$this->{debug} )
1283             # {
1284             # if( defined( &{ "$pkg\::message" } ) )
1285             # {
1286             # *{ "$pkg\::message_off" } = \&{ "$pkg\::message" } unless( defined( &{ "$pkg\::message_off" } ) );
1287             # *{ "$pkg\::message" } = sub { 1 };
1288             # }
1289 298         601 # }
1290             return( $self );
1291             }
1292 0     0 1 0  
1293             sub log_handler { return( shift->_set_get_code( '_log_handler', @_ ) ); }
1294              
1295             # sub log4perl
1296             # {
1297             # my $self = shift( @_ );
1298             # if( @_ )
1299             # {
1300             # require Log::Log4perl;
1301             # my $ref = shift( @_ );
1302             # Log::Log4perl::init( $ref->{ 'config_file' } );
1303             # my $log = Log::Log4perl->get_logger( $ref->{ 'domain' } );
1304             # $self->{ 'log4perl' } = $log;
1305             # }
1306             # else
1307             # {
1308             # $self->{ 'log4perl' };
1309             # }
1310             # }
1311              
1312             sub message
1313 0     0 1 0 {
1314 0   0     0 my $self = shift( @_ );
1315             my $class = ref( $self ) || $self;
1316 0         0 ## my( $pack, $file, $line ) = caller;
1317             my $this = $self->_obj2h;
1318 0         0 ## 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" );
1319 0 0       0 my $r;
1320 0 0 0     0 $r = Apache2::RequestUtil->request if( $MOD_PERL );
  0   0     0  
1321             if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
1322             {
1323 0         0 # $r->log_error( "Got here in Module::Generic::message before checking message." ) if( $r );
1324 0         0 my $ref;
1325             $ref = $self->message_check( @_ );
1326             ## print( STDERR __PACKAGE__ . "::message(): message_check() returns '$ref' (", join( '', @$ref ), ")\n" );
1327 0 0       0 ## return( 1 ) if( !( $ref = $self->message_check( @_ ) ) );
1328             return( 1 ) if( !$ref );
1329 0         0
1330 0 0       0 my $opts = {};
1331             $opts = pop( @$ref ) if( ref( $ref->[-1] ) eq 'HASH' );
1332             ## print( STDERR __PACKAGE__ . "::message(): \$opts contains: ", $self->dumper( $opts ), "\n" );
1333            
1334             ## By now, we should have a reference to @_ in $ref
1335             ## my $class = ref( $self ) || $self;
1336             ## print( STDERR __PACKAGE__ . "::message(): caller at 0 is ", (caller(0))[3], " and at 1 is ", (caller(1))[3], "\n" );
1337 0   0     0 ## $r->log_error( "Got here in Module::Generic::message checking frames stack." ) if( $r );
1338 0 0       0 my $stackFrame = $self->message_frame( (caller(1))[3] ) || 1;
1339 0 0       0 $stackFrame = 1 unless( $stackFrame =~ /^\d+$/ );
1340 0 0 0     0 $stackFrame-- if( $stackFrame );
1341             $stackFrame++ if( (caller(1))[3] eq 'Module::Generic::messagef' ||
1342 0 0       0 (caller(1))[3] eq 'Module::Generic::message_colour' );
1343 0         0 $stackFrame++ if( (caller(2))[3] eq 'Module::Generic::messagef_colour' );
1344 0         0 my( $pkg, $file, $line, @otherInfo ) = caller( $stackFrame );
1345 0         0 my $sub = ( caller( $stackFrame + 1 ) )[3];
1346 0 0       0 my $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
1347             if( ref( $this->{_message_frame} ) eq 'HASH' )
1348 0 0       0 {
1349             if( exists( $this->{_message_frame}->{ $sub2 } ) )
1350 0         0 {
1351 0 0       0 my $frameNo = int( $this->{_message_frame}->{ $sub2 } );
1352             if( $frameNo > 0 )
1353 0         0 {
1354 0         0 ( $pkg, $file, $line, $sub ) = caller( $frameNo );
1355             $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
1356             }
1357             }
1358             }
1359 0 0       0 ## $r->log_error( "Called from package $pkg in file $file at line $line from sub $sub2 ($sub)" ) if( $r );
1360             if( $sub2 eq 'message' )
1361 0         0 {
1362 0         0 $stackFrame++;
1363 0         0 ( $pkg, $file, $line, @otherInfo ) = caller( $stackFrame );
1364 0         0 my $sub = ( caller( $stackFrame + 1 ) )[3];
1365             $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 );
1366             }
1367 0         0 ## $r->log_error( "Got here in Module::Generic::message building the message string." ) if( $r );
1368 0 0       0 my $txt;
1369             if( $opts->{message} )
1370 0 0       0 {
1371             if( ref( $opts->{message} ) eq 'ARRAY' )
1372 0 0 0     0 {
  0         0  
1373             $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @{$opts->{message}} ) );
1374             }
1375             else
1376 0         0 {
1377             $txt = $opts->{message};
1378             }
1379             }
1380             else
1381 0 0 0     0 {
1382             $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) );
1383             }
1384 0         0 ## Reset it
1385             $this->{_msg_no_exec_sub} = 0;
1386 7     7   68 ## $r->log_error( "Got here in Module::Generic::message with message string '$txt'." ) if( $r );
  7         15  
  7         29064  
1387 0         0 no overloading;
1388 0         0 my $mesg = "${pkg}::${sub2}( $self ) [$line]: " . $txt;
1389 0         0 $mesg =~ s/\n$//gs;
1390             $mesg = '## ' . join( "\n## ", split( /\n/, $mesg ) );
1391            
1392             my $info =
1393             {
1394             'formatted' => $mesg,
1395             'message' => $txt,
1396             'file' => $file,
1397             'line' => $line,
1398             'package' => $class,
1399 0 0       0 'sub' => $sub2,
    0          
1400             'level' => ( $_[0] =~ /^\d+$/ ? $_[0] : CORE::exists( $opts->{level} ) ? $opts->{level} : 0 ),
1401 0 0       0 };
1402             $info->{type} = $opts->{type} if( $opts->{type} );
1403            
1404             ## $r->log_error( "Got here in Module::Generic::message checkin if we run under ModPerl." ) if( $r );
1405             ## If Mod perl is activated AND we are not using a private log
1406             ## my $r;
1407 0 0 0     0 ## if( $MOD_PERL && !${ "${class}::LOG_DEBUG" } && ( $r = eval{ require Apache2::RequestUtil; Apache2::RequestUtil->request; } ) )
  0 0 0     0  
    0 0        
    0 0        
    0 0        
      0        
1408             if( $r && !${ "${class}::LOG_DEBUG" } )
1409             {
1410 0 0       0 ## $r->log_error( "Got here in Module::Generic::message, going to call our log handler." );
1411             if( my $log_handler = $r->get_handlers( 'PerlPrivateLogHandler' ) )
1412             {
1413             # my $meta = B::svref_2object( $log_handler );
1414 0         0 # $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 );
1415             $log_handler->( $mesg );
1416             }
1417             else
1418 0         0 {
1419             $r->log_error( $mesg );
1420             }
1421             }
1422 0         0 ## Using ModPerl Server to log
1423             elsif( $MOD_PERL && !${ "${class}::LOG_DEBUG" } )
1424 0         0 {
1425 0         0 require Apache2::ServerUtil;
1426 0         0 my $s = Apache2::ServerUtil->server;
1427             $s->log_error( $mesg );
1428             }
1429             ## e.g. in our package, we could set the handler using the curry module like $self->{_log_handler} = $self->curry::log
1430             elsif( !-t( STDIN ) && $this->{_log_handler} && ref( $this->{_log_handler} ) eq 'CODE' )
1431             {
1432             # $r = Apache2::RequestUtil->request;
1433             # $r->log_error( "Got here in Module::Generic::message, going to call our log handler without using Apache callbacks." );
1434             # my $meta = B::svref_2object( $self->{_log_handler} );
1435 0         0 # $r->log_error( "Log handler code routine name is " . $meta->GV->NAME . " called in file " . $meta->GV->FILE . " at line " . $meta->GV->LINE );
1436             $this->{_log_handler}->( $info );
1437 0         0 }
  0         0  
1438             elsif( !-t( STDIN ) && ${ $class . '::MESSAGE_HANDLER' } && ref( ${ $class . '::MESSAGE_HANDLER' } ) eq 'CODE' )
1439 0         0 {
  0         0  
1440 0         0 my $h = ${ $class . '::MESSAGE_HANDLER' };
1441             $h->( $info );
1442             }
1443             ## Or maybe then into a private log file?
1444             ## This way, even if the log method is superseeded, we can keep using ours without interfering with the other one
1445             elsif( $self->message_log( $mesg, "\n" ) )
1446 0         0 {
1447             return( 1 );
1448             }
1449             ## Otherwise just on the stderr
1450             else
1451 0         0 {
1452 0         0 my $err = IO::File->new;
1453 0 0       0 $err->fdopen( fileno( STDERR ), 'w' );
1454 0         0 $err->binmode( ":utf8" ) unless( $opts->{no_encoding} );
1455 0         0 $err->autoflush( 1 );
1456             $err->print( $mesg, "\n" );
1457             }
1458 0         0 }
1459             return( 1 );
1460             }
1461              
1462             sub message_check
1463 0     0 1 0 {
1464 0   0     0 my $self = shift( @_ );
1465 0         0 my $class = ref( $self ) || $self;
1466             my $this = $self->_obj2h;
1467 0 0       0 ## printf( STDERR "Our class is $class and DEBUG_TARGET contains: '%s' and debug value is %s\n", join( ', ', @${ "${class}::DEBUG_TARGET" } ), $hash->{ 'debug' } );
1468             if( @_ )
1469 0 0       0 {
1470             if( $_[0] !~ /^\d/ )
1471             {
1472 0 0 0     0 ## The last parameter is an options parameter which has the level property set
    0 0        
1473             if( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) )
1474             {
1475             ## Then let's use this
1476             }
1477             elsif( $this->{ '_message_default_level' } =~ /^\d+$/ &&
1478             $this->{ '_message_default_level' } > 0 )
1479 0         0 {
1480             unshift( @_, $this->{ '_message_default_level' } );
1481             }
1482             else
1483 0         0 {
1484             unshift( @_, 1 );
1485             }
1486             }
1487             ## If the first argument looks line a number, and there is more than 1 argument
1488             ## and it is greater than 1, and greater than our current debug level
1489 0 0 0     0 ## well, we do not output anything then...
      0        
1490             if( ( $_[ 0 ] =~ /^\d+$/ || ( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) ) ) &&
1491             @_ > 1 )
1492 0         0 {
1493 0 0 0     0 my $message_level;
    0          
1494             if( $_[ 0 ] =~ /^\d+$/ )
1495 0         0 {
1496             $message_level = shift( @_ );
1497             }
1498             elsif( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) )
1499 0         0 {
1500             $message_level = $_[-1]->{level};
1501 0         0 }
1502 0 0       0 my $target_re = '';
  0         0  
1503             if( ref( ${ "${class}::DEBUG_TARGET" } ) eq 'ARRAY' )
1504 0 0       0 {
  0         0  
  0         0  
1505             $target_re = scalar( @${ "${class}::DEBUG_TARGET" } ) ? join( '|', @${ "${class}::DEBUG_TARGET" } ) : '';
1506 0 0 0     0 }
      0        
      0        
      0        
      0        
      0        
      0        
1507             if( $this->{debug} >= $message_level ||
1508 0         0 $this->{verbose} >= $message_level ||
1509             ${ $class . '::DEBUG' } >= $message_level ||
1510             $this->{debug_level} >= $message_level ||
1511 0         0 $this->{debug} >= 100 ||
1512             ( length( $target_re ) && $class =~ /^$target_re$/ && ${ $class . '::GLOBAL_DEBUG' } >= $message_level ) )
1513             {
1514 0         0 ## print( STDERR ref( $self ) . "::message_check(): debug is '$hash->{debug}', verbose '$hash->{verbose}', DEBUG '", ${ $class . '::DEBUG' }, "', debug_level = $hash->{debug_level}\n" );
1515             return( [ @_ ] );
1516             }
1517             else
1518 0         0 {
1519             return( 0 );
1520             }
1521             }
1522 0         0 }
1523             return( 0 );
1524             }
1525              
1526             *message_color = \&message_colour;
1527              
1528             sub message_colour
1529 0     0 1 0 {
1530 0   0     0 my $self = shift( @_ );
1531 0         0 my $class = ref( $self ) || $self;
1532 0 0 0     0 my $this = $self->_obj2h;
  0   0     0  
1533             if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
1534 0 0       0 {
1535 0         0 my $level = ( $_[0] =~ /^\d+$/ ? shift( @_ ) : undef() );
1536 0 0 0     0 my $opts = {};
      0        
      0        
1537             if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' && ( CORE::exists( $_[-1]->{level} ) || CORE::exists( $_[-1]->{type} ) || CORE::exists( $_[-1]->{message} ) ) )
1538 0         0 {
1539             $opts = pop( @_ );
1540 0         0 }
1541 0 0 0     0 my $ref = [@_];
1542 0         0 $level = $opts->{level} if( !defined( $level ) && CORE::exists( $opts->{level} ) );
1543 0 0       0 my $txt;
1544             if( $opts->{message} )
1545 0 0       0 {
1546             if( ref( $opts->{message} ) eq 'ARRAY' )
1547 0 0 0     0 {
  0         0  
1548             $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @{$opts->{message}} ) );
1549             }
1550             else
1551 0         0 {
1552             $txt = $opts->{message};
1553             }
1554             }
1555             else
1556 0 0 0     0 {
1557             $txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) );
1558 0         0 }
1559 0         0 $txt = $self->colour_parse( $txt );
1560 0 0       0 $opts->{message} = $txt;
1561 0   0     0 $opts->{level} = $level if( defined( $level ) );
1562             return( $self->message( ( $level || 0 ), $opts ) );
1563 0         0 }
1564             return( 1 );
1565             }
1566              
1567             sub message_frame
1568 0     0 0 0 {
1569 0         0 my $self = shift( @_ );
1570 0 0       0 my $this = $self->_obj2h;
1571 0         0 $this->{_message_frame } = {} if( !exists( $this->{_message_frame} ) );
1572 0 0       0 my $mf = $this->{_message_frame};
1573             if( @_ )
1574 0         0 {
1575 0 0       0 my $args = {};
    0          
    0          
1576             if( ref( $_[0] ) eq 'HASH' )
1577 0         0 {
1578 0         0 $args = shift( @_ );
1579 0         0 my @k = keys( %$args );
1580             @$mf{ @k } = @$args{ @k };
1581             }
1582             elsif( !( @_ % 2 ) )
1583 0         0 {
1584 0         0 $args = { @_ };
1585 0         0 my @k = keys( %$args );
1586             @$mf{ @k } = @$args{ @k };
1587             }
1588             elsif( scalar( @_ ) == 1 )
1589 0         0 {
1590 0 0       0 my $sub = shift( @_ );
1591 0         0 $sub = substr( $sub, rindex( $sub, '::' ) + 2 ) if( index( $sub, '::' ) != -1 );
1592             return( $mf->{ $sub } );
1593             }
1594             else
1595 0         0 {
1596             return( $self->error( "I was expecting a key => value pair such as routine => stack frame (integer)" ) );
1597             }
1598 0         0 }
1599             return( $mf );
1600             }
1601              
1602             sub message_log
1603 0     0 1 0 {
1604 0         0 my $self = shift( @_ );
1605             my $io = $self->message_log_io;
1606 0 0       0 #print( STDERR "Module::Generic::log: \$io now is '$io'\n" );
1607             return( undef() ) if( !$io );
1608 0 0 0     0 #print( STDERR "Module::Generic::log: \$io is not an open handle\n" ) if( !openhandle( $io ) && $io );
1609             return( undef() ) if( !Scalar::Util::openhandle( $io ) && $io );
1610             ## 2019-06-14: I decided to remove this test, because if a log is provided it should print to it
1611             ## 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
1612             ## if it were printed directly on the console
1613 0   0     0 # my $rc = CORE::print( $io @_ ) || return( $self->error( "Unable to print to log file: $!" ) );
1614             my $rc = $io->print( scalar( localtime( time() ) ), " [$$]: ", @_ ) || return( $self->error( "Unable to print to log file: $!" ) );
1615 0         0 ## print( STDERR "Module::Generic::log (", ref( $self ), "): successfully printed to debug log file. \$rc is $rc, \$io is '$io' and message is: ", join( '', @_ ), "\n" );
1616             return( $rc );
1617             }
1618              
1619             sub message_log_io
1620             {
1621 0     0 1 0 #return( shift->_set_get( 'log_io', @_ ) );
1622 0         0 my $self = shift( @_ );
1623 0         0 my $class = ref( $self );
1624 0 0 0     0 my $this = $self->_obj2h;
    0 0        
1625             if( @_ )
1626 0         0 {
1627 0         0 my $io = shift( @_ );
1628             $self->_set_get( 'log_io', $io );
1629 0         0 }
1630             elsif( ${ "${class}::LOG_DEBUG" } &&
1631 0         0 !$self->_set_get( 'log_io' ) &&
1632             ${ "${class}::DEB_LOG" } )
1633 0         0 {
  0         0  
1634 0 0       0 our $DEB_LOG = ${ "${class}::DEB_LOG" };
1635             unless( $DEBUG_LOG_IO )
1636 0   0     0 {
1637 0         0 $DEBUG_LOG_IO = IO::File->new( ">>$DEB_LOG" ) || die( "Unable to open debug log file $DEB_LOG in append mode: $!\n" );
1638 0         0 $DEBUG_LOG_IO->binmode( ':utf8' );
1639             $DEBUG_LOG_IO->autoflush( 1 );
1640 0         0 }
1641             $self->_set_get( 'log_io', $DEBUG_LOG_IO );
1642 0         0 }
1643             return( $self->_set_get( 'log_io' ) );
1644             }
1645              
1646             sub message_switch
1647 298     298 1 572 {
1648 298   33     951 my $self = shift( @_ );
1649 298         778 my $pkg = ref( $self ) || $self;
1650 298 50       783 my $this = $self->_obj2h;
1651             if( @_ )
1652 298         774 {
1653 298 100 33     2129 my $flag = shift( @_ );
    50          
1654             if( $flag )
1655 1 50       3 {
  1         8  
1656             if( defined( &{ "$pkg\::message_off" } ) )
1657             {
1658 1         3 ## Restore previous backup
  1         8  
  1         3  
1659             *{ "${pkg}::message" } = \&{ "${pkg}::message_off" };
1660             }
1661             else
1662 0         0 {
  0         0  
  0         0  
1663             *{ "${pkg}::message" } = \&{ "Module::Generic::message" };
1664             }
1665             }
1666             ## We switch it down if nobody is going to use it
1667             elsif( !$flag && !$this->{verbose} && !$this->{debug} )
1668 297 100       477 {
  24         156  
  24         166  
  297         1518  
1669 297     170   1267 *{ "${pkg}::message_off" } = \&{ "${pkg}::message" } unless( defined( &{ "${pkg}::message_off" } ) );
  297         3022  
  170         274  
1670             *{ "${pkg}::message" } = sub { 1 };
1671             }
1672 298         712 }
1673             return( 1 );
1674             }
1675              
1676             sub messagef
1677 0     0 1 0 {
1678             my $self = shift( @_ );
1679 0   0     0 ## print( STDERR "got here: ", ref( $self ), "::messagef\n" );
1680 0         0 my $class = ref( $self ) || $self;
1681 0 0 0     0 my $this = $self->_obj2h;
  0   0     0  
1682             if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
1683 0 0       0 {
1684 0         0 my $level = ( $_[0] =~ /^\d+$/ ? shift( @_ ) : undef() );
1685 0 0 0     0 my $opts = {};
      0        
      0        
1686             if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' && ( CORE::exists( $_[-1]->{level} ) || CORE::exists( $_[-1]->{type} ) || CORE::exists( $_[-1]->{message} ) || CORE::exists( $_[-1]->{colour} ) ) )
1687 0         0 {
1688             $opts = pop( @_ );
1689 0 0 0     0 }
1690 0         0 $level = $opts->{level} if( !defined( $level ) && CORE::exists( $opts->{level} ) );
1691 0 0       0 my( $ref, $fmt );
1692             if( $opts->{message} )
1693 0 0       0 {
1694             if( ref( $opts->{message} ) eq 'ARRAY' )
1695 0         0 {
1696 0         0 $ref = $opts->{message};
1697             $fmt = shift( @$ref );
1698             }
1699             else
1700 0         0 {
1701 0         0 $fmt = $opts->{message};
1702             $ref = \@_;
1703             }
1704             }
1705             else
1706 0         0 {
1707 0         0 $ref = \@_;
1708             $fmt = shift( @$ref );
1709 0 0 0     0 }
1710             my $txt = sprintf( $fmt, map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) );
1711 0 0       0 ## $self->message( 3, "Option colour set? '$opts->{colour}'. Text is: '$txt'" );
1712             $txt = $self->colour_parse( $txt ) if( $opts->{colour} );
1713 0         0 ## print( STDERR ref( $self ), "::messagef \$txt is '$txt'\n" );
1714 0 0       0 $opts->{message} = $txt;
1715             $opts->{level} = $level if( defined( $level ) );
1716 0   0     0 # return( $self->message( defined( $level ) ? ( $level, $txt ) : $txt ) );
1717             return( $self->message( ( $level || 0 ), $opts ) );
1718 0         0 }
1719             return( 1 );
1720             }
1721              
1722             sub messagef_colour
1723 0     0 1 0 {
1724 0         0 my $self = shift( @_ );
1725 0 0 0     0 my $this = $self->_obj2h;
  0   0     0  
1726             if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } )
1727 0         0 {
1728 0         0 my @args = @_;
1729 0 0 0     0 my $opts = {};
      0        
      0        
1730             if( scalar( @args ) > 1 && ref( $args[-1] ) eq 'HASH' && ( CORE::exists( $args[-1]->{level} ) || CORE::exists( $args[-1]->{type} ) || CORE::exists( $args[-1]->{message} ) ) )
1731 0         0 {
1732             $opts = pop( @args );
1733 0         0 }
1734 0         0 $opts->{colour} = 1;
1735             CORE::push( @args, $opts );
1736 0         0 ## $self->message( 0, "Sending arguments: ", sub{ $self->dumper( \@args ) } );
1737             return( $this->messagef( @args ) );
1738 0         0 }
1739             return( 1 );
1740             }
1741              
1742             sub new_array
1743 0     0 1 0 {
1744 0         0 my $self = shift( @_ );
1745             return( Module::Generic::Array->new( @_ ) );
1746             }
1747              
1748             sub new_hash
1749 0     0 1 0 {
1750 0         0 my $self = shift( @_ );
1751             return( Module::Generic::Hash->new( @_ ) );
1752             }
1753              
1754             sub new_number
1755 0     0 1 0 {
1756 0         0 my $self = shift( @_ );
1757             return( Module::Generic::Number->new( @_ ) );
1758             }
1759              
1760             sub new_scalar
1761 0     0 1 0 {
1762 0         0 my $self = shift( @_ );
1763             return( Module::Generic::Scalar->new( @_ ) );
1764             }
1765 0     0 1 0  
  0         0  
1766             sub noexec { $_[0]->{_msg_no_exec_sub} = 1; return( $_[0] ); }
1767              
1768             ## Purpose is to get an error object thrown from another package, and make it ours and pass it along
1769             sub pass_error
1770 0     0 1 0 {
1771 0         0 my $self = shift( @_ );
1772 0         0 my $this = $self->_obj2h;
1773 0 0 0     0 my $err = shift( @_ );
1774 0         0 return if( !ref( $err ) || !Scalar::Util::blessed( $err ) );
  0         0  
1775 0 0       0 $this->{error} = ${ $class . '::ERROR' } = $err;
1776             if( want( 'OBJECT' ) )
1777 0         0 {
1778 0         0 my $null = Module::Generic::Null->new( $err, { debug => $this->{debug}, has_error => 1 });
1779             rreturn( $null );
1780 0         0 }
1781             return;
1782             }
1783 0     0 1 0  
1784             sub quiet { return( shift->_set_get( 'quiet', @_ ) ); }
1785              
1786             sub save
1787 0     0 1 0 {
1788 0         0 my $self = shift( @_ );
1789 0         0 my $this = $self->_obj2h;
1790 0 0       0 my $opts = {};
1791 0         0 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
1792 0 0       0 my( $file, $data );
1793             if( @_ == 2 )
1794 0         0 {
1795 0         0 $opts->{data} = shift( @_ );
1796             $opts->{file} = shift( @_ );
1797 0 0       0 }
1798 0   0     0 return( $self->error( "No file was provided to save data to." ) ) if( !$opts->{file} );
1799 0 0       0 my $fh = IO::File->new( ">$opts->{file}" ) || return( $self->error( "Unable to open file \"$opts->{file}\" in write mode: $!" ) );
1800 0         0 $fh->binmode( ':' . $opts->{encoding} ) if( $opts->{encoding} );
1801 0 0       0 $fh->autoflush( 1 );
  0 0       0  
1802             if( !defined( $fh->print( ref( $opts->{data} ) eq 'SCALAR' ? ${$opts->{data}} : $opts->{data} ) ) )
1803 0         0 {
1804             return( $self->error( "Unable to write data to file \"$opts->{file}\": $!" ) )
1805 0         0 }
1806 0         0 $fh->close;
1807 0         0 my $bytes = -s( $opts->{file} );
1808             return( $bytes );
1809             }
1810              
1811             sub set
1812 0     0 1 0 {
1813 0         0 my $self = shift( @_ );
1814 0 0       0 my %arg = ();
1815             if( @_ )
1816 0         0 {
1817 0         0 %arg = ( @_ );
1818 0 0       0 my $this = $self->_obj2h;
1819 0         0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
1820 0         0 my @keys = keys( %arg );
1821             @$data{ @keys } = @arg{ @keys };
1822 0         0 }
1823             return( scalar( keys( %arg ) ) );
1824             }
1825              
1826             sub subclasses
1827 0     0 1 0 {
1828 0         0 my $self = shift( @_ );
1829 0 0       0 my $that = '';
1830 0   0     0 $that = @_ ? shift( @_ ) : $self;
1831 0         0 my $base = ref( $that ) || $that;
1832 0         0 $base =~ s,::,/,g;
1833             $base .= '.pm';
1834 0         0
1835             require IO::Dir;
1836 0         0 ## remove '.pm'
1837             my $dir = substr( $INC{ $base }, 0, ( length( $INC{ $base } ) ) - 3 );
1838 0         0
1839 0         0 my @packages = ();
1840 0 0       0 my $io = IO::Dir->open( $dir );
1841             if( defined( $io ) )
1842 0 0       0 {
  0         0  
  0         0  
1843 0 0       0 @packages = map{ substr( $_, 0, length( $_ ) - 3 ) } grep{ substr( $_, -3 ) eq '.pm' && -f( "$dir/$_" ) } $io->read();
1844             $io->close ||
1845             warn( "Unable to close directory \"$dir\": $!\n" );
1846             }
1847             else
1848 0         0 {
1849             warn( "Unable to open directory \"$dir\": $!\n" );
1850 0 0       0 }
1851             return( wantarray() ? @packages : \@packages );
1852             }
1853 0     0 1 0  
  0         0  
1854             sub true { ${"Module::Generic::Boolean::true"} }
1855 0     0 1 0  
  0         0  
1856             sub false { ${"Module::Generic::Boolean::false"} }
1857              
1858             sub verbose
1859 0     0 1 0 {
1860 0         0 my $self = shift( @_ );
1861 0 0       0 my $this = $self->_obj2h;
1862             if( @_ )
1863 0         0 {
1864 0         0 my $flag = shift( @_ );
1865 0 0       0 $this->{verbose} = $flag;
1866             $self->message_switch( $flag ) if( $OPTIMIZE_MESG_SUB );
1867 0         0 }
1868             return( $this->{verbose} );
1869             }
1870              
1871             sub will
1872 0 0 0 0 1 0 {
1873 0         0 ( @_ >= 2 && @_ <= 3 ) || die( 'Usage: $obj->can( "method" ) or Module::Generic::will( $obj, "method" )' );
1874             my( $obj, $meth, $level );
1875 0 0 0     0 ## $obj->will( $other_obj, 'method' );
1876             if( @_ == 3 && ref( $_[ 1 ] ) )
1877 0         0 {
1878 0         0 $obj = $_[ 1 ];
1879             $meth = $_[ 2 ];
1880             }
1881             else
1882 0         0 {
1883             ( $obj, $meth, $level ) = @_;
1884 0 0 0     0 }
1885             return( undef() ) if( !ref( $obj ) && index( $obj, '::' ) == -1 );
1886 0         0 ## Give a chance to UNIVERSAL::can
1887 0 0 0     0 my $ref = undef;
1888             if( Scalar::Util::blessed( $obj ) && ( $ref = $obj->can( $meth ) ) )
1889 0         0 {
1890             return( $ref );
1891 0   0     0 }
1892 0         0 my $class = ref( $obj ) || $obj;
1893 0 0       0 my $origi = $class;
1894             if( index( $meth, '::' ) != -1 )
1895 0         0 {
1896 0         0 $origi = substr( $meth, 0, rindex( $meth, '::' ) );
1897             $meth = substr( $meth, rindex( $meth, '::' ) + 2 );
1898 0 0       0 }
  0         0  
  0         0  
1899             $ref = \&{ "$class\::$meth" } if( defined( &{ "$class\::$meth" } ) );
1900             ## print( $err "\t" x $level, "UNIVERSAL::can ", defined( $ref ) ? "succeeded" : "failed", " in finding the method \"$meth\" in object/class $obj.\n" );
1901 0 0       0 ## print( $err "\t" x $level, defined( $ref ) ? "succeeded" : "failed", " in finding the method \"$meth\" in object/class $obj.\n" );
1902             return( $ref ) if( defined( $ref ) );
1903 0   0     0 ## We do not go further down the rabbit hole if level is greater or equal to 10
1904 0 0       0 $level ||= 0;
1905 0         0 return( undef() ) if( $level >= 10 );
1906             $level++;
1907             ## Let's see what Alice has got for us... :-)
1908             ## We look in the @ISA to see if the method exists in the package from which we
1909 0 0       0 ## possibly inherited
  0         0  
1910             if( @{ "$class\::ISA" } )
1911             {
1912 0         0 ## print( STDERR "\t" x $level, "Checking ", scalar( @{ "$class\::ISA" } ), " entries in \"\@${class}\:\:ISA\".\n" );
  0         0  
1913             foreach my $pack ( @{ "$class\::ISA" } )
1914             {
1915 0         0 ## print( STDERR "\t" x $level, "Looking up method \"$meth\" in inherited package \"$pack\".\n" );
1916 0 0       0 my $ref = &will( $pack, "$origi\::$meth", $level );
1917             return( $ref ) if( defined( $ref ) );
1918             }
1919             }
1920             ## Then, maybe there is an AUTOLOAD to trap undefined routine?
1921             ## But, we do not want any loop, do we?
1922             ## Since will() is called from Module::Generic::AUTOLOAD to check if EXTRA_AUTOLOAD exists
1923 0 0 0     0 ## we are not going to call Module::Generic::AUTOLOAD for EXTRA_AUTOLOAD...
  0   0     0  
1924             if( $class ne 'Module::Generic' && $meth ne 'EXTRA_AUTOLOAD' && defined( &{ "$class\::AUTOLOAD" } ) )
1925             {
1926             ## print( STDERR "\t" x ( $level - 1 ), "Found an AUTOLOAD in class \"$class\". Ok.\n" );
1927             my $sub = sub
1928 0     0   0 {
1929 0         0 $class::AUTOLOAD = "$origi\::$meth";
  0         0  
1930 0         0 &{ "$class::AUTOLOAD" }( @_ );
1931 0         0 };
1932             return( $sub );
1933 0         0 }
1934             return( undef() );
1935             }
1936              
1937             ## Initially those data were stored after the __END__, but it seems some module is interfering with <DATA>
1938             ## and so those data could not be loaded reliably
1939             ## This is called once by colour_to_rgb to generate the hash reference COLOUR_NAME_TO_RGB
1940             sub __colour_data
1941 1     1   3 {
1942             my $colour_data = <<EOT;
1943             {'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']}
1944             EOT
1945             }
1946              
1947             sub __instantiate_object
1948 0     0   0 {
1949 0         0 my $self = shift( @_ );
1950 0         0 my $field = shift( @_ );
1951 0         0 my $class = shift( @_ );
1952 0         0 my $this = $self->_obj2h;
1953 0         0 my $o;
1954 0     0   0 try
1955             {
1956             ## https://stackoverflow.com/questions/32608504/how-to-check-if-perl-module-is-available#comment53081298_32608860
1957 0         0 ## require $class unless( defined( *{"${class}::"} ) );
  0         0  
1958 0 0       0 my $rc = eval{ Class::Load::load_class( $class ); };
1959             return( $self->error( "Unable to load class $class: $@" ) ) if( $@ );
1960 0 0 0     0 # $self->message( 3, "Called with args: ", sub{ $self->dumper( \@_ ) } );
1961 0 0       0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
1962 0 0       0 $o = @_ ? $class->new( @_ ) : $class->new;
1963 0 0       0 $o->debug( $this->{debug} ) if( $o->can( 'debug' ) );
1964             return( $self->pass_error( "Unable to instantiate an object of class $class: ", $class->error ) ) if( !defined( $o ) );
1965 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         0  
  0         0  
1966 0     0   0 catch( $e )
1967 0         0 {
1968 0 0 0     0 return( $self->error({ code => 500, message => $e }) );
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
1969 0         0 }
1970             return( $o );
1971             }
1972              
1973             ## Call to the actual method doing the work
1974             ## The reason for doing so is because _instantiate_object() may be inherited, but
1975             ## _set_get_class or _set_get_hash_as_object created dynamic class which requires to call _instantiate_object
1976 0     0   0 ## If _instantiate_object is inherited, it will yield unpredictable results
1977             sub _instantiate_object { return( shift->__instantiate_object( @_ ) ); }
1978              
1979             sub _is_a
1980 0     0   0 {
1981 0         0 my $self = shift( @_ );
1982 0         0 my $obj = shift( @_ );
1983 7     7   64 my $pkg = shift( @_ );
  7         16  
  7         29967  
1984 0 0 0     0 no overloading;
1985 0 0       0 return if( !$obj || !$pkg );
1986 0         0 return if( !$self->_is_object( $obj ) );
1987             return( $obj->isa( $pkg ) );
1988             }
1989 0     0   0  
  0         0  
1990             sub _is_class_loaded { shift( @_ ); return( Class::Load::is_class_loaded( @_ ) ); }
1991              
1992             ## UNIVERSAL::isa works for both array or array as objects
1993 0     0   0 ## sub _is_array { return( UNIVERSAL::isa( $_[1], 'ARRAY' ) ); }
1994             sub _is_array { return( Scalar::Util::reftype( $_[1] ) eq 'ARRAY' ); }
1995              
1996 12     12   54 ## sub _is_hash { return( UNIVERSAL::isa( $_[1], 'HASH' ) ); }
1997             sub _is_hash { return( Scalar::Util::reftype( $_[1] ) eq 'HASH' ); }
1998 125509     125509   492388  
1999             sub _is_object { return( Scalar::Util::blessed( $_[1] ) ); }
2000 0     0   0  
2001             sub _is_scalar{ return( Scalar::Util::reftype( $_[1] ) eq 'SCALAR' ); }
2002              
2003             sub _load_class
2004 0     0   0 {
2005 0   0     0 my $self = shift( @_ );
2006 0         0 my $class = shift( @_ ) || return( $self->error( "No package name was provided to load." ) );
2007 0     0   0 try
2008 0         0 {
2009             return( Class::Load::load_class( "$class" ) );
2010 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         0  
  0         0  
2011 0     0   0 catch( $e )
2012 0         0 {
2013 0 0 0     0 return( $self->error( $e ) );
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
2014             }
2015             }
2016              
2017             sub _obj2h
2018 66960     66960   89422 {
2019             my $self = shift( @_ );
2020 66960 50       157600 ## print( STDERR "_obj2h(): Getting a hash refernece out of the object '$self'\n" );
    0          
    0          
2021             if( Scalar::Util::reftype( $self ) eq 'HASH' )
2022 66960         106213 {
2023             return( $self );
2024             }
2025             elsif( Scalar::Util::reftype( $self ) eq 'GLOB' )
2026             {
2027 0         0 ## print( STDERR "Returning a reference to an hash for glob $self\n" );
  0         0  
2028             return( \%{*$self} );
2029             }
2030             ## The method that called message was itself called using the package name like My::Package->some_method
2031             ## 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
2032             elsif( !ref( $self ) )
2033 0         0 {
2034             my $class = $self;
2035             my $hash =
2036 0         0 {
2037 0         0 'debug' => ${ "${class}\::DEBUG" },
2038 0         0 'verbose' => ${ "${class}\::VERBOSE" },
  0         0  
2039             'error' => ${ "${class}\::ERROR" },
2040             };
2041             ## XXX
2042 0         0 ## print( STDERR "Called with '$self' with debug value '$hash->{debug}' and verbose '$hash->{verbose}'\n" );
2043             return( bless( $hash => $class ) );
2044             }
2045             ## Because object may be accessed as My::Package->method or My::Package::method
2046             ## there is not always an object available, so we need to fake it to avoid error
2047             ## This is primarly itended for generic methods error(), errstr() to work under any conditions.
2048             else
2049 0         0 {
2050             return( {} );
2051             }
2052             }
2053              
2054             sub _parse_timestamp
2055 0     0   0 {
2056 0         0 my $self = shift( @_ );
2057             my $str = shift( @_ );
2058 0 0       0 ## No value was actually provided
2059 0         0 return( undef() ) if( !length( $str ) );
2060 0         0 my $this = $self->_obj2h;
2061 0         0 my $tz = DateTime::TimeZone->new( name => 'local' );
2062             my $error = 0;
2063             my $opt =
2064             {
2065             pattern => '%Y-%m-%d %T',
2066             locale => 'en_GB',
2067 0     0   0 time_zone => $tz->name,
2068 0         0 on_error => sub{ $error++ },
2069             };
2070             # $self->message( 3, "Checking timestamp string '$str' for appropriate pattern" );
2071             ## 2019-06-19 23:23:57.000000000+0900
2072             ## From PostgreSQL: 2019-06-20 11:02:36.306917+09
2073 0 0       0 ## ISO 8601: 2019-06-20T11:08:27
    0          
    0          
2074             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})?/ )
2075 0         0 {
2076 0 0       0 my( $date, $time, $zone ) = ( "$1-$2-$3", $4, $5 );
2077             if( !length( $zone ) )
2078 0         0 {
2079 0         0 my $dt = DateTime->now( time_zone => $tz );
2080             my $offset = $dt->offset;
2081 0         0 ## e.g. 9 or possibly 9.5
2082             my $offset_hour = ( $offset / 3600 );
2083 0         0 ## e.g. 9.5 => 0.5 * 60 = 30
2084 0         0 my $offset_min = ( $offset_hour - CORE::int( $offset_hour ) ) * 60;
2085             $zone = sprintf( '%+03d%02d', $offset_hour, $offset_min );
2086             }
2087 0         0 # $self->message( 3, "\tMatched pattern #1 with date '$date', time '$time' and time zone '$zone'." );
2088 0 0       0 $date =~ tr/\//-/;
2089 0         0 $zone .= '00' if( length( $zone ) == 3 );
2090 0         0 $str = "$date $time$zone";
2091 0         0 $self->message( 3, "\tChanging string to '$str'" );
2092             $opt->{pattern} = '%Y-%m-%d %T%z';
2093             }
2094             ## From SQLite: 2019-06-20 02:03:14
2095             ## From MySQL: 2019-06-20 11:04:01
2096             elsif( $str =~ /(\d{4})[-|\/](\d{1,2})[-|\/](\d{1,2})(?:[[:blank:]]+|T)(\d{1,2}:\d{1,2}:\d{1,2})/ )
2097 0         0 {
2098             my( $date, $time ) = ( "$1-$2-$3", $4 );
2099 0         0 # $self->message( 3, "\tMatched pattern #2 with date '$date', time '$time' and without time zone." );
2100 0         0 my $dt = DateTime->now( time_zone => $tz );
2101             my $offset = $dt->offset;
2102 0         0 ## e.g. 9 or possibly 9.5
2103             my $offset_hour = ( $offset / 3600 );
2104 0         0 ## e.g. 9.5 => 0.5 * 60 = 30
2105 0         0 my $offset_min = ( $offset_hour - CORE::int( $offset_hour ) ) * 60;
2106 0         0 my $offset_str = sprintf( '%+03d%02d', $offset_hour, $offset_min );
2107 0         0 $date =~ tr/\//-/;
2108 0         0 $str = "$date $time$offset_str";
2109 0         0 $self->message( 3, "\tAdding time zone '", $tz->name, "' offset of $offset_str with result: '$str'." );
2110             $opt->{pattern} = '%Y-%m-%d %T%z';
2111             }
2112             elsif( $str =~ /^(\d{4})[-|\/](\d{1,2})[-|\/](\d{1,2})$/ )
2113 0         0 {
2114             $str = "$1-$2-$3";
2115 0         0 # $self->message( 3, "\tMatched pattern #3 with date '$date' only." );
2116             $opt->{pattern} = '%Y-%m-%d';
2117             }
2118             else
2119 0         0 {
2120             return( '' );
2121 0         0 }
2122 0         0 my $strp = DateTime::Format::Strptime->new( %$opt );
2123 0         0 my $dt = $strp->parse_datetime( $str );
2124             return( $dt );
2125             }
2126              
2127             sub _set_get
2128 4     4   7 {
2129 4         7 my $self = shift( @_ );
2130 4         9 my $field = shift( @_ );
2131 4 50       12 my $this = $self->_obj2h;
2132 4 50       10 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2133             if( @_ )
2134 4 50       10 {
2135 4         10 my $val = ( @_ == 1 ) ? shift( @_ ) : [ @_ ];
2136             $data->{ $field } = $val;
2137 4 50       10 }
2138             if( wantarray() )
2139 0 0       0 {
    0          
2140             if( ref( $data->{ $field } ) eq 'ARRAY' )
2141 0         0 {
  0         0  
2142             return( @{ $data->{ $field } } );
2143             }
2144             elsif( ref( $data->{ $field } ) eq 'HASH' )
2145 0         0 {
  0         0  
2146             return( %{ $data->{ $field } } );
2147             }
2148             else
2149 0         0 {
2150             return( ( $data->{ $field } ) );
2151             }
2152             }
2153             else
2154 4         10 {
2155             return( $data->{ $field } );
2156             }
2157             }
2158              
2159             sub _set_get_array
2160 0     0   0 {
2161 0         0 my $self = shift( @_ );
2162 0         0 my $field = shift( @_ );
2163 0 0       0 my $this = $self->_obj2h;
2164 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2165             if( @_ )
2166 0 0 0     0 {
2167 0         0 my $val = ( @_ == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? shift( @_ ) : [ @_ ];
2168             $data->{ $field } = $val;
2169 0         0 }
2170             return( $data->{ $field } );
2171             }
2172              
2173             sub _set_get_array_as_object
2174 20     20   51 {
2175 20         47 my $self = shift( @_ );
2176 20         51 my $field = shift( @_ );
2177 20 50       95 my $this = $self->_obj2h;
2178 20 50       65 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2179             if( @_ )
2180 0 0 0     0 {
2181 0         0 my $val = ( @_ == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? shift( @_ ) : [ @_ ];
2182             my $o = $data->{ $field };
2183 0 0       0 ## Some existing data, like maybe default value
2184             if( $o )
2185 0 0       0 {
2186             if( !$self->_is_object( $o ) )
2187 0         0 {
2188 0         0 my $tmp = $o;
2189             $o = Module::Generic::Array->new( $tmp );
2190 0         0 }
2191             $o->set( $val );
2192             }
2193             else
2194 0         0 {
2195 0         0 $o = Module::Generic::Array->new( $val );
2196             $data->{ $field } = $o;
2197             }
2198 20 50 33     116 }
2199             if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) )
2200 0         0 {
2201 0         0 my $o = Module::Generic::Array->new( $data->{ $field } );
2202             $data->{ $field } = $o;
2203 20         91 }
2204             return( $data->{ $field } );
2205             }
2206              
2207             sub _set_get_boolean
2208 472     472   802 {
2209 472         756 my $self = shift( @_ );
2210 472         1052 my $field = shift( @_ );
2211 472 50       1580 my $this = $self->_obj2h;
2212 472 50       1136 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2213             if( @_ )
2214 472         773 {
2215             my $val = shift( @_ );
2216 472 50 0     3266 # $self->message( 3, "Value provided for field '$field' is '$val' of reference (", ref( $val ), ")." );
    50 33        
    50 33        
2217             if( Scalar::Util::blessed( $val ) &&
2218             ( $val->isa( 'JSON::PP::Boolean' ) || $val->isa( 'Module::Generic::Boolean' ) ) )
2219 0         0 {
2220             $data->{ $field } = $val;
2221             }
2222             elsif( Scalar::Util::reftype( $val ) eq 'SCALAR' )
2223 0 0       0 {
2224             $data->{ $field } = $$val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2225             }
2226             elsif( lc( $val ) eq 'true' || lc( $val ) eq 'false' )
2227 0 0       0 {
2228             $data->{ $field } = lc( $val ) eq 'true' ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2229             }
2230             else
2231 472 100       2237 {
2232             $data->{ $field } = $val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2233             }
2234             # $self->message( 3, "Boolean field now has value $self->{$field} (", ref( $self->{ $field } ), ")." );
2235             }
2236             ## If there is a value set, like a default value and it is not an object or at least not one we recognise
2237 472 50 33     1596 ## We transform it into a Module::Generic::Boolean object
      33        
2238             if( CORE::length( $data->{ $field } ) &&
2239             (
2240             !Scalar::Util::blessed( $data->{ $field } ) ||
2241             (
2242             Scalar::Util::blessed( $data->{ $field } ) &&
2243             !$data->{ $field }->isa( 'Module::Generic::Boolean' ) &&
2244             !$data->{ $field }->isa( 'JSON::PP::Boolean' )
2245             )
2246             ) )
2247 0         0 {
2248 0 0       0 my $val = $data->{ $field };
2249             $data->{ $field } = $val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false;
2250 472         1312 }
2251             return( $data->{ $field } );
2252             }
2253              
2254             sub __create_class
2255 0     0   0 {
2256 0   0     0 my $self = shift( @_ );
2257 0         0 my $field = shift( @_ ) || return( $self->error( "No field was provided to create a dynamic class." ) );
2258 0         0 my $def = shift( @_ );
2259 0 0       0 my $class;
2260             if( $def->{_class} )
2261 0         0 {
2262             $class = $def->{_class};
2263             }
2264             else
2265 0         0 {
2266 0         0 my $new_class = $field;
2267 0         0 $new_class =~ tr/-/_/;
2268 0         0 $new_class =~ s/\_{2,}/_/g;
2269 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
2270             $class = ref( $self ) . "\::${new_class}";
2271 0 0       0 }
2272             unless( Class::Load::is_class_loaded( $class ) )
2273             {
2274 0         0 # $self->message( 3, "Class '$class' is not created yet, creating it." );
2275             my $type2func =
2276             {
2277             array => '_set_get_array',
2278             array_as_object => '_set_get_array_as_object',
2279             boolean => '_set_get_boolean',
2280             class => '_set_get_class',
2281             class_array => '_set_get_class_array',
2282             datetime => '_set_get_datetime',
2283             hash => '_set_get_hash',
2284             number => '_set_get_number',
2285             object => '_set_get_object',
2286             object_array => '_set_get_object_array',
2287             object_array_object => '_set_get_object_array_object',
2288             scalar => '_set_get_scalar',
2289             scalar_or_object => '_set_get_scalar_or_object',
2290             uri => '_set_get_uri',
2291             };
2292 0         0 ## Alias
2293             $type2func->{string} = $type2func->{scalar};
2294 0         0
2295             my $perl = <<EOT;
2296             package $class;
2297             BEGIN
2298             {
2299             use strict;
2300             use Module::Generic;
2301             use parent -norequire, qw( Module::Generic );
2302             };
2303              
2304 0         0 EOT
2305 0 0       0 my $call_sub = ( split( /::/, ( caller(1) )[3] ) )[-1];
2306 0         0 my $call_frame = $call_sub eq '_set_get_class' ? 1 : 0;
2307 0         0 my( $pack, $file, $line ) = caller( $call_frame );
2308 0         0 my $code_lines = [];
2309             foreach my $f ( sort( keys( %$def ) ) )
2310             {
2311 0         0 # $self->message( 3, "Checking field '$f'." );
2312 0         0 my $info = $def->{ $f };
2313 0 0       0 my $type = lc( $info->{type} );
2314             if( !CORE::exists( $type2func->{ $type } ) )
2315 0         0 {
2316 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" );
2317             next;
2318 0         0 }
2319 0 0 0     0 my $func = $type2func->{ $type };
    0 0        
      0        
2320             if( $type eq 'object' ||
2321             $type eq 'scalar_or_object' ||
2322             $type eq 'object_array' )
2323 0 0       0 {
2324             if( !$info->{class} )
2325 0         0 {
2326 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" );
2327             next;
2328 0         0 }
2329 0         0 my $this_class = $info->{class};
2330             CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', '$this_class', \@_ ) ); }" );
2331             }
2332             elsif( $type eq 'class' || $type eq 'class_array' )
2333 0         0 {
2334 0 0       0 my $this_def = $info->{definition};
    0          
2335             if( !CORE::exists( $info->{definition} ) )
2336 0         0 {
2337 0         0 warn( "Warning only: No dynamic class fields definition was provided for this field \"$f\". Skipping this field.\n" );
2338             next;
2339             }
2340             elsif( ref( $this_def ) ne 'HASH' )
2341 0         0 {
2342 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" );
2343             next;
2344 0         0 }
2345 0         0 my $d = Data::Dumper->new( [ $this_def ] );
2346 0         0 $d->Indent( 0 );
2347 0         0 $d->Purity( 1 );
2348 0         0 $d->Pad( '' );
2349 0         0 $d->Terse( 1 );
2350 0         0 $d->Sortkeys( 1 );
2351 0         0 my $hash_str = $d->Dump;
2352             CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', $hash_str, \@_ ) ); }" );
2353             }
2354             else
2355 0         0 {
2356             CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', \@_ ) ); }" );
2357             }
2358 0         0 }
2359             $perl .= join( "\n\n", @$code_lines );
2360 0         0  
2361             $perl .= <<EOT;
2362              
2363              
2364             1;
2365              
2366             EOT
2367             # $self->message( 3, "Evaluating code:\n$perl" );
2368 0         0 # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" );
2369             my $rc = eval( $perl );
2370 0 0       0 # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" );
2371             die( "Unable to dynamically create module $class: $@" ) if( $@ );
2372 0         0 }
2373             return( $class );
2374             }
2375              
2376             ## $self->_set_get_class( 'my_field', {
2377             ## _class => 'My::Class',
2378             ## field1 => { type => 'datetime' },
2379             ## field2 => { type => 'scalar' },
2380             ## field3 => { type => 'boolean' },
2381             ## field4 => { type => 'object', class => 'Some::Class' },
2382             ## }, @_ );
2383             sub _set_get_class
2384 0     0   0 {
2385             my $self = shift( @_ );
2386 0         0 # $self->message( 3, "Got here with arguments: '", join( "', '", @_ ), "'." );
2387 0         0 my $field = shift( @_ );
2388 0         0 my $def = shift( @_ );
2389 0 0       0 my $this = $self->_obj2h;
2390 0 0 0     0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2391 0 0       0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2392             if( ref( $def ) ne 'HASH' )
2393 0         0 {
2394 0         0 CORE::warn( "Warning only: dynamic class field definition hash ($def) for field \"$field\" is not a hash reference.\n" );
2395             return;
2396             }
2397 0   0     0
2398             my $class = $self->__create_class( $field, $def ) || die( "Failed to create the dynamic class for field \"$field\".\n" );
2399 0 0       0
2400             if( @_ )
2401 0         0 {
2402             my $hash = shift( @_ );
2403 0         0 # my $o = $class->new( $hash );
  0         0  
2404             $self->messagef( 3, "Instantiating object of class '$class' with hash '$hash' containing %d elements: '%s'", scalar( keys( %$hash ) ), join( "', '", map{ "$_ => $hash->{$_}" } sort( keys( %$hash ) ) ) );
2405 0         0 ## $self->messagef( 3, "Instantiating object of class '$class' with hash '$hash' containing %d elements: '%s'", scalar( keys( %$hash ) ), $self->dumper( $hash ) );
2406             my $o = $self->__instantiate_object( $field, $class, $hash );
2407 0         0 # $self->message( 3, "\tReturning object for field '$field' and class '$class': '$o'." );
2408             $data->{ $field } = $o;
2409             }
2410 0 0       0
2411             if( !$data->{ $field } )
2412 0         0 {
2413 0         0 my $o = $self->__instantiate_object( $field, $class );
2414             $data->{ $field } = $o;
2415 0         0 }
2416             return( $data->{ $field } );
2417             }
2418              
2419             sub _set_get_class_array
2420 0     0   0 {
2421 0         0 my $self = shift( @_ );
2422 0         0 my $field = shift( @_ );
2423 0         0 my $def = shift( @_ );
2424 0 0       0 my $this = $self->_obj2h;
2425 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2426             if( ref( $def ) ne 'HASH' )
2427 0         0 {
2428 0         0 CORE::warn( "Warning only: dynamic class field definition hash ($def) for field \"$field\" is not a hash reference.\n" );
2429             return;
2430 0 0 0     0 }
2431 0   0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2432             my $class = $self->__create_class( $field, $def ) || die( "Failed to create the dynamic class for field \"$field\".\n" );
2433 0 0       0 ## return( $self->_set_get_object_array( $field, $class, @_ ) );
2434             if( @_ )
2435 0         0 {
2436 0 0       0 my $ref = shift( @_ );
2437 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 ) );
2438 0         0 my $arr = [];
2439             for( my $i = 0; $i < scalar( @$ref ); $i++ )
2440 0 0       0 {
2441             if( ref( $ref->[$i] ) ne 'HASH' )
2442 0         0 {
2443             return( $self->error( "Array offset $i is not a hash reference. I was expecting a hash reference to instantiate an object of class $class." ) );
2444 0         0 }
2445 0         0 my $o = $self->__instantiate_object( $field, $class, $ref->[$i] );
2446             CORE::push( @$arr, $o );
2447 0         0 }
2448             $data->{ $field } = $arr;
2449 0         0 }
2450             return( $data->{ $field } );
2451             }
2452              
2453             sub _set_get_code
2454 1     1   3 {
2455 1         2 my $self = shift( @_ );
2456 1         3 my $field = shift( @_ );
2457 1 50       9 my $this = $self->_obj2h;
2458 1 50       5 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2459             if( @_ )
2460 0         0 {
2461 0 0       0 my $v = shift( @_ );
2462 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' );
2463             $data->{ $field } = $v;
2464 1         2 }
2465             return( $data->{ $field } );
2466             }
2467              
2468             sub _set_get_datetime
2469 0     0   0 {
2470 0         0 my $self = shift( @_ );
2471 0         0 my $field = shift( @_ );
2472 0 0       0 my $this = $self->_obj2h;
2473 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2474             if( @_ )
2475 0         0 {
2476             my $time = shift( @_ );
2477 0         0 # $self->message( 3, "Processing time stamp $time possibly of ref (", ref( $time ), ")." );
2478 0 0 0     0 my $now;
    0          
    0          
    0          
2479             if( !defined( $time ) )
2480 0         0 {
2481 0         0 $data->{ $field } = $time;
2482             return( $data->{ $field } );
2483             }
2484             elsif( Scalar::Util::blessed( $time ) )
2485 0 0       0 {
2486 0         0 return( $self->error( "Object provided as value for $field, but this is not a DateTime object" ) ) if( !$time->isa( 'DateTime' ) );
2487 0         0 $data->{ $field } = $time;
2488             return( $data->{ $field } );
2489             }
2490             elsif( $time =~ /^\d+$/ && $time !~ /^\d{10}$/ )
2491 0         0 {
2492             return( $self->error( "DateTime value ($time) provided for field $field does not look like a unix timestamp" ) );
2493             }
2494             elsif( $now = $self->_parse_timestamp( $time ) )
2495             {
2496 0         0 ## Found a parsed datetime value
2497 0         0 $data->{ $field } = $now;
2498             return( $now );
2499             }
2500            
2501             # $self->message( 3, "Creating a DateTime object out of $time\n" );
2502 0         0 eval
2503 0         0 {
2504 0         0 require DateTime;
2505 0         0 require DateTime::Format::Strptime;
2506             $now = DateTime->from_epoch(
2507             epoch => $time,
2508             time_zone => 'local',
2509 0         0 );
2510             my $strp = DateTime::Format::Strptime->new(
2511             pattern => '%s',
2512             locale => 'en_GB',
2513             time_zone => 'local',
2514 0         0 );
2515             $now->set_formatter( $strp );
2516 0 0       0 };
2517             if( $@ )
2518 0         0 {
2519             $self->message( "Error while trying to get the DateTime object for field $k with value $time" );
2520             }
2521             else
2522             {
2523 0         0 # $self->message( 3, "Returning the DateTime object '$now'" );
2524             $data->{ $field } = $now;
2525             }
2526             }
2527 0 0 0     0 ## So that a call to this field will not trigger an error: "Can't call method "xxx" on an undefined value"
2528             if( !$data->{ $field } && want( 'OBJECT' ) )
2529 0         0 {
2530 0         0 my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 });
2531             rreturn( $null );
2532 0         0 }
2533             return( $data->{ $field } );
2534             }
2535              
2536             sub _set_get_hash
2537 0     0   0 {
2538 0         0 my $self = shift( @_ );
2539 0         0 my $field = shift( @_ );
2540 0 0       0 my $this = $self->_obj2h;
2541             my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2542 0 0 0     0 # $self->message( 3, "Called for field '$field' with data '", join( "', '", @_ ), "'." );
2543 0 0       0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2544             if( @_ )
2545 0         0 {
2546 0 0       0 my $val;
    0          
2547             if( ref( $_[0] ) eq 'HASH' )
2548 0         0 {
2549             $val = shift( @_ );
2550             }
2551             elsif( ( @_ % 2 ) )
2552 0         0 {
2553             $val = { @_ };
2554             }
2555             else
2556 0         0 {
2557 0         0 my $val = shift( @_ );
2558             return( $self->error( "Method $field takes only a hash or reference to a hash, but value provided ($val) is not supported" ) );
2559             }
2560 0         0 # $self->message( 3, "Setting value $val for field $field" );
2561             $data->{ $field } = $val;
2562 0         0 }
2563             return( $data->{ $field } );
2564             }
2565              
2566             sub _set_get_hash_as_mix_object
2567 143     143   295 {
2568 143         343 my $self = shift( @_ );
2569 143         346 my $field = shift( @_ );
2570 143 50       8993 my $this = $self->_obj2h;
2571             my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2572 143 50 33     681 # $self->message( 3, "Called for field '$field' with data '", join( "', '", @_ ), "'." );
2573 143 50       451 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2574             if( @_ )
2575 0         0 {
2576 0 0       0 my $val;
    0          
2577             if( ref( $_[0] ) eq 'HASH' )
2578 0         0 {
2579             $val = shift( @_ );
2580             }
2581             elsif( ( @_ % 2 ) )
2582 0         0 {
2583             $val = { @_ };
2584             }
2585             else
2586 0         0 {
2587 0         0 my $val = shift( @_ );
2588             return( $self->error( "Method $field takes only a hash or reference to a hash, but value provided ($val) is not supported" ) );
2589             }
2590 0         0 # $self->message( 3, "Setting value $val for field $field" );
2591             $data->{ $field } = Module::Generic::Hash->new( $val );
2592 143 50 33     804 }
2593             if( $data->{ $field } && !$self->_is_object( $data->{ $field } ) )
2594 143         920 {
2595 143         439 my $o = Module::Generic::Hash->new( $data->{ $field } );
2596             $data->{ $field } = $o;
2597 143         448 }
2598             return( $data->{ $field } );
2599             }
2600              
2601             sub _set_get_hash_as_object
2602 0     0   0 {
2603 0         0 my $self = shift( @_ );
2604             my $this = $self->_obj2h;
2605 0   0     0 # $self->message( 3, "Called with args: ", $self->dumper( \@_ ) );
2606 0         0 my $field = shift( @_ ) || return( $self->error( "No field provided for _set_get_hash_as_object" ) );
2607 0 0 0     0 my $class;
2608 0 0       0 @_ = () if( @_ == 1 && !defined( $_[0] ) );
2609             if( @_ )
2610             {
2611             ## No class was provided
2612 0 0       0 # if( ref( $_[0] ) eq 'HASH' )
    0          
2613             if( Scalar::Util::reftype( $_[0] ) eq 'HASH' )
2614 0         0 {
2615 0         0 my $new_class = $field;
2616 0         0 $new_class =~ tr/-/_/;
2617 0         0 $new_class =~ s/\_{2,}/_/g;
2618 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
2619             $class = ref( $self ) . "\::${new_class}";
2620             }
2621             elsif( ref( $_[0] ) )
2622 0         0 {
2623             return( $self->error( "Class name in _set_get_hash_as_object helper method cannot be a reference. Received: \"", overload::StrVal( $_[0] ), "\"." ) );
2624             }
2625             else
2626 0         0 {
2627             $class = shift( @_ );
2628             }
2629             }
2630             else
2631 0         0 {
2632 0         0 my $new_class = $field;
2633 0         0 $new_class =~ tr/-/_/;
2634 0         0 $new_class =~ s/\_{2,}/_/g;
2635 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
2636             $class = ref( $self ) . "\::${new_class}";
2637             }
2638 0 0       0 # my $class = shift( @_ );
2639 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2640             unless( Class::Load::is_class_loaded( $class ) )
2641 0         0 {
2642             my $perl = <<EOT;
2643             package $class;
2644             BEGIN
2645             {
2646             use strict;
2647             use warnings::register;
2648             use Module::Generic;
2649             use parent -norequire, qw( Module::Generic::Dynamic );
2650             };
2651              
2652             1;
2653              
2654             EOT
2655 0         0 # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" );
2656             my $rc = eval( $perl );
2657 0 0       0 # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" );
2658             die( "Unable to dynamically create module \"$class\" for field \"$field\" based on our own class \"", ref( $self ), "\": $@" ) if( $@ );
2659             }
2660 0 0       0
2661             if( @_ )
2662 0         0 {
2663             my $hash = shift( @_ );
2664             # my $o = $class->new( $hash );
2665 0         0 # print( STDERR ref( $self ), "::_set_get_hash_as_object instantiating hash with ref (", ref( $hash ), ") ", overload::StrVal( $hash ), "\n" );
2666 0     0   0 my $o = $self->__instantiate_object( $field, $class, $hash );
  0         0  
2667 0         0 $self->message( 3, "Resulting object contains: ", sub{ $self->dumper( $o ) } );
2668             $data->{ $field } = $o;
2669             }
2670 0 0 0     0
2671             if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) )
2672 0         0 {
2673             my $o = $data->{ $field } = $self->__instantiate_object( $field, $class, $data->{ $field } );
2674 0         0 }
2675             return( $data->{ $field } );
2676             }
2677              
2678             sub _set_get_lvalue : lvalue
2679 0     0   0 {
2680 0         0 my $self = shift( @_ );
2681 0         0 my $field = shift( @_ );
2682 0 0       0 my $this = $self->_obj2h;
2683 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2684             if( want( qw( LVALUE ASSIGN ) ) )
2685 0         0 {
2686 0         0 my( $a ) = want( 'ASSIGN' );
2687             $data->{ $field } = $a;
2688 0         0 # lnoreturn;
2689             return( $data->{ $field } );
2690             }
2691             else
2692 0 0       0 {
2693             if( @_ )
2694 0 0 0     0 {
2695 0         0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2696             $data->{ $field } = shift( @_ );
2697 0 0       0 }
2698 0         0 return( $data->{ $field } ) if( want( 'LVALUE' ) );
2699             rreturn( $data->{ $field } );
2700 0         0 }
2701             return;
2702             }
2703              
2704             # sub _set_get_number
2705             # {
2706             # my $self = shift( @_ );
2707             # my $field = shift( @_ );
2708             # my $this = $self->_obj2h;
2709             # my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2710             # @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2711             # if( @_ )
2712             # {
2713             # $data->{ $field } = Module::Generic::Number->new( shift( @_ ) );
2714             # }
2715             # return( $data->{ $field } );
2716             # }
2717             sub _set_get_number : lvalue
2718 4     4   9 {
2719 4         8 my $self = shift( @_ );
2720 4         26 my $field = shift( @_ );
2721 7     7   67 my $this = $self->_obj2h;
  7         16  
  7         60  
2722 4 50       20 no overload;
2723             my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2724 4 50       22 # print( STDERR ref( $self ), "::_set_get_number: Current value is '", overload::StrVal( $data->{ $field } ), "'\n" );
2725             if( want( qw( LVALUE ASSIGN ) ) )
2726 0         0 {
2727             my( $a ) = want( 'ASSIGN' );
2728 0         0 # print( STDERR ref( $self ), "::_set_get_number: Setting Module::Generic::Number object for lvalue '$a'.\n" );
2729             $data->{ $field } = Module::Generic::Number->new( $a );
2730             # print( STDERR ref( $self ), "::_set_get_number: Lvalue context, object now is '", overload::StrVal( $data->{ $field } ), "'\n" );
2731 0         0 # print( STDERR ref( $self ), "::_set_get_number: Returning value '", overload::StrVal( $data->{ $field } ), "' in LVALUE context\n" );
2732             return( $data->{ $field } );
2733             }
2734             else
2735 4 50 66     255 {
2736 4 100       11 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2737             if( @_ )
2738             {
2739 3         18 # print( STDERR ref( $self ), "::_set_get_number: Setting Module::Generic::Number object for regular values '", join( "', '", @_ ), "'.\n" );
2740             $data->{ $field } = Module::Generic::Number->new( shift( @_ ) );
2741             # print( STDERR ref( $self ), "::_set_get_number: Regular context, object now is '", overload::StrVal( $data->{ $field } ), "'\n" );
2742 4 50 33     21 }
2743             if( CORE::length( $data->{ $field } ) && !ref( $data->{ $field } ) )
2744 0         0 {
2745             $data->{ $field } = Module::Generic::Number->new( $data->{ $field } );
2746             }
2747 4 50       19 # print( STDERR ref( $self ), "::_set_get_number: Returning value '", overload::StrVal( $data->{ $field } ), "' in regular context\n" );
2748             return( $data->{ $field } ) if( want( 'LVALUE' ) );
2749 4         252 # print( STDERR ref( $self ), "::_set_get_number: RReturning value '", overload::StrVal( $data->{ $field } ), "' in rvalue context\n" );
2750             rreturn( $data->{ $field } );
2751 0         0 }
2752             return;
2753             }
2754 0     0   0  
2755             sub _set_get_number_as_object : lvalue { return( shift->_set_get_number( @_ ) ); }
2756              
2757             sub _set_get_number_or_object
2758 0     0   0 {
2759 0         0 my $self = shift( @_ );
2760 0         0 my $field = shift( @_ );
2761 0         0 my $class = shift( @_ );
2762 0 0       0 my $this = $self->_obj2h;
2763 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2764             if( @_ )
2765 0 0 0     0 {
2766             if( ref( $_[0] ) eq 'HASH' || Scalar::Util::blessed( $_[0] ) )
2767 0         0 {
2768             return( $self->_set_get_object( $field, $class, @_ ) );
2769             }
2770             else
2771 0         0 {
2772             return( $self->_set_get_number( $field, @_ ) );
2773             }
2774 0         0 }
2775             return( $data->{ $field } );
2776             }
2777              
2778             sub _set_get_object
2779 3973     3973   5879 {
2780 3973         5769 my $self = shift( @_ );
2781 3973         5644 my $field = shift( @_ );
2782 3973         9163 my $class = shift( @_ );
2783 3973 50       9236 my $this = $self->_obj2h;
2784 7     7   2484 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
  7         18  
  7         19276  
2785             no overloading;
2786 3973 100       7938 # $self->message( 3, "Called for field '$field' and class '$class'." );
2787             if( @_ )
2788 3962 50       7195 {
2789             if( scalar( @_ ) == 1 )
2790             {
2791 3962 50       13066 ## User removed the value by passing it an undefined value
    50          
2792             if( !defined( $_[0] ) )
2793 0         0 {
2794             $data->{ $field } = undef();
2795             }
2796             ## User pass an object
2797             elsif( Scalar::Util::blessed( $_[0] ) )
2798 3962         6481 {
2799 3962 50       12127 my $o = shift( @_ );
2800             return( $self->error( "Object provided (", ref( $o ), ") for $field is not a valid $class object" ) ) if( !$o->isa( "$class" ) );
2801             ## XXX Bad idea:
2802 3962         18008 ## $o->debug( $this->{debug} ) if( $o->can( 'debug' ) );
2803             $data->{ $field } = $o;
2804             }
2805             else
2806 0   0     0 {
2807             my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) );
2808 0         0 # $self->message( 3, "Setting field $field value to $o" );
2809             $data->{ $field } = $o;
2810             }
2811             }
2812             else
2813 0   0     0 {
2814             my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) );
2815 0         0 # $self->message( 3, "Setting field $field value to $o" );
2816             $data->{ $field } = $o;
2817             }
2818             }
2819             ## If nothing has been set for this field, ie no object, but we are called in chain
2820 3973 50 33     12827 ## we set a dummy object that will just call itself to avoid perl complaining about undefined value calling a method
2821             if( !$data->{ $field } && want( 'OBJECT' ) )
2822             {
2823             # 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" );
2824             # $self->message( 3, "Called in a chain, but no object is set, reverting to dummy object." );
2825             ## my $null = Module::Generic::Null->new( $o, { debug => $self->{debug}, has_error => 1 });
2826 0   0     0 ## rreturn( $null );
2827 0         0 my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) );
2828 0         0 $data->{ $field } = $o;
2829             return( $o );
2830             }
2831 3973         11180 # $self->message( 3, "Returning for field '$field' value: ", $self->{ $field } );
2832             return( $data->{ $field } );
2833             }
2834              
2835             sub _set_get_object_array2
2836 0     0   0 {
2837 0         0 my $self = shift( @_ );
2838 0         0 my $field = shift( @_ );
2839 0         0 my $class = shift( @_ );
2840 0 0       0 my $this = $self->_obj2h;
2841 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2842             if( @_ )
2843 0         0 {
2844 0 0       0 my $data_to_process = shift( @_ );
2845 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 ) );
2846 0         0 my $arr1 = [];
2847             foreach my $ref ( @$data_to_process )
2848 0 0       0 {
2849 0         0 return( $self->error( "I was expecting an embeded array ref, but instead got '$ref'." ) ) if( ref( $ref ) ne 'ARRAY' );
2850 0         0 my $arr = [];
2851             for( my $i = 0; $i < scalar( @$ref ); $i++ )
2852 0         0 {
2853 0 0       0 my $o;
2854             if( defined( $ref->[$i] ) )
2855 0 0       0 {
2856 0 0       0 return( $self->error( "Parameter provided for adding object of class $class is not a reference." ) ) if( !ref( $ref->[$i] ) );
    0          
2857             if( Scalar::Util::blessed( $ref->[$i] ) )
2858 0 0       0 {
2859 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 ) );
2860             $o = $ref->[$i];
2861             }
2862             elsif( ref( $ref->[$i] ) eq 'HASH' )
2863             {
2864 0         0 #$o = $class->new( $h, $ref->[$i] );
2865             $o = $self->_instantiate_object( $field, $class, $ref->[$i] );
2866             }
2867             else
2868 0         0 {
2869             $self->error( "Warning only: data provided to instaantiate object of class $class is not a hash reference" );
2870             }
2871             }
2872             else
2873             {
2874 0         0 #$o = $class->new( $h );
2875             $o = $self->_instantiate_object( $field, $class );
2876 0 0       0 }
2877             return( $self->error( "Unable to instantiate an object of class $class: ", $class->error ) ) if( !defined( $o ) );
2878 0         0 # $o->{ '_parent' } = $self->{ '_parent' };
2879             push( @$arr, $o );
2880 0         0 }
2881             push( @$arr1, $arr );
2882 0         0 }
2883             $data->{ $field } = $arr1;
2884 0         0 }
2885             return( $data->{ $field } );
2886             }
2887              
2888             sub _set_get_object_array
2889 0     0   0 {
2890 0         0 my $self = shift( @_ );
2891 0         0 my $field = shift( @_ );
2892 0         0 my $class = shift( @_ );
2893 0 0       0 my $this = $self->_obj2h;
2894 0 0 0     0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2895 0 0       0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2896             if( @_ )
2897 0         0 {
2898 0 0       0 my $ref = shift( @_ );
2899 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 ) );
2900 0         0 my $arr = [];
2901             for( my $i = 0; $i < scalar( @$ref ); $i++ )
2902 0 0       0 {
2903             if( defined( $ref->[$i] ) )
2904 0 0       0 {
2905 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] ) );
    0          
2906             if( Scalar::Util::blessed( $ref->[$i] ) )
2907 0 0       0 {
2908 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 ) );
2909             push( @$arr, $ref->[$i] );
2910             }
2911             elsif( ref( $ref->[$i] ) eq 'HASH' )
2912             {
2913 0   0     0 #$o = $class->new( $h, $ref->[$i] );
2914 0         0 $o = $self->_instantiate_object( $field, $class, $ref->[$i] ) || return;
2915             push( @$arr, $o );
2916             }
2917             else
2918 0         0 {
2919             $self->error( "Warning only: data provided to instantiate object of class $class is not a hash reference" );
2920             }
2921             }
2922             else
2923 0         0 {
2924 0   0     0 return( $self->error( "Array offset $i contains an undefined value. I was expecting an object of class $class." ) );
2925 0         0 $o = $self->_instantiate_object( $field, $class ) || return;
2926             push( @$arr, $o );
2927             }
2928 0         0 }
2929             $data->{ $field } = $arr;
2930 0         0 }
2931             return( $data->{ $field } );
2932             }
2933              
2934             sub _set_get_object_array_object
2935 0     0   0 {
2936 0   0     0 my $self = shift( @_ );
2937 0   0     0 my $field = shift( @_ ) || return( $self->error( "No field name was provided for this array of object." ) );
2938 0         0 my $class = shift( @_ ) || return( $self->error( "No class was provided for this array of objects." ) );
2939 0 0       0 my $this = $self->_obj2h;
2940 0 0 0     0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2941 0 0       0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
2942             if( @_ )
2943 0 0 0     0 {
2944             my $that = ( scalar( @_ ) == 1 && UNIVERSAL::isa( $_[0], 'ARRAY' ) ) ? shift( @_ ) : [ @_ ];
2945 0   0     0 ## $self->message( 3, "Received following data to store as array object: ", sub{ $self->dump( $that ) } );
2946             my $ref = $self->_set_get_object_array( $field, $class, $that ) || return;
2947 0         0 ## $self->message( 3, "Object array returned is: ", sub{ $self->dump( $ref ) } );
2948             $data->{ $field } = Module::Generic::Array->new( $ref );
2949             ## $self->message( 3, "Now value for field '$field' is: ", $data->{ $field }, " which contains: '", $data->{ $field }->join( "', '" ), "'." );
2950             }
2951             ## 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"
2952 0 0 0     0 ## Also, this will make i possible to set default value in caller's object and we would turn it into array object.
2953             if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) )
2954 0         0 {
2955 0         0 my $o = Module::Generic::Array->new( $data->{ $field } );
2956             $data->{ $field } = $o;
2957 0         0 }
2958             return( $data->{ $field } );
2959             }
2960              
2961             sub _set_get_object_variant
2962 0     0   0 {
2963 0         0 my $self = shift( @_ );
2964             my $field = shift( @_ );
2965 0         0 ## The class precisely depends on what we find looking ahead
2966 0         0 my $class = shift( @_ );
2967 0 0       0 my $this = $self->_obj2h;
2968 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2969             if( @_ )
2970 0 0       0 {
    0          
2971             if( ref( $_[0] ) eq 'HASH' )
2972 0         0 {
2973             my $o = $self->_instantiate_object( $field, $class, @_ );
2974             }
2975             ## AN array of objects hash
2976             elsif( ref( $_[0] ) eq 'ARRAY' )
2977 0         0 {
2978 0         0 my $arr = shift( @_ );
2979 0         0 my $res = [];
2980             foreach my $data ( @$arr )
2981 0   0     0 {
2982 0         0 my $o = $self->_instantiate_object( $field, $class, $data ) || return( $self->error( "Unable to create object: ", $self->error ) );
2983             push( @$res, $o );
2984 0         0 }
2985             $data->{ $field } = $res;
2986             }
2987 0         0 }
2988             return( $data->{ $field } );
2989             }
2990              
2991             sub _set_get_scalar
2992 4     4   6 {
2993 4         5 my $self = shift( @_ );
2994 4         8 my $field = shift( @_ );
2995 4 50       10 my $this = $self->_obj2h;
2996 4 50       8 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
2997             if( @_ )
2998 0 0       0 {
2999             my $val = ( @_ == 1 ) ? shift( @_ ) : join( '', @_ );
3000             ## Just in case, we force stringification
3001 0 0 0     0 ## $val = "$val" if( defined( $val ) );
3002 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' );
3003             $data->{ $field } = $val;
3004 4         14 }
3005             return( $data->{ $field } );
3006             }
3007              
3008             sub _set_get_scalar_as_object
3009 61554     61554   76843 {
3010 61554         75097 my $self = shift( @_ );
3011 61554         105542 my $field = shift( @_ );
3012 61554 50       111960 my $this = $self->_obj2h;
3013 61554 100       104303 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
3014             if( @_ )
3015 4030         5419 {
3016 4030 50 33     15469 my $val;
    50          
3017             if( ref( $val ) eq 'SCALAR' || UNIVERSAL::isa( $val, 'SCALAR' ) )
3018 0         0 {
3019             $val = $$_[0];
3020             }
3021             elsif( ref( $val ) )
3022 0         0 {
3023             return( $self->error( "I was expecting a string or a scalar reference, but instead got '$val'" ) );
3024             }
3025             else
3026 4030         6395 {
3027             $val = shift( @_ );
3028 4030         6295 }
3029             my $o = $data->{ $field };
3030 4030 100       7773 # $self->message( 3, "Value to use is '$val' and current object is '", ref( $o ), "'." );
3031             if( ref( $o ) )
3032 3814         8612 {
3033             $o->set( $val );
3034             }
3035             else
3036 216         732 {
3037             $data->{ $field } = Module::Generic::Scalar->new( $val );
3038             }
3039             # $self->message( 3, "Object now is: '", ref( $data->{ $field } ), "'." );
3040             }
3041 61554 50 33     116071 # $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 }, "'." );
      66        
3042             if( !$self->_is_object( $data->{ $field } ) || ( $self->_is_object( $data->{ $field } ) && ref( $data->{ $field } ) ne ref( $self ) ) )
3043             {
3044 61554         133162 # $self->message( 3, "No object is set yet, initiating one." );
3045             $data->{ $field } = Module::Generic::Scalar->new( $data->{ $field } );
3046 61554         114040 }
3047 61554 100       110423 my $v = $data->{ $field };
3048             if( !$v->defined )
3049 54320 100       115019 {
3050             if( Want::want( 'OBJECT' ) )
3051 1612         89977 {
3052             return( Module::Generic::Null->new );
3053             }
3054             else
3055 52708         2735729 {
3056             return;
3057             }
3058             }
3059             else
3060 7234         18216 {
3061             return( $v );
3062             }
3063             }
3064              
3065             sub _set_get_scalar_or_object
3066 0     0   0 {
3067 0         0 my $self = shift( @_ );
3068 0         0 my $field = shift( @_ );
3069 0         0 my $class = shift( @_ );
3070 0 0       0 my $this = $self->_obj2h;
3071 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
3072             if( @_ )
3073 0 0 0     0 {
3074             if( ref( $_[0] ) eq 'HASH' || Scalar::Util::blessed( $_[0] ) )
3075 0         0 {
3076             return( $self->_set_get_object( $field, $class, @_ ) );
3077             }
3078             else
3079 0         0 {
3080             return( $self->_set_get_scalar( $field, @_ ) );
3081             }
3082 0 0 0     0 }
3083             if( !$data->{ $field } && want( 'OBJECT' ) )
3084             {
3085             # $self->message( 3, "Called in a chain for field $field and class $class, but no object is set, reverting to dummy object." );
3086 0         0 # $self->messagef( 3, "Expecting void? '%s'. Want scalar? '%s'. Want hash? '%s', wantref: '%s'", want('VOID'), want('SCALAR'), Want::want('HASH'), Want::wantref() );
3087 0         0 my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 });
3088             rreturn( $null );
3089 0         0 }
3090             return( $data->{ $field } );
3091             }
3092              
3093             sub _set_get_uri
3094 0     0   0 {
3095 0         0 my $self = shift( @_ );
3096 0         0 my $field = shift( @_ );
3097 0 0       0 my $this = $self->_obj2h;
3098 0 0       0 my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
3099             if( @_ )
3100 0         0 {
3101 0     0   0 try
3102 0 0       0 {
3103             require URI if( !$self->_is_class_loaded( 'URI' ) );
3104 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         0  
  0         0  
3105 0     0   0 catch( $e )
3106 0         0 {
3107 0 0 0     0 return( $self->error( "Error trying to load module URI: $e" ) );
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
3108             }
3109 0         0
3110 0 0 0     0 my $str = shift( @_ );
    0 0        
    0 0        
    0          
3111             if( Scalar::Util::blessed( $str ) && $str->isa( 'URI' ) )
3112 0         0 {
3113             $data->{ $field } = $str;
3114             }
3115             elsif( defined( $str ) && ( $str =~ /^[a-zA-Z]+:\/{2}/ || $str =~ /^urn\:[a-z]+\:/ || $str =~ /^[a-z]+\:/ ) )
3116 0         0 {
3117 0 0       0 $data->{ $field } = URI->new( $str );
3118             warn( "URI subclass is missing to handle this specific URI '$str'\n" ) if( !$data->{ $field }->has_recognized_scheme );
3119             }
3120             ## Is it an absolute path?
3121             elsif( substr( $str, 0, 1 ) eq '/' )
3122 0         0 {
3123             $data->{ $field } = URI->new( $str );
3124             }
3125             elsif( defined( $str ) )
3126 0         0 {
3127             return( $self->error( "URI value provided '$str' does not look like an URI, so I do not know what to do with it." ) );
3128             }
3129             else
3130 0         0 {
3131             $data->{ $field } = undef();
3132             }
3133 0         0 }
3134             return( $data->{ $field } );
3135             }
3136              
3137             sub _to_array_object
3138 0     0   0 {
3139 0 0 0     0 my $self = shift( @_ );
    0 0        
3140             my $data = scalar( @_ ) == 1 && $self->_is_array( $_[0] )
3141             ? shift( @_ )
3142             : ( scalar( @_ ) == 0 || ( scalar( @_ ) == 1 && !defined( $_[0] ) ) )
3143             ? []
3144 0         0 : [ @_ ];
3145             return( $self->new_array( $data ) );
3146             }
3147 1   33 1   131  
3148             sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); }
3149              
3150             sub __dbh
3151 0     0   0 {
3152 0   0     0 my $self = shift( @_ );
3153 0         0 my $class = ref( $self ) || $self;
3154 0 0       0 my $this = $self->_obj2h;
3155             if( !$this->{ '__dbh' } )
3156 0 0       0 {
  0         0  
3157 0         0 return( '' ) if( !${ "$class\::DB_DSN" } );
3158             require DBI;
3159 0         0 ## Connecting to database
3160 0 0       0 my $db_opt = {};
  0         0  
  0         0  
3161 0 0       0 $db_opt->{RaiseError} = ${ "$class\::DB_RAISE_ERROR" } if( length( ${ "$class\::DB_RAISE_ERROR" } ) );
  0         0  
  0         0  
3162 0 0       0 $db_opt->{AutoCommit} = ${ "$class\::DB_AUTO_COMMIT" } if( length( ${ "$class\::DB_AUTO_COMMIT" } ) );
  0         0  
  0         0  
3163 0 0       0 $db_opt->{PrintError} = ${ "$class\::DB_PRINT_ERROR" } if( length( ${ "$class\::DB_PRINT_ERROR" } ) );
  0         0  
  0         0  
3164 0 0       0 $db_opt->{ShowErrorStatement} = ${ "$class\::DB_SHOW_ERROR_STATEMENT" } if( length( ${ "$class\::DB_SHOW_ERROR_STATEMENT" } ) );
  0         0  
  0         0  
3165             $db_opt->{client_encoding} = ${ "$class\::DB_CLIENT_ENCODING" } if( length( ${ "$class\::DB_CLIENT_ENCODING" } ) );
3166 0   0     0 my $dbh = DBI->connect_cached( ${ "$class\::DB_DSN" } ) ||
3167 0 0       0 die( "Unable to connect to sql database with dsn '", ${ "$class\::DB_DSN" }, "'\n" );
  0         0  
3168 0         0 $dbh->{pg_server_prepare} = 1 if( ${ "$class\::DB_SERVER_PREPARE" } );
3169             $this->{ '__dbh' } = $dbh;
3170 0         0 }
3171             return( $this->{ '__dbh' } );
3172             }
3173              
3174             sub DEBUG
3175 0     0 1 0 {
3176 0   0     0 my $self = shift( @_ );
3177 0         0 my $pkg = ref( $self ) || $self;
3178 0         0 my $this = $self->_obj2h;
  0         0  
3179             return( ${ $pkg . '::DEBUG' } );
3180             }
3181              
3182             sub VERBOSE
3183 0     0 1 0 {
3184 0   0     0 my $self = shift( @_ );
3185 0         0 my $pkg = ref( $self ) || $self;
3186 0         0 my $this = $self->_obj2h;
  0         0  
3187             return( ${ $pkg . '::VERBOSE' } );
3188             }
3189              
3190             AUTOLOAD
3191 0     0   0 {
3192             my $self;
3193 0 0 0     0 # $self = shift( @_ ) if( ref( $_[ 0 ] ) && index( ref( $_[ 0 ] ), 'Module::' ) != -1 );
3194 0         0 $self = shift( @_ ) if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic' ) );
3195 0   0     0 my( $class, $meth );
3196             $class = ref( $self ) || $self;
3197 0         0 ## Leave this commented out as we need it a little bit lower
3198 0         0 my( $pkg, $file, $line ) = caller();
3199 7     7   67 my $sub = ( caller( 1 ) )[ 3 ];
  7         15  
  7         2459  
3200 0 0       0 no overloading;
3201             if( $sub eq 'Module::Generic::AUTOLOAD' )
3202 0         0 {
3203 0 0       0 my $mesg = "Module::Generic::AUTOLOAD (called at line '$line') is looping for autoloadable method '$AUTOLOAD' and args '" . join( "', '", @_ ) . "'.";
3204             if( $MOD_PERL )
3205 0         0 {
3206 0         0 my $r = Apache2::RequestUtil->request;
3207             $r->log_error( $mesg );
3208             }
3209             else
3210 0         0 {
3211             print( $err $mesg, "\n" );
3212 0         0 }
3213             exit( 0 );
3214 0         0 }
3215 0 0       0 $meth = $AUTOLOAD;
3216             if( CORE::index( $meth, '::' ) != -1 )
3217 0         0 {
3218 0         0 my $idx = rindex( $meth, '::' );
3219 0         0 $class = substr( $meth, 0, $idx );
3220             $meth = substr( $meth, $idx + 2 );
3221             }
3222 0 0 0     0
3223             if( $self && $self->can( 'autoload' ) )
3224 0 0       0 {
3225             if( my $code = $self->autoload( $meth ) )
3226 0 0       0 {
3227             return( $code->( $self ) ) if( $code );
3228             }
3229             }
3230 0         0
3231 0         0 $meth = lc( $meth );
3232 0 0       0 my $this;
3233 0         0 $this = $self->_obj2h if( defined( $self ) );
3234 0 0       0 my $data;
3235             if( $this )
3236 0 0       0 {
3237             $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this;
3238             }
3239 0 0 0     0 ## CORE::print( STDERR "Storing '$meth' with value ", join( ', ', @_ ), "\n" );
    0 0        
    0 0        
3240             if( $data && CORE::exists( $data->{ $meth } ) )
3241 0 0       0 {
3242             if( @_ )
3243 0 0       0 {
3244 0         0 my $val = ( @_ == 1 ) ? shift( @_ ) : [ @_ ];
3245             $data->{ $meth } = $val;
3246 0 0       0 }
3247             if( wantarray() )
3248 0 0       0 {
    0          
3249             if( ref( $data->{ $meth } ) eq 'ARRAY' )
3250 0         0 {
  0         0  
3251             return( @{ $data->{ $meth } } );
3252             }
3253             elsif( ref( $data->{ $meth } ) eq 'HASH' )
3254 0         0 {
  0         0  
3255             return( %{ $data->{ $meth } } );
3256             }
3257             else
3258 0         0 {
3259             return( ( $data->{ $meth } ) );
3260             }
3261             }
3262             else
3263 0         0 {
3264             return( $data->{ $meth } );
3265             }
3266             }
3267             ## Because, if it does not exist in the caller's package,
3268             ## calling the method will get us here infinitly,
3269 0         0 ## since UNIVERSAL::can will somehow return true even if it does not exist
3270             elsif( $self && $self->can( $meth ) && defined( &{ "$class\::$meth" } ) )
3271 0         0 {
3272             return( $self->$meth( @_ ) );
3273             }
3274             elsif( defined( &$meth ) )
3275 7     7   56 {
  7         15  
  7         5400  
3276 0         0 no strict 'refs';
3277 0         0 *$meth = \&$meth;
3278             return( &$meth( @_ ) );
3279             }
3280             else
3281 0         0 {
3282 0         0 my $sub = $AUTOLOAD;
3283 0         0 my( $pkg, $func ) = ( $sub =~ /(.*)::([^:]+)$/ );
3284 0 0       0 my $mesg = "Module::Generic::AUTOLOAD(): Searching for routine '$func' from package '$pkg'.";
3285             if( $MOD_PERL )
3286 0         0 {
3287 0         0 my $r = Apache2::RequestUtil->request;
3288             $r->log_error( $mesg );
3289             }
3290             else
3291 0 0       0 {
3292             print( STDERR $mesg . "\n" ) if( $DEBUG );
3293 0         0 }
3294 0 0       0 $pkg =~ s/::/\//g;
3295             if( defined( $filename = $INC{ "$pkg.pm" } ) )
3296 0         0 {
3297             $filename =~ s/^(.*)$pkg\.pm\z/$1auto\/$pkg\/$func.al/s;
3298 0 0       0 ## print( STDERR "Found possible autoloadable file '$filename'.\n" );
3299             if( -r( $filename ) )
3300 0 0       0 {
3301             unless( $filename =~ m|^/|s )
3302 0         0 {
3303             $filename = "./$filename";
3304             }
3305             }
3306             else
3307 0         0 {
3308             $filename = undef();
3309             }
3310 0 0       0 }
3311             if( !defined( $filename ) )
3312 0         0 {
3313 0         0 $filename = "auto/$sub.al";
3314             $filename =~ s/::/\//g;
3315 0         0 }
3316             my $save = $@;
3317 0         0 eval
3318 0     0   0 {
3319 0     0   0 local $SIG{ '__DIE__' } = sub{ };
3320 0         0 local $SIG{ '__WARN__' } = sub{ };
3321             require $filename;
3322 0 0       0 };
3323             if( $@ )
3324 0 0       0 {
3325             if( substr( $sub, -9 ) eq '::DESTROY' )
3326 0     0   0 {
3327             *$sub = sub {};
3328             }
3329             else
3330             {
3331             # The load might just have failed because the filename was too
3332             # long for some old SVR3 systems which treat long names as errors.
3333             # If we can succesfully truncate a long name then it's worth a go.
3334             # There is a slight risk that we could pick up the wrong file here
3335 0 0       0 # but autosplit should have warned about that when splitting.
  0         0  
3336             if( $filename =~ s/(\w{12,})\.al$/substr( $1, 0, 11 ) . ".al"/e )
3337             {
3338 0         0 eval
3339 0     0   0 {
3340 0     0   0 local $SIG{ '__DIE__' } = sub{ };
3341 0         0 local $SIG{ '__WARN__' } = sub{ };
3342             require $filename
3343             };
3344 0 0       0 }
3345             if( $@ )
3346             {
3347             #$@ =~ s/ at .*\n//;
3348             #my $error = $@;
3349             #CORE::die( $error );
3350             ## die( "Method $meth() is not defined in class $class and not autoloadable.\n" );
3351             ## print( $err "EXTRA_AUTOLOAD is ", defined( &{ "${class}::EXTRA_AUTOLOAD" } ) ? "defined" : "not defined", " in package '$class'.\n" );
3352             ## if( $self && defined( &{ "${class}::EXTRA_AUTOLOAD" } ) )
3353             ## Look up in our caller's @ISA to see if there is any package that has this special
3354 0         0 ## EXTRA_AUTOLOAD() sub routine
3355 0 0       0 my $sub_ref = '';
3356 0 0 0     0 die( "EXTRA_AUTOLOAD: ", join( "', '", @_ ), "\n" ) if( $func eq 'EXTRA_AUTOLOAD' );
      0        
3357             if( $self && $func ne 'EXTRA_AUTOLOAD' && ( $sub_ref = $self->will( 'EXTRA_AUTOLOAD' ) ) )
3358             {
3359             ## return( &{ "${class}::EXTRA_AUTOLOAD" }( $self, $meth ) );
3360 0         0 ## return( $self->EXTRA_AUTOLOAD( $AUTOLOAD, @_ ) );
3361             return( $sub_ref->( $self, $AUTOLOAD, @_ ) );
3362             }
3363             else
3364 0         0 {
3365 0         0 my $keys = CORE::join( ',', keys( %$data ) );
3366 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";
3367 0         0 $msg .= "There are actually the following fields in the object '$self': '$keys'\n";
3368             die( $msg );
3369             }
3370             }
3371             }
3372 0         0 }
3373 0 0       0 $@ = $save;
3374             if( $DEBUG )
3375 0         0 {
3376 0 0       0 my $mesg = "unshifting '$self' to args for sub '$sub'.";
3377             if( $MOD_PERL )
3378 0         0 {
3379 0         0 my $r = Apache2::RequestUtil->request;
3380             $r->log_error( $mesg );
3381             }
3382             else
3383 0         0 {
3384             print( $err "$mesg\n" );
3385             }
3386 0 0       0 }
3387             unshift( @_, $self ) if( $self );
3388 0         0 #use overloading;
3389             goto &$sub;
3390             ## die( "Method $meth() is not defined in class $class and not autoloadable.\n" );
3391             ## my $mesg = "Method $meth() is not defined in class $class and not autoloadable.";
3392             ## $self->{ 'fatal' } ? die( $mesg ) : return( $self->error( $mesg ) );
3393             }
3394             };
3395              
3396       0     DESTROY
3397             {
3398             ## Do nothing
3399             };
3400              
3401             package Module::Generic::Exception;
3402             BEGIN
3403 7     7   58 {
  7         12  
  7         186  
3404 7     7   35 use strict;
  7         14  
  7         53  
3405 7     7   563 use parent qw( Module::Generic );
  7         17  
  7         377  
3406 7     7   41 use Scalar::Util;
  7         15  
  7         505  
3407             use Devel::StackTrace;
3408 0     0   0 use overload ('""' => 'as_string',
3409 0     0   0 '==' => sub { _obj_eq(@_) },
3410 7         69 '!=' => sub { !_obj_eq(@_) },
3411 7     7   40 fallback => 1,
  7         13  
3412 7     7   4298 );
3413             our( $VERSION ) = '0.1.0';
3414             };
3415              
3416             sub init
3417 1     1   3 {
3418             my $self = shift( @_ );
3419             # require Data::Dumper::Concise;
3420 1         59 # print( STDERR __PACKAGE__, "::init() Got here with args: ", Data::Dumper::Concise::Dumper( \@_ ), "\n" );
3421 1         4 $self->{code} = '';
3422 1         3 $self->{type} = '';
3423 1         3 $self->{file} = '';
3424 1         2 $self->{line} = '';
3425 1         3 $self->{message} = '';
3426 1         3 $self->{package} = '';
3427 1         3 $self->{retry_after} = '';
3428 1         3 $self->{subroutine} = '';
3429 1 50       3 my $args = {};
3430             if( @_ )
3431 1 50 33     11 {
    50          
3432             if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic::Exception' ) )
3433 0         0 {
3434             $args->{object} = shift( @_ );
3435             }
3436             elsif( ref( $_[0] ) eq 'HASH' )
3437 1         2 {
3438             $args = shift( @_ );
3439             }
3440             else
3441 0 0       0 {
3442             $args->{message} = join( '', map( ref( $_ ) eq 'CODE' ? $_->() : $_, @_ ) );
3443             }
3444             }
3445 1   50     4 # $self->SUPER::init( @_ );
3446             my $skip_frame = $args->{skip_frames} || 0;
3447 1         2 ## Skip one frame to exclude us
3448 1         12 $skip_frame++;
3449 1         235 my $trace = Devel::StackTrace->new( skip_frames => $skip_frame, indent => 1 );
3450 1         304 my $frame = $trace->next_frame;
3451 1         16 my $frame2 = $trace->next_frame;
3452 1 50 33     10 $trace->reset_pointer;
      33        
3453             if( ref( $args->{object} ) && Scalar::Util::blessed( $args->{object} ) && $args->{object}->isa( 'Module::Generic::Exception' ) )
3454 0         0 {
3455 0         0 my $o = $args->{object};
3456 0         0 $self->{message} = $o->message;
3457 0         0 $self->{code} = $o->code;
3458 0         0 $self->{type} = $o->type;
3459             $self->{retry_after} = $o->retry_after;
3460             }
3461             else
3462             {
3463 1   50     3 # print( STDERR __PACKAGE__, "::init() Got here with args: ", Data::Dumper::Concise::Dumper( $args ), "\n" );
3464 1 50       4 $self->{message} = $args->{message} || '';
3465 1 50       3 $self->{code} = $args->{code} if( exists( $args->{code} ) );
3466 1 50       4 $self->{type} = $args->{type} if( exists( $args->{type} ) );
3467             $self->{retry_after} = $args->{retry_after} if( exists( $args->{retry_after} ) );
3468 1         2 ## 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.
3469 1         4 my $copy = {};
3470 1         4 %$copy = %$args;
3471             CORE::delete( @$copy{ qw( message code type retry_after skip_frames ) } );
3472             # print( STDERR __PACKAGE__, "::init() Following non-standard keys to set up: '", join( "', '", sort( keys( %$copy ) ) ), "'\n" );
3473 1         4 ## Do we have some non-standard parameters?
3474             foreach my $p ( keys( %$copy ) )
3475 0         0 {
3476 0         0 my $p2 = $p;
3477 0         0 $p2 =~ tr/-/_/;
3478 0         0 $p2 =~ s/[^a-zA-Z0-9\_]+//g;
3479 0         0 $p2 =~ s/^\d+//g;
3480             $self->$p2( $copy->{ $p } );
3481             }
3482 1         4 }
3483 1         7 $self->{file} = $frame->filename;
3484             $self->{line} = $frame->line;
3485 1         6 ## 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
3486 1         6 $self->{subroutine} = $frame2->subroutine;
3487 1         6 $self->{package} = $frame->package;
3488 1         2 $self->{trace} = $trace;
3489             return( $self );
3490             }
3491              
3492             #sub as_string { return( $_[0]->{message} ); }
3493             ## This is important as stringification is called by die, so as per the manual page, we need to end with new line
3494             ## And will add the stack trace
3495             sub as_string
3496 7     7   58 {
  7         15  
  7         2639  
3497 1     1   3 no overloading;
3498 1         4 my $self = shift( @_ );
3499 1         4 my $str = $self->message;
3500 1         4 $str =~ s/\r?\n$//g;
3501 1         262 $str .= sprintf( " within package %s at line %d in file %s\n%s", $self->package, $self->line, $self->file, $self->trace->as_string );
3502             return( $str );
3503             }
3504              
3505             ## if( Module::Generic::Exception->caught( $e ) ) { # do something, it's ours }
3506             sub caught
3507 0     0   0 {
3508 0 0       0 my( $class, $e ) = @_;
3509 0 0 0     0 return if( ref( $class ) );
3510 0         0 return unless( Scalar::Util::blessed( $e ) && $e->isa( $class ) );
3511             return( $e );
3512             }
3513 0     0   0  
3514             sub code { return( shift->_set_get_scalar( 'code', @_ ) ); }
3515 1     1   5  
3516             sub file { return( shift->_set_get_scalar( 'file', @_ ) ); }
3517 1     1   3  
3518             sub line { return( shift->_set_get_scalar( 'line', @_ ) ); }
3519 1     1   6  
3520             sub message { return( shift->_set_get_scalar( 'message', @_ ) ); }
3521 1     1   3  
3522             sub package { return( shift->_set_get_scalar( 'package', @_ ) ); }
3523              
3524             sub rethrow
3525 0     0   0 {
3526 0 0       0 my $self = shift( @_ );
3527 0         0 return if( !Scalar::Util::blessed( $self ) );
3528             die( $self );
3529             }
3530 0     0   0  
3531             sub retry_after { return( shift->_set_get_scalar( 'retry_after', @_ ) ); }
3532 0     0   0  
3533             sub subroutine { return( shift->_set_get_scalar( 'subroutine', @_ ) ); }
3534              
3535             sub throw
3536 0     0   0 {
3537 0         0 my $self = shift( @_ );
3538 0         0 my $msg = shift( @_ );
3539             my $e = $self->new({
3540             skip_frames => 1,
3541             message => $msg,
3542 0         0 });
3543             die( $e );
3544             }
3545              
3546 1     1   5 ## 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
3547             sub trace { return( shift->_set_get_object( 'trace', 'Devel::StackTrace', @_ ) ); }
3548 0     0   0  
3549             sub type { return( shift->_set_get_scalar( 'type', @_ ) ); }
3550              
3551             sub _obj_eq
3552             {
3553 7     7   53 ##return overload::StrVal( $_[0] ) eq overload::StrVal( $_[1] );
  7         14  
  7         1143  
3554 0     0   0 no overloading;
3555 0         0 my $self = shift( @_ );
3556 0         0 my $other = shift( @_ );
3557 0 0 0     0 my $me;
    0          
3558             if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Exception' ) )
3559 0 0 0     0 {
      0        
3560             if( $self->message eq $other->message &&
3561             $self->file eq $other->file &&
3562             $self->line == $other->line )
3563 0         0 {
3564             return( 1 );
3565             }
3566             else
3567 0         0 {
3568             return( 0 );
3569             }
3570             }
3571             ## Compare error message
3572             elsif( !ref( $other ) )
3573 0         0 {
3574 0         0 my $me = $self->message;
3575             return( $me eq $other );
3576             }
3577 0         0 ## Otherwise some reference data to which we cannot compare
3578             return( 0 ) ;
3579             }
3580              
3581             AUTOLOAD
3582 0     0   0 {
3583             my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
3584 7     7   46 # my( $class, $method ) = our $AUTOLOAD =~ /^(.*?)::([^\:]+)$/;
  7         14  
  7         849  
3585 0         0 no overloading;
3586 0   0     0 my $self = shift( @_ );
3587 0         0 my $class = ref( $self ) || $self;
3588             my $code;
3589 0 0       0 # print( STDERR __PACKAGE__, "::$method(): Called with value '$_[0]'\n" );
3590             if( $code = $self->can( $method ) )
3591 0         0 {
3592             return( $code->( @_ ) );
3593             }
3594             ## elsif( CORE::exists( $self->{ $method } ) )
3595             else
3596 0         0 {
3597 0 0       0 eval( "sub ${class}::${method} { return( shift->_set_get_scalar( '$method', \@_ ) ); }" );
3598 0         0 die( $@ ) if( $@ );
3599             return( $self->$method( @_ ) );
3600             }
3601             };
3602              
3603             ## Purpose of this package is to provide an object that will be invoked in chain without breaking and then return undef at the end
3604             ## 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.
3605             ## 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
3606             ## And also by user "particle" in this perl monks discussion here: https://www.perlmonks.org/?node_id=265214
3607             package Module::Generic::Null;
3608             BEGIN
3609 7     7   47 {
  7         14  
  7         147  
3610 7     7   33 use strict;
  7         16  
  7         762  
3611 0     0   0 use Want;
3612 0     0   0 use overload ('""' => sub{ '' },
3613 0     0   0 'eq' => sub { _obj_eq(@_) },
3614 7         63 'ne' => sub { !_obj_eq(@_) },
3615 7     7   45 fallback => 1,
  7         13  
3616 7     7   579 );
  7         14  
  7         343  
3617 7     7   639 use Want;
3618             our( $VERSION ) = '0.2.0';
3619             };
3620              
3621             sub new
3622 1612     1612   2854 {
3623 1612   33     5037 my $this = shift( @_ );
3624 1612         2373 my $class = ref( $this ) || $this;
3625 1612 50 33     4593 my $error_object = shift( @_ );
3626 1612         3156 my $hash = ( @_ == 1 && ref( $_[0] ) ? shift( @_ ) : { @_ } );
3627 1612         9295 $hash->{has_error} = $error_object;
3628             return( bless( $hash => $class ) );
3629             }
3630              
3631             sub _obj_eq
3632             {
3633 7     7   45 ##return overload::StrVal( $_[0] ) eq overload::StrVal( $_[1] );
  7         13  
  7         1246  
3634 0     0   0 no overloading;
3635 0         0 my $self = shift( @_ );
3636 0         0 my $other = shift( @_ );
3637 0 0 0     0 my $me;
    0          
3638             if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Null' ) )
3639 0         0 {
3640             return( $self eq $other );
3641             }
3642             ## Compare error message
3643             elsif( !ref( $other ) )
3644 0         0 {
3645             return( '' eq $other );
3646             }
3647 0         0 ## Otherwise some reference data to which we cannot compare
3648             return( 0 ) ;
3649             }
3650              
3651             AUTOLOAD
3652 1612     1612   10638 {
3653             my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
3654             # my $debug = $_[0]->{debug};
3655             # my( $pack, $file, $file ) = caller;
3656             # my $sub = ( caller( 1 ) )[3];
3657             # print( STDERR __PACKAGE__, ": Method $method called in package $pack in file $file at line $line from subroutine $sub (AUTOLOAD = $AUTOLOAD)\n" ) if( $debug );
3658 1612 50       3749 ## If we are chained, return our null object, so the chain continues to work
3659             if( want( 'OBJECT' ) )
3660             {
3661 0         0 ## No, this is NOT a typo. rreturn() is a function of module Want
3662             rreturn( $_[0] );
3663             }
3664 1612         67463 ## Otherwise, we return undef; Empty return returns undef in scalar context and empty list in list context
3665             return;
3666             };
3667       0      
3668             DESTROY {};
3669              
3670             package Module::Generic::Dynamic;
3671             BEGIN
3672 7     7   44 {
  7         15  
  7         162  
3673 7     7   31 use strict;
  7         13  
  7         30  
3674 7     7   374 use parent qw( Module::Generic );
  7         14  
  7         835  
3675 7     7   38 use warnings::register;
  7         14  
  7         166  
3676             use Scalar::Util ();
3677 7     7   5550 # use Class::ISA;
3678             our( $VERSION ) = '0.1.0';
3679             };
3680              
3681             sub new
3682 0     0   0 {
3683 0   0     0 my $this = shift( @_ );
3684 0         0 my $class = ref( $this ) || $this;
3685 0         0 my $self = bless( {} => $class );
3686             my $data = $self->{_data} = {};
3687 0         0 ## A Module::Generic object standard parameter
3688 0         0 $self->{_data_repo} = '_data';
3689 0 0 0     0 my $hash = {};
3690 0 0 0     0 @_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) );
    0          
3691             if( scalar( @_ ) == 1 && Scalar::Util::reftype( $_[0] ) eq 'HASH' )
3692 0         0 {
3693             $hash = shift( @_ );
3694             }
3695             elsif( @_ )
3696 0 0       0 {
3697             CORE::warn( "Parameter provided is not an hash reference: '", join( "', '", @_ ), "'\n" ) if( $this->_warnings_is_enabled );
3698             }
3699             ## $self->message( 3, "Data provided are: ", sub{ $self->dumper( $hash ) } );
3700             ## print( STDERR __PACKAGE__, "::new(): Got for hash: '", join( "', '", sort( keys( %$hash ) ) ), "'\n" );
3701             local $make_class = sub
3702 0     0   0 {
3703 0         0 my $k = shift( @_ );
3704 0         0 my $new_class = $k;
3705 0         0 $new_class =~ tr/-/_/;
3706 0         0 $new_class =~ s/\_{2,}/_/g;
3707 0         0 $new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) );
3708             $new_class = "${class}\::${new_class}";
3709 0         0 ## Sanitise the key which will serve as a method name
3710 0         0 my $clean_field = $k;
3711 0         0 $clean_field =~ tr/-/_/;
3712 0         0 $clean_field =~ s/\_{2,}/_/g;
3713 0         0 $clean_field =~ s/[^a-zA-Z0-9\_]+//g;
3714             $clean_field =~ s/^\d+//g;
3715 0         0 ## print( STDERR __PACKAGE__, "::new(): \$clean_field now is '$clean_field'\n" );
3716             my $perl = <<EOT;
3717             package $new_class;
3718             BEGIN
3719             {
3720             use strict;
3721             use Module::Generic;
3722             use parent -norequire, qw( Module::Generic::Dynamic );
3723             };
3724              
3725             1;
3726              
3727             EOT
3728 0         0 # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" );
3729             my $rc = eval( $perl );
3730 0 0       0 # print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" );
3731 0         0 die( "Unable to dynamically create module $new_class: $@" ) if( $@ );
3732 0         0 return( $new_class, $clean_field );
3733             };
3734 0         0
3735             foreach my $k ( sort( keys( %$hash ) ) )
3736 0 0       0 {
    0          
    0          
3737             if( ref( $hash->{ $k } ) eq 'HASH' )
3738 0         0 {
3739 0         0 my $clean_field = $k;
3740 0         0 $clean_field =~ tr/-/_/;
3741 0         0 $clean_field =~ s/\_{2,}/_/g;
3742 0         0 $clean_field =~ s/[^a-zA-Z0-9\_]+//g;
3743             $clean_field =~ s/^\d+//g;
3744             # my( $new_class, $clean_field ) = $make_class->( $k );
3745             # print( STDERR __PACKAGE__, "::new(): Is hash looping? ", ( $hash->{ $k }->{_looping} ? 'yes' : 'no' ), " (", ref( $hash->{ $k }->{_looping} ), ")\n" );
3746             # my $o = $hash->{ $k }->{_looping} ? $hash->{ $k }->{_looping} : $new_class->new( $hash->{ $k } );
3747             # $data->{ $clean_field } = $o;
3748 0         0 # $hash->{ $k }->{_looping} = $o;
3749 0 0       0 eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_object( $clean_field, '$new_class', \@_ ) ); }" );
3750 0         0 die( $@ ) if( $@ );
3751             $self->$clean_field( $hash->{ $k } );
3752             }
3753             elsif( ref( $hash->{ $k } ) eq 'ARRAY' )
3754 0         0 {
3755             my( $new_class, $clean_field ) = $make_class->( $k );
3756             # print( STDERR __PACKAGE__, "::new() found an array for key $k, creating objects for class $new_class\n" );
3757 0 0       0 ## We take a peek at what we have to determine how we will handle the data
  0         0  
3758 0 0       0 my $mode = lc( scalar( @{$hash->{ $k }} ) ? ref( $hash->{ $k }->[0] ) : '' );
3759             if( $mode eq 'hash' )
3760 0         0 {
3761 0         0 my $all = [];
  0         0  
3762             foreach my $this ( @{$hash->{ $k }} )
3763 0 0       0 {
3764 0         0 my $o = $this->{_looping} ? $this->{_looping} : $new_class->new( $this );
3765 0         0 $this->{_looping} = $o;
3766             CORE::push( @$all, $o );
3767             }
3768 0         0 # $data->{ $clean_field } = $all;
3769             eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_object_array_object( '$clean_field', '$new_class', \@_ ) ); }" );
3770             }
3771             else
3772             {
3773 0         0 # $data->{ $clean_field } = $hash->{ $k };
3774             eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_array_as_object( '$clean_field', \@_ ) ); }" );
3775 0 0       0 }
3776 0         0 die( $@ ) if( $@ );
3777             $self->$clean_field( $hash->{ $k } );
3778             }
3779             elsif( !ref( $hash->{ $k } ) )
3780 0         0 {
3781 0         0 my $clean_field = $k;
3782 0         0 $clean_field =~ tr/-/_/;
3783 0         0 $clean_field =~ s/\_{2,}/_/g;
3784 0         0 $clean_field =~ s/[^a-zA-Z0-9\_]+//g;
3785 0         0 $clean_field =~ s/^\d+//g;
3786 0         0 eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_scalar_as_object( '$clean_field', \@_ ) ); }" );
3787             $self->$clean_field( $hash->{ $k } );
3788             }
3789             else
3790 0         0 {
3791             $self->$k( $hash->{ $k } );
3792             }
3793 0         0 }
3794             return( $self );
3795             }
3796              
3797             AUTOLOAD
3798 0     0   0 {
3799             my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
3800 7     7   57 # my( $class, $method ) = our $AUTOLOAD =~ /^(.*?)::([^\:]+)$/;
  7         14  
  7         1470  
3801 0         0 no overloading;
3802 0   0     0 my $self = shift( @_ );
3803 0         0 my $class = ref( $self ) || $self;
3804             my $code;
3805 0 0       0 # print( STDERR __PACKAGE__, "::$method(): Called\n" );
3806             if( $code = $self->can( $method ) )
3807 0         0 {
3808             return( $code->( @_ ) );
3809             }
3810             ## elsif( CORE::exists( $self->{ $method } ) )
3811             else
3812 0         0 {
3813 0         0 my $ref = lc( ref( $_[0] ) );
3814             my $handler = '_set_get_scalar_as_object';
3815 0 0 0     0 # if( @_ && ( $ref eq 'hash' || $ref eq 'array' ) )
    0 0        
      0        
      0        
      0        
3816             if( $ref eq 'hash' || $ref eq 'array' )
3817             {
3818 0         0 # print( STDERR __PACKAGE__, "::$method(): using handler $handler for type $ref\n" );
3819             $handler = "_set_get_${ref}_as_object";
3820             }
3821             elsif( $ref eq 'json::pp::boolean' ||
3822             $ref eq 'module::generic::boolean' ||
3823             ( $ref eq 'scalar' && ( $$ref == 1 || $$ref == 0 ) ) )
3824 0         0 {
3825             $handler = '_set_get_boolean';
3826 0         0 }
3827 0 0       0 eval( "sub ${class}::${method} { return( shift->$handler( '$method', \@_ ) ); }" );
3828             die( $@ ) if( $@ );
3829 0         0 ## $self->message( 3, "Calling method '$method' with data: ", sub{ $self->printer( @_ ) } );
3830             return( $self->$method( @_ ) );
3831             }
3832             };
3833              
3834             package Module::Generic::Boolean;
3835             BEGIN
3836 7     7   4439 {
  7         100  
  7         34  
3837             use common::sense;
3838 4019     4019   5586 use overload
  4019         13901  
3839 0     0   0 "0+" => sub { ${$_[0]} },
  0         0  
3840 0     0   0 "++" => sub { $_[0] = ${$_[0]} + 1 },
  0         0  
3841 7     7   1264 "--" => sub { $_[0] = ${$_[0]} - 1 },
  7         15  
  7         65  
3842             fallback => 1;
3843 7     7   2277 # *Module::Generic::Boolean:: = *JSON::PP::Boolean::;
3844             our( $VERSION ) = '0.1.0';
3845             };
3846 7 100   7   51  
3847             sub new { return( $_[1] ? $true : $false ); }
3848 0     0   0  
3849             sub defined { return( 1 ); }
3850              
3851             our $true = do{ bless( \( my $dummy = 1 ) => Module::Generic::Boolean ) };
3852             our $false = do{ bless( \( my $dummy = 0 ) => Module::Generic::Boolean ) };
3853 310     310   766  
3854 162     162   410 sub true () { $true }
3855             sub false () { $false }
3856 0     0   0  
3857 0 0   0   0 sub is_bool ($) { UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) }
3858 0 0   0   0 sub is_true ($) { $_[0] && UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) }
3859             sub is_false ($) { !$_[0] && UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) }
3860              
3861             sub TO_JSON
3862             {
3863             ## JSON does not check that the value is a proper true or false. It stupidly assumes this is a string
3864             ## The only way to make it understand is to return a scalar ref of 1 or 0
3865 0 0   0   0 # return( $_[0] ? 'true' : 'false' );
3866             return( $_[0] ? \1 : \0 );
3867             }
3868              
3869             package Module::Generic::Array;
3870             BEGIN
3871 7     7   50 {
  7         16  
  7         30  
3872 7     7   316 use common::sense;
  7         17  
  7         209  
3873 7     7   35 use warnings;
  7         14  
  7         594  
3874 7     7   37 use warnings::register;
  7         14  
  7         105  
3875 7     7   30 use Scalar::Util ();
  7         12  
  7         1042  
3876             use Want;
3877             ## use Data::Dumper;
3878             use overload (
3879             # Turned out to be not such a good ide as it create unexpected results, especially when this is an array of overloaded objects
3880 0     0   0 # '""' => 'as_string',
3881 0     0   0 '==' => sub { _obj_eq(@_) },
3882 2     2   673 '!=' => sub { !_obj_eq(@_) },
3883 1     1   9 'eq' => sub { _obj_eq(@_) },
3884 7         105 'ne' => sub { !_obj_eq(@_) },
3885             '%{}' => 'as_hash',
3886 7     7   42 fallback => 1,
  7         12  
3887 7     7   14506 );
3888             our( $VERSION ) = 'v0.1.1';
3889             };
3890              
3891             sub new
3892 38     38   747 {
3893 38         71 my $this = CORE::shift( @_ );
3894 38 50 33     382 my $init = [];
      66        
3895 38   66     275 $init = CORE::shift( @_ ) if( @_ && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) );
3896             return( bless( $init => ( ref( $this ) || $this ) ) );
3897             }
3898              
3899             sub as_hash
3900 2     2   427 {
3901 2         5 my $self = CORE::shift( @_ );
3902 2 50       11 my $opts = {};
3903             $opts = CORE::shift( @_ ) if( Scalar::Util::reftype( $opts ) eq 'HASH' );
3904 2         5 ## print( STDERR ref( $self ), "::as_hash\n" );
3905 2         9 my $ref = {};
3906 2 50       7 my( @offsets ) = $self->keys;
3907             if( $opts->{start_from} )
3908 0         0 {
3909 0         0 my $start = CORE::int( $opts->{start_from} );
3910             for my $i ( 0..$#offsets )
3911 0         0 {
3912             $offsets[ $i ] += $start;
3913             }
3914 2         24 }
3915             @$ref{ @$self } = @offsets;
3916 2         9 ## print( ref( $self ), "::as_hash -> dump: ", Data::Dumper::Dumper( $ref ), "\n" );
3917             return( Module::Generic::Hash->new( $ref ) );
3918             }
3919              
3920             sub as_string
3921 19     19   53 {
3922 19         30 my $self = CORE::shift( @_ );
3923 19 100       63 my $sort = 0;
3924 19 100       53 $sort = CORE::shift( @_ ) if( @_ );
3925 13         83 return( $self->sort->as_string ) if( $sort );
3926             return( "@$self" );
3927             }
3928 5     5   18  
  5         36  
3929             sub clone { return( $_[0]->new( [ @{$_[0]} ] ) ); }
3930              
3931             sub delete
3932 4     4   15 {
3933 4         12 my $self = CORE::shift( @_ );
3934 4 50       11 my( $offset, $length ) = @_;
3935             if( defined( $offset ) )
3936 4 100       28 {
3937             if( $offset !~ /^\-?\d+$/ )
3938 1 50       6 {
3939 1         8 warn( "Non integer offset \"$offset\" provided to delete array element\n" ) if( $self->_warnings_is_enabled );
3940             return( $self );
3941 3 50 66     21 }
3942             if( CORE::defined( $length ) && $length !~ /^\-?\d+$/ )
3943 0 0       0 {
3944 0         0 warn( $self, "Non integer length \"$length\" provided to delete array element\n" ) if( $self->_warnings_is_enabled );
3945             return( $self );
3946 3 100       17 }
3947 3 50       13 my @removed = CORE::splice( @$self, $offset, CORE::defined( $length ) ? CORE::int( $length ) : 1 );
3948             if( Want::want( 'LIST' ) )
3949 0         0 {
3950             rreturn( @removed );
3951             }
3952             else
3953 3         184 {
3954             rreturn( $self->new( \@removed ) );
3955             }
3956 0         0 # Required to make the compiler happy, as per Want documentation
3957             return;
3958 0         0 }
3959             return( $self );
3960             }
3961              
3962             sub each
3963 1     1   3 {
3964             my $self = CORE::shift( @_ );
3965 1   33     5 my $code = CORE::shift( @_ ) || do
3966             {
3967             warn( "No subroutine callback as provided for each\n" ) if( $self->_warnings_is_enabled );
3968             return;
3969 1 50       5 };
3970             if( ref( $code ) ne 'CODE' )
3971 0 0       0 {
3972 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 );
3973             return;
3974             }
3975 1         7 ## Index starts from 0
3976             while( my( $i, $v ) = CORE::each( @$self ) )
3977 18         675 {
3978 18 50       30 local $_ = $v;
3979             CORE::defined( $code->( $i, $v ) ) || CORE::last;
3980 1         10 }
3981             return( $self );
3982             }
3983              
3984             sub exists
3985 4     4   13 {
3986 4         8 my $self = CORE::shift( @_ );
3987 4         165 my $this = CORE::shift( @_ );
3988             return( $self->_number( CORE::scalar( CORE::grep( /^$this$/, @$self ) ) ) );
3989             }
3990              
3991             sub first
3992 0     0   0 {
3993 0 0       0 my $self = CORE::shift( @_ );
3994 0 0       0 return( $self->[0] ) if( CORE::length( $self->[0] ) );
3995             if( Want::want( 'OBJECT' ) )
3996 0         0 {
3997             rreturn( Module::Generic::Null->new );
3998 0         0 }
3999             return( $self->[0] );
4000             }
4001              
4002             sub for
4003 1     1   553 {
4004 1         4 my $self = CORE::shift( @_ );
4005 1 50       5 my $code = CORE::shift( @_ );
4006 1         6 return if( ref( $code ) ne 'CODE' );
4007             CORE::for( my $i = 0; $i < scalar( @$self ); $i++ )
4008 18         788 {
4009 18 50       32 local $_ = $self->[ $i ];
4010             CORE::defined( $code->( $i, $self->[ $i ] ) ) || CORE::last;
4011 1         8 }
4012             return( $self );
4013             }
4014              
4015             sub foreach
4016 1     1   40 {
4017 1         3 my $self = CORE::shift( @_ );
4018 1 50       6 my $code = CORE::shift( @_ );
4019 1         4 return if( ref( $code ) ne 'CODE' );
4020             CORE::foreach my $v ( @$self )
4021 18         83 {
4022 18 50       26 local $_ = $v;
4023             CORE::defined( $code->( $v ) ) || CORE::last;
4024 1         6 }
4025             return( $self );
4026             }
4027              
4028             sub get
4029 1     1   338 {
4030 1         2 my $self = CORE::shift( @_ );
4031 1         7 my $offset = CORE::shift( @_ );
4032             return( $self->[ CORE::int( $offset ) ] );
4033             }
4034              
4035             sub grep
4036 3     3   12 {
4037 3         6 my $self = CORE::shift( @_ );
4038 3         9 my $expr = CORE::shift( @_ );
4039 3 100       13 my $ref;
4040             if( ref( $expr ) eq 'CODE' )
4041 1         7 {
4042             $ref = [CORE::grep( $expr->( $_ ), @$self )];
4043             }
4044             else
4045 2 100       28 {
4046             $expr = ref( $expr ) eq 'Regexp'
4047             ? $expr
4048 2         45 : qr/\Q$expr\E/;
4049             $ref = [ CORE::grep( $_ =~ /$expr/, @$self ) ];
4050 3 50       55 }
4051             if( Want::want( 'LIST' ) )
4052 0         0 {
4053             return( @$ref );
4054             }
4055             else
4056 3         211 {
4057             return( $self->new( $ref ) );
4058             }
4059             }
4060 0     0   0  
4061             sub has { return( CORE::shift->exists( @_ ) ); }
4062              
4063             sub index
4064 3     3   6 {
4065 3         7 my $self = CORE::shift( @_ );
4066 3         8 my $pos = CORE::shift( @_ );
4067 3         14 $pos = CORE::int( $pos );
4068             return( $self->[ $pos ] );
4069             }
4070 0     0   0  
4071             sub iterator { return( Module::Generic::Iterator->new( $self ) ); }
4072              
4073             sub join
4074 4     4   1515 {
4075 4         34 my $self = CORE::shift( @_ );
4076             return( $self->_scalar( CORE::join( $_[0], @$self ) ) );
4077             }
4078              
4079             sub keys
4080 5     5   339 {
4081 5         34 my $self = CORE::shift( @_ );
4082             return( $self->new( [ CORE::keys( @$self ) ] ) );
4083             }
4084              
4085             sub last
4086 0     0   0 {
4087 0 0       0 my $self = CORE::shift( @_ );
4088 0 0       0 return( $self->[-1] ) if( CORE::length( $self->[-1] ) );
4089             if( Want::want( 'OBJECT' ) )
4090 0         0 {
4091             rreturn( Module::Generic::Null->new );
4092 0         0 }
4093             return( $self->[-1] );
4094             }
4095 22     22   1128  
  22         144  
4096             sub length { return( $_[0]->_number( scalar( @{$_[0]} ) ) ); }
4097 1     1   2  
  1         12  
4098             sub list { return( @{$_[0]} ); }
4099              
4100             sub map
4101 3     3   352 {
4102 3         7 my $self = CORE::shift( @_ );
4103 3 50       11 my $code = CORE::shift( @_ );
4104 3         15 return if( ref( $code ) ne 'CODE' );
4105 3 100       72 my $ref = [ CORE::map( $code->( $_ ), @$self ) ];
    100          
4106             if( Want::want( 'OBJECT' ) )
4107 1         58 {
4108             return( $self->new( $ref ) );
4109             }
4110             elsif( Want::want( 'LIST' ) )
4111 1         107 {
4112             return( @$ref );
4113             }
4114             else
4115 1         108 {
4116             return( $self->new( $ref ) );
4117             }
4118             }
4119              
4120             sub pop
4121 2     2   600 {
4122 2         11 my $self = CORE::shift( @_ );
4123             return( CORE::pop( @$self ) );
4124             }
4125              
4126             sub pos
4127 0     0   0 {
4128 0         0 my $self = CORE::shift( @_ );
4129 0 0       0 my $this = CORE::shift( @_ );
4130 0         0 return if( !CORE::length( $this ) );
4131 0 0       0 my $is_ref = ref( $this );
4132 0         0 my $ref = $is_ref ? Scalar::Util::refaddr( $this ) : $this;
4133             foreach my $i ( 0 .. $#$self )
4134 0 0 0     0 {
      0        
      0        
4135             if( ( $is_ref && Scalar::Util::refaddr( $self->[$i] ) eq $ref ) ||
4136             ( !$is_ref && $self->[$i] eq $this ) )
4137 0         0 {
4138             return( $i );
4139             }
4140 0         0 }
4141             return;
4142             }
4143              
4144             sub push
4145 1     1   3 {
4146 1         5 my $self = CORE::shift( @_ );
4147 1         4 CORE::push( @$self, @_ );
4148             return( $self );
4149             }
4150              
4151             sub push_arrayref
4152 1     1   3 {
4153 1         4 my $self = CORE::shift( @_ );
4154 1 50       5 my $ref = CORE::shift( @_ );
4155 1         7 return( $self->error( "Data provided ($ref) is not an array reference." ) ) if( !UNIVERSAL::isa( $ref, 'ARRAY' ) );
4156 1         3 CORE::push( @$self, @$ref );
4157             return( $self );
4158             }
4159              
4160             sub reset
4161 1     1   3 {
4162 1         4 my $self = CORE::shift( @_ );
4163 1         5 @$self = ();
4164             return( $self );
4165             }
4166              
4167             sub reverse
4168 1     1   4 {
4169 1         6 my $self = CORE::shift( @_ );
4170 1 50       116 my $ref = [ CORE::reverse( @$self ) ];
4171             if( wantarray() )
4172 0         0 {
4173             return( @$ref );
4174             }
4175             else
4176 1         5 {
4177             return( $self->new( $ref ) );
4178             }
4179             }
4180 0     0   0  
4181             sub scalar { return( CORE::shift->length ); }
4182              
4183             sub set
4184 1     1   3 {
4185 1 50 33     15 my $self = CORE::shift( @_ );
4186 1         6 my $ref = ( scalar( @_ ) == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? CORE::shift( @_ ) : [ @_ ];
4187 1         60 @$self = @$ref;
4188             return( $self );
4189             }
4190              
4191             sub shift
4192 1     1   4 {
4193 1         6 my $self = CORE::shift( @_ );
4194             return( CORE::shift( @$self ) );
4195             }
4196 1     1   3  
  1         7  
4197             sub size { return( $_[0]->_number( $#{$_[0]} ) ); }
4198              
4199             sub sort
4200 8     8   20 {
4201 8         16 my $self = CORE::shift( @_ );
4202 8         12 my $code = CORE::shift( @_ );
4203 8 100       26 my $ref;
4204             if( ref( $code ) eq 'CODE' )
4205             {
4206             $ref = [sort
4207 1         9 {
  53         129  
4208             $code->( $a, $b );
4209             } @$self];
4210             }
4211             else
4212 7         67 {
4213             $ref = [ CORE::sort( @$self ) ];
4214 8 50       35 }
4215             if( Want::want( 'LIST' ) )
4216 0         0 {
4217             return( @$ref );
4218             }
4219             else
4220 8         486 {
4221             return( $self->new( $ref ) );
4222             }
4223             }
4224              
4225             sub splice
4226 2     2   7 {
4227 2         9 my $self = CORE::shift( @_ );
4228 2 50 66     20 my( $offset, $length, @list ) = @_;
4229             if( defined( $offset ) && $offset !~ /^\-?\d+$/ )
4230 0 0       0 {
4231             warn( "Offset provided for splice \"$offset\" is not an integer.\n" ) if( $self->_warnings_is_enabled );
4232 0 0       0 ## If a list was provided, the user is not looking to get an element removed, but add it, so we return out object
4233 0         0 return( $self ) if( scalar( @list ) );
4234             return;
4235 2 50 66     15 }
4236             if( defined( $length ) && $length !~ /^\-?\d+$/ )
4237 0 0       0 {
4238 0 0       0 warn( "Length provided for splice \"$length\" is not an integer.\n" ) if( $self->_warnings_is_enabled );
4239 0         0 return( $self ) if( scalar( @list ) );
4240             return;
4241             }
4242             ## Adding elements, so we return our object and allow chaining
4243 2 100       10 ## @_ = offset, length, replacement list
    50          
4244             if( scalar( @_ ) > 2 )
4245 1         5 {
4246 1         6 CORE::splice( @$self, $offset, $length, @list );
4247             return( $self );
4248             }
4249             elsif( !scalar( @_ ) )
4250 1         4 {
4251 1         7 CORE::splice( @$self );
4252             return( $self );
4253             }
4254             else
4255 0 0 0     0 {
4256 0 0       0 return( CORE::splice( @$self, $offset, $length ) ) if( CORE::defined( $offset ) && CORE::defined( $length ) );
4257             return( CORE::splice( @$self, $offset ) ) if( CORE::defined( $offset ) );
4258             }
4259             }
4260              
4261             sub undef
4262 1     1   3 {
4263 1         4 my $self = CORE::shift( @_ );
4264 1         5 @$self = ();
4265             return( $self );
4266             }
4267              
4268             sub unshift
4269 1     1   5 {
4270 1         6 my $self = CORE::shift( @_ );
4271 1         7 CORE::unshift( @$self, @_ );
4272             return( $self );
4273             }
4274              
4275             sub values
4276 1     1   3 {
4277 1         6 my $self = CORE::shift( @_ );
4278 1 50       5 my $ref = [ CORE::values( @$self ) ];
4279             if( Want::want( 'LIST' ) )
4280 0         0 {
4281             return( @$ref );
4282             }
4283             else
4284 1         71 {
4285             return( $self->new( $ref ) );
4286             }
4287             }
4288              
4289             sub _number
4290 27     27   96 {
4291 27         72 my $self = CORE::shift( @_ );
4292 27 50       131 my $num = CORE::shift( @_ );
4293 27 50       101 return if( !defined( $num ) );
4294 27         137 return( $num ) if( !CORE::length( $num ) );
4295             return( Module::Generic::Number->new( $num ) );
4296             }
4297              
4298             sub _obj_eq
4299 7     7   61 {
  7         13  
  7         1326  
4300 3     3   9 no overloading;
4301 3         6 my $self = CORE::shift( @_ );
4302             my $other = CORE::shift( @_ );
4303 3         14 ## Sorted
4304 3         16 my $strA = $self->as_string(1);
4305 3 100 66     25 my $strB;
    50          
4306             if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Array' ) )
4307 1         4 {
4308             $strB = $other->as_string(1);
4309             }
4310             ## Compare error message
4311             elsif( Scalar::Util::reftype( $other ) eq 'ARRAY' )
4312 2         6 {
4313             $strB = $self->new( $other )->as_string(1);
4314             }
4315             else
4316 0         0 {
4317             return( 0 );
4318             }
4319 3         33 ## print( STDERR ref( $self ), "::_obj_eq: Comparing array A (", CORE::scalar( @$self ), ") with '$strA' to array B (", CORE::scalar( @$other ), ") with '$strB'\n" );
4320             return( $strA eq $strB ) ;
4321             }
4322              
4323             sub _scalar
4324 4     4   15 {
4325 4         10 my $self = CORE::shift( @_ );
4326 4 50       18 my $str = CORE::shift( @_ );
4327             return if( !defined( $str ) );
4328 4         19 ## Whether empty or not, return an object
4329             return( Module::Generic::Scalar->new( $str ) );
4330             }
4331 1   33 1   143  
4332             sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); }
4333              
4334              
4335             package Module::Generic::Iterator;
4336             BEGIN
4337 7     7   167 {
  7         15  
  7         27  
4338 7     7   437 use common::sense;
  7         20  
  7         200  
4339 7     7   43 use warnings;
  7         12  
  7         731  
4340 7     7   42 use warnings::register;
  7         14  
  7         42  
4341 7     7   303 use parent -norequire, qw( Module::Generic );
  7         16  
  7         112  
4342 7     7   29 use Scalar::Util ();
  7         13  
  7         418  
4343 7     7   5841 use Want;
4344             our( $VERSION ) = 'v0.1.0';
4345             };
4346              
4347             sub init
4348 1     1   3 {
4349 1         2 my $self = CORE::shift( @_ );
4350 1 50 33     14 my $init = [];
      33        
4351 1         56 $init = CORE::shift( @_ ) if( @_ && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) );
4352 1         7 $self->{_init_strict_use_sub} = 1;
4353 1         8 $self->SUPER::init( @_ );
4354             my $elems = Module::Generic::Array->new;
4355 1         3 ## Wrap each element in an Iterator element to enable next, prev, etc
4356             foreach my $this ( @$init )
4357 5         48 {
4358             CORE::push( @$elems, Module::Generic::Iterator::Element->new( $this, { parent => $self, debug => $self->debug } ) );
4359 1         4 }
4360 1         3 $self->{elements} = $elems;
4361 1         5 $self->{pos} = 0;
4362             return( $self );
4363             }
4364 20     20   81  
4365             sub elements { return( shift->_set_get_array_as_object( 'elements', @_ ) ); }
4366              
4367             sub eof
4368 1     1   4 {
4369 1         3 my $self = shift( @_ );
4370 1 50       4 my $pos;
4371             if( @_ )
4372 0         0 {
4373 0 0       0 $pos = $self->_find_pos( @_ );
4374             return if( !CORE::defined( $pos ) );
4375             }
4376             else
4377 1         4 {
4378             $pos = $self->pos;
4379 1         16 }
4380             return( $pos >= ( $self->elements->length - 1 ) );
4381             }
4382              
4383             sub find
4384 2     2   7 {
4385 2         8 my $self = shift( @_ );
4386 2 100       9 my $pos = $self->_find_pos( @_ );
4387 1         3 return if( !CORE::defined( $pos ) );
4388             return( $self->elements->index( $pos ) );
4389             }
4390              
4391             sub first
4392 1     1   316 {
4393 1         7 my $self = shift( @_ );
4394 1         17 $self->pos = 0;
4395             return( $self->elements->index( 0 ) );
4396             }
4397              
4398             sub has_next
4399 2     2   6 {
4400 2         8 my $self = shift( @_ );
4401 2         23 my $pos = $self->pos;
4402             return( $pos < ( $self->elements->length - 1 ) );
4403             }
4404              
4405             sub has_prev
4406 2     2   8 {
4407 2         11 my $self = shift( @_ );
4408 2   66     30 my $pos = $self->pos;
4409             return( $pos > 0 && $self->elements->length > 0 );
4410             }
4411              
4412             sub last
4413 1     1   5 {
4414 1         6 my $self = shift( @_ );
4415 1         51 my $pos = $self->elements->length - 1;
4416 1         20 $self->pos = $pos;
4417             return( $self->elements->index( $pos ) );
4418             }
4419 1     1   622  
4420             sub length { return( shift->elements->length ); }
4421              
4422             sub next
4423 0     0   0 {
4424 0         0 my $self = shift( @_ );
4425 0 0       0 my $pos;
4426             if( @_ )
4427 0         0 {
4428 0 0       0 $pos = $self->_find_pos( @_ );
4429 0 0       0 return if( !CORE::defined( $pos ) );
4430 0         0 return if( $pos >= ( $self->elements->length - 1 ) );
4431             $pos++;
4432             }
4433             else
4434 0         0 {
4435 0 0       0 $pos = $self->pos;
4436 0         0 return if( $self->eof );
4437             $self->pos++;
4438 0         0 }
4439             return( $self->elements->index( $pos ) );
4440             }
4441              
4442             sub pos : lvalue
4443 13     13   49 {
4444 13 100       51 my $self = shift( @_ );
    100          
4445             if( want( qw( LVALUE ASSIGN ) ) )
4446 4         644 {
4447 4 50       491 my( $a ) = want( 'ASSIGN' );
4448             if( $a !~ /^\d+$/ )
4449 0         0 {
4450 0         0 CORE::warn( "Position provided \"$a\" is not an integer.\n" );
4451             lnoreturn;
4452 4         14 }
4453 4         47 $self->{pos} = $a;
4454             lnoreturn;
4455             }
4456             elsif( want( 'RVALUE' ) )
4457             {
4458 5         514 # $self->message( 3, "Returning rvalue" );
4459             rreturn( $self->{pos} );
4460             }
4461             else
4462             {
4463 4         788 # $self->message( 3, "Else returning pos value" );
4464             return( $self->{pos} );
4465 0         0 }
4466             return;
4467             }
4468              
4469             sub prev
4470 0     0   0 {
4471 0         0 my $self = shift( @_ );
4472 0 0       0 my $pos;
4473             if( @_ )
4474 0         0 {
4475 0 0       0 $pos = $self->_find_pos( @_ );
4476 0 0       0 return if( !CORE::defined( $pos ) );
4477 0         0 return if ( $pos <= 0 );
4478             $pos--;
4479             }
4480             else
4481 0         0 {
4482 0 0       0 $pos = $self->pos;
4483             $self->pos-- if( $pos > 0 );
4484 0 0       0 ## Position of the given element is at the beginning of our array, there is nothing more
4485 0         0 return if( $pos <= 0 );
4486             $self->pos--;
4487 0         0 }
4488             return( $self->elements->index( $pos ) );
4489             }
4490              
4491             sub reset
4492 1     1   3 {
4493 1         4 my $self = shift( @_ );
4494 1         74 $self->pos = 0;
4495             return( $self );
4496             }
4497              
4498             sub _find_pos
4499 8     8   20 {
4500 8         18 my $self = shift( @_ );
4501             my $this = shift( @_ );
4502 8 50       46 # $self->message( 3, "Searching for \"$this\" (", ref( $this ) ? $this->value : $this, ")" );
4503 8         19 return if( !CORE::length( $this ) );
4504 8 100       30 my $is_ref = ref( $this );
4505             my $ref = $is_ref ? Scalar::Util::refaddr( $this ) : $this;
4506 8         34 # $self->message( 3, "\"$this\" reference address is \"$ref\"." );
4507             my $elems = $self->elements;
4508 8         32 # $self->messagef( 3, "Searching in a %d elements long stack.", $elems->length );
4509             foreach my $i ( 0 .. $#$elems )
4510 25         73 {
4511             my $val = $elems->[$i]->value;
4512 25 100 100     137 # $self->message( 3, "Checking ", ( ref( $this ) ? $this->value : $this ), " ($ref) with element No $i \"$val\" (", Scalar::Util::refaddr( $elems->[$i] ), ")." );
      100        
      100        
4513             if( ( $is_ref && Scalar::Util::refaddr( $elems->[$i] ) eq $ref ) ||
4514             ( !$is_ref && $val eq $this ) )
4515 7         32 {
4516             return( $i );
4517             }
4518 1         3 }
4519             return;
4520             }
4521              
4522             package Module::Generic::Iterator::Element;
4523             BEGIN
4524 7     7   56 {
  7         14  
  7         35  
4525 7     7   313 use common::sense;
  7         14  
  7         169  
4526 7     7   33 use warnings;
  7         28  
  7         676  
4527 7     7   40 use warnings::register;
  7         23  
  7         34  
4528 7     7   324 use parent -norequire, qw( Module::Generic );
  7         17  
  7         426  
4529 7     7   2058 use Want;
4530             our( $VERSION ) = 'v0.1.0';
4531             };
4532              
4533             sub init
4534 5     5   11 {
4535             my $self = CORE::shift( @_ );
4536 5         9 ## This could be anything
4537 5         46 my $value = CORE::shift( @_ );
4538 5         10 $self->{value} = '';
4539 5         7 $self->{parent} = '';
4540 5         17 $self->{_init_strict_use_sub} = 1;
4541 5         183 $self->SUPER::init( @_ );
4542 5         21 $self->{value} = $value;
4543             return( $self );
4544             }
4545              
4546             sub has_next
4547 2     2   7 {
4548 2         9 my $self = shift( @_ );
4549 2         8 my $pos = $self->pos;
4550             return( $pos < ( $self->parent->elements->length - 1 ) );
4551             }
4552              
4553             sub has_prev
4554 2     2   6 {
4555 2         9 my $self = shift( @_ );
4556 2   66     14 my $pos = $self->pos;
4557             return( $pos > 0 && $self->parent->elements->length > 0 );
4558             }
4559              
4560             sub next
4561 0     0   0 {
4562 0         0 my $self = shift( @_ );
4563 0 0       0 my $next = $self->parent->next( $self );
4564             if( want( 'OBJECT' ) )
4565 0         0 {
4566             return( $next );
4567             }
4568             else
4569 0         0 {
4570             return( $next->value );
4571             }
4572             }
4573 15     15   55  
4574             sub parent { return( shift->_set_get_object( 'parent', 'Module::Generic::Iterator', @_ ) ); }
4575 6     6   25  
4576             sub pos { return( $_[0]->parent->_find_pos( $_[0] ) ); }
4577              
4578             sub prev
4579 0     0   0 {
4580 0         0 my $self = shift( @_ );
4581 0 0       0 my $prev = $self->parent->prev( $self );
4582             if( want( 'OBJECT' ) )
4583 0         0 {
4584             return( $prev );
4585             }
4586             else
4587 0         0 {
4588             return( $prev->value );
4589             }
4590             }
4591 28     28   1485  
4592             sub value { return( shift->{value} ); }
4593              
4594              
4595             package Module::Generic::Scalar;
4596             BEGIN
4597 7     7   48 {
  7         14  
  7         28  
4598 7     7   320 use common::sense;
  7         18  
  7         175  
4599 7     7   33 use warnings;
  7         12  
  7         612  
4600             use warnings::register;
4601             ## So that the user can say $obj->isa( 'Module::Generic::Scalar' ) and it would return true
4602 7     7   35 ## use parent -norequire, qw( Module::Generic::Scalar );
  7         15  
  7         106  
4603 7     7   29 use Scalar::Util ();
  7         15  
  7         544  
4604             use Want;
4605             use overload (
4606             '""' => 'as_string',
4607             '.=' => sub
4608 3     3   14 {
4609 7     7   42 my( $self, $other, $swap ) = @_;
  7         14  
  7         1151  
4610 3 50       16 no warnings 'uninitialized';
    50          
4611             if( !CORE::defined( $$self ) )
4612 0         0 {
4613             return( $other );
4614             }
4615             elsif( !CORE::defined( $other ) )
4616 0         0 {
4617             return( $$self );
4618             }
4619             ## print( STDERR ref( $self ), "::concatenate: Got here with other = '$other', and swap = '$swap'\n" );
4620 3         9 ## print( STDERR "Module::Generic::Scalar::overload->.=: Received arguments '", join( "', '", @_ ), "'\n" );
4621 3 50       7 my $expr;
4622             if( $swap )
4623 0         0 {
4624 0         0 $expr = "\$other .= \$$self";
4625             return( $other );
4626             }
4627             else
4628 3         9 {
4629 3         9 $$self .= $other;
4630             return( $self );
4631             }
4632             },
4633             'x' => sub
4634 1     1   6 {
4635 7     7   41 my( $self, $other, $swap ) = @_;
  7         11  
  7         970  
4636             no warnings 'uninitialized';
4637 1 50       8 ## print( STDERR "Module::Generic::Scalar::overload->x: Received arguments '", join( "', '", @_ ), "'\n" );
4638 1         72 my $expr = $swap ? "\"$other" x \"$$self\"" : "\"$$self\" x \"$other\"";
4639 1 50       9 my $res = eval( $expr );
4640             if( $@ )
4641 0         0 {
4642 0         0 CORE::warn( $@ );
4643             return;
4644 1         4 }
4645             return( $self->new( $res ) );
4646             },
4647             'eq' => sub
4648 4056     4056   839201 {
4649 7     7   41 my( $self, $other, $swap ) = @_;
  7         13  
  7         657  
4650 4056 100 66     12265 no warnings 'uninitialized';
4651             if( Scalar::Util::blessed( $other ) && ref( $other ) eq ref( $self ) )
4652 1         11 {
4653             return( $$self eq $$other );
4654             }
4655             else
4656 4055         12067 {
4657             return( $$self eq "$other" );
4658             }
4659 7         76 },
4660 7     7   37 fallback => 1,
  7         11  
4661 7     7   19198 );
4662             our( $VERSION ) = 'v0.2.3';
4663             };
4664              
4665             ## sub new { return( shift->_new( @_ ) ); }
4666             sub new
4667 61830     61830   85389 {
4668 61830         81152 my $this = shift( @_ );
4669 61830 100 66     213436 my $init = '';
    50 33        
    50          
    50          
4670             if( ref( $_[0] ) eq 'SCALAR' || UNIVERSAL::isa( $_[0], 'SCALAR' ) )
4671 59901         79288 {
  59901         95769  
4672             $init = ${$_[0]};
4673             }
4674             elsif( ref( $_[0] ) eq 'ARRAY' || UNIVERSAL::isa( $_[0], 'ARRAY' ) )
4675 0         0 {
  0         0  
4676             $init = CORE::join( '', @{$_[0]} );
4677             }
4678             elsif( ref( $_[0] ) )
4679 0 0       0 {
4680 0         0 warn( "I do not know what to do with \"", $_[0], "\"\n" ) if( $this->_warnings_is_enabled );
4681             return;
4682             }
4683             elsif( @_ )
4684 1929         3013 {
4685             $init = $_[0];
4686             }
4687             else
4688 0         0 {
4689             $init = undef();
4690             }
4691             ## print( STDERR __PACKAGE__, "::new: got here for value '$init' (defined? ", CORE::defined( $init ) ? 'yes' : 'no', ")\n" );
4692 61830   66     201154 # CORE::tie( $self, 'Module::Generic::Scalar::Tie', $init );
4693             return( bless( \$init => ( ref( $this ) || $this ) ) );
4694             }
4695 0     0   0  
  0         0  
  0         0  
4696             sub append { ${$_[0]} .= $_[1]; return( $_[0] ); }
4697 3 100   3   6  
  3         16  
4698             sub as_boolean { return( Module::Generic::Boolean->new( ${$_[0]} ? 1 : 0 ) ); }
4699              
4700             ## sub as_string { CORE::defined( ${$_[0]} ) ? return( ${$_[0]} ) : return; }
4701 7446     7446   11051  
  7446         24420  
4702             sub as_string { return( ${$_[0]} ); }
4703              
4704             ## Credits: John Gruber, Aristotle Pagaltzis
4705             ## https://gist.github.com/gruber/9f9e8650d68b13ce4d78
4706             sub capitalise
4707 1     1   3 {
4708 1         8 my $self = CORE::shift( @_ );
4709 1         6 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[.]? );
4710             my $small_re = CORE::join( '|', @small_words );
4711 1         6  
4712             my $apos = qr/ (?: ['’] [[:lower:]]* )? /x;
4713 1         3
4714 1         5 my $copy = $$self;
4715 1 50       5 $copy =~ s{\A\s+}{}, s{\s+\z}{};
4716 1         213 $copy = CORE::lc( $copy ) if( not /[[:lower:]]/ );
4717             $copy =~ s{
4718             \b (_*) (?:
4719             ( (?<=[ ][/\\]) [[:alpha:]]+ [-_[:alpha:]/\\]+ | # file path or
4720             [-_[:alpha:]]+ [@.:] [-_[:alpha:]@.:/]+ $apos ) # URL, domain, or email
4721             |
4722             ( (?i: $small_re ) $apos ) # or small word (case-insensitive)
4723             |
4724             ( [[:alpha:]] [[:lower:]'’()\[\]{}]* $apos ) # or word w/o internal caps
4725             |
4726             ( [[:alpha:]] [[:alpha:]'’()\[\]{}]* $apos ) # or some other word
4727             ) (_*) \b
4728 18 50       136 }{
    100          
    50          
4729             $1 . (
4730             defined $2 ? $2 # preserve URL, domain, or email
4731             : defined $3 ? "\L$3" # lowercase small word
4732             : defined $4 ? "\u\L$4" # capitalize word w/o internal caps
4733             : $5 # preserve other kinds of word
4734             ) . $6
4735             }xeg;
4736              
4737              
4738 1         122 # Exceptions for small words: capitalize at start and end of title
4739             $copy =~ s{
4740             ( \A [[:punct:]]* # start of title...
4741             | [:.;?!][ ]+ # or of subsentence...
4742             | [ ]['"“‘(\[][ ]* ) # or of inserted subphrase...
4743             ( $small_re ) \b # ... followed by small word
4744             }{$1\u\L$2}xig;
4745 1         112  
4746             $copy =~ s{
4747             \b ( $small_re ) # small word...
4748             (?= [[:punct:]]* \Z # ... at the end of the title...
4749             | ['"’”)\]] [ ] ) # ... or of an inserted subphrase?
4750             }{\u\L$1}xig;
4751              
4752             # Exceptions for small words in hyphenated compound words
4753 1         62 ## e.g. "in-flight" -> In-Flight
4754             $copy =~ s{
4755             \b
4756             (?<! -) # Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (in-flight)
4757             ( $small_re )
4758             (?= -[[:alpha:]]+) # lookahead for "-someword"
4759             }{\u\L$1}xig;
4760              
4761 1         53 ## # e.g. "Stand-in" -> "Stand-In" (Stand is already capped at this point)
4762             $copy =~ s{
4763             \b
4764             (?<!…) # Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (stand-in)
4765             ( [[:alpha:]]+- ) # $1 = first word and hyphen, should already be properly capped
4766             ( $small_re ) # ... followed by small word
4767             (?! - ) # Negative lookahead for another '-'
4768             }{$1\u$2}xig;
4769 1         6  
4770             return( $self->_new( $copy ) );
4771             }
4772 1     1   3  
  1         6  
4773             sub chomp { return( CORE::chomp( ${$_[0]} ) ); }
4774 1     1   3  
  1         50  
4775             sub chop { return( CORE::chop( ${$_[0]} ) ); }
4776              
4777             sub clone
4778 5     5   787 {
4779 5 100       20 my $self = shift( @_ );
4780             if( @_ )
4781 1         4 {
4782             return( $self->_new( @_ ) );
4783             }
4784             else
4785 4         10 {
  4         20  
4786             return( $self->_new( ${$self} ) );
4787             }
4788             }
4789 1     1   2  
  1         604  
4790             sub crypt { return( __PACKAGE__->_new( CORE::crypt( ${$_[0]}, $_[1] ) ) ); }
4791 61804     61804   74893  
  61804         144885  
4792             sub defined { return( CORE::defined( ${$_[0]} ) ); }
4793 1     1   345  
  1         8  
4794             sub fc { return( CORE::fc( ${$_[0]} ) eq CORE::fc( $_[1] ) ); }
4795 2     2   5  
  2         12  
4796             sub hex { return( $_[0]->_number( CORE::hex( ${$_[0]} ) ) ); }
4797              
4798             sub index
4799 2     2   9 {
4800 2         6 my $self = shift( @_ );
4801 2 50       9 my( $substr, $pos ) = @_;
  0         0  
4802 2         4 return( $self->_number( CORE::index( ${$self}, $substr, $pos ) ) ) if( CORE::defined( $pos ) );
  2         12  
4803             return( $self->_number( CORE::index( ${$self}, $substr ) ) );
4804             }
4805 2     2   5  
  2         22  
4806             sub is_alpha { return( ${$_[0]} =~ /^[[:alpha:]]+$/ ); }
4807 1     1   2  
  1         9  
4808             sub is_alpha_numeric { return( ${$_[0]} =~ /^[[:alnum:]]+$/ ); }
4809 1     1   4  
  1         5  
4810             sub is_empty { return( CORE::length( ${$_[0]} ) == 0 ); }
4811 1     1   3  
  1         10  
4812             sub is_lower { return( ${$_[0]} =~ /^[[:lower:]]+$/ ); }
4813 1     1   2  
  1         10  
4814             sub is_numeric { return( Scalar::Util::looks_like_number( ${$_[0]} ) ); }
4815 1     1   2  
  1         10  
4816             sub is_upper { return( ${$_[0]} =~ /^[[:upper:]]+$/ ); }
4817 1     1   2  
  1         5  
4818             sub lc { return( __PACKAGE__->_new( CORE::lc( ${$_[0]} ) ) ); }
4819 1     1   3  
  1         6  
4820             sub lcfirst { return( __PACKAGE__->_new( CORE::lcfirst( ${$_[0]} ) ) ); }
4821 1     1   3  
  1         8  
4822             sub left { return( $_[0]->_new( CORE::substr( ${$_[0]}, 0, CORE::int( $_[1] ) ) ) ); }
4823 2     2   8  
  2         10  
4824             sub length { return( $_[0]->_number( CORE::length( ${$_[0]} ) ) ); }
4825              
4826             sub like
4827 1     1   3 {
4828 1         3 my $self = shift( @_ );
4829 1 50       7 my $str = shift( @_ );
    50          
4830             $str = CORE::defined( $str )
4831             ? ref( $str ) eq 'Regexp'
4832             ? $str
4833             : qr/(?:\Q$str\E)+/
4834 1         12 : qr/[[:blank:]\r\n]*/;
4835             return( $$self =~ /$str/ );
4836             }
4837              
4838             sub ltrim
4839 1     1   4 {
4840 1         3 my $self = shift( @_ );
4841 1 0       7 my $str = shift( @_ );
    50          
4842             $str = CORE::defined( $str )
4843             ? ref( $str ) eq 'Regexp'
4844             ? $str
4845             : qr/(?:\Q$str\E)+/
4846 1         31 : qr/[[:blank:]\r\n]*/;
4847 1         8 $$self =~ s/^$str//g;
4848             return( $self );
4849             }
4850              
4851             sub match
4852 1     1   4 {
4853 1 50       8 my( $self, $re ) = @_;
    50          
4854             $re = CORE::defined( $re )
4855             ? ref( $re ) eq 'Regexp'
4856             ? $re
4857             : qr/(?:\Q$re\E)+/
4858 1         13 : $re;
4859             return( $$self =~ /$re/ );
4860             }
4861 1     1   3  
  1         5  
4862             sub ord { return( $_[0]->_number( CORE::ord( ${$_[0]} ) ) ); }
4863              
4864             sub pad
4865 2     2   5 {
4866 2         5 my $self = shift( @_ );
4867 2   50     9 my( $n, $str ) = @_;
4868 2 50       17 $str //= ' ';
    50          
4869             if( !CORE::length( $n ) )
4870 0 0       0 {
4871             warn( "No number provided to pad the string object.\n" ) if( $self->_warnings_is_enabled );
4872             }
4873             elsif( $n !~ /^\-?\d+$/ )
4874 0 0       0 {
4875             warn( "Number provided \"$n\" to pad string is not an integer.\n" ) if( $self->_warnings_is_enabled );
4876             }
4877 2 100       7
4878             if( $n < 0 )
4879 1         5 {
4880             $$self .= ( "$str" x CORE::abs( $n ) );
4881             }
4882             else
4883 1         5 {
4884             CORE::substr( $$self, 0, 0 ) = ( "$str" x $n );
4885 2         10 }
4886             return( $self );
4887             }
4888 0 0   0   0  
  0         0  
  0         0  
4889             sub pos { return( $_[0]->_number( @_ > 1 ? ( CORE::pos( ${$_[0]} ) = $_[1] ) : CORE::pos( ${$_[0]} ) ) ); }
4890 1     1   3  
  1         8  
4891             sub quotemeta { return( __PACKAGE__->_new( CORE::quotemeta( ${$_[0]} ) ) ); }
4892 0     0   0  
  0         0  
4893             sub right { return( $_[0]->_new( CORE::substr( ${$_[0]}, ( CORE::int( $_[1] ) * -1 ) ) ) ); }
4894              
4895             sub replace
4896 4     4   731 {
4897 4 100       50 my( $self, $re, $replacement ) = @_;
    50          
4898             $re = CORE::defined( $re )
4899             ? ref( $re ) eq 'Regexp'
4900             ? $re
4901             : qr/(?:\Q$re\E)+/
4902 4         55 : $re;
4903             return( $$self =~ s/$re/$replacement/gs );
4904             }
4905 1     1   3  
  1         4  
  1         6  
4906             sub reset { ${$_[0]} = ''; return( $_[0] ); }
4907 1     1   3  
  1         5  
4908             sub reverse { return( __PACKAGE__->_new( CORE::scalar( CORE::reverse( ${$_[0]} ) ) ) ); }
4909              
4910             sub rindex
4911 2     2   7 {
4912 2         6 my $self = shift( @_ );
4913 2 100       9 my( $substr, $pos ) = @_;
  1         5  
4914 1         3 return( $self->_number( CORE::rindex( ${$self}, $substr, $pos ) ) ) if( CORE::defined( $pos ) );
  1         5  
4915             return( $self->_number( CORE::rindex( ${$self}, $substr ) ) );
4916             }
4917              
4918             sub rtrim
4919 1     1   4 {
4920 1         3 my $self = shift( @_ );
4921 1 50       34 my $str = shift( @_ );
    50          
4922             $str = CORE::defined( $str )
4923             ? ref( $str ) eq 'Regexp'
4924             ? $str
4925             : qr/(?:\Q$str\E)+/
4926 1         17 : qr/[[:blank:]\r\n]*/;
4927 1         8 $$self =~ s/${str}$//g;
4928             return( $self );
4929             }
4930 950     950   2631  
4931             sub scalar { return( shift->as_string ); }
4932              
4933             sub set
4934 3815     3815   5514 {
4935 3815         4760 my $self = CORE::shift( @_ );
4936 3815 50 33     22746 my $init;
    50 33        
    50          
4937             if( ref( $_[0] ) eq 'SCALAR' || UNIVERSAL::isa( $_[0], 'SCALAR' ) )
4938 0         0 {
  0         0  
4939             $init = ${$_[0]};
4940             }
4941             elsif( ref( $_[0] ) eq 'ARRAY' || UNIVERSAL::isa( $_[0], 'ARRAY' ) )
4942 0         0 {
  0         0  
4943             $init = CORE::join( '', @{$_[0]} );
4944             }
4945             elsif( ref( $_[0] ) )
4946 0 0       0 {
4947 0         0 warn( "I do not know what to do with \"", $_[0], "\"\n" ) if( $self->_warnings_is_enabled );
4948             return;
4949             }
4950             else
4951 3815         5677 {
4952             $init = shift( @_ );
4953 3815         5510 }
4954 3815         5814 $$self = $init;
4955             return( $self );
4956             }
4957              
4958             sub split
4959 2     2   15 {
4960 2         7 my $self = CORE::shift( @_ );
4961 2 50       8 my( $expr, $limit ) = @_;
4962 2         5 CORE::warn( "No argument was provided to split string in Module::Generic::Scalar::split\n" ) if( !scalar( @_ ) );
4963 2         4 my $ref;
4964 2 50 33     13 $limit = "$limit";
4965             if( CORE::defined( $limit ) && $limit =~ /^\d+$/ )
4966 0         0 {
4967             $ref = [ CORE::split( $expr, $$self, $limit ) ];
4968             }
4969             else
4970 2         69 {
4971             $ref = [ CORE::split( $expr, $$self ) ];
4972 2 50 33     107 }
    0          
4973             if( Want::want( 'OBJECT' ) ||
4974             Want::want( 'SCALAR' ) )
4975 2         269 {
4976             rreturn( $self->_array( $ref ) );
4977             }
4978             elsif( Want::want( 'LIST' ) )
4979 0         0 {
4980             rreturn( @$ref );
4981 0         0 }
4982             return;
4983             }
4984 1     1   3  
  1         11  
4985             sub sprintf { return( __PACKAGE__->_new( CORE::sprintf( ${$_[0]}, @_[1..$#_] ) ) ); }
4986              
4987             sub substr
4988 2     2   6 {
4989 2         6 my $self = CORE::shift( @_ );
4990 2 100 66     13 my( $offset, $length, $replacement ) = @_;
  1         7  
4991 1 50       4 return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset, $length, $replacement ) ) ) if( CORE::defined( $length ) && CORE::defined( $replacement ) );
  1         5  
4992 0         0 return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset, $length ) ) ) if( CORE::defined( $length ) );
  0         0  
4993             return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset ) ) );
4994             }
4995              
4996             ## The 3 dash here are just so my editor does not get confused with colouring
4997             sub tr ###
4998 1     1   7 {
4999 1         3 my $self = CORE::shift( @_ );
5000 1         73 my( $search, $replace, $opts ) = @_;
5001 1         8 eval( "\$\$self =~ CORE::tr/$search/$replace/$opts" );
5002             return( $self );
5003             }
5004              
5005             sub trim
5006 2     2   6 {
5007 2         5 my $self = shift( @_ );
5008 2 50       14 my $str = shift( @_ );
5009 2         80 $str = CORE::defined( $str ) ? CORE::quotemeta( $str ) : qr/[[:blank:]\r\n]*/;
5010 2         12 $$self =~ s/^$str|$str$//gs;
5011             return( $self );
5012             }
5013 2     2   4  
  2         11  
5014             sub uc { return( __PACKAGE__->_new( CORE::uc( ${$_[0]} ) ) ); }
5015 0     0   0  
  0         0  
5016             sub ucfirst { return( __PACKAGE__->_new( CORE::ucfirst( ${$_[0]} ) ) ); }
5017              
5018             sub undef
5019 1     1   3 {
5020 1         4 my $self = shift( @_ );
5021 1         3 $$self = undef;
5022             return( $self );
5023             }
5024              
5025             sub _array
5026 2     2   6 {
5027 2         5 my $self = shift( @_ );
5028 2 50       7 my $arr = shift( @_ );
5029 2 50       14 return if( !defined( $arr ) );
5030 2         71 return( $arr ) if( Scalar::Util::reftype( $arr ) ne 'ARRAY' );
5031             return( Module::Generic::Array->new( $arr ) );
5032             }
5033              
5034             sub _number
5035 9     9   25 {
5036 9         19 my $self = shift( @_ );
5037 9 50       32 my $num = shift( @_ );
5038 9 50       36 return if( !defined( $num ) );
5039 9         47 return( $num ) if( !CORE::length( $num ) );
5040             return( Module::Generic::Number->new( $num ) );
5041             }
5042 17     17   64  
5043             sub _new { return( shift->Module::Generic::Scalar::new( @_ ) ); }
5044 0   0 0   0  
5045             sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); }
5046              
5047              
5048             package Module::Generic::Number;
5049             BEGIN
5050 7     7   60 {
  7         15  
  7         223  
5051 7     7   36 use strict;
  7         13  
  7         33  
5052 7     7   320 use parent -norequire, qw( Module::Generic );
  7         15  
  7         623  
5053 7     7   40 use warnings::register;
  7         13  
  7         278  
5054 7     7   41 use Number::Format;
  7         12  
  7         59  
5055 7     7   26708180 use Nice::Try;
  7         16255  
  7         32  
5056 7     7   18851 use Regexp::Common qw( number );
  7         22  
  7         205  
5057 7     7   5470 use POSIX ();
5058             our( $VERSION ) = 'v0.4.0';
5059             };
5060              
5061             use overload (
5062             ## I know there is the nomethod feature, but I need to provide return_object set to true or false
5063 59     59   12166 ## And I do not necessarily want to catch all the operation.
5064 9     9   233 '""' => sub { return( shift->{_number} ); },
5065 5     5   51 '-' => sub { return( shift->compute( @_, { op => '-', return_object => 1 }) ); },
5066 3     3   49 '+' => sub { return( shift->compute( @_, { op => '+', return_object => 1 }) ); },
5067 4     4   59 '*' => sub { return( shift->compute( @_, { op => '*', return_object => 1 }) ); },
5068 2     2   28 '/' => sub { return( shift->compute( @_, { op => '/', return_object => 1 }) ); },
5069             '%' => sub { return( shift->compute( @_, { op => '%', return_object => 1 }) ); },
5070 3     3   38 ## Exponent
5071             '**' => sub { return( shift->compute( @_, { op => '**', return_object => 1 }) ); },
5072 1     1   21 ## Bitwise AND
5073             '&' => sub { return( shift->compute( @_, { op => '&', return_object => 1 }) ); },
5074 1     1   8 ## Bitwise OR
5075             '|' => sub { return( shift->compute( @_, { op => '|', return_object => 1 }) ); },
5076 1     1   13 ## Bitwise XOR
5077             '^' => sub { return( shift->compute( @_, { op => '^', return_object => 1 }) ); },
5078 1     1   13 ## Bitwise shift left
5079             '<<' => sub { return( shift->compute( @_, { op => '<<', return_object => 1 }) ); },
5080 1     1   32 ## Bitwise shift right
5081 1     1   28 '>>' => sub { return( shift->compute( @_, { op => '>>', return_object => 1 }) ); },
5082 2     2   20 'x' => sub { return( shift->compute( @_, { op => 'x', return_object => 1, type => 'scalar' }) ); },
5083 1     1   18 '+=' => sub { return( shift->compute( @_, { op => '+=', return_object => 1 }) ); },
5084 2     2   987 '-=' => sub { return( shift->compute( @_, { op => '-=', return_object => 1 }) ); },
5085 1     1   8 '*=' => sub { return( shift->compute( @_, { op => '*=', return_object => 1 }) ); },
5086 1     1   27 '/=' => sub { return( shift->compute( @_, { op => '/=', return_object => 1 }) ); },
5087 1     1   23 '%=' => sub { return( shift->compute( @_, { op => '%=', return_object => 1 }) ); },
5088 1     1   16 '**=' => sub { return( shift->compute( @_, { op => '**=', return_object => 1 }) ); },
5089 1     1   44 '<<=' => sub { return( shift->compute( @_, { op => '<<=', return_object => 1 }) ); },
5090 1     1   6 '>>=' => sub { return( shift->compute( @_, { op => '>>=', return_object => 1 }) ); },
5091             'x=' => sub { return( shift->compute( @_, { op => 'x=', return_object => 1 }) ); },
5092             ## '.=' => sub { return( shift->compute( @_, { op => '.=', return_object => 1 }) ); },
5093             '.=' => sub
5094 2     2   24 {
5095 2         9 my( $self, $other, $swap ) = @_;
5096 2 50       15 my $op = '.=';
5097 2         117 my $operation = $swap ? "${other} ${op} \$self->{_number}" : "\$self->{_number} ${op} ${other}";
5098 2 50 33     30 my $res = eval( $operation );
5099 2 50       8 warn( "Error with formula \"$operation\": $@" ) if( $@ && $self->_warnings_is_enabled );
5100             return if( $@ );
5101 2 100       21 ## Concatenated something. If it still look like a number, we return it as an object
5102             if( $res =~ /^$RE{num}{real}$/ )
5103 1         274 {
5104             return( $self->clone( $res ) );
5105             }
5106             ## Otherwise we pass it to the scalar module
5107             else
5108 1         201 {
5109             return( Module::Generic::Scalar->new( "$res" ) );
5110             }
5111 6     6   60 },
5112 2     2   24 '<' => sub { return( shift->compute( @_, { op => '<', boolean => 1 }) ); },
5113 4     4   37 '<=' => sub { return( shift->compute( @_, { op => '<=', boolean => 1 }) ); },
5114 2     2   39 '>' => sub { return( shift->compute( @_, { op => '>', boolean => 1 }) ); },
5115 3     3   22 '>=' => sub { return( shift->compute( @_, { op => '>=', boolean => 1 }) ); },
5116 6     6   62 '<=>' => sub { return( shift->compute( @_, { op => '<=>', return_object => 0 }) ); },
5117 7     7   51 '==' => sub { return( shift->compute( @_, { op => '==', boolean => 1 }) ); },
5118 82     82   32327 '!=' => sub { return( shift->compute( @_, { op => '!=', boolean => 1 }) ); },
5119 1     1   14 'eq' => sub { return( shift->compute( @_, { op => 'eq', boolean => 1 }) ); },
5120             'ne' => sub { return( shift->compute( @_, { op => 'ne', boolean => 1 }) ); },
5121             '++' => sub
5122 3     3   19 {
5123 3         18 my( $self ) = @_;
5124             return( ++$self->{_number} );
5125             },
5126             '--' => sub
5127 2     2   5 {
5128 2         10 my( $self ) = @_;
5129             return( --$self->{_number} );
5130 7         275 },
5131 7     7   59 'fallback' => 1,
  7         19  
5132             );
5133              
5134             our $SUPPORTED_LOCALES =
5135             {
5136             aa_DJ => [qw( aa_DJ.UTF-8 aa_DJ.ISO-8859-1 aa_DJ.ISO8859-1 )],
5137             aa_ER => [qw( aa_ER.UTF-8 )],
5138             aa_ET => [qw( aa_ET.UTF-8 )],
5139             af_ZA => [qw( af_ZA.UTF-8 af_ZA.ISO-8859-1 af_ZA.ISO8859-1 )],
5140             ak_GH => [qw( ak_GH.UTF-8 )],
5141             am_ET => [qw( am_ET.UTF-8 )],
5142             an_ES => [qw( an_ES.UTF-8 an_ES.ISO-8859-15 an_ES.ISO8859-15 )],
5143             anp_IN => [qw( anp_IN.UTF-8 )],
5144             ar_AE => [qw( ar_AE.UTF-8 ar_AE.ISO-8859-6 ar_AE.ISO8859-6 )],
5145             ar_BH => [qw( ar_BH.UTF-8 ar_BH.ISO-8859-6 ar_BH.ISO8859-6 )],
5146             ar_DZ => [qw( ar_DZ.UTF-8 ar_DZ.ISO-8859-6 ar_DZ.ISO8859-6 )],
5147             ar_EG => [qw( ar_EG.UTF-8 ar_EG.ISO-8859-6 ar_EG.ISO8859-6 )],
5148             ar_IN => [qw( ar_IN.UTF-8 )],
5149             ar_IQ => [qw( ar_IQ.UTF-8 ar_IQ.ISO-8859-6 ar_IQ.ISO8859-6 )],
5150             ar_JO => [qw( ar_JO.UTF-8 ar_JO.ISO-8859-6 ar_JO.ISO8859-6 )],
5151             ar_KW => [qw( ar_KW.UTF-8 ar_KW.ISO-8859-6 ar_KW.ISO8859-6 )],
5152             ar_LB => [qw( ar_LB.UTF-8 ar_LB.ISO-8859-6 ar_LB.ISO8859-6 )],
5153             ar_LY => [qw( ar_LY.UTF-8 ar_LY.ISO-8859-6 ar_LY.ISO8859-6 )],
5154             ar_MA => [qw( ar_MA.UTF-8 ar_MA.ISO-8859-6 ar_MA.ISO8859-6 )],
5155             ar_OM => [qw( ar_OM.UTF-8 ar_OM.ISO-8859-6 ar_OM.ISO8859-6 )],
5156             ar_QA => [qw( ar_QA.UTF-8 ar_QA.ISO-8859-6 ar_QA.ISO8859-6 )],
5157             ar_SA => [qw( ar_SA.UTF-8 ar_SA.ISO-8859-6 ar_SA.ISO8859-6 )],
5158             ar_SD => [qw( ar_SD.UTF-8 ar_SD.ISO-8859-6 ar_SD.ISO8859-6 )],
5159             ar_SS => [qw( ar_SS.UTF-8 )],
5160             ar_SY => [qw( ar_SY.UTF-8 ar_SY.ISO-8859-6 ar_SY.ISO8859-6 )],
5161             ar_TN => [qw( ar_TN.UTF-8 ar_TN.ISO-8859-6 ar_TN.ISO8859-6 )],
5162             ar_YE => [qw( ar_YE.UTF-8 ar_YE.ISO-8859-6 ar_YE.ISO8859-6 )],
5163             as_IN => [qw( as_IN.UTF-8 )],
5164             ast_ES => [qw( ast_ES.UTF-8 ast_ES.ISO-8859-15 ast_ES.ISO8859-15 )],
5165             ayc_PE => [qw( ayc_PE.UTF-8 )],
5166             az_AZ => [qw( az_AZ.UTF-8 )],
5167             be_BY => [qw( be_BY.UTF-8 be_BY.CP1251 )],
5168             bem_ZM => [qw( bem_ZM.UTF-8 )],
5169             ber_DZ => [qw( ber_DZ.UTF-8 )],
5170             ber_MA => [qw( ber_MA.UTF-8 )],
5171             bg_BG => [qw( bg_BG.UTF-8 bg_BG.CP1251 )],
5172             bhb_IN => [qw( bhb_IN.UTF-8 )],
5173             bho_IN => [qw( bho_IN.UTF-8 )],
5174             bn_BD => [qw( bn_BD.UTF-8 )],
5175             bn_IN => [qw( bn_IN.UTF-8 )],
5176             bo_CN => [qw( bo_CN.UTF-8 )],
5177             bo_IN => [qw( bo_IN.UTF-8 )],
5178             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 )],
5179             brx_IN => [qw( brx_IN.UTF-8 )],
5180             bs_BA => [qw( bs_BA.UTF-8 bs_BA.ISO-8859-2 bs_BA.ISO8859-2 )],
5181             byn_ER => [qw( byn_ER.UTF-8 )],
5182             ca_AD => [qw( ca_AD.UTF-8 ca_AD.ISO-8859-15 ca_AD.ISO8859-15 )],
5183             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 )],
5184             ca_FR => [qw( ca_FR.UTF-8 ca_FR.ISO-8859-15 ca_FR.ISO8859-15 )],
5185             ca_IT => [qw( ca_IT.UTF-8 ca_IT.ISO-8859-15 ca_IT.ISO8859-15 )],
5186             ce_RU => [qw( ce_RU.UTF-8 )],
5187             ckb_IQ => [qw( ckb_IQ.UTF-8 )],
5188             cmn_TW => [qw( cmn_TW.UTF-8 )],
5189             crh_UA => [qw( crh_UA.UTF-8 )],
5190             cs_CZ => [qw( cs_CZ.UTF-8 cs_CZ.ISO-8859-2 cs_CZ.ISO8859-2 )],
5191             csb_PL => [qw( csb_PL.UTF-8 )],
5192             cv_RU => [qw( cv_RU.UTF-8 )],
5193             cy_GB => [qw( cy_GB.UTF-8 cy_GB.ISO-8859-14 cy_GB.ISO8859-14 )],
5194             da_DK => [qw( da_DK.UTF-8 da_DK.ISO-8859-1 da_DK.ISO8859-1 )],
5195             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 )],
5196             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 )],
5197             de_CH => [qw( de_CH.UTF-8 de_CH.ISO-8859-1 de_CH.ISO8859-1 )],
5198             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 )],
5199             de_LI => [qw( de_LI.UTF-8 )],
5200             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 )],
5201             doi_IN => [qw( doi_IN.UTF-8 )],
5202             dv_MV => [qw( dv_MV.UTF-8 )],
5203             dz_BT => [qw( dz_BT.UTF-8 )],
5204             el_CY => [qw( el_CY.UTF-8 el_CY.ISO-8859-7 el_CY.ISO8859-7 )],
5205             el_GR => [qw( el_GR.UTF-8 el_GR.ISO-8859-7 el_GR.ISO8859-7 )],
5206             en_AG => [qw( en_AG.UTF-8 )],
5207             en_AU => [qw( en_AU.UTF-8 en_AU.ISO-8859-1 en_AU.ISO8859-1 )],
5208             en_BW => [qw( en_BW.UTF-8 en_BW.ISO-8859-1 en_BW.ISO8859-1 )],
5209             en_CA => [qw( en_CA.UTF-8 en_CA.ISO-8859-1 en_CA.ISO8859-1 )],
5210             en_DK => [qw( en_DK.UTF-8 en_DK.ISO-8859-15 en_DK.ISO8859-15 )],
5211             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 )],
5212             en_HK => [qw( en_HK.UTF-8 en_HK.ISO-8859-1 en_HK.ISO8859-1 )],
5213             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 )],
5214             en_IN => [qw( en_IN.UTF-8 )],
5215             en_NG => [qw( en_NG.UTF-8 )],
5216             en_NZ => [qw( en_NZ.UTF-8 en_NZ.ISO-8859-1 en_NZ.ISO8859-1 )],
5217             en_PH => [qw( en_PH.UTF-8 en_PH.ISO-8859-1 en_PH.ISO8859-1 )],
5218             en_SG => [qw( en_SG.UTF-8 en_SG.ISO-8859-1 en_SG.ISO8859-1 )],
5219             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 )],
5220             en_ZA => [qw( en_ZA.UTF-8 en_ZA.ISO-8859-1 en_ZA.ISO8859-1 )],
5221             en_ZM => [qw( en_ZM.UTF-8 )],
5222             en_ZW => [qw( en_ZW.UTF-8 en_ZW.ISO-8859-1 en_ZW.ISO8859-1 )],
5223             eo => [qw( eo.UTF-8 eo.ISO-8859-3 eo.ISO8859-3 )],
5224             eo_US => [qw( eo_US.UTF-8 )],
5225             es_AR => [qw( es_AR.UTF-8 es_AR.ISO-8859-1 es_AR.ISO8859-1 )],
5226             es_BO => [qw( es_BO.UTF-8 es_BO.ISO-8859-1 es_BO.ISO8859-1 )],
5227             es_CL => [qw( es_CL.UTF-8 es_CL.ISO-8859-1 es_CL.ISO8859-1 )],
5228             es_CO => [qw( es_CO.UTF-8 es_CO.ISO-8859-1 es_CO.ISO8859-1 )],
5229             es_CR => [qw( es_CR.UTF-8 es_CR.ISO-8859-1 es_CR.ISO8859-1 )],
5230             es_CU => [qw( es_CU.UTF-8 )],
5231             es_DO => [qw( es_DO.UTF-8 es_DO.ISO-8859-1 es_DO.ISO8859-1 )],
5232             es_EC => [qw( es_EC.UTF-8 es_EC.ISO-8859-1 es_EC.ISO8859-1 )],
5233             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 )],
5234             es_GT => [qw( es_GT.UTF-8 es_GT.ISO-8859-1 es_GT.ISO8859-1 )],
5235             es_HN => [qw( es_HN.UTF-8 es_HN.ISO-8859-1 es_HN.ISO8859-1 )],
5236             es_MX => [qw( es_MX.UTF-8 es_MX.ISO-8859-1 es_MX.ISO8859-1 )],
5237             es_NI => [qw( es_NI.UTF-8 es_NI.ISO-8859-1 es_NI.ISO8859-1 )],
5238             es_PA => [qw( es_PA.UTF-8 es_PA.ISO-8859-1 es_PA.ISO8859-1 )],
5239             es_PE => [qw( es_PE.UTF-8 es_PE.ISO-8859-1 es_PE.ISO8859-1 )],
5240             es_PR => [qw( es_PR.UTF-8 es_PR.ISO-8859-1 es_PR.ISO8859-1 )],
5241             es_PY => [qw( es_PY.UTF-8 es_PY.ISO-8859-1 es_PY.ISO8859-1 )],
5242             es_SV => [qw( es_SV.UTF-8 es_SV.ISO-8859-1 es_SV.ISO8859-1 )],
5243             es_US => [qw( es_US.UTF-8 es_US.ISO-8859-1 es_US.ISO8859-1 )],
5244             es_UY => [qw( es_UY.UTF-8 es_UY.ISO-8859-1 es_UY.ISO8859-1 )],
5245             es_VE => [qw( es_VE.UTF-8 es_VE.ISO-8859-1 es_VE.ISO8859-1 )],
5246             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 )],
5247             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 )],
5248             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 )],
5249             fa_IR => [qw( fa_IR.UTF-8 )],
5250             ff_SN => [qw( ff_SN.UTF-8 )],
5251             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 )],
5252             fil_PH => [qw( fil_PH.UTF-8 )],
5253             fo_FO => [qw( fo_FO.UTF-8 fo_FO.ISO-8859-1 fo_FO.ISO8859-1 )],
5254             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 )],
5255             fr_CA => [qw( fr_CA.UTF-8 fr_CA.ISO-8859-1 fr_CA.ISO8859-1 )],
5256             fr_CH => [qw( fr_CH.UTF-8 fr_CH.ISO-8859-1 fr_CH.ISO8859-1 )],
5257             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 )],
5258             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 )],
5259             fur_IT => [qw( fur_IT.UTF-8 )],
5260             fy_DE => [qw( fy_DE.UTF-8 )],
5261             fy_NL => [qw( fy_NL.UTF-8 )],
5262             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 )],
5263             gd_GB => [qw( gd_GB.UTF-8 gd_GB.ISO-8859-15 gd_GB.ISO8859-15 )],
5264             gez_ER => [qw( gez_ER.UTF-8 )],
5265             gez_ET => [qw( gez_ET.UTF-8 )],
5266             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 )],
5267             gu_IN => [qw( gu_IN.UTF-8 )],
5268             gv_GB => [qw( gv_GB.UTF-8 gv_GB.ISO-8859-1 gv_GB.ISO8859-1 )],
5269             ha_NG => [qw( ha_NG.UTF-8 )],
5270             hak_TW => [qw( hak_TW.UTF-8 )],
5271             he_IL => [qw( he_IL.UTF-8 he_IL.ISO-8859-8 he_IL.ISO8859-8 )],
5272             hi_IN => [qw( hi_IN.UTF-8 )],
5273             hne_IN => [qw( hne_IN.UTF-8 )],
5274             hr_HR => [qw( hr_HR.UTF-8 hr_HR.ISO-8859-2 hr_HR.ISO8859-2 )],
5275             hsb_DE => [qw( hsb_DE.UTF-8 hsb_DE.ISO-8859-2 hsb_DE.ISO8859-2 )],
5276             ht_HT => [qw( ht_HT.UTF-8 )],
5277             hu_HU => [qw( hu_HU.UTF-8 hu_HU.ISO-8859-2 hu_HU.ISO8859-2 )],
5278             hy_AM => [qw( hy_AM.UTF-8 hy_AM.ARMSCII-8 hy_AM.ARMSCII8 )],
5279             ia_FR => [qw( ia_FR.UTF-8 )],
5280             id_ID => [qw( id_ID.UTF-8 id_ID.ISO-8859-1 id_ID.ISO8859-1 )],
5281             ig_NG => [qw( ig_NG.UTF-8 )],
5282             ik_CA => [qw( ik_CA.UTF-8 )],
5283             is_IS => [qw( is_IS.UTF-8 is_IS.ISO-8859-1 is_IS.ISO8859-1 )],
5284             it_CH => [qw( it_CH.UTF-8 it_CH.ISO-8859-1 it_CH.ISO8859-1 )],
5285             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 )],
5286             iu_CA => [qw( iu_CA.UTF-8 )],
5287             iw_IL => [qw( iw_IL.UTF-8 iw_IL.ISO-8859-8 iw_IL.ISO8859-8 )],
5288             ja_JP => [qw( ja_JP.UTF-8 ja_JP.EUC-JP ja_JP.EUCJP )],
5289             ka_GE => [qw( ka_GE.UTF-8 ka_GE.GEORGIAN-PS ka_GE.GEORGIANPS )],
5290             kk_KZ => [qw( kk_KZ.UTF-8 kk_KZ.PT154 kk_KZ.RK1048 )],
5291             kl_GL => [qw( kl_GL.UTF-8 kl_GL.ISO-8859-1 kl_GL.ISO8859-1 )],
5292             km_KH => [qw( km_KH.UTF-8 )],
5293             kn_IN => [qw( kn_IN.UTF-8 )],
5294             ko_KR => [qw( ko_KR.UTF-8 ko_KR.EUC-KR ko_KR.EUCKR )],
5295             kok_IN => [qw( kok_IN.UTF-8 )],
5296             ks_IN => [qw( ks_IN.UTF-8 )],
5297             ku_TR => [qw( ku_TR.UTF-8 ku_TR.ISO-8859-9 ku_TR.ISO8859-9 )],
5298             kw_GB => [qw( kw_GB.UTF-8 kw_GB.ISO-8859-1 kw_GB.ISO8859-1 )],
5299             ky_KG => [qw( ky_KG.UTF-8 )],
5300             lb_LU => [qw( lb_LU.UTF-8 )],
5301             lg_UG => [qw( lg_UG.UTF-8 lg_UG.ISO-8859-10 lg_UG.ISO8859-10 )],
5302             li_BE => [qw( li_BE.UTF-8 )],
5303             li_NL => [qw( li_NL.UTF-8 )],
5304             lij_IT => [qw( lij_IT.UTF-8 )],
5305             ln_CD => [qw( ln_CD.UTF-8 )],
5306             lo_LA => [qw( lo_LA.UTF-8 )],
5307             lt_LT => [qw( lt_LT.UTF-8 lt_LT.ISO-8859-13 lt_LT.ISO8859-13 )],
5308             lv_LV => [qw( lv_LV.UTF-8 lv_LV.ISO-8859-13 lv_LV.ISO8859-13 )],
5309             lzh_TW => [qw( lzh_TW.UTF-8 )],
5310             mag_IN => [qw( mag_IN.UTF-8 )],
5311             mai_IN => [qw( mai_IN.UTF-8 )],
5312             mg_MG => [qw( mg_MG.UTF-8 mg_MG.ISO-8859-15 mg_MG.ISO8859-15 )],
5313             mhr_RU => [qw( mhr_RU.UTF-8 )],
5314             mi_NZ => [qw( mi_NZ.UTF-8 mi_NZ.ISO-8859-13 mi_NZ.ISO8859-13 )],
5315             mk_MK => [qw( mk_MK.UTF-8 mk_MK.ISO-8859-5 mk_MK.ISO8859-5 )],
5316             ml_IN => [qw( ml_IN.UTF-8 )],
5317             mn_MN => [qw( mn_MN.UTF-8 )],
5318             mni_IN => [qw( mni_IN.UTF-8 )],
5319             mr_IN => [qw( mr_IN.UTF-8 )],
5320             ms_MY => [qw( ms_MY.UTF-8 ms_MY.ISO-8859-1 ms_MY.ISO8859-1 )],
5321             mt_MT => [qw( mt_MT.UTF-8 mt_MT.ISO-8859-3 mt_MT.ISO8859-3 )],
5322             my_MM => [qw( my_MM.UTF-8 )],
5323             nan_TW => [qw( nan_TW.UTF-8 )],
5324             nb_NO => [qw( nb_NO.UTF-8 nb_NO.ISO-8859-1 nb_NO.ISO8859-1 )],
5325             nds_DE => [qw( nds_DE.UTF-8 )],
5326             nds_NL => [qw( nds_NL.UTF-8 )],
5327             ne_NP => [qw( ne_NP.UTF-8 )],
5328             nhn_MX => [qw( nhn_MX.UTF-8 )],
5329             niu_NU => [qw( niu_NU.UTF-8 )],
5330             niu_NZ => [qw( niu_NZ.UTF-8 )],
5331             nl_AW => [qw( nl_AW.UTF-8 )],
5332             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 )],
5333             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 )],
5334             nn_NO => [qw( nn_NO.UTF-8 nn_NO.ISO-8859-1 nn_NO.ISO8859-1 )],
5335             nr_ZA => [qw( nr_ZA.UTF-8 )],
5336             nso_ZA => [qw( nso_ZA.UTF-8 )],
5337             oc_FR => [qw( oc_FR.UTF-8 oc_FR.ISO-8859-1 oc_FR.ISO8859-1 )],
5338             om_ET => [qw( om_ET.UTF-8 )],
5339             om_KE => [qw( om_KE.UTF-8 om_KE.ISO-8859-1 om_KE.ISO8859-1 )],
5340             or_IN => [qw( or_IN.UTF-8 )],
5341             os_RU => [qw( os_RU.UTF-8 )],
5342             pa_IN => [qw( pa_IN.UTF-8 )],
5343             pa_PK => [qw( pa_PK.UTF-8 )],
5344             pap_AN => [qw( pap_AN.UTF-8 )],
5345             pap_AW => [qw( pap_AW.UTF-8 )],
5346             pap_CW => [qw( pap_CW.UTF-8 )],
5347             pl_PL => [qw( pl_PL.UTF-8 pl_PL.ISO-8859-2 pl_PL.ISO8859-2 )],
5348             ps_AF => [qw( ps_AF.UTF-8 )],
5349             pt_BR => [qw( pt_BR.UTF-8 pt_BR.ISO-8859-1 pt_BR.ISO8859-1 )],
5350             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 )],
5351             quz_PE => [qw( quz_PE.UTF-8 )],
5352             raj_IN => [qw( raj_IN.UTF-8 )],
5353             ro_RO => [qw( ro_RO.UTF-8 ro_RO.ISO-8859-2 ro_RO.ISO8859-2 )],
5354             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 )],
5355             ru_UA => [qw( ru_UA.UTF-8 ru_UA.KOI8-U ru_UA.KOI8U )],
5356             rw_RW => [qw( rw_RW.UTF-8 )],
5357             sa_IN => [qw( sa_IN.UTF-8 )],
5358             sat_IN => [qw( sat_IN.UTF-8 )],
5359             sc_IT => [qw( sc_IT.UTF-8 )],
5360             sd_IN => [qw( sd_IN.UTF-8 )],
5361             sd_PK => [qw( sd_PK.UTF-8 )],
5362             se_NO => [qw( se_NO.UTF-8 )],
5363             shs_CA => [qw( shs_CA.UTF-8 )],
5364             si_LK => [qw( si_LK.UTF-8 )],
5365             sid_ET => [qw( sid_ET.UTF-8 )],
5366             sk_SK => [qw( sk_SK.UTF-8 sk_SK.ISO-8859-2 sk_SK.ISO8859-2 )],
5367             sl_SI => [qw( sl_SI.UTF-8 sl_SI.ISO-8859-2 sl_SI.ISO8859-2 )],
5368             so_DJ => [qw( so_DJ.UTF-8 so_DJ.ISO-8859-1 so_DJ.ISO8859-1 )],
5369             so_ET => [qw( so_ET.UTF-8 )],
5370             so_KE => [qw( so_KE.UTF-8 so_KE.ISO-8859-1 so_KE.ISO8859-1 )],
5371             so_SO => [qw( so_SO.UTF-8 so_SO.ISO-8859-1 so_SO.ISO8859-1 )],
5372             sq_AL => [qw( sq_AL.UTF-8 sq_AL.ISO-8859-1 sq_AL.ISO8859-1 )],
5373             sq_MK => [qw( sq_MK.UTF-8 )],
5374             sr_ME => [qw( sr_ME.UTF-8 )],
5375             sr_RS => [qw( sr_RS.UTF-8 )],
5376             ss_ZA => [qw( ss_ZA.UTF-8 )],
5377             st_ZA => [qw( st_ZA.UTF-8 st_ZA.ISO-8859-1 st_ZA.ISO8859-1 )],
5378             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 )],
5379             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 )],
5380             sw_KE => [qw( sw_KE.UTF-8 )],
5381             sw_TZ => [qw( sw_TZ.UTF-8 )],
5382             szl_PL => [qw( szl_PL.UTF-8 )],
5383             ta_IN => [qw( ta_IN.UTF-8 )],
5384             ta_LK => [qw( ta_LK.UTF-8 )],
5385             tcy_IN => [qw( tcy_IN.UTF-8 )],
5386             te_IN => [qw( te_IN.UTF-8 )],
5387             tg_TJ => [qw( tg_TJ.UTF-8 tg_TJ.KOI8-T tg_TJ.KOI8T )],
5388             th_TH => [qw( th_TH.UTF-8 th_TH.TIS-620 th_TH.TIS620 )],
5389             the_NP => [qw( the_NP.UTF-8 )],
5390             ti_ER => [qw( ti_ER.UTF-8 )],
5391             ti_ET => [qw( ti_ET.UTF-8 )],
5392             tig_ER => [qw( tig_ER.UTF-8 )],
5393             tk_TM => [qw( tk_TM.UTF-8 )],
5394             tl_PH => [qw( tl_PH.UTF-8 tl_PH.ISO-8859-1 tl_PH.ISO8859-1 )],
5395             tn_ZA => [qw( tn_ZA.UTF-8 )],
5396             tr_CY => [qw( tr_CY.UTF-8 tr_CY.ISO-8859-9 tr_CY.ISO8859-9 )],
5397             tr_TR => [qw( tr_TR.UTF-8 tr_TR.ISO-8859-9 tr_TR.ISO8859-9 )],
5398             ts_ZA => [qw( ts_ZA.UTF-8 )],
5399             tt_RU => [qw( tt_RU.UTF-8 )],
5400             ug_CN => [qw( ug_CN.UTF-8 )],
5401             uk_UA => [qw( uk_UA.UTF-8 uk_UA.KOI8-U uk_UA.KOI8U )],
5402             unm_US => [qw( unm_US.UTF-8 )],
5403             ur_IN => [qw( ur_IN.UTF-8 )],
5404             ur_PK => [qw( ur_PK.UTF-8 )],
5405             uz_UZ => [qw( uz_UZ.UTF-8 uz_UZ.ISO-8859-1 uz_UZ.ISO8859-1 )],
5406             ve_ZA => [qw( ve_ZA.UTF-8 )],
5407             vi_VN => [qw( vi_VN.UTF-8 )],
5408             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 )],
5409             wae_CH => [qw( wae_CH.UTF-8 )],
5410             wal_ET => [qw( wal_ET.UTF-8 )],
5411             wo_SN => [qw( wo_SN.UTF-8 )],
5412             xh_ZA => [qw( xh_ZA.UTF-8 xh_ZA.ISO-8859-1 xh_ZA.ISO8859-1 )],
5413             yi_US => [qw( yi_US.UTF-8 yi_US.CP1255 )],
5414             yo_NG => [qw( yo_NG.UTF-8 )],
5415             yue_HK => [qw( yue_HK.UTF-8 )],
5416             zh_CN => [qw( zh_CN.UTF-8 zh_CN.GB18030 zh_CN.GBK zh_CN.GB2312 )],
5417             zh_HK => [qw( zh_HK.UTF-8 zh_HK.BIG5-HKSCS zh_HK.BIG5HKSCS )],
5418             zh_SG => [qw( zh_SG.UTF-8 zh_SG.GBK zh_SG.GB2312 )],
5419             zh_TW => [qw( zh_TW.UTF-8 zh_TW.EUC-TW zh_TW.EUCTW zh_TW.BIG5 )],
5420             zu_ZA => [qw( zu_ZA.UTF-8 zu_ZA.ISO-8859-1 zu_ZA.ISO8859-1 )],
5421             };
5422              
5423             our $DEFAULT =
5424             {
5425             ## The local currency symbol.
5426             currency_symbol => '€',
5427             ## The decimal point character, except for currency values, cannot be an empty string
5428             decimal_point => '.',
5429             ## The number of digits after the decimal point in the local style for currency values.
5430             frac_digits => 2,
5431             ## The sizes of the groups of digits, except for currency values. unpack( "C*", $grouping ) will give the number
5432             grouping => (CORE::chr(3) x 2),
5433             ## The standardized international currency symbol.
5434             int_curr_symbol => '€',
5435             ## The number of digits after the decimal point in an international-style currency value.
5436             int_frac_digits => 2,
5437             ## Same as n_cs_precedes, but for internationally formatted monetary quantities.
5438             int_n_cs_precedes => '',
5439             ## Same as n_sep_by_space, but for internationally formatted monetary quantities.
5440             int_n_sep_by_space => '',
5441             ## Same as n_sign_posn, but for internationally formatted monetary quantities.
5442             int_n_sign_posn => 1,
5443             ## Same as p_cs_precedes, but for internationally formatted monetary quantities.
5444             int_p_cs_precedes => 1,
5445             ## Same as p_sep_by_space, but for internationally formatted monetary quantities.
5446             int_p_sep_by_space => 0,
5447             ## Same as p_sign_posn, but for internationally formatted monetary quantities.
5448             int_p_sign_posn => 1,
5449             ## The decimal point character for currency values.
5450             mon_decimal_point => '.',
5451             ## Like grouping but for currency values.
5452             mon_grouping => (CORE::chr(3) x 2),
5453             ## The separator for digit groups in currency values.
5454             mon_thousands_sep => ',',
5455             ## Like p_cs_precedes but for negative values.
5456             n_cs_precedes => 1,
5457             ## Like p_sep_by_space but for negative values.
5458             n_sep_by_space => 0,
5459             ## Like p_sign_posn but for negative currency values.
5460             n_sign_posn => 1,
5461             ## The character used to denote negative currency values, usually a minus sign.
5462             negative_sign => '-',
5463             ## 1 if the currency symbol precedes the currency value for nonnegative values, 0 if it follows.
5464             p_cs_precedes => 1,
5465             ## 1 if a space is inserted between the currency symbol and the currency value for nonnegative values, 0 otherwise.
5466             p_sep_by_space => 0,
5467             ## The location of the positive_sign with respect to a nonnegative quantity and the currency_symbol, coded as follows:
5468             ## 0 Parentheses around the entire string.
5469             ## 1 Before the string.
5470             ## 2 After the string.
5471             ## 3 Just before currency_symbol.
5472             ## 4 Just after currency_symbol.
5473             p_sign_posn => 1,
5474             ## The character used to denote nonnegative currency values, usually the empty string.
5475             positive_sign => '',
5476             ## The separator between groups of digits before the decimal point, except for currency values
5477             thousands_sep => ',',
5478             };
5479              
5480             my $map =
5481             {
5482             decimal => [qw( decimal_point mon_decimal_point )],
5483             grouping => [qw( grouping mon_grouping )],
5484             position_neg => [qw( n_sign_posn int_n_sign_posn )],
5485             position_pos => [qw( n_sign_posn int_p_sign_posn )],
5486             precede => [qw( p_cs_precedes int_p_cs_precedes )],
5487             precede_neg => [qw( n_cs_precedes int_n_cs_precedes )],
5488             precision => [qw( frac_digits int_frac_digits )],
5489             sign_neg => [qw( negative_sign )],
5490             sign_pos => [qw( positive_sign )],
5491             space_pos => [qw( p_sep_by_space int_p_sep_by_space )],
5492             space_neg => [qw( n_sep_by_space int_n_sep_by_space )],
5493             symbol => [qw( currency_symbol int_curr_symbol )],
5494             thousand => [qw( thousands_sep mon_thousands_sep )],
5495             };
5496              
5497             sub init
5498 145     145   406 {
5499 145         430 my $self = shift( @_ );
5500 145 50       732 my $num = shift( @_ );
5501 145 100       815 return( $self->error( "No number was provided." ) ) if( !CORE::length( $num ) );
5502 144 100       552 return( Module::Generic::Infinity->new( $num ) ) if( POSIX::isinf( $num ) );
5503 7     7   10606 return( Module::Generic::Nan->new( $num ) ) if( POSIX::isnan( $num ) );
  7         62  
  7         50  
5504 143         631 use utf8;
5505 143         1378 my @k = keys( %$map );
5506 143         507 @$self{ @k } = ( '' x scalar( @k ) );
5507 143         421 $self->{lang} = '';
5508 143         557 $self->{default} = $DEFAULT;
5509 143         883 $self->{_init_strict_use_sub} = 1;
5510 143         688 $self->SUPER::init( @_ );
5511             my $default = $self->default;
5512 143         1051 # $self->message( 3, "Getting current locale" );
5513             my $curr_locale = POSIX::setlocale( &POSIX::LC_ALL );
5514 143 100 33     1155 ## $self->message( 3, "Current locale is '$curr_locale'" );
    50          
5515             if( $self->{lang} )
5516             {
5517 73         124 # $self->message( 3, "Language requested '$self->{lang}'." );
5518 73     73   147 try
5519             {
5520             # $self->message( 3, "Current locale found is '$curr_locale'" );
5521             local $try_locale = sub
5522 73         116 {
5523             my $loc;
5524             # $self->message( 3, "Checking language '$_[0]'" );
5525             ## 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
5526             ## Try several possibilities
5527 73 50       216 ## RT https://rt.cpan.org/Public/Bug/Display.html?id=132664
5528             if( index( $_[0], '.' ) == -1 )
5529             {
5530 73         311 # $self->message( 3, "Language '$_[0]' is a bareword, check if it works as is." );
5531             $loc = POSIX::setlocale( &POSIX::LC_ALL, $_[0] );
5532 73         189 # $self->message( 3, "Succeeded to set up locale for language '$_[0]'" ) if( $loc );
5533 73 50 33     315 $_[0] =~ s/^(?<locale>[a-z]{2,3})_(?<country>[a-z]{2})$/$+{locale}_\U$+{country}\E/;
5534             if( !$loc && CORE::exists( $SUPPORTED_LOCALES->{ $_[0] } ) )
5535             {
5536 0         0 # $self->message( 3, "Language '$_[0]' is supported, let's check for right variation" );
  0         0  
5537             foreach my $supported ( @{$SUPPORTED_LOCALES->{ $_[0] }} )
5538 0 0       0 {
5539             if( ( $loc = POSIX::setlocale( &POSIX::LC_ALL, $supported ) ) )
5540 0         0 {
5541             $_[0] = $supported;
5542 0         0 # $self->message( "-> Language variation '$supported' found." );
5543             last;
5544             }
5545             }
5546             }
5547             }
5548             ## We got something like fr_FR.ISO-8859
5549             ## The user is specific, so we try as is
5550             else
5551             {
5552 0         0 # $self->message( 3, "Language '$_[0]' is specific enough, let's try it." );
5553             $loc = POSIX::setlocale( &POSIX::LC_ALL, $_[0] );
5554 73         259 }
5555 73         443 return( $loc );
5556             };
5557            
5558 73 50       246 ## $self->message( 3, "Current locale is: '$curr_locale'" );
5559             if( my $loc = $try_locale->( $self->{lang} ) )
5560             {
5561             # $self->message( 3, "Succeeded in setting locale for language '$self->{lang}'" );
5562 73         441 ## $self->message( 3, "Succeeded in setting locale to '$self->{lang}'." );
5563             my $lconv = POSIX::localeconv();
5564 73         672 ## Set back the LC_ALL to what it was, because we do not want to disturb the user environment
5565             POSIX::setlocale( &POSIX::LC_ALL, $curr_locale );
5566 73 50 50     1141 ## $self->messagef( 3, "POSIX::localeconv() returned %d items", scalar( keys( %$lconv ) ) );
5567             $default = $lconv if( $lconv && scalar( keys( %$lconv ) ) );
5568             }
5569             else
5570 0         0 {
5571             return( $self->error( "Language \"$self->{lang}\" is not supported by your system." ) );
5572             }
5573 73 50       499 }
  73 50       209  
  73 50       187  
  73 0       153  
  73 50       185  
  73         127  
  73         137  
  73         153  
  73         364  
  0         0  
  73         166  
  0         0  
  73         250  
  73         141  
  73         168  
  73         191  
  0         0  
  0         0  
  0         0  
  0         0  
5574 0     0   0 catch( $e )
5575 0         0 {
5576 0 0 33     0 return( $self->error( "An error occurred while getting the locale information for \"$self->{lang}\": $e" ) );
  0 0 33     0  
  0 0       0  
  0 50       0  
  0         0  
  0         0  
  73         1228  
  0         0  
5577             }
5578             }
5579             elsif( $curr_locale && ( my $lconv = POSIX::localeconv() ) )
5580 70 50       319 {
5581             $default = $lconv if( scalar( keys( %$lconv ) ) );
5582             ## To simulate running on Windows
5583             # my $fail = [qw(
5584             # frac_digits
5585             # int_frac_digits
5586             # n_cs_precedes
5587             # n_sep_by_space
5588             # n_sign_posn
5589             # p_cs_precedes
5590             # p_sep_by_space
5591             # p_sign_posn
5592             # )];
5593             # @$lconv{ @$fail } = ( -1 ) x scalar( @$fail );
5594 70         212 ## $self->message( 3, "No language provided, but current locale '$curr_locale' found" );
5595             $self->{lang} = $curr_locale;
5596             }
5597              
5598             ## This serves 2 purposes:
5599             ## 1) to silence warnings issued from Number::Format when it uses an empty string when evaluating a number, e.g. '' == 1
5600             ## 2) to ensure that blank numerical values are not interpreted to anything else than equivalent of empty
5601             ## 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
5602 143         1715 ## 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.
5603             my $numerics =
5604             {
5605             grouping => 0,
5606             frac_digits => 0,
5607             int_frac_digits => 0,
5608             int_n_cs_precedes => 0,
5609             int_p_cs_precedes => 0,
5610             int_n_sep_by_space => 0,
5611             int_p_sep_by_space => 0,
5612             int_n_sign_posn => 1,
5613             int_p_sign_posn => 1,
5614             mon_grouping => 0,
5615             n_cs_precedes => 0,
5616             n_sep_by_space => 0,
5617             n_sign_posn => 1,
5618             p_cs_precedes => 0,
5619             p_sep_by_space => 0,
5620             ## Position of positive sign. 1 = before (0 = parentheses)
5621             p_sign_posn => 1,
5622             };
5623 143         696
5624             foreach my $prop ( keys( %$map ) )
5625 1859         4135 {
5626             my $ref = $map->{ $prop };
5627 1859 100       4980 ## Already set by user
5628 1681         3682 next if( CORE::length( $self->{ $prop } ) );
5629             foreach my $lconv_prop ( @$ref )
5630 3006 100       7173 {
5631             if( CORE::defined( $default->{ $lconv_prop } ) )
5632             {
5633             ## Number::Format bug RT #71044 when running on Windows
5634             ## https://rt.cpan.org/Ticket/Display.html?id=71044
5635 70 0 33     392 ## This is a workaround when values are lower than 0 (i.e. -1)
      33        
5636             if( CORE::exists( $numerics->{ $lconv_prop } ) &&
5637             CORE::length( $default->{ $lconv_prop } ) &&
5638             $default->{ $lconv_prop } < 0 )
5639 0         0 {
5640             $default->{ $lconv_prop } = $numerics->{ $lconv_prop };
5641 70         278 }
5642 70         231 $self->$prop( $default->{ $lconv_prop } );
5643             last;
5644             }
5645             else
5646 2936         10551 {
5647             $self->$prop( $default->{ $lconv_prop } );
5648             }
5649             }
5650             }
5651            
5652 143         626 # $Number::Format::DEFAULT_LOCALE->{int_curr_symbol} = 'EUR';
5653 0         0 try
5654             {
5655 143         1153 ## Those are unsupported by Number::Format
5656             my $skip =
5657             {
5658             int_n_cs_precedes => 1,
5659             int_p_cs_precedes => 1,
5660             int_n_sep_by_space => 1,
5661             int_p_sep_by_space => 1,
5662             int_n_sign_posn => 1,
5663             int_p_sign_posn => 1,
5664 143         386 };
5665 143         678 my $opts = {};
5666             foreach my $prop ( CORE::keys( %$map ) )
5667             {
5668 1859         2481 ## $self->message( 3, "Checking property \"$prop\" value \"", overload::StrVal( $self->{ $prop } ), "\" (", $self->$prop->defined ? 'defined' : 'undefined', ")." );
5669 1859 100       4936 my $prop_val;
5670             if( $self->$prop->defined )
5671 248         655 {
5672             $prop_val = $self->$prop;
5673             }
5674             ## To prevent Number::Format from defaulting to property values not in sync with ours
5675             ## Because it seems the POSIX::setlocale only affect one module
5676             else
5677 1611         2623 {
5678             $prop_val = '';
5679             }
5680             ## $self->message( 3, "Using property \"$prop\" value \"$prop_val\" (", CORE::defined( $prop_val ) ? 'defined' : 'undefined', ") [ref=", ref( $prop_val ), "]." );
5681 1859         3874 ## Need to set all the localeconv properties for Number::Format, because it uses mon_thousand_sep intsead of just thousand_sep
  1859         5120  
5682             foreach my $lconv_prop ( @{$map->{ $prop }} )
5683 3432 100       7507 {
5684             CORE::next if( CORE::exists( $skip->{ $lconv_prop } ) );
5685 2574         5508 ## Cannot be undefined, but can be empty string
5686 2574 100 100     9143 $opts->{ $lconv_prop } = "$prop_val";
5687             if( !CORE::length( $opts->{ $lconv_prop } ) && CORE::exists( $numerics->{ $lconv_prop } ) )
5688 1296         3077 {
5689             $opts->{ $lconv_prop } = $numerics->{ $lconv_prop };
5690             }
5691             }
5692             }
5693 7     7   6432 ## $self->message( 3, "Using following options for Number::Format: ", sub{ $self->dumper( $opts ) } );
  7         25  
  7         430  
5694 143         1370 no warnings qw( uninitialized );
5695 7     7   43 $self->{_fmt} = Number::Format->new( %$opts );
  7         19  
  7         6981  
5696 143     143   290 use warnings;
5697 143 100       1150 }
  143 50       39751  
  143 50       387  
  143 0       333  
  143 50       335  
  143         286  
  143         289  
  143         310  
  143         618  
  1         4  
  142         421  
  0         0  
  143         548  
  143         401  
  143         399  
  143         480  
  0         0  
  0         0  
  0         0  
  0         0  
5698 0     0   0 catch( $e )
5699             {
5700 0         0 ## $self->message( 3, "Error trapped in creating a Number::Format object: '$e'" );
5701 0 0 33     0 return( $self->error( "Unable to create a Number::Format object: $e" ) );
  0 0 33     0  
  0 0       0  
  0 50       0  
  0         0  
  0         0  
  143         2855  
  0         0  
5702 143         587 }
5703 143         312 $self->{_original} = $num;
5704 143     143   324 try
5705 143 100       2027 {
5706             if( $num !~ /^$RE{num}{real}$/ )
5707 1         201 {
5708             $self->{_number} = $self->{_fmt}->unformat_number( $num );
5709             }
5710             else
5711 142         32258 {
5712             $self->{_number} = $num;
5713             }
5714 143 100       1603 ## $self->message( 3, "Unformatted number is: '$self->{_number}'" );
5715             return( $self->error( "Invalid number: $num" ) ) if( !defined( $self->{_number} ) );
5716 143 100       857 }
  142 50       545  
  143 50       450  
  143 0       294  
  143 50       323  
  143         271  
  143         293  
  143         333  
  143         601  
  1         4  
  142         393  
  0         0  
  143         515  
  143         345  
  143         368  
  143         424  
  0         0  
  0         0  
  0         0  
  0         0  
5717 0     0   0 catch( $e )
5718 0         0 {
5719 0 0 66     0 return( $self->error( "Invalid number: $num" ) );
  0 0 66     0  
  0 50       0  
  0 100       0  
  0         0  
  0         0  
  143         2461  
  1         51  
5720 142         4051 }
5721             return( $self );
5722             }
5723 3     3   18  
5724             sub abs { return( shift->_func( 'abs' ) ); }
5725              
5726             # sub asin { return( shift->_func( 'asin', { posix => 1 } ) ); }
5727 1     1   456  
5728             sub atan { return( shift->_func( 'atan', { posix => 1 } ) ); }
5729 1     1   11  
5730             sub atan2 { return( shift->_func( 'atan2', @_ ) ); }
5731 4 100   4   60  
5732             sub as_boolean { return( Module::Generic::Boolean->new( shift->{_number} ? 1 : 0 ) ); }
5733 0     0   0  
5734             sub as_string { return( shift->{_number} ) }
5735 1     1   7  
5736             sub cbrt { return( shift->_func( 'cbrt', { posix => 1 } ) ); }
5737 1     1   6  
5738             sub ceil { return( shift->_func( 'ceil', { posix => 1 } ) ); }
5739 1     1   6  
5740             sub chr { return( Module::Generic::Scalar->new( CORE::chr( $_[0]->{_number} ) ) ); }
5741              
5742             sub clone
5743 73     73   173 {
5744 73 100       328 my $self = shift( @_ );
5745 73 50       337 my $num = @_ ? shift( @_ ) : $self->{_number};
5746 73 50       299 return( Module::Generic::Infinity->new( $num ) ) if( POSIX::isinf( $num ) );
5747 73         425 return( Module::Generic::Nan->new( $num ) ) if( POSIX::isnan( $num ) );
5748 73         321 my @keys = keys( %$map );
5749 73         149 push( @keys, qw( lang debug ) );
5750 73         827 my $hash = {};
5751 73         349 @$hash{ @keys } = @$self{ @keys };
5752             return( $self->new( $num, $hash ) );
5753             }
5754              
5755             sub compute
5756 156     156   595 {
5757 156 100       994 my( $self, $other, $swap, $opts ) = @_;
5758 156 100       756 my $other_val = Scalar::Util::blessed( $other ) ? $other : "\"$other\"";
5759 156 100       712 my $operation = $swap ? "${other_val} $opts->{op} \$self->{_number}" : "\$self->{_number} $opts->{op} ${other_val}";
    100          
5760             if( $opts->{return_object} )
5761 43         3204 {
5762 7     7   62 my $res = eval( $operation );
  7         14  
  7         877  
5763 43 50 33     295 no overloading;
5764 43 50       452 warn( "Error with return formula \"$operation\" using object $self having number '$self->{_number}': $@" ) if( $@ && $self->_warnings_is_enabled );
5765 43 100       206 return if( $@ );
5766 42 100       229 return( Module::Generic::Scalar->new( $res ) ) if( $opts->{type} eq 'scalar' );
5767 37 100       172 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
5768             return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
5769 33 50       214 ## undef may be returned for example on platform supporting NaN when using <=>
5770 0         0 return( $self->clone( $res ) ) if( defined( $res ) );
5771             return;
5772             }
5773             elsif( $opts->{boolean} )
5774 110         8261 {
5775 7     7   50 my $res = eval( $operation );
  7         17  
  7         1924  
5776 110 50 33     758 no overloading;
5777 110 50       376 warn( "Error with boolean formula \"$operation\" using object $self having number '$self->{_number}': $@" ) if( $@ && $self->_warnings_is_enabled );
5778             return if( $@ );
5779 110         1466 # return( $res ? $self->true : $self->false );
5780             return( $res );
5781             }
5782             else
5783 3         171 {
5784             return( eval( $operation ) );
5785             }
5786             }
5787 1     1   6  
5788             sub cos { return( shift->_func( 'cos' ) ); }
5789 4     4   15  
5790             sub currency { return( shift->_set_get_prop( 'symbol', @_ ) ); }
5791 4387     4387   8874  
5792             sub decimal { return( shift->_set_get_prop( 'decimal', @_ ) ); }
5793 143     143   687  
5794             sub default { return( shift->_set_get_hash_as_mix_object( 'default', @_ ) ); }
5795 1     1   6  
5796             sub exp { return( shift->_func( 'exp' ) ); }
5797 2     2   13  
5798             sub floor { return( shift->_func( 'floor', { posix => 1 } ) ); }
5799              
5800             sub format
5801 2     2   6 {
5802 2 50 33     17 my $self = shift( @_ );
5803 7     7   56 my $precision = ( @_ && $_[0] =~ /^\d+$/ ) ? shift( @_ ) : $self->precision;
  7         21  
  7         9607  
5804 2         5 no overloading;
5805             my $num = $self->{_number};
5806 2 50       14 ## 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
5807 2         7 return( $num ) if( !defined( $num ) );
5808 2         4 my $fmt = $self->{_fmt};
5809 2     2   4 try
5810             {
5811             ## 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?
5812             ## To circumvent this, we provide the precision along with the "add trailing zeros" parameter expected by Number::Format
5813 2         22 ## return( $fmt->format_number( $num, $precision, 1 ) );
5814 2 50       48 my $res = $fmt->format_number( "$num", $precision, 1 );
5815 2         12 return if( !defined( $res ) );
5816             return( Module::Generic::Scalar->new( $res ) );
5817 2 50       23 }
  0 50       0  
  2 50       6  
  2 0       8  
  2 50       6  
  2         4  
  2         9  
  2         4  
  2         8  
  0         0  
  2         7  
  0         0  
  2         9  
  2         5  
  2         5  
  2         7  
  0         0  
  0         0  
  0         0  
  0         0  
5818 0     0   0 catch( $e )
5819 0         0 {
5820 0 0 33     0 return( $self->error( "Error formatting number \"$num\": $e" ) );
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  2         30  
  2         27  
5821             }
5822             }
5823 2     2   19  
5824             sub format_binary { return( Module::Generic::Scalar->new( CORE::sprintf( '%b', shift->{_number} ) ) ); }
5825              
5826             sub format_bytes
5827 1     1   3 {
5828             my $self = shift( @_ );
5829 1         4 # no overloading;
5830             my $num = $self->{_number};
5831 1 50       4 ## See comment in format() method
5832 1         3 return( $num ) if( !defined( $num ) );
5833 1         1 my $fmt = $self->{_fmt};
5834 1     1   2 try
5835             {
5836 1         8 ## return( $fmt->format_bytes( $num, @_ ) );
5837 1 50       225 my $res = $fmt->format_bytes( "$num", @_ );
5838 1         6 return if( !defined( $res ) );
5839             return( Module::Generic::Scalar->new( $res ) );
5840 1 50       7 }
  0 50       0  
  1 50       3  
  1 0       2  
  1 50       2  
  1         10  
  1         3  
  1         1  
  1         10  
  0         0  
  1         4  
  0         0  
  1         4  
  1         3  
  1         4  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
5841 0     0   0 catch( $e )
5842 0         0 {
5843 0 0 33     0 return( $self->error( "Error formatting number \"$num\": $e" ) );
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         24  
  1         21  
5844             }
5845             }
5846 2     2   13  
5847             sub format_hex { return( Module::Generic::Scalar->new( CORE::sprintf( '0x%X', shift->{_number} ) ) ); }
5848              
5849             sub format_money
5850 1     1   3 {
5851 1 50 33     7 my $self = shift( @_ );
5852 1 50       5 my $precision = ( @_ && $_[0] =~ /^\d+$/ ) ? shift( @_ ) : $self->precision;
5853             my $currency_symbol = @_ ? shift( @_ ) : $self->currency;
5854 1         3 # no overloading;
5855             my $num = $self->{_number};
5856 1 50       10 ## See comment in format() method
5857 1         4 return( $num ) if( !defined( $num ) );
5858 1         3 my $fmt = $self->{_fmt};
5859 1     1   2 try
5860             {
5861             ## Even though the Number::Format instantiated is set with a currency symbol,
5862             ## Number::Format will not respect it, and revert to USD if nothing was provided as argument
5863             ## This highlights that Number::Format is designed to be used more for exporting function rather than object methods
5864             ## $self->message( 3, "Passing Number = '$num', precision = '$precision', currency symbol = '$currency_symbol'." );
5865 1         9 ## return( $fmt->format_price( $num, $precision, $currency_symbol ) );
5866 1 50       188 my $res = $fmt->format_price( "$num", "$precision", "$currency_symbol" );
5867 1         5 return if( !defined( $res ) );
5868             return( Module::Generic::Scalar->new( $res ) );
5869 1 50       14 }
  0 50       0  
  1 50       4  
  1 0       2  
  1 50       7  
  1         3  
  1         1  
  1         2  
  1         4  
  0         0  
  1         8  
  0         0  
  1         5  
  1         3  
  1         3  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
5870 0     0   0 catch( $e )
5871 0         0 {
5872 0 0 33     0 return( $self->error( "Error formatting number \"$num\": $e" ) );
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         41  
  1         21  
5873             }
5874             }
5875              
5876             sub format_negative
5877 1     1   433 {
5878             my $self = shift( @_ );
5879 1         3 # no overloading;
5880             my $num = $self->{_number};
5881 1 50       12 ## See comment in format() method
5882 1         4 return( $num ) if( !defined( $num ) );
5883 1         6 my $fmt = $self->{_fmt};
5884 1     1   2 try
5885 1         6 {
5886             my $new = $self->format;
5887             ## $self->message( 3, "Formatted number '$self->{_number}' now is '$new'" );
5888 1         3 ## return( $fmt->format_negative( $new, @_ ) );
5889             my $res = $fmt->format_negative( "$new", @_ );
5890 1 50       19 ## $self->message( 3, "Result is '$res'" );
5891 1         4 return if( !defined( $res ) );
5892             return( Module::Generic::Scalar->new( $res ) );
5893 1 50       18 }
  0 50       0  
  1 50       4  
  1 0       3  
  1 50       3  
  1         2  
  1         2  
  1         2  
  1         5  
  0         0  
  1         8  
  0         0  
  1         11  
  1         3  
  1         2  
  1         4  
  0         0  
  0         0  
  0         0  
  0         0  
5894 0     0   0 catch( $e )
5895 0         0 {
5896 0 0 33     0 return( $self->error( "Error formatting number \"$num\": $e" ) );
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         21  
  1         45  
5897             }
5898             }
5899              
5900             sub format_picture
5901 0     0   0 {
5902 7     7   82 my $self = shift( @_ );
  7         17  
  7         14543  
5903 0         0 no overloading;
5904             my $num = $self->{_number};
5905 0 0       0 ## See comment in format() method
5906 0         0 return( $num ) if( !defined( $num ) );
5907 0         0 my $fmt = $self->{_fmt};
5908 0     0   0 try
5909             {
5910 0         0 ## return( $fmt->format_picture( $num, @_ ) );
5911 0 0       0 my $res = $fmt->format_picture( "$num", @_ );
5912 0         0 return if( !defined( $res ) );
5913             return( Module::Generic::Scalar->new( $res ) );
5914 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         0  
  0         0  
5915 0     0   0 catch( $e )
5916 0         0 {
5917 0 0 0     0 return( $self->error( "Error formatting number \"$num\": $e" ) );
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
5918             }
5919             }
5920 3957     3957   10813  
5921             sub formatter { return( shift->_set_get_object( 'formatter', 'Number::Format', @_ ) ); }
5922              
5923             ## https://stackoverflow.com/a/483708/4814971
5924             sub from_binary
5925 1     1   4 {
5926 1         3 my $self = shift( @_ );
5927 1 50 33     14 my $binary = shift( @_ );
5928 1         3 return if( !defined( $binary ) || !CORE::length( $binary ) );
5929 1     1   3 try
5930             {
5931 1         3 ## Nice trick to convert from binary to decimal. See perlfunc -> oct
5932 1 50       3 my $res = CORE::oct( "0b${binary}" );
5933 1         4 return if( !defined( $res ) );
5934             return( $self->clone( $res ) );
5935 1 50       15 }
  0 50       0  
  1 50       3  
  1 0       3  
  1 50       3  
  1         1  
  1         3  
  1         2  
  1         4  
  0         0  
  1         3  
  0         0  
  1         5  
  1         4  
  1         3  
  1         5  
  0         0  
  0         0  
  0         0  
  0         0  
5936 0     0   0 catch( $e )
5937 0         0 {
5938 0 0 33     0 return( $self->error( "Error while getting number from hexadecimal value \"$hex\": $e" ) );
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         29  
  1         20  
5939             }
5940             }
5941              
5942             sub from_hex
5943 1     1   3 {
5944 1         3 my $self = shift( @_ );
5945 1 50 33     7 my $hex = shift( @_ );
5946 1         3 return if( !defined( $hex ) || !CORE::length( $hex ) );
5947 1     1   1 try
5948 1         3 {
5949 1 50       3 my $res = CORE::hex( $hex );
5950 1         4 return if( !defined( $res ) );
5951             return( $self->clone( $res ) );
5952 1 50       16 }
  0 50       0  
  1 50       4  
  1 0       2  
  1 50       3  
  1         1  
  1         3  
  1         3  
  1         5  
  0         0  
  1         3  
  0         0  
  1         5  
  1         3  
  1         4  
  1         3  
  0         0  
  0         0  
  0         0  
  0         0  
5953 0     0   0 catch( $e )
5954 0         0 {
5955 0 0 33     0 return( $self->error( "Error while getting number from hexadecimal value \"$hex\": $e" ) );
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         30  
  1         20  
5956             }
5957             }
5958 4459     4459   9104  
5959             sub grouping { return( shift->_set_get_prop( 'grouping', @_ ) ); }
5960 1     1   492  
5961             sub int { return( shift->_func( 'int' ) ); }
5962              
5963             *is_decimal = \&is_float;
5964 0     0   0  
5965             sub is_even { return( !( shift->{_number} % 2 ) ); }
5966 1     1   6  
5967             sub is_finite { return( shift->_func( 'isfinite', { posix => 1 }) ); }
5968 1     1   16  
5969             sub is_float { return( (POSIX::modf( shift->{_number} ))[0] != 0 ); }
5970              
5971 0     0   0 # sub is_infinite { return( !(shift->is_finite) ); }
5972             sub is_infinite { return( shift->_func( 'isinf', { posix => 1 }) ); }
5973 1     1   11  
5974             sub is_int { return( (POSIX::modf( shift->{_number} ))[0] == 0 ); }
5975 1     1   7  
5976             sub is_nan { return( shift->_func( 'isnan', { posix => 1}) ); }
5977              
5978             *is_neg = \&is_negative;
5979 4     4   349  
5980             sub is_negative { return( shift->_func( 'signbit', { posix => 1 }) != 0 ); }
5981 1     1   6  
5982             sub is_normal { return( shift->_func( 'isnormal', { posix => 1}) ); }
5983 0     0   0  
5984             sub is_odd { return( shift->{_number} % 2 ); }
5985              
5986             *is_pos = \&is_positive;
5987 4     4   30  
5988             sub is_positive { return( shift->_func( 'signbit', { posix => 1 }) == 0 ); }
5989 74     74   252  
5990             sub lang { return( shift->_set_get_scalar_as_object( 'lang', @_ ) ); }
5991 1     1   12  
5992             sub length { return( $_[0]->clone( CORE::length( $_[0]->{_number} ) ) ); }
5993 1     1   10  
5994             sub locale { return( shift->_set_get_scalar_as_object( 'lang', @_ ) ); }
5995 1     1   7  
5996             sub log { return( shift->_func( 'log' ) ); }
5997 1     1   7  
5998             sub log2 { return( shift->_func( 'log2', { posix => 1 } ) ); }
5999 1     1   7  
6000             sub log10 { return( shift->_func( 'log10', { posix => 1 } ) ); }
6001 3     3   23  
6002             sub max { return( shift->_func( 'fmax', @_, { posix => 1 } ) ); }
6003 2     2   14  
6004             sub min { return( shift->_func( 'fmin', @_, { posix => 1 } ) ); }
6005 1     1   6  
6006             sub mod { return( shift->_func( 'fmod', @_, { posix => 1 } ) ); }
6007              
6008             ## This is used so that we can change formatter when the user changes thousand separator, decimal separator, precision or currency
6009             sub new_formatter
6010 3957     3957   6180 {
6011 3957         6397 my $self = shift( @_ );
6012 3957 50       6957 my $hash = {};
6013             if( @_ )
6014 0 0 0     0 {
    0          
6015             if( @_ == 1 && $self->_is_hash( $_[0] ) )
6016 0         0 {
6017             $hash = shift( @_ );
6018             }
6019             elsif( !( @_ % 2 ) )
6020 0         0 {
6021             $hash = { @_ };
6022             }
6023             else
6024 0         0 {
6025             return( $self->error( "Invalid parameters provided: '", join( "', '", @_ ), "'." ) );
6026             }
6027             }
6028             else
6029 3957         14437 {
6030             my @keys = keys( %$map );
6031 3957         7476 # @$hash{ @keys } = @$self{ @keys };
6032             for( @keys )
6033 51441         126988 {
6034             $hash->{ $_ } = $self->$_();
6035             }
6036 3957         5794 }
6037 3957     3957   5086 try
6038 3957         6026 {
6039 3957         16668 my $opts = {};
6040             foreach my $prop ( keys( %$map ) )
6041 51441 100       90548 {
6042             $opts->{ $map->{ $prop }->[0] } = $hash->{ $prop } if( CORE::defined( $hash->{ $prop } ) );
6043 3957         17474 }
6044             return( Number::Format->new( %$opts ) );
6045 3957 50       17635 }
  0 0       0  
  3957 50       8317  
  3957 0       5349  
  3957 50       6671  
  3957         4962  
  3957         5723  
  3957         6564  
  3957         6742  
  3957         6263  
  0         0  
  0         0  
  3957         319658  
  3957         6937  
  3957         7496  
  3957         7479  
  0         0  
  0         0  
  0         0  
  0         0  
6046 0     0   0 catch( $e )
6047 0         0 {
6048 0 0 33     0 return( $self->error( "Error while trying to get a Number::Format object: $e" ) );
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  3957         30729  
  3957         32883  
6049             }
6050             }
6051 1     1   7  
6052             sub oct { return( shift->_func( 'oct' ) ); }
6053 4459     4459   9055  
6054             sub position_neg { return( shift->_set_get_prop( 'position_neg', @_ ) ); }
6055 4459     4459   9053  
6056             sub position_pos { return( shift->_set_get_prop( 'position_pos', @_ ) ); }
6057 0     0   0  
6058             sub pow { return( shift->_func( 'pow', @_, { posix => 1 } ) ); }
6059 4460     4460   9054  
6060             sub precede { return( shift->_set_get_prop( 'precede', @_ ) ); }
6061 4459     4459   9087  
6062             sub precede_neg { return( shift->_set_get_prop( 'precede_neg', @_ ) ); }
6063 0     0   0  
6064             sub precede_pos { return( shift->_set_get_prop( 'precede', @_ ) ); }
6065 4398     4398   8704  
6066             sub precision { return( shift->_set_get_prop( 'precision', @_ ) ); }
6067 0     0   0  
6068             sub rand { return( shift->_func( 'rand' ) ); }
6069 1 50   1   29  
6070             sub round { return( $_[0]->clone( CORE::sprintf( '%.*f', CORE::int( CORE::length( $_[1] ) ? $_[1] : 0 ), $_[0]->{_number} ) ) ); }
6071 0     0   0  
6072             sub round_zero { return( shift->_func( 'round', @_, { posix => 1 } ) ); }
6073              
6074             sub round2
6075 0     0   0 {
6076 7     7   67 my $self = shift( @_ );
  7         16  
  7         11078  
6077 0         0 no overloading;
6078             my $num = $self->{_number};
6079 0 0       0 ## See comment in format() method
6080 0         0 return( $num ) if( !defined( $num ) );
6081 0         0 my $fmt = $self->{_fmt};
6082 0     0   0 try
6083             {
6084 0         0 ## return( $fmt->round( $num, @_ ) );
6085 0 0       0 my $res = $fmt->round( $num, @_ );
6086 0         0 return if( !defined( $res ) );
6087 0         0 my $clone = $self->clone;
6088 0         0 $clone->{_number} = $res;
6089             return( $clone );
6090 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         0  
  0         0  
6091 0     0   0 catch( $e )
6092 0         0 {
6093 0 0 0     0 return( $self->error( "Error rounding number \"$num\": $e" ) );
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
6094             }
6095             }
6096 0     0   0  
6097             sub scalar { return( shift->as_string ); }
6098 4316     4316   8946  
6099             sub sign_neg { return( shift->_set_get_prop( 'sign_neg', @_ ) ); }
6100 4316     4316   9032  
6101             sub sign_pos { return( shift->_set_get_prop( 'sign_pos', @_ ) ); }
6102 1     1   5  
6103             sub sin { return( shift->_func( 'sin' ) ); }
6104              
6105             *space = \&space_pos;
6106 4459     4459   8947  
6107             sub space_neg { return( shift->_set_get_prop( 'space_neg', @_ ) ); }
6108 4459     4459   10089  
6109             sub space_pos { return( shift->_set_get_prop( 'space_pos', @_ ) ); }
6110 1     1   4  
6111             sub sqrt { return( shift->_func( 'sqrt' ) ); }
6112 4422     4422   8570  
6113             sub symbol { return( shift->_set_get_prop( 'symbol', @_ ) ); }
6114 1     1   7  
6115             sub tan { return( shift->_func( 'tan', { posix => 1 } ) ); }
6116 4460     4460   9291  
6117             sub thousand { return( shift->_set_get_prop( 'thousand', @_ ) ); }
6118              
6119             sub unformat
6120 1     1   3 {
6121 1         11 my $self = shift( @_ );
6122 1 50       9 my $num = shift( @_ );
6123 1         2 return if( !defined( $num ) );
6124 1     1   2 try
6125 1         15 {
6126 1         38 my $num2 = $self->{_fmt}->unformat_number( $num );
6127 1         4 my $clone = $self->clone;
6128 1         11 $clone->{_original} = $num;
6129 1         11 $clone->{_number} = $num2;
6130             return( $clone );
6131 1 50       16 }
  0 50       0  
  1 50       4  
  1 0       2  
  1 50       3  
  1         6  
  1         2  
  1         2  
  1         10  
  0         0  
  1         3  
  0         0  
  1         5  
  1         8  
  1         3  
  1         9  
  0         0  
  0         0  
  0         0  
  0         0  
6132 0     0   0 catch( $e )
6133 0         0 {
6134 0 0 33     0 return( $self->error( "Unable to unformat the number \"$num\": $e" ) );
  0 0 33     0  
  0 50       0  
  0 50       0  
  0         0  
  0         0  
  1         39  
  1         14  
6135             }
6136             }
6137              
6138             sub _func
6139 29     29   113 {
6140 29   50     202 my $self = shift( @_ );
6141             my $func = shift( @_ ) || return( $self->error( "No function was provided." ) );
6142 29         95 ## $self->message( 3, "Arguments received are: '", join( "', '", @_ ), "'." );
6143 29 100       165 my $opts = {};
6144 29 100       137 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
6145 29 100       97 my $namespace = $opts->{posix} ? 'POSIX' : 'CORE';
6146 29 100       158 my $val = @_ ? shift( @_ ) : undef;
6147             my $expr = defined( $val ) ? "${namespace}::${func}( \$self->{_number}, $val )" : "${namespace}::${func}( \$self->{_number} )";
6148 29         2153 ## $self->message( 3, "Evaluating '$expr'" );
6149             my $res = eval( $expr );
6150 29 50       179 ## $self->message( 3, "Result for number '$self->{_number}' is '$res'" );
6151 29 50       105 $self->message( 3, "Error: $@" ) if( $@ );
6152 29 50       113 return( $self->pass_error( $@ ) ) if( $@ );
6153 29 50       157 return if( !defined( $res ) );
6154 29 50       134 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
6155 29         116 return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
6156             return( $self->clone( $res ) );
6157             }
6158              
6159             sub _set_get_prop
6160 57517     57517   76998 {
6161 57517         73596 my $self = shift( @_ );
6162 57517 100       103503 my $prop = shift( @_ );
6163             if( @_ )
6164 3957         7515 {
6165 3957 100 66     7872 my $val = shift( @_ );
6166             $val = $val->scalar if( $self->_is_object( $val ) && $val->isa( 'Module::Generic::Scalar' ) );
6167 3957 50 66     11530 ## $self->message( 3, "Setting value \"$val\" (", defined( $val ) ? 'defined' : 'undefined', ") for property \"$prop\"." );
6168             if( $val ne $self->{ $prop } || !CORE::defined( $val ) )
6169             {
6170 3957         9196 # $self->{ $prop } = $val;
6171             $self->_set_get_scalar_as_object( $prop, $val );
6172 3957 50       10114 ## If an error was set, we return nothing
6173             $self->formatter( $self->new_formatter ) || return;
6174             }
6175             }
6176 57517         94340 # return( $self->{ $prop } );
6177             return( $self->_set_get_scalar_as_object( $prop ) );
6178             }
6179              
6180             AUTOLOAD
6181 0     0   0 {
6182 0   0     0 my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
6183 0   0     0 my $self = shift( @_ ) || return;
6184 0         0 my $fmt_obj = $self->{_fmt} || return;
6185 0 0       0 my $code = $fmt_obj->can( $method );
6186             if( $code )
6187 0         0 {
6188 0     0   0 try
6189 0         0 {
6190             return( $code->( $fmt_obj, @_ ) );
6191 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         0  
  0         0  
6192 0     0   0 catch( $e )
6193 0         0 {
6194 0         0 CORE::warn( $e );
6195 0 0 0     0 return;
  0 0 0     0  
  0 0       0  
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
6196             }
6197 0         0 }
6198             return;
6199             };
6200              
6201             package Module::Generic::NumberSpecial;
6202             BEGIN
6203 7     7   62 {
  7         17  
  7         166  
6204 7     7   37 use strict;
  7         16  
  7         276  
6205 7     7   44 use warnings;
  7         14  
  7         68  
6206 5     5   881 use parent -norequire, qw( Module::Generic::Number );
6207 0     0   0 use overload ('""' => sub{ $_[0]->{_number} },
6208 0     0   0 '+=' => sub{ &_catchall( @_[0..2], '+' ) },
6209 1     1   8 '-=' => sub{ &_catchall( @_[0..2], '-' ) },
6210 0     0   0 '*=' => sub{ &_catchall( @_[0..2], '*' ) },
6211 0     0   0 '/=' => sub{ &_catchall( @_[0..2], '/' ) },
6212 0     0   0 '%=' => sub{ &_catchall( @_[0..2], '%' ) },
6213 0     0   0 '**=' => sub{ &_catchall( @_[0..2], '**' ) },
6214 0     0   0 '<<=' => sub{ &_catchall( @_[0..2], '<<' ) },
6215 0     0   0 '>>=' => sub{ &_catchall( @_[0..2], '>>' ) },
6216 0     0   0 'x=' => sub{ &_catchall( @_[0..2], 'x' ) },
6217 7         141 '.=' => sub{ &_catchall( @_[0..2], '.' ) },
6218             nomethod => \&_catchall,
6219 7     7   2105 fallback => 1,
  7         18  
6220 7     7   1183 );
  7         18  
  7         543  
6221 7     7   45 use Want;
  7         16  
  7         173  
6222 7     7   4288 use POSIX ();
6223             our( $VERSION ) = '0.1.0';
6224             };
6225              
6226             sub new
6227 17     17   51 {
6228 17   66     167 my $this = shift( @_ );
6229             return( bless( { _number => CORE::shift( @_ ) } => ( ref( $this ) || $this ) ) );
6230             }
6231 1     1   22  
6232             sub clone { return( shift->new( @_ ) ); }
6233 0     0   0  
6234             sub is_finite { return( 0 ); }
6235 0     0   0  
6236             sub is_float { return( 0 ); }
6237 0     0   0  
6238             sub is_infinite { return( 0 ); }
6239 0     0   0  
6240             sub is_int { return( 0 ); }
6241 0     0   0  
6242             sub is_nan { return( 0 ); }
6243 2     2   10  
6244             sub is_normal { return( 0 ); }
6245 0     0   0  
6246             sub length { return( CORE::length( $self->{_number} ) ); }
6247              
6248             sub _catchall
6249 1     1   9 {
6250 1 50       9 my( $self, $other, $swap, $op ) = @_;
6251 1         68 my $expr = $swap ? "$other $op $self->{_number}" : "$self->{_number} $op $other";
6252             my $res = eval( $expr );
6253 1 50       14 ## print( ref( $self ), "::_catchall: evaluating $expr => $res\n" );
6254 1 50       4 CORE::warn( "Error evaluating expression \"$expr\": $@" ) if( $@ );
6255 1 50       4 return if( $@ );
6256 1 50       6 return( Module::Generic::Number->new( $res ) ) if( POSIX::isnormal( $res ) );
6257 0 0       0 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
6258 0         0 return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
6259             return( $res );
6260             }
6261              
6262             sub _func
6263 7     7   14 {
6264 7   50     34 my $self = shift( @_ );
6265 7         12 my $func = shift( @_ ) || return( $self->error( "No function was provided." ) );
6266 7 100       26 my $opts = {};
6267 7 100       30 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
6268 7 100       20 my $namespace = $opts->{posix} ? 'POSIX' : 'CORE';
6269 7 100       110 my $val = @_ ? shift( @_ ) : undef;
6270 7         389 my $expr = defined( $val ) ? "${namespace}::${func}( $self->{_number}, $val )" : "${namespace}::${func}( $self->{_number} )";
6271             my $res = eval( $expr );
6272             ## $self->message( 3, "Error: $@" ) if( $@ );
6273 7 50       27 ## print( STDERR ref( $self ), "::_func -> evaluating '$expr' -> '$res'\n" );
6274 7 50       17 CORE::warn( $@ ) if( $@ );
6275 7 100       38 return if( !defined( $res ) );
6276 4 50       14 return( Module::Generic::Number->new( $res ) ) if( POSIX::isnormal( $res ) );
6277 0 0       0 return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) );
6278 0         0 return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) );
6279             return( $res );
6280             }
6281              
6282             AUTOLOAD
6283 0     0   0 {
6284             my( $method ) = our $AUTOLOAD =~ /([^:]+)$/;
6285             ## print( STDERR "$AUTOLOAD: called for method \"$method\"\n" );
6286 0 0       0 ## If we are chained, return our null object, so the chain continues to work
6287             if( want( 'OBJECT' ) )
6288             {
6289 0         0 ## No, this is NOT a typo. rreturn() is a function of module Want
6290 0         0 print( STDERR "$AUTOLOAD: Returning the object itself (", ref( $_[0] ), ")\n" );
6291             rreturn( $_[0] );
6292             }
6293             ## Otherwise, we return infinity, whether positive or negative or NaN depending on what was set
6294 0         0 ## print( STDERR "$AUTOLOAD: returning '", $_[0]->{_number}, "'\n" );
6295             return( $_[0]->{_number} );
6296             };
6297       0      
6298             DESTROY {};
6299              
6300             ## Purpose is to allow chaining of methods when infinity is returned
6301             ## At the end of the chain, Inf or -Inf is returned
6302             package Module::Generic::Infinity;
6303             BEGIN
6304 7     7   59 {
  7         14  
  7         154  
6305 7     7   32 use strict;
  7         16  
  7         225  
6306 7     7   37 use warnings;
  7         14  
  7         35  
6307 7     7   605 use parent -norequire, qw( Module::Generic::NumberSpecial );
6308             our( $VERSION ) = '0.1.0';
6309             };
6310 1     1   5  
6311             sub is_infinite { return( 1 ); }
6312              
6313             package Module::Generic::Nan;
6314             BEGIN
6315 7     7   40 {
  7         15  
  7         133  
6316 7     7   32 use strict;
  7         15  
  7         196  
6317 7     7   36 use warnings;
  7         15  
  7         28  
6318 7     7   577 use parent -norequire, qw( Module::Generic::NumberSpecial );
6319             our( $VERSION ) = '0.1.0';
6320             };
6321 1     1   4  
6322             sub is_nan { return( 1 ); }
6323              
6324              
6325             package Module::Generic::Hash;
6326             BEGIN
6327 7     7   36 {
  7         14  
  7         162  
6328 7     7   33 use strict;
  7         13  
  7         925  
6329 7     7   40 use warnings::register;
  7         18  
  7         31  
6330             use parent -norequire, qw( Module::Generic );
6331             use overload (
6332 1     1   48 ## '""' => 'as_string',
6333 1     1   4 'eq' => sub { _obj_eq(@_) },
6334 4     4   20 'ne' => sub { !_obj_eq(@_) },
6335 3     3   56 '<' => sub { _obj_comp( @_, '<') },
6336 1     1   6 '>' => sub { _obj_comp( @_, '>') },
6337 2     2   11 '<=' => sub { _obj_comp( @_, '<=') },
6338 0     0   0 '>=' => sub { _obj_comp( @_, '>=') },
6339 0     0   0 '==' => sub { _obj_comp( @_, '>=') },
6340 1     1   6 '!=' => sub { _obj_comp( @_, '>=') },
6341 1     1   6 'lt' => sub { _obj_comp( @_, 'lt') },
6342 0     0   0 'gt' => sub { _obj_comp( @_, 'gt') },
6343 0     0   0 'le' => sub { _obj_comp( @_, 'le') },
6344 7         119 'ge' => sub { _obj_comp( @_, 'ge') },
6345 7     7   1614 fallback => 1,
  7         15  
6346 7     7   1192 );
  7         16  
  7         360  
6347 7     7   4791 use Data::Dumper;
  7         61808  
  7         39  
6348 7     7   1170 use JSON;
  7         16  
  7         127  
6349 7     7   33 use Clone ();
  7         16  
  7         380  
6350 7     7   43 use Want;
  7         17  
  7         55  
6351             use Regexp::Common;
6352             };
6353              
6354             sub new
6355 148     148   418 {
6356 148   66     660 my $that = shift( @_ );
6357             my $class = ref( $that ) || $that;
6358             ## my $data = shift( @_ ) ||
6359 148         355 ## return( $that->error( "No hash was provided to initiate a $class hash object." ) );
6360 148 50       639 my $data = {};
6361 148 50       779 $data = shift( @_ ) if( scalar( @_ ) );
6362 148         472 return( $that->error( "I was expecting an hash, but instead got '$data'." ) ) if( Scalar::Util::reftype( $data ) ne 'HASH' );
6363 148 50       412 my $tied = tied( %$data );
6364 148         367 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 );
6365             my %hash = ();
6366 148         1606 ## This enables access to the hash just like a real hash while still the user an call our object methods
6367             my $obj = tie( %hash, 'Module::Generic::TieHash', {
6368             disable => ['Module::Generic'],
6369             debug => 0,
6370 148         533 });
6371 148         703 my $self = bless( \%hash => $class );
6372 148         1097 $obj->enable( 1 );
6373 148         4588 my @keys = CORE::keys( %$data );
6374 148         1330 @hash{ @keys } = @$data{ @keys };
6375 148         799 $obj->enable( 0 );
6376 148         537 $self->SUPER::init( @_ );
6377 148         846 $obj->enable( 1 );
6378             return( $self );
6379             }
6380 1     1   5  
6381             sub as_string { return( shift->dump ); }
6382              
6383             sub clone
6384 1     1   3 {
6385 1         5 my $self = shift( @_ );
6386 1         6 $self->_tie_object->enable( 0 );
6387 1         29 my $data = $self->{data};
6388 1         4 my $clone = Clone::clone( $data );
6389 1         6 $self->_tie_object->enable( 1 );
6390             return( $self->new( $clone ) );
6391             }
6392 4     4   20  
6393             sub debug { return( shift->_internal( 'debug', '_set_get_number', @_ ) ); }
6394 2     2   581  
6395             sub defined { CORE::defined( $_[0]->{ $_[1] } ); }
6396 1     1   10  
6397             sub delete { return( CORE::delete( shift->{ shift( @_ ) } ) ); }
6398              
6399             sub dump
6400 3     3   7 {
6401 3         12 my $self = shift( @_ );
6402             return( $self->_dumper( $self ) );
6403             }
6404              
6405             sub each
6406 1     1   4 {
6407 1   50     4 my $self = shift( @_ );
6408 1 50       6 my $code = shift( @_ ) || return( $self->error( "No subroutine callback as provided for each" ) );
6409 1         4 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' );
6410             while( my( $k, $v ) = CORE::each( %$self ) )
6411 4 50       13 {
6412             CORE::defined( $code->( $k, $v ) ) || CORE::last;
6413 1         4 }
6414             return( $self );
6415             }
6416 1     1   6  
6417             sub exists { return( CORE::exists( shift->{ shift( @_ ) } ) ); }
6418 1     1   6  
6419             sub for { return( shift->foreach( @_ ) ); }
6420              
6421             sub foreach
6422 1     1   2 {
6423 1   50     5 my $self = shift( @_ );
6424 1 50       5 my $code = shift( @_ ) || return( $self->error( "No subroutine callback as provided for each" ) );
6425 1         4 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' );
6426             CORE::foreach my $k ( CORE::keys( %$self ) )
6427 4         1785 {
6428 4 50       19 local $_ = $self->{ $k };
6429             CORE::defined( $code->( $k, $self->{ $k } ) ) || CORE::last;
6430 1         563 }
6431             return( $self );
6432             }
6433 0     0   0  
6434             sub get { return( $_[0]->{ $_[1] } ); }
6435 0     0   0  
6436             sub has { return( shift->exists( @_ ) ); }
6437              
6438             sub json
6439 2     2   5 {
6440 2         5 my $self = shift( @_ );
6441 2 100       10 my $opts = {};
6442 2         6 $opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' );
6443 2         9 $self->_tie_object->enable( 0 );
6444 2         6 my $data = $self->{data};
6445 2 100       6 my $json;
6446             if( $opts->{pretty} )
6447 1         57 {
6448             $json = JSON->new->pretty->utf8->indent(1)->relaxed(1)->canonical(1)->allow_nonref->encode( $data );
6449             }
6450             else
6451 1         16 {
6452             $json = JSON->new->utf8->canonical(1)->allow_nonref->encode( $data );
6453 2         12 }
6454 2         8 $self->_tie_object->enable( 1 );
6455             return( Module::Generic::Scalar->new( $json ) );
6456             }
6457              
6458 1     1   659 # $h->keys->sort
  1         44  
6459             sub keys { return( Module::Generic::Array->new( [ CORE::keys( %{$_[0]} ) ] ) ); }
6460 21     21   54  
  21         585  
6461             sub length { return( Module::Generic::Number->new( CORE::scalar( CORE::keys( %{$_[0]} ) ) ) ); }
6462              
6463             sub map
6464 0     0   0 {
6465 0         0 my $self = shift( @_ );
6466 0 0       0 my $code = CORE::shift( @_ );
6467 0         0 return if( ref( $code ) ne 'CODE' );
6468             return( CORE::map( $code->( $_, $self->{ $_ } ), CORE::keys( %$self ) ) );
6469             }
6470              
6471             sub map_array
6472 0     0   0 {
6473 0         0 my $self = shift( @_ );
6474 0 0       0 my $code = CORE::shift( @_ );
6475 0         0 return if( ref( $code ) ne 'CODE' );
6476             return( Module::Generic::Array->new( [CORE::map( $code->( $_, $self->{ $_ } ), CORE::keys( %$self ) )] ) );
6477             }
6478              
6479             sub map_hash
6480 0     0   0 {
6481 0         0 my $self = shift( @_ );
6482 0 0       0 my $code = CORE::shift( @_ );
6483 0         0 return if( ref( $code ) ne 'CODE' );
6484             return( $self->new( {CORE::map( $code->( $_, $self->{ $_ } ), CORE::keys( %$self ) )} ) );
6485             }
6486              
6487             sub merge
6488 2     2   6 {
6489 2         4 my $self = shift( @_ );
6490 2         4 my $hash = {};
6491 2 50 33     19 $hash = shift( @_ );
6492             return( $self->error( "No valid hash provided." ) ) if( !$hash || Scalar::Util::reftype( $hash ) ne 'HASH' );
6493 2         4 ## $self->message( 3, "Hash provided is: ", sub{ $self->dumper( $hash ) } );
6494 2 100 66     11 my $opts = {};
6495 2 100       8 $opts = pop( @_ ) if( @_ && ref( $_[-1] ) eq 'HASH' );
6496 2         6 $opts->{overwrite} = 1 unless( CORE::exists( $opts->{overwrite} ) );
6497 2         11 $self->_tie_object->enable( 0 );
6498 2         5 my $data = $self->{data};
6499             my $seen = {};
6500             local $copy = sub
6501 4     4   7 {
6502 4         7 my $this = shift( @_ );
6503 4         6 my $to = shift( @_ );
6504 4 100 66     19 my $p = {};
6505             $p = shift( @_ ) if( @_ && ref( $_[-1] ) eq 'HASH' );
6506 4         15 ## $self->message( 3, "Merging hash ", sub{ $self->dumper( $this ) }, " to hash ", sub{ $self->dumper( $to ) }, " and with parameters ", sub{ $self->dumper( $p ) } );
6507             CORE::foreach my $k ( CORE::keys( %$this ) )
6508             {
6509 14 100 100     42 # $self->message( 3, "Skipping existing property '$k'." ) if( CORE::exists( $to->{ $k } ) && !$p->{overwrite} );
6510 8 100 33     34 next if( CORE::exists( $to->{ $k } ) && !$p->{overwrite} );
      66        
6511             if( ref( $this->{ $k } ) eq 'HASH' ||
6512             ( Scalar::Util::blessed( $this->{ $k } ) && $this->{ $k }->isa( 'Module::Generic::Hash' ) ) )
6513 2         8 {
6514             my $addr = Scalar::Util::refaddr( $this->{ $k } );
6515 2 50       6 # $self->message( 3, "Checking if hash in property '$k' was already processed with address '$addr'." );
6516             if( CORE::exists( $seen->{ $addr } ) )
6517 0         0 {
6518 0         0 $to->{ $k } = $seen->{ $addr };
6519             next;
6520             }
6521             else
6522 2 100       11 {
6523 2         10 $to->{ $k } = {} unless( Scalar::Util::reftype( $to->{ $k } ) eq 'HASH' );
6524             $copy->( $this->{ $k }, $to->{ $k } );
6525 2         7 }
6526             $seen->{ $addr } = $this->{ $k };
6527             }
6528             else
6529 6         15 {
6530             $to->{ $k } = $this->{ $k };
6531             }
6532 2         16 }
6533             };
6534 2         8 ## $self->message( 3, "Propagating hash ", sub{ $self->dumper( $hash ) }, " to hash ", sub{ $self->dumper( $data ) } );
6535 2         6 $copy->( $hash, $data, $opts );
6536 2         24 $self->_tie_object->enable( 1 );
6537             return( $self );
6538             }
6539 0     0   0  
  0         0  
6540             sub reset { %{$_[0]} = () };
6541 0     0   0  
6542             sub set { $_[0]->{ $_[1] } = $_[2]; }
6543 0     0   0  
  0         0  
6544             sub undef { %{$_[0]} = () };
6545              
6546             sub values
6547 1     1   4 {
6548 1         2 my $self = shift( @_ );
6549 1 50 33     10 my $code;
6550 1         3 $code = shift( @_ ) if( @_ && ref( $_[0] ) eq 'CODE' );
6551 1 50       8 my $opts = {};
6552 1 50       4 $opts = pop( @_ ) if( Scalar::Util::reftype( $_[-1] ) eq 'HASH' );
6553             if( $code )
6554 1 50       4 {
6555             if( $opts->{sort} )
6556 1         72 {
6557             return( Module::Generic::Array->new( [ CORE::map( $code->( $_ ), CORE::sort( CORE::values( %$self ) ) ) ] ) );
6558             }
6559             else
6560 0         0 {
6561             return( Module::Generic::Array->new( [ CORE::map( $code->( $_ ), CORE::values( %$self ) ) ] ) );
6562             }
6563             }
6564             else
6565 0 0       0 {
6566             if( $opts->{sort} )
6567 0         0 {
6568             return( Module::Generic::Array->new( [ CORE::sort( CORE::values( %$self ) ) ] ) );
6569             }
6570             else
6571 0         0 {
6572             return( Module::Generic::Array->new( [ CORE::values( %$self ) ] ) );
6573             }
6574             }
6575             }
6576              
6577             # sub _dumper
6578             # {
6579             # my $self = shift( @_ );
6580             # if( !$self->{_dumper} )
6581             # {
6582             # my $d = Data::Dumper->new;
6583             # $d->Indent( 1 );
6584             # $d->Useqq( 1 );
6585             # $d->Terse( 1 );
6586             # $d->Sortkeys( 1 );
6587             # $self->{_dumper} = $d;
6588             # }
6589             # return( $self->{_dumper}->Dumper( @_ ) );
6590             # }
6591             #
6592             sub _dumper
6593 5     5   10 {
6594 5         12 my $self = shift( @_ );
6595 5         22 $self->_tie_object->enable( 0 );
6596 5         34 my $data = $self->{data};
6597 5         175 my $d = Data::Dumper->new( [ $data ] );
6598 5         77 $d->Indent( 1 );
6599 5         35 $d->Useqq( 1 );
6600 5         72 $d->Terse( 1 );
6601             $d->Sortkeys( 1 );
6602 5         34 # $d->Freezer( '' );
6603             $d->Bless( '' );
6604 5         36 # return( $d->Dump );
6605 5         250 my $str = $d->Dump;
6606 5         47 $self->_tie_object->enable( 1 );
6607             return( $str );
6608             }
6609              
6610             sub _internal
6611 4     4   11 {
6612 4         11 my $self = shift( @_ );
6613 4         10 my $field = shift( @_ );
6614             my $meth = shift( @_ );
6615 4         15 # print( STDERR ref( $self ), "::_internal -> Caling method '$meth' for field '$field' with value '", join( "', '", @_ ), "'\n" );
6616 4         9 $self->_tie_object->enable( 0 );
6617 4 50       12 my( @resA, $resB );
6618             if( wantarray )
6619 0         0 {
6620             @resA = $self->$meth( $field, @_ );
6621             # $self->message( "Resturn list value is: '@resA'" );
6622             }
6623             else
6624 4         23 {
6625             $resB = $self->$meth( $field, @_ );
6626             # $self->message( "Resturn scalar value is: '$resB'" );
6627 4         16 }
6628 4 50       25 $self->_tie_object->enable( 1 );
6629             return( wantarray ? @resA : $resB );
6630             }
6631              
6632             sub _obj_comp
6633 12     12   49 {
6634 12         30 my( $self, $other, $swap, $op ) = @_;
6635 12         45 my( $lA, $lB );
6636 12 100 66     149 $lA = $self->length;
    50          
6637             if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Hash' ) )
6638 7         32 {
6639             $lB = $other->length;
6640             }
6641             elsif( $other =~ /^$RE{num}{real}$/ )
6642 5         767 {
6643             $lB = $other;
6644             }
6645             else
6646 0         0 {
6647             return;
6648 12 100       127 }
6649 12         1276 my $expr = $swap ? "$lB $op $lA" : "$lA $op $lB";
6650             return( eval( $expr ) );
6651             }
6652 0     0   0  
6653             sub _printer { return( shift->printer( @_ ) ); }
6654              
6655             sub _obj_eq
6656 7     7   1043866 {
  7         21  
  7         1132  
6657 2     2   6 no overloading;
6658 2         5 my $self = shift( @_ );
6659 2         7 my $other = shift( @_ );
6660 2         5 my $strA = $self->_dumper( $self );
6661 2 50 33     16 my $strB;
    0          
6662             if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Hash' ) )
6663 2         9 {
6664             $strB = $other->dump;
6665             }
6666             elsif( Scalar::Util::reftype( $other ) eq 'HASH' )
6667 0         0 {
6668             $strB = $self->_dumper( $other )
6669             }
6670             else
6671 0         0 {
6672             return( 0 );
6673 2         16 }
6674             return( $strA eq $strB );
6675             }
6676              
6677             sub _tie_object
6678 28     28   54 {
6679 28         174 my $self = shift( @_ );
6680             return( tied( %$self ) );
6681             }
6682              
6683             package Module::Generic::TieHash;
6684             BEGIN
6685 7     7   54 {
  7         19  
  7         164  
6686 7     7   42 use strict;
  7         17  
  7         981  
6687 7     7   54 use warnings::register;
  7         16  
  7         69  
6688 7     7   373 use parent -norequire, qw( Module::Generic );
  7         16  
  7         173  
6689 7     7   4530 use Scalar::Util ();
6690             our( $VERSION ) = '0.1.0';
6691             };
6692              
6693             sub TIEHASH
6694 148     148   452 {
6695 148         380 my $self = shift( @_ );
6696 148 50       598 my $opts = {};
6697 148 50       687 $opts = shift( @_ ) if( @_ );
6698             if( Scalar::Util::reftype( $opts ) ne 'HASH' )
6699 0 0       0 {
6700 0         0 warn( "Parameters provided ($opts) is not an hash reference.\n" ) if( $self->_warnings_is_enabled );
6701             return;
6702 148         382 }
6703 148 50       796 my $disable = [];
6704 148         303 $disable = $opts->{disable} if( Scalar::Util::reftype( $opts->{disable} ) );
6705 148         630 my $list = {};
6706             @$list{ @$disable } = ( 1 ) x scalar( @$disable );
6707             my $hash =
6708             {
6709             ## The caller sets this to its class, so we can differentiate calls from inside and outside our caller's package
6710             disable => $list,
6711             debug => $opts->{debug},
6712             ## When disabled, the Tie::Hash system will return hash key values directly under $self instead of $self->{data}
6713             ## Disabled by default so the new() method can access its setup data directly under $self
6714 148         855 ## Then new() can call enable to active it
6715             enable => 0,
6716             ## Where to store the actual hash data
6717             data => {},
6718 148   33     661 };
6719 148         659 my $class = ref( $self ) || $self;
6720             return( bless( $hash => $class ) );
6721             }
6722              
6723             sub CLEAR
6724 0     0   0 {
6725 0         0 my $self = shift( @_ );
6726 0         0 my $data = $self->{data};
6727             %$data = ();
6728             }
6729              
6730             sub DELETE
6731 1     1   3 {
6732 1         4 my $self = shift( @_ );
6733 1         3 my $data = $self->{data};
6734 1         3 my $key = shift( @_ );
6735 1 50 33     4 my $caller = caller;
6736             if( $self->_exclude( $caller ) || !$self->{enable} )
6737             # if( !$self->{enable} )
6738 0         0 {
6739             CORE::delete( $self->{ $key } );
6740             }
6741             else
6742 1         7 {
6743             CORE::delete( $data->{ $key } );
6744             }
6745             }
6746              
6747             sub EXISTS
6748 3     3   10 {
6749 3         8 my $self = shift( @_ );
6750 3         7 my $data = $self->{data};
6751 3         8 my $key = shift( @_ );
6752 3 50 33     12 my $caller = caller;
6753             if( $self->_exclude( $caller ) || !$self->{enable} )
6754             # if( !$self->{enable} )
6755 0         0 {
6756             CORE::exists( $self->{ $key } );
6757             }
6758             else
6759 3         22 {
6760             CORE::exists( $data->{ $key } );
6761             }
6762             }
6763              
6764             sub FETCH
6765 1378     1378   2268 {
6766 1378         2036 my $self = shift( @_ );
6767 1378         1963 my $data = $self->{data};
6768 1378         2007 my $key = shift( @_ );
6769             my $caller = caller;
6770 1378 100 100     2142 ## print( STDERR "FETCH($caller)[enable=$self->{enable}] <- '$key''\n" );
6771             if( $self->_exclude( $caller ) || !$self->{enable} )
6772             # if( !$self->{enable} )
6773             {
6774 1356         5491 #print( STDERR "FETCH($caller)[owner calling, enable=$self->{enable}] <- '$key' <- '$self->{$key}'\n" );
6775             return( $self->{ $key } )
6776             }
6777             else
6778             {
6779 22         112 #print( STDERR "FETCH($caller)[enable=$self->{enable}] <- '$key' <- '$data->{$key}'\n" );
6780             return( $data->{ $key } );
6781             }
6782             }
6783              
6784             sub FIRSTKEY
6785 26     26   64 {
6786 26         89 my $self = shift( @_ );
6787 26         67 my $data = $self->{data};
6788 26         92 my @keys = ();
6789 26 50 33     119 my $caller = caller;
6790             if( $self->_exclude( $caller ) || !$self->{enable} )
6791             # if( !$self->{enable} )
6792 0         0 {
6793             @keys = keys( %$self );
6794             }
6795             else
6796 26         133 {
6797             @keys = keys( %$data );
6798 26         86 }
6799 26         154 $self->{ITERATOR} = \@keys;
6800             return( shift( @keys ) );
6801             }
6802              
6803             sub NEXTKEY
6804 88     88   2492 {
6805 88         134 my $self = shift( @_ );
6806 88 50       218 my $data = $self->{data};
6807 88         231 my $keys = ref( $self->{ITERATOR} ) ? $self->{ITERATOR} : [];
6808             return( shift( @$keys ) );
6809             }
6810              
6811             sub SCALAR
6812 0     0   0 {
6813 0         0 my $self = shift( @_ );
6814 0         0 my $data = $self->{data};
6815 0 0 0     0 my $caller = caller;
6816             if( $self->_exclude( $caller ) || !$self->{enable} )
6817             # if( !$self->{enable} )
6818 0         0 {
6819             return( scalar( keys( %$self ) ) );
6820             }
6821             else
6822 0         0 {
6823             return( scalar( keys( %$data ) ) );
6824             }
6825             }
6826              
6827             sub STORE
6828 4367     4367   6523 {
6829 4367         5505 my $self = shift( @_ );
6830 4367         6655 my $data = $self->{data};
6831 4367         6407 my( $key, $val ) = @_;
6832 4367 100 66     6577 my $caller = caller;
6833             if( $self->_exclude( $caller ) || !$self->{enable} )
6834             # if( !$self->{enable} )
6835             {
6836 891         2603 #print( STDERR "STORE($caller)[owner calling] <- '$key' -> '$val'\n" );
6837             $self->{ $key } = $val;
6838             }
6839             else
6840             {
6841 3476         11524 #print( STDERR "STORE($caller)[enable=$self->{enable}] <- '$key' -> '$val'\n" );
6842             $data->{ $key } = $val;
6843             }
6844             }
6845 472     472   1504  
6846             sub enable { return( shift->_set_get_boolean( 'enable', @_ ) ); }
6847              
6848             sub _exclude
6849 5775     5775   7117 {
6850 5775         6872 my $self = shift( @_ );
6851             my $caller = shift( @_ );
6852 5775         14892 ## $self->message( 3, "Disable hash contains: ", sub{ $self->dump( $self->{disable} ) });
6853             return( CORE::exists( $self->{disable}->{ $caller } ) );
6854             }
6855              
6856             package Module::Generic::Tie;
6857             BEGIN
6858 7     7   57 {
  7         17  
  7         368  
6859 7     7   134 use Tie::Hash;
6860 7         6399 our( @ISA ) = qw( Tie::Hash );
6861             our( $VERSION ) = '0.1.0';
6862             };
6863              
6864             sub TIEHASH
6865 0     0     {
6866 0           my $self = shift( @_ );
6867             my $pkg = ( caller() )[ 0 ];
6868 0           ## print( STDERR __PACKAGE__ . "::TIEHASH() called with following arguments: '", join( ', ', @_ ), "'.\n" );
6869 0           my %arg = ( @_ );
6870 0 0         my $auth = [ $pkg, __PACKAGE__ ];
6871             if( $arg{ 'pkg' } )
6872 0           {
6873 0 0         my $ok = delete( $arg{ 'pkg' } );
6874             push( @$auth, ref( $ok ) eq 'ARRAY' ? @$ok : $ok );
6875 0           }
6876 0           my $priv = { 'pkg' => $auth };
6877 0           my $data = { '__priv__' => $priv };
6878 0           my @keys = keys( %arg );
6879 0   0       @$priv{ @keys } = @arg{ @keys };
6880             return( bless( $data, ref( $self ) || $self ) );
6881             }
6882              
6883             sub CLEAR
6884 0     0     {
6885 0           my $self = shift( @_ );
6886             my $pkg = ( caller() )[ 0 ];
6887 0           ## print( $err __PACKAGE__ . "::CLEAR() called by package '$pkg'.\n" );
6888 0 0 0       my $data = $self->{ '__priv__' };
6889             return() if( $data->{ 'readonly' } && $pkg ne __PACKAGE__ );
6890 0 0         ## if( $data->{ 'readonly' } || $data->{ 'protect' } )
6891             if( !( $data->{ 'perms' } & 2 ) )
6892 0 0         {
  0            
6893             return if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
6894 0           }
6895 0           my $key = $self->FIRSTKEY( @_ );
6896 0           my @keys = ();
6897             while( defined( $key ) )
6898 0           {
6899 0           push( @keys, $key );
6900             $key = $self->NEXTKEY( @_, $key );
6901 0           }
6902             foreach $key ( @keys )
6903 0           {
6904             $self->DELETE( @_, $key );
6905             }
6906             }
6907              
6908             sub DELETE
6909 0     0     {
6910 0           my $self = shift( @_ );
6911 0 0         my $pkg = ( caller() )[ 0 ];
6912             $pkg = ( caller( 1 ) )[ 0 ] if( $pkg eq 'Module::Generic' );
6913 0           ## print( STDERR __PACKAGE__ . "::DELETE() package '$pkg' tries to delete '$_[ 0 ]'\n" );
6914 0 0 0       my $data = $self->{ '__priv__' };
6915             return if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ );
6916 0 0         ## if( $data->{ 'readonly' } || $data->{ 'protect' } )
6917             if( !( $data->{ 'perms' } & 2 ) )
6918 0 0         {
  0            
6919             return() if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
6920 0           }
6921             return( delete( $self->{ shift( @_ ) } ) );
6922             }
6923              
6924             sub EXISTS
6925 0     0     {
6926             my $self = shift( @_ );
6927 0 0 0       ## print( STDERR __PACKAGE__ . "::EXISTS() called from package '", ( caller() )[ 0 ], "'.\n" );
6928 0           return( 0 ) if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ );
6929 0 0         my $data = $self->{ '__priv__' };
6930             if( !( $data->{ 'perms' } & 4 ) )
6931 0           {
6932 0 0         my $pkg = ( caller() )[ 0 ];
  0            
6933             return( 0 ) if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
6934             }
6935 0           ## print( STDERR __PACKAGE__ . "::EXISTS() returns: '", exists( $self->{ $_[ 0 ] } ), "'.\n" );
6936             return( exists( $self->{ shift( @_ ) } ) );
6937             }
6938              
6939             sub FETCH
6940             {
6941             ## return( shift->{ shift( @_ ) } );
6942 0     0     ## print( STDERR __PACKAGE__ . "::FETCH() called with arguments: '", join( ', ', @_ ), "'.\n" );
6943             my $self = shift( @_ );
6944 0 0 0       ## This is a hidden entry, we return nothing
6945 0           return() if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ );
6946             my $data = $self->{ '__priv__' };
6947             ## If we have to protect our object, we hide its inner content if our caller is not our creator
6948 0 0         ## if( $data->{ 'protect' } )
6949             if( !( $data->{ 'perms' } & 4 ) )
6950 0           {
6951             my $pkg = ( caller() )[ 0 ];
6952 0 0         ## print( STDERR __PACKAGE__ . "::FETCH() package '$pkg' wants to fetch the value of '$_[ 0 ]'\n" );
  0            
6953             return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
6954 0           }
6955             return( $self->{ shift( @_ ) } );
6956             }
6957              
6958             sub FIRSTKEY
6959 0     0     {
6960             my $self = shift( @_ );
6961             ## my $a = scalar( keys( %$hash ) );
6962 0           ## return( each( %$hash ) );
6963             my $data = $self->{ '__priv__' };
6964 0 0         ## if( $data->{ 'protect' } )
6965             if( !( $data->{ 'perms' } & 4 ) )
6966 0           {
6967             my $pkg = ( caller( 0 ) )[ 0 ];
6968 0 0         ## print( STDERR __PACKAGE__ . "::FIRSTKEY() called by package '$pkg'\n" );
  0            
6969             return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
6970             }
6971 0           ## print( STDERR __PACKAGE__ . "::FIRSTKEY(): gathering object's keys.\n" );
6972 0           my( @keys ) = grep( !/^__priv__$/, keys( %$self ) );
6973             $self->{ '__priv__' }->{ 'ITERATOR' } = \@keys;
6974             ## print( STDERR __PACKAGE__ . "::FIRSTKEY(): keys are: '", join( ', ', @keys ), "'.\n" );
6975 0           ## print( STDERR __PACKAGE__ . "::FIRSTKEY() returns '$keys[ 0 ]'.\n" );
6976             return( shift( @keys ) );
6977             }
6978              
6979             sub NEXTKEY
6980 0     0     {
6981             my $self = shift( @_ );
6982 0           ## return( each( %$hash ) );
6983             my $data = $self->{ '__priv__' };
6984 0 0         ## if( $data->{ 'protect' } )
6985             if( !( $data->{ 'perms' } & 4 ) )
6986 0           {
6987             my $pkg = ( caller( 0 ) )[ 0 ];
6988 0 0         ## print( STDERR __PACKAGE__ . "::NEXTKEY() called by package '$pkg'\n" );
  0            
6989             return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) );
6990 0           }
6991             my $keys = $self->{ '__priv__' }->{ 'ITERATOR' };
6992 0           ## print( STDERR __PACKAGE__ . "::NEXTKEY() returns '$_[ 0 ]'.\n" );
6993             return( shift( @$keys ) );
6994             }
6995              
6996             sub STORE
6997 0     0     {
6998 0 0         my $self = shift( @_ );
6999 0           return() if( $_[ 0 ] eq '__priv__' );
7000             my $data = $self->{ '__priv__' };
7001             #if( $data->{ 'readonly' } ||
7002 0 0         # $data->{ 'protect' } )
7003             if( !( $data->{ 'perms' } & 2 ) )
7004 0           {
7005 0 0         my $pkg = ( caller() )[ 0 ];
7006             $pkg = ( caller( 1 ) )[ 0 ] if( $pkg eq 'Module::Generic' );
7007 0 0         ## print( STDERR __PACKAGE__ . "::STORE() package '$pkg' is trying to STORE the value '$_[ 1 ]' to key '$_[ 0 ]'\n" );
  0            
7008             return if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) );
7009             }
7010             ## print( STDERR __PACKAGE__ . "::STORE() ", ( caller() )[ 0 ], " is storing value '$_[ 1 ]' for key '$_[ 0 ]'.\n" );
7011 0           ## $self->{ shift( @_ ) } = shift( @_ );
7012             $self->{ $_[ 0 ] } = $_[ 1 ];
7013             ## print( STDERR __PACKAGE__ . "::STORE(): object '$self' now contains: '", join( ', ', map{ "$_, $self->{ $_ }" } keys( %$self ) ), "'.\n" );
7014             }
7015              
7016             1;
7017              
7018             __END__
7019              
7020             =encoding utf8
7021              
7022             =head1 NAME
7023              
7024             Module::Generic - Generic Module to inherit from
7025              
7026             =head1 SYNOPSIS
7027              
7028             package MyModule;
7029             BEGIN
7030             {
7031             use strict;
7032             use Module::Generic;
7033             our( @ISA ) = qw( Module::Generic );
7034             };
7035              
7036             =head1 VERSION
7037              
7038             v0.13.0
7039              
7040             =head1 DESCRIPTION
7041              
7042             L<Module::Generic> as its name says it all, is a generic module to inherit from.
7043             It is designed to provide a useful framework and speed up coding and debugging.
7044             It contains standard and support methods that may be superseded by your the module using
7045             L<Module::Generic>.
7046              
7047             As an added benefit, it also contains a powerfull AUTOLOAD transforming any hash
7048             object key into dynamic methods and also recognize the dynamic routine a la AutoLoader
7049             from which I have shamelessly copied in the AUTOLOAD code. The reason is that while
7050             C<AutoLoader> provides the user with a convenient AUTOLOAD, I wanted a way to also
7051             keep the functionnality of L<Module::Generic> AUTOLOAD that were not included in
7052             C<AutoLoader>. So the only solution was a merger.
7053              
7054             =head1 METHODS
7055              
7056             =head2 import
7057              
7058             B<import>() is used for the AutoLoader mechanism and hence is not a public method.
7059             It is just mentionned here for info only.
7060              
7061             =head2 new
7062              
7063             B<new> will create a new object for the package, pass any argument it might receive
7064             to the special standard routine B<init> that I<must> exist.
7065             Then it returns what returns L</"init">.
7066              
7067             To protect object inner content from sneaking by third party, you can declare the
7068             package global variable I<OBJECT_PERMS> and give it a Unix permission, but only 1 digit.
7069             It will then work just like Unix permission. That is, if permission is 7, then only the
7070             module who generated the object may read/write content of the object. However, if
7071             you set 5, the, other may look into the content of the object, but may not modify it.
7072             7, as you would have guessed, allow other to modify the content of an object.
7073             If I<OBJECT_PERMS> is not defined, permissions system is not activated and hence anyone
7074             may access and possibly modify the content of your object.
7075              
7076             If the module runs under mod_perl, it is recognised and a clean up registered routine is
7077             declared to Apache to clean up the content of the object.
7078              
7079             =head2 as_hash
7080              
7081             This will recursively transform the object into an hash suitable to be encoded in json.
7082              
7083             It does this by calling each method of the object and build an hash reference with the
7084             method name as the key and the method returned value as the value.
7085              
7086             If the method returned value is an object, it will call its L</"as_hash"> method if it supports it.
7087              
7088             It returns the hash reference built
7089              
7090             =head2 clear_error
7091              
7092             Clear all error from the object and from the available global variable C<$ERROR>.
7093              
7094             This is a handy method to use at the beginning of other methods of calling package,
7095             so the end user may do a test such as:
7096              
7097             $obj->some_method( 'some arguments' );
7098             die( $obj->error() ) if( $obj->error() );
7099              
7100             ## some_method() would then contain something like:
7101             sub some_method
7102             {
7103             my $self = shift( @_ );
7104             ## Clear all previous error, so we may set our own later one eventually
7105             $self->clear_error();
7106             ## ...
7107             }
7108              
7109             This way the end user may be sure that if C<$obj->error()> returns true something
7110             wrong has occured.
7111              
7112             =head2 clone
7113              
7114             Clone the current object if it is of type hash or array reference. It returns an error if the type is neither.
7115              
7116             It returns the clone.
7117              
7118             =head2 colour_closest
7119              
7120             Provided with a colour, this returns the closest standard one supported by terminal.
7121              
7122             A colour provided can be a colour name, or a 9 digits rgb value or an hexadecimal value
7123              
7124             =head2 colour_format
7125              
7126             Provided with a hash reference of parameters, this will return a string properly formatted to display colours on the command line.
7127              
7128             Parameters are:
7129              
7130             =over 4
7131              
7132             =item I<text> or I<message>
7133              
7134             This is the text to be formatted in colour.
7135              
7136             =item I<bgcolour> or I<bgcolor> or I<bg_colour> or I<bg_color>
7137              
7138             The value for the background colour.
7139              
7140             =item I<colour> or I<color> or I<fg_colour> or I<fg_color> or I<fgcolour> or I<fgcolor>
7141              
7142             The value for the foreground colour.
7143              
7144             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)>
7145              
7146             A colour can be preceded by the words C<light> or C<bright> to provide slightly lighter colour where supported.
7147              
7148             Similarly, if an rgba value is provided, and the opacity is less than 1, this is equivalent to using the keyword C<light>
7149              
7150             It returns the text properly formatted to be outputted in a terminal.
7151              
7152             =item I<style>
7153              
7154             The possible values are: I<bold>, I<italic>, I<underline>, I<blink>, I<reverse>, I<conceal>, I<strike>
7155              
7156             =back
7157              
7158             =head2 colour_parse
7159              
7160             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:
7161              
7162             $self->colour_parse( "And {style => 'i|b', color => green}what about{/} {style => 'blink', color => yellow}me{/} ?" );
7163              
7164             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).
7165              
7166             Another way is:
7167              
7168             $self->colour_parse( "And {bold light red on white}what about{/} {underline yellow}me too{/} ?" );
7169              
7170             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.
7171              
7172             $self->colour_parse( "Hello {bold red on white}everyone! This is {underline rgb(0,0,255)}embedded{/}{/} text..." );
7173              
7174             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
7175              
7176             The idea for this syntax, not the code, is taken from L<Term::ANSIColor>
7177              
7178             =head2 coloured
7179              
7180             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:
7181              
7182             print( $o->coloured( 'bold white on red', "Hello it's me!\n" ) );
7183              
7184             A colour can be expressed as a rgb, such as :
7185              
7186             print( $o->coloured( 'underline rgb( 0, 0, 255 ) on white', "Hello everyone!" ), "\n" );
7187              
7188             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 :
7189              
7190             print( $o->coloured( 'underline rgba(255, 0, 0, 0.5)', "Hello everyone!" ), "\n" );
7191              
7192             =head2 debug
7193              
7194             Set or get the debug level. This takes and return an integer.
7195              
7196             Based on the value, L</"message"> will or will not print out messages. For example :
7197              
7198             $self->debug( 2 );
7199             $self->message( 2, "Debugging message here." );
7200              
7201             Since C<2> used in L</"message"> is equal to the debug value, the debugging message is printed.
7202              
7203             If the debug value is switched to 1, the message will be silenced.
7204              
7205             =head2 dump
7206              
7207             Provided with some data, this will return a string representation of the data formatted by L<Data::Printer>
7208              
7209             =head2 dump_print
7210              
7211             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.
7212              
7213             =head2 dumper
7214              
7215             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.
7216              
7217             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.
7218              
7219             =head2 printer
7220              
7221             Same as L</"dumper">, but using L<Data::Printer> to format the data.
7222              
7223             =head2 dumpto_printer
7224              
7225             Same as L</"dump_print"> above that is an alias of this method.
7226              
7227             =head2 dumpto_dumper
7228              
7229             Same as L</"dumpto_printer"> above, but using L<Data::Dumper>
7230              
7231             =head2 error
7232              
7233             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:
7234              
7235             if( $some_condition )
7236             {
7237             return( $self->error( "Some error." ) );
7238             }
7239              
7240             Note that you do not have to worry about a trailing line feed sequence.
7241             B<error>() takes care of it.
7242              
7243             The script calling your module could write calls to your module methods like this:
7244              
7245             my $cust_name = $object->customer->name ||
7246             die( "Got an error in file ", $object->error->file, " at line ", $object->error->line, ": ", $object->error->trace, "\n" );
7247             # or simply:
7248             my $cust_name = $object->customer->name ||
7249             die( "Got an error: ", $object->error, "\n" );
7250              
7251             Note also that by calling B<error>() it will not clear the current error. For that
7252             you have to call B<clear_error>() explicitly.
7253              
7254             Also, when an error is set, the global variable I<ERROR> is set accordingly. This is
7255             especially usefull, when your initiating an object and that an error occured. At that
7256             time, since the object could not be initiated, the end user can not use the object to
7257             get the error message, and then can get it using the global module variable
7258             I<ERROR>, for example:
7259              
7260             my $obj = Some::Package->new ||
7261             die( $Some::Package::ERROR, "\n" );
7262              
7263             If the caller has disabled warnings using the pragma C<no warnings>, L</"error"> will
7264             respect it and not call B<warn>. Calling B<warn> can also be silenced if the object has
7265             a property I<quiet> set to true.
7266              
7267             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">
7268              
7269             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.
7270              
7271             If an Apache2 modperl log handler has been set, this will also be called to log the error.
7272              
7273             If the object property I<fatal> is set to true, this will call die instead of L<perlfunc/"warn">.
7274              
7275             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 :
7276              
7277             my $o = My::Package->new;
7278             my $total $o->get_customer(10)->products->total || die( $o->error, "\n" );
7279              
7280             Assuming this method here C<get_customer> returns an error, the chaining will continue, but produce nothing and ultimately returns undef.
7281              
7282             =head2 errors
7283              
7284             Used by B<error>() to store the error sent to him for history.
7285              
7286             It returns an array of all error that have occured in lsit context, and the last
7287             error in scalar context.
7288              
7289             =head2 errstr
7290              
7291             Set/get the error string, period. It does not produce any warning like B<error> would do.
7292              
7293             =head2 get
7294              
7295             Uset to get an object data key value:
7296              
7297             $obj->set( 'verbose' => 1, 'debug' => 0 );
7298             ## ...
7299             my $verbose = $obj->get( 'verbose' );
7300             my @vals = $obj->get( qw( verbose debug ) );
7301             print( $out "Verbose level is $vals[ 0 ] and debug level is $vals[ 1 ]\n" );
7302              
7303             This is no more needed, as it has been more conveniently bypassed by the AUTOLOAD
7304             generic routine with chich you may say:
7305              
7306             $obj->verbose( 1 );
7307             $obj->debug( 0 );
7308             ## ...
7309             my $verbose = $obj->verbose();
7310              
7311             Much better, no?
7312              
7313             =head2 init
7314              
7315             This is the L</"new"> package object initializer. It is called by L</"new">
7316             and is used to set up any parameter provided in a hash like fashion:
7317              
7318             my $obj My::Module->new( 'verbose' => 1, 'debug' => 0 );
7319              
7320             You may want to superseed L</"init"> to have suit your needs.
7321              
7322             L</"init"> needs to returns the object it received in the first place or an error if
7323             something went wrong, such as:
7324              
7325             sub init
7326             {
7327             my $self = shift( @_ );
7328             my $dbh = DB::Object->connect() ||
7329             return( $self->error( "Unable to connect to database server." ) );
7330             $self->{ 'dbh' } = $dbh;
7331             return( $self );
7332             }
7333              
7334             In this example, using L</"error"> will set the global variable C<$ERROR> that will
7335             contain the error, so user can say:
7336              
7337             my $obj = My::Module->new() || die( $My::Module::ERROR );
7338              
7339             If the global variable I<VERBOSE>, I<DEBUG>, I<VERSION> are defined in the module,
7340             and that they do not exist as an object key, they will be set automatically and
7341             accordingly to those global variable.
7342              
7343             The supported data type of the object generated by the L</"new"> method may either be
7344             a hash reference or a glob reference. Those supported data types may very well be
7345             extended to an array reference in a near future.
7346              
7347             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:
7348              
7349             sub init
7350             {
7351             my $self = shift( @_ );
7352             $self->{_init_strict} = 1;
7353             $self->{products} = [];
7354             return( $self->SUPER::init( @_ ) );
7355             }
7356              
7357             Then, if init is called like this:
7358              
7359             $object->init({ products => $some_string_but_not_array }) || die( $object->error, "\n" );
7360              
7361             This would cause your script to die, because C<products> value is a string and not an array reference.
7362              
7363             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 :
7364              
7365             sub init
7366             {
7367             my $self = shift( @_ );
7368             return( $self->SUPER::init( @_ ) );
7369             }
7370              
7371             Then, if init is called like this:
7372              
7373             $object->init( products => $array_ref, first_name => 'John', last_name => 'Doe' });
7374              
7375             The object would then contain the properties I<products>, I<first_name> and I<last_name> and can be accessed as methods, such as :
7376              
7377             my $fname = $object->first_name;
7378              
7379             =head2 log_handler
7380              
7381             Provided a reference to a sub routine or an anonymous sub routine, this will set the handler that is called by L</"message">
7382              
7383             It returns the current value set.
7384              
7385             =head2 message
7386              
7387             B<message>() is used to display verbose/debug output. It will display something
7388             to the extend that either I<verbose> or I<debug> are toggled on.
7389              
7390             If so, all debugging message will be prepended by C<## > to highlight the fact
7391             that this is a debugging message.
7392              
7393             Addionally, if a number is provided as first argument to B<message>(), it will be
7394             treated as the minimum required level of debugness. So, if the current debug
7395             state level is not equal or superior to the one provided as first argument, the
7396             message will not be displayed.
7397              
7398             For example:
7399              
7400             ## Set debugness to 3
7401             $obj->debug( 3 );
7402             ## This message will not be printed
7403             $obj->message( 4, "Some detailed debugging stuff that we might not want." );
7404             ## This will be displayed
7405             $obj->message( 2, "Some more common message we want the user to see." );
7406              
7407             Now, why debug is used and not verbose level? Well, because mostly, the verbose level
7408             needs only to be true, that is equal to 1 to be efficient. You do not really need to have
7409             a verbose level greater than 1. However, the debug level usually may have various level.
7410              
7411             Also, the text provided can be separated by comma, and even be a code reference, such as:
7412              
7413             $self->message( 2, "I have found", "something weird here:", sub{ $self->dumper( $data ) } );
7414              
7415             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:
7416              
7417             $self->noexec->message( 2, "I have found", "something weird here:", sub{ $self->dumper( $data ) } );
7418              
7419             =head2 message_check
7420              
7421             This is called by L</"message">
7422              
7423             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.
7424              
7425             =head2 message_colour
7426              
7427             This is the same as L</"message">, except this will check for colour formatting, which
7428             L</"message"> does not do. For example:
7429              
7430             $self->message_colour( 3, "And {bold light white on red}what about{/} {underline green}me again{/} ?" );
7431              
7432             L</"message_colour"> can also be called as B<message_color>
7433              
7434             See also L</"colour_format"> and L</"colour_parse">
7435              
7436             =head2 messagef
7437              
7438             This works like L<perlfunc/"sprintf">, so provided with a format and a list of arguments, this print out the message. For example :
7439              
7440             $self->messagef( 1, "Customer name is %s", $cust->name );
7441              
7442             Where 1 is the debug level set with L</"debug">
7443              
7444             =head2 messagef_colour
7445              
7446             This method is same as L</message_colour> and L<messagef> combined.
7447              
7448             It enables to pass sprintf-like parameters while enabling colours.
7449              
7450             =head2 message_log
7451              
7452             This is called from L</"message">.
7453              
7454             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.
7455              
7456             If no file handle is set, this returns undef, other it returns the value from C<$io->print>
7457              
7458             =head2 message_log_io
7459              
7460             Set or get the message log file handle. If set, L</"message_log"> will use it to print messages received from L</"message">
7461              
7462             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.
7463              
7464             It returns the current log file handle, if any.
7465              
7466             =head2 message_switch
7467              
7468             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">
7469              
7470             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.
7471              
7472             =head2 new_array
7473              
7474             Instantiate a new L<Module::Generic::Array> object. If any arguments are provided, it will pass it to L<Module::Generic::Array/new> and return the object.
7475              
7476             =head2 new_hash
7477              
7478             Instantiate a new L<Module::Generic::Hash> object. If any arguments are provided, it will pass it to L<Module::Generic::Hash/new> and return the object.
7479              
7480             =head2 new_number
7481              
7482             Instantiate a new L<Module::Generic::Number> object. If any arguments are provided, it will pass it to L<Module::Generic::Number/new> and return the object.
7483              
7484             =head2 new_scalar
7485              
7486             Instantiate a new L<Module::Generic::Scalar> object. If any arguments are provided, it will pass it to L<Module::Generic::Scalar/new> and return the object.
7487              
7488             =head2 noexec
7489              
7490             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:
7491              
7492             sub hello
7493             {
7494             return( "Hello !" );
7495             }
7496              
7497             And in your code, you write:
7498              
7499             $self->message( 2, "Someone said: ", \&hello );
7500              
7501             If I<_msg_no_exec_sub> is set to false (by default), then the above would print out the following message:
7502              
7503             Someone said Hello !
7504              
7505             But if I<_msg_no_exec_sub> is set to true, then the same would rather produce the following :
7506              
7507             Someone said CODE(0x7f9103801700)
7508              
7509             =head2 pass_error
7510              
7511             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.
7512              
7513             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 :
7514              
7515             sub getCustomerInfo
7516             {
7517             my $self = shift( @_ );
7518             # Maybe a LWP::UserAgent sub class?
7519             my $client = $self->lwp_client_object;
7520             my $res = $client->get( $remote_api_endpoint ) ||
7521             return( $self->pass_error( $client->error ) );
7522             }
7523              
7524             Then :
7525              
7526             my $client_info = $object->getCustomerInfo || die( $object->error, "\n" );
7527              
7528             Which would return the http client error that has been passed along
7529              
7530             =head2 quiet
7531              
7532             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.
7533              
7534             =head2 save
7535              
7536             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>.
7537              
7538             This is designed to simplify the tedious task of write to files.
7539              
7540             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.
7541              
7542             =head2 set
7543              
7544             B<set>() sets object inner data type and takes arguments in a hash like fashion:
7545              
7546             $obj->set( 'verbose' => 1, 'debug' => 0 );
7547              
7548             =head2 subclasses
7549              
7550             Provided with a I<CLASS> value, this method try to guess all the existing sub classes of the provided I<CLASS>.
7551              
7552             If I<CLASS> is not provided, the class into which was blessed the calling object will
7553             be used instead.
7554              
7555             It returns an array of subclasses in list context and a reference to an array of those
7556             subclasses in scalar context.
7557              
7558             If an error occured, undef is returned and an error is set accordingly. The latter can
7559             be retrieved using the B<error> method.
7560              
7561             =head2 true
7562              
7563             Returns a C<true> variable from L<Module::Generic::Boolean>
7564              
7565             =head2 false
7566              
7567             Returns a C<false> variable from L<Module::Generic::Boolean>
7568              
7569             =head2 verbose
7570              
7571             Set or get the verbosity level with an integer.
7572              
7573             =head2 will
7574              
7575             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.
7576              
7577             =head2 AUTOLOAD
7578              
7579             The special B<AUTOLOAD>() routine is called by perl when no matching routine was found
7580             in the module.
7581              
7582             B<AUTOLOAD>() will then try hard to process the request.
7583             For example, let's assue we have a routine B<foo>.
7584              
7585             It will first, check if an equivalent entry of the routine name that was called exist in
7586             the hash reference of the object. If there is and that more than one argument were
7587             passed to this non existing routine, those arguments will be stored as a reference to an
7588             array as a value of the key in the object. Otherwise the single argument will simply be stored
7589             as the value of the key of the object.
7590              
7591             Then, if called in list context, it will return a array if the value of the key entry was an array
7592             reference, or a hash list if the value of the key entry was a hash reference, or finally the value
7593             of the key entry.
7594              
7595             If this non existing routine that was called is actually defined, the routine will be redeclared and
7596             the arguments passed to it.
7597              
7598             If this fails too, it will try to check for an AutoLoadable file in C<auto/PackageName/routine_name.al>
7599              
7600             If the filed exists, it will be required, the routine name linked into the package name space and finally
7601             called with the arguments.
7602              
7603             If the require process failed or if the AutoLoadable routine file did not exist, B<AUTOLOAD>() will
7604             check if the special routine B<EXTRA_AUTOLOAD>() exists in the module. If it does, it will call it and pass
7605             it the arguments. Otherwise, B<AUTOLOAD> will die with a message explaining that the called routine did
7606             not exist and could not be found in the current class.
7607              
7608             =head1 SPECIAL METHODS
7609              
7610             =head2 __instantiate_object
7611              
7612             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">
7613              
7614             This is a support method used by L</"_instantiate_object">
7615              
7616             =head2 _instantiate_object
7617              
7618             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">
7619              
7620             =head2 _is_a
7621              
7622             Provided with an object and a package name and this will return true if the object is a blessed object from this package name (or a sub package of it), or false if not.
7623              
7624             The value of this is to reduce the burden of having to check whether the object actually exists, i.e. is not null or undef, if it is an object and if it is from that class. This allows to do it in just one method call like this:
7625              
7626             if( $self->_is_a( $obj, 'My::Package' ) )
7627             {
7628             # Do something
7629             }
7630              
7631             Of course, if you are sure the object is actually an object, then you can directly do:
7632              
7633             if( $obj->isa( 'My::Package' ) )
7634             {
7635             # Do something
7636             }
7637              
7638             =head2 _is_class_loaded
7639              
7640             Provided with a class/package name, this returns true if the module is already loaded or false otherwise.
7641              
7642             =head2 _is_array
7643              
7644             Provided with some data, this checks if the data is of type array, even if it is an object.
7645              
7646             This uses L<Scalar::Util/"reftype"> to achieve that purpose. So for example, an object such as :
7647              
7648             package My::Module;
7649              
7650             sub new
7651             {
7652             return( bless( [] => ( ref( $_[0] ) || $_[0] ) ) );
7653             }
7654              
7655             This would produce an object like :
7656              
7657             My::Module=ARRAY(0x7f8f3b035c20)
7658              
7659             When checked with L</"_is_array"> this, would return true just like an ordinary array.
7660              
7661             If you would use :
7662              
7663             ref( $object );
7664              
7665             It would rather return the module package name: C<My::Module>
7666              
7667             =head2 _is_hash
7668              
7669             Same as L</"_is_array">, but for hash reference.
7670              
7671             =head2 _is_object
7672              
7673             Provided with some data, this checks if the data is an object. It uses L<Scalar::Util/"blessed"> to achieve that purpose.
7674              
7675             =head2 _is_scalar
7676              
7677             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.
7678              
7679             =head2 _load_class
7680              
7681             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.
7682              
7683             =head2 _obj2h
7684              
7685             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.
7686              
7687             =head2 _parse_timestamp
7688              
7689             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.
7690              
7691             =head2 _set_get
7692              
7693             Provided with an object property name and some value and this will set or get that value for that property.
7694              
7695             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.
7696              
7697             =head2 _set_get_array
7698              
7699             Provided with an object property name and some data and this will store the data as an array reference.
7700              
7701             It returns the current value stored, such as an array reference notwithstanding it is called in list or scalar context.
7702              
7703             Example :
7704              
7705             sub products { return( shift->_set_get_array( 'products', @_ ) ); }
7706              
7707             =head2 _set_get_array_as_object
7708              
7709             Provided with an object property name and some data and this will store the data as an object of L<Module::Generic::Array>
7710              
7711             If this is called with no data set, an object is created with no data inside and returned
7712              
7713             Example :
7714              
7715             # In your module
7716             sub products { return( shift->_set_get_array_as_object( 'products', @_ ) ); }
7717              
7718             And using your method:
7719              
7720             printf( "There are %d products\n", $object->products->length );
7721             $object->products->push( $new_product );
7722              
7723             =head2 _set_get_boolean
7724              
7725             Provided with an object property name and some data and this will store the data as a boolean value.
7726              
7727             If the data provided is a L<JSON::PP::Boolean> or L<Module::Generic::Boolean> object, the data is stored as is.
7728              
7729             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.
7730              
7731             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.
7732              
7733             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.
7734              
7735             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.
7736              
7737             =head2 __create_class
7738              
7739             Provided with an object property name and an hash reference representing a dictionary and this will produce a dynamically created class/module.
7740              
7741             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 :
7742              
7743             sub products { return( 'products', shift->_set_get_class(
7744             {
7745             name => { type => 'scalar' },
7746             customer => { type => 'object', class => 'My::Customer' },
7747             orders => { type => 'array_as_object' },
7748             active => { type => 'boolean' },
7749             created => { type => 'datetime' },
7750             metadata => { type => 'hash' },
7751             stock => { type => 'number' },
7752             url => { type => 'uri' },
7753             }, @_ ) ); }
7754              
7755             Then calling your module method B<products> such as :
7756              
7757             my $prod = $object->products({
7758             name => 'Cool product',
7759             customer => { first_name => 'John', last_name => 'Doe', email => 'john.doe@example.com' },
7760             orders => [qw( 123 987 456 654 )],
7761             active => 1,
7762             metadata => { transaction_id => 123, api_call_id => 456 },
7763             stock => 10,
7764             uri => 'https://example.com/p/20'
7765             });
7766              
7767             Using the resulting object C<$prod>, we can access this dynamically created class/module such as :
7768              
7769             printf( <<EOT, $prod->name, $prod->orders->length, $prod->customer->last_name,, $prod->url->path )
7770             Product name: %s
7771             No of orders: %d
7772             Customer name: %s
7773             Product page path: %s
7774             EOT
7775              
7776             =head2 _set_get_class
7777              
7778             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">
7779              
7780             For example, consider the following:
7781              
7782             #!/usr/local/bin/perl
7783             BEGIN
7784             {
7785             use strict;
7786             use Data::Dumper;
7787             };
7788              
7789             {
7790             my $o = MyClass->new( debug => 3 );
7791             $o->setup->age( 42 );
7792             print( "Age is: ", $o->setup->age, "\n" );
7793             print( "Setup object is: ", $o->setup, "\n" );
7794             $o->setup->billing->interval( 'month' );
7795             print( "Billing interval is: ", $o->setup->billing->interval, "\n" );
7796             print( "Billing object is: ", $o->setup->billing, "\n" );
7797             $o->setup->rgb( 255, 122, 100 );
7798             print( "rgb: ", join( ', ', @{$o->setup->rgb} ), "\n" );
7799             exit( 0 );
7800             }
7801              
7802             package MyClass;
7803             BEGIN
7804             {
7805             use strict;
7806             use lib './lib';
7807             use parent qw( Module::Generic );
7808             };
7809              
7810             sub setup
7811             {
7812             return( shift->_set_get_class( 'setup',
7813             {
7814             name => { type => 'scalar' },
7815             age => { type => 'number' },
7816             metadata => { type => 'hash' },
7817             rgb => { type => 'array' },
7818             url => { type => 'uri' },
7819             online => { type => 'boolean' },
7820             created => { type => 'datetime' },
7821             billing => { type => 'class', definition =>
7822             {
7823             interval => { type => 'scalar' },
7824             frequency => { type => 'number' },
7825             nickname => { type => 'scalar' },
7826             }}
7827             }) );
7828             }
7829              
7830             1;
7831              
7832             __END__
7833              
7834             This will yield:
7835              
7836             Age is: 42
7837             Setup object is: MyClass::Setup=HASH(0x7fa805abcb20)
7838             Billing interval is: month
7839             Billing object is: MyClass::Setup::Billing=HASH(0x7fa804ec3f40)
7840             rgb: 255, 122, 100
7841              
7842             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.
7843              
7844             =head2 _set_get_class_array
7845              
7846             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 :
7847              
7848             sub products { return( shift->_set_get_class_array( 'products',
7849             {
7850             name => { type => 'scalar' },
7851             customer => { type => 'object', class => 'My::Customer' },
7852             orders => { type => 'array_as_object' },
7853             active => { type => 'boolean' },
7854             created => { type => 'datetime' },
7855             metadata => { type => 'hash' },
7856             stock => { type => 'number' },
7857             url => { type => 'uri' },
7858             }, @_ ) ); }
7859              
7860             Then your script would call this method like this :
7861              
7862             $object->products([
7863             { 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' },
7864             { 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' },
7865             ]);
7866              
7867             And this would store an array reference containing 2 objects with the above data.
7868              
7869             =head2 _set_get_code
7870              
7871             Provided with an object property name and some code reference and this stores and retrieve the current value.
7872              
7873             It returns under and set an error if the provided value is not a code reference.
7874              
7875             =head2 _set_get_datetime
7876              
7877             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.
7878              
7879             If the data is a 10 digits integer, this will treat it as a unix timestamp.
7880              
7881             Parsing also recognise special word such as C<now>
7882              
7883             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.
7884              
7885             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:
7886              
7887             $object->created->iso8601
7888              
7889             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.
7890              
7891             =head2 _set_get_hash
7892              
7893             Provided with an object property name and an hash reference and this set the property name with this hash reference.
7894              
7895             You can even pass it an associative array, and it will be saved as a hash reference, such as :
7896              
7897             $object->metadata(
7898             transaction_id => 123,
7899             customer_id => 456
7900             );
7901              
7902             my $hash = $object->metadata;
7903              
7904             =head2 _set_get_hash_as_mix_object
7905              
7906             Provided with an object property name, and an optional hash reference and this returns a L<Module::Generic::Hash> object, which allows to manipulate the hash just like any regular hash, but it provides on top object oriented method described in details in L<Module::Generic::Hash>.
7907              
7908             This is different from L</_set_get_hash_as_object> below whose keys and values are accessed as dynamic methods and method arguments.
7909              
7910             =head2 _set_get_hash_as_object
7911              
7912             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.
7913              
7914             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.
7915              
7916             For example in your module :
7917              
7918             sub metadata { return( shift->_set_get_hash_as_object( 'metadata', @_ ) ); }
7919              
7920             Then populating the data :
7921              
7922             $object->metadata({
7923             first_name => 'John',
7924             last_name => 'Doe',
7925             email => 'john.doe@example.com',
7926             });
7927              
7928             printf( "Customer name is %s\n", $object->metadata->last_name );
7929              
7930             =head2 _set_get_lvalue
7931              
7932             This helper method makes it very easy to implement a L<perlsub/"Lvalue subroutines"> method.
7933              
7934             package MyObject;
7935             use strict;
7936             use warnings;
7937             use parent qw( Module::Generic );
7938            
7939             sub debug : lvalue { return( shift->_set_get_lvalue( 'debug', @_ ) ); }
7940              
7941             And then, this method can be called either as a lvalue method:
7942              
7943             my $obj = MyObject->new;
7944             $obj->debug = 3;
7945              
7946             But also as a regular method:
7947              
7948             $obj->debug( 1 );
7949             printf( "Debug value is %d\n", $obj->debug );
7950              
7951             It uses L<Want> to achieve this. See also L<Sentinel>
7952              
7953             =head2 _set_get_number
7954              
7955             Provided with an object property name and a number, and this will create a L<Module::Generic::Number> object and return it.
7956              
7957             As of version v0.13.0 it also works as a lvalue method. See L<perlsub>
7958              
7959             In your module:
7960              
7961             package MyObject;
7962             use parent qw( Module::Generic );
7963            
7964             sub level : lvalue { return( shift->_set_get_number( 'level', @_ ) ); }
7965              
7966             In the script using module C<MyObject>:
7967              
7968             my $obj = MyObject->new;
7969             $obj->level = 3; # level is now 3
7970             # or
7971             $obj->level( 4 ) # level is now 4
7972             print( "Level is: ", $obj->level, "\n" ); # Level is 4
7973             print( "Is it an odd number: ", $obj->level->is_odd ? 'yes' : 'no', "\n" );
7974             # Is it an od number: no
7975             $obj->level++; # level is now 5
7976              
7977             =head2 _set_get_number_or_object
7978              
7979             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
7980              
7981             =head2 _set_get_object
7982              
7983             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.
7984              
7985             If you pass an undefined value, it will set the property as undefined, removing whatever was set before.
7986              
7987             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.
7988              
7989             It returns the object currently set, if any.
7990              
7991             =head2 _set_get_object_array2
7992              
7993             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.
7994              
7995             =head2 _set_get_object_array
7996              
7997             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.
7998              
7999             =head2 _set_get_object_array_object
8000              
8001             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>
8002              
8003             =head2 _set_get_object_variant
8004              
8005             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.
8006              
8007             This means the value stored for the object property will vary between an hash or array reference.
8008              
8009             =head2 _set_get_scalar
8010              
8011             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.
8012              
8013             It returns the currently value stored.
8014              
8015             =head2 _set_get_scalar_as_object
8016              
8017             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>
8018              
8019             If there is already an object set for this property, the value provided will be assigned to it using L<Module::Generic::Scalar/"set">
8020              
8021             If it is called and not value is set yet, this will instantiate a L<Module::Generic::Scalar> object with no value.
8022              
8023             So a call to this method can safely be chained to access the L<Module::Generic::Scalar> methods. For example :
8024              
8025             sub name { return( shift->_set_get_scalar_as_object( 'name', @_ ) ); }
8026              
8027             Then, calling it :
8028              
8029             $object->name( 'John Doe' );
8030              
8031             Getting the value :
8032              
8033             my $cust_name = $object->name;
8034             print( "Nothing set yet.\n" ) if( !$cust_name->length );
8035              
8036             =head2 _set_get_scalar_or_object
8037              
8038             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">
8039              
8040             If no value has been set yet, this returns a L<Module::Generic::Null> object to enable chaining.
8041              
8042             =head2 _set_get_uri
8043              
8044             Provided with an object property name, and an uri and this creates a L<URI> object and sets the property value accordingly.
8045              
8046             It accepts an L<URI> object, an uri or urn string, or an absolute path, i.e. a string starting with C</>.
8047              
8048             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 ?
8049              
8050             =head2 _to_array_object
8051              
8052             Provided with arguments or not, and this will return a L<Module::Generic::Array> object of those data.
8053              
8054             my $array = $self->_to_array_object( qw( Hello world ) ); # Becomes an array object of 'Hello' and 'world'
8055             my $array = $self->_to_array_object( [qw( Hello world )] ); # Becomes an array object of 'Hello' and 'world'
8056              
8057             =head2 __dbh
8058              
8059             if your module has the global variables C<DB_DSN>, this will create a database handler using L<DBI>
8060              
8061             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>
8062              
8063             If C<DB_SERVER_PREPARE> is provided and true, C<pg_server_prepare> will be set to true in the database handler.
8064              
8065             It returns the database handler object.
8066              
8067             =head2 DEBUG
8068              
8069             Return the value of your global variable I<DEBUG>, if any.
8070              
8071             =head2 VERBOSE
8072              
8073             Return the value of your global variable I<VERBOSE>, if any.
8074              
8075             =head1 SEE ALSO
8076              
8077             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>
8078              
8079             L<Number::Format>, L<Class::Load>, L<Scalar::Util>
8080              
8081             =head1 AUTHOR
8082              
8083             Jacques Deguest E<lt>F<jack@deguest.jp>E<gt>
8084              
8085             =head1 COPYRIGHT & LICENSE
8086              
8087             Copyright (c) 2000-2020 DEGUEST Pte. Ltd.
8088              
8089             You can use, copy, modify and redistribute this package and associated
8090             files under the same terms as Perl itself.
8091              
8092             =cut