line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
## -*- perl -*- |
2
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
3
|
|
|
|
|
|
|
## Module Generic - ~/lib/Module/Generic.pm |
4
|
|
|
|
|
|
|
## Version v0.12.16 |
5
|
|
|
|
|
|
|
## Copyright(c) 2020 DEGUEST Pte. Ltd. |
6
|
|
|
|
|
|
|
## Author: Jacques Deguest <@sitael.tokyo.deguest.jp> |
7
|
|
|
|
|
|
|
## Created 2019/08/24 |
8
|
|
|
|
|
|
|
## Modified 2020/06/19 |
9
|
|
|
|
|
|
|
## |
10
|
|
|
|
|
|
|
##---------------------------------------------------------------------------- |
11
|
|
|
|
|
|
|
package Module::Generic; |
12
|
|
|
|
|
|
|
BEGIN |
13
|
0
|
|
|
|
|
0
|
{ |
14
|
6
|
|
|
6
|
|
79
|
require 5.6.0; |
15
|
6
|
|
|
6
|
|
612373
|
use strict; |
|
6
|
|
|
|
|
62
|
|
|
6
|
|
|
|
|
191
|
|
16
|
6
|
|
|
6
|
|
38
|
use warnings::register; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
789
|
|
17
|
6
|
|
|
6
|
|
40
|
use Scalar::Util qw( openhandle ); |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
316
|
|
18
|
6
|
|
|
6
|
|
2763
|
use Sub::Util (); |
|
6
|
|
|
|
|
1531
|
|
|
6
|
|
|
|
|
132
|
|
19
|
6
|
|
|
6
|
|
2511
|
use Clone (); |
|
6
|
|
|
|
|
15380
|
|
|
6
|
|
|
|
|
162
|
|
20
|
6
|
|
|
6
|
|
3719
|
use Data::Dumper; |
|
6
|
|
|
|
|
40728
|
|
|
6
|
|
|
|
|
621
|
|
21
|
|
|
|
|
|
|
use Data::Printer |
22
|
|
|
|
|
|
|
{ |
23
|
|
|
|
|
|
|
sort_keys => 1, |
24
|
|
|
|
|
|
|
filters => |
25
|
|
|
|
|
|
|
{ |
26
|
0
|
|
|
|
|
0
|
'DateTime' => sub{ $_[0]->stringify }, |
27
|
|
|
|
|
|
|
} |
28
|
6
|
|
|
6
|
|
4014
|
}; |
|
6
|
|
|
|
|
241997
|
|
|
6
|
|
|
|
|
91
|
|
29
|
6
|
|
|
6
|
|
11428
|
use Devel::StackTrace; |
|
6
|
|
|
|
|
32499
|
|
|
6
|
|
|
|
|
220
|
|
30
|
6
|
|
|
6
|
|
3701
|
use Number::Format; |
|
6
|
|
|
|
|
38737
|
|
|
6
|
|
|
|
|
301
|
|
31
|
6
|
|
|
6
|
|
3626
|
use Nice::Try; |
|
6
|
|
|
|
|
669991
|
|
|
6
|
|
|
|
|
48
|
|
32
|
6
|
|
|
6
|
|
69591739
|
use B; |
|
6
|
|
|
|
|
20
|
|
|
6
|
|
|
|
|
534
|
|
33
|
|
|
|
|
|
|
## To get some context on what the caller expect. This is used in our error() method to allow chaining without breaking |
34
|
6
|
|
|
6
|
|
4353
|
use Want; |
|
6
|
|
|
|
|
11128
|
|
|
6
|
|
|
|
|
414
|
|
35
|
6
|
|
|
6
|
|
2846
|
use Class::Load (); |
|
6
|
|
|
|
|
37152
|
|
|
6
|
|
|
|
|
240
|
|
36
|
6
|
|
|
6
|
|
3161
|
use Encode (); |
|
6
|
|
|
|
|
83258
|
|
|
6
|
|
|
|
|
745
|
|
37
|
6
|
|
|
|
|
22
|
our( @ISA, @EXPORT_OK, @EXPORT, %EXPORT_TAGS, $AUTOLOAD ); |
38
|
6
|
|
|
|
|
9
|
our( $VERSION, $ERROR, $SILENT_AUTOLOAD, $VERBOSE, $DEBUG, $MOD_PERL ); |
39
|
6
|
|
|
|
|
11
|
our( $PARAM_CHECKER_LOAD_ERROR, $PARAM_CHECKER_LOADED, $CALLER_LEVEL ); |
40
|
6
|
|
|
|
|
10
|
our( $OPTIMIZE_MESG_SUB, $COLOUR_NAME_TO_RGB ); |
41
|
6
|
|
|
6
|
|
51
|
use Exporter (); |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
466
|
|
42
|
6
|
|
|
|
|
142
|
@ISA = qw( Exporter ); |
43
|
6
|
|
|
|
|
24
|
@EXPORT = qw( ); |
44
|
6
|
|
|
|
|
16
|
@EXPORT_OK = qw( subclasses ); |
45
|
6
|
|
|
|
|
82
|
%EXPORT_TAGS = (); |
46
|
6
|
|
|
|
|
13
|
$VERSION = 'v0.12.16'; |
47
|
6
|
|
|
|
|
11
|
$VERBOSE = 0; |
48
|
6
|
|
|
|
|
40
|
$DEBUG = 0; |
49
|
6
|
|
|
|
|
10
|
$SILENT_AUTOLOAD = 1; |
50
|
6
|
|
|
|
|
9
|
$PARAM_CHECKER_LOADED = 0; |
51
|
6
|
|
|
|
|
10
|
$CALLER_LEVEL = 0; |
52
|
6
|
|
|
|
|
9
|
$OPTIMIZE_MESG_SUB = 0; |
53
|
6
|
|
|
|
|
4485
|
$COLOUR_NAME_TO_RGB = {}; |
54
|
|
|
|
|
|
|
# local $^W; |
55
|
6
|
|
|
6
|
|
34
|
no strict qw(refs); |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
190
|
|
56
|
6
|
|
|
6
|
|
32
|
use constant COLOUR_OPEN => '<'; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
337
|
|
57
|
6
|
|
|
6
|
|
36
|
use constant COLOUR_CLOSE => '>'; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
287
|
|
58
|
|
|
|
|
|
|
}; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
INIT |
61
|
|
|
|
|
|
|
{ |
62
|
6
|
|
|
6
|
|
739
|
our $true = ${"Module::Generic::Boolean::true"}; |
|
6
|
|
|
|
|
49
|
|
63
|
6
|
|
|
|
|
15
|
our $false = ${"Module::Generic::Boolean::false"}; |
|
6
|
|
|
|
|
31
|
|
64
|
6
|
|
|
|
|
187
|
while( <DATA> ) |
65
|
|
|
|
|
|
|
{ |
66
|
0
|
|
|
|
|
0
|
chomp; |
67
|
0
|
|
|
|
|
0
|
print( "INIT: found colour data: '$_'\n" ); |
68
|
|
|
|
|
|
|
} |
69
|
|
|
|
|
|
|
}; |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
{ |
72
|
|
|
|
|
|
|
## mod_perl/2.0.10 |
73
|
|
|
|
|
|
|
if( exists( $ENV{ 'MOD_PERL' } ) |
74
|
|
|
|
|
|
|
&& |
75
|
|
|
|
|
|
|
( $MOD_PERL = $ENV{ 'MOD_PERL' } =~ /^mod_perl\/\d+\.[\d\.]+/ ) ) |
76
|
|
|
|
|
|
|
{ |
77
|
|
|
|
|
|
|
select( ( select( STDOUT ), $| = 1 )[ 0 ] ); |
78
|
|
|
|
|
|
|
require Apache2::Log; |
79
|
|
|
|
|
|
|
require Apache2::ServerUtil; |
80
|
|
|
|
|
|
|
require Apache2::RequestUtil; |
81
|
|
|
|
|
|
|
require Apache2::ServerRec; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
our $DEBUG_LOG_IO = undef(); |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
our $DB_NAME = $DATABASE; |
87
|
|
|
|
|
|
|
our $DB_HOST = $SQL_SERVER; |
88
|
|
|
|
|
|
|
our $DB_USER = $DB_LOGIN; |
89
|
|
|
|
|
|
|
our $DB_PWD = $DB_PASSWD; |
90
|
|
|
|
|
|
|
our $DB_RAISE_ERROR = $SQL_RAISE_ERROR; |
91
|
|
|
|
|
|
|
our $DB_AUTO_COMMIT = $SQL_AUTO_COMMIT; |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
sub import |
95
|
|
|
|
|
|
|
{ |
96
|
6
|
|
|
6
|
|
88
|
my $self = shift( @_ ); |
97
|
6
|
|
|
|
|
34
|
my( $pkg, $file, $line ) = caller(); |
98
|
6
|
|
|
|
|
35
|
local $Exporter::ExportLevel = 1; |
99
|
|
|
|
|
|
|
## local $Exporter::Verbose = $VERBOSE; |
100
|
6
|
|
|
|
|
161
|
Exporter::import( $self, @_ ); |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
##print( STDERR "Module::Generic::import(): called from package '$pkg' in file '$file' at line '$line'.\n" ) if( $DEBUG ); |
103
|
6
|
|
|
|
|
34
|
( my $dir = $pkg ) =~ s/::/\//g; |
104
|
6
|
|
|
|
|
25
|
my $path = $INC{ $dir . '.pm' }; |
105
|
|
|
|
|
|
|
##print( STDERR "Module::Generic::import(): using primary path of '$path'.\n" ) if( $DEBUG ); |
106
|
6
|
50
|
|
|
|
109
|
if( defined( $path ) ) |
107
|
|
|
|
|
|
|
{ |
108
|
|
|
|
|
|
|
## Try absolute path name |
109
|
0
|
|
|
|
|
0
|
$path =~ s/^(.*)$dir\.pm$/$1auto\/$dir\/autosplit.ix/; |
110
|
|
|
|
|
|
|
##print( STDERR "Module::Generic::import(): using treated path of '$path'.\n" ) if( $DEBUG ); |
111
|
|
|
|
|
|
|
eval |
112
|
0
|
|
|
|
|
0
|
{ |
113
|
0
|
|
|
0
|
|
0
|
local $SIG{ '__DIE__' } = sub{ }; |
114
|
0
|
|
|
0
|
|
0
|
local $SIG{ '__WARN__' } = sub{ }; |
115
|
0
|
|
|
|
|
0
|
require $path; |
116
|
|
|
|
|
|
|
}; |
117
|
0
|
0
|
|
|
|
0
|
if( $@ ) |
118
|
|
|
|
|
|
|
{ |
119
|
0
|
|
|
|
|
0
|
$path = "auto/$dir/autosplit.ix"; |
120
|
|
|
|
|
|
|
eval |
121
|
0
|
|
|
|
|
0
|
{ |
122
|
0
|
|
|
0
|
|
0
|
local $SIG{ '__DIE__' } = sub{ }; |
123
|
0
|
|
|
0
|
|
0
|
local $SIG{ '__WARN__' } = sub{ }; |
124
|
0
|
|
|
|
|
0
|
require $path; |
125
|
|
|
|
|
|
|
}; |
126
|
|
|
|
|
|
|
} |
127
|
0
|
0
|
|
|
|
0
|
if( $@ ) |
128
|
|
|
|
|
|
|
{ |
129
|
0
|
0
|
|
|
|
0
|
CORE::warn( $@ ) unless( $SILENT_AUTOLOAD ); |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
##print( STDERR "Module::Generic::import(): '$path' ", $@ ? 'not ' : '', "loaded.\n" ) if( $DEBUG ); |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub new |
136
|
|
|
|
|
|
|
{ |
137
|
133
|
|
|
133
|
1
|
426
|
my $that = shift( @_ ); |
138
|
133
|
|
66
|
|
|
722
|
my $class = ref( $that ) || $that; |
139
|
|
|
|
|
|
|
## my $pkg = ( caller() )[ 0 ]; |
140
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::new(): our calling package is '", ( caller() )[ 0 ], "', our class is '$class'.\n" ); |
141
|
133
|
|
|
|
|
358
|
my $self = {}; |
142
|
|
|
|
|
|
|
## print( STDERR "${class}::OBJECT_READONLY: ", ${ "${class}\::OBJECT_READONLY" }, "\n" ); |
143
|
133
|
50
|
|
|
|
435
|
if( defined( ${ "${class}\::OBJECT_PERMS" } ) ) |
|
133
|
|
|
|
|
1535
|
|
144
|
|
|
|
|
|
|
{ |
145
|
0
|
|
|
|
|
0
|
my %hash = (); |
146
|
|
|
|
|
|
|
my $obj = tie( |
147
|
|
|
|
|
|
|
%hash, |
148
|
|
|
|
|
|
|
'Module::Generic::Tie', |
149
|
|
|
|
|
|
|
'pkg' => [ __PACKAGE__, $class ], |
150
|
0
|
|
|
|
|
0
|
'perms' => ${ "${class}::OBJECT_PERMS" }, |
|
0
|
|
|
|
|
0
|
|
151
|
|
|
|
|
|
|
); |
152
|
0
|
|
|
|
|
0
|
$self = \%hash; |
153
|
|
|
|
|
|
|
} |
154
|
133
|
|
|
|
|
419
|
bless( $self, $class ); |
155
|
133
|
50
|
|
|
|
574
|
if( $MOD_PERL ) |
156
|
|
|
|
|
|
|
{ |
157
|
0
|
|
|
|
|
0
|
my $r = Apache2::RequestUtil->request; |
158
|
|
|
|
|
|
|
$r->pool->cleanup_register |
159
|
|
|
|
|
|
|
( |
160
|
|
|
|
|
|
|
sub |
161
|
|
|
|
|
|
|
{ |
162
|
|
|
|
|
|
|
## my( $pkg, $file, $line ) = caller(); |
163
|
|
|
|
|
|
|
## print( STDERR "Apache procedure: Deleting all the object keys for object '$self' and package '$class' called within package '$pkg' in file '$file' at line '$line'.\n" ); |
164
|
0
|
|
|
0
|
|
0
|
map{ delete( $self->{ $_ } ) } keys( %$self ); |
|
0
|
|
|
|
|
0
|
|
165
|
0
|
|
|
|
|
0
|
undef( %$self ); |
166
|
|
|
|
|
|
|
} |
167
|
0
|
|
|
|
|
0
|
); |
168
|
|
|
|
|
|
|
} |
169
|
133
|
50
|
|
|
|
293
|
if( defined( ${ "${class}\::LOG_DEBUG" } ) ) |
|
133
|
|
|
|
|
933
|
|
170
|
|
|
|
|
|
|
{ |
171
|
0
|
|
|
|
|
0
|
$self->{ 'log_debug' } = ${ "${class}::LOG_DEBUG" }; |
|
0
|
|
|
|
|
0
|
|
172
|
|
|
|
|
|
|
} |
173
|
133
|
|
|
|
|
680
|
return( $self->init( @_ ) ); |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
## This is used to transform package data set into hash refer suitable for api calls |
177
|
|
|
|
|
|
|
## If package use AUTOLOAD, those AUtILOAD should make sure to create methods on the fly so they become defined |
178
|
|
|
|
|
|
|
sub as_hash |
179
|
|
|
|
|
|
|
{ |
180
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
181
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
182
|
0
|
|
|
|
|
0
|
my $p = {}; |
183
|
0
|
0
|
0
|
|
|
0
|
$p = shift( @_ ) if( scalar( @_ ) == 1 && ref( $_[0] ) eq 'HASH' ); |
184
|
|
|
|
|
|
|
# $self->message( 3, "Parameters are: ", sub{ $self->dumper( $p ) } ); |
185
|
0
|
|
|
|
|
0
|
my $class = ref( $self ); |
186
|
6
|
|
|
6
|
|
51
|
no strict 'refs'; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
439
|
|
187
|
0
|
|
|
|
|
0
|
my @methods = grep{ defined &{"${class}::$_"} } keys( %{"${class}::"} ); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
188
|
|
|
|
|
|
|
# $self->messagef( 3, "The following methods found in package $class: '%s'.", join( "', '", sort( @methods ) ) ); |
189
|
6
|
|
|
6
|
|
35
|
use strict 'refs'; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
528
|
|
190
|
0
|
|
|
|
|
0
|
my $ref = {}; |
191
|
0
|
|
|
|
|
0
|
foreach my $meth ( sort( @methods ) ) |
192
|
|
|
|
|
|
|
{ |
193
|
0
|
0
|
|
|
|
0
|
next if( substr( $meth, 0, 1 ) eq '_' ); |
194
|
0
|
|
|
|
|
0
|
my $rv = eval{ $self->$meth }; |
|
0
|
|
|
|
|
0
|
|
195
|
0
|
0
|
|
|
|
0
|
if( $@ ) |
196
|
|
|
|
|
|
|
{ |
197
|
0
|
|
|
|
|
0
|
warn( "An error occured while accessing method $meth: $@\n" ); |
198
|
0
|
|
|
|
|
0
|
next; |
199
|
|
|
|
|
|
|
} |
200
|
6
|
|
|
6
|
|
43
|
no overloading; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
228
|
|
201
|
|
|
|
|
|
|
# $self->message( 3, "Value for method '$meth' is '$rv'." ); |
202
|
6
|
|
|
6
|
|
31
|
use overloading; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
10861
|
|
203
|
0
|
0
|
0
|
|
|
0
|
if( $p->{json} && ( ref( $rv ) eq 'JSON::PP::Boolean' || ref( $rv ) eq 'Module::Generic::Boolean' ) ) |
|
|
0
|
0
|
|
|
|
|
204
|
|
|
|
|
|
|
{ |
205
|
|
|
|
|
|
|
# $self->message( 3, "Encoding boolean to true or false for method '$meth'." ); |
206
|
0
|
|
|
|
|
0
|
$ref->{ $meth } = Module::Generic::Boolean::TO_JSON( $ref->{ $meth } ); |
207
|
0
|
|
|
|
|
0
|
next; |
208
|
|
|
|
|
|
|
} |
209
|
|
|
|
|
|
|
elsif( $self->_is_object( $rv ) ) |
210
|
|
|
|
|
|
|
{ |
211
|
0
|
0
|
0
|
|
|
0
|
if( $rv->can( 'as_hash' ) && overload::Overloaded( $rv ) && overload::Method( $rv, '""' ) ) |
|
|
0
|
0
|
|
|
|
|
212
|
|
|
|
|
|
|
{ |
213
|
0
|
|
|
|
|
0
|
$rv = $rv . ''; |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
elsif( $rv->can( 'as_hash' ) ) |
216
|
|
|
|
|
|
|
{ |
217
|
|
|
|
|
|
|
# $self->message( 3, "$rv is an object (", ref( $rv ), ") capable of as_hash, calling it." ); |
218
|
0
|
|
|
|
|
0
|
$rv = $rv->as_hash( $p ); |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
## $self->message( 3, "Checking field '$meth' with value '$rv'." ); |
223
|
|
|
|
|
|
|
|
224
|
0
|
0
|
|
|
|
0
|
if( ref( $rv ) eq 'HASH' ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
225
|
|
|
|
|
|
|
{ |
226
|
0
|
0
|
|
|
|
0
|
$ref->{ $meth } = $rv if( scalar( keys( %$rv ) ) ); |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
## If method call returned an array, like array of string or array of object such as in data from Net::API::Stripe::List |
229
|
|
|
|
|
|
|
elsif( ref( $rv ) eq 'ARRAY' ) |
230
|
|
|
|
|
|
|
{ |
231
|
0
|
|
|
|
|
0
|
my $arr = []; |
232
|
0
|
|
|
|
|
0
|
foreach my $this_ref ( @$rv ) |
233
|
|
|
|
|
|
|
{ |
234
|
0
|
0
|
0
|
|
|
0
|
my $that_ref = ( $self->_is_object( $this_ref ) && $this_ref->can( 'as_hash' ) ) ? $this_ref->as_hash : $this_ref; |
235
|
0
|
|
|
|
|
0
|
CORE::push( @$arr, $that_ref ); |
236
|
|
|
|
|
|
|
} |
237
|
0
|
0
|
|
|
|
0
|
$ref->{ $meth } = $arr if( scalar( @$arr ) ); |
238
|
|
|
|
|
|
|
} |
239
|
|
|
|
|
|
|
elsif( !ref( $rv ) ) |
240
|
|
|
|
|
|
|
{ |
241
|
0
|
0
|
|
|
|
0
|
$ref->{ $meth } = $rv if( CORE::length( $rv ) ); |
242
|
|
|
|
|
|
|
} |
243
|
|
|
|
|
|
|
elsif( CORE::length( "$rv" ) ) |
244
|
|
|
|
|
|
|
{ |
245
|
0
|
|
|
|
|
0
|
$self->message( 3, "Adding value '$rv' to field '$meth' in hash \$ref" ); |
246
|
0
|
|
|
|
|
0
|
$ref->{ $meth } = $rv; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
} |
249
|
0
|
|
|
|
|
0
|
return( $ref ); |
250
|
|
|
|
|
|
|
} |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
sub clear |
253
|
|
|
|
|
|
|
{ |
254
|
0
|
|
|
0
|
0
|
0
|
goto( &clear_error ); |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
sub clear_error |
258
|
|
|
|
|
|
|
{ |
259
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
260
|
0
|
|
0
|
|
|
0
|
my $class = ref( $self ) || $self; |
261
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
262
|
0
|
|
|
|
|
0
|
$this->{error} = ${ "$class\::ERROR" } = ''; |
|
0
|
|
|
|
|
0
|
|
263
|
0
|
|
|
|
|
0
|
return( 1 ); |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
# sub clone |
267
|
|
|
|
|
|
|
# { |
268
|
|
|
|
|
|
|
# my $self = shift( @_ ); |
269
|
|
|
|
|
|
|
# if( Scalar::Util::reftype( $self ) eq 'HASH' ) |
270
|
|
|
|
|
|
|
# { |
271
|
|
|
|
|
|
|
# return( bless( { %$self } => ( ref( $self ) || $self ) ) ); |
272
|
|
|
|
|
|
|
# } |
273
|
|
|
|
|
|
|
# elsif( Scalar::Util::reftype( $self ) eq 'ARRAY' ) |
274
|
|
|
|
|
|
|
# { |
275
|
|
|
|
|
|
|
# return( bless( [ @$self ] => ( ref( $self ) || $self ) ) ); |
276
|
|
|
|
|
|
|
# } |
277
|
|
|
|
|
|
|
# else |
278
|
|
|
|
|
|
|
# { |
279
|
|
|
|
|
|
|
# return( $self->error( "Cloning is unsupported for type \"", ref( $self ), "\". Only hash or array references are supported." ) ); |
280
|
|
|
|
|
|
|
# } |
281
|
|
|
|
|
|
|
# } |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
sub clone |
284
|
|
|
|
|
|
|
{ |
285
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
286
|
0
|
|
|
|
|
0
|
try |
287
|
0
|
|
|
0
|
|
0
|
{ |
288
|
0
|
|
|
|
|
0
|
$self->message( 3, "Cloning object '", overload::StrVal( $self ), "'." ); |
289
|
0
|
|
|
|
|
0
|
return( Clone::clone( $self ) ); |
290
|
|
|
|
|
|
|
} |
291
|
0
|
0
|
|
|
|
0
|
catch( $e ) |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
292
|
0
|
|
|
0
|
|
0
|
{ |
293
|
0
|
|
|
|
|
0
|
return( $self->error( "Error cloning object \"", overload::StrVal( $self ), "\": $e" ) ); |
294
|
0
|
0
|
0
|
|
|
0
|
} |
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
2
|
|
|
2
|
0
|
7
|
sub colour_close { return( shift->_set_get( 'colour_close', @_ ) ); } |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
sub colour_closest |
300
|
|
|
|
|
|
|
{ |
301
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
302
|
0
|
|
|
|
|
0
|
my $colour = uc( shift( @_ ) ); |
303
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
304
|
0
|
|
|
|
|
0
|
my $colours = |
305
|
|
|
|
|
|
|
{ |
306
|
|
|
|
|
|
|
'000000000' => 'black', |
307
|
|
|
|
|
|
|
'000000255' => 'blue', |
308
|
|
|
|
|
|
|
'000255000' => 'green', |
309
|
|
|
|
|
|
|
'000255255' => 'cyan', |
310
|
|
|
|
|
|
|
'255000000' => 'red', |
311
|
|
|
|
|
|
|
'255000255' => 'magenta', |
312
|
|
|
|
|
|
|
'255255000' => 'yellow', |
313
|
|
|
|
|
|
|
'255255255' => 'white', |
314
|
|
|
|
|
|
|
}; |
315
|
0
|
|
|
|
|
0
|
my( $red, $green, $blue ) = ( '', '', '' ); |
316
|
0
|
0
|
|
|
|
0
|
if( $colour =~ /^[A-Z]+([A-Z\s]+)*$/ ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
317
|
|
|
|
|
|
|
{ |
318
|
0
|
0
|
|
|
|
0
|
if( !scalar( keys( %$COLOUR_NAME_TO_RGB ) ) ) |
319
|
|
|
|
|
|
|
{ |
320
|
|
|
|
|
|
|
## $self->message( 3, "Processing colour map in <DATA> section." ); |
321
|
0
|
|
|
|
|
0
|
while( <DATA> ) |
322
|
|
|
|
|
|
|
{ |
323
|
0
|
|
|
|
|
0
|
chomp; |
324
|
0
|
0
|
|
|
|
0
|
next if( /^[[:blank:]]*$/ ); |
325
|
0
|
0
|
|
|
|
0
|
last if( /^\=/ ); |
326
|
0
|
|
|
|
|
0
|
my( $r, $g, $b, $name ) = split( /[[:blank:]]+/, $_, 4 ); |
327
|
0
|
|
|
|
|
0
|
$COLOUR_NAME_TO_RGB->{ lc( $name ) } = [ $r, $g, $b ]; |
328
|
|
|
|
|
|
|
} |
329
|
0
|
|
|
|
|
0
|
close( DATA ); |
330
|
|
|
|
|
|
|
} |
331
|
0
|
0
|
|
|
|
0
|
if( CORE::exists( $COLOUR_NAME_TO_RGB->{ lc( $colour ) } ) ) |
332
|
|
|
|
|
|
|
{ |
333
|
0
|
|
|
|
|
0
|
( $red, $green, $blue ) = @{$COLOUR_NAME_TO_RGB->{ lc( $colour ) }}; |
|
0
|
|
|
|
|
0
|
|
334
|
|
|
|
|
|
|
} |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
## Colour all in decimal?? |
337
|
|
|
|
|
|
|
elsif( $colour =~ /^\d{9}$/ ) |
338
|
|
|
|
|
|
|
{ |
339
|
|
|
|
|
|
|
## $self->message( 3, "Got colour all in decimal. Less work to do..." ); |
340
|
0
|
|
|
|
|
0
|
$red = substr( $colour, 0, 3 ); |
341
|
0
|
|
|
|
|
0
|
$green = substr( $colour, 3, 3 ); |
342
|
0
|
|
|
|
|
0
|
$blue = substr( $colour, 6, 3 ); |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
## Colour in hexadecimal, convert it |
345
|
|
|
|
|
|
|
elsif( $colour =~ /^[A-F0-9]+$/ ) |
346
|
|
|
|
|
|
|
{ |
347
|
0
|
|
|
|
|
0
|
$red = hex( substr( $colour, 0, 2 ) ); |
348
|
0
|
|
|
|
|
0
|
$green = hex( substr( $colour, 2, 2 ) ); |
349
|
0
|
|
|
|
|
0
|
$blue = hex( substr( $colour, 4, 2 ) ); |
350
|
|
|
|
|
|
|
} |
351
|
|
|
|
|
|
|
## Clueless |
352
|
|
|
|
|
|
|
else |
353
|
|
|
|
|
|
|
{ |
354
|
|
|
|
|
|
|
## Not undef, but rather empty string. Undef is associated with an error |
355
|
0
|
|
|
|
|
0
|
return( '' ); |
356
|
|
|
|
|
|
|
} |
357
|
0
|
|
|
|
|
0
|
my $dec_colour = CORE::sprintf( '%3d%3d%3d', $red, $green, $blue ); |
358
|
0
|
|
|
|
|
0
|
my $last = ''; |
359
|
0
|
|
|
|
|
0
|
my @colours = reverse( sort( keys( %$colours ) ) ); |
360
|
0
|
|
|
|
|
0
|
$red = CORE::sprintf( '%03d', $red ); |
361
|
0
|
|
|
|
|
0
|
$green = CORE::sprintf( '%03d', $green ); |
362
|
0
|
|
|
|
|
0
|
$blue = CORE::sprintf( '%03d', $blue ); |
363
|
0
|
|
|
|
|
0
|
my $cur = CORE::sprintf( '%03d%03d%03d', $red, $green, $blue ); |
364
|
0
|
|
|
|
|
0
|
my( $red_ok, $green_ok, $blue_ok ) = ( 0, 0, 0 ); |
365
|
|
|
|
|
|
|
## $self->message( 3, "Current colour: '$cur'." ); |
366
|
0
|
|
|
|
|
0
|
for( my $i = 0; $i < scalar( @colours ); $i++ ) |
367
|
|
|
|
|
|
|
{ |
368
|
0
|
|
|
|
|
0
|
my $r = CORE::sprintf( '%03d', substr( $colours[ $i ], 0, 3 ) ); |
369
|
0
|
|
|
|
|
0
|
my $g = CORE::sprintf( '%03d', substr( $colours[ $i ], 3, 3 ) ); |
370
|
0
|
|
|
|
|
0
|
my $b = CORE::sprintf( '%03d', substr( $colours[ $i ], 6, 3 ) ); |
371
|
|
|
|
|
|
|
|
372
|
0
|
|
|
|
|
0
|
my $r_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 0, 3 ) ); |
373
|
0
|
|
|
|
|
0
|
my $g_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 3, 3 ) ); |
374
|
0
|
|
|
|
|
0
|
my $b_p = CORE::sprintf( '%03d', substr( $colours[ $i - 1 ], 6, 3 ) ); |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
## $self->message( 3, "$r ($red), $g ($green), $b ($blue)" ); |
377
|
0
|
0
|
0
|
|
|
0
|
if( $red == $r || |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
378
|
|
|
|
|
|
|
( $red < $r && $red > int( $r / 2 ) ) || |
379
|
|
|
|
|
|
|
( $red > $r && $red < int( $r_p / 2 ) && $r_p ) || |
380
|
|
|
|
|
|
|
$red > $r ) |
381
|
|
|
|
|
|
|
{ |
382
|
0
|
|
|
|
|
0
|
$red_ok++; |
383
|
|
|
|
|
|
|
} |
384
|
|
|
|
|
|
|
|
385
|
0
|
0
|
|
|
|
0
|
if( $red_ok ) |
386
|
|
|
|
|
|
|
{ |
387
|
0
|
0
|
0
|
|
|
0
|
if( $green == $g || |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
388
|
|
|
|
|
|
|
( $green < $g && $green > int( $g / 2 ) ) || |
389
|
|
|
|
|
|
|
( $green > $g && $green < int( $g_p / 2 ) && $g_p ) || |
390
|
|
|
|
|
|
|
$green > $g ) |
391
|
|
|
|
|
|
|
{ |
392
|
0
|
|
|
|
|
0
|
$blue_ok++; |
393
|
|
|
|
|
|
|
} |
394
|
|
|
|
|
|
|
} |
395
|
|
|
|
|
|
|
|
396
|
0
|
0
|
|
|
|
0
|
if( $blue_ok ) |
397
|
|
|
|
|
|
|
{ |
398
|
0
|
0
|
0
|
|
|
0
|
if( $blue == $b || |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
399
|
|
|
|
|
|
|
( $blue < $b && $blue > int( $b / 2 ) ) || |
400
|
|
|
|
|
|
|
( $blue > $b && $blue < int( $b_p / 2 ) && $b_p ) || |
401
|
|
|
|
|
|
|
$blue > $b ) |
402
|
|
|
|
|
|
|
{ |
403
|
0
|
|
|
|
|
0
|
$last = $colours[ $i ]; |
404
|
0
|
|
|
|
|
0
|
last; |
405
|
|
|
|
|
|
|
} |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
} |
408
|
0
|
|
|
|
|
0
|
return( $colours->{ $last } ); |
409
|
|
|
|
|
|
|
} |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
sub colour_format |
412
|
|
|
|
|
|
|
{ |
413
|
12
|
|
|
12
|
1
|
20
|
my $self = shift( @_ ); |
414
|
|
|
|
|
|
|
## style, colour or color and text |
415
|
12
|
|
|
|
|
15
|
my $opts = shift( @_ ); |
416
|
12
|
50
|
|
|
|
26
|
return( $self->error( "Parameter hash provided is not an hash reference." ) ) if( !$self->_is_hash( $opts ) ); |
417
|
12
|
|
|
|
|
22
|
my $this = $self->_obj2h; |
418
|
|
|
|
|
|
|
## To make it possible to use either text or message property |
419
|
12
|
50
|
33
|
|
|
32
|
$opts->{text} = CORE::delete( $opts->{message} ) if( CORE::length( $opts->{message} ) && !CORE::length( $opts->{text} ) ); |
420
|
12
|
50
|
|
|
|
23
|
return( $self->error( "No text was provided to format." ) ) if( !CORE::length( $opts->{text} ) ); |
421
|
|
|
|
|
|
|
|
422
|
12
|
|
0
|
|
|
35
|
$opts->{colour} //= CORE::delete( $opts->{color} ) || CORE::delete( $opts->{fg_colour} ) || CORE::delete( $opts->{fg_color} ) || CORE::delete( $opts->{fgcolour} ) || CORE::delete( $opts->{fgcolor} ); |
|
|
|
66
|
|
|
|
|
423
|
12
|
|
66
|
|
|
79
|
$opts->{bgcolour} //= CORE::delete( $opts->{bgcolor} ) || CORE::delete( $opts->{bg_colour} ) || CORE::delete( $opts->{bg_color} ); |
|
|
|
66
|
|
|
|
|
424
|
|
|
|
|
|
|
|
425
|
12
|
|
|
|
|
16
|
my $bold = "\e[1m"; |
426
|
12
|
|
|
|
|
17
|
my $underline = "\e[4m"; |
427
|
12
|
|
|
|
|
14
|
my $reverse = "\e[7m"; |
428
|
12
|
|
|
|
|
13
|
my $normal = "\e[m"; |
429
|
12
|
|
|
|
|
14
|
my $cls = "\e[H\e[2J"; |
430
|
12
|
|
|
|
|
117
|
my $styles = |
431
|
|
|
|
|
|
|
{ |
432
|
|
|
|
|
|
|
# Bold |
433
|
|
|
|
|
|
|
b => 1, |
434
|
|
|
|
|
|
|
bold => 1, |
435
|
|
|
|
|
|
|
strong => 1, |
436
|
|
|
|
|
|
|
# Italic |
437
|
|
|
|
|
|
|
i => 3, |
438
|
|
|
|
|
|
|
italic => 3, |
439
|
|
|
|
|
|
|
# Underline |
440
|
|
|
|
|
|
|
u => 4, |
441
|
|
|
|
|
|
|
underline => 4, |
442
|
|
|
|
|
|
|
underlined => 4, |
443
|
|
|
|
|
|
|
blink => 5, |
444
|
|
|
|
|
|
|
# Reverse |
445
|
|
|
|
|
|
|
r => 7, |
446
|
|
|
|
|
|
|
reverse => 7, |
447
|
|
|
|
|
|
|
reversed => 7, |
448
|
|
|
|
|
|
|
# Concealed |
449
|
|
|
|
|
|
|
c => 8, |
450
|
|
|
|
|
|
|
conceal => 8, |
451
|
|
|
|
|
|
|
concealed => 8, |
452
|
|
|
|
|
|
|
strike => 9, |
453
|
|
|
|
|
|
|
striked => 9, |
454
|
|
|
|
|
|
|
striken => 9, |
455
|
|
|
|
|
|
|
}; |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
local $convert_24_To_8bits = sub |
458
|
|
|
|
|
|
|
{ |
459
|
17
|
|
|
17
|
|
35
|
my( $r, $g, $b ) = @_; |
460
|
17
|
|
|
|
|
58
|
$self->message( 9, "Converting $r, $g, $b to 8 bits" ); |
461
|
17
|
|
|
|
|
168
|
return( ( POSIX::floor( $r * 7 / 255 ) << 5 ) + |
462
|
|
|
|
|
|
|
( POSIX::floor( $g * 7 / 255 ) << 2 ) + |
463
|
|
|
|
|
|
|
( POSIX::floor( $b * 3 / 255 ) ) |
464
|
|
|
|
|
|
|
); |
465
|
12
|
|
|
|
|
54
|
}; |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
## opacity * original + (1-opacity)*background = resulting pixel |
468
|
|
|
|
|
|
|
## https://stackoverflow.com/a/746934/4814971 |
469
|
|
|
|
|
|
|
local $colour_with_alpha = sub |
470
|
|
|
|
|
|
|
{ |
471
|
1
|
|
|
1
|
|
3
|
my( $r, $g, $b, $a, $bg ) = @_; |
472
|
|
|
|
|
|
|
## Assuming a white background (255) |
473
|
1
|
|
|
|
|
2
|
my( $bg_r, $bg_g, $bg_b ) = ( 255, 255, 255 ); |
474
|
1
|
50
|
|
|
|
4
|
if( ref( $bg ) eq 'HASH' ) |
475
|
|
|
|
|
|
|
{ |
476
|
1
|
|
|
|
|
3
|
( $bg_r, $bg_g, $bg_b ) = @$bg{qw( red green blue )}; |
477
|
|
|
|
|
|
|
} |
478
|
1
|
|
|
|
|
7
|
$r = POSIX::round( ( $a * $r ) + ( ( 1 - $a ) * $bg_r ) ); |
479
|
1
|
|
|
|
|
4
|
$g = POSIX::round( ( $a * $g ) + ( ( 1 - $a ) * $bg_g ) ); |
480
|
1
|
|
|
|
|
3
|
$b = POSIX::round( ( $a * $b ) + ( ( 1 - $a ) * $bg_b ) ); |
481
|
1
|
|
|
|
|
3
|
return( [$r, $g, $b] ); |
482
|
12
|
|
|
|
|
43
|
}; |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
local $check_colour = sub |
485
|
|
|
|
|
|
|
{ |
486
|
18
|
|
|
18
|
|
26
|
my $col = shift( @_ ); |
487
|
|
|
|
|
|
|
## $self->message( 3, "Checking colour '$col'." ); |
488
|
|
|
|
|
|
|
## $colours or $bg_colours |
489
|
18
|
|
|
|
|
26
|
my $map = shift( @_ ); |
490
|
18
|
|
|
|
|
27
|
my $code; |
491
|
|
|
|
|
|
|
my $light; |
492
|
|
|
|
|
|
|
## Example: 'light red' or 'light_red' |
493
|
18
|
100
|
|
|
|
108
|
if( $col =~ /^(?:(?<light>bright|light)[[:blank:]\_]+)? |
|
|
50
|
|
|
|
|
|
494
|
|
|
|
|
|
|
(?<colour> |
495
|
|
|
|
|
|
|
(?:[a-zA-Z]+)(?:[[:blank:]]+\w+)? |
496
|
|
|
|
|
|
|
| |
497
|
|
|
|
|
|
|
(?<rgb_type>rgb[a]?)\([[:blank:]]*(?<red>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<green>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<blue>\d{1,3}) |
498
|
|
|
|
|
|
|
(?:[[:blank:]]*\,[[:blank:]]*(?<opacity>\d(?:\.\d+)?))?[[:blank:]]* |
499
|
|
|
|
|
|
|
\) |
500
|
|
|
|
|
|
|
)$/xi ) |
501
|
|
|
|
|
|
|
{ |
502
|
6
|
|
|
6
|
|
2994
|
my %regexp = %+; |
|
6
|
|
|
|
|
2456
|
|
|
6
|
|
|
|
|
37148
|
|
|
17
|
|
|
|
|
168
|
|
503
|
17
|
|
|
|
|
100
|
$self->message( 9, "Light colour request '$col'. Capture: ", sub{ $self->dumper( \%regexp ) } ); |
|
0
|
|
|
|
|
0
|
|
504
|
17
|
|
|
|
|
124
|
( $light, $col ) = ( $+{light}, $+{colour} ); |
505
|
17
|
100
|
66
|
|
|
97
|
if( CORE::length( $+{rgb_type} ) && |
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
506
|
|
|
|
|
|
|
CORE::length( $+{red} ) && |
507
|
|
|
|
|
|
|
CORE::length( $+{green} ) && |
508
|
|
|
|
|
|
|
CORE::length( $+{blue} ) ) |
509
|
|
|
|
|
|
|
{ |
510
|
3
|
100
|
66
|
|
|
20
|
if( $+{opacity} || $light ) |
511
|
|
|
|
|
|
|
{ |
512
|
|
|
|
|
|
|
my $opacity = CORE::length( $+{opacity} ) |
513
|
|
|
|
|
|
|
? $+{opacity} |
514
|
1
|
0
|
|
|
|
6
|
: $light |
|
|
50
|
|
|
|
|
|
515
|
|
|
|
|
|
|
? 0.5 |
516
|
|
|
|
|
|
|
: 1; |
517
|
1
|
|
|
|
|
21
|
$col = CORE::sprintf( 'rgba(%03d%03d%03d,%.1f)', $+{red}, $+{green}, $+{blue}, $opacity ); |
518
|
|
|
|
|
|
|
} |
519
|
|
|
|
|
|
|
else |
520
|
|
|
|
|
|
|
{ |
521
|
2
|
|
|
|
|
24
|
$col = CORE::sprintf( 'rgb(%03d%03d%03d)', $+{red}, $+{green}, $+{blue} ); |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
else |
525
|
|
|
|
|
|
|
{ |
526
|
14
|
|
|
|
|
41
|
$self->message( 9, "Colour '$col' is not rgb[a]" ); |
527
|
|
|
|
|
|
|
} |
528
|
|
|
|
|
|
|
} |
529
|
|
|
|
|
|
|
elsif( $col =~ /^(?<rgb_type>rgb[a]?)\([[:blank:]]*(?<red>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<green>\d{1,3})[[:blank:]]*\,[[:blank:]]*(?<blue>\d{1,3})[[:blank:]]*(?:\,[[:blank:]]*(?<opacity>\d(?:\.\d+)?))?[[:blank:]]*\)$/i ) |
530
|
|
|
|
|
|
|
{ |
531
|
0
|
0
|
|
|
|
0
|
if( $+{opacity} ) |
532
|
|
|
|
|
|
|
{ |
533
|
0
|
|
|
|
|
0
|
$col = CORE::sprintf( 'rgba(%03d%03d%03d,%.1f)', $+{red}, $+{green}, $+{blue}, $+{opacity} ); |
534
|
|
|
|
|
|
|
} |
535
|
|
|
|
|
|
|
else |
536
|
|
|
|
|
|
|
{ |
537
|
0
|
|
|
|
|
0
|
$col = CORE::sprintf( '%03d%03d%03d', $+{red}, $+{green}, $+{blue} ); |
538
|
|
|
|
|
|
|
} |
539
|
|
|
|
|
|
|
} |
540
|
|
|
|
|
|
|
else |
541
|
|
|
|
|
|
|
{ |
542
|
1
|
|
|
|
|
6
|
$self->message( 9, "Colour '$col' failed to match our rgba regexp." ); |
543
|
|
|
|
|
|
|
} |
544
|
|
|
|
|
|
|
|
545
|
18
|
|
|
|
|
33
|
my $col_ref; |
546
|
18
|
100
|
66
|
|
|
78
|
if( $col =~ /^rgb[a]?\((?<red>\d{3})(?<green>\d{3})(?<blue>\d{3})\)$/i ) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
547
|
|
|
|
|
|
|
{ |
548
|
3
|
|
|
|
|
6
|
$col_ref = {}; |
549
|
3
|
|
|
|
|
54
|
%$col_ref = %+; |
550
|
3
|
|
|
|
|
39
|
$self->message( 9, "Rgb colour '$+{red}', '$+{green}' and '$+{blue}' found: ", sub{ $self->dumper( $col_ref ) }); |
|
0
|
|
|
|
|
0
|
|
551
|
|
|
|
|
|
|
return({ |
552
|
|
|
|
|
|
|
_24bits => [@$col_ref{qw( red green blue )}], |
553
|
3
|
|
|
|
|
22
|
_8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} ) |
554
|
|
|
|
|
|
|
}); |
555
|
|
|
|
|
|
|
} |
556
|
|
|
|
|
|
|
## Treating opacity to make things lighter; not ideal, but standard scheme |
557
|
|
|
|
|
|
|
elsif( $col =~ /^rgba\((?<red>\d{3})(?<green>\d{3})(?<blue>\d{3})[[:blank:]]*\,[[:blank:]]*(?<opacity>\d(?:\.\d)?)\)$/i ) |
558
|
|
|
|
|
|
|
{ |
559
|
1
|
|
|
|
|
2
|
$col_ref = {}; |
560
|
1
|
|
|
|
|
11
|
%$col_ref = %+; |
561
|
1
|
|
|
|
|
13
|
$self->message( 9, "Rgba colour '$+{red}', '$+{green}' and '$+{blue}' found with opacity $+{opacity}: ", sub{ $self->dumper( $col_ref ) }); |
|
0
|
|
|
|
|
0
|
|
562
|
1
|
50
|
|
|
|
8
|
if( $+{opacity} ) |
563
|
|
|
|
|
|
|
{ |
564
|
1
|
|
|
|
|
4
|
my $opacity = $+{opacity}; |
565
|
1
|
|
|
|
|
5
|
$self->message( 9, "Opacity of $opacity found, applying the factor to the colour." ); |
566
|
1
|
|
|
|
|
1
|
my $bg; |
567
|
1
|
50
|
|
|
|
3
|
if( $opts->{bgcolour} ) |
568
|
|
|
|
|
|
|
{ |
569
|
1
|
|
|
|
|
4
|
$bg = $self->colour_to_rgb( $opts->{bgcolour} ); |
570
|
1
|
|
|
|
|
5
|
$self->message( 9, "Calculating new rgb with opacity and background information: ", sub{ $self->dumper( $bg ) }); |
|
0
|
|
|
|
|
0
|
|
571
|
|
|
|
|
|
|
} |
572
|
1
|
|
|
|
|
5
|
my $new_col = $colour_with_alpha->( @$col_ref{qw( red green blue )}, $opacity, $bg ); |
573
|
1
|
|
|
|
|
6
|
$self->message( 9, "New colour with opacity applied: ", sub{ $self->dumper( $new_col ) }); |
|
0
|
|
|
|
|
0
|
|
574
|
1
|
|
|
|
|
4
|
@$col_ref{qw( red green blue )} = @$new_col; |
575
|
1
|
|
|
|
|
17
|
$self->message( 9, "Colour $+{red}, $+{green}, $+{blue} * $opacity => $col_ref->{red}, $col_red->{green}, $col_ref->{blue}" ); |
576
|
|
|
|
|
|
|
} |
577
|
|
|
|
|
|
|
return({ |
578
|
|
|
|
|
|
|
_24bits => [@$col_ref{qw( red green blue )}], |
579
|
1
|
|
|
|
|
6
|
_8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} ) |
580
|
|
|
|
|
|
|
}); |
581
|
|
|
|
|
|
|
} |
582
|
|
|
|
|
|
|
elsif( $self->message( 9, "Checking if rgb value exists for colour '$col'" ) && |
583
|
|
|
|
|
|
|
( $col_ref = $self->colour_to_rgb( $col ) ) ) |
584
|
|
|
|
|
|
|
{ |
585
|
13
|
|
|
|
|
62
|
$self->message( 9, "Setting up colour '$col' with data: ", sub{ $self->dumper( $col_ref ) }); |
|
0
|
|
|
|
|
0
|
|
586
|
|
|
|
|
|
|
## $code = $map->{ $col }; |
587
|
|
|
|
|
|
|
return({ |
588
|
|
|
|
|
|
|
_24bits => [@$col_ref{qw( red green blue )}], |
589
|
13
|
|
|
|
|
57
|
_8bits => $convert_24_To_8bits->( @$col_ref{qw( red green blue )} ) |
590
|
|
|
|
|
|
|
}); |
591
|
|
|
|
|
|
|
} |
592
|
|
|
|
|
|
|
else |
593
|
|
|
|
|
|
|
{ |
594
|
1
|
|
|
|
|
4
|
$self->message( 9, "Could not find a match for colour '$col'." ); |
595
|
1
|
|
|
|
|
3
|
return( {} ); |
596
|
|
|
|
|
|
|
} |
597
|
|
|
|
|
|
|
# my $is_bg = ( CORE::substr( $code, 0, 1 ) == 4 ); |
598
|
|
|
|
|
|
|
# if( CORE::length( $code ) && $light ) |
599
|
|
|
|
|
|
|
# { |
600
|
|
|
|
|
|
|
# ## If the colour is a background colour, replace 4 by 10 (e.g.: 42 becomes 103) |
601
|
|
|
|
|
|
|
# ## and if foreground colour, replace 3 by 9 |
602
|
|
|
|
|
|
|
# CORE::substr( $code, 0, 1 ) = ( $is_bg ? 10 : 9 ); |
603
|
|
|
|
|
|
|
# } |
604
|
|
|
|
|
|
|
# return( $code ); |
605
|
12
|
|
|
|
|
77
|
}; |
606
|
12
|
|
|
|
|
20
|
my $data = []; |
607
|
12
|
|
|
|
|
17
|
my $params = []; |
608
|
|
|
|
|
|
|
## 8 bits parameters compatible |
609
|
12
|
|
|
|
|
16
|
my $params8 = []; |
610
|
12
|
0
|
33
|
|
|
25
|
if( $opts->{colour} || $opts->{color} || $opts->{fgcolour} || $opts->{fgcolor} || $opts->{fg_colour} || $opts->{fg_color} ) |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
611
|
|
|
|
|
|
|
{ |
612
|
12
|
|
0
|
|
|
24
|
$opts->{colour} ||= CORE::delete( $opts->{color} ) || CORE::delete( $opts->{fg_colour} ) || CORE::delete( $opts->{fg_color} ) || CORE::delete( $opts->{fgcolour} ) || CORE::delete( $opts->{fgcolor} ); |
|
|
|
33
|
|
|
|
|
613
|
12
|
|
|
|
|
25
|
my $col_ref = $check_colour->( $opts->{colour}, $colours ); |
614
|
|
|
|
|
|
|
## CORE::push( @$params, $col ) if( CORE::length( $col ) ); |
615
|
12
|
100
|
|
|
|
34
|
if( scalar( keys( %$col_ref ) ) ) |
616
|
|
|
|
|
|
|
{ |
617
|
11
|
|
|
0
|
|
58
|
$self->message( 9, "Foreground colour '$opts->{colour}' data are: ", sub{ $self->dumper( $col_ref ) }); |
|
0
|
|
|
|
|
0
|
|
618
|
11
|
|
|
|
|
54
|
CORE::push( @$params8, sprintf( '38;5;%d', $col_ref->{_8bits} ) ); |
619
|
11
|
|
|
|
|
17
|
CORE::push( @$params, sprintf( '38;2;%d;%d;%d', @{$col_ref->{_24bits}} ) ); |
|
11
|
|
|
|
|
49
|
|
620
|
|
|
|
|
|
|
} |
621
|
|
|
|
|
|
|
else |
622
|
|
|
|
|
|
|
{ |
623
|
1
|
|
|
|
|
5
|
$self->message( 9, "Could not resolve the foreground colour '$opts->{colour}'." ); |
624
|
|
|
|
|
|
|
} |
625
|
|
|
|
|
|
|
} |
626
|
12
|
50
|
66
|
|
|
59
|
if( $opts->{bgcolour} || $opts->{bgcolor} || $opts->{bg_colour} || $opts->{bg_color} ) |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
627
|
|
|
|
|
|
|
{ |
628
|
6
|
|
0
|
|
|
14
|
$opts->{bgcolour} ||= CORE::delete( $opts->{bgcolor} ) || CORE::delete( $opts->{bg_colour} ) || CORE::delete( $opts->{bg_color} ); |
|
|
|
33
|
|
|
|
|
629
|
6
|
|
|
|
|
14
|
my $col_ref = $check_colour->( $opts->{bgcolour}, $bg_colours ); |
630
|
|
|
|
|
|
|
## CORE::push( @$params, $col ) if( CORE::length( $col ) ); |
631
|
6
|
50
|
|
|
|
16
|
if( scalar( keys( %$col_ref ) ) ) |
632
|
|
|
|
|
|
|
{ |
633
|
6
|
|
|
0
|
|
32
|
$self->message( 9, "Foreground colour '$opts->{bgcolour}' data are: ", sub{ $self->dumper( $col_ref ) }); |
|
0
|
|
|
|
|
0
|
|
634
|
6
|
|
|
|
|
30
|
CORE::push( @$params8, sprintf( '48;5;%d', $col_ref->{_8bits} ) ); |
635
|
6
|
|
|
|
|
8
|
CORE::push( @$params, sprintf( '48;2;%d;%d;%d', @{$col_ref->{_24bits}} ) ); |
|
6
|
|
|
|
|
26
|
|
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
else |
638
|
|
|
|
|
|
|
{ |
639
|
0
|
|
|
|
|
0
|
$self->message( 9, "Could not resolve the background colour '$opts->{colour}'." ); |
640
|
|
|
|
|
|
|
} |
641
|
|
|
|
|
|
|
} |
642
|
12
|
100
|
|
|
|
29
|
if( $opts->{style} ) |
643
|
|
|
|
|
|
|
{ |
644
|
|
|
|
|
|
|
## $self->message( 9, "Style '$opts->{style}' provided." ); |
645
|
11
|
|
|
|
|
33
|
my $those_styles = [CORE::split( /\|/, $opts->{style} )]; |
646
|
|
|
|
|
|
|
## $self->message( 9, "Split styles: ", sub{ $self->dumper( $those_styles ) } ); |
647
|
11
|
|
|
|
|
23
|
foreach my $s ( @$those_styles ) |
648
|
|
|
|
|
|
|
{ |
649
|
|
|
|
|
|
|
## $self->message( 9, "Adding style '$s'" ) if( CORE::exists( $styles->{lc($s)} ) ); |
650
|
12
|
50
|
|
|
|
31
|
if( CORE::exists( $styles->{lc($s)} ) ) |
651
|
|
|
|
|
|
|
{ |
652
|
12
|
|
|
|
|
21
|
CORE::push( @$params, $styles->{lc($s)} ); |
653
|
|
|
|
|
|
|
## We add the 8 bits compliant version only if any colour was provided, i.e. |
654
|
|
|
|
|
|
|
## This is not just a style definition |
655
|
12
|
50
|
|
|
|
32
|
CORE::push( @$params8, $styles->{lc($s)} ) if( scalar( @$params8 ) ); |
656
|
|
|
|
|
|
|
} |
657
|
|
|
|
|
|
|
} |
658
|
|
|
|
|
|
|
} |
659
|
12
|
100
|
|
|
|
43
|
CORE::push( @$data, "\e[" . CORE::join( ';', @$params8 ) . "m" ) if( scalar( @$params8 ) ); |
660
|
12
|
100
|
|
|
|
49
|
CORE::push( @$data, "\e[" . CORE::join( ';', @$params ) . "m" ) if( scalar( @$params ) ); |
661
|
12
|
|
|
0
|
|
48
|
$self->message( 9, "Pre final colour data contains: ", sub{ $self->dumper( $data ) }); |
|
0
|
|
|
|
|
0
|
|
662
|
|
|
|
|
|
|
## If the text contains libe breaks, we must stop the formatting before, or else there would be an ugly formatting on the entire screen following the line break |
663
|
12
|
100
|
100
|
|
|
59
|
if( scalar( @$params ) && $opts->{text} =~ /\n+/ ) |
664
|
|
|
|
|
|
|
{ |
665
|
1
|
|
|
|
|
5
|
my $text_parts = [CORE::split( /\n/, $opts->{text} )]; |
666
|
1
|
|
|
|
|
4
|
my $fmt = CORE::join( '', @$data ); |
667
|
1
|
|
|
|
|
2
|
my $fmt8 = CORE::join( '', @$data8 ); |
668
|
1
|
|
|
|
|
6
|
for( my $i = 0; $i < scalar( @$text_parts ); $i++ ) |
669
|
|
|
|
|
|
|
{ |
670
|
|
|
|
|
|
|
## Empty due to \n repeated |
671
|
2
|
50
|
|
|
|
6
|
next if( !CORE::length( $text_parts->[$i] ) ); |
672
|
2
|
|
|
|
|
7
|
$text_parts->[$i] = $fmt . $text_parts->[$i] . $normal; |
673
|
|
|
|
|
|
|
} |
674
|
1
|
|
|
|
|
3
|
$opts->{text} = CORE::join( "\n", @$text_parts ); |
675
|
1
|
|
|
|
|
4
|
CORE::push( @$data, $opts->{text} ); |
676
|
|
|
|
|
|
|
} |
677
|
|
|
|
|
|
|
else |
678
|
|
|
|
|
|
|
{ |
679
|
11
|
|
|
|
|
19
|
CORE::push( @$data, $opts->{text} ); |
680
|
11
|
100
|
|
|
|
25
|
CORE::push( @$data, $normal, $normal ) if( scalar( @$params ) ); |
681
|
|
|
|
|
|
|
} |
682
|
|
|
|
|
|
|
## $self->message( "Returning '", quotemeta( CORE::join( '', @$data ) ), "'" ); |
683
|
12
|
|
|
|
|
369
|
return( CORE::join( '', @$data ) ); |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
|
686
|
2
|
|
|
2
|
0
|
12
|
sub colour_open { return( shift->_set_get( 'colour_open', @_ ) ); } |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
sub colour_parse |
689
|
|
|
|
|
|
|
{ |
690
|
5
|
|
|
5
|
1
|
15
|
my $self = shift( @_ ); |
691
|
5
|
|
|
|
|
16
|
my $txt = join( '', @_ ); |
692
|
5
|
|
|
|
|
11
|
my $this = $self->_obj2h; |
693
|
5
|
|
50
|
|
|
16
|
my $open = $this->{colour_open} || COLOUR_OPEN; |
694
|
5
|
|
50
|
|
|
13
|
my $close = $this->{colour_close} || COLOUR_CLOSE; |
695
|
5
|
|
|
|
|
23
|
$self->message( 9, "Color open is '${open}' and close is '${close}'." ); |
696
|
|
|
|
|
|
|
## $self->message( 3, "Parsing text '$txt'" ); |
697
|
5
|
|
|
|
|
17
|
my $colour_re = qr/(?:(?:bright|light)[[:blank:]])?(?:[a-zA-Z]+(?:[[:blank:]]+[\w\-]+)?|rgb[a]?\([[:blank:]]*\d{1,3}[[:blank:]]*\,[[:blank:]]*\d{1,3}[[:blank:]]*\,[[:blank:]]*\d{1,3}[[:blank:]]*(?:\,[[:blank:]]*\d(?:\.\d)?)?[[:blank:]]*\))/; |
698
|
5
|
|
|
|
|
14
|
my $style_re = qr/(?:bold|faint|italic|underline|blink|reverse|conceal|strike)/; |
699
|
|
|
|
|
|
|
local $parse = sub |
700
|
|
|
|
|
|
|
{ |
701
|
7
|
|
|
7
|
|
12
|
my $opts = shift( @_ ); |
702
|
7
|
|
|
|
|
12
|
my $chunk = $opts->{text}; |
703
|
7
|
|
100
|
|
|
22
|
my $start = $opts->{start} || 0; |
704
|
7
|
|
|
|
|
10
|
my $buff = ''; |
705
|
7
|
|
|
|
|
8
|
my $in = 0; |
706
|
7
|
|
|
|
|
8
|
my $this_def = ''; |
707
|
7
|
|
|
|
|
9
|
my $def = {}; |
708
|
7
|
|
|
|
|
12
|
my $err = ''; |
709
|
7
|
|
|
|
|
9
|
my $data = []; |
710
|
7
|
|
|
|
|
10
|
my $chunk_len = CORE::length( $$chunk ); |
711
|
7
|
|
|
|
|
9
|
my $i; |
712
|
7
|
|
|
|
|
30
|
$self->message( 9, "Parsing text $$chunk starting from position $start" ); |
713
|
7
|
|
|
|
|
20
|
for( $i = $start; $i < $chunk_len; $i++ ) |
714
|
|
|
|
|
|
|
{ |
715
|
214
|
|
|
|
|
255
|
my $c = CORE::substr( $$chunk, $i, 1 ); |
716
|
|
|
|
|
|
|
# $self->message( 9, "Checking character '$c' at position $i" ); |
717
|
214
|
100
|
|
|
|
329
|
if( $c eq $open ) |
|
|
100
|
|
|
|
|
|
718
|
|
|
|
|
|
|
{ |
719
|
|
|
|
|
|
|
## Is this the closing element? |
720
|
20
|
100
|
|
|
|
55
|
if( CORE::substr( $$chunk, $i, 3 ) eq "${open}/${close}" ) |
|
|
100
|
|
|
|
|
|
721
|
|
|
|
|
|
|
{ |
722
|
9
|
|
|
|
|
53
|
$self->message( 9, "Found closing element and buffered text '$def->{text}' and definition is: ", sub{ $self->dumper( $def ) } ); |
|
0
|
|
|
|
|
0
|
|
723
|
|
|
|
|
|
|
## $def includes the property text containing concatenated text |
724
|
9
|
50
|
|
|
|
41
|
my $res = CORE::length( $def->{text} ) ? $self->colour_format( $def ) : ''; |
725
|
9
|
|
|
|
|
73
|
$self->message( 9, "Resulting formatted text is: '$res'." ); |
726
|
|
|
|
|
|
|
## If this is a child, we return right now, the section we processed |
727
|
9
|
100
|
|
|
|
21
|
if( $opts->{is_child} ) |
728
|
|
|
|
|
|
|
{ |
729
|
2
|
|
|
|
|
12
|
$self->message( 9, "Being a child, return formatted text '$res' and position ", $i + 3, " for text '$$chunk'" ); |
730
|
2
|
|
|
|
|
13
|
return({ text => $res, position => $i + 3 }); |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
## Otherwise we push it to the data stack |
733
|
|
|
|
|
|
|
else |
734
|
|
|
|
|
|
|
{ |
735
|
7
|
50
|
|
|
|
19
|
CORE::push( @$data, $res ) if( CORE::length( $res ) ); |
736
|
7
|
|
|
|
|
10
|
$i += 2; |
737
|
7
|
|
|
|
|
20
|
$def = {}; |
738
|
7
|
|
|
|
|
18
|
next; |
739
|
|
|
|
|
|
|
} |
740
|
|
|
|
|
|
|
} |
741
|
|
|
|
|
|
|
## If we have a style definition already and we find an open style curly bracket, |
742
|
|
|
|
|
|
|
## this means this is an embedded text, we call $parse recursively |
743
|
|
|
|
|
|
|
elsif( CORE::scalar( keys( %$def ) ) ) |
744
|
|
|
|
|
|
|
{ |
745
|
2
|
|
|
|
|
15
|
$self->message( 9, "Found a sub style, calling parse recursively starting from position $i. \$def has ", sub{ $self->dumper( $def ) } ); |
|
0
|
|
|
|
|
0
|
|
746
|
2
|
|
|
|
|
27
|
my $res = $parse->({ text => $chunk, start => $i, is_child => 1 }); |
747
|
2
|
|
|
|
|
7
|
$def->{text} .= $res->{text}; |
748
|
|
|
|
|
|
|
## $self->message( 9, "Resuming parsing at position $res->{position} in text '$$chunk'." ); |
749
|
2
|
|
|
|
|
3
|
$i = $res->{position}; |
750
|
2
|
|
|
|
|
3
|
$i--; |
751
|
2
|
|
|
|
|
5
|
next; |
752
|
|
|
|
|
|
|
} |
753
|
|
|
|
|
|
|
|
754
|
9
|
|
|
|
|
15
|
my $j; |
755
|
9
|
|
|
|
|
24
|
for( $j = $i; $j < CORE::length( $$chunk ); $j++ ) |
756
|
|
|
|
|
|
|
{ |
757
|
265
|
100
|
|
|
|
456
|
next unless( CORE::substr( $$chunk, $j, 1 ) eq $close ); |
758
|
9
|
|
|
|
|
21
|
$this_def = CORE::substr( $$chunk, $i, ( $j + 1 ) - $i ); |
759
|
9
|
|
|
|
|
40
|
$self->message( 9, "Found a style at position $i, ending at position ", ( $j + 1 ), ": '$this_def'" ); |
760
|
|
|
|
|
|
|
|
761
|
9
|
100
|
|
|
|
475
|
if( $this_def =~ /^\Q${open}\E[[:blank:]]*(?:(?<style1>$style_re)[[:blank:]]+)?(?<fg_colour>$colour_re)(?:[[:blank:]]+(?<style2>$style_re))?(?:[[:blank:]]+on[[:blank:]]+(?<bg_colour>$colour_re))?[[:blank:]]*\Q${close}\E$/i ) |
762
|
|
|
|
|
|
|
{ |
763
|
5
|
|
66
|
|
|
41
|
$style = $+{style1} || $+{style2}; |
764
|
5
|
|
|
|
|
21
|
$fg = $+{fg_colour}; |
765
|
5
|
|
|
|
|
14
|
$bg = $+{bg_colour}; |
766
|
5
|
|
|
|
|
22
|
$self->message( 9, "Found style '$style', colour '$fg' and background colour '$bg'." ); |
767
|
5
|
|
|
|
|
19
|
$def = |
768
|
|
|
|
|
|
|
{ |
769
|
|
|
|
|
|
|
style => $style, |
770
|
|
|
|
|
|
|
colour => $fg, |
771
|
|
|
|
|
|
|
bg_colour => $bg, |
772
|
|
|
|
|
|
|
}; |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
else |
775
|
|
|
|
|
|
|
{ |
776
|
4
|
|
|
|
|
19
|
$self->message( 9, "Evaluating the styling '$this_def'." ); |
777
|
4
|
|
|
|
|
211
|
$def = eval( $this_def ); |
778
|
4
|
50
|
33
|
|
|
27
|
if( $@ || ref( $def ) ne 'HASH' ) |
779
|
|
|
|
|
|
|
{ |
780
|
0
|
|
0
|
|
|
0
|
$err = $@ || "Invalid styling \"${this_def}\""; |
781
|
|
|
|
|
|
|
} |
782
|
|
|
|
|
|
|
else |
783
|
|
|
|
|
|
|
{ |
784
|
4
|
|
|
|
|
8
|
$err = ''; |
785
|
|
|
|
|
|
|
} |
786
|
|
|
|
|
|
|
} |
787
|
9
|
50
|
|
|
|
22
|
unless( $err ) |
788
|
|
|
|
|
|
|
{ |
789
|
9
|
|
|
|
|
16
|
$def->{start} = $i; |
790
|
|
|
|
|
|
|
} |
791
|
9
|
|
|
|
|
17
|
last; |
792
|
|
|
|
|
|
|
} |
793
|
9
|
50
|
|
|
|
20
|
if( !CORE::length( $this_def ) ) |
794
|
|
|
|
|
|
|
{ |
795
|
0
|
|
|
|
|
0
|
$self->message( 9, "Reaching the end of the string and could not find a closing curly bracket \"${close}\"." ); |
796
|
0
|
|
|
|
|
0
|
$self->error( "Failed to find a closing curly bracket for opening style." ); |
797
|
0
|
|
|
|
|
0
|
$def->{error} = 'no closeing curly bracket'; |
798
|
|
|
|
|
|
|
} |
799
|
9
|
|
|
|
|
10
|
$i = $j; |
800
|
9
|
|
|
|
|
20
|
next; |
801
|
|
|
|
|
|
|
} |
802
|
|
|
|
|
|
|
## We are inside a formatting |
803
|
|
|
|
|
|
|
elsif( scalar( keys( %$def ) ) ) |
804
|
|
|
|
|
|
|
{ |
805
|
147
|
|
|
|
|
211
|
$def->{text} .= $c; |
806
|
|
|
|
|
|
|
## $self->message( 9, "Text buffer now is '$def->{text}'." ); |
807
|
|
|
|
|
|
|
} |
808
|
|
|
|
|
|
|
else |
809
|
|
|
|
|
|
|
{ |
810
|
47
|
|
|
|
|
89
|
CORE::push( @$data, $c ); |
811
|
|
|
|
|
|
|
## $self->message( 9, "Adding text outside formatting. \$data now is: '", join( '', @$data ), "'." ); |
812
|
|
|
|
|
|
|
} |
813
|
|
|
|
|
|
|
} |
814
|
|
|
|
|
|
|
## Return the text with replacement performed |
815
|
5
|
|
|
|
|
27
|
$self->message( 9, "Final formatted text is: ", quotemeta( CORE::join( '', @$data ) ) ); |
816
|
5
|
50
|
|
|
|
153
|
return( $opts->{is_child} ? { text => CORE::join( '', @$data ), position => $i } : CORE::join( '', @$data ) ); |
817
|
5
|
|
|
|
|
45
|
}; |
818
|
5
|
|
|
|
|
19
|
return( $parse->({ text => \$txt }) ); |
819
|
|
|
|
|
|
|
} |
820
|
|
|
|
|
|
|
|
821
|
|
|
|
|
|
|
sub colour_to_rgb |
822
|
|
|
|
|
|
|
{ |
823
|
15
|
|
|
15
|
0
|
27
|
my $self = shift( @_ ); |
824
|
15
|
|
|
|
|
26
|
my $colour = lc( shift( @_ ) ); |
825
|
15
|
|
|
|
|
38
|
my $this = $self->_obj2h; |
826
|
15
|
|
|
|
|
28
|
my( $red, $green, $blue ) = ( '', '', '' ); |
827
|
15
|
|
|
|
|
137
|
$self->message( 9, "Checking rgb value for '$colour'. Called from line ", (caller)[2] ); |
828
|
15
|
50
|
|
|
|
63
|
if( $colour =~ /^[A-Za-z]+([\w\-]+)*([[:blank:]]+\w+)?$/ ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
829
|
|
|
|
|
|
|
{ |
830
|
15
|
|
|
|
|
44
|
$self->message( 9, "Checking colour '$colour' as string. Looking up its rgb value." ); |
831
|
15
|
100
|
|
|
|
37
|
if( !scalar( keys( %$COLOUR_NAME_TO_RGB ) ) ) |
832
|
|
|
|
|
|
|
{ |
833
|
1
|
|
|
|
|
3
|
$self->message( 9, "Processing colour map in <DATA> section." ); |
834
|
1
|
|
|
|
|
4
|
my $colour_data = $self->__colour_data; |
835
|
1
|
|
|
|
|
3002
|
$COLOUR_NAME_TO_RGB = eval( $colour_data ); |
836
|
1
|
50
|
|
|
|
9
|
if( $@ ) |
837
|
|
|
|
|
|
|
{ |
838
|
0
|
|
|
|
|
0
|
return( $self->error( "An error occurred loading data from __colour_data: $@" ) ); |
839
|
|
|
|
|
|
|
} |
840
|
|
|
|
|
|
|
} |
841
|
15
|
100
|
|
|
|
37
|
if( CORE::exists( $COLOUR_NAME_TO_RGB->{ $colour } ) ) |
842
|
|
|
|
|
|
|
{ |
843
|
14
|
|
|
|
|
16
|
( $red, $green, $blue ) = @{$COLOUR_NAME_TO_RGB->{ $colour }}; |
|
14
|
|
|
|
|
37
|
|
844
|
14
|
|
|
|
|
37
|
$self->message( 9, "Found rgb '$red, $green, $blue' for colour '$colour'." ); |
845
|
|
|
|
|
|
|
} |
846
|
|
|
|
|
|
|
else |
847
|
|
|
|
|
|
|
{ |
848
|
1
|
|
|
|
|
5
|
$self->message( 9, "Could not find colour '$colour' in our colour map." ); |
849
|
1
|
|
|
|
|
3
|
return( '' ); |
850
|
|
|
|
|
|
|
} |
851
|
|
|
|
|
|
|
} |
852
|
|
|
|
|
|
|
## Colour all in decimal?? |
853
|
|
|
|
|
|
|
elsif( $colour =~ /^\d{9}$/ ) |
854
|
|
|
|
|
|
|
{ |
855
|
|
|
|
|
|
|
## $self->message( 9, "Got colour all in decimal. Less work to do..." ); |
856
|
0
|
|
|
|
|
0
|
$red = substr( $colour, 0, 3 ); |
857
|
0
|
|
|
|
|
0
|
$green = substr( $colour, 3, 3 ); |
858
|
0
|
|
|
|
|
0
|
$blue = substr( $colour, 6, 3 ); |
859
|
|
|
|
|
|
|
} |
860
|
|
|
|
|
|
|
## Colour in hexadecimal, convert it |
861
|
|
|
|
|
|
|
elsif( $colour =~ /^[A-F0-9]+$/ ) |
862
|
|
|
|
|
|
|
{ |
863
|
0
|
|
|
|
|
0
|
$red = hex( substr( $colour, 0, 2 ) ); |
864
|
0
|
|
|
|
|
0
|
$green = hex( substr( $colour, 2, 2 ) ); |
865
|
0
|
|
|
|
|
0
|
$blue = hex( substr( $colour, 4, 2 ) ); |
866
|
|
|
|
|
|
|
} |
867
|
|
|
|
|
|
|
## Clueless |
868
|
|
|
|
|
|
|
else |
869
|
|
|
|
|
|
|
{ |
870
|
0
|
|
|
|
|
0
|
$self->message( 9, "Clueless about what to do with colour '$colour'." ); |
871
|
|
|
|
|
|
|
## Not undef, but rather empty string. Undef is associated with an error |
872
|
0
|
|
|
|
|
0
|
return( '' ); |
873
|
|
|
|
|
|
|
} |
874
|
14
|
|
|
|
|
66
|
return({ red => $red, green => $green, blue => $blue }); |
875
|
|
|
|
|
|
|
} |
876
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
sub coloured |
878
|
|
|
|
|
|
|
{ |
879
|
3
|
|
|
3
|
1
|
6
|
my $self = shift( @_ ); |
880
|
3
|
|
|
|
|
8
|
my $pref = shift( @_ ); |
881
|
3
|
|
|
|
|
9
|
my $text = CORE::join( '', @_ ); |
882
|
3
|
|
|
|
|
8
|
my $this = $self->_obj2h; |
883
|
3
|
|
|
|
|
7
|
my( $style, $fg, $bg ); |
884
|
|
|
|
|
|
|
## my $colour_re = qr/(?:(?:bright|light)[[:blank:]])?[a-zA-Z]+/; |
885
|
3
|
|
|
|
|
12
|
my $colour_re = qr/(?:(?:bright|light)[[:blank:]])?(?:[a-zA-Z]+(?:[[:blank:]]+[\w\-]+)?|rgb[a]?\([[:blank:]]*\d{1,3}[[:blank:]]*\,[[:blank:]]*\d{1,3}[[:blank:]]*\,[[:blank:]]*\d{1,3}[[:blank:]]*(?:\,[[:blank:]]*\d(?:\.\d)?)?[[:blank:]]*\))/; |
886
|
3
|
|
|
|
|
8
|
my $style_re = qr/(?:bold|faint|italic|underline|blink|reverse|conceal|strike)/; |
887
|
3
|
50
|
|
|
|
212
|
if( $pref =~ /^(?:(?<style1>$style_re)[[:blank:]]+)?(?<fg_colour>$colour_re)(?:[[:blank:]]+(?<style2>$style_re))?(?:[[:blank:]]+on[[:blank:]]+(?<bg_colour>$colour_re))?$/i ) |
888
|
|
|
|
|
|
|
{ |
889
|
3
|
|
33
|
|
|
57
|
$style = $+{style1} || $+{style2}; |
890
|
3
|
|
|
|
|
14
|
$fg = $+{fg_colour}; |
891
|
3
|
|
|
|
|
10
|
$bg = $+{bg_colour}; |
892
|
|
|
|
|
|
|
## $self->message( 9, "Found style '$style', colour '$fg' and background colour '$bg'." ); |
893
|
3
|
|
|
|
|
19
|
return( $self->colour_format({ text => $text, style => $style, colour => $fg, bg_colour => $bg }) ); |
894
|
|
|
|
|
|
|
} |
895
|
|
|
|
|
|
|
else |
896
|
|
|
|
|
|
|
{ |
897
|
0
|
|
|
|
|
0
|
$self->message( 9, "No match." ); |
898
|
0
|
|
|
|
|
0
|
return( '' ); |
899
|
|
|
|
|
|
|
} |
900
|
|
|
|
|
|
|
} |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
sub debug |
903
|
|
|
|
|
|
|
{ |
904
|
135
|
|
|
135
|
1
|
269
|
my $self = shift( @_ ); |
905
|
135
|
|
|
|
|
329
|
my $class = ref( $self ); |
906
|
135
|
|
|
|
|
299
|
my $this = $self->_obj2h; |
907
|
135
|
50
|
|
|
|
463
|
if( @_ ) |
908
|
|
|
|
|
|
|
{ |
909
|
135
|
|
|
|
|
377
|
my $flag = shift( @_ ); |
910
|
135
|
|
|
|
|
317
|
$this->{debug} = $flag; |
911
|
135
|
50
|
|
|
|
373
|
$self->message_switch( $flag ) if( $OPTIMIZE_MESG_SUB ); |
912
|
135
|
100
|
66
|
|
|
444
|
if( $this->{debug} && |
913
|
|
|
|
|
|
|
!$this->{debug_level} ) |
914
|
|
|
|
|
|
|
{ |
915
|
1
|
|
|
|
|
4
|
$this->{debug_level} = $this->{debug}; |
916
|
|
|
|
|
|
|
} |
917
|
|
|
|
|
|
|
} |
918
|
135
|
|
66
|
|
|
422
|
return( $this->{debug} || ${"$class\:\:DEBUG"} ); |
919
|
|
|
|
|
|
|
} |
920
|
|
|
|
|
|
|
|
921
|
0
|
|
|
0
|
1
|
0
|
sub dump { return( shift->printer( @_ ) ); } |
922
|
|
|
|
|
|
|
|
923
|
|
|
|
|
|
|
## For backward compatibility and traceability |
924
|
0
|
|
|
0
|
1
|
0
|
sub dump_print { return( shift->dumpto_printer( @_ ) ); } |
925
|
|
|
|
|
|
|
|
926
|
|
|
|
|
|
|
sub dumper |
927
|
|
|
|
|
|
|
{ |
928
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
929
|
0
|
|
|
|
|
0
|
my $opts = {}; |
930
|
0
|
0
|
0
|
|
|
0
|
$opts = pop( @_ ) if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' ); |
931
|
|
|
|
|
|
|
# local $Data::Dumper::Sortkeys = 1; |
932
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Terse = 1; |
933
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Indent = 1; |
934
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Useqq = 1; |
935
|
0
|
0
|
|
|
|
0
|
local $Data::Dumper::Maxdepth = $opts->{depth} if( CORE::length( $opts->{depth} ) ); |
936
|
|
|
|
|
|
|
local $Data::Dumper::Sortkeys = sub |
937
|
|
|
|
|
|
|
{ |
938
|
0
|
|
|
0
|
|
0
|
my $h = shift( @_ ); |
939
|
0
|
|
|
|
|
0
|
return( [ sort( grep{ ref( $h->{ $_ } ) !~ /^(DateTime|DateTime\:\:)/ } keys( %$h ) ) ] ); |
|
0
|
|
|
|
|
0
|
|
940
|
0
|
|
|
|
|
0
|
}; |
941
|
0
|
|
|
|
|
0
|
return( Data::Dumper::Dumper( @_ ) ); |
942
|
|
|
|
|
|
|
} |
943
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
sub printer |
945
|
|
|
|
|
|
|
{ |
946
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
947
|
0
|
|
|
|
|
0
|
my $opts = {}; |
948
|
0
|
0
|
0
|
|
|
0
|
$opts = pop( @_ ) if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' ); |
949
|
0
|
|
|
0
|
|
0
|
local $SIG{__WARN__} = sub{ }; |
950
|
0
|
0
|
|
|
|
0
|
if( scalar( keys( %$opts ) ) ) |
951
|
|
|
|
|
|
|
{ |
952
|
0
|
|
|
|
|
0
|
return( Data::Printer::np( @_, %$opts ) ); |
953
|
|
|
|
|
|
|
} |
954
|
|
|
|
|
|
|
else |
955
|
|
|
|
|
|
|
{ |
956
|
0
|
|
|
|
|
0
|
return( Data::Printer::np( @_ ) ); |
957
|
|
|
|
|
|
|
} |
958
|
|
|
|
|
|
|
} |
959
|
|
|
|
|
|
|
|
960
|
|
|
|
|
|
|
*dumpto = \&dumpto_dumper; |
961
|
|
|
|
|
|
|
|
962
|
|
|
|
|
|
|
sub dumpto_printer |
963
|
|
|
|
|
|
|
{ |
964
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
965
|
0
|
|
|
|
|
0
|
my( $data, $file ) = @_; |
966
|
0
|
|
0
|
|
|
0
|
my $fh = IO::File->new( ">$file" ) || die( "Unable to create file '$file': $!\n" ); |
967
|
0
|
|
|
|
|
0
|
$fh->binmode( ':utf8' ); |
968
|
0
|
|
|
|
|
0
|
$fh->print( Data::Printer::np( $data ), "\n" ); |
969
|
0
|
|
|
|
|
0
|
$fh->close; |
970
|
|
|
|
|
|
|
## 666 so it can work under command line and web alike |
971
|
0
|
|
|
|
|
0
|
chmod( 0666, $file ); |
972
|
0
|
|
|
|
|
0
|
return( 1 ); |
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
sub dumpto_dumper |
976
|
|
|
|
|
|
|
{ |
977
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
978
|
0
|
|
|
|
|
0
|
my( $data, $file ) = @_; |
979
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Sortkeys = 1; |
980
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Terse = 1; |
981
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Indent = 1; |
982
|
0
|
|
|
|
|
0
|
local $Data::Dumper::Useqq = 1; |
983
|
0
|
|
0
|
|
|
0
|
my $fh = IO::File->new( ">$file" ) || die( "Unable to create file '$file': $!\n" ); |
984
|
0
|
0
|
|
|
|
0
|
if( ref( $data ) ) |
985
|
|
|
|
|
|
|
{ |
986
|
0
|
|
|
|
|
0
|
$fh->print( Data::Dumper::Dumper( $data ), "\n" ); |
987
|
|
|
|
|
|
|
} |
988
|
|
|
|
|
|
|
else |
989
|
|
|
|
|
|
|
{ |
990
|
0
|
|
|
|
|
0
|
$fh->binmode( ':utf8' ); |
991
|
0
|
|
|
|
|
0
|
$fh->print( $data ); |
992
|
|
|
|
|
|
|
} |
993
|
0
|
|
|
|
|
0
|
$fh->close; |
994
|
|
|
|
|
|
|
## 666 so it can work under command line and web alike |
995
|
0
|
|
|
|
|
0
|
chmod( 0666, $file ); |
996
|
0
|
|
|
|
|
0
|
return( 1 ); |
997
|
|
|
|
|
|
|
} |
998
|
|
|
|
|
|
|
|
999
|
|
|
|
|
|
|
sub errno |
1000
|
|
|
|
|
|
|
{ |
1001
|
0
|
|
|
0
|
0
|
0
|
my $self = shift( @_ ); |
1002
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1003
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
1004
|
|
|
|
|
|
|
{ |
1005
|
0
|
0
|
|
|
|
0
|
$this->{errno} = shift( @_ ) if( $_[ 0 ] =~ /^\-?\d+$/ ); |
1006
|
0
|
0
|
|
|
|
0
|
return( $self->error( @_ ) ) if( @_ ); |
1007
|
|
|
|
|
|
|
} |
1008
|
0
|
|
|
|
|
0
|
return( $this->{errno} ); |
1009
|
|
|
|
|
|
|
} |
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
sub error |
1012
|
|
|
|
|
|
|
{ |
1013
|
1
|
|
|
1
|
1
|
3
|
my $self = shift( @_ ); |
1014
|
1
|
|
33
|
|
|
5
|
my $class = ref( $self ) || $self; |
1015
|
1
|
|
|
|
|
4
|
my $this = $self->_obj2h; |
1016
|
1
|
50
|
|
|
|
5
|
if( @_ ) |
1017
|
|
|
|
|
|
|
{ |
1018
|
1
|
|
|
|
|
3
|
my $args = {}; |
1019
|
1
|
50
|
33
|
|
|
10
|
if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic::Exception' ) ) |
|
|
50
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
{ |
1021
|
0
|
|
|
|
|
0
|
$args->{object} = shift( @_ ); |
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
elsif( ref( $_[0] ) eq 'HASH' ) |
1024
|
|
|
|
|
|
|
{ |
1025
|
0
|
|
|
|
|
0
|
$args = shift( @_ ); |
1026
|
|
|
|
|
|
|
} |
1027
|
|
|
|
|
|
|
else |
1028
|
|
|
|
|
|
|
{ |
1029
|
1
|
50
|
33
|
|
|
14
|
$args->{message} = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @_ ) ); |
1030
|
|
|
|
|
|
|
} |
1031
|
1
|
50
|
33
|
|
|
27
|
$args->{message} = substr( $args->{message}, 0, $this->{error_max_length} ) if( $this->{error_max_length} > 0 && length( $args->{message} ) > $this->{error_max_length} ); |
1032
|
|
|
|
|
|
|
# Reset it |
1033
|
1
|
|
|
|
|
5
|
$this->{_msg_no_exec_sub} = 0; |
1034
|
1
|
|
|
|
|
2
|
my $n = 1; |
1035
|
|
|
|
|
|
|
# $n++ while( ( caller( $n ) )[0] eq 'Module::Generic' ); |
1036
|
1
|
|
|
|
|
3
|
$args->{skip_frames} = $n + 1; |
1037
|
|
|
|
|
|
|
## my( $p, $f, $l ) = caller( $n ); |
1038
|
|
|
|
|
|
|
## my( $sub ) = ( caller( $n + 1 ) )[3]; |
1039
|
1
|
|
|
|
|
19
|
my $o = $this->{error} = ${ $class . '::ERROR' } = Module::Generic::Exception->new( $args ); |
|
1
|
|
|
|
|
8
|
|
1040
|
|
|
|
|
|
|
## printf( STDERR "%s::error() called from package %s ($p) in file %s ($f) at line %d ($l) from sub %s ($sub)\n", __PACKAGE__, $o->package, $o->file, $o->line, $o->subroutine ); |
1041
|
|
|
|
|
|
|
|
1042
|
|
|
|
|
|
|
## Get the warnings status of the caller. We use caller(1) to skip one frame further, ie our caller's caller |
1043
|
|
|
|
|
|
|
## This can be changed by using 'no warnings' |
1044
|
1
|
|
|
|
|
4
|
my $should_display_warning = 0; |
1045
|
1
|
|
|
|
|
2
|
my $no_use_warnings = 1; |
1046
|
|
|
|
|
|
|
## Try to get the warnings status if is enabled at all. |
1047
|
1
|
|
|
|
|
2
|
try |
1048
|
1
|
|
|
1
|
|
2
|
{ |
1049
|
1
|
|
|
|
|
9
|
$should_display_warning = $self->_warnings_is_enabled; |
1050
|
1
|
|
|
|
|
3
|
$no_use_warnings = 0; |
1051
|
|
|
|
|
|
|
} |
1052
|
1
|
50
|
|
|
|
7
|
catch( $e ) |
|
1
|
50
|
|
|
|
3
|
|
|
1
|
50
|
|
|
|
3
|
|
|
1
|
0
|
|
|
|
3
|
|
|
1
|
50
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
7
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
4
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
4
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1053
|
0
|
|
|
0
|
|
0
|
{ |
1054
|
|
|
|
|
|
|
# |
1055
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
18
|
|
|
0
|
|
|
|
|
0
|
|
1056
|
|
|
|
|
|
|
|
1057
|
1
|
50
|
|
|
|
5
|
if( $no_use_warnings ) |
1058
|
|
|
|
|
|
|
{ |
1059
|
0
|
|
|
|
|
0
|
my $call_offset = 0; |
1060
|
0
|
|
|
|
|
0
|
while( my @call_data = caller( $call_offset ) ) |
1061
|
|
|
|
|
|
|
{ |
1062
|
|
|
|
|
|
|
## printf( STDERR "[$call_offset] In file $call_data[1] at line $call_data[2] from subroutine %s has bitmask $call_data[9]\n", (caller($call_offset+1))[3] ); |
1063
|
0
|
0
|
0
|
|
|
0
|
unless( $call_offset > 0 && $call_data[0] ne $class && (caller($call_offset-1))[0] eq $class ) |
|
|
|
0
|
|
|
|
|
1064
|
|
|
|
|
|
|
{ |
1065
|
|
|
|
|
|
|
## print( STDERR "Skipping package $call_data[0]\n" ); |
1066
|
0
|
|
|
|
|
0
|
$call_offset++; |
1067
|
0
|
|
|
|
|
0
|
next; |
1068
|
|
|
|
|
|
|
} |
1069
|
0
|
0
|
0
|
|
|
0
|
last if( $call_data[9] || ( $call_offset > 0 && (caller($call_offset-1))[0] ne $class ) ); |
|
|
|
0
|
|
|
|
|
1070
|
0
|
|
|
|
|
0
|
$call_offset++; |
1071
|
|
|
|
|
|
|
} |
1072
|
|
|
|
|
|
|
## print( STDERR "Using offset $call_offset with bitmask ", ( caller( $call_offset ) )[9], "\n" ); |
1073
|
0
|
|
|
|
|
0
|
my $bitmask = ( caller( $call_offset ) )[9]; |
1074
|
0
|
|
|
|
|
0
|
my $offset = $warnings::Offsets{uninitialized}; |
1075
|
|
|
|
|
|
|
## $self->message( 3, "Caller (2)'s bitmask is '$bitmask', warnings offset is '$offset' and vector is '", vec( $bitmask, $offset, 1 ), "'." ); |
1076
|
0
|
|
|
|
|
0
|
$should_display_warning = vec( $bitmask, $offset, 1 ); |
1077
|
|
|
|
|
|
|
} |
1078
|
|
|
|
|
|
|
|
1079
|
1
|
|
|
|
|
3
|
my $r; |
1080
|
1
|
50
|
|
|
|
4
|
$r = Apache2::RequestUtil->request if( $MOD_PERL ); |
1081
|
|
|
|
|
|
|
# $r->log_error( "Called for error $o" ) if( $r ); |
1082
|
1
|
50
|
|
|
|
4
|
$r->warn( $o->as_string ) if( $r ); |
1083
|
1
|
|
|
|
|
7
|
my $err_handler = $self->error_handler; |
1084
|
1
|
50
|
33
|
|
|
21
|
if( $err_handler && ref( $err_handler ) eq 'CODE' ) |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1085
|
|
|
|
|
|
|
{ |
1086
|
|
|
|
|
|
|
# $r->log_error( "Module::Generic::error(): called for object error hanler" ) if( $r ); |
1087
|
0
|
|
|
|
|
0
|
$err_handler->( $o ); |
1088
|
|
|
|
|
|
|
} |
1089
|
|
|
|
|
|
|
elsif( $r ) |
1090
|
|
|
|
|
|
|
{ |
1091
|
|
|
|
|
|
|
# $r->log_error( "Module::Generic::error(): called for Apache mod_perl error hanler" ) if( $r ); |
1092
|
0
|
0
|
|
|
|
0
|
if( my $log_handler = $r->get_handlers( 'PerlPrivateErrorHandler' ) ) |
1093
|
|
|
|
|
|
|
{ |
1094
|
0
|
|
|
|
|
0
|
$log_handler->( $o ); |
1095
|
|
|
|
|
|
|
} |
1096
|
|
|
|
|
|
|
else |
1097
|
|
|
|
|
|
|
{ |
1098
|
|
|
|
|
|
|
# $r->log_error( "Module::Generic::error(): No Apache mod_perl error handler set, reverting to log_error" ) if( $r ); |
1099
|
|
|
|
|
|
|
# $r->log_error( "$o" ); |
1100
|
0
|
0
|
|
|
|
0
|
$r->warn( $o->as_string ) if( $should_display_warning ); |
1101
|
|
|
|
|
|
|
} |
1102
|
|
|
|
|
|
|
} |
1103
|
|
|
|
|
|
|
elsif( $this->{fatal} ) |
1104
|
|
|
|
|
|
|
{ |
1105
|
|
|
|
|
|
|
## die( sprintf( "Within package %s in file %s at line %d: %s\n", $o->package, $o->file, $o->line, $o->message ) ); |
1106
|
|
|
|
|
|
|
# $r->log_error( "Module::Generic::error(): called calling die" ) if( $r ); |
1107
|
0
|
|
|
|
|
0
|
my $enc_str = eval{ Encode::encode( 'UTF-8', "$o", Encode::FB_CROAK ) }; |
|
0
|
|
|
|
|
0
|
|
1108
|
0
|
0
|
|
|
|
0
|
die( $@ ? $o : $enc_str ); |
1109
|
|
|
|
|
|
|
} |
1110
|
|
|
|
|
|
|
elsif( !exists( $this->{quiet} ) || !$this->{quiet} ) |
1111
|
|
|
|
|
|
|
{ |
1112
|
|
|
|
|
|
|
# $r->log_error( "Module::Generic::error(): calling warn" ) if( $r ); |
1113
|
1
|
50
|
|
|
|
4
|
if( $r ) |
1114
|
|
|
|
|
|
|
{ |
1115
|
0
|
0
|
|
|
|
0
|
$r->warn( $o->as_string ) if( $should_display_warning ); |
1116
|
|
|
|
|
|
|
} |
1117
|
|
|
|
|
|
|
else |
1118
|
|
|
|
|
|
|
{ |
1119
|
1
|
|
|
|
|
3
|
my $enc_str = eval{ Encode::encode( 'UTF-8', "$o", Encode::FB_CROAK ) }; |
|
1
|
|
|
|
|
4
|
|
1120
|
1
|
0
|
|
|
|
272
|
warn( $@ ? $o : $enc_str ) if( $should_display_warning ); |
|
|
50
|
|
|
|
|
|
1121
|
|
|
|
|
|
|
} |
1122
|
|
|
|
|
|
|
} |
1123
|
|
|
|
|
|
|
|
1124
|
1
|
50
|
|
|
|
7
|
if( overload::Overloaded( $self ) ) |
1125
|
|
|
|
|
|
|
{ |
1126
|
1
|
|
|
|
|
54
|
my $overload_meth_ref = overload::Method( $self, '""' ); |
1127
|
1
|
|
|
|
|
111
|
my $overload_meth_name = Sub::Util::subname( $overload_meth_ref ); |
1128
|
|
|
|
|
|
|
## use Sub::Identify (); |
1129
|
|
|
|
|
|
|
## my( $over_file, $over_line ) = Sub::Identify::get_code_location( $overload_meth_ref ); |
1130
|
|
|
|
|
|
|
# my( $over_call_pack, $over_call_file, $over_call_line ) = caller(); |
1131
|
1
|
|
|
|
|
7
|
my $call_sub = (caller(1))[3]; |
1132
|
|
|
|
|
|
|
# my $call_hash = (caller(0))[10]; |
1133
|
|
|
|
|
|
|
# my @call_keys = CORE::keys( %$call_hash ); |
1134
|
|
|
|
|
|
|
# print( STDERR "\$self is overloaded and stringification method is '$overload_meth', its sub name is '$overload_meth_name' from file '$over_file' at line '$over_line' and our caller subroutine is '$call_sub' from file '$over_call_file' at line '$over_call_line' with hint hash keys '@call_keys'.\n" ); |
1135
|
|
|
|
|
|
|
## overloaded method name can be, for example: My::Package::as_string |
1136
|
|
|
|
|
|
|
## or, for anonymous sub: My::Package::__ANON__[lib/My/Package.pm:12] |
1137
|
|
|
|
|
|
|
## caller sub will reliably be the same, so we use it to check if we are called from an overloaded stringification and return undef right here. |
1138
|
|
|
|
|
|
|
## Want::want check of being called in an OBJECT context triggers a perl segmentation fault |
1139
|
1
|
50
|
|
|
|
6
|
if( $overload_meth_name eq $call_sub ) |
1140
|
|
|
|
|
|
|
{ |
1141
|
1
|
|
|
|
|
7
|
return; |
1142
|
|
|
|
|
|
|
} |
1143
|
|
|
|
|
|
|
} |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
## https://metacpan.org/pod/Perl::Critic::Policy::Subroutines::ProhibitExplicitReturnUndef |
1146
|
|
|
|
|
|
|
## https://perlmonks.org/index.pl?node_id=741847 |
1147
|
|
|
|
|
|
|
## Because in list context this would create a lit with one element undef() |
1148
|
|
|
|
|
|
|
## A bare return will return an empty list or an undef scalar |
1149
|
|
|
|
|
|
|
## return( undef() ); |
1150
|
|
|
|
|
|
|
## return; |
1151
|
|
|
|
|
|
|
## As of 2019-10-13, Module::Generic version 0.6, we use this special package Module::Generic::Null to be returned in chain without perl causing the error that a method was called on an undefined value |
1152
|
|
|
|
|
|
|
## 2020-05-12: Added the no_return_null_object to instruct not to return a null object |
1153
|
|
|
|
|
|
|
## This is especially needed when an error is called from TIEHASH that returns a special object. |
1154
|
|
|
|
|
|
|
## A Null object would trigger a fatal perl segmentation fault |
1155
|
0
|
0
|
0
|
|
|
0
|
if( !$args->{no_return_null_object} && want( 'OBJECT' ) ) |
1156
|
|
|
|
|
|
|
{ |
1157
|
0
|
|
|
|
|
0
|
my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 }); |
1158
|
0
|
|
|
|
|
0
|
rreturn( $null ); |
1159
|
|
|
|
|
|
|
} |
1160
|
0
|
|
|
|
|
0
|
return; |
1161
|
|
|
|
|
|
|
} |
1162
|
0
|
0
|
|
|
|
0
|
return( ref( $self ) ? $this->{error} : ${ $class . '::ERROR' } ); |
|
0
|
|
|
|
|
0
|
|
1163
|
|
|
|
|
|
|
} |
1164
|
|
|
|
|
|
|
|
1165
|
1
|
|
|
1
|
0
|
8
|
sub error_handler { return( shift->_set_get_code( '_error_handler', @_ ) ); } |
1166
|
|
|
|
|
|
|
|
1167
|
|
|
|
|
|
|
*errstr = \&error; |
1168
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
sub get |
1170
|
|
|
|
|
|
|
{ |
1171
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1172
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1173
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
1174
|
0
|
|
|
|
|
0
|
my @data = map{ $data->{ $_ } } @_; |
|
0
|
|
|
|
|
0
|
|
1175
|
0
|
0
|
|
|
|
0
|
return( wantarray() ? @data : $data[ 0 ] ); |
1176
|
|
|
|
|
|
|
} |
1177
|
|
|
|
|
|
|
|
1178
|
|
|
|
|
|
|
sub init |
1179
|
|
|
|
|
|
|
{ |
1180
|
264
|
|
|
264
|
1
|
619
|
my $self = shift( @_ ); |
1181
|
264
|
|
|
|
|
612
|
my $pkg = ref( $self ); |
1182
|
264
|
|
|
|
|
795
|
my $this = $self->_obj2h; |
1183
|
264
|
50
|
|
|
|
1554
|
$this->{verbose} = ${ $pkg . '::VERBOSE' } if( !length( $this->{verbose} ) ); |
|
264
|
|
|
|
|
1770
|
|
1184
|
264
|
100
|
|
|
|
983
|
$this->{debug} = ${ $pkg . '::DEBUG' } if( !length( $this->{debug} ) ); |
|
130
|
|
|
|
|
587
|
|
1185
|
264
|
50
|
|
|
|
1009
|
$this->{version} = ${ $pkg . '::VERSION' } if( !defined( $this->{version} ) ); |
|
264
|
|
|
|
|
1351
|
|
1186
|
264
|
|
|
|
|
897
|
$this->{level} = 0; |
1187
|
264
|
|
|
|
|
861
|
$self->{colour_open} = COLOUR_OPEN; |
1188
|
264
|
|
|
|
|
857
|
$self->{colour_close} = COLOUR_CLOSE; |
1189
|
|
|
|
|
|
|
## If no debug level was provided when calling message, this level will be assumed |
1190
|
|
|
|
|
|
|
## Example: message( "Hello" ); |
1191
|
|
|
|
|
|
|
## If _message_default_level was set to 3, this would be equivalent to message( 3, "Hello" ) |
1192
|
264
|
|
|
|
|
802
|
$this->{ '_message_default_level' } = 0; |
1193
|
264
|
|
|
|
|
670
|
my $data = $this; |
1194
|
264
|
50
|
|
|
|
809
|
if( $this->{_data_repo} ) |
1195
|
|
|
|
|
|
|
{ |
1196
|
0
|
0
|
|
|
|
0
|
$this->{ $this->{_data_repo} } = {} if( !$this->{ $this->{_data_repo} } ); |
1197
|
0
|
|
|
|
|
0
|
$data = $this->{ $this->{_data_repo} }; |
1198
|
|
|
|
|
|
|
} |
1199
|
264
|
50
|
66
|
|
|
1335
|
@_ = () if( @_ == 1 && !defined( $_[0] ) ); |
1200
|
264
|
100
|
|
|
|
794
|
if( @_ ) |
1201
|
|
|
|
|
|
|
{ |
1202
|
70
|
|
|
|
|
230
|
my @args = @_; |
1203
|
70
|
|
|
|
|
176
|
my $vals; |
1204
|
70
|
100
|
33
|
|
|
450
|
if( ref( $args[0] ) eq 'HASH' || |
|
|
50
|
66
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1205
|
|
|
|
|
|
|
( Scalar::Util::blessed( $args[0] ) && $args[0]->isa( 'Module::Generic::Hash' ) ) ) |
1206
|
|
|
|
|
|
|
{ |
1207
|
|
|
|
|
|
|
## $self->_message( 3, "Got an hash ref" ); |
1208
|
68
|
|
|
|
|
161
|
my $h = shift( @args ); |
1209
|
68
|
|
|
|
|
150
|
my $debug_value; |
1210
|
68
|
50
|
|
|
|
351
|
$debug_value = $h->{debug} if( CORE::exists( $h->{debug} ) ); |
1211
|
68
|
|
|
|
|
633
|
$vals = [ %$h ]; |
1212
|
68
|
100
|
|
|
|
474
|
unshift( @$vals, debug => $debug_value ) if( CORE::defined( $debug_value ) ); |
1213
|
|
|
|
|
|
|
## $vals = [ %{$_[0]} ]; |
1214
|
|
|
|
|
|
|
} |
1215
|
|
|
|
|
|
|
elsif( ref( $args[0] ) eq 'ARRAY' ) |
1216
|
|
|
|
|
|
|
{ |
1217
|
|
|
|
|
|
|
## $self->_message( 3, "Got an array ref" ); |
1218
|
0
|
|
|
|
|
0
|
$vals = $args[0]; |
1219
|
|
|
|
|
|
|
} |
1220
|
|
|
|
|
|
|
## Special case when there is an undefined value passed (null) even though it is declared as a hash or object |
1221
|
|
|
|
|
|
|
elsif( scalar( @args ) == 1 && !defined( $args[0] ) ) |
1222
|
|
|
|
|
|
|
{ |
1223
|
|
|
|
|
|
|
# return( undef() ); |
1224
|
0
|
|
|
|
|
0
|
return; |
1225
|
|
|
|
|
|
|
} |
1226
|
|
|
|
|
|
|
elsif( ( scalar( @args ) % 2 ) ) |
1227
|
|
|
|
|
|
|
{ |
1228
|
0
|
|
|
|
|
0
|
return( $self->error( sprintf( "Uneven number of parameters provided (%d). Should receive key => value pairs. Parameters provideds are: %s", scalar( @args ), join( ', ', @args ) ) ) ); |
1229
|
|
|
|
|
|
|
} |
1230
|
|
|
|
|
|
|
else |
1231
|
|
|
|
|
|
|
{ |
1232
|
|
|
|
|
|
|
## $self->message( 3, "Got an array: ", sub{ $self->dumper( \@args ) } ); |
1233
|
2
|
|
|
|
|
7
|
$vals = \@args; |
1234
|
|
|
|
|
|
|
} |
1235
|
|
|
|
|
|
|
## Check if there is a debug parameter, and if we find one, set it first so that that |
1236
|
|
|
|
|
|
|
## calls to the package subroutines can produce verbose feedback as necessary |
1237
|
70
|
|
|
|
|
379
|
for( my $i = 0; $i < scalar( @$vals ); $i++ ) |
1238
|
|
|
|
|
|
|
{ |
1239
|
1895
|
100
|
|
|
|
4132
|
if( $vals->[$i] eq 'debug' ) |
1240
|
|
|
|
|
|
|
{ |
1241
|
131
|
|
|
|
|
311
|
my $v = $vals->[$i + 1]; |
1242
|
131
|
|
|
|
|
563
|
$self->debug( $v ); |
1243
|
131
|
|
|
|
|
502
|
CORE::splice( @$vals, $i, 2 ); |
1244
|
|
|
|
|
|
|
} |
1245
|
|
|
|
|
|
|
} |
1246
|
|
|
|
|
|
|
|
1247
|
70
|
|
|
|
|
365
|
for( my $i = 0; $i < scalar( @$vals ); $i++ ) |
1248
|
|
|
|
|
|
|
{ |
1249
|
947
|
|
|
|
|
1795
|
my $name = $vals->[ $i ]; |
1250
|
947
|
|
|
|
|
1682
|
my $val = $vals->[ ++$i ]; |
1251
|
947
|
|
|
|
|
2862
|
my $meth = $self->can( $name ); |
1252
|
|
|
|
|
|
|
# $self->message( 3, "Does the object from class (", ref( $self ), ") has a method $name? ", ( defined( $meth ) ? 'yes' : 'no' ) ); |
1253
|
947
|
50
|
|
|
|
2035
|
if( defined( $meth ) ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1254
|
|
|
|
|
|
|
{ |
1255
|
947
|
|
|
|
|
2785
|
$self->$name( $val ); |
1256
|
947
|
|
|
|
|
3766
|
next; |
1257
|
|
|
|
|
|
|
} |
1258
|
|
|
|
|
|
|
elsif( $this->{_init_strict_use_sub} ) |
1259
|
|
|
|
|
|
|
{ |
1260
|
|
|
|
|
|
|
# $self->message( 3, "Checking if method $name exist in class ", ref( $self ), ": ", $self->can( $name ) ? 'yes' : 'no' ); |
1261
|
|
|
|
|
|
|
#if( !defined( $meth = $self->can( $name ) ) ) |
1262
|
|
|
|
|
|
|
#{ |
1263
|
0
|
|
|
|
|
0
|
$self->error( "Unknown method $name in class $pkg" ); |
1264
|
0
|
|
|
|
|
0
|
next; |
1265
|
|
|
|
|
|
|
#} |
1266
|
|
|
|
|
|
|
# $self->message( 3, "Calling method $name with value $val" ); |
1267
|
|
|
|
|
|
|
# $self->$meth( $val ); |
1268
|
|
|
|
|
|
|
# $meth->( $self, $val ); |
1269
|
|
|
|
|
|
|
#$self->$name( $val ); |
1270
|
|
|
|
|
|
|
#next; |
1271
|
|
|
|
|
|
|
} |
1272
|
|
|
|
|
|
|
elsif( exists( $data->{ $name } ) ) |
1273
|
|
|
|
|
|
|
{ |
1274
|
|
|
|
|
|
|
## Pre-existing field value looks like a module package and that package is already loaded |
1275
|
0
|
0
|
0
|
|
|
0
|
if( ( index( $data->{ $name }, '::' ) != -1 || $data->{ $name } =~ /^[a-zA-Z][a-zA-Z\_]*[a-zA-Z]$/ ) && |
|
|
0
|
0
|
|
|
|
|
1276
|
|
|
|
|
|
|
$self->_is_class_loaded( $data->{ $name } ) ) |
1277
|
|
|
|
|
|
|
{ |
1278
|
0
|
|
|
|
|
0
|
my $thisPack = $data->{ $name }; |
1279
|
0
|
0
|
|
|
|
0
|
if( !Scalar::Util::blessed( $val ) ) |
|
|
0
|
|
|
|
|
|
1280
|
|
|
|
|
|
|
{ |
1281
|
0
|
|
|
|
|
0
|
return( $self->error( "$name parameter expects a package $thisPack object, but instead got '$val'." ) ); |
1282
|
|
|
|
|
|
|
} |
1283
|
|
|
|
|
|
|
elsif( !$val->isa( $thisPack ) ) |
1284
|
|
|
|
|
|
|
{ |
1285
|
0
|
|
|
|
|
0
|
return( $self->error( "$name parameter expects a package $thisPack object, but instead got an object from package '", ref( $val ), "'." ) ); |
1286
|
|
|
|
|
|
|
} |
1287
|
|
|
|
|
|
|
} |
1288
|
|
|
|
|
|
|
elsif( $this->{_init_strict} ) |
1289
|
|
|
|
|
|
|
{ |
1290
|
0
|
0
|
|
|
|
0
|
if( ref( $data->{ $name } ) eq 'ARRAY' ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1291
|
|
|
|
|
|
|
{ |
1292
|
0
|
0
|
|
|
|
0
|
return( $self->error( "$name parameter expects an array reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'ARRAY' ); |
1293
|
|
|
|
|
|
|
} |
1294
|
|
|
|
|
|
|
elsif( ref( $data->{ $name } ) eq 'HASH' ) |
1295
|
|
|
|
|
|
|
{ |
1296
|
0
|
0
|
|
|
|
0
|
return( $self->error( "$name parameter expects an hash reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'HASH' ); |
1297
|
|
|
|
|
|
|
} |
1298
|
|
|
|
|
|
|
elsif( ref( $data->{ $name } ) eq 'SCALAR' ) |
1299
|
|
|
|
|
|
|
{ |
1300
|
0
|
0
|
|
|
|
0
|
return( $self->error( "$name parameter expects a scalar reference, but instead got '$val'." ) ) if( Scalar::Util::reftype( $val ) ne 'SCALAR' ); |
1301
|
|
|
|
|
|
|
} |
1302
|
|
|
|
|
|
|
} |
1303
|
|
|
|
|
|
|
} |
1304
|
|
|
|
|
|
|
## The name parameter does not exist |
1305
|
|
|
|
|
|
|
else |
1306
|
|
|
|
|
|
|
{ |
1307
|
|
|
|
|
|
|
## If we are strict, we reject |
1308
|
0
|
0
|
|
|
|
0
|
next if( $this->{_init_strict} ); |
1309
|
|
|
|
|
|
|
} |
1310
|
|
|
|
|
|
|
## We passed all tests |
1311
|
0
|
|
|
|
|
0
|
$data->{ $name } = $val; |
1312
|
|
|
|
|
|
|
} |
1313
|
|
|
|
|
|
|
} |
1314
|
264
|
0
|
33
|
|
|
936
|
if( $OPTIMIZE_MESG_SUB && !$this->{verbose} && !$this->{debug} ) |
|
|
|
33
|
|
|
|
|
1315
|
|
|
|
|
|
|
{ |
1316
|
0
|
0
|
|
|
|
0
|
if( defined( &{ "$pkg\::message" } ) ) |
|
0
|
|
|
|
|
0
|
|
1317
|
|
|
|
|
|
|
{ |
1318
|
0
|
0
|
|
|
|
0
|
*{ "$pkg\::message_off" } = \&{ "$pkg\::message" } unless( defined( &{ "$pkg\::message_off" } ) ); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1319
|
0
|
|
|
0
|
|
0
|
*{ "$pkg\::message" } = sub { 1 }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1320
|
|
|
|
|
|
|
} |
1321
|
|
|
|
|
|
|
} |
1322
|
264
|
|
|
|
|
572
|
return( $self ); |
1323
|
|
|
|
|
|
|
} |
1324
|
|
|
|
|
|
|
|
1325
|
0
|
|
|
0
|
1
|
0
|
sub log_handler { return( shift->_set_get_code( '_log_handler', @_ ) ); } |
1326
|
|
|
|
|
|
|
|
1327
|
|
|
|
|
|
|
# sub log4perl |
1328
|
|
|
|
|
|
|
# { |
1329
|
|
|
|
|
|
|
# my $self = shift( @_ ); |
1330
|
|
|
|
|
|
|
# if( @_ ) |
1331
|
|
|
|
|
|
|
# { |
1332
|
|
|
|
|
|
|
# require Log::Log4perl; |
1333
|
|
|
|
|
|
|
# my $ref = shift( @_ ); |
1334
|
|
|
|
|
|
|
# Log::Log4perl::init( $ref->{ 'config_file' } ); |
1335
|
|
|
|
|
|
|
# my $log = Log::Log4perl->get_logger( $ref->{ 'domain' } ); |
1336
|
|
|
|
|
|
|
# $self->{ 'log4perl' } = $log; |
1337
|
|
|
|
|
|
|
# } |
1338
|
|
|
|
|
|
|
# else |
1339
|
|
|
|
|
|
|
# { |
1340
|
|
|
|
|
|
|
# $self->{ 'log4perl' }; |
1341
|
|
|
|
|
|
|
# } |
1342
|
|
|
|
|
|
|
# } |
1343
|
|
|
|
|
|
|
|
1344
|
|
|
|
|
|
|
sub message |
1345
|
|
|
|
|
|
|
{ |
1346
|
218
|
|
|
218
|
1
|
282
|
my $self = shift( @_ ); |
1347
|
218
|
|
33
|
|
|
418
|
my $class = ref( $self ) || $self; |
1348
|
|
|
|
|
|
|
## my( $pack, $file, $line ) = caller; |
1349
|
218
|
|
|
|
|
328
|
my $this = $self->_obj2h; |
1350
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::message(): Called from package $pack in file $file at line $line with debug value '$hash->{debug}', package DEBUG value '", ${ $class . '::DEBUG' }, "' and params '", join( "', '", @_ ), "'\n" ); |
1351
|
218
|
|
|
|
|
243
|
my $r; |
1352
|
218
|
50
|
|
|
|
310
|
$r = Apache2::RequestUtil->request if( $MOD_PERL ); |
1353
|
218
|
50
|
33
|
|
|
655
|
if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } ) |
|
0
|
|
33
|
|
|
0
|
|
1354
|
|
|
|
|
|
|
{ |
1355
|
|
|
|
|
|
|
# $r->log_error( "Got here in Module::Generic::message before checking message." ) if( $r ); |
1356
|
218
|
|
|
|
|
226
|
my $ref; |
1357
|
218
|
|
|
|
|
310
|
$ref = $self->message_check( @_ ); |
1358
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::message(): message_check() returns '$ref' (", join( '', @$ref ), ")\n" ); |
1359
|
|
|
|
|
|
|
## return( 1 ) if( !( $ref = $self->message_check( @_ ) ) ); |
1360
|
218
|
50
|
|
|
|
426
|
return( 1 ) if( !$ref ); |
1361
|
|
|
|
|
|
|
|
1362
|
0
|
|
|
|
|
0
|
my $opts = {}; |
1363
|
0
|
0
|
|
|
|
0
|
$opts = pop( @$ref ) if( ref( $ref->[-1] ) eq 'HASH' ); |
1364
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::message(): \$opts contains: ", $self->dumper( $opts ), "\n" ); |
1365
|
|
|
|
|
|
|
|
1366
|
|
|
|
|
|
|
## By now, we should have a reference to @_ in $ref |
1367
|
|
|
|
|
|
|
## my $class = ref( $self ) || $self; |
1368
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::message(): caller at 0 is ", (caller(0))[3], " and at 1 is ", (caller(1))[3], "\n" ); |
1369
|
|
|
|
|
|
|
## $r->log_error( "Got here in Module::Generic::message checking frames stack." ) if( $r ); |
1370
|
0
|
|
0
|
|
|
0
|
my $stackFrame = $self->message_frame( (caller(1))[3] ) || 1; |
1371
|
0
|
0
|
|
|
|
0
|
$stackFrame = 1 unless( $stackFrame =~ /^\d+$/ ); |
1372
|
0
|
0
|
|
|
|
0
|
$stackFrame-- if( $stackFrame ); |
1373
|
0
|
0
|
0
|
|
|
0
|
$stackFrame++ if( (caller(1))[3] eq 'Module::Generic::messagef' || |
1374
|
|
|
|
|
|
|
(caller(1))[3] eq 'Module::Generic::message_colour' ); |
1375
|
0
|
0
|
|
|
|
0
|
$stackFrame++ if( (caller(2))[3] eq 'Module::Generic::messagef_colour' ); |
1376
|
0
|
|
|
|
|
0
|
my( $pkg, $file, $line, @otherInfo ) = caller( $stackFrame ); |
1377
|
0
|
|
|
|
|
0
|
my $sub = ( caller( $stackFrame + 1 ) )[3]; |
1378
|
0
|
|
|
|
|
0
|
my $sub2 = substr( $sub, rindex( $sub, '::' ) + 2 ); |
1379
|
0
|
0
|
|
|
|
0
|
if( ref( $this->{_message_frame} ) eq 'HASH' ) |
1380
|
|
|
|
|
|
|
{ |
1381
|
0
|
0
|
|
|
|
0
|
if( exists( $this->{_message_frame}->{ $sub2 } ) ) |
1382
|
|
|
|
|
|
|
{ |
1383
|
0
|
|
|
|
|
0
|
my $frameNo = int( $this->{_message_frame}->{ $sub2 } ); |
1384
|
0
|
0
|
|
|
|
0
|
if( $frameNo > 0 ) |
1385
|
|
|
|
|
|
|
{ |
1386
|
0
|
|
|
|
|
0
|
( $pkg, $file, $line, $sub ) = caller( $frameNo ); |
1387
|
0
|
|
|
|
|
0
|
$sub2 = substr( $sub, rindex( $sub, '::' ) + 2 ); |
1388
|
|
|
|
|
|
|
} |
1389
|
|
|
|
|
|
|
} |
1390
|
|
|
|
|
|
|
} |
1391
|
|
|
|
|
|
|
## $r->log_error( "Called from package $pkg in file $file at line $line from sub $sub2 ($sub)" ) if( $r ); |
1392
|
0
|
0
|
|
|
|
0
|
if( $sub2 eq 'message' ) |
1393
|
|
|
|
|
|
|
{ |
1394
|
0
|
|
|
|
|
0
|
$stackFrame++; |
1395
|
0
|
|
|
|
|
0
|
( $pkg, $file, $line, @otherInfo ) = caller( $stackFrame ); |
1396
|
0
|
|
|
|
|
0
|
my $sub = ( caller( $stackFrame + 1 ) )[3]; |
1397
|
0
|
|
|
|
|
0
|
$sub2 = substr( $sub, rindex( $sub, '::' ) + 2 ); |
1398
|
|
|
|
|
|
|
} |
1399
|
|
|
|
|
|
|
## $r->log_error( "Got here in Module::Generic::message building the message string." ) if( $r ); |
1400
|
0
|
|
|
|
|
0
|
my $txt; |
1401
|
0
|
0
|
|
|
|
0
|
if( $opts->{message} ) |
1402
|
|
|
|
|
|
|
{ |
1403
|
0
|
0
|
|
|
|
0
|
if( ref( $opts->{message} ) eq 'ARRAY' ) |
1404
|
|
|
|
|
|
|
{ |
1405
|
0
|
0
|
0
|
|
|
0
|
$txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @{$opts->{message}} ) ); |
|
0
|
|
|
|
|
0
|
|
1406
|
|
|
|
|
|
|
} |
1407
|
|
|
|
|
|
|
else |
1408
|
|
|
|
|
|
|
{ |
1409
|
0
|
|
|
|
|
0
|
$txt = $opts->{message}; |
1410
|
|
|
|
|
|
|
} |
1411
|
|
|
|
|
|
|
} |
1412
|
|
|
|
|
|
|
else |
1413
|
|
|
|
|
|
|
{ |
1414
|
0
|
0
|
0
|
|
|
0
|
$txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) ); |
1415
|
|
|
|
|
|
|
} |
1416
|
|
|
|
|
|
|
## Reset it |
1417
|
0
|
|
|
|
|
0
|
$this->{_msg_no_exec_sub} = 0; |
1418
|
|
|
|
|
|
|
## $r->log_error( "Got here in Module::Generic::message with message string '$txt'." ) if( $r ); |
1419
|
6
|
|
|
6
|
|
95
|
no overloading; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
27439
|
|
1420
|
0
|
|
|
|
|
0
|
my $mesg = "${pkg}::${sub2}( $self ) [$line]: " . $txt; |
1421
|
0
|
|
|
|
|
0
|
$mesg =~ s/\n$//gs; |
1422
|
0
|
|
|
|
|
0
|
$mesg = '## ' . join( "\n## ", split( /\n/, $mesg ) ); |
1423
|
|
|
|
|
|
|
|
1424
|
|
|
|
|
|
|
my $info = |
1425
|
|
|
|
|
|
|
{ |
1426
|
|
|
|
|
|
|
'formatted' => $mesg, |
1427
|
|
|
|
|
|
|
'message' => $txt, |
1428
|
|
|
|
|
|
|
'file' => $file, |
1429
|
|
|
|
|
|
|
'line' => $line, |
1430
|
|
|
|
|
|
|
'package' => $class, |
1431
|
|
|
|
|
|
|
'sub' => $sub2, |
1432
|
0
|
0
|
|
|
|
0
|
'level' => ( $_[0] =~ /^\d+$/ ? $_[0] : CORE::exists( $opts->{level} ) ? $opts->{level} : 0 ), |
|
|
0
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
}; |
1434
|
0
|
0
|
|
|
|
0
|
$info->{type} = $opts->{type} if( $opts->{type} ); |
1435
|
|
|
|
|
|
|
|
1436
|
|
|
|
|
|
|
## $r->log_error( "Got here in Module::Generic::message checkin if we run under ModPerl." ) if( $r ); |
1437
|
|
|
|
|
|
|
## If Mod perl is activated AND we are not using a private log |
1438
|
|
|
|
|
|
|
## my $r; |
1439
|
|
|
|
|
|
|
## if( $MOD_PERL && !${ "${class}::LOG_DEBUG" } && ( $r = eval{ require Apache2::RequestUtil; Apache2::RequestUtil->request; } ) ) |
1440
|
0
|
0
|
0
|
|
|
0
|
if( $r && !${ "${class}::LOG_DEBUG" } ) |
|
0
|
0
|
0
|
|
|
0
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1441
|
|
|
|
|
|
|
{ |
1442
|
|
|
|
|
|
|
## $r->log_error( "Got here in Module::Generic::message, going to call our log handler." ); |
1443
|
0
|
0
|
|
|
|
0
|
if( my $log_handler = $r->get_handlers( 'PerlPrivateLogHandler' ) ) |
1444
|
|
|
|
|
|
|
{ |
1445
|
|
|
|
|
|
|
# my $meta = B::svref_2object( $log_handler ); |
1446
|
|
|
|
|
|
|
# $r->log_error( "Module::Generic::message(): Log handler code routine name is " . $meta->GV->NAME . " called in file " . $meta->GV->FILE . " at line " . $meta->GV->LINE ); |
1447
|
0
|
|
|
|
|
0
|
$log_handler->( $mesg ); |
1448
|
|
|
|
|
|
|
} |
1449
|
|
|
|
|
|
|
else |
1450
|
|
|
|
|
|
|
{ |
1451
|
0
|
|
|
|
|
0
|
$r->log_error( $mesg ); |
1452
|
|
|
|
|
|
|
} |
1453
|
|
|
|
|
|
|
} |
1454
|
|
|
|
|
|
|
## Using ModPerl Server to log |
1455
|
0
|
|
|
|
|
0
|
elsif( $MOD_PERL && !${ "${class}::LOG_DEBUG" } ) |
1456
|
|
|
|
|
|
|
{ |
1457
|
0
|
|
|
|
|
0
|
require Apache2::ServerUtil; |
1458
|
0
|
|
|
|
|
0
|
my $s = Apache2::ServerUtil->server; |
1459
|
0
|
|
|
|
|
0
|
$s->log_error( $mesg ); |
1460
|
|
|
|
|
|
|
} |
1461
|
|
|
|
|
|
|
## e.g. in our package, we could set the handler using the curry module like $self->{_log_handler} = $self->curry::log |
1462
|
|
|
|
|
|
|
elsif( !-t( STDIN ) && $this->{_log_handler} && ref( $this->{_log_handler} ) eq 'CODE' ) |
1463
|
|
|
|
|
|
|
{ |
1464
|
|
|
|
|
|
|
# $r = Apache2::RequestUtil->request; |
1465
|
|
|
|
|
|
|
# $r->log_error( "Got here in Module::Generic::message, going to call our log handler without using Apache callbacks." ); |
1466
|
|
|
|
|
|
|
# my $meta = B::svref_2object( $self->{_log_handler} ); |
1467
|
|
|
|
|
|
|
# $r->log_error( "Log handler code routine name is " . $meta->GV->NAME . " called in file " . $meta->GV->FILE . " at line " . $meta->GV->LINE ); |
1468
|
0
|
|
|
|
|
0
|
$this->{_log_handler}->( $info ); |
1469
|
|
|
|
|
|
|
} |
1470
|
0
|
|
|
|
|
0
|
elsif( !-t( STDIN ) && ${ $class . '::MESSAGE_HANDLER' } && ref( ${ $class . '::MESSAGE_HANDLER' } ) eq 'CODE' ) |
|
0
|
|
|
|
|
0
|
|
1471
|
|
|
|
|
|
|
{ |
1472
|
0
|
|
|
|
|
0
|
my $h = ${ $class . '::MESSAGE_HANDLER' }; |
|
0
|
|
|
|
|
0
|
|
1473
|
0
|
|
|
|
|
0
|
$h->( $info ); |
1474
|
|
|
|
|
|
|
} |
1475
|
|
|
|
|
|
|
## Or maybe then into a private log file? |
1476
|
|
|
|
|
|
|
## This way, even if the log method is superseeded, we can keep using ours without interfering with the other one |
1477
|
|
|
|
|
|
|
elsif( $self->message_log( $mesg, "\n" ) ) |
1478
|
|
|
|
|
|
|
{ |
1479
|
0
|
|
|
|
|
0
|
return( 1 ); |
1480
|
|
|
|
|
|
|
} |
1481
|
|
|
|
|
|
|
## Otherwise just on the stderr |
1482
|
|
|
|
|
|
|
else |
1483
|
|
|
|
|
|
|
{ |
1484
|
0
|
|
|
|
|
0
|
my $err = IO::File->new; |
1485
|
0
|
|
|
|
|
0
|
$err->fdopen( fileno( STDERR ), 'w' ); |
1486
|
0
|
0
|
|
|
|
0
|
$err->binmode( ":utf8" ) unless( $opts->{no_encoding} ); |
1487
|
0
|
|
|
|
|
0
|
$err->autoflush( 1 ); |
1488
|
0
|
|
|
|
|
0
|
$err->print( $mesg, "\n" ); |
1489
|
|
|
|
|
|
|
} |
1490
|
|
|
|
|
|
|
} |
1491
|
0
|
|
|
|
|
0
|
return( 1 ); |
1492
|
|
|
|
|
|
|
} |
1493
|
|
|
|
|
|
|
|
1494
|
|
|
|
|
|
|
*message_color = \&message_colour; |
1495
|
|
|
|
|
|
|
|
1496
|
|
|
|
|
|
|
sub message_colour |
1497
|
|
|
|
|
|
|
{ |
1498
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1499
|
0
|
|
0
|
|
|
0
|
my $class = ref( $self ) || $self; |
1500
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1501
|
0
|
0
|
0
|
|
|
0
|
if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } ) |
|
0
|
|
0
|
|
|
0
|
|
1502
|
|
|
|
|
|
|
{ |
1503
|
0
|
0
|
|
|
|
0
|
my $level = ( $_[0] =~ /^\d+$/ ? shift( @_ ) : undef() ); |
1504
|
0
|
|
|
|
|
0
|
my $opts = {}; |
1505
|
0
|
0
|
0
|
|
|
0
|
if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' && ( CORE::exists( $_[-1]->{level} ) || CORE::exists( $_[-1]->{type} ) || CORE::exists( $_[-1]->{message} ) ) ) |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1506
|
|
|
|
|
|
|
{ |
1507
|
0
|
|
|
|
|
0
|
$opts = pop( @_ ); |
1508
|
|
|
|
|
|
|
} |
1509
|
0
|
|
|
|
|
0
|
my $ref = [@_]; |
1510
|
0
|
0
|
0
|
|
|
0
|
$level = $opts->{level} if( !defined( $level ) && CORE::exists( $opts->{level} ) ); |
1511
|
0
|
|
|
|
|
0
|
my $txt; |
1512
|
0
|
0
|
|
|
|
0
|
if( $opts->{message} ) |
1513
|
|
|
|
|
|
|
{ |
1514
|
0
|
0
|
|
|
|
0
|
if( ref( $opts->{message} ) eq 'ARRAY' ) |
1515
|
|
|
|
|
|
|
{ |
1516
|
0
|
0
|
0
|
|
|
0
|
$txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @{$opts->{message}} ) ); |
|
0
|
|
|
|
|
0
|
|
1517
|
|
|
|
|
|
|
} |
1518
|
|
|
|
|
|
|
else |
1519
|
|
|
|
|
|
|
{ |
1520
|
0
|
|
|
|
|
0
|
$txt = $opts->{message}; |
1521
|
|
|
|
|
|
|
} |
1522
|
|
|
|
|
|
|
} |
1523
|
|
|
|
|
|
|
else |
1524
|
|
|
|
|
|
|
{ |
1525
|
0
|
0
|
0
|
|
|
0
|
$txt = join( '', map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) ); |
1526
|
|
|
|
|
|
|
} |
1527
|
0
|
|
|
|
|
0
|
$txt = $self->colour_parse( $txt ); |
1528
|
0
|
|
|
|
|
0
|
$opts->{message} = $txt; |
1529
|
0
|
0
|
|
|
|
0
|
$opts->{level} = $level if( defined( $level ) ); |
1530
|
0
|
|
0
|
|
|
0
|
return( $self->message( ( $level || 0 ), $opts ) ); |
1531
|
|
|
|
|
|
|
} |
1532
|
0
|
|
|
|
|
0
|
return( 1 ); |
1533
|
|
|
|
|
|
|
} |
1534
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
sub messagef |
1536
|
|
|
|
|
|
|
{ |
1537
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1538
|
|
|
|
|
|
|
## print( STDERR "got here: ", ref( $self ), "::messagef\n" ); |
1539
|
0
|
|
0
|
|
|
0
|
my $class = ref( $self ) || $self; |
1540
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1541
|
0
|
0
|
0
|
|
|
0
|
if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } ) |
|
0
|
|
0
|
|
|
0
|
|
1542
|
|
|
|
|
|
|
{ |
1543
|
0
|
0
|
|
|
|
0
|
my $level = ( $_[0] =~ /^\d+$/ ? shift( @_ ) : undef() ); |
1544
|
0
|
|
|
|
|
0
|
my $opts = {}; |
1545
|
0
|
0
|
0
|
|
|
0
|
if( scalar( @_ ) > 1 && ref( $_[-1] ) eq 'HASH' && ( CORE::exists( $_[-1]->{level} ) || CORE::exists( $_[-1]->{type} ) || CORE::exists( $_[-1]->{message} ) || CORE::exists( $_[-1]->{colour} ) ) ) |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1546
|
|
|
|
|
|
|
{ |
1547
|
0
|
|
|
|
|
0
|
$opts = pop( @_ ); |
1548
|
|
|
|
|
|
|
} |
1549
|
0
|
0
|
0
|
|
|
0
|
$level = $opts->{level} if( !defined( $level ) && CORE::exists( $opts->{level} ) ); |
1550
|
0
|
|
|
|
|
0
|
my( $ref, $fmt ); |
1551
|
0
|
0
|
|
|
|
0
|
if( $opts->{message} ) |
1552
|
|
|
|
|
|
|
{ |
1553
|
0
|
0
|
|
|
|
0
|
if( ref( $opts->{message} ) eq 'ARRAY' ) |
1554
|
|
|
|
|
|
|
{ |
1555
|
0
|
|
|
|
|
0
|
$ref = $opts->{message}; |
1556
|
0
|
|
|
|
|
0
|
$fmt = shift( @$ref ); |
1557
|
|
|
|
|
|
|
} |
1558
|
|
|
|
|
|
|
else |
1559
|
|
|
|
|
|
|
{ |
1560
|
0
|
|
|
|
|
0
|
$fmt = $opts->{message}; |
1561
|
0
|
|
|
|
|
0
|
$ref = \@_; |
1562
|
|
|
|
|
|
|
} |
1563
|
|
|
|
|
|
|
} |
1564
|
|
|
|
|
|
|
else |
1565
|
|
|
|
|
|
|
{ |
1566
|
0
|
|
|
|
|
0
|
$ref = \@_; |
1567
|
0
|
|
|
|
|
0
|
$fmt = shift( @$ref ); |
1568
|
|
|
|
|
|
|
} |
1569
|
0
|
0
|
0
|
|
|
0
|
my $txt = sprintf( $fmt, map( ( ref( $_ ) eq 'CODE' && !$this->{_msg_no_exec_sub} ) ? $_->() : $_, @$ref ) ); |
1570
|
|
|
|
|
|
|
## $self->message( 3, "Option colour set? '$opts->{colour}'. Text is: '$txt'" ); |
1571
|
0
|
0
|
|
|
|
0
|
$txt = $self->colour_parse( $txt ) if( $opts->{colour} ); |
1572
|
|
|
|
|
|
|
## print( STDERR ref( $self ), "::messagef \$txt is '$txt'\n" ); |
1573
|
0
|
|
|
|
|
0
|
$opts->{message} = $txt; |
1574
|
0
|
0
|
|
|
|
0
|
$opts->{level} = $level if( defined( $level ) ); |
1575
|
|
|
|
|
|
|
# return( $self->message( defined( $level ) ? ( $level, $txt ) : $txt ) ); |
1576
|
0
|
|
0
|
|
|
0
|
return( $self->message( ( $level || 0 ), $opts ) ); |
1577
|
|
|
|
|
|
|
} |
1578
|
0
|
|
|
|
|
0
|
return( 1 ); |
1579
|
|
|
|
|
|
|
} |
1580
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
sub messagef_colour |
1582
|
|
|
|
|
|
|
{ |
1583
|
0
|
|
|
0
|
0
|
0
|
my $self = shift( @_ ); |
1584
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1585
|
0
|
0
|
0
|
|
|
0
|
if( $this->{verbose} || $this->{debug} || ${ $class . '::DEBUG' } ) |
|
0
|
|
0
|
|
|
0
|
|
1586
|
|
|
|
|
|
|
{ |
1587
|
0
|
|
|
|
|
0
|
my @args = @_; |
1588
|
0
|
|
|
|
|
0
|
my $opts = {}; |
1589
|
0
|
0
|
0
|
|
|
0
|
if( scalar( @args ) > 1 && ref( $args[-1] ) eq 'HASH' && ( CORE::exists( $args[-1]->{level} ) || CORE::exists( $args[-1]->{type} ) || CORE::exists( $args[-1]->{message} ) ) ) |
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
1590
|
|
|
|
|
|
|
{ |
1591
|
0
|
|
|
|
|
0
|
$opts = pop( @args ); |
1592
|
|
|
|
|
|
|
} |
1593
|
0
|
|
|
|
|
0
|
$opts->{colour} = 1; |
1594
|
0
|
|
|
|
|
0
|
CORE::push( @args, $opts ); |
1595
|
|
|
|
|
|
|
## $self->message( 0, "Sending arguments: ", sub{ $self->dumper( \@args ) } ); |
1596
|
0
|
|
|
|
|
0
|
return( $this->messagef( @args ) ); |
1597
|
|
|
|
|
|
|
} |
1598
|
0
|
|
|
|
|
0
|
return( 1 ); |
1599
|
|
|
|
|
|
|
} |
1600
|
|
|
|
|
|
|
|
1601
|
|
|
|
|
|
|
sub message_check |
1602
|
|
|
|
|
|
|
{ |
1603
|
218
|
|
|
218
|
1
|
253
|
my $self = shift( @_ ); |
1604
|
218
|
|
33
|
|
|
357
|
my $class = ref( $self ) || $self; |
1605
|
218
|
|
|
|
|
279
|
my $this = $self->_obj2h; |
1606
|
|
|
|
|
|
|
## printf( STDERR "Our class is $class and DEBUG_TARGET contains: '%s' and debug value is %s\n", join( ', ', @${ "${class}::DEBUG_TARGET" } ), $hash->{ 'debug' } ); |
1607
|
218
|
50
|
|
|
|
362
|
if( @_ ) |
1608
|
|
|
|
|
|
|
{ |
1609
|
218
|
50
|
|
|
|
484
|
if( $_[0] !~ /^\d/ ) |
1610
|
|
|
|
|
|
|
{ |
1611
|
|
|
|
|
|
|
## The last parameter is an options parameter which has the level property set |
1612
|
0
|
0
|
0
|
|
|
0
|
if( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) ) |
|
|
0
|
0
|
|
|
|
|
1613
|
|
|
|
|
|
|
{ |
1614
|
|
|
|
|
|
|
## Then let's use this |
1615
|
|
|
|
|
|
|
} |
1616
|
|
|
|
|
|
|
elsif( $this->{ '_message_default_level' } =~ /^\d+$/ && |
1617
|
|
|
|
|
|
|
$this->{ '_message_default_level' } > 0 ) |
1618
|
|
|
|
|
|
|
{ |
1619
|
0
|
|
|
|
|
0
|
unshift( @_, $this->{ '_message_default_level' } ); |
1620
|
|
|
|
|
|
|
} |
1621
|
|
|
|
|
|
|
else |
1622
|
|
|
|
|
|
|
{ |
1623
|
0
|
|
|
|
|
0
|
unshift( @_, 1 ); |
1624
|
|
|
|
|
|
|
} |
1625
|
|
|
|
|
|
|
} |
1626
|
|
|
|
|
|
|
## If the first argument looks line a number, and there is more than 1 argument |
1627
|
|
|
|
|
|
|
## and it is greater than 1, and greater than our current debug level |
1628
|
|
|
|
|
|
|
## well, we do not output anything then... |
1629
|
218
|
50
|
33
|
|
|
791
|
if( ( $_[ 0 ] =~ /^\d+$/ || ( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) ) ) && |
|
|
|
33
|
|
|
|
|
1630
|
|
|
|
|
|
|
@_ > 1 ) |
1631
|
|
|
|
|
|
|
{ |
1632
|
218
|
|
|
|
|
255
|
my $message_level; |
1633
|
218
|
50
|
0
|
|
|
365
|
if( $_[ 0 ] =~ /^\d+$/ ) |
|
|
0
|
|
|
|
|
|
1634
|
|
|
|
|
|
|
{ |
1635
|
218
|
|
|
|
|
291
|
$message_level = shift( @_ ); |
1636
|
|
|
|
|
|
|
} |
1637
|
|
|
|
|
|
|
elsif( ref( $_[-1] ) eq 'HASH' && CORE::exists( $_[-1]->{level} ) ) |
1638
|
|
|
|
|
|
|
{ |
1639
|
0
|
|
|
|
|
0
|
$message_level = $_[-1]->{level}; |
1640
|
|
|
|
|
|
|
} |
1641
|
218
|
|
|
|
|
255
|
my $target_re = ''; |
1642
|
218
|
50
|
|
|
|
231
|
if( ref( ${ "${class}::DEBUG_TARGET" } ) eq 'ARRAY' ) |
|
218
|
|
|
|
|
536
|
|
1643
|
|
|
|
|
|
|
{ |
1644
|
0
|
0
|
|
|
|
0
|
$target_re = scalar( @${ "${class}::DEBUG_TARGET" } ) ? join( '|', @${ "${class}::DEBUG_TARGET" } ) : ''; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1645
|
|
|
|
|
|
|
} |
1646
|
218
|
50
|
33
|
|
|
601
|
if( $this->{debug} >= $message_level || |
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
33
|
|
|
|
|
1647
|
|
|
|
|
|
|
$this->{verbose} >= $message_level || |
1648
|
218
|
|
|
|
|
1219
|
${ $class . '::DEBUG' } >= $message_level || |
1649
|
|
|
|
|
|
|
$this->{debug_level} >= $message_level || |
1650
|
|
|
|
|
|
|
$this->{debug} >= 100 || |
1651
|
0
|
|
|
|
|
0
|
( length( $target_re ) && $class =~ /^$target_re$/ && ${ $class . '::GLOBAL_DEBUG' } >= $message_level ) ) |
1652
|
|
|
|
|
|
|
{ |
1653
|
|
|
|
|
|
|
## print( STDERR ref( $self ) . "::message_check(): debug is '$hash->{debug}', verbose '$hash->{verbose}', DEBUG '", ${ $class . '::DEBUG' }, "', debug_level = $hash->{debug_level}\n" ); |
1654
|
0
|
|
|
|
|
0
|
return( [ @_ ] ); |
1655
|
|
|
|
|
|
|
} |
1656
|
|
|
|
|
|
|
else |
1657
|
|
|
|
|
|
|
{ |
1658
|
218
|
|
|
|
|
379
|
return( 0 ); |
1659
|
|
|
|
|
|
|
} |
1660
|
|
|
|
|
|
|
} |
1661
|
|
|
|
|
|
|
} |
1662
|
0
|
|
|
|
|
0
|
return( 0 ); |
1663
|
|
|
|
|
|
|
} |
1664
|
|
|
|
|
|
|
|
1665
|
|
|
|
|
|
|
sub message_frame |
1666
|
|
|
|
|
|
|
{ |
1667
|
0
|
|
|
0
|
0
|
0
|
my $self = shift( @_ ); |
1668
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1669
|
0
|
0
|
|
|
|
0
|
$this->{_message_frame } = {} if( !exists( $this->{_message_frame} ) ); |
1670
|
0
|
|
|
|
|
0
|
my $mf = $this->{_message_frame}; |
1671
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
1672
|
|
|
|
|
|
|
{ |
1673
|
0
|
|
|
|
|
0
|
my $args = {}; |
1674
|
0
|
0
|
|
|
|
0
|
if( ref( $_[0] ) eq 'HASH' ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1675
|
|
|
|
|
|
|
{ |
1676
|
0
|
|
|
|
|
0
|
$args = shift( @_ ); |
1677
|
0
|
|
|
|
|
0
|
my @k = keys( %$args ); |
1678
|
0
|
|
|
|
|
0
|
@$mf{ @k } = @$args{ @k }; |
1679
|
|
|
|
|
|
|
} |
1680
|
|
|
|
|
|
|
elsif( !( @_ % 2 ) ) |
1681
|
|
|
|
|
|
|
{ |
1682
|
0
|
|
|
|
|
0
|
$args = { @_ }; |
1683
|
0
|
|
|
|
|
0
|
my @k = keys( %$args ); |
1684
|
0
|
|
|
|
|
0
|
@$mf{ @k } = @$args{ @k }; |
1685
|
|
|
|
|
|
|
} |
1686
|
|
|
|
|
|
|
elsif( scalar( @_ ) == 1 ) |
1687
|
|
|
|
|
|
|
{ |
1688
|
0
|
|
|
|
|
0
|
my $sub = shift( @_ ); |
1689
|
0
|
0
|
|
|
|
0
|
$sub = substr( $sub, rindex( $sub, '::' ) + 2 ) if( index( $sub, '::' ) != -1 ); |
1690
|
0
|
|
|
|
|
0
|
return( $mf->{ $sub } ); |
1691
|
|
|
|
|
|
|
} |
1692
|
|
|
|
|
|
|
else |
1693
|
|
|
|
|
|
|
{ |
1694
|
0
|
|
|
|
|
0
|
return( $self->error( "I was expecting a key => value pair such as routine => stack frame (integer)" ) ); |
1695
|
|
|
|
|
|
|
} |
1696
|
|
|
|
|
|
|
} |
1697
|
0
|
|
|
|
|
0
|
return( $mf ); |
1698
|
|
|
|
|
|
|
} |
1699
|
|
|
|
|
|
|
|
1700
|
|
|
|
|
|
|
sub message_log |
1701
|
|
|
|
|
|
|
{ |
1702
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1703
|
0
|
|
|
|
|
0
|
my $io = $self->message_log_io; |
1704
|
|
|
|
|
|
|
#print( STDERR "Module::Generic::log: \$io now is '$io'\n" ); |
1705
|
0
|
0
|
|
|
|
0
|
return( undef() ) if( !$io ); |
1706
|
|
|
|
|
|
|
#print( STDERR "Module::Generic::log: \$io is not an open handle\n" ) if( !openhandle( $io ) && $io ); |
1707
|
0
|
0
|
0
|
|
|
0
|
return( undef() ) if( !Scalar::Util::openhandle( $io ) && $io ); |
1708
|
|
|
|
|
|
|
## 2019-06-14: I decided to remove this test, because if a log is provided it should print to it |
1709
|
|
|
|
|
|
|
## If we are on the command line, we can easily just do tail -f log_file.txt for example and get the same result as |
1710
|
|
|
|
|
|
|
## if it were printed directly on the console |
1711
|
|
|
|
|
|
|
# my $rc = CORE::print( $io @_ ) || return( $self->error( "Unable to print to log file: $!" ) ); |
1712
|
0
|
|
0
|
|
|
0
|
my $rc = $io->print( scalar( localtime( time() ) ), " [$$]: ", @_ ) || return( $self->error( "Unable to print to log file: $!" ) ); |
1713
|
|
|
|
|
|
|
## print( STDERR "Module::Generic::log (", ref( $self ), "): successfully printed to debug log file. \$rc is $rc, \$io is '$io' and message is: ", join( '', @_ ), "\n" ); |
1714
|
0
|
|
|
|
|
0
|
return( $rc ); |
1715
|
|
|
|
|
|
|
} |
1716
|
|
|
|
|
|
|
|
1717
|
|
|
|
|
|
|
sub message_log_io |
1718
|
|
|
|
|
|
|
{ |
1719
|
|
|
|
|
|
|
#return( shift->_set_get( 'log_io', @_ ) ); |
1720
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1721
|
0
|
|
|
|
|
0
|
my $class = ref( $self ); |
1722
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1723
|
0
|
0
|
0
|
|
|
0
|
if( @_ ) |
|
|
0
|
0
|
|
|
|
|
1724
|
|
|
|
|
|
|
{ |
1725
|
0
|
|
|
|
|
0
|
my $io = shift( @_ ); |
1726
|
0
|
|
|
|
|
0
|
$self->_set_get( 'log_io', $io ); |
1727
|
|
|
|
|
|
|
} |
1728
|
0
|
|
|
|
|
0
|
elsif( ${ "${class}::LOG_DEBUG" } && |
1729
|
|
|
|
|
|
|
!$self->_set_get( 'log_io' ) && |
1730
|
0
|
|
|
|
|
0
|
${ "${class}::DEB_LOG" } ) |
1731
|
|
|
|
|
|
|
{ |
1732
|
0
|
|
|
|
|
0
|
our $DEB_LOG = ${ "${class}::DEB_LOG" }; |
|
0
|
|
|
|
|
0
|
|
1733
|
0
|
0
|
|
|
|
0
|
unless( $DEBUG_LOG_IO ) |
1734
|
|
|
|
|
|
|
{ |
1735
|
0
|
|
0
|
|
|
0
|
$DEBUG_LOG_IO = IO::File->new( ">>$DEB_LOG" ) || die( "Unable to open debug log file $DEB_LOG in append mode: $!\n" ); |
1736
|
0
|
|
|
|
|
0
|
$DEBUG_LOG_IO->binmode( ':utf8' ); |
1737
|
0
|
|
|
|
|
0
|
$DEBUG_LOG_IO->autoflush( 1 ); |
1738
|
|
|
|
|
|
|
} |
1739
|
0
|
|
|
|
|
0
|
$self->_set_get( 'log_io', $DEBUG_LOG_IO ); |
1740
|
|
|
|
|
|
|
} |
1741
|
0
|
|
|
|
|
0
|
return( $self->_set_get( 'log_io' ) ); |
1742
|
|
|
|
|
|
|
} |
1743
|
|
|
|
|
|
|
|
1744
|
|
|
|
|
|
|
sub message_switch |
1745
|
|
|
|
|
|
|
{ |
1746
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1747
|
0
|
|
0
|
|
|
0
|
my $pkg = ref( $self ) || $self; |
1748
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1749
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
1750
|
|
|
|
|
|
|
{ |
1751
|
0
|
|
|
|
|
0
|
my $flag = shift( @_ ); |
1752
|
0
|
0
|
0
|
|
|
0
|
if( $flag ) |
|
|
0
|
|
|
|
|
|
1753
|
|
|
|
|
|
|
{ |
1754
|
0
|
0
|
|
|
|
0
|
if( defined( &{ "$pkg\::message_off" } ) ) |
|
0
|
|
|
|
|
0
|
|
1755
|
|
|
|
|
|
|
{ |
1756
|
|
|
|
|
|
|
## Restore previous backup |
1757
|
0
|
|
|
|
|
0
|
*{ "${pkg}::message" } = \&{ "${pkg}::message_off" }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1758
|
|
|
|
|
|
|
} |
1759
|
|
|
|
|
|
|
else |
1760
|
|
|
|
|
|
|
{ |
1761
|
0
|
|
|
|
|
0
|
*{ "${pkg}::message" } = \&{ "Module::Generic::message" }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1762
|
|
|
|
|
|
|
} |
1763
|
|
|
|
|
|
|
} |
1764
|
|
|
|
|
|
|
## We switch it down if nobody is going to use it |
1765
|
|
|
|
|
|
|
elsif( !$flag && !$this->{verbose} && !$this->{debug} ) |
1766
|
|
|
|
|
|
|
{ |
1767
|
0
|
0
|
|
|
|
0
|
*{ "${pkg}::message_off" } = \&{ "${pkg}::message" } unless( defined( &{ "${pkg}::message_off" } ) ); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1768
|
0
|
|
|
0
|
|
0
|
*{ "${pkg}::message" } = sub { 1 }; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1769
|
|
|
|
|
|
|
} |
1770
|
|
|
|
|
|
|
} |
1771
|
0
|
|
|
|
|
0
|
return( 1 ); |
1772
|
|
|
|
|
|
|
} |
1773
|
|
|
|
|
|
|
|
1774
|
|
|
|
|
|
|
sub new_array |
1775
|
|
|
|
|
|
|
{ |
1776
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1777
|
0
|
|
|
|
|
0
|
return( Module::Generic::Array->new( @_ ) ); |
1778
|
|
|
|
|
|
|
} |
1779
|
|
|
|
|
|
|
|
1780
|
|
|
|
|
|
|
sub new_hash |
1781
|
|
|
|
|
|
|
{ |
1782
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1783
|
0
|
|
|
|
|
0
|
return( Module::Generic::Hash->new( @_ ) ); |
1784
|
|
|
|
|
|
|
} |
1785
|
|
|
|
|
|
|
|
1786
|
|
|
|
|
|
|
sub new_number |
1787
|
|
|
|
|
|
|
{ |
1788
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1789
|
0
|
|
|
|
|
0
|
return( Module::Generic::Number->new( @_ ) ); |
1790
|
|
|
|
|
|
|
} |
1791
|
|
|
|
|
|
|
|
1792
|
|
|
|
|
|
|
sub new_scalar |
1793
|
|
|
|
|
|
|
{ |
1794
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1795
|
0
|
|
|
|
|
0
|
return( Module::Generic::Scalar->new( @_ ) ); |
1796
|
|
|
|
|
|
|
} |
1797
|
|
|
|
|
|
|
|
1798
|
0
|
|
|
0
|
1
|
0
|
sub noexec { $_[0]->{_msg_no_exec_sub} = 1; return( $_[0] ); } |
|
0
|
|
|
|
|
0
|
|
1799
|
|
|
|
|
|
|
|
1800
|
|
|
|
|
|
|
## Purpose is to get an error object thrown from another package, and make it ours and pass it along |
1801
|
|
|
|
|
|
|
sub pass_error |
1802
|
|
|
|
|
|
|
{ |
1803
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1804
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1805
|
0
|
|
|
|
|
0
|
my $err = shift( @_ ); |
1806
|
0
|
0
|
0
|
|
|
0
|
return if( !ref( $err ) || !Scalar::Util::blessed( $err ) ); |
1807
|
0
|
|
|
|
|
0
|
$this->{error} = ${ $class . '::ERROR' } = $err; |
|
0
|
|
|
|
|
0
|
|
1808
|
0
|
0
|
|
|
|
0
|
if( want( 'OBJECT' ) ) |
1809
|
|
|
|
|
|
|
{ |
1810
|
0
|
|
|
|
|
0
|
my $null = Module::Generic::Null->new( $err, { debug => $this->{debug}, has_error => 1 }); |
1811
|
0
|
|
|
|
|
0
|
rreturn( $null ); |
1812
|
|
|
|
|
|
|
} |
1813
|
0
|
|
|
|
|
0
|
return; |
1814
|
|
|
|
|
|
|
} |
1815
|
|
|
|
|
|
|
|
1816
|
0
|
|
|
0
|
1
|
0
|
sub quiet { return( shift->_set_get( 'quiet', @_ ) ); } |
1817
|
|
|
|
|
|
|
|
1818
|
|
|
|
|
|
|
sub save |
1819
|
|
|
|
|
|
|
{ |
1820
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1821
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1822
|
0
|
|
|
|
|
0
|
my $opts = {}; |
1823
|
0
|
0
|
|
|
|
0
|
$opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' ); |
1824
|
0
|
|
|
|
|
0
|
my( $file, $data ); |
1825
|
0
|
0
|
|
|
|
0
|
if( @_ == 2 ) |
1826
|
|
|
|
|
|
|
{ |
1827
|
0
|
|
|
|
|
0
|
$opts->{data} = shift( @_ ); |
1828
|
0
|
|
|
|
|
0
|
$opts->{file} = shift( @_ ); |
1829
|
|
|
|
|
|
|
} |
1830
|
0
|
0
|
|
|
|
0
|
return( $self->error( "No file was provided to save data to." ) ) if( !$opts->{file} ); |
1831
|
0
|
|
0
|
|
|
0
|
my $fh = IO::File->new( ">$opts->{file}" ) || return( $self->error( "Unable to open file \"$opts->{file}\" in write mode: $!" ) ); |
1832
|
0
|
0
|
|
|
|
0
|
$fh->binmode( ':' . $opts->{encoding} ) if( $opts->{encoding} ); |
1833
|
0
|
|
|
|
|
0
|
$fh->autoflush( 1 ); |
1834
|
0
|
0
|
|
|
|
0
|
if( !defined( $fh->print( ref( $opts->{data} ) eq 'SCALAR' ? ${$opts->{data}} : $opts->{data} ) ) ) |
|
0
|
0
|
|
|
|
0
|
|
1835
|
|
|
|
|
|
|
{ |
1836
|
0
|
|
|
|
|
0
|
return( $self->error( "Unable to write data to file \"$opts->{file}\": $!" ) ) |
1837
|
|
|
|
|
|
|
} |
1838
|
0
|
|
|
|
|
0
|
$fh->close; |
1839
|
0
|
|
|
|
|
0
|
my $bytes = -s( $opts->{file} ); |
1840
|
0
|
|
|
|
|
0
|
return( $bytes ); |
1841
|
|
|
|
|
|
|
} |
1842
|
|
|
|
|
|
|
|
1843
|
|
|
|
|
|
|
sub set |
1844
|
|
|
|
|
|
|
{ |
1845
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1846
|
0
|
|
|
|
|
0
|
my %arg = (); |
1847
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
1848
|
|
|
|
|
|
|
{ |
1849
|
0
|
|
|
|
|
0
|
%arg = ( @_ ); |
1850
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1851
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
1852
|
0
|
|
|
|
|
0
|
my @keys = keys( %arg ); |
1853
|
0
|
|
|
|
|
0
|
@$data{ @keys } = @arg{ @keys }; |
1854
|
|
|
|
|
|
|
} |
1855
|
0
|
|
|
|
|
0
|
return( scalar( keys( %arg ) ) ); |
1856
|
|
|
|
|
|
|
} |
1857
|
|
|
|
|
|
|
|
1858
|
|
|
|
|
|
|
sub subclasses |
1859
|
|
|
|
|
|
|
{ |
1860
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1861
|
0
|
|
|
|
|
0
|
my $that = ''; |
1862
|
0
|
0
|
|
|
|
0
|
$that = @_ ? shift( @_ ) : $self; |
1863
|
0
|
|
0
|
|
|
0
|
my $base = ref( $that ) || $that; |
1864
|
0
|
|
|
|
|
0
|
$base =~ s,::,/,g; |
1865
|
0
|
|
|
|
|
0
|
$base .= '.pm'; |
1866
|
|
|
|
|
|
|
|
1867
|
0
|
|
|
|
|
0
|
require IO::Dir; |
1868
|
|
|
|
|
|
|
## remove '.pm' |
1869
|
0
|
|
|
|
|
0
|
my $dir = substr( $INC{ $base }, 0, ( length( $INC{ $base } ) ) - 3 ); |
1870
|
|
|
|
|
|
|
|
1871
|
0
|
|
|
|
|
0
|
my @packages = (); |
1872
|
0
|
|
|
|
|
0
|
my $io = IO::Dir->open( $dir ); |
1873
|
0
|
0
|
|
|
|
0
|
if( defined( $io ) ) |
1874
|
|
|
|
|
|
|
{ |
1875
|
0
|
0
|
|
|
|
0
|
@packages = map{ substr( $_, 0, length( $_ ) - 3 ) } grep{ substr( $_, -3 ) eq '.pm' && -f( "$dir/$_" ) } $io->read(); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1876
|
0
|
0
|
|
|
|
0
|
$io->close || |
1877
|
|
|
|
|
|
|
warn( "Unable to close directory \"$dir\": $!\n" ); |
1878
|
|
|
|
|
|
|
} |
1879
|
|
|
|
|
|
|
else |
1880
|
|
|
|
|
|
|
{ |
1881
|
0
|
|
|
|
|
0
|
warn( "Unable to open directory \"$dir\": $!\n" ); |
1882
|
|
|
|
|
|
|
} |
1883
|
0
|
0
|
|
|
|
0
|
return( wantarray() ? @packages : \@packages ); |
1884
|
|
|
|
|
|
|
} |
1885
|
|
|
|
|
|
|
|
1886
|
97
|
|
|
97
|
1
|
209
|
sub true { ${"Module::Generic::Boolean::true"} } |
|
97
|
|
|
|
|
1967
|
|
1887
|
|
|
|
|
|
|
|
1888
|
4
|
|
|
4
|
1
|
17
|
sub false { ${"Module::Generic::Boolean::false"} } |
|
4
|
|
|
|
|
64
|
|
1889
|
|
|
|
|
|
|
|
1890
|
|
|
|
|
|
|
sub verbose |
1891
|
|
|
|
|
|
|
{ |
1892
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
1893
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1894
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
1895
|
|
|
|
|
|
|
{ |
1896
|
0
|
|
|
|
|
0
|
my $flag = shift( @_ ); |
1897
|
0
|
|
|
|
|
0
|
$this->{verbose} = $flag; |
1898
|
0
|
0
|
|
|
|
0
|
$self->message_switch( $flag ) if( $OPTIMIZE_MESG_SUB ); |
1899
|
|
|
|
|
|
|
} |
1900
|
0
|
|
|
|
|
0
|
return( $this->{verbose} ); |
1901
|
|
|
|
|
|
|
} |
1902
|
|
|
|
|
|
|
|
1903
|
|
|
|
|
|
|
sub will |
1904
|
|
|
|
|
|
|
{ |
1905
|
0
|
0
|
0
|
0
|
1
|
0
|
( @_ >= 2 && @_ <= 3 ) || die( 'Usage: $obj->can( "method" ) or Module::Generic::will( $obj, "method" )' ); |
1906
|
0
|
|
|
|
|
0
|
my( $obj, $meth, $level ); |
1907
|
|
|
|
|
|
|
## $obj->will( $other_obj, 'method' ); |
1908
|
0
|
0
|
0
|
|
|
0
|
if( @_ == 3 && ref( $_[ 1 ] ) ) |
1909
|
|
|
|
|
|
|
{ |
1910
|
0
|
|
|
|
|
0
|
$obj = $_[ 1 ]; |
1911
|
0
|
|
|
|
|
0
|
$meth = $_[ 2 ]; |
1912
|
|
|
|
|
|
|
} |
1913
|
|
|
|
|
|
|
else |
1914
|
|
|
|
|
|
|
{ |
1915
|
0
|
|
|
|
|
0
|
( $obj, $meth, $level ) = @_; |
1916
|
|
|
|
|
|
|
} |
1917
|
0
|
0
|
0
|
|
|
0
|
return( undef() ) if( !ref( $obj ) && index( $obj, '::' ) == -1 ); |
1918
|
|
|
|
|
|
|
## Give a chance to UNIVERSAL::can |
1919
|
0
|
|
|
|
|
0
|
my $ref = undef; |
1920
|
0
|
0
|
0
|
|
|
0
|
if( Scalar::Util::blessed( $obj ) && ( $ref = $obj->can( $meth ) ) ) |
1921
|
|
|
|
|
|
|
{ |
1922
|
0
|
|
|
|
|
0
|
return( $ref ); |
1923
|
|
|
|
|
|
|
} |
1924
|
0
|
|
0
|
|
|
0
|
my $class = ref( $obj ) || $obj; |
1925
|
0
|
|
|
|
|
0
|
my $origi = $class; |
1926
|
0
|
0
|
|
|
|
0
|
if( index( $meth, '::' ) != -1 ) |
1927
|
|
|
|
|
|
|
{ |
1928
|
0
|
|
|
|
|
0
|
$origi = substr( $meth, 0, rindex( $meth, '::' ) ); |
1929
|
0
|
|
|
|
|
0
|
$meth = substr( $meth, rindex( $meth, '::' ) + 2 ); |
1930
|
|
|
|
|
|
|
} |
1931
|
0
|
0
|
|
|
|
0
|
$ref = \&{ "$class\::$meth" } if( defined( &{ "$class\::$meth" } ) ); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1932
|
|
|
|
|
|
|
## print( $err "\t" x $level, "UNIVERSAL::can ", defined( $ref ) ? "succeeded" : "failed", " in finding the method \"$meth\" in object/class $obj.\n" ); |
1933
|
|
|
|
|
|
|
## print( $err "\t" x $level, defined( $ref ) ? "succeeded" : "failed", " in finding the method \"$meth\" in object/class $obj.\n" ); |
1934
|
0
|
0
|
|
|
|
0
|
return( $ref ) if( defined( $ref ) ); |
1935
|
|
|
|
|
|
|
## We do not go further down the rabbit hole if level is greater or equal to 10 |
1936
|
0
|
|
0
|
|
|
0
|
$level ||= 0; |
1937
|
0
|
0
|
|
|
|
0
|
return( undef() ) if( $level >= 10 ); |
1938
|
0
|
|
|
|
|
0
|
$level++; |
1939
|
|
|
|
|
|
|
## Let's see what Alice has got for us... :-) |
1940
|
|
|
|
|
|
|
## We look in the @ISA to see if the method exists in the package from which we |
1941
|
|
|
|
|
|
|
## possibly inherited |
1942
|
0
|
0
|
|
|
|
0
|
if( @{ "$class\::ISA" } ) |
|
0
|
|
|
|
|
0
|
|
1943
|
|
|
|
|
|
|
{ |
1944
|
|
|
|
|
|
|
## print( STDERR "\t" x $level, "Checking ", scalar( @{ "$class\::ISA" } ), " entries in \"\@${class}\:\:ISA\".\n" ); |
1945
|
0
|
|
|
|
|
0
|
foreach my $pack ( @{ "$class\::ISA" } ) |
|
0
|
|
|
|
|
0
|
|
1946
|
|
|
|
|
|
|
{ |
1947
|
|
|
|
|
|
|
## print( STDERR "\t" x $level, "Looking up method \"$meth\" in inherited package \"$pack\".\n" ); |
1948
|
0
|
|
|
|
|
0
|
my $ref = &will( $pack, "$origi\::$meth", $level ); |
1949
|
0
|
0
|
|
|
|
0
|
return( $ref ) if( defined( $ref ) ); |
1950
|
|
|
|
|
|
|
} |
1951
|
|
|
|
|
|
|
} |
1952
|
|
|
|
|
|
|
## Then, maybe there is an AUTOLOAD to trap undefined routine? |
1953
|
|
|
|
|
|
|
## But, we do not want any loop, do we? |
1954
|
|
|
|
|
|
|
## Since will() is called from Module::Generic::AUTOLOAD to check if EXTRA_AUTOLOAD exists |
1955
|
|
|
|
|
|
|
## we are not going to call Module::Generic::AUTOLOAD for EXTRA_AUTOLOAD... |
1956
|
0
|
0
|
0
|
|
|
0
|
if( $class ne 'Module::Generic' && $meth ne 'EXTRA_AUTOLOAD' && defined( &{ "$class\::AUTOLOAD" } ) ) |
|
0
|
|
0
|
|
|
0
|
|
1957
|
|
|
|
|
|
|
{ |
1958
|
|
|
|
|
|
|
## print( STDERR "\t" x ( $level - 1 ), "Found an AUTOLOAD in class \"$class\". Ok.\n" ); |
1959
|
|
|
|
|
|
|
my $sub = sub |
1960
|
|
|
|
|
|
|
{ |
1961
|
0
|
|
|
0
|
|
0
|
$class::AUTOLOAD = "$origi\::$meth"; |
1962
|
0
|
|
|
|
|
0
|
&{ "$class::AUTOLOAD" }( @_ ); |
|
0
|
|
|
|
|
0
|
|
1963
|
0
|
|
|
|
|
0
|
}; |
1964
|
0
|
|
|
|
|
0
|
return( $sub ); |
1965
|
|
|
|
|
|
|
} |
1966
|
0
|
|
|
|
|
0
|
return( undef() ); |
1967
|
|
|
|
|
|
|
} |
1968
|
|
|
|
|
|
|
|
1969
|
|
|
|
|
|
|
## Initially those data were stored after the __END__, but it seems some module is interfering with <DATA> |
1970
|
|
|
|
|
|
|
## and so those data could not be loaded reliably |
1971
|
|
|
|
|
|
|
## This is called once by colour_to_rgb to generate the hash reference COLOUR_NAME_TO_RGB |
1972
|
|
|
|
|
|
|
sub __colour_data |
1973
|
|
|
|
|
|
|
{ |
1974
|
1
|
|
|
1
|
|
4
|
my $colour_data = <<EOT; |
1975
|
|
|
|
|
|
|
{'alice blue' => ['240','248','255'],'aliceblue' => ['240','248','255'],'antique white' => ['250','235','215'],'antiquewhite' => ['250','235','215'],'antiquewhite1' => ['255','239','219'],'antiquewhite2' => ['238','223','204'],'antiquewhite3' => ['205','192','176'],'antiquewhite4' => ['139','131','120'],'aquamarine' => ['127','255','212'],'aquamarine1' => ['127','255','212'],'aquamarine2' => ['118','238','198'],'aquamarine3' => ['102','205','170'],'aquamarine4' => ['69','139','116'],'azure' => ['240','255','255'],'azure1' => ['240','255','255'],'azure2' => ['224','238','238'],'azure3' => ['193','205','205'],'azure4' => ['131','139','139'],'beige' => ['245','245','220'],'bisque' => ['255','228','196'],'bisque1' => ['255','228','196'],'bisque2' => ['238','213','183'],'bisque3' => ['205','183','158'],'bisque4' => ['139','125','107'],'black' => ['0','0','0'],'blanched almond' => ['255','235','205'],'blanchedalmond' => ['255','235','205'],'blue' => ['0','0','255'],'blue violet' => ['138','43','226'],'blue1' => ['0','0','255'],'blue2' => ['0','0','238'],'blue3' => ['0','0','205'],'blue4' => ['0','0','139'],'blueviolet' => ['138','43','226'],'brown' => ['165','42','42'],'brown1' => ['255','64','64'],'brown2' => ['238','59','59'],'brown3' => ['205','51','51'],'brown4' => ['139','35','35'],'burlywood' => ['222','184','135'],'burlywood1' => ['255','211','155'],'burlywood2' => ['238','197','145'],'burlywood3' => ['205','170','125'],'burlywood4' => ['139','115','85'],'cadet blue' => ['95','158','160'],'cadetblue' => ['95','158','160'],'cadetblue1' => ['152','245','255'],'cadetblue2' => ['142','229','238'],'cadetblue3' => ['122','197','205'],'cadetblue4' => ['83','134','139'],'chartreuse' => ['127','255','0'],'chartreuse1' => ['127','255','0'],'chartreuse2' => ['118','238','0'],'chartreuse3' => ['102','205','0'],'chartreuse4' => ['69','139','0'],'chocolate' => ['210','105','30'],'chocolate1' => ['255','127','36'],'chocolate2' => ['238','118','33'],'chocolate3' => ['205','102','29'],'chocolate4' => ['139','69','19'],'coral' => ['255','127','80'],'coral1' => ['255','114','86'],'coral2' => ['238','106','80'],'coral3' => ['205','91','69'],'coral4' => ['139','62','47'],'cornflower blue' => ['100','149','237'],'cornflowerblue' => ['100','149','237'],'cornsilk' => ['255','248','220'],'cornsilk1' => ['255','248','220'],'cornsilk2' => ['238','232','205'],'cornsilk3' => ['205','200','177'],'cornsilk4' => ['139','136','120'],'cyan' => ['0','255','255'],'cyan1' => ['0','255','255'],'cyan2' => ['0','238','238'],'cyan3' => ['0','205','205'],'cyan4' => ['0','139','139'],'dark blue' => ['0','0','139'],'dark cyan' => ['0','139','139'],'dark goldenrod' => ['184','134','11'],'dark gray' => ['169','169','169'],'dark green' => ['0','100','0'],'dark grey' => ['169','169','169'],'dark khaki' => ['189','183','107'],'dark magenta' => ['139','0','139'],'dark olive green' => ['85','107','47'],'dark orange' => ['255','140','0'],'dark orchid' => ['153','50','204'],'dark red' => ['139','0','0'],'dark salmon' => ['233','150','122'],'dark sea green' => ['143','188','143'],'dark slate blue' => ['72','61','139'],'dark slate gray' => ['47','79','79'],'dark slate grey' => ['47','79','79'],'dark turquoise' => ['0','206','209'],'dark violet' => ['148','0','211'],'darkblue' => ['0','0','139'],'darkcyan' => ['0','139','139'],'darkgoldenrod' => ['184','134','11'],'darkgoldenrod1' => ['255','185','15'],'darkgoldenrod2' => ['238','173','14'],'darkgoldenrod3' => ['205','149','12'],'darkgoldenrod4' => ['139','101','8'],'darkgray' => ['169','169','169'],'darkgreen' => ['0','100','0'],'darkgrey' => ['169','169','169'],'darkkhaki' => ['189','183','107'],'darkmagenta' => ['139','0','139'],'darkolivegreen' => ['85','107','47'],'darkolivegreen1' => ['202','255','112'],'darkolivegreen2' => ['188','238','104'],'darkolivegreen3' => ['162','205','90'],'darkolivegreen4' => ['110','139','61'],'darkorange' => ['255','140','0'],'darkorange1' => ['255','127','0'],'darkorange2' => ['238','118','0'],'darkorange3' => ['205','102','0'],'darkorange4' => ['139','69','0'],'darkorchid' => ['153','50','204'],'darkorchid1' => ['191','62','255'],'darkorchid2' => ['178','58','238'],'darkorchid3' => ['154','50','205'],'darkorchid4' => ['104','34','139'],'darkred' => ['139','0','0'],'darksalmon' => ['233','150','122'],'darkseagreen' => ['143','188','143'],'darkseagreen1' => ['193','255','193'],'darkseagreen2' => ['180','238','180'],'darkseagreen3' => ['155','205','155'],'darkseagreen4' => ['105','139','105'],'darkslateblue' => ['72','61','139'],'darkslategray' => ['47','79','79'],'darkslategray1' => ['151','255','255'],'darkslategray2' => ['141','238','238'],'darkslategray3' => ['121','205','205'],'darkslategray4' => ['82','139','139'],'darkslategrey' => ['47','79','79'],'darkturquoise' => ['0','206','209'],'darkviolet' => ['148','0','211'],'deep pink' => ['255','20','147'],'deep sky blue' => ['0','191','255'],'deeppink' => ['255','20','147'],'deeppink1' => ['255','20','147'],'deeppink2' => ['238','18','137'],'deeppink3' => ['205','16','118'],'deeppink4' => ['139','10','80'],'deepskyblue' => ['0','191','255'],'deepskyblue1' => ['0','191','255'],'deepskyblue2' => ['0','178','238'],'deepskyblue3' => ['0','154','205'],'deepskyblue4' => ['0','104','139'],'dim gray' => ['105','105','105'],'dim grey' => ['105','105','105'],'dimgray' => ['105','105','105'],'dimgrey' => ['105','105','105'],'dodger blue' => ['30','144','255'],'dodgerblue' => ['30','144','255'],'dodgerblue1' => ['30','144','255'],'dodgerblue2' => ['28','134','238'],'dodgerblue3' => ['24','116','205'],'dodgerblue4' => ['16','78','139'],'firebrick' => ['178','34','34'],'firebrick1' => ['255','48','48'],'firebrick2' => ['238','44','44'],'firebrick3' => ['205','38','38'],'firebrick4' => ['139','26','26'],'floral white' => ['255','250','240'],'floralwhite' => ['255','250','240'],'forest green' => ['34','139','34'],'forestgreen' => ['34','139','34'],'gainsboro' => ['220','220','220'],'ghost white' => ['248','248','255'],'ghostwhite' => ['248','248','255'],'gold' => ['255','215','0'],'gold1' => ['255','215','0'],'gold2' => ['238','201','0'],'gold3' => ['205','173','0'],'gold4' => ['139','117','0'],'goldenrod' => ['218','165','32'],'goldenrod1' => ['255','193','37'],'goldenrod2' => ['238','180','34'],'goldenrod3' => ['205','155','29'],'goldenrod4' => ['139','105','20'],'gray' => ['190','190','190'],'gray0' => ['0','0','0'],'gray1' => ['3','3','3'],'gray10' => ['26','26','26'],'gray100' => ['255','255','255'],'gray11' => ['28','28','28'],'gray12' => ['31','31','31'],'gray13' => ['33','33','33'],'gray14' => ['36','36','36'],'gray15' => ['38','38','38'],'gray16' => ['41','41','41'],'gray17' => ['43','43','43'],'gray18' => ['46','46','46'],'gray19' => ['48','48','48'],'gray2' => ['5','5','5'],'gray20' => ['51','51','51'],'gray21' => ['54','54','54'],'gray22' => ['56','56','56'],'gray23' => ['59','59','59'],'gray24' => ['61','61','61'],'gray25' => ['64','64','64'],'gray26' => ['66','66','66'],'gray27' => ['69','69','69'],'gray28' => ['71','71','71'],'gray29' => ['74','74','74'],'gray3' => ['8','8','8'],'gray30' => ['77','77','77'],'gray31' => ['79','79','79'],'gray32' => ['82','82','82'],'gray33' => ['84','84','84'],'gray34' => ['87','87','87'],'gray35' => ['89','89','89'],'gray36' => ['92','92','92'],'gray37' => ['94','94','94'],'gray38' => ['97','97','97'],'gray39' => ['99','99','99'],'gray4' => ['10','10','10'],'gray40' => ['102','102','102'],'gray41' => ['105','105','105'],'gray42' => ['107','107','107'],'gray43' => ['110','110','110'],'gray44' => ['112','112','112'],'gray45' => ['115','115','115'],'gray46' => ['117','117','117'],'gray47' => ['120','120','120'],'gray48' => ['122','122','122'],'gray49' => ['125','125','125'],'gray5' => ['13','13','13'],'gray50' => ['127','127','127'],'gray51' => ['130','130','130'],'gray52' => ['133','133','133'],'gray53' => ['135','135','135'],'gray54' => ['138','138','138'],'gray55' => ['140','140','140'],'gray56' => ['143','143','143'],'gray57' => ['145','145','145'],'gray58' => ['148','148','148'],'gray59' => ['150','150','150'],'gray6' => ['15','15','15'],'gray60' => ['153','153','153'],'gray61' => ['156','156','156'],'gray62' => ['158','158','158'],'gray63' => ['161','161','161'],'gray64' => ['163','163','163'],'gray65' => ['166','166','166'],'gray66' => ['168','168','168'],'gray67' => ['171','171','171'],'gray68' => ['173','173','173'],'gray69' => ['176','176','176'],'gray7' => ['18','18','18'],'gray70' => ['179','179','179'],'gray71' => ['181','181','181'],'gray72' => ['184','184','184'],'gray73' => ['186','186','186'],'gray74' => ['189','189','189'],'gray75' => ['191','191','191'],'gray76' => ['194','194','194'],'gray77' => ['196','196','196'],'gray78' => ['199','199','199'],'gray79' => ['201','201','201'],'gray8' => ['20','20','20'],'gray80' => ['204','204','204'],'gray81' => ['207','207','207'],'gray82' => ['209','209','209'],'gray83' => ['212','212','212'],'gray84' => ['214','214','214'],'gray85' => ['217','217','217'],'gray86' => ['219','219','219'],'gray87' => ['222','222','222'],'gray88' => ['224','224','224'],'gray89' => ['227','227','227'],'gray9' => ['23','23','23'],'gray90' => ['229','229','229'],'gray91' => ['232','232','232'],'gray92' => ['235','235','235'],'gray93' => ['237','237','237'],'gray94' => ['240','240','240'],'gray95' => ['242','242','242'],'gray96' => ['245','245','245'],'gray97' => ['247','247','247'],'gray98' => ['250','250','250'],'gray99' => ['252','252','252'],'green' => ['0','255','0'],'green yellow' => ['173','255','47'],'green1' => ['0','255','0'],'green2' => ['0','238','0'],'green3' => ['0','205','0'],'green4' => ['0','139','0'],'greenyellow' => ['173','255','47'],'grey' => ['190','190','190'],'grey0' => ['0','0','0'],'grey1' => ['3','3','3'],'grey10' => ['26','26','26'],'grey100' => ['255','255','255'],'grey11' => ['28','28','28'],'grey12' => ['31','31','31'],'grey13' => ['33','33','33'],'grey14' => ['36','36','36'],'grey15' => ['38','38','38'],'grey16' => ['41','41','41'],'grey17' => ['43','43','43'],'grey18' => ['46','46','46'],'grey19' => ['48','48','48'],'grey2' => ['5','5','5'],'grey20' => ['51','51','51'],'grey21' => ['54','54','54'],'grey22' => ['56','56','56'],'grey23' => ['59','59','59'],'grey24' => ['61','61','61'],'grey25' => ['64','64','64'],'grey26' => ['66','66','66'],'grey27' => ['69','69','69'],'grey28' => ['71','71','71'],'grey29' => ['74','74','74'],'grey3' => ['8','8','8'],'grey30' => ['77','77','77'],'grey31' => ['79','79','79'],'grey32' => ['82','82','82'],'grey33' => ['84','84','84'],'grey34' => ['87','87','87'],'grey35' => ['89','89','89'],'grey36' => ['92','92','92'],'grey37' => ['94','94','94'],'grey38' => ['97','97','97'],'grey39' => ['99','99','99'],'grey4' => ['10','10','10'],'grey40' => ['102','102','102'],'grey41' => ['105','105','105'],'grey42' => ['107','107','107'],'grey43' => ['110','110','110'],'grey44' => ['112','112','112'],'grey45' => ['115','115','115'],'grey46' => ['117','117','117'],'grey47' => ['120','120','120'],'grey48' => ['122','122','122'],'grey49' => ['125','125','125'],'grey5' => ['13','13','13'],'grey50' => ['127','127','127'],'grey51' => ['130','130','130'],'grey52' => ['133','133','133'],'grey53' => ['135','135','135'],'grey54' => ['138','138','138'],'grey55' => ['140','140','140'],'grey56' => ['143','143','143'],'grey57' => ['145','145','145'],'grey58' => ['148','148','148'],'grey59' => ['150','150','150'],'grey6' => ['15','15','15'],'grey60' => ['153','153','153'],'grey61' => ['156','156','156'],'grey62' => ['158','158','158'],'grey63' => ['161','161','161'],'grey64' => ['163','163','163'],'grey65' => ['166','166','166'],'grey66' => ['168','168','168'],'grey67' => ['171','171','171'],'grey68' => ['173','173','173'],'grey69' => ['176','176','176'],'grey7' => ['18','18','18'],'grey70' => ['179','179','179'],'grey71' => ['181','181','181'],'grey72' => ['184','184','184'],'grey73' => ['186','186','186'],'grey74' => ['189','189','189'],'grey75' => ['191','191','191'],'grey76' => ['194','194','194'],'grey77' => ['196','196','196'],'grey78' => ['199','199','199'],'grey79' => ['201','201','201'],'grey8' => ['20','20','20'],'grey80' => ['204','204','204'],'grey81' => ['207','207','207'],'grey82' => ['209','209','209'],'grey83' => ['212','212','212'],'grey84' => ['214','214','214'],'grey85' => ['217','217','217'],'grey86' => ['219','219','219'],'grey87' => ['222','222','222'],'grey88' => ['224','224','224'],'grey89' => ['227','227','227'],'grey9' => ['23','23','23'],'grey90' => ['229','229','229'],'grey91' => ['232','232','232'],'grey92' => ['235','235','235'],'grey93' => ['237','237','237'],'grey94' => ['240','240','240'],'grey95' => ['242','242','242'],'grey96' => ['245','245','245'],'grey97' => ['247','247','247'],'grey98' => ['250','250','250'],'grey99' => ['252','252','252'],'honeydew' => ['240','255','240'],'honeydew1' => ['240','255','240'],'honeydew2' => ['224','238','224'],'honeydew3' => ['193','205','193'],'honeydew4' => ['131','139','131'],'hot pink' => ['255','105','180'],'hotpink' => ['255','105','180'],'hotpink1' => ['255','110','180'],'hotpink2' => ['238','106','167'],'hotpink3' => ['205','96','144'],'hotpink4' => ['139','58','98'],'indian red' => ['205','92','92'],'indianred' => ['205','92','92'],'indianred1' => ['255','106','106'],'indianred2' => ['238','99','99'],'indianred3' => ['205','85','85'],'indianred4' => ['139','58','58'],'ivory' => ['255','255','240'],'ivory1' => ['255','255','240'],'ivory2' => ['238','238','224'],'ivory3' => ['205','205','193'],'ivory4' => ['139','139','131'],'khaki' => ['240','230','140'],'khaki1' => ['255','246','143'],'khaki2' => ['238','230','133'],'khaki3' => ['205','198','115'],'khaki4' => ['139','134','78'],'lavender' => ['230','230','250'],'lavender blush' => ['255','240','245'],'lavenderblush' => ['255','240','245'],'lavenderblush1' => ['255','240','245'],'lavenderblush2' => ['238','224','229'],'lavenderblush3' => ['205','193','197'],'lavenderblush4' => ['139','131','134'],'lawn green' => ['124','252','0'],'lawngreen' => ['124','252','0'],'lemon chiffon' => ['255','250','205'],'lemonchiffon' => ['255','250','205'],'lemonchiffon1' => ['255','250','205'],'lemonchiffon2' => ['238','233','191'],'lemonchiffon3' => ['205','201','165'],'lemonchiffon4' => ['139','137','112'],'light blue' => ['173','216','230'],'light coral' => ['240','128','128'],'light cyan' => ['224','255','255'],'light goldenrod' => ['238','221','130'],'light goldenrod yellow' => ['250','250','210'],'light gray' => ['211','211','211'],'light green' => ['144','238','144'],'light grey' => ['211','211','211'],'light pink' => ['255','182','193'],'light salmon' => ['255','160','122'],'light sea green' => ['32','178','170'],'light sky blue' => ['135','206','250'],'light slate blue' => ['132','112','255'],'light slate gray' => ['119','136','153'],'light slate grey' => ['119','136','153'],'light steel blue' => ['176','196','222'],'light yellow' => ['255','255','224'],'lightblue' => ['173','216','230'],'lightblue1' => ['191','239','255'],'lightblue2' => ['178','223','238'],'lightblue3' => ['154','192','205'],'lightblue4' => ['104','131','139'],'lightcoral' => ['240','128','128'],'lightcyan' => ['224','255','255'],'lightcyan1' => ['224','255','255'],'lightcyan2' => ['209','238','238'],'lightcyan3' => ['180','205','205'],'lightcyan4' => ['122','139','139'],'lightgoldenrod' => ['238','221','130'],'lightgoldenrod1' => ['255','236','139'],'lightgoldenrod2' => ['238','220','130'],'lightgoldenrod3' => ['205','190','112'],'lightgoldenrod4' => ['139','129','76'],'lightgoldenrodyellow' => ['250','250','210'],'lightgray' => ['211','211','211'],'lightgreen' => ['144','238','144'],'lightgrey' => ['211','211','211'],'lightpink' => ['255','182','193'],'lightpink1' => ['255','174','185'],'lightpink2' => ['238','162','173'],'lightpink3' => ['205','140','149'],'lightpink4' => ['139','95','101'],'lightsalmon' => ['255','160','122'],'lightsalmon1' => ['255','160','122'],'lightsalmon2' => ['238','149','114'],'lightsalmon3' => ['205','129','98'],'lightsalmon4' => ['139','87','66'],'lightseagreen' => ['32','178','170'],'lightskyblue' => ['135','206','250'],'lightskyblue1' => ['176','226','255'],'lightskyblue2' => ['164','211','238'],'lightskyblue3' => ['141','182','205'],'lightskyblue4' => ['96','123','139'],'lightslateblue' => ['132','112','255'],'lightslategray' => ['119','136','153'],'lightslategrey' => ['119','136','153'],'lightsteelblue' => ['176','196','222'],'lightsteelblue1' => ['202','225','255'],'lightsteelblue2' => ['188','210','238'],'lightsteelblue3' => ['162','181','205'],'lightsteelblue4' => ['110','123','139'],'lightyellow' => ['255','255','224'],'lightyellow1' => ['255','255','224'],'lightyellow2' => ['238','238','209'],'lightyellow3' => ['205','205','180'],'lightyellow4' => ['139','139','122'],'lime green' => ['50','205','50'],'limegreen' => ['50','205','50'],'linen' => ['250','240','230'],'magenta' => ['255','0','255'],'magenta1' => ['255','0','255'],'magenta2' => ['238','0','238'],'magenta3' => ['205','0','205'],'magenta4' => ['139','0','139'],'maroon' => ['176','48','96'],'maroon1' => ['255','52','179'],'maroon2' => ['238','48','167'],'maroon3' => ['205','41','144'],'maroon4' => ['139','28','98'],'medium aquamarine' => ['102','205','170'],'medium blue' => ['0','0','205'],'medium orchid' => ['186','85','211'],'medium purple' => ['147','112','219'],'medium sea green' => ['60','179','113'],'medium slate blue' => ['123','104','238'],'medium spring green' => ['0','250','154'],'medium turquoise' => ['72','209','204'],'medium violet red' => ['199','21','133'],'mediumaquamarine' => ['102','205','170'],'mediumblue' => ['0','0','205'],'mediumorchid' => ['186','85','211'],'mediumorchid1' => ['224','102','255'],'mediumorchid2' => ['209','95','238'],'mediumorchid3' => ['180','82','205'],'mediumorchid4' => ['122','55','139'],'mediumpurple' => ['147','112','219'],'mediumpurple1' => ['171','130','255'],'mediumpurple2' => ['159','121','238'],'mediumpurple3' => ['137','104','205'],'mediumpurple4' => ['93','71','139'],'mediumseagreen' => ['60','179','113'],'mediumslateblue' => ['123','104','238'],'mediumspringgreen' => ['0','250','154'],'mediumturquoise' => ['72','209','204'],'mediumvioletred' => ['199','21','133'],'midnight blue' => ['25','25','112'],'midnightblue' => ['25','25','112'],'mint cream' => ['245','255','250'],'mintcream' => ['245','255','250'],'misty rose' => ['255','228','225'],'mistyrose' => ['255','228','225'],'mistyrose1' => ['255','228','225'],'mistyrose2' => ['238','213','210'],'mistyrose3' => ['205','183','181'],'mistyrose4' => ['139','125','123'],'moccasin' => ['255','228','181'],'navajo white' => ['255','222','173'],'navajowhite' => ['255','222','173'],'navajowhite1' => ['255','222','173'],'navajowhite2' => ['238','207','161'],'navajowhite3' => ['205','179','139'],'navajowhite4' => ['139','121','94'],'navy' => ['0','0','128'],'navy blue' => ['0','0','128'],'navyblue' => ['0','0','128'],'old lace' => ['253','245','230'],'oldlace' => ['253','245','230'],'olive drab' => ['107','142','35'],'olivedrab' => ['107','142','35'],'olivedrab1' => ['192','255','62'],'olivedrab2' => ['179','238','58'],'olivedrab3' => ['154','205','50'],'olivedrab4' => ['105','139','34'],'orange' => ['255','165','0'],'orange red' => ['255','69','0'],'orange1' => ['255','165','0'],'orange2' => ['238','154','0'],'orange3' => ['205','133','0'],'orange4' => ['139','90','0'],'orangered' => ['255','69','0'],'orangered1' => ['255','69','0'],'orangered2' => ['238','64','0'],'orangered3' => ['205','55','0'],'orangered4' => ['139','37','0'],'orchid' => ['218','112','214'],'orchid1' => ['255','131','250'],'orchid2' => ['238','122','233'],'orchid3' => ['205','105','201'],'orchid4' => ['139','71','137'],'pale goldenrod' => ['238','232','170'],'pale green' => ['152','251','152'],'pale turquoise' => ['175','238','238'],'pale violet red' => ['219','112','147'],'palegoldenrod' => ['238','232','170'],'palegreen' => ['152','251','152'],'palegreen1' => ['154','255','154'],'palegreen2' => ['144','238','144'],'palegreen3' => ['124','205','124'],'palegreen4' => ['84','139','84'],'paleturquoise' => ['175','238','238'],'paleturquoise1' => ['187','255','255'],'paleturquoise2' => ['174','238','238'],'paleturquoise3' => ['150','205','205'],'paleturquoise4' => ['102','139','139'],'palevioletred' => ['219','112','147'],'palevioletred1' => ['255','130','171'],'palevioletred2' => ['238','121','159'],'palevioletred3' => ['205','104','137'],'palevioletred4' => ['139','71','93'],'papaya whip' => ['255','239','213'],'papayawhip' => ['255','239','213'],'peach puff' => ['255','218','185'],'peachpuff' => ['255','218','185'],'peachpuff1' => ['255','218','185'],'peachpuff2' => ['238','203','173'],'peachpuff3' => ['205','175','149'],'peachpuff4' => ['139','119','101'],'peru' => ['205','133','63'],'pink' => ['255','192','203'],'pink1' => ['255','181','197'],'pink2' => ['238','169','184'],'pink3' => ['205','145','158'],'pink4' => ['139','99','108'],'plum' => ['221','160','221'],'plum1' => ['255','187','255'],'plum2' => ['238','174','238'],'plum3' => ['205','150','205'],'plum4' => ['139','102','139'],'powder blue' => ['176','224','230'],'powderblue' => ['176','224','230'],'purple' => ['160','32','240'],'purple1' => ['155','48','255'],'purple2' => ['145','44','238'],'purple3' => ['125','38','205'],'purple4' => ['85','26','139'],'red' => ['255','0','0'],'red1' => ['255','0','0'],'red2' => ['238','0','0'],'red3' => ['205','0','0'],'red4' => ['139','0','0'],'rosy brown' => ['188','143','143'],'rosybrown' => ['188','143','143'],'rosybrown1' => ['255','193','193'],'rosybrown2' => ['238','180','180'],'rosybrown3' => ['205','155','155'],'rosybrown4' => ['139','105','105'],'royal blue' => ['65','105','225'],'royalblue' => ['65','105','225'],'royalblue1' => ['72','118','255'],'royalblue2' => ['67','110','238'],'royalblue3' => ['58','95','205'],'royalblue4' => ['39','64','139'],'saddle brown' => ['139','69','19'],'saddlebrown' => ['139','69','19'],'salmon' => ['250','128','114'],'salmon1' => ['255','140','105'],'salmon2' => ['238','130','98'],'salmon3' => ['205','112','84'],'salmon4' => ['139','76','57'],'sandy brown' => ['244','164','96'],'sandybrown' => ['244','164','96'],'sea green' => ['46','139','87'],'seagreen' => ['46','139','87'],'seagreen1' => ['84','255','159'],'seagreen2' => ['78','238','148'],'seagreen3' => ['67','205','128'],'seagreen4' => ['46','139','87'],'seashell' => ['255','245','238'],'seashell1' => ['255','245','238'],'seashell2' => ['238','229','222'],'seashell3' => ['205','197','191'],'seashell4' => ['139','134','130'],'sienna' => ['160','82','45'],'sienna1' => ['255','130','71'],'sienna2' => ['238','121','66'],'sienna3' => ['205','104','57'],'sienna4' => ['139','71','38'],'sky blue' => ['135','206','235'],'skyblue' => ['135','206','235'],'skyblue1' => ['135','206','255'],'skyblue2' => ['126','192','238'],'skyblue3' => ['108','166','205'],'skyblue4' => ['74','112','139'],'slate blue' => ['106','90','205'],'slate gray' => ['112','128','144'],'slate grey' => ['112','128','144'],'slateblue' => ['106','90','205'],'slateblue1' => ['131','111','255'],'slateblue2' => ['122','103','238'],'slateblue3' => ['105','89','205'],'slateblue4' => ['71','60','139'],'slategray' => ['112','128','144'],'slategray1' => ['198','226','255'],'slategray2' => ['185','211','238'],'slategray3' => ['159','182','205'],'slategray4' => ['108','123','139'],'slategrey' => ['112','128','144'],'snow' => ['255','250','250'],'snow1' => ['255','250','250'],'snow2' => ['238','233','233'],'snow3' => ['205','201','201'],'snow4' => ['139','137','137'],'spring green' => ['0','255','127'],'springgreen' => ['0','255','127'],'springgreen1' => ['0','255','127'],'springgreen2' => ['0','238','118'],'springgreen3' => ['0','205','102'],'springgreen4' => ['0','139','69'],'steel blue' => ['70','130','180'],'steelblue' => ['70','130','180'],'steelblue1' => ['99','184','255'],'steelblue2' => ['92','172','238'],'steelblue3' => ['79','148','205'],'steelblue4' => ['54','100','139'],'tan' => ['210','180','140'],'tan1' => ['255','165','79'],'tan2' => ['238','154','73'],'tan3' => ['205','133','63'],'tan4' => ['139','90','43'],'thistle' => ['216','191','216'],'thistle1' => ['255','225','255'],'thistle2' => ['238','210','238'],'thistle3' => ['205','181','205'],'thistle4' => ['139','123','139'],'tomato' => ['255','99','71'],'tomato1' => ['255','99','71'],'tomato2' => ['238','92','66'],'tomato3' => ['205','79','57'],'tomato4' => ['139','54','38'],'turquoise' => ['64','224','208'],'turquoise1' => ['0','245','255'],'turquoise2' => ['0','229','238'],'turquoise3' => ['0','197','205'],'turquoise4' => ['0','134','139'],'violet' => ['238','130','238'],'violet red' => ['208','32','144'],'violetred' => ['208','32','144'],'violetred1' => ['255','62','150'],'violetred2' => ['238','58','140'],'violetred3' => ['205','50','120'],'violetred4' => ['139','34','82'],'wheat' => ['245','222','179'],'wheat1' => ['255','231','186'],'wheat2' => ['238','216','174'],'wheat3' => ['205','186','150'],'wheat4' => ['139','126','102'],'white' => ['255','255','255'],'white smoke' => ['245','245','245'],'whitesmoke' => ['245','245','245'],'yellow' => ['255','255','0'],'yellow green' => ['154','205','50'],'yellow1' => ['255','255','0'],'yellow2' => ['238','238','0'],'yellow3' => ['205','205','0'],'yellow4' => ['139','139','0'],'yellowgreen' => ['154','205','50']} |
1976
|
|
|
|
|
|
|
EOT |
1977
|
|
|
|
|
|
|
} |
1978
|
|
|
|
|
|
|
|
1979
|
|
|
|
|
|
|
sub __instantiate_object |
1980
|
|
|
|
|
|
|
{ |
1981
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
1982
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
1983
|
0
|
|
|
|
|
0
|
my $class = shift( @_ ); |
1984
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
1985
|
0
|
|
|
|
|
0
|
my $o; |
1986
|
0
|
|
|
|
|
0
|
try |
1987
|
0
|
|
|
0
|
|
0
|
{ |
1988
|
|
|
|
|
|
|
## https://stackoverflow.com/questions/32608504/how-to-check-if-perl-module-is-available#comment53081298_32608860 |
1989
|
|
|
|
|
|
|
## require $class unless( defined( *{"${class}::"} ) ); |
1990
|
0
|
|
|
|
|
0
|
my $rc = eval{ Class::Load::load_class( $class ); }; |
|
0
|
|
|
|
|
0
|
|
1991
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Unable to load class $class: $@" ) ) if( $@ ); |
1992
|
|
|
|
|
|
|
# $self->message( 3, "Called with args: ", sub{ $self->dumper( \@_ ) } ); |
1993
|
0
|
0
|
0
|
|
|
0
|
@_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) ); |
1994
|
0
|
0
|
|
|
|
0
|
$o = @_ ? $class->new( @_ ) : $class->new; |
1995
|
0
|
0
|
|
|
|
0
|
$o->debug( $this->{debug} ) if( $o->can( 'debug' ) ); |
1996
|
0
|
0
|
|
|
|
0
|
return( $self->pass_error( "Unable to instantiate an object of class $class: ", $class->error ) ) if( !defined( $o ) ); |
1997
|
|
|
|
|
|
|
} |
1998
|
0
|
0
|
|
|
|
0
|
catch( $e ) |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
1999
|
0
|
|
|
0
|
|
0
|
{ |
2000
|
0
|
|
|
|
|
0
|
return( $self->error({ code => 500, message => $e }) ); |
2001
|
0
|
0
|
0
|
|
|
0
|
} |
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
2002
|
0
|
|
|
|
|
0
|
return( $o ); |
2003
|
|
|
|
|
|
|
} |
2004
|
|
|
|
|
|
|
|
2005
|
|
|
|
|
|
|
## Call to the actual method doing the work |
2006
|
|
|
|
|
|
|
## The reason for doing so is because _instantiate_object() may be inherited, but |
2007
|
|
|
|
|
|
|
## _set_get_class or _set_get_hash_as_object created dynamic class which requires to call _instantiate_object |
2008
|
|
|
|
|
|
|
## If _instantiate_object is inherited, it will yield unpredictable results |
2009
|
0
|
|
|
0
|
|
0
|
sub _instantiate_object { return( shift->__instantiate_object( @_ ) ); } |
2010
|
|
|
|
|
|
|
|
2011
|
|
|
|
|
|
|
sub _is_a |
2012
|
|
|
|
|
|
|
{ |
2013
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2014
|
0
|
|
|
|
|
0
|
my $obj = shift( @_ ); |
2015
|
0
|
|
|
|
|
0
|
my $pkg = shift( @_ ); |
2016
|
6
|
|
|
6
|
|
58
|
no overloading; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
29166
|
|
2017
|
0
|
0
|
0
|
|
|
0
|
return if( !$obj || !$pkg ); |
2018
|
0
|
0
|
|
|
|
0
|
return if( !$self->_is_object( $obj ) ); |
2019
|
0
|
|
|
|
|
0
|
return( $obj->isa( $pkg ) ); |
2020
|
|
|
|
|
|
|
} |
2021
|
|
|
|
|
|
|
|
2022
|
0
|
|
|
0
|
|
0
|
sub _is_class_loaded { shift( @_ ); return( Class::Load::is_class_loaded( @_ ) ); } |
|
0
|
|
|
|
|
0
|
|
2023
|
|
|
|
|
|
|
|
2024
|
|
|
|
|
|
|
## UNIVERSAL::isa works for both array or array as objects |
2025
|
|
|
|
|
|
|
## sub _is_array { return( UNIVERSAL::isa( $_[1], 'ARRAY' ) ); } |
2026
|
0
|
|
|
0
|
|
0
|
sub _is_array { return( Scalar::Util::reftype( $_[1] ) eq 'ARRAY' ); } |
2027
|
|
|
|
|
|
|
|
2028
|
|
|
|
|
|
|
## sub _is_hash { return( UNIVERSAL::isa( $_[1], 'HASH' ) ); } |
2029
|
12
|
|
|
12
|
|
40
|
sub _is_hash { return( Scalar::Util::reftype( $_[1] ) eq 'HASH' ); } |
2030
|
|
|
|
|
|
|
|
2031
|
113025
|
|
|
113025
|
|
501790
|
sub _is_object { return( Scalar::Util::blessed( $_[1] ) ); } |
2032
|
|
|
|
|
|
|
|
2033
|
0
|
|
|
0
|
|
0
|
sub _is_scalar{ return( Scalar::Util::reftype( $_[1] ) eq 'SCALAR' ); } |
2034
|
|
|
|
|
|
|
|
2035
|
|
|
|
|
|
|
sub _load_class |
2036
|
|
|
|
|
|
|
{ |
2037
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2038
|
0
|
|
0
|
|
|
0
|
my $class = shift( @_ ) || return( $self->error( "No package name was provided to load." ) ); |
2039
|
0
|
|
|
|
|
0
|
try |
2040
|
0
|
|
|
0
|
|
0
|
{ |
2041
|
0
|
|
|
|
|
0
|
return( Class::Load::load_class( "$class" ) ); |
2042
|
|
|
|
|
|
|
} |
2043
|
0
|
0
|
|
|
|
0
|
catch( $e ) |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
2044
|
0
|
|
|
0
|
|
0
|
{ |
2045
|
0
|
|
|
|
|
0
|
return( $self->error( $e ) ); |
2046
|
0
|
0
|
0
|
|
|
0
|
} |
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
2047
|
|
|
|
|
|
|
} |
2048
|
|
|
|
|
|
|
|
2049
|
|
|
|
|
|
|
sub _obj2h |
2050
|
|
|
|
|
|
|
{ |
2051
|
60449
|
|
|
60449
|
|
87821
|
my $self = shift( @_ ); |
2052
|
|
|
|
|
|
|
## print( STDERR "_obj2h(): Getting a hash refernece out of the object '$self'\n" ); |
2053
|
60449
|
50
|
|
|
|
156575
|
if( Scalar::Util::reftype( $self ) eq 'HASH' ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
2054
|
|
|
|
|
|
|
{ |
2055
|
60449
|
|
|
|
|
105155
|
return( $self ); |
2056
|
|
|
|
|
|
|
} |
2057
|
|
|
|
|
|
|
elsif( Scalar::Util::reftype( $self ) eq 'GLOB' ) |
2058
|
|
|
|
|
|
|
{ |
2059
|
|
|
|
|
|
|
## print( STDERR "Returning a reference to an hash for glob $self\n" ); |
2060
|
0
|
|
|
|
|
0
|
return( \%{*$self} ); |
|
0
|
|
|
|
|
0
|
|
2061
|
|
|
|
|
|
|
} |
2062
|
|
|
|
|
|
|
## The method that called message was itself called using the package name like My::Package->some_method |
2063
|
|
|
|
|
|
|
## We are going to check if global $DEBUG or $VERBOSE variables are set and create the related debug and verbose entry into the hash we return |
2064
|
|
|
|
|
|
|
elsif( !ref( $self ) ) |
2065
|
|
|
|
|
|
|
{ |
2066
|
0
|
|
|
|
|
0
|
my $class = $self; |
2067
|
|
|
|
|
|
|
my $hash = |
2068
|
|
|
|
|
|
|
{ |
2069
|
0
|
|
|
|
|
0
|
'debug' => ${ "${class}\::DEBUG" }, |
2070
|
0
|
|
|
|
|
0
|
'verbose' => ${ "${class}\::VERBOSE" }, |
2071
|
0
|
|
|
|
|
0
|
'error' => ${ "${class}\::ERROR" }, |
|
0
|
|
|
|
|
0
|
|
2072
|
|
|
|
|
|
|
}; |
2073
|
|
|
|
|
|
|
## XXX |
2074
|
|
|
|
|
|
|
## print( STDERR "Called with '$self' with debug value '$hash->{debug}' and verbose '$hash->{verbose}'\n" ); |
2075
|
0
|
|
|
|
|
0
|
return( bless( $hash => $class ) ); |
2076
|
|
|
|
|
|
|
} |
2077
|
|
|
|
|
|
|
## Because object may be accessed as My::Package->method or My::Package::method |
2078
|
|
|
|
|
|
|
## there is not always an object available, so we need to fake it to avoid error |
2079
|
|
|
|
|
|
|
## This is primarly itended for generic methods error(), errstr() to work under any conditions. |
2080
|
|
|
|
|
|
|
else |
2081
|
|
|
|
|
|
|
{ |
2082
|
0
|
|
|
|
|
0
|
return( {} ); |
2083
|
|
|
|
|
|
|
} |
2084
|
|
|
|
|
|
|
} |
2085
|
|
|
|
|
|
|
|
2086
|
|
|
|
|
|
|
sub _parse_timestamp |
2087
|
|
|
|
|
|
|
{ |
2088
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2089
|
0
|
|
|
|
|
0
|
my $str = shift( @_ ); |
2090
|
|
|
|
|
|
|
## No value was actually provided |
2091
|
0
|
0
|
|
|
|
0
|
return( undef() ) if( !length( $str ) ); |
2092
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2093
|
0
|
|
|
|
|
0
|
my $tz = DateTime::TimeZone->new( name => 'local' ); |
2094
|
0
|
|
|
|
|
0
|
my $error = 0; |
2095
|
|
|
|
|
|
|
my $opt = |
2096
|
|
|
|
|
|
|
{ |
2097
|
|
|
|
|
|
|
pattern => '%Y-%m-%d %T', |
2098
|
|
|
|
|
|
|
locale => 'en_GB', |
2099
|
|
|
|
|
|
|
time_zone => $tz->name, |
2100
|
0
|
|
|
0
|
|
0
|
on_error => sub{ $error++ }, |
2101
|
0
|
|
|
|
|
0
|
}; |
2102
|
|
|
|
|
|
|
# $self->message( 3, "Checking timestamp string '$str' for appropriate pattern" ); |
2103
|
|
|
|
|
|
|
## 2019-06-19 23:23:57.000000000+0900 |
2104
|
|
|
|
|
|
|
## From PostgreSQL: 2019-06-20 11:02:36.306917+09 |
2105
|
|
|
|
|
|
|
## ISO 8601: 2019-06-20T11:08:27 |
2106
|
0
|
0
|
|
|
|
0
|
if( $str =~ /(\d{4})[-|\/](\d{1,2})[-|\/](\d{1,2})(?:[[:blank:]]+|T)(\d{1,2}:\d{1,2}:\d{1,2})(?:\.\d+)?((?:\+|\-)\d{2,4})?/ ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
2107
|
|
|
|
|
|
|
{ |
2108
|
0
|
|
|
|
|
0
|
my( $date, $time, $zone ) = ( "$1-$2-$3", $4, $5 ); |
2109
|
0
|
0
|
|
|
|
0
|
if( !length( $zone ) ) |
2110
|
|
|
|
|
|
|
{ |
2111
|
0
|
|
|
|
|
0
|
my $dt = DateTime->now( time_zone => $tz ); |
2112
|
0
|
|
|
|
|
0
|
my $offset = $dt->offset; |
2113
|
|
|
|
|
|
|
## e.g. 9 or possibly 9.5 |
2114
|
0
|
|
|
|
|
0
|
my $offset_hour = ( $offset / 3600 ); |
2115
|
|
|
|
|
|
|
## e.g. 9.5 => 0.5 * 60 = 30 |
2116
|
0
|
|
|
|
|
0
|
my $offset_min = ( $offset_hour - CORE::int( $offset_hour ) ) * 60; |
2117
|
0
|
|
|
|
|
0
|
$zone = sprintf( '%+03d%02d', $offset_hour, $offset_min ); |
2118
|
|
|
|
|
|
|
} |
2119
|
|
|
|
|
|
|
# $self->message( 3, "\tMatched pattern #1 with date '$date', time '$time' and time zone '$zone'." ); |
2120
|
0
|
|
|
|
|
0
|
$date =~ tr/\//-/; |
2121
|
0
|
0
|
|
|
|
0
|
$zone .= '00' if( length( $zone ) == 3 ); |
2122
|
0
|
|
|
|
|
0
|
$str = "$date $time$zone"; |
2123
|
0
|
|
|
|
|
0
|
$self->message( 3, "\tChanging string to '$str'" ); |
2124
|
0
|
|
|
|
|
0
|
$opt->{pattern} = '%Y-%m-%d %T%z'; |
2125
|
|
|
|
|
|
|
} |
2126
|
|
|
|
|
|
|
## From SQLite: 2019-06-20 02:03:14 |
2127
|
|
|
|
|
|
|
## From MySQL: 2019-06-20 11:04:01 |
2128
|
|
|
|
|
|
|
elsif( $str =~ /(\d{4})[-|\/](\d{1,2})[-|\/](\d{1,2})(?:[[:blank:]]+|T)(\d{1,2}:\d{1,2}:\d{1,2})/ ) |
2129
|
|
|
|
|
|
|
{ |
2130
|
0
|
|
|
|
|
0
|
my( $date, $time ) = ( "$1-$2-$3", $4 ); |
2131
|
|
|
|
|
|
|
# $self->message( 3, "\tMatched pattern #2 with date '$date', time '$time' and without time zone." ); |
2132
|
0
|
|
|
|
|
0
|
my $dt = DateTime->now( time_zone => $tz ); |
2133
|
0
|
|
|
|
|
0
|
my $offset = $dt->offset; |
2134
|
|
|
|
|
|
|
## e.g. 9 or possibly 9.5 |
2135
|
0
|
|
|
|
|
0
|
my $offset_hour = ( $offset / 3600 ); |
2136
|
|
|
|
|
|
|
## e.g. 9.5 => 0.5 * 60 = 30 |
2137
|
0
|
|
|
|
|
0
|
my $offset_min = ( $offset_hour - CORE::int( $offset_hour ) ) * 60; |
2138
|
0
|
|
|
|
|
0
|
my $offset_str = sprintf( '%+03d%02d', $offset_hour, $offset_min ); |
2139
|
0
|
|
|
|
|
0
|
$date =~ tr/\//-/; |
2140
|
0
|
|
|
|
|
0
|
$str = "$date $time$offset_str"; |
2141
|
0
|
|
|
|
|
0
|
$self->message( 3, "\tAdding time zone '", $tz->name, "' offset of $offset_str with result: '$str'." ); |
2142
|
0
|
|
|
|
|
0
|
$opt->{pattern} = '%Y-%m-%d %T%z'; |
2143
|
|
|
|
|
|
|
} |
2144
|
|
|
|
|
|
|
elsif( $str =~ /^(\d{4})[-|\/](\d{1,2})[-|\/](\d{1,2})$/ ) |
2145
|
|
|
|
|
|
|
{ |
2146
|
0
|
|
|
|
|
0
|
$str = "$1-$2-$3"; |
2147
|
|
|
|
|
|
|
# $self->message( 3, "\tMatched pattern #3 with date '$date' only." ); |
2148
|
0
|
|
|
|
|
0
|
$opt->{pattern} = '%Y-%m-%d'; |
2149
|
|
|
|
|
|
|
} |
2150
|
|
|
|
|
|
|
else |
2151
|
|
|
|
|
|
|
{ |
2152
|
0
|
|
|
|
|
0
|
return( '' ); |
2153
|
|
|
|
|
|
|
} |
2154
|
0
|
|
|
|
|
0
|
my $strp = DateTime::Format::Strptime->new( %$opt ); |
2155
|
0
|
|
|
|
|
0
|
my $dt = $strp->parse_datetime( $str ); |
2156
|
0
|
|
|
|
|
0
|
return( $dt ); |
2157
|
|
|
|
|
|
|
} |
2158
|
|
|
|
|
|
|
|
2159
|
|
|
|
|
|
|
sub _set_get |
2160
|
|
|
|
|
|
|
{ |
2161
|
4
|
|
|
4
|
|
6
|
my $self = shift( @_ ); |
2162
|
4
|
|
|
|
|
8
|
my $field = shift( @_ ); |
2163
|
4
|
|
|
|
|
78
|
my $this = $self->_obj2h; |
2164
|
4
|
50
|
|
|
|
13
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2165
|
4
|
50
|
|
|
|
9
|
if( @_ ) |
2166
|
|
|
|
|
|
|
{ |
2167
|
4
|
50
|
|
|
|
12
|
my $val = ( @_ == 1 ) ? shift( @_ ) : [ @_ ]; |
2168
|
4
|
|
|
|
|
8
|
$data->{ $field } = $val; |
2169
|
|
|
|
|
|
|
} |
2170
|
4
|
50
|
|
|
|
9
|
if( wantarray() ) |
2171
|
|
|
|
|
|
|
{ |
2172
|
0
|
0
|
|
|
|
0
|
if( ref( $data->{ $field } ) eq 'ARRAY' ) |
|
|
0
|
|
|
|
|
|
2173
|
|
|
|
|
|
|
{ |
2174
|
0
|
|
|
|
|
0
|
return( @{ $data->{ $field } } ); |
|
0
|
|
|
|
|
0
|
|
2175
|
|
|
|
|
|
|
} |
2176
|
|
|
|
|
|
|
elsif( ref( $data->{ $field } ) eq 'HASH' ) |
2177
|
|
|
|
|
|
|
{ |
2178
|
0
|
|
|
|
|
0
|
return( %{ $data->{ $field } } ); |
|
0
|
|
|
|
|
0
|
|
2179
|
|
|
|
|
|
|
} |
2180
|
|
|
|
|
|
|
else |
2181
|
|
|
|
|
|
|
{ |
2182
|
0
|
|
|
|
|
0
|
return( ( $data->{ $field } ) ); |
2183
|
|
|
|
|
|
|
} |
2184
|
|
|
|
|
|
|
} |
2185
|
|
|
|
|
|
|
else |
2186
|
|
|
|
|
|
|
{ |
2187
|
4
|
|
|
|
|
8
|
return( $data->{ $field } ); |
2188
|
|
|
|
|
|
|
} |
2189
|
|
|
|
|
|
|
} |
2190
|
|
|
|
|
|
|
|
2191
|
|
|
|
|
|
|
sub _set_get_array |
2192
|
|
|
|
|
|
|
{ |
2193
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2194
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
2195
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2196
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2197
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2198
|
|
|
|
|
|
|
{ |
2199
|
0
|
0
|
0
|
|
|
0
|
my $val = ( @_ == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? shift( @_ ) : [ @_ ]; |
2200
|
0
|
|
|
|
|
0
|
$data->{ $field } = $val; |
2201
|
|
|
|
|
|
|
} |
2202
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2203
|
|
|
|
|
|
|
} |
2204
|
|
|
|
|
|
|
|
2205
|
|
|
|
|
|
|
sub _set_get_array_as_object |
2206
|
|
|
|
|
|
|
{ |
2207
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2208
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
2209
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2210
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2211
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2212
|
|
|
|
|
|
|
{ |
2213
|
0
|
0
|
0
|
|
|
0
|
my $val = ( @_ == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? shift( @_ ) : [ @_ ]; |
2214
|
0
|
|
|
|
|
0
|
my $o = $data->{ $field }; |
2215
|
|
|
|
|
|
|
## Some existing data, like maybe default value |
2216
|
0
|
0
|
|
|
|
0
|
if( $o ) |
2217
|
|
|
|
|
|
|
{ |
2218
|
0
|
0
|
|
|
|
0
|
if( !$self->_is_object( $o ) ) |
2219
|
|
|
|
|
|
|
{ |
2220
|
0
|
|
|
|
|
0
|
my $tmp = $o; |
2221
|
0
|
|
|
|
|
0
|
$o = Module::Generic::Array->new( $tmp ); |
2222
|
|
|
|
|
|
|
} |
2223
|
0
|
|
|
|
|
0
|
$o->set( $val ); |
2224
|
|
|
|
|
|
|
} |
2225
|
|
|
|
|
|
|
else |
2226
|
|
|
|
|
|
|
{ |
2227
|
0
|
|
|
|
|
0
|
$o = Module::Generic::Array->new( $val ); |
2228
|
0
|
|
|
|
|
0
|
$data->{ $field } = $o; |
2229
|
|
|
|
|
|
|
} |
2230
|
|
|
|
|
|
|
} |
2231
|
0
|
0
|
0
|
|
|
0
|
if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) ) |
2232
|
|
|
|
|
|
|
{ |
2233
|
0
|
|
|
|
|
0
|
my $o = Module::Generic::Array->new( $data->{ $field } ); |
2234
|
0
|
|
|
|
|
0
|
$data->{ $field } = $o; |
2235
|
|
|
|
|
|
|
} |
2236
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2237
|
|
|
|
|
|
|
} |
2238
|
|
|
|
|
|
|
|
2239
|
|
|
|
|
|
|
sub _set_get_boolean |
2240
|
|
|
|
|
|
|
{ |
2241
|
430
|
|
|
430
|
|
839
|
my $self = shift( @_ ); |
2242
|
430
|
|
|
|
|
799
|
my $field = shift( @_ ); |
2243
|
430
|
|
|
|
|
994
|
my $this = $self->_obj2h; |
2244
|
430
|
50
|
|
|
|
1146
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2245
|
430
|
50
|
|
|
|
1085
|
if( @_ ) |
2246
|
|
|
|
|
|
|
{ |
2247
|
430
|
|
|
|
|
756
|
my $val = shift( @_ ); |
2248
|
|
|
|
|
|
|
# $self->message( 3, "Value provided for field '$field' is '$val' of reference (", ref( $val ), ")." ); |
2249
|
430
|
50
|
0
|
|
|
3203
|
if( Scalar::Util::blessed( $val ) && |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
33
|
|
|
|
|
2250
|
|
|
|
|
|
|
( $val->isa( 'JSON::PP::Boolean' ) || $val->isa( 'Module::Generic::Boolean' ) ) ) |
2251
|
|
|
|
|
|
|
{ |
2252
|
0
|
|
|
|
|
0
|
$data->{ $field } = $val; |
2253
|
|
|
|
|
|
|
} |
2254
|
|
|
|
|
|
|
elsif( Scalar::Util::reftype( $val ) eq 'SCALAR' ) |
2255
|
|
|
|
|
|
|
{ |
2256
|
0
|
0
|
|
|
|
0
|
$data->{ $field } = $$val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false; |
2257
|
|
|
|
|
|
|
} |
2258
|
|
|
|
|
|
|
elsif( lc( $val ) eq 'true' || lc( $val ) eq 'false' ) |
2259
|
|
|
|
|
|
|
{ |
2260
|
0
|
0
|
|
|
|
0
|
$data->{ $field } = lc( $val ) eq 'true' ? Module::Generic::Boolean->true : Module::Generic::Boolean->false; |
2261
|
|
|
|
|
|
|
} |
2262
|
|
|
|
|
|
|
else |
2263
|
|
|
|
|
|
|
{ |
2264
|
430
|
100
|
|
|
|
2141
|
$data->{ $field } = $val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false; |
2265
|
|
|
|
|
|
|
} |
2266
|
|
|
|
|
|
|
# $self->message( 3, "Boolean field now has value $self->{$field} (", ref( $self->{ $field } ), ")." ); |
2267
|
|
|
|
|
|
|
} |
2268
|
|
|
|
|
|
|
## If there is a value set, like a default value and it is not an object or at least not one we recognise |
2269
|
|
|
|
|
|
|
## We transform it into a Module::Generic::Boolean object |
2270
|
430
|
50
|
33
|
|
|
1462
|
if( CORE::length( $data->{ $field } ) && |
|
|
|
33
|
|
|
|
|
2271
|
|
|
|
|
|
|
( |
2272
|
|
|
|
|
|
|
!Scalar::Util::blessed( $data->{ $field } ) || |
2273
|
|
|
|
|
|
|
( |
2274
|
|
|
|
|
|
|
Scalar::Util::blessed( $data->{ $field } ) && |
2275
|
|
|
|
|
|
|
!$data->{ $field }->isa( 'Module::Generic::Boolean' ) && |
2276
|
|
|
|
|
|
|
!$data->{ $field }->isa( 'JSON::PP::Boolean' ) |
2277
|
|
|
|
|
|
|
) |
2278
|
|
|
|
|
|
|
) ) |
2279
|
|
|
|
|
|
|
{ |
2280
|
0
|
|
|
|
|
0
|
my $val = $data->{ $field }; |
2281
|
0
|
0
|
|
|
|
0
|
$data->{ $field } = $val ? Module::Generic::Boolean->true : Module::Generic::Boolean->false; |
2282
|
|
|
|
|
|
|
} |
2283
|
430
|
|
|
|
|
1326
|
return( $data->{ $field } ); |
2284
|
|
|
|
|
|
|
} |
2285
|
|
|
|
|
|
|
|
2286
|
|
|
|
|
|
|
sub __create_class |
2287
|
|
|
|
|
|
|
{ |
2288
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2289
|
0
|
|
0
|
|
|
0
|
my $field = shift( @_ ) || return( $self->error( "No field was provided to create a dynamic class." ) ); |
2290
|
0
|
|
|
|
|
0
|
my $def = shift( @_ ); |
2291
|
0
|
|
|
|
|
0
|
my $class; |
2292
|
0
|
0
|
|
|
|
0
|
if( $def->{_class} ) |
2293
|
|
|
|
|
|
|
{ |
2294
|
0
|
|
|
|
|
0
|
$class = $def->{_class}; |
2295
|
|
|
|
|
|
|
} |
2296
|
|
|
|
|
|
|
else |
2297
|
|
|
|
|
|
|
{ |
2298
|
0
|
|
|
|
|
0
|
my $new_class = $field; |
2299
|
0
|
|
|
|
|
0
|
$new_class =~ tr/-/_/; |
2300
|
0
|
|
|
|
|
0
|
$new_class =~ s/\_{2,}/_/g; |
2301
|
0
|
|
|
|
|
0
|
$new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) ); |
2302
|
0
|
|
|
|
|
0
|
$class = ref( $self ) . "\::${new_class}"; |
2303
|
|
|
|
|
|
|
} |
2304
|
0
|
0
|
|
|
|
0
|
unless( Class::Load::is_class_loaded( $class ) ) |
2305
|
|
|
|
|
|
|
{ |
2306
|
|
|
|
|
|
|
# $self->message( 3, "Class '$class' is not created yet, creating it." ); |
2307
|
0
|
|
|
|
|
0
|
my $type2func = |
2308
|
|
|
|
|
|
|
{ |
2309
|
|
|
|
|
|
|
array => '_set_get_array', |
2310
|
|
|
|
|
|
|
array_as_object => '_set_get_array_as_object', |
2311
|
|
|
|
|
|
|
boolean => '_set_get_boolean', |
2312
|
|
|
|
|
|
|
class => '_set_get_class', |
2313
|
|
|
|
|
|
|
class_array => '_set_get_class_array', |
2314
|
|
|
|
|
|
|
datetime => '_set_get_datetime', |
2315
|
|
|
|
|
|
|
hash => '_set_get_hash', |
2316
|
|
|
|
|
|
|
number => '_set_get_number', |
2317
|
|
|
|
|
|
|
object => '_set_get_object', |
2318
|
|
|
|
|
|
|
object_array => '_set_get_object_array', |
2319
|
|
|
|
|
|
|
object_array_object => '_set_get_object_array_object', |
2320
|
|
|
|
|
|
|
scalar => '_set_get_scalar', |
2321
|
|
|
|
|
|
|
scalar_or_object => '_set_get_scalar_or_object', |
2322
|
|
|
|
|
|
|
uri => '_set_get_uri', |
2323
|
|
|
|
|
|
|
}; |
2324
|
|
|
|
|
|
|
## Alias |
2325
|
0
|
|
|
|
|
0
|
$type2func->{string} = $type2func->{scalar}; |
2326
|
|
|
|
|
|
|
|
2327
|
0
|
|
|
|
|
0
|
my $perl = <<EOT; |
2328
|
|
|
|
|
|
|
package $class; |
2329
|
|
|
|
|
|
|
BEGIN |
2330
|
|
|
|
|
|
|
{ |
2331
|
|
|
|
|
|
|
use strict; |
2332
|
|
|
|
|
|
|
use Module::Generic; |
2333
|
|
|
|
|
|
|
use parent -norequire, qw( Module::Generic ); |
2334
|
|
|
|
|
|
|
}; |
2335
|
|
|
|
|
|
|
|
2336
|
|
|
|
|
|
|
EOT |
2337
|
0
|
|
|
|
|
0
|
my $call_sub = ( split( /::/, ( caller(1) )[3] ) )[-1]; |
2338
|
0
|
0
|
|
|
|
0
|
my $call_frame = $call_sub eq '_set_get_class' ? 1 : 0; |
2339
|
0
|
|
|
|
|
0
|
my( $pack, $file, $line ) = caller( $call_frame ); |
2340
|
0
|
|
|
|
|
0
|
my $code_lines = []; |
2341
|
0
|
|
|
|
|
0
|
foreach my $f ( sort( keys( %$def ) ) ) |
2342
|
|
|
|
|
|
|
{ |
2343
|
|
|
|
|
|
|
# $self->message( 3, "Checking field '$f'." ); |
2344
|
0
|
|
|
|
|
0
|
my $info = $def->{ $f }; |
2345
|
0
|
|
|
|
|
0
|
my $type = lc( $info->{type} ); |
2346
|
0
|
0
|
|
|
|
0
|
if( !CORE::exists( $type2func->{ $type } ) ) |
2347
|
|
|
|
|
|
|
{ |
2348
|
0
|
|
|
|
|
0
|
warn( "Warning only: _set_get_class was called from package $pack at line $line in file $file, but the type provided \"$type\" is unknown to us, so we are skipping this field \"$f\" in the creation of our virtual class.\n" ); |
2349
|
0
|
|
|
|
|
0
|
next; |
2350
|
|
|
|
|
|
|
} |
2351
|
0
|
|
|
|
|
0
|
my $func = $type2func->{ $type }; |
2352
|
0
|
0
|
0
|
|
|
0
|
if( $type eq 'object' || |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
2353
|
|
|
|
|
|
|
$type eq 'scalar_or_object' || |
2354
|
|
|
|
|
|
|
$type eq 'object_array' ) |
2355
|
|
|
|
|
|
|
{ |
2356
|
0
|
0
|
|
|
|
0
|
if( !$info->{class} ) |
2357
|
|
|
|
|
|
|
{ |
2358
|
0
|
|
|
|
|
0
|
warn( "Warning only: _set_get_class was called from package $pack at line $line in file $file, and class \"$class\" field \"$f\" is to require an object, but no object class name was provided. Use the \"class\" property parameter. So we are skipping this field \"$f\" in the creation of our virtual class.\n" ); |
2359
|
0
|
|
|
|
|
0
|
next; |
2360
|
|
|
|
|
|
|
} |
2361
|
0
|
|
|
|
|
0
|
my $this_class = $info->{class}; |
2362
|
0
|
|
|
|
|
0
|
CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', '$this_class', \@_ ) ); }" ); |
2363
|
|
|
|
|
|
|
} |
2364
|
|
|
|
|
|
|
elsif( $type eq 'class' || $type eq 'class_array' ) |
2365
|
|
|
|
|
|
|
{ |
2366
|
0
|
|
|
|
|
0
|
my $this_def = $info->{definition}; |
2367
|
0
|
0
|
|
|
|
0
|
if( !CORE::exists( $info->{definition} ) ) |
|
|
0
|
|
|
|
|
|
2368
|
|
|
|
|
|
|
{ |
2369
|
0
|
|
|
|
|
0
|
warn( "Warning only: No dynamic class fields definition was provided for this field \"$f\". Skipping this field.\n" ); |
2370
|
0
|
|
|
|
|
0
|
next; |
2371
|
|
|
|
|
|
|
} |
2372
|
|
|
|
|
|
|
elsif( ref( $this_def ) ne 'HASH' ) |
2373
|
|
|
|
|
|
|
{ |
2374
|
0
|
|
|
|
|
0
|
warn( "Warning only: I was expecting a fields definition hash reference for dynamic class field \"$f\", but instead got '$this_def'. Skipping this field.\n" ); |
2375
|
0
|
|
|
|
|
0
|
next; |
2376
|
|
|
|
|
|
|
} |
2377
|
0
|
|
|
|
|
0
|
my $d = Data::Dumper->new( [ $this_def ] ); |
2378
|
0
|
|
|
|
|
0
|
$d->Indent( 0 ); |
2379
|
0
|
|
|
|
|
0
|
$d->Purity( 1 ); |
2380
|
0
|
|
|
|
|
0
|
$d->Pad( '' ); |
2381
|
0
|
|
|
|
|
0
|
$d->Terse( 1 ); |
2382
|
0
|
|
|
|
|
0
|
$d->Sortkeys( 1 ); |
2383
|
0
|
|
|
|
|
0
|
my $hash_str = $d->Dump; |
2384
|
0
|
|
|
|
|
0
|
CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', $hash_str, \@_ ) ); }" ); |
2385
|
|
|
|
|
|
|
} |
2386
|
|
|
|
|
|
|
else |
2387
|
|
|
|
|
|
|
{ |
2388
|
0
|
|
|
|
|
0
|
CORE::push( @$code_lines, "sub $f { return( shift->${func}( '$f', \@_ ) ); }" ); |
2389
|
|
|
|
|
|
|
} |
2390
|
|
|
|
|
|
|
} |
2391
|
0
|
|
|
|
|
0
|
$perl .= join( "\n\n", @$code_lines ); |
2392
|
|
|
|
|
|
|
|
2393
|
0
|
|
|
|
|
0
|
$perl .= <<EOT; |
2394
|
|
|
|
|
|
|
|
2395
|
|
|
|
|
|
|
|
2396
|
|
|
|
|
|
|
1; |
2397
|
|
|
|
|
|
|
|
2398
|
|
|
|
|
|
|
EOT |
2399
|
|
|
|
|
|
|
# $self->message( 3, "Evaluating code:\n$perl" ); |
2400
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" ); |
2401
|
0
|
|
|
|
|
0
|
my $rc = eval( $perl ); |
2402
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" ); |
2403
|
0
|
0
|
|
|
|
0
|
die( "Unable to dynamically create module $class: $@" ) if( $@ ); |
2404
|
|
|
|
|
|
|
} |
2405
|
0
|
|
|
|
|
0
|
return( $class ); |
2406
|
|
|
|
|
|
|
} |
2407
|
|
|
|
|
|
|
|
2408
|
|
|
|
|
|
|
## $self->_set_get_class( 'my_field', { |
2409
|
|
|
|
|
|
|
## _class => 'My::Class', |
2410
|
|
|
|
|
|
|
## field1 => { type => 'datetime' }, |
2411
|
|
|
|
|
|
|
## field2 => { type => 'scalar' }, |
2412
|
|
|
|
|
|
|
## field3 => { type => 'boolean' }, |
2413
|
|
|
|
|
|
|
## field4 => { type => 'object', class => 'Some::Class' }, |
2414
|
|
|
|
|
|
|
## }, @_ ); |
2415
|
|
|
|
|
|
|
sub _set_get_class |
2416
|
|
|
|
|
|
|
{ |
2417
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2418
|
|
|
|
|
|
|
# $self->message( 3, "Got here with arguments: '", join( "', '", @_ ), "'." ); |
2419
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
2420
|
0
|
|
|
|
|
0
|
my $def = shift( @_ ); |
2421
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2422
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2423
|
0
|
0
|
0
|
|
|
0
|
@_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) ); |
2424
|
0
|
0
|
|
|
|
0
|
if( ref( $def ) ne 'HASH' ) |
2425
|
|
|
|
|
|
|
{ |
2426
|
0
|
|
|
|
|
0
|
CORE::warn( "Warning only: dynamic class field definition hash ($def) for field \"$field\" is not a hash reference.\n" ); |
2427
|
0
|
|
|
|
|
0
|
return; |
2428
|
|
|
|
|
|
|
} |
2429
|
|
|
|
|
|
|
|
2430
|
0
|
|
0
|
|
|
0
|
my $class = $self->__create_class( $field, $def ) || die( "Failed to create the dynamic class for field \"$field\".\n" ); |
2431
|
|
|
|
|
|
|
|
2432
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2433
|
|
|
|
|
|
|
{ |
2434
|
0
|
|
|
|
|
0
|
my $hash = shift( @_ ); |
2435
|
|
|
|
|
|
|
# my $o = $class->new( $hash ); |
2436
|
0
|
|
|
|
|
0
|
$self->messagef( 3, "Instantiating object of class '$class' with hash '$hash' containing %d elements: '%s'", scalar( keys( %$hash ) ), join( "', '", map{ "$_ => $hash->{$_}" } sort( keys( %$hash ) ) ) ); |
|
0
|
|
|
|
|
0
|
|
2437
|
|
|
|
|
|
|
## $self->messagef( 3, "Instantiating object of class '$class' with hash '$hash' containing %d elements: '%s'", scalar( keys( %$hash ) ), $self->dumper( $hash ) ); |
2438
|
0
|
|
|
|
|
0
|
my $o = $self->__instantiate_object( $field, $class, $hash ); |
2439
|
|
|
|
|
|
|
# $self->message( 3, "\tReturning object for field '$field' and class '$class': '$o'." ); |
2440
|
0
|
|
|
|
|
0
|
$data->{ $field } = $o; |
2441
|
|
|
|
|
|
|
} |
2442
|
|
|
|
|
|
|
|
2443
|
0
|
0
|
|
|
|
0
|
if( !$data->{ $field } ) |
2444
|
|
|
|
|
|
|
{ |
2445
|
0
|
|
|
|
|
0
|
my $o = $self->__instantiate_object( $field, $class ); |
2446
|
0
|
|
|
|
|
0
|
$data->{ $field } = $o; |
2447
|
|
|
|
|
|
|
} |
2448
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2449
|
|
|
|
|
|
|
} |
2450
|
|
|
|
|
|
|
|
2451
|
|
|
|
|
|
|
sub _set_get_class_array |
2452
|
|
|
|
|
|
|
{ |
2453
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2454
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
2455
|
0
|
|
|
|
|
0
|
my $def = shift( @_ ); |
2456
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2457
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2458
|
0
|
0
|
|
|
|
0
|
if( ref( $def ) ne 'HASH' ) |
2459
|
|
|
|
|
|
|
{ |
2460
|
0
|
|
|
|
|
0
|
CORE::warn( "Warning only: dynamic class field definition hash ($def) for field \"$field\" is not a hash reference.\n" ); |
2461
|
0
|
|
|
|
|
0
|
return; |
2462
|
|
|
|
|
|
|
} |
2463
|
0
|
0
|
0
|
|
|
0
|
@_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) ); |
2464
|
0
|
|
0
|
|
|
0
|
my $class = $self->__create_class( $field, $def ) || die( "Failed to create the dynamic class for field \"$field\".\n" ); |
2465
|
|
|
|
|
|
|
## return( $self->_set_get_object_array( $field, $class, @_ ) ); |
2466
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2467
|
|
|
|
|
|
|
{ |
2468
|
0
|
|
|
|
|
0
|
my $ref = shift( @_ ); |
2469
|
0
|
0
|
|
|
|
0
|
return( $self->error( "I was expecting an array ref, but instead got '$ref'. _is_array returned: '", $self->_is_array( $ref ), "'" ) ) if( !$self->_set_get_array( $ref ) ); |
2470
|
0
|
|
|
|
|
0
|
my $arr = []; |
2471
|
0
|
|
|
|
|
0
|
for( my $i = 0; $i < scalar( @$ref ); $i++ ) |
2472
|
|
|
|
|
|
|
{ |
2473
|
0
|
0
|
|
|
|
0
|
if( ref( $ref->[$i] ) ne 'HASH' ) |
2474
|
|
|
|
|
|
|
{ |
2475
|
0
|
|
|
|
|
0
|
return( $self->error( "Array offset $i is not a hash reference. I was expecting a hash reference to instantiate an object of class $class." ) ); |
2476
|
|
|
|
|
|
|
} |
2477
|
0
|
|
|
|
|
0
|
my $o = $self->__instantiate_object( $field, $class, $ref->[$i] ); |
2478
|
0
|
|
|
|
|
0
|
CORE::push( @$arr, $o ); |
2479
|
|
|
|
|
|
|
} |
2480
|
0
|
|
|
|
|
0
|
$data->{ $field } = $arr; |
2481
|
|
|
|
|
|
|
} |
2482
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2483
|
|
|
|
|
|
|
} |
2484
|
|
|
|
|
|
|
|
2485
|
|
|
|
|
|
|
sub _set_get_code |
2486
|
|
|
|
|
|
|
{ |
2487
|
1
|
|
|
1
|
|
3
|
my $self = shift( @_ ); |
2488
|
1
|
|
|
|
|
3
|
my $field = shift( @_ ); |
2489
|
1
|
|
|
|
|
4
|
my $this = $self->_obj2h; |
2490
|
1
|
50
|
|
|
|
4
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2491
|
1
|
50
|
|
|
|
4
|
if( @_ ) |
2492
|
|
|
|
|
|
|
{ |
2493
|
0
|
|
|
|
|
0
|
my $v = shift( @_ ); |
2494
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Value provided for \"$field\" ($v) is not an anonymous subroutine (code). You can pass as argument something like \$self->curry::my_sub or something like sub { some_code_here; }" ) ) if( ref( $v ) ne 'CODE' ); |
2495
|
0
|
|
|
|
|
0
|
$data->{ $field } = $v; |
2496
|
|
|
|
|
|
|
} |
2497
|
1
|
|
|
|
|
4
|
return( $data->{ $field } ); |
2498
|
|
|
|
|
|
|
} |
2499
|
|
|
|
|
|
|
|
2500
|
|
|
|
|
|
|
sub _set_get_datetime |
2501
|
|
|
|
|
|
|
{ |
2502
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2503
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
2504
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2505
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2506
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2507
|
|
|
|
|
|
|
{ |
2508
|
0
|
|
|
|
|
0
|
my $time = shift( @_ ); |
2509
|
|
|
|
|
|
|
# $self->message( 3, "Processing time stamp $time possibly of ref (", ref( $time ), ")." ); |
2510
|
0
|
|
|
|
|
0
|
my $now; |
2511
|
0
|
0
|
0
|
|
|
0
|
if( !defined( $time ) ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
2512
|
|
|
|
|
|
|
{ |
2513
|
0
|
|
|
|
|
0
|
$data->{ $field } = $time; |
2514
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2515
|
|
|
|
|
|
|
} |
2516
|
|
|
|
|
|
|
elsif( Scalar::Util::blessed( $time ) ) |
2517
|
|
|
|
|
|
|
{ |
2518
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Object provided as value for $field, but this is not a DateTime object" ) ) if( !$time->isa( 'DateTime' ) ); |
2519
|
0
|
|
|
|
|
0
|
$data->{ $field } = $time; |
2520
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2521
|
|
|
|
|
|
|
} |
2522
|
|
|
|
|
|
|
elsif( $time =~ /^\d+$/ && $time !~ /^\d{10}$/ ) |
2523
|
|
|
|
|
|
|
{ |
2524
|
0
|
|
|
|
|
0
|
return( $self->error( "DateTime value ($time) provided for field $field does not look like a unix timestamp" ) ); |
2525
|
|
|
|
|
|
|
} |
2526
|
|
|
|
|
|
|
elsif( $now = $self->_parse_timestamp( $time ) ) |
2527
|
|
|
|
|
|
|
{ |
2528
|
|
|
|
|
|
|
## Found a parsed datetime value |
2529
|
0
|
|
|
|
|
0
|
$data->{ $field } = $now; |
2530
|
0
|
|
|
|
|
0
|
return( $now ); |
2531
|
|
|
|
|
|
|
} |
2532
|
|
|
|
|
|
|
|
2533
|
|
|
|
|
|
|
# $self->message( 3, "Creating a DateTime object out of $time\n" ); |
2534
|
|
|
|
|
|
|
eval |
2535
|
0
|
|
|
|
|
0
|
{ |
2536
|
0
|
|
|
|
|
0
|
require DateTime; |
2537
|
0
|
|
|
|
|
0
|
require DateTime::Format::Strptime; |
2538
|
0
|
|
|
|
|
0
|
$now = DateTime->from_epoch( |
2539
|
|
|
|
|
|
|
epoch => $time, |
2540
|
|
|
|
|
|
|
time_zone => 'local', |
2541
|
|
|
|
|
|
|
); |
2542
|
0
|
|
|
|
|
0
|
my $strp = DateTime::Format::Strptime->new( |
2543
|
|
|
|
|
|
|
pattern => '%s', |
2544
|
|
|
|
|
|
|
locale => 'en_GB', |
2545
|
|
|
|
|
|
|
time_zone => 'local', |
2546
|
|
|
|
|
|
|
); |
2547
|
0
|
|
|
|
|
0
|
$now->set_formatter( $strp ); |
2548
|
|
|
|
|
|
|
}; |
2549
|
0
|
0
|
|
|
|
0
|
if( $@ ) |
2550
|
|
|
|
|
|
|
{ |
2551
|
0
|
|
|
|
|
0
|
$self->message( "Error while trying to get the DateTime object for field $k with value $time" ); |
2552
|
|
|
|
|
|
|
} |
2553
|
|
|
|
|
|
|
else |
2554
|
|
|
|
|
|
|
{ |
2555
|
|
|
|
|
|
|
# $self->message( 3, "Returning the DateTime object '$now'" ); |
2556
|
0
|
|
|
|
|
0
|
$data->{ $field } = $now; |
2557
|
|
|
|
|
|
|
} |
2558
|
|
|
|
|
|
|
} |
2559
|
|
|
|
|
|
|
## So that a call to this field will not trigger an error: "Can't call method "xxx" on an undefined value" |
2560
|
0
|
0
|
0
|
|
|
0
|
if( !$data->{ $field } && want( 'OBJECT' ) ) |
2561
|
|
|
|
|
|
|
{ |
2562
|
0
|
|
|
|
|
0
|
my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 }); |
2563
|
0
|
|
|
|
|
0
|
rreturn( $null ); |
2564
|
|
|
|
|
|
|
} |
2565
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2566
|
|
|
|
|
|
|
} |
2567
|
|
|
|
|
|
|
|
2568
|
|
|
|
|
|
|
sub _set_get_hash |
2569
|
|
|
|
|
|
|
{ |
2570
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2571
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
2572
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2573
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2574
|
|
|
|
|
|
|
# $self->message( 3, "Called for field '$field' with data '", join( "', '", @_ ), "'." ); |
2575
|
0
|
0
|
0
|
|
|
0
|
@_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) ); |
2576
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2577
|
|
|
|
|
|
|
{ |
2578
|
0
|
|
|
|
|
0
|
my $val; |
2579
|
0
|
0
|
|
|
|
0
|
if( ref( $_[0] ) eq 'HASH' ) |
|
|
0
|
|
|
|
|
|
2580
|
|
|
|
|
|
|
{ |
2581
|
0
|
|
|
|
|
0
|
$val = shift( @_ ); |
2582
|
|
|
|
|
|
|
} |
2583
|
|
|
|
|
|
|
elsif( ( @_ % 2 ) ) |
2584
|
|
|
|
|
|
|
{ |
2585
|
0
|
|
|
|
|
0
|
$val = { @_ }; |
2586
|
|
|
|
|
|
|
} |
2587
|
|
|
|
|
|
|
else |
2588
|
|
|
|
|
|
|
{ |
2589
|
0
|
|
|
|
|
0
|
my $val = shift( @_ ); |
2590
|
0
|
|
|
|
|
0
|
return( $self->error( "Method $field takes only a hash or reference to a hash, but value provided ($val) is not supported" ) ); |
2591
|
|
|
|
|
|
|
} |
2592
|
|
|
|
|
|
|
# $self->message( 3, "Setting value $val for field $field" ); |
2593
|
0
|
|
|
|
|
0
|
$data->{ $field } = $val; |
2594
|
|
|
|
|
|
|
} |
2595
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2596
|
|
|
|
|
|
|
} |
2597
|
|
|
|
|
|
|
|
2598
|
|
|
|
|
|
|
sub _set_get_hash_as_mix_object |
2599
|
|
|
|
|
|
|
{ |
2600
|
129
|
|
|
129
|
|
360
|
my $self = shift( @_ ); |
2601
|
129
|
|
|
|
|
308
|
my $field = shift( @_ ); |
2602
|
129
|
|
|
|
|
437
|
my $this = $self->_obj2h; |
2603
|
129
|
50
|
|
|
|
506
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2604
|
|
|
|
|
|
|
# $self->message( 3, "Called for field '$field' with data '", join( "', '", @_ ), "'." ); |
2605
|
129
|
50
|
33
|
|
|
571
|
@_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) ); |
2606
|
129
|
50
|
|
|
|
440
|
if( @_ ) |
2607
|
|
|
|
|
|
|
{ |
2608
|
0
|
|
|
|
|
0
|
my $val; |
2609
|
0
|
0
|
|
|
|
0
|
if( ref( $_[0] ) eq 'HASH' ) |
|
|
0
|
|
|
|
|
|
2610
|
|
|
|
|
|
|
{ |
2611
|
0
|
|
|
|
|
0
|
$val = shift( @_ ); |
2612
|
|
|
|
|
|
|
} |
2613
|
|
|
|
|
|
|
elsif( ( @_ % 2 ) ) |
2614
|
|
|
|
|
|
|
{ |
2615
|
0
|
|
|
|
|
0
|
$val = { @_ }; |
2616
|
|
|
|
|
|
|
} |
2617
|
|
|
|
|
|
|
else |
2618
|
|
|
|
|
|
|
{ |
2619
|
0
|
|
|
|
|
0
|
my $val = shift( @_ ); |
2620
|
0
|
|
|
|
|
0
|
return( $self->error( "Method $field takes only a hash or reference to a hash, but value provided ($val) is not supported" ) ); |
2621
|
|
|
|
|
|
|
} |
2622
|
|
|
|
|
|
|
# $self->message( 3, "Setting value $val for field $field" ); |
2623
|
0
|
|
|
|
|
0
|
$data->{ $field } = Module::Generic::Hash->new( $val ); |
2624
|
|
|
|
|
|
|
} |
2625
|
129
|
50
|
33
|
|
|
808
|
if( $data->{ $field } && !$self->_is_object( $data->{ $field } ) ) |
2626
|
|
|
|
|
|
|
{ |
2627
|
129
|
|
|
|
|
874
|
my $o = Module::Generic::Hash->new( $data->{ $field } ); |
2628
|
129
|
|
|
|
|
446
|
$data->{ $field } = $o; |
2629
|
|
|
|
|
|
|
} |
2630
|
129
|
|
|
|
|
463
|
return( $data->{ $field } ); |
2631
|
|
|
|
|
|
|
} |
2632
|
|
|
|
|
|
|
|
2633
|
|
|
|
|
|
|
sub _set_get_hash_as_object |
2634
|
|
|
|
|
|
|
{ |
2635
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2636
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2637
|
|
|
|
|
|
|
# $self->message( 3, "Called with args: ", $self->dumper( \@_ ) ); |
2638
|
0
|
|
0
|
|
|
0
|
my $field = shift( @_ ) || return( $self->error( "No field provided for _set_get_hash_as_object" ) ); |
2639
|
0
|
|
|
|
|
0
|
my $class; |
2640
|
0
|
0
|
0
|
|
|
0
|
@_ = () if( @_ == 1 && !defined( $_[0] ) ); |
2641
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2642
|
|
|
|
|
|
|
{ |
2643
|
|
|
|
|
|
|
## No class was provided |
2644
|
|
|
|
|
|
|
# if( ref( $_[0] ) eq 'HASH' ) |
2645
|
0
|
0
|
|
|
|
0
|
if( Scalar::Util::reftype( $_[0] ) eq 'HASH' ) |
|
|
0
|
|
|
|
|
|
2646
|
|
|
|
|
|
|
{ |
2647
|
0
|
|
|
|
|
0
|
my $new_class = $field; |
2648
|
0
|
|
|
|
|
0
|
$new_class =~ tr/-/_/; |
2649
|
0
|
|
|
|
|
0
|
$new_class =~ s/\_{2,}/_/g; |
2650
|
0
|
|
|
|
|
0
|
$new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) ); |
2651
|
0
|
|
|
|
|
0
|
$class = ref( $self ) . "\::${new_class}"; |
2652
|
|
|
|
|
|
|
} |
2653
|
|
|
|
|
|
|
elsif( ref( $_[0] ) ) |
2654
|
|
|
|
|
|
|
{ |
2655
|
0
|
|
|
|
|
0
|
return( $self->error( "Class name in _set_get_hash_as_object helper method cannot be a reference. Received: \"", overload::StrVal( $_[0] ), "\"." ) ); |
2656
|
|
|
|
|
|
|
} |
2657
|
|
|
|
|
|
|
else |
2658
|
|
|
|
|
|
|
{ |
2659
|
0
|
|
|
|
|
0
|
$class = shift( @_ ); |
2660
|
|
|
|
|
|
|
} |
2661
|
|
|
|
|
|
|
} |
2662
|
|
|
|
|
|
|
else |
2663
|
|
|
|
|
|
|
{ |
2664
|
0
|
|
|
|
|
0
|
my $new_class = $field; |
2665
|
0
|
|
|
|
|
0
|
$new_class =~ tr/-/_/; |
2666
|
0
|
|
|
|
|
0
|
$new_class =~ s/\_{2,}/_/g; |
2667
|
0
|
|
|
|
|
0
|
$new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) ); |
2668
|
0
|
|
|
|
|
0
|
$class = ref( $self ) . "\::${new_class}"; |
2669
|
|
|
|
|
|
|
} |
2670
|
|
|
|
|
|
|
# my $class = shift( @_ ); |
2671
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2672
|
0
|
0
|
|
|
|
0
|
unless( Class::Load::is_class_loaded( $class ) ) |
2673
|
|
|
|
|
|
|
{ |
2674
|
0
|
|
|
|
|
0
|
my $perl = <<EOT; |
2675
|
|
|
|
|
|
|
package $class; |
2676
|
|
|
|
|
|
|
BEGIN |
2677
|
|
|
|
|
|
|
{ |
2678
|
|
|
|
|
|
|
use strict; |
2679
|
|
|
|
|
|
|
use warnings::register; |
2680
|
|
|
|
|
|
|
use Module::Generic; |
2681
|
|
|
|
|
|
|
use parent -norequire, qw( Module::Generic::Dynamic ); |
2682
|
|
|
|
|
|
|
}; |
2683
|
|
|
|
|
|
|
|
2684
|
|
|
|
|
|
|
1; |
2685
|
|
|
|
|
|
|
|
2686
|
|
|
|
|
|
|
EOT |
2687
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" ); |
2688
|
0
|
|
|
|
|
0
|
my $rc = eval( $perl ); |
2689
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" ); |
2690
|
0
|
0
|
|
|
|
0
|
die( "Unable to dynamically create module \"$class\" for field \"$field\" based on our own class \"", ref( $self ), "\": $@" ) if( $@ ); |
2691
|
|
|
|
|
|
|
} |
2692
|
|
|
|
|
|
|
|
2693
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2694
|
|
|
|
|
|
|
{ |
2695
|
0
|
|
|
|
|
0
|
my $hash = shift( @_ ); |
2696
|
|
|
|
|
|
|
# my $o = $class->new( $hash ); |
2697
|
|
|
|
|
|
|
# print( STDERR ref( $self ), "::_set_get_hash_as_object instantiating hash with ref (", ref( $hash ), ") ", overload::StrVal( $hash ), "\n" ); |
2698
|
0
|
|
|
|
|
0
|
my $o = $self->__instantiate_object( $field, $class, $hash ); |
2699
|
0
|
|
|
0
|
|
0
|
$self->message( 3, "Resulting object contains: ", sub{ $self->dumper( $o ) } ); |
|
0
|
|
|
|
|
0
|
|
2700
|
0
|
|
|
|
|
0
|
$data->{ $field } = $o; |
2701
|
|
|
|
|
|
|
} |
2702
|
|
|
|
|
|
|
|
2703
|
0
|
0
|
0
|
|
|
0
|
if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) ) |
2704
|
|
|
|
|
|
|
{ |
2705
|
0
|
|
|
|
|
0
|
my $o = $data->{ $field } = $self->__instantiate_object( $field, $class, $data->{ $field } ); |
2706
|
|
|
|
|
|
|
} |
2707
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2708
|
|
|
|
|
|
|
} |
2709
|
|
|
|
|
|
|
|
2710
|
|
|
|
|
|
|
sub _set_get_number |
2711
|
|
|
|
|
|
|
{ |
2712
|
4
|
|
|
4
|
|
11
|
my $self = shift( @_ ); |
2713
|
4
|
|
|
|
|
10
|
my $field = shift( @_ ); |
2714
|
4
|
|
|
|
|
9
|
my $this = $self->_obj2h; |
2715
|
4
|
50
|
|
|
|
18
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2716
|
4
|
50
|
66
|
|
|
29
|
@_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) ); |
2717
|
4
|
100
|
|
|
|
11
|
if( @_ ) |
2718
|
|
|
|
|
|
|
{ |
2719
|
3
|
|
|
|
|
20
|
$data->{ $field } = Module::Generic::Number->new( shift( @_ ) ); |
2720
|
|
|
|
|
|
|
} |
2721
|
4
|
|
|
|
|
20
|
return( $data->{ $field } ); |
2722
|
|
|
|
|
|
|
} |
2723
|
|
|
|
|
|
|
|
2724
|
|
|
|
|
|
|
sub _set_get_number_or_object |
2725
|
|
|
|
|
|
|
{ |
2726
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2727
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
2728
|
0
|
|
|
|
|
0
|
my $class = shift( @_ ); |
2729
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2730
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2731
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2732
|
|
|
|
|
|
|
{ |
2733
|
0
|
0
|
0
|
|
|
0
|
if( ref( $_[0] ) eq 'HASH' || Scalar::Util::blessed( $_[0] ) ) |
2734
|
|
|
|
|
|
|
{ |
2735
|
0
|
|
|
|
|
0
|
return( $self->_set_get_object( $field, $class, @_ ) ); |
2736
|
|
|
|
|
|
|
} |
2737
|
|
|
|
|
|
|
else |
2738
|
|
|
|
|
|
|
{ |
2739
|
0
|
|
|
|
|
0
|
return( $self->_set_get_number( $field, @_ ) ); |
2740
|
|
|
|
|
|
|
} |
2741
|
|
|
|
|
|
|
} |
2742
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2743
|
|
|
|
|
|
|
} |
2744
|
|
|
|
|
|
|
|
2745
|
|
|
|
|
|
|
sub _set_get_object |
2746
|
|
|
|
|
|
|
{ |
2747
|
3564
|
|
|
3564
|
|
5992
|
my $self = shift( @_ ); |
2748
|
3564
|
|
|
|
|
5607
|
my $field = shift( @_ ); |
2749
|
3564
|
|
|
|
|
5693
|
my $class = shift( @_ ); |
2750
|
3564
|
|
|
|
|
8378
|
my $this = $self->_obj2h; |
2751
|
3564
|
50
|
|
|
|
9227
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2752
|
6
|
|
|
6
|
|
63
|
no overloading; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
17938
|
|
2753
|
|
|
|
|
|
|
# $self->message( 3, "Called for field '$field' and class '$class'." ); |
2754
|
3564
|
100
|
|
|
|
7617
|
if( @_ ) |
2755
|
|
|
|
|
|
|
{ |
2756
|
3563
|
50
|
|
|
|
7820
|
if( scalar( @_ ) == 1 ) |
2757
|
|
|
|
|
|
|
{ |
2758
|
|
|
|
|
|
|
## User removed the value by passing it an undefined value |
2759
|
3563
|
50
|
|
|
|
13307
|
if( !defined( $_[0] ) ) |
|
|
50
|
|
|
|
|
|
2760
|
|
|
|
|
|
|
{ |
2761
|
0
|
|
|
|
|
0
|
$data->{ $field } = undef(); |
2762
|
|
|
|
|
|
|
} |
2763
|
|
|
|
|
|
|
## User pass an object |
2764
|
|
|
|
|
|
|
elsif( Scalar::Util::blessed( $_[0] ) ) |
2765
|
|
|
|
|
|
|
{ |
2766
|
3563
|
|
|
|
|
5927
|
my $o = shift( @_ ); |
2767
|
3563
|
50
|
|
|
|
12602
|
return( $self->error( "Object provided (", ref( $o ), ") for $field is not a valid $class object" ) ) if( !$o->isa( "$class" ) ); |
2768
|
|
|
|
|
|
|
## XXX Bad idea: |
2769
|
|
|
|
|
|
|
## $o->debug( $this->{debug} ) if( $o->can( 'debug' ) ); |
2770
|
3563
|
|
|
|
|
19438
|
$data->{ $field } = $o; |
2771
|
|
|
|
|
|
|
} |
2772
|
|
|
|
|
|
|
else |
2773
|
|
|
|
|
|
|
{ |
2774
|
0
|
|
0
|
|
|
0
|
my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) ); |
2775
|
|
|
|
|
|
|
# $self->message( 3, "Setting field $field value to $o" ); |
2776
|
0
|
|
|
|
|
0
|
$data->{ $field } = $o; |
2777
|
|
|
|
|
|
|
} |
2778
|
|
|
|
|
|
|
} |
2779
|
|
|
|
|
|
|
else |
2780
|
|
|
|
|
|
|
{ |
2781
|
0
|
|
0
|
|
|
0
|
my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) ); |
2782
|
|
|
|
|
|
|
# $self->message( 3, "Setting field $field value to $o" ); |
2783
|
0
|
|
|
|
|
0
|
$data->{ $field } = $o; |
2784
|
|
|
|
|
|
|
} |
2785
|
|
|
|
|
|
|
} |
2786
|
|
|
|
|
|
|
## If nothing has been set for this field, ie no object, but we are called in chain |
2787
|
|
|
|
|
|
|
## we set a dummy object that will just call itself to avoid perl complaining about undefined value calling a method |
2788
|
3564
|
50
|
33
|
|
|
12111
|
if( !$data->{ $field } && want( 'OBJECT' ) ) |
2789
|
|
|
|
|
|
|
{ |
2790
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::_set_get_object(): Called in a chain for field $field and class $class, but no object is set, reverting to dummy object\n" ); |
2791
|
|
|
|
|
|
|
# $self->message( 3, "Called in a chain, but no object is set, reverting to dummy object." ); |
2792
|
|
|
|
|
|
|
## my $null = Module::Generic::Null->new( $o, { debug => $self->{debug}, has_error => 1 }); |
2793
|
|
|
|
|
|
|
## rreturn( $null ); |
2794
|
0
|
|
0
|
|
|
0
|
my $o = $self->_instantiate_object( $field, $class, @_ ) || return( $self->pass_error( $class->error ) ); |
2795
|
0
|
|
|
|
|
0
|
$data->{ $field } = $o; |
2796
|
0
|
|
|
|
|
0
|
return( $o ); |
2797
|
|
|
|
|
|
|
} |
2798
|
|
|
|
|
|
|
# $self->message( 3, "Returning for field '$field' value: ", $self->{ $field } ); |
2799
|
3564
|
|
|
|
|
10965
|
return( $data->{ $field } ); |
2800
|
|
|
|
|
|
|
} |
2801
|
|
|
|
|
|
|
|
2802
|
|
|
|
|
|
|
sub _set_get_object_array2 |
2803
|
|
|
|
|
|
|
{ |
2804
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2805
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
2806
|
0
|
|
|
|
|
0
|
my $class = shift( @_ ); |
2807
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2808
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2809
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2810
|
|
|
|
|
|
|
{ |
2811
|
0
|
|
|
|
|
0
|
my $data_to_process = shift( @_ ); |
2812
|
0
|
0
|
|
|
|
0
|
return( $self->error( "I was expecting an array ref, but instead got '$this'. _is_array returned: '", $self->_is_array( $ref ), "'" ) ) if( !$self->_is_array( $data_to_process ) ); |
2813
|
0
|
|
|
|
|
0
|
my $arr1 = []; |
2814
|
0
|
|
|
|
|
0
|
foreach my $ref ( @$data_to_process ) |
2815
|
|
|
|
|
|
|
{ |
2816
|
0
|
0
|
|
|
|
0
|
return( $self->error( "I was expecting an embeded array ref, but instead got '$ref'." ) ) if( ref( $ref ) ne 'ARRAY' ); |
2817
|
0
|
|
|
|
|
0
|
my $arr = []; |
2818
|
0
|
|
|
|
|
0
|
for( my $i = 0; $i < scalar( @$ref ); $i++ ) |
2819
|
|
|
|
|
|
|
{ |
2820
|
0
|
|
|
|
|
0
|
my $o; |
2821
|
0
|
0
|
|
|
|
0
|
if( defined( $ref->[$i] ) ) |
2822
|
|
|
|
|
|
|
{ |
2823
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Parameter provided for adding object of class $class is not a reference." ) ) if( !ref( $ref->[$i] ) ); |
2824
|
0
|
0
|
|
|
|
0
|
if( Scalar::Util::blessed( $ref->[$i] ) ) |
|
|
0
|
|
|
|
|
|
2825
|
|
|
|
|
|
|
{ |
2826
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Array offset $i contains an object from class $pack, but was expecting an object of class $class." ) ) if( !$ref->[$i]->isa( $class ) ); |
2827
|
0
|
|
|
|
|
0
|
$o = $ref->[$i]; |
2828
|
|
|
|
|
|
|
} |
2829
|
|
|
|
|
|
|
elsif( ref( $ref->[$i] ) eq 'HASH' ) |
2830
|
|
|
|
|
|
|
{ |
2831
|
|
|
|
|
|
|
#$o = $class->new( $h, $ref->[$i] ); |
2832
|
0
|
|
|
|
|
0
|
$o = $self->_instantiate_object( $field, $class, $ref->[$i] ); |
2833
|
|
|
|
|
|
|
} |
2834
|
|
|
|
|
|
|
else |
2835
|
|
|
|
|
|
|
{ |
2836
|
0
|
|
|
|
|
0
|
$self->error( "Warning only: data provided to instaantiate object of class $class is not a hash reference" ); |
2837
|
|
|
|
|
|
|
} |
2838
|
|
|
|
|
|
|
} |
2839
|
|
|
|
|
|
|
else |
2840
|
|
|
|
|
|
|
{ |
2841
|
|
|
|
|
|
|
#$o = $class->new( $h ); |
2842
|
0
|
|
|
|
|
0
|
$o = $self->_instantiate_object( $field, $class ); |
2843
|
|
|
|
|
|
|
} |
2844
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Unable to instantiate an object of class $class: ", $class->error ) ) if( !defined( $o ) ); |
2845
|
|
|
|
|
|
|
# $o->{ '_parent' } = $self->{ '_parent' }; |
2846
|
0
|
|
|
|
|
0
|
push( @$arr, $o ); |
2847
|
|
|
|
|
|
|
} |
2848
|
0
|
|
|
|
|
0
|
push( @$arr1, $arr ); |
2849
|
|
|
|
|
|
|
} |
2850
|
0
|
|
|
|
|
0
|
$data->{ $field } = $arr1; |
2851
|
|
|
|
|
|
|
} |
2852
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2853
|
|
|
|
|
|
|
} |
2854
|
|
|
|
|
|
|
|
2855
|
|
|
|
|
|
|
sub _set_get_object_array |
2856
|
|
|
|
|
|
|
{ |
2857
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2858
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
2859
|
0
|
|
|
|
|
0
|
my $class = shift( @_ ); |
2860
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2861
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2862
|
0
|
0
|
0
|
|
|
0
|
@_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) ); |
2863
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2864
|
|
|
|
|
|
|
{ |
2865
|
0
|
|
|
|
|
0
|
my $ref = shift( @_ ); |
2866
|
0
|
0
|
|
|
|
0
|
return( $self->error( "I was expecting an array ref, but instead got '$ref'. _is_array returned: '", $self->_is_array( $ref ), "'" ) ) if( !$self->_is_array( $ref ) ); |
2867
|
0
|
|
|
|
|
0
|
my $arr = []; |
2868
|
0
|
|
|
|
|
0
|
for( my $i = 0; $i < scalar( @$ref ); $i++ ) |
2869
|
|
|
|
|
|
|
{ |
2870
|
0
|
0
|
|
|
|
0
|
if( defined( $ref->[$i] ) ) |
2871
|
|
|
|
|
|
|
{ |
2872
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Array offset $i is not a reference. I was expecting an object of class $class or an hash reference to instantiate an object." ) ) if( !ref( $ref->[$i] ) ); |
2873
|
0
|
0
|
|
|
|
0
|
if( Scalar::Util::blessed( $ref->[$i] ) ) |
|
|
0
|
|
|
|
|
|
2874
|
|
|
|
|
|
|
{ |
2875
|
0
|
0
|
|
|
|
0
|
return( $self->error( "Array offset $i contains an object from class $pack, but was expecting an object of class $class." ) ) if( !$ref->[$i]->isa( $class ) ); |
2876
|
0
|
|
|
|
|
0
|
push( @$arr, $ref->[$i] ); |
2877
|
|
|
|
|
|
|
} |
2878
|
|
|
|
|
|
|
elsif( ref( $ref->[$i] ) eq 'HASH' ) |
2879
|
|
|
|
|
|
|
{ |
2880
|
|
|
|
|
|
|
#$o = $class->new( $h, $ref->[$i] ); |
2881
|
0
|
|
0
|
|
|
0
|
$o = $self->_instantiate_object( $field, $class, $ref->[$i] ) || return; |
2882
|
0
|
|
|
|
|
0
|
push( @$arr, $o ); |
2883
|
|
|
|
|
|
|
} |
2884
|
|
|
|
|
|
|
else |
2885
|
|
|
|
|
|
|
{ |
2886
|
0
|
|
|
|
|
0
|
$self->error( "Warning only: data provided to instantiate object of class $class is not a hash reference" ); |
2887
|
|
|
|
|
|
|
} |
2888
|
|
|
|
|
|
|
} |
2889
|
|
|
|
|
|
|
else |
2890
|
|
|
|
|
|
|
{ |
2891
|
0
|
|
|
|
|
0
|
return( $self->error( "Array offset $i contains an undefined value. I was expecting an object of class $class." ) ); |
2892
|
0
|
|
0
|
|
|
0
|
$o = $self->_instantiate_object( $field, $class ) || return; |
2893
|
0
|
|
|
|
|
0
|
push( @$arr, $o ); |
2894
|
|
|
|
|
|
|
} |
2895
|
|
|
|
|
|
|
} |
2896
|
0
|
|
|
|
|
0
|
$data->{ $field } = $arr; |
2897
|
|
|
|
|
|
|
} |
2898
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2899
|
|
|
|
|
|
|
} |
2900
|
|
|
|
|
|
|
|
2901
|
|
|
|
|
|
|
sub _set_get_object_array_object |
2902
|
|
|
|
|
|
|
{ |
2903
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2904
|
0
|
|
0
|
|
|
0
|
my $field = shift( @_ ) || return( $self->error( "No field name was provided for this array of object." ) ); |
2905
|
0
|
|
0
|
|
|
0
|
my $class = shift( @_ ) || return( $self->error( "No class was provided for this array of objects." ) ); |
2906
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2907
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2908
|
0
|
0
|
0
|
|
|
0
|
@_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) ); |
2909
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2910
|
|
|
|
|
|
|
{ |
2911
|
0
|
0
|
0
|
|
|
0
|
my $that = ( scalar( @_ ) == 1 && UNIVERSAL::isa( $_[0], 'ARRAY' ) ) ? shift( @_ ) : [ @_ ]; |
2912
|
|
|
|
|
|
|
## $self->message( 3, "Received following data to store as array object: ", sub{ $self->dump( $that ) } ); |
2913
|
0
|
|
0
|
|
|
0
|
my $ref = $self->_set_get_object_array( $field, $class, $that ) || return; |
2914
|
|
|
|
|
|
|
## $self->message( 3, "Object array returned is: ", sub{ $self->dump( $ref ) } ); |
2915
|
0
|
|
|
|
|
0
|
$data->{ $field } = Module::Generic::Array->new( $ref ); |
2916
|
|
|
|
|
|
|
## $self->message( 3, "Now value for field '$field' is: ", $data->{ $field }, " which contains: '", $data->{ $field }->join( "', '" ), "'." ); |
2917
|
|
|
|
|
|
|
} |
2918
|
|
|
|
|
|
|
## Default value so that call to the caller's method like my_sub->length will not produce something like "Can't call method "length" on an undefined value" |
2919
|
|
|
|
|
|
|
## Also, this will make i possible to set default value in caller's object and we would turn it into array object. |
2920
|
0
|
0
|
0
|
|
|
0
|
if( !$data->{ $field } || !$self->_is_object( $data->{ $field } ) ) |
2921
|
|
|
|
|
|
|
{ |
2922
|
0
|
|
|
|
|
0
|
my $o = Module::Generic::Array->new( $data->{ $field } ); |
2923
|
0
|
|
|
|
|
0
|
$data->{ $field } = $o; |
2924
|
|
|
|
|
|
|
} |
2925
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2926
|
|
|
|
|
|
|
} |
2927
|
|
|
|
|
|
|
|
2928
|
|
|
|
|
|
|
sub _set_get_object_variant |
2929
|
|
|
|
|
|
|
{ |
2930
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
2931
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
2932
|
|
|
|
|
|
|
## The class precisely depends on what we find looking ahead |
2933
|
0
|
|
|
|
|
0
|
my $class = shift( @_ ); |
2934
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
2935
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2936
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
2937
|
|
|
|
|
|
|
{ |
2938
|
0
|
0
|
|
|
|
0
|
if( ref( $_[0] ) eq 'HASH' ) |
|
|
0
|
|
|
|
|
|
2939
|
|
|
|
|
|
|
{ |
2940
|
0
|
|
|
|
|
0
|
my $o = $self->_instantiate_object( $field, $class, @_ ); |
2941
|
|
|
|
|
|
|
} |
2942
|
|
|
|
|
|
|
## AN array of objects hash |
2943
|
|
|
|
|
|
|
elsif( ref( $_[0] ) eq 'ARRAY' ) |
2944
|
|
|
|
|
|
|
{ |
2945
|
0
|
|
|
|
|
0
|
my $arr = shift( @_ ); |
2946
|
0
|
|
|
|
|
0
|
my $res = []; |
2947
|
0
|
|
|
|
|
0
|
foreach my $data ( @$arr ) |
2948
|
|
|
|
|
|
|
{ |
2949
|
0
|
|
0
|
|
|
0
|
my $o = $self->_instantiate_object( $field, $class, $data ) || return( $self->error( "Unable to create object: ", $self->error ) ); |
2950
|
0
|
|
|
|
|
0
|
push( @$res, $o ); |
2951
|
|
|
|
|
|
|
} |
2952
|
0
|
|
|
|
|
0
|
$data->{ $field } = $res; |
2953
|
|
|
|
|
|
|
} |
2954
|
|
|
|
|
|
|
} |
2955
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
2956
|
|
|
|
|
|
|
} |
2957
|
|
|
|
|
|
|
|
2958
|
|
|
|
|
|
|
sub _set_get_scalar |
2959
|
|
|
|
|
|
|
{ |
2960
|
4
|
|
|
4
|
|
8
|
my $self = shift( @_ ); |
2961
|
4
|
|
|
|
|
7
|
my $field = shift( @_ ); |
2962
|
4
|
|
|
|
|
10
|
my $this = $self->_obj2h; |
2963
|
4
|
50
|
|
|
|
10
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2964
|
4
|
50
|
|
|
|
10
|
if( @_ ) |
2965
|
|
|
|
|
|
|
{ |
2966
|
0
|
0
|
|
|
|
0
|
my $val = ( @_ == 1 ) ? shift( @_ ) : join( '', @_ ); |
2967
|
|
|
|
|
|
|
## Just in case, we force stringification |
2968
|
|
|
|
|
|
|
## $val = "$val" if( defined( $val ) ); |
2969
|
0
|
0
|
0
|
|
|
0
|
return( $self->error( "Method $field takes only a scalar, but value provided ($val) is a reference" ) ) if( ref( $val ) eq 'HASH' || ref( $val ) eq 'ARRAY' ); |
2970
|
0
|
|
|
|
|
0
|
$data->{ $field } = $val; |
2971
|
|
|
|
|
|
|
} |
2972
|
4
|
|
|
|
|
18
|
return( $data->{ $field } ); |
2973
|
|
|
|
|
|
|
} |
2974
|
|
|
|
|
|
|
|
2975
|
|
|
|
|
|
|
sub _set_get_scalar_as_object |
2976
|
|
|
|
|
|
|
{ |
2977
|
55442
|
|
|
55442
|
|
78704
|
my $self = shift( @_ ); |
2978
|
55442
|
|
|
|
|
78857
|
my $field = shift( @_ ); |
2979
|
55442
|
|
|
|
|
98550
|
my $this = $self->_obj2h; |
2980
|
55442
|
50
|
|
|
|
118332
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
2981
|
55442
|
100
|
|
|
|
107792
|
if( @_ ) |
2982
|
|
|
|
|
|
|
{ |
2983
|
3630
|
|
|
|
|
5214
|
my $val; |
2984
|
3630
|
50
|
33
|
|
|
16537
|
if( ref( $val ) eq 'SCALAR' || UNIVERSAL::isa( $val, 'SCALAR' ) ) |
|
|
50
|
|
|
|
|
|
2985
|
|
|
|
|
|
|
{ |
2986
|
0
|
|
|
|
|
0
|
$val = $$_[0]; |
2987
|
|
|
|
|
|
|
} |
2988
|
|
|
|
|
|
|
elsif( ref( $val ) ) |
2989
|
|
|
|
|
|
|
{ |
2990
|
0
|
|
|
|
|
0
|
return( $self->error( "I was expecting a string or a scalar reference, but instead got '$val'" ) ); |
2991
|
|
|
|
|
|
|
} |
2992
|
|
|
|
|
|
|
else |
2993
|
|
|
|
|
|
|
{ |
2994
|
3630
|
|
|
|
|
6673
|
$val = shift( @_ ); |
2995
|
|
|
|
|
|
|
} |
2996
|
3630
|
|
|
|
|
6175
|
my $o = $data->{ $field }; |
2997
|
|
|
|
|
|
|
# $self->message( 3, "Value to use is '$val' and current object is '", ref( $o ), "'." ); |
2998
|
3630
|
100
|
|
|
|
8097
|
if( ref( $o ) ) |
2999
|
|
|
|
|
|
|
{ |
3000
|
3434
|
|
|
|
|
8761
|
$o->set( $val ); |
3001
|
|
|
|
|
|
|
} |
3002
|
|
|
|
|
|
|
else |
3003
|
|
|
|
|
|
|
{ |
3004
|
196
|
|
|
|
|
687
|
$data->{ $field } = Module::Generic::Scalar->new( $val ); |
3005
|
|
|
|
|
|
|
} |
3006
|
|
|
|
|
|
|
# $self->message( 3, "Object now is: '", ref( $data->{ $field } ), "'." ); |
3007
|
|
|
|
|
|
|
} |
3008
|
|
|
|
|
|
|
# $self->message( 3, "Checking if object '", ref( $data->{ $field } ), "' is set. Is it an object? ", $self->_is_object( $data->{ $field } ) ? 'yes' : 'no', " and its stringified value is '", $data->{ $field }, "'." ); |
3009
|
55442
|
50
|
33
|
|
|
116378
|
if( !$self->_is_object( $data->{ $field } ) || ( $self->_is_object( $data->{ $field } ) && ref( $data->{ $field } ) ne ref( $self ) ) ) |
|
|
|
66
|
|
|
|
|
3010
|
|
|
|
|
|
|
{ |
3011
|
|
|
|
|
|
|
# $self->message( 3, "No object is set yet, initiating one." ); |
3012
|
55442
|
|
|
|
|
132474
|
$data->{ $field } = Module::Generic::Scalar->new( $data->{ $field } ); |
3013
|
|
|
|
|
|
|
} |
3014
|
55442
|
|
|
|
|
110791
|
my $v = $data->{ $field }; |
3015
|
55442
|
100
|
|
|
|
120765
|
if( !$v->defined ) |
3016
|
|
|
|
|
|
|
{ |
3017
|
49053
|
100
|
|
|
|
119100
|
if( Want::want( 'OBJECT' ) ) |
3018
|
|
|
|
|
|
|
{ |
3019
|
1444
|
|
|
|
|
88926
|
return( Module::Generic::Null->new ); |
3020
|
|
|
|
|
|
|
} |
3021
|
|
|
|
|
|
|
else |
3022
|
|
|
|
|
|
|
{ |
3023
|
47609
|
|
|
|
|
2795677
|
return; |
3024
|
|
|
|
|
|
|
} |
3025
|
|
|
|
|
|
|
} |
3026
|
|
|
|
|
|
|
else |
3027
|
|
|
|
|
|
|
{ |
3028
|
6389
|
|
|
|
|
21641
|
return( $v ); |
3029
|
|
|
|
|
|
|
} |
3030
|
|
|
|
|
|
|
} |
3031
|
|
|
|
|
|
|
|
3032
|
|
|
|
|
|
|
sub _set_get_scalar_or_object |
3033
|
|
|
|
|
|
|
{ |
3034
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
3035
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
3036
|
0
|
|
|
|
|
0
|
my $class = shift( @_ ); |
3037
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
3038
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
3039
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
3040
|
|
|
|
|
|
|
{ |
3041
|
0
|
0
|
0
|
|
|
0
|
if( ref( $_[0] ) eq 'HASH' || Scalar::Util::blessed( $_[0] ) ) |
3042
|
|
|
|
|
|
|
{ |
3043
|
0
|
|
|
|
|
0
|
return( $self->_set_get_object( $field, $class, @_ ) ); |
3044
|
|
|
|
|
|
|
} |
3045
|
|
|
|
|
|
|
else |
3046
|
|
|
|
|
|
|
{ |
3047
|
0
|
|
|
|
|
0
|
return( $self->_set_get_scalar( $field, @_ ) ); |
3048
|
|
|
|
|
|
|
} |
3049
|
|
|
|
|
|
|
} |
3050
|
0
|
0
|
0
|
|
|
0
|
if( !$data->{ $field } && want( 'OBJECT' ) ) |
3051
|
|
|
|
|
|
|
{ |
3052
|
|
|
|
|
|
|
# $self->message( 3, "Called in a chain for field $field and class $class, but no object is set, reverting to dummy object." ); |
3053
|
|
|
|
|
|
|
# $self->messagef( 3, "Expecting void? '%s'. Want scalar? '%s'. Want hash? '%s', wantref: '%s'", want('VOID'), want('SCALAR'), Want::want('HASH'), Want::wantref() ); |
3054
|
0
|
|
|
|
|
0
|
my $null = Module::Generic::Null->new( $o, { debug => $this->{debug}, has_error => 1 }); |
3055
|
0
|
|
|
|
|
0
|
rreturn( $null ); |
3056
|
|
|
|
|
|
|
} |
3057
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
3058
|
|
|
|
|
|
|
} |
3059
|
|
|
|
|
|
|
|
3060
|
|
|
|
|
|
|
sub _set_get_uri |
3061
|
|
|
|
|
|
|
{ |
3062
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
3063
|
0
|
|
|
|
|
0
|
my $field = shift( @_ ); |
3064
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
3065
|
0
|
0
|
|
|
|
0
|
my $data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
3066
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
3067
|
|
|
|
|
|
|
{ |
3068
|
0
|
|
|
|
|
0
|
try |
3069
|
0
|
|
|
0
|
|
0
|
{ |
3070
|
0
|
0
|
|
|
|
0
|
require URI if( !$self->_is_class_loaded( 'URI' ) ); |
3071
|
|
|
|
|
|
|
} |
3072
|
0
|
0
|
|
|
|
0
|
catch( $e ) |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
3073
|
0
|
|
|
0
|
|
0
|
{ |
3074
|
0
|
|
|
|
|
0
|
return( $self->error( "Error trying to load module URI: $e" ) ); |
3075
|
0
|
0
|
0
|
|
|
0
|
} |
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
3076
|
|
|
|
|
|
|
|
3077
|
0
|
|
|
|
|
0
|
my $str = shift( @_ ); |
3078
|
0
|
0
|
0
|
|
|
0
|
if( Scalar::Util::blessed( $str ) && $str->isa( 'URI' ) ) |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
|
|
0
|
|
|
|
|
|
3079
|
|
|
|
|
|
|
{ |
3080
|
0
|
|
|
|
|
0
|
$data->{ $field } = $str; |
3081
|
|
|
|
|
|
|
} |
3082
|
|
|
|
|
|
|
elsif( defined( $str ) && ( $str =~ /^[a-zA-Z]+:\/{2}/ || $str =~ /^urn\:[a-z]+\:/ || $str =~ /^[a-z]+\:/ ) ) |
3083
|
|
|
|
|
|
|
{ |
3084
|
0
|
|
|
|
|
0
|
$data->{ $field } = URI->new( $str ); |
3085
|
0
|
0
|
|
|
|
0
|
warn( "URI subclass is missing to handle this specific URI '$str'\n" ) if( !$data->{ $field }->has_recognized_scheme ); |
3086
|
|
|
|
|
|
|
} |
3087
|
|
|
|
|
|
|
## Is it an absolute path? |
3088
|
|
|
|
|
|
|
elsif( substr( $str, 0, 1 ) eq '/' ) |
3089
|
|
|
|
|
|
|
{ |
3090
|
0
|
|
|
|
|
0
|
$data->{ $field } = URI->new( $str ); |
3091
|
|
|
|
|
|
|
} |
3092
|
|
|
|
|
|
|
elsif( defined( $str ) ) |
3093
|
|
|
|
|
|
|
{ |
3094
|
0
|
|
|
|
|
0
|
return( $self->error( "URI value provided '$str' does not look like an URI, so I do not know what to do with it." ) ); |
3095
|
|
|
|
|
|
|
} |
3096
|
|
|
|
|
|
|
else |
3097
|
|
|
|
|
|
|
{ |
3098
|
0
|
|
|
|
|
0
|
$data->{ $field } = undef(); |
3099
|
|
|
|
|
|
|
} |
3100
|
|
|
|
|
|
|
} |
3101
|
0
|
|
|
|
|
0
|
return( $data->{ $field } ); |
3102
|
|
|
|
|
|
|
} |
3103
|
|
|
|
|
|
|
|
3104
|
1
|
|
33
|
1
|
|
167
|
sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); } |
3105
|
|
|
|
|
|
|
|
3106
|
|
|
|
|
|
|
sub __dbh |
3107
|
|
|
|
|
|
|
{ |
3108
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
3109
|
0
|
|
0
|
|
|
0
|
my $class = ref( $self ) || $self; |
3110
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
3111
|
0
|
0
|
|
|
|
0
|
if( !$this->{ '__dbh' } ) |
3112
|
|
|
|
|
|
|
{ |
3113
|
0
|
0
|
|
|
|
0
|
return( '' ) if( !${ "$class\::DB_DSN" } ); |
|
0
|
|
|
|
|
0
|
|
3114
|
0
|
|
|
|
|
0
|
require DBI; |
3115
|
|
|
|
|
|
|
## Connecting to database |
3116
|
0
|
|
|
|
|
0
|
my $db_opt = {}; |
3117
|
0
|
0
|
|
|
|
0
|
$db_opt->{RaiseError} = ${ "$class\::DB_RAISE_ERROR" } if( length( ${ "$class\::DB_RAISE_ERROR" } ) ); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
3118
|
0
|
0
|
|
|
|
0
|
$db_opt->{AutoCommit} = ${ "$class\::DB_AUTO_COMMIT" } if( length( ${ "$class\::DB_AUTO_COMMIT" } ) ); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
3119
|
0
|
0
|
|
|
|
0
|
$db_opt->{PrintError} = ${ "$class\::DB_PRINT_ERROR" } if( length( ${ "$class\::DB_PRINT_ERROR" } ) ); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
3120
|
0
|
0
|
|
|
|
0
|
$db_opt->{ShowErrorStatement} = ${ "$class\::DB_SHOW_ERROR_STATEMENT" } if( length( ${ "$class\::DB_SHOW_ERROR_STATEMENT" } ) ); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
3121
|
0
|
0
|
|
|
|
0
|
$db_opt->{client_encoding} = ${ "$class\::DB_CLIENT_ENCODING" } if( length( ${ "$class\::DB_CLIENT_ENCODING" } ) ); |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
3122
|
|
|
|
|
|
|
my $dbh = DBI->connect_cached( ${ "$class\::DB_DSN" } ) || |
3123
|
0
|
|
0
|
|
|
0
|
die( "Unable to connect to sql database with dsn '", ${ "$class\::DB_DSN" }, "'\n" ); |
3124
|
0
|
0
|
|
|
|
0
|
$dbh->{pg_server_prepare} = 1 if( ${ "$class\::DB_SERVER_PREPARE" } ); |
|
0
|
|
|
|
|
0
|
|
3125
|
0
|
|
|
|
|
0
|
$this->{ '__dbh' } = $dbh; |
3126
|
|
|
|
|
|
|
} |
3127
|
0
|
|
|
|
|
0
|
return( $this->{ '__dbh' } ); |
3128
|
|
|
|
|
|
|
} |
3129
|
|
|
|
|
|
|
|
3130
|
|
|
|
|
|
|
sub DEBUG |
3131
|
|
|
|
|
|
|
{ |
3132
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
3133
|
0
|
|
0
|
|
|
0
|
my $pkg = ref( $self ) || $self; |
3134
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
3135
|
0
|
|
|
|
|
0
|
return( ${ $pkg . '::DEBUG' } ); |
|
0
|
|
|
|
|
0
|
|
3136
|
|
|
|
|
|
|
} |
3137
|
|
|
|
|
|
|
|
3138
|
|
|
|
|
|
|
sub VERBOSE |
3139
|
|
|
|
|
|
|
{ |
3140
|
0
|
|
|
0
|
1
|
0
|
my $self = shift( @_ ); |
3141
|
0
|
|
0
|
|
|
0
|
my $pkg = ref( $self ) || $self; |
3142
|
0
|
|
|
|
|
0
|
my $this = $self->_obj2h; |
3143
|
0
|
|
|
|
|
0
|
return( ${ $pkg . '::VERBOSE' } ); |
|
0
|
|
|
|
|
0
|
|
3144
|
|
|
|
|
|
|
} |
3145
|
|
|
|
|
|
|
|
3146
|
|
|
|
|
|
|
AUTOLOAD |
3147
|
|
|
|
|
|
|
{ |
3148
|
0
|
|
|
0
|
|
0
|
my $self; |
3149
|
|
|
|
|
|
|
# $self = shift( @_ ) if( ref( $_[ 0 ] ) && index( ref( $_[ 0 ] ), 'Module::' ) != -1 ); |
3150
|
0
|
0
|
0
|
|
|
0
|
$self = shift( @_ ) if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic' ) ); |
3151
|
0
|
|
|
|
|
0
|
my( $class, $meth ); |
3152
|
0
|
|
0
|
|
|
0
|
$class = ref( $self ) || $self; |
3153
|
|
|
|
|
|
|
## Leave this commented out as we need it a little bit lower |
3154
|
0
|
|
|
|
|
0
|
my( $pkg, $file, $line ) = caller(); |
3155
|
0
|
|
|
|
|
0
|
my $sub = ( caller( 1 ) )[ 3 ]; |
3156
|
6
|
|
|
6
|
|
63
|
no overloading; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
2351
|
|
3157
|
0
|
0
|
|
|
|
0
|
if( $sub eq 'Module::Generic::AUTOLOAD' ) |
3158
|
|
|
|
|
|
|
{ |
3159
|
0
|
|
|
|
|
0
|
my $mesg = "Module::Generic::AUTOLOAD (called at line '$line') is looping for autoloadable method '$AUTOLOAD' and args '" . join( "', '", @_ ) . "'."; |
3160
|
0
|
0
|
|
|
|
0
|
if( $MOD_PERL ) |
3161
|
|
|
|
|
|
|
{ |
3162
|
0
|
|
|
|
|
0
|
my $r = Apache2::RequestUtil->request; |
3163
|
0
|
|
|
|
|
0
|
$r->log_error( $mesg ); |
3164
|
|
|
|
|
|
|
} |
3165
|
|
|
|
|
|
|
else |
3166
|
|
|
|
|
|
|
{ |
3167
|
0
|
|
|
|
|
0
|
print( $err $mesg, "\n" ); |
3168
|
|
|
|
|
|
|
} |
3169
|
0
|
|
|
|
|
0
|
exit( 0 ); |
3170
|
|
|
|
|
|
|
} |
3171
|
0
|
|
|
|
|
0
|
$meth = $AUTOLOAD; |
3172
|
0
|
0
|
|
|
|
0
|
if( CORE::index( $meth, '::' ) != -1 ) |
3173
|
|
|
|
|
|
|
{ |
3174
|
0
|
|
|
|
|
0
|
my $idx = rindex( $meth, '::' ); |
3175
|
0
|
|
|
|
|
0
|
$class = substr( $meth, 0, $idx ); |
3176
|
0
|
|
|
|
|
0
|
$meth = substr( $meth, $idx + 2 ); |
3177
|
|
|
|
|
|
|
} |
3178
|
|
|
|
|
|
|
|
3179
|
0
|
0
|
0
|
|
|
0
|
if( $self && $self->can( 'autoload' ) ) |
3180
|
|
|
|
|
|
|
{ |
3181
|
0
|
0
|
|
|
|
0
|
if( my $code = $self->autoload( $meth ) ) |
3182
|
|
|
|
|
|
|
{ |
3183
|
0
|
0
|
|
|
|
0
|
return( $code->( $self ) ) if( $code ); |
3184
|
|
|
|
|
|
|
} |
3185
|
|
|
|
|
|
|
} |
3186
|
|
|
|
|
|
|
|
3187
|
0
|
|
|
|
|
0
|
$meth = lc( $meth ); |
3188
|
0
|
|
|
|
|
0
|
my $this; |
3189
|
0
|
0
|
|
|
|
0
|
$this = $self->_obj2h if( defined( $self ) ); |
3190
|
0
|
|
|
|
|
0
|
my $data; |
3191
|
0
|
0
|
|
|
|
0
|
if( $this ) |
3192
|
|
|
|
|
|
|
{ |
3193
|
0
|
0
|
|
|
|
0
|
$data = $this->{_data_repo} ? $this->{ $this->{_data_repo} } : $this; |
3194
|
|
|
|
|
|
|
} |
3195
|
|
|
|
|
|
|
## CORE::print( STDERR "Storing '$meth' with value ", join( ', ', @_ ), "\n" ); |
3196
|
0
|
0
|
0
|
|
|
0
|
if( $data && CORE::exists( $data->{ $meth } ) ) |
|
|
0
|
0
|
|
|
|
|
|
|
0
|
0
|
|
|
|
|
3197
|
|
|
|
|
|
|
{ |
3198
|
0
|
0
|
|
|
|
0
|
if( @_ ) |
3199
|
|
|
|
|
|
|
{ |
3200
|
0
|
0
|
|
|
|
0
|
my $val = ( @_ == 1 ) ? shift( @_ ) : [ @_ ]; |
3201
|
0
|
|
|
|
|
0
|
$data->{ $meth } = $val; |
3202
|
|
|
|
|
|
|
} |
3203
|
0
|
0
|
|
|
|
0
|
if( wantarray() ) |
3204
|
|
|
|
|
|
|
{ |
3205
|
0
|
0
|
|
|
|
0
|
if( ref( $data->{ $meth } ) eq 'ARRAY' ) |
|
|
0
|
|
|
|
|
|
3206
|
|
|
|
|
|
|
{ |
3207
|
0
|
|
|
|
|
0
|
return( @{ $data->{ $meth } } ); |
|
0
|
|
|
|
|
0
|
|
3208
|
|
|
|
|
|
|
} |
3209
|
|
|
|
|
|
|
elsif( ref( $data->{ $meth } ) eq 'HASH' ) |
3210
|
|
|
|
|
|
|
{ |
3211
|
0
|
|
|
|
|
0
|
return( %{ $data->{ $meth } } ); |
|
0
|
|
|
|
|
0
|
|
3212
|
|
|
|
|
|
|
} |
3213
|
|
|
|
|
|
|
else |
3214
|
|
|
|
|
|
|
{ |
3215
|
0
|
|
|
|
|
0
|
return( ( $data->{ $meth } ) ); |
3216
|
|
|
|
|
|
|
} |
3217
|
|
|
|
|
|
|
} |
3218
|
|
|
|
|
|
|
else |
3219
|
|
|
|
|
|
|
{ |
3220
|
0
|
|
|
|
|
0
|
return( $data->{ $meth } ); |
3221
|
|
|
|
|
|
|
} |
3222
|
|
|
|
|
|
|
} |
3223
|
|
|
|
|
|
|
## Because, if it does not exist in the caller's package, |
3224
|
|
|
|
|
|
|
## calling the method will get us here infinitly, |
3225
|
|
|
|
|
|
|
## since UNIVERSAL::can will somehow return true even if it does not exist |
3226
|
0
|
|
|
|
|
0
|
elsif( $self && $self->can( $meth ) && defined( &{ "$class\::$meth" } ) ) |
3227
|
|
|
|
|
|
|
{ |
3228
|
0
|
|
|
|
|
0
|
return( $self->$meth( @_ ) ); |
3229
|
|
|
|
|
|
|
} |
3230
|
|
|
|
|
|
|
elsif( defined( &$meth ) ) |
3231
|
|
|
|
|
|
|
{ |
3232
|
6
|
|
|
6
|
|
53
|
no strict 'refs'; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
5152
|
|
3233
|
0
|
|
|
|
|
0
|
*$meth = \&$meth; |
3234
|
0
|
|
|
|
|
0
|
return( &$meth( @_ ) ); |
3235
|
|
|
|
|
|
|
} |
3236
|
|
|
|
|
|
|
else |
3237
|
|
|
|
|
|
|
{ |
3238
|
0
|
|
|
|
|
0
|
my $sub = $AUTOLOAD; |
3239
|
0
|
|
|
|
|
0
|
my( $pkg, $func ) = ( $sub =~ /(.*)::([^:]+)$/ ); |
3240
|
0
|
|
|
|
|
0
|
my $mesg = "Module::Generic::AUTOLOAD(): Searching for routine '$func' from package '$pkg'."; |
3241
|
0
|
0
|
|
|
|
0
|
if( $MOD_PERL ) |
3242
|
|
|
|
|
|
|
{ |
3243
|
0
|
|
|
|
|
0
|
my $r = Apache2::RequestUtil->request; |
3244
|
0
|
|
|
|
|
0
|
$r->log_error( $mesg ); |
3245
|
|
|
|
|
|
|
} |
3246
|
|
|
|
|
|
|
else |
3247
|
|
|
|
|
|
|
{ |
3248
|
0
|
0
|
|
|
|
0
|
print( STDERR $mesg . "\n" ) if( $DEBUG ); |
3249
|
|
|
|
|
|
|
} |
3250
|
0
|
|
|
|
|
0
|
$pkg =~ s/::/\//g; |
3251
|
0
|
0
|
|
|
|
0
|
if( defined( $filename = $INC{ "$pkg.pm" } ) ) |
3252
|
|
|
|
|
|
|
{ |
3253
|
0
|
|
|
|
|
0
|
$filename =~ s/^(.*)$pkg\.pm\z/$1auto\/$pkg\/$func.al/s; |
3254
|
|
|
|
|
|
|
## print( STDERR "Found possible autoloadable file '$filename'.\n" ); |
3255
|
0
|
0
|
|
|
|
0
|
if( -r( $filename ) ) |
3256
|
|
|
|
|
|
|
{ |
3257
|
0
|
0
|
|
|
|
0
|
unless( $filename =~ m|^/|s ) |
3258
|
|
|
|
|
|
|
{ |
3259
|
0
|
|
|
|
|
0
|
$filename = "./$filename"; |
3260
|
|
|
|
|
|
|
} |
3261
|
|
|
|
|
|
|
} |
3262
|
|
|
|
|
|
|
else |
3263
|
|
|
|
|
|
|
{ |
3264
|
0
|
|
|
|
|
0
|
$filename = undef(); |
3265
|
|
|
|
|
|
|
} |
3266
|
|
|
|
|
|
|
} |
3267
|
0
|
0
|
|
|
|
0
|
if( !defined( $filename ) ) |
3268
|
|
|
|
|
|
|
{ |
3269
|
0
|
|
|
|
|
0
|
$filename = "auto/$sub.al"; |
3270
|
0
|
|
|
|
|
0
|
$filename =~ s/::/\//g; |
3271
|
|
|
|
|
|
|
} |
3272
|
0
|
|
|
|
|
0
|
my $save = $@; |
3273
|
|
|
|
|
|
|
eval |
3274
|
0
|
|
|
|
|
0
|
{ |
3275
|
0
|
|
|
0
|
|
0
|
local $SIG{ '__DIE__' } = sub{ }; |
3276
|
0
|
|
|
0
|
|
0
|
local $SIG{ '__WARN__' } = sub{ }; |
3277
|
0
|
|
|
|
|
0
|
require $filename; |
3278
|
|
|
|
|
|
|
}; |
3279
|
0
|
0
|
|
|
|
0
|
if( $@ ) |
3280
|
|
|
|
|
|
|
{ |
3281
|
0
|
0
|
|
|
|
0
|
if( substr( $sub, -9 ) eq '::DESTROY' ) |
3282
|
|
|
|
|
|
|
{ |
3283
|
0
|
|
|
0
|
|
0
|
*$sub = sub {}; |
3284
|
|
|
|
|
|
|
} |
3285
|
|
|
|
|
|
|
else |
3286
|
|
|
|
|
|
|
{ |
3287
|
|
|
|
|
|
|
# The load might just have failed because the filename was too |
3288
|
|
|
|
|
|
|
# long for some old SVR3 systems which treat long names as errors. |
3289
|
|
|
|
|
|
|
# If we can succesfully truncate a long name then it's worth a go. |
3290
|
|
|
|
|
|
|
# There is a slight risk that we could pick up the wrong file here |
3291
|
|
|
|
|
|
|
# but autosplit should have warned about that when splitting. |
3292
|
0
|
0
|
|
|
|
0
|
if( $filename =~ s/(\w{12,})\.al$/substr( $1, 0, 11 ) . ".al"/e ) |
|
0
|
|
|
|
|
0
|
|
3293
|
|
|
|
|
|
|
{ |
3294
|
|
|
|
|
|
|
eval |
3295
|
0
|
|
|
|
|
0
|
{ |
3296
|
0
|
|
|
0
|
|
0
|
local $SIG{ '__DIE__' } = sub{ }; |
3297
|
0
|
|
|
0
|
|
0
|
local $SIG{ '__WARN__' } = sub{ }; |
3298
|
0
|
|
|
|
|
0
|
require $filename |
3299
|
|
|
|
|
|
|
}; |
3300
|
|
|
|
|
|
|
} |
3301
|
0
|
0
|
|
|
|
0
|
if( $@ ) |
3302
|
|
|
|
|
|
|
{ |
3303
|
|
|
|
|
|
|
#$@ =~ s/ at .*\n//; |
3304
|
|
|
|
|
|
|
#my $error = $@; |
3305
|
|
|
|
|
|
|
#CORE::die( $error ); |
3306
|
|
|
|
|
|
|
## die( "Method $meth() is not defined in class $class and not autoloadable.\n" ); |
3307
|
|
|
|
|
|
|
## print( $err "EXTRA_AUTOLOAD is ", defined( &{ "${class}::EXTRA_AUTOLOAD" } ) ? "defined" : "not defined", " in package '$class'.\n" ); |
3308
|
|
|
|
|
|
|
## if( $self && defined( &{ "${class}::EXTRA_AUTOLOAD" } ) ) |
3309
|
|
|
|
|
|
|
## Look up in our caller's @ISA to see if there is any package that has this special |
3310
|
|
|
|
|
|
|
## EXTRA_AUTOLOAD() sub routine |
3311
|
0
|
|
|
|
|
0
|
my $sub_ref = ''; |
3312
|
0
|
0
|
|
|
|
0
|
die( "EXTRA_AUTOLOAD: ", join( "', '", @_ ), "\n" ) if( $func eq 'EXTRA_AUTOLOAD' ); |
3313
|
0
|
0
|
0
|
|
|
0
|
if( $self && $func ne 'EXTRA_AUTOLOAD' && ( $sub_ref = $self->will( 'EXTRA_AUTOLOAD' ) ) ) |
|
|
|
0
|
|
|
|
|
3314
|
|
|
|
|
|
|
{ |
3315
|
|
|
|
|
|
|
## return( &{ "${class}::EXTRA_AUTOLOAD" }( $self, $meth ) ); |
3316
|
|
|
|
|
|
|
## return( $self->EXTRA_AUTOLOAD( $AUTOLOAD, @_ ) ); |
3317
|
0
|
|
|
|
|
0
|
return( $sub_ref->( $self, $AUTOLOAD, @_ ) ); |
3318
|
|
|
|
|
|
|
} |
3319
|
|
|
|
|
|
|
else |
3320
|
|
|
|
|
|
|
{ |
3321
|
0
|
|
|
|
|
0
|
my $keys = CORE::join( ',', keys( %$data ) ); |
3322
|
0
|
|
|
|
|
0
|
my $msg = "Method $func() is not defined in class $class and not autoloadable in package $pkg in file $file at line $line.\n"; |
3323
|
0
|
|
|
|
|
0
|
$msg .= "There are actually the following fields in the object '$self': '$keys'\n"; |
3324
|
0
|
|
|
|
|
0
|
die( $msg ); |
3325
|
|
|
|
|
|
|
} |
3326
|
|
|
|
|
|
|
} |
3327
|
|
|
|
|
|
|
} |
3328
|
|
|
|
|
|
|
} |
3329
|
0
|
|
|
|
|
0
|
$@ = $save; |
3330
|
0
|
0
|
|
|
|
0
|
if( $DEBUG ) |
3331
|
|
|
|
|
|
|
{ |
3332
|
0
|
|
|
|
|
0
|
my $mesg = "unshifting '$self' to args for sub '$sub'."; |
3333
|
0
|
0
|
|
|
|
0
|
if( $MOD_PERL ) |
3334
|
|
|
|
|
|
|
{ |
3335
|
0
|
|
|
|
|
0
|
my $r = Apache2::RequestUtil->request; |
3336
|
0
|
|
|
|
|
0
|
$r->log_error( $mesg ); |
3337
|
|
|
|
|
|
|
} |
3338
|
|
|
|
|
|
|
else |
3339
|
|
|
|
|
|
|
{ |
3340
|
0
|
|
|
|
|
0
|
print( $err "$mesg\n" ); |
3341
|
|
|
|
|
|
|
} |
3342
|
|
|
|
|
|
|
} |
3343
|
0
|
0
|
|
|
|
0
|
unshift( @_, $self ) if( $self ); |
3344
|
|
|
|
|
|
|
#use overloading; |
3345
|
0
|
|
|
|
|
0
|
goto &$sub; |
3346
|
|
|
|
|
|
|
## die( "Method $meth() is not defined in class $class and not autoloadable.\n" ); |
3347
|
|
|
|
|
|
|
## my $mesg = "Method $meth() is not defined in class $class and not autoloadable."; |
3348
|
|
|
|
|
|
|
## $self->{ 'fatal' } ? die( $mesg ) : return( $self->error( $mesg ) ); |
3349
|
|
|
|
|
|
|
} |
3350
|
|
|
|
|
|
|
}; |
3351
|
|
|
|
|
|
|
|
3352
|
|
|
|
|
|
|
DESTROY |
3353
|
|
|
|
0
|
|
|
{ |
3354
|
|
|
|
|
|
|
## Do nothing |
3355
|
|
|
|
|
|
|
}; |
3356
|
|
|
|
|
|
|
|
3357
|
|
|
|
|
|
|
package Module::Generic::Exception; |
3358
|
|
|
|
|
|
|
BEGIN |
3359
|
|
|
|
|
|
|
{ |
3360
|
6
|
|
|
6
|
|
55
|
use strict; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
181
|
|
3361
|
6
|
|
|
6
|
|
35
|
use parent qw( Module::Generic ); |
|
6
|
|
|
|
|
60
|
|
|
6
|
|
|
|
|
60
|
|
3362
|
6
|
|
|
6
|
|
514
|
use Scalar::Util; |
|
6
|
|
|
|
|
18
|
|
|
6
|
|
|
|
|
429
|
|
3363
|
6
|
|
|
6
|
|
62
|
use Devel::StackTrace; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
527
|
|
3364
|
|
|
|
|
|
|
use overload ('""' => 'as_string', |
3365
|
0
|
|
|
0
|
|
0
|
'==' => sub { _obj_eq(@_) }, |
3366
|
0
|
|
|
0
|
|
0
|
'!=' => sub { !_obj_eq(@_) }, |
3367
|
6
|
|
|
|
|
79
|
fallback => 1, |
3368
|
6
|
|
|
6
|
|
45
|
); |
|
6
|
|
|
|
|
14
|
|
3369
|
6
|
|
|
6
|
|
4077
|
our( $VERSION ) = '0.1.0'; |
3370
|
|
|
|
|
|
|
}; |
3371
|
|
|
|
|
|
|
|
3372
|
|
|
|
|
|
|
sub init |
3373
|
|
|
|
|
|
|
{ |
3374
|
1
|
|
|
1
|
|
4
|
my $self = shift( @_ ); |
3375
|
|
|
|
|
|
|
# require Data::Dumper::Concise; |
3376
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::init() Got here with args: ", Data::Dumper::Concise::Dumper( \@_ ), "\n" ); |
3377
|
1
|
|
|
|
|
95
|
$self->{code} = ''; |
3378
|
1
|
|
|
|
|
5
|
$self->{type} = ''; |
3379
|
1
|
|
|
|
|
3
|
$self->{file} = ''; |
3380
|
1
|
|
|
|
|
4
|
$self->{line} = ''; |
3381
|
1
|
|
|
|
|
4
|
$self->{message} = ''; |
3382
|
1
|
|
|
|
|
3
|
$self->{package} = ''; |
3383
|
1
|
|
|
|
|
3
|
$self->{retry_after} = ''; |
3384
|
1
|
|
|
|
|
4
|
$self->{subroutine} = ''; |
3385
|
1
|
|
|
|
|
4
|
my $args = {}; |
3386
|
1
|
50
|
|
|
|
5
|
if( @_ ) |
3387
|
|
|
|
|
|
|
{ |
3388
|
1
|
50
|
33
|
|
|
11
|
if( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'Module::Generic::Exception' ) ) |
|
|
50
|
|
|
|
|
|
3389
|
|
|
|
|
|
|
{ |
3390
|
0
|
|
|
|
|
0
|
$args->{object} = shift( @_ ); |
3391
|
|
|
|
|
|
|
} |
3392
|
|
|
|
|
|
|
elsif( ref( $_[0] ) eq 'HASH' ) |
3393
|
|
|
|
|
|
|
{ |
3394
|
1
|
|
|
|
|
5
|
$args = shift( @_ ); |
3395
|
|
|
|
|
|
|
} |
3396
|
|
|
|
|
|
|
else |
3397
|
|
|
|
|
|
|
{ |
3398
|
0
|
0
|
|
|
|
0
|
$args->{message} = join( '', map( ref( $_ ) eq 'CODE' ? $_->() : $_, @_ ) ); |
3399
|
|
|
|
|
|
|
} |
3400
|
|
|
|
|
|
|
} |
3401
|
|
|
|
|
|
|
# $self->SUPER::init( @_ ); |
3402
|
1
|
|
50
|
|
|
3
|
my $skip_frame = $args->{skip_frames} || 0; |
3403
|
|
|
|
|
|
|
## Skip one frame to exclude us |
3404
|
1
|
|
|
|
|
4
|
$skip_frame++; |
3405
|
1
|
|
|
|
|
12
|
my $trace = Devel::StackTrace->new( skip_frames => $skip_frame, indent => 1 ); |
3406
|
1
|
|
|
|
|
288
|
my $frame = $trace->next_frame; |
3407
|
1
|
|
|
|
|
393
|
my $frame2 = $trace->next_frame; |
3408
|
1
|
|
|
|
|
20
|
$trace->reset_pointer; |
3409
|
1
|
50
|
33
|
|
|
12
|
if( ref( $args->{object} ) && Scalar::Util::blessed( $args->{object} ) && $args->{object}->isa( 'Module::Generic::Exception' ) ) |
|
|
|
33
|
|
|
|
|
3410
|
|
|
|
|
|
|
{ |
3411
|
0
|
|
|
|
|
0
|
my $o = $args->{object}; |
3412
|
0
|
|
|
|
|
0
|
$self->{message} = $o->message; |
3413
|
0
|
|
|
|
|
0
|
$self->{code} = $o->code; |
3414
|
0
|
|
|
|
|
0
|
$self->{type} = $o->type; |
3415
|
0
|
|
|
|
|
0
|
$self->{retry_after} = $o->retry_after; |
3416
|
|
|
|
|
|
|
} |
3417
|
|
|
|
|
|
|
else |
3418
|
|
|
|
|
|
|
{ |
3419
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::init() Got here with args: ", Data::Dumper::Concise::Dumper( $args ), "\n" ); |
3420
|
1
|
|
50
|
|
|
5
|
$self->{message} = $args->{message} || ''; |
3421
|
1
|
50
|
|
|
|
4
|
$self->{code} = $args->{code} if( exists( $args->{code} ) ); |
3422
|
1
|
50
|
|
|
|
5
|
$self->{type} = $args->{type} if( exists( $args->{type} ) ); |
3423
|
1
|
50
|
|
|
|
5
|
$self->{retry_after} = $args->{retry_after} if( exists( $args->{retry_after} ) ); |
3424
|
|
|
|
|
|
|
## I do not want to alter the original hash reference, which may adversely affect the calling code if they depend on its content for further execution for example. |
3425
|
1
|
|
|
|
|
3
|
my $copy = {}; |
3426
|
1
|
|
|
|
|
6
|
%$copy = %$args; |
3427
|
1
|
|
|
|
|
5
|
CORE::delete( @$copy{ qw( message code type retry_after skip_frames ) } ); |
3428
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::init() Following non-standard keys to set up: '", join( "', '", sort( keys( %$copy ) ) ), "'\n" ); |
3429
|
|
|
|
|
|
|
## Do we have some non-standard parameters? |
3430
|
1
|
|
|
|
|
5
|
foreach my $p ( keys( %$copy ) ) |
3431
|
|
|
|
|
|
|
{ |
3432
|
0
|
|
|
|
|
0
|
my $p2 = $p; |
3433
|
0
|
|
|
|
|
0
|
$p2 =~ tr/-/_/; |
3434
|
0
|
|
|
|
|
0
|
$p2 =~ s/[^a-zA-Z0-9\_]+//g; |
3435
|
0
|
|
|
|
|
0
|
$p2 =~ s/^\d+//g; |
3436
|
0
|
|
|
|
|
0
|
$self->$p2( $copy->{ $p } ); |
3437
|
|
|
|
|
|
|
} |
3438
|
|
|
|
|
|
|
} |
3439
|
1
|
|
|
|
|
6
|
$self->{file} = $frame->filename; |
3440
|
1
|
|
|
|
|
9
|
$self->{line} = $frame->line; |
3441
|
|
|
|
|
|
|
## The caller sub routine ( caller( n ) )[3] returns the sub called by our caller instead of the sub that called our caller, so we go one frame back to get it |
3442
|
1
|
|
|
|
|
10
|
$self->{subroutine} = $frame2->subroutine; |
3443
|
1
|
|
|
|
|
9
|
$self->{package} = $frame->package; |
3444
|
1
|
|
|
|
|
7
|
$self->{trace} = $trace; |
3445
|
1
|
|
|
|
|
4
|
return( $self ); |
3446
|
|
|
|
|
|
|
} |
3447
|
|
|
|
|
|
|
|
3448
|
|
|
|
|
|
|
#sub as_string { return( $_[0]->{message} ); } |
3449
|
|
|
|
|
|
|
## This is important as stringification is called by die, so as per the manual page, we need to end with new line |
3450
|
|
|
|
|
|
|
## And will add the stack trace |
3451
|
|
|
|
|
|
|
sub as_string |
3452
|
|
|
|
|
|
|
{ |
3453
|
6
|
|
|
6
|
|
58
|
no overloading; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
2641
|
|
3454
|
1
|
|
|
1
|
|
4
|
my $self = shift( @_ ); |
3455
|
1
|
|
|
|
|
4
|
my $str = $self->message; |
3456
|
1
|
|
|
|
|
4
|
$str =~ s/\r?\n$//g; |
3457
|
1
|
|
|
|
|
5
|
$str .= sprintf( " within package %s at line %d in file %s\n%s", $self->package, $self->line, $self->file, $self->trace->as_string ); |
3458
|
1
|
|
|
|
|
334
|
return( $str ); |
3459
|
|
|
|
|
|
|
} |
3460
|
|
|
|
|
|
|
|
3461
|
|
|
|
|
|
|
## if( Module::Generic::Exception->caught( $e ) ) { # do something, it's ours } |
3462
|
|
|
|
|
|
|
sub caught |
3463
|
|
|
|
|
|
|
{ |
3464
|
0
|
|
|
0
|
|
0
|
my( $class, $e ) = @_; |
3465
|
0
|
0
|
|
|
|
0
|
return if( ref( $class ) ); |
3466
|
0
|
0
|
0
|
|
|
0
|
return unless( Scalar::Util::blessed( $e ) && $e->isa( $class ) ); |
3467
|
0
|
|
|
|
|
0
|
return( $e ); |
3468
|
|
|
|
|
|
|
} |
3469
|
|
|
|
|
|
|
|
3470
|
0
|
|
|
0
|
|
0
|
sub code { return( shift->_set_get_scalar( 'code', @_ ) ); } |
3471
|
|
|
|
|
|
|
|
3472
|
1
|
|
|
1
|
|
24
|
sub file { return( shift->_set_get_scalar( 'file', @_ ) ); } |
3473
|
|
|
|
|
|
|
|
3474
|
1
|
|
|
1
|
|
3
|
sub line { return( shift->_set_get_scalar( 'line', @_ ) ); } |
3475
|
|
|
|
|
|
|
|
3476
|
1
|
|
|
1
|
|
8
|
sub message { return( shift->_set_get_scalar( 'message', @_ ) ); } |
3477
|
|
|
|
|
|
|
|
3478
|
1
|
|
|
1
|
|
4
|
sub package { return( shift->_set_get_scalar( 'package', @_ ) ); } |
3479
|
|
|
|
|
|
|
|
3480
|
|
|
|
|
|
|
sub rethrow |
3481
|
|
|
|
|
|
|
{ |
3482
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
3483
|
0
|
0
|
|
|
|
0
|
return if( !Scalar::Util::blessed( $self ) ); |
3484
|
0
|
|
|
|
|
0
|
die( $self ); |
3485
|
|
|
|
|
|
|
} |
3486
|
|
|
|
|
|
|
|
3487
|
0
|
|
|
0
|
|
0
|
sub retry_after { return( shift->_set_get_scalar( 'retry_after', @_ ) ); } |
3488
|
|
|
|
|
|
|
|
3489
|
0
|
|
|
0
|
|
0
|
sub subroutine { return( shift->_set_get_scalar( 'subroutine', @_ ) ); } |
3490
|
|
|
|
|
|
|
|
3491
|
|
|
|
|
|
|
sub throw |
3492
|
|
|
|
|
|
|
{ |
3493
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
3494
|
0
|
|
|
|
|
0
|
my $msg = shift( @_ ); |
3495
|
0
|
|
|
|
|
0
|
my $e = $self->new({ |
3496
|
|
|
|
|
|
|
skip_frames => 1, |
3497
|
|
|
|
|
|
|
message => $msg, |
3498
|
|
|
|
|
|
|
}); |
3499
|
0
|
|
|
|
|
0
|
die( $e ); |
3500
|
|
|
|
|
|
|
} |
3501
|
|
|
|
|
|
|
|
3502
|
|
|
|
|
|
|
## Devel::StackTrace has a stringification overloaded so users can use the object to get more information or simply use it as a string to get the stack trace equivalent of doing $trace->as_string |
3503
|
1
|
|
|
1
|
|
7
|
sub trace { return( shift->_set_get_object( 'trace', 'Devel::StackTrace', @_ ) ); } |
3504
|
|
|
|
|
|
|
|
3505
|
0
|
|
|
0
|
|
0
|
sub type { return( shift->_set_get_scalar( 'type', @_ ) ); } |
3506
|
|
|
|
|
|
|
|
3507
|
|
|
|
|
|
|
sub _obj_eq |
3508
|
|
|
|
|
|
|
{ |
3509
|
|
|
|
|
|
|
##return overload::StrVal( $_[0] ) eq overload::StrVal( $_[1] ); |
3510
|
6
|
|
|
6
|
|
45
|
no overloading; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
1120
|
|
3511
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
3512
|
0
|
|
|
|
|
0
|
my $other = shift( @_ ); |
3513
|
0
|
|
|
|
|
0
|
my $me; |
3514
|
0
|
0
|
0
|
|
|
0
|
if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Exception' ) ) |
|
|
0
|
|
|
|
|
|
3515
|
|
|
|
|
|
|
{ |
3516
|
0
|
0
|
0
|
|
|
0
|
if( $self->message eq $other->message && |
|
|
|
0
|
|
|
|
|
3517
|
|
|
|
|
|
|
$self->file eq $other->file && |
3518
|
|
|
|
|
|
|
$self->line == $other->line ) |
3519
|
|
|
|
|
|
|
{ |
3520
|
0
|
|
|
|
|
0
|
return( 1 ); |
3521
|
|
|
|
|
|
|
} |
3522
|
|
|
|
|
|
|
else |
3523
|
|
|
|
|
|
|
{ |
3524
|
0
|
|
|
|
|
0
|
return( 0 ); |
3525
|
|
|
|
|
|
|
} |
3526
|
|
|
|
|
|
|
} |
3527
|
|
|
|
|
|
|
## Compare error message |
3528
|
|
|
|
|
|
|
elsif( !ref( $other ) ) |
3529
|
|
|
|
|
|
|
{ |
3530
|
0
|
|
|
|
|
0
|
my $me = $self->message; |
3531
|
0
|
|
|
|
|
0
|
return( $me eq $other ); |
3532
|
|
|
|
|
|
|
} |
3533
|
|
|
|
|
|
|
## Otherwise some reference data to which we cannot compare |
3534
|
0
|
|
|
|
|
0
|
return( 0 ) ; |
3535
|
|
|
|
|
|
|
} |
3536
|
|
|
|
|
|
|
|
3537
|
|
|
|
|
|
|
AUTOLOAD |
3538
|
|
|
|
|
|
|
{ |
3539
|
0
|
|
|
0
|
|
0
|
my( $method ) = our $AUTOLOAD =~ /([^:]+)$/; |
3540
|
|
|
|
|
|
|
# my( $class, $method ) = our $AUTOLOAD =~ /^(.*?)::([^\:]+)$/; |
3541
|
6
|
|
|
6
|
|
44
|
no overloading; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
830
|
|
3542
|
0
|
|
|
|
|
0
|
my $self = shift( @_ ); |
3543
|
0
|
|
0
|
|
|
0
|
my $class = ref( $self ) || $self; |
3544
|
0
|
|
|
|
|
0
|
my $code; |
3545
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::$method(): Called with value '$_[0]'\n" ); |
3546
|
0
|
0
|
|
|
|
0
|
if( $code = $self->can( $method ) ) |
3547
|
|
|
|
|
|
|
{ |
3548
|
0
|
|
|
|
|
0
|
return( $code->( @_ ) ); |
3549
|
|
|
|
|
|
|
} |
3550
|
|
|
|
|
|
|
## elsif( CORE::exists( $self->{ $method } ) ) |
3551
|
|
|
|
|
|
|
else |
3552
|
|
|
|
|
|
|
{ |
3553
|
0
|
|
|
|
|
0
|
eval( "sub ${class}::${method} { return( shift->_set_get_scalar( '$method', \@_ ) ); }" ); |
3554
|
0
|
0
|
|
|
|
0
|
die( $@ ) if( $@ ); |
3555
|
0
|
|
|
|
|
0
|
return( $self->$method( @_ ) ); |
3556
|
|
|
|
|
|
|
} |
3557
|
|
|
|
|
|
|
}; |
3558
|
|
|
|
|
|
|
|
3559
|
|
|
|
|
|
|
## Purpose of this package is to provide an object that will be invoked in chain without breaking and then return undef at the end |
3560
|
|
|
|
|
|
|
## Normally if a method in the chain returns undef, perl will then complain that the following method in the chain was called on an undefined value. This Null package alleviate this problem. |
3561
|
|
|
|
|
|
|
## This is an original idea from https://stackoverflow.com/users/2766176/brian-d-foy as document in this Stackoverflow thread here: https://stackoverflow.com/a/7068271/4814971 |
3562
|
|
|
|
|
|
|
## And also by user "particle" in this perl monks discussion here: https://www.perlmonks.org/?node_id=265214 |
3563
|
|
|
|
|
|
|
package Module::Generic::Null; |
3564
|
|
|
|
|
|
|
BEGIN |
3565
|
|
|
|
|
|
|
{ |
3566
|
6
|
|
|
6
|
|
41
|
use strict; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
143
|
|
3567
|
6
|
|
|
6
|
|
34
|
use Want; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
819
|
|
3568
|
0
|
|
|
0
|
|
0
|
use overload ('""' => sub{ '' }, |
3569
|
0
|
|
|
0
|
|
0
|
'eq' => sub { _obj_eq(@_) }, |
3570
|
0
|
|
|
0
|
|
0
|
'ne' => sub { !_obj_eq(@_) }, |
3571
|
6
|
|
|
|
|
58
|
fallback => 1, |
3572
|
6
|
|
|
6
|
|
45
|
); |
|
6
|
|
|
|
|
14
|
|
3573
|
6
|
|
|
6
|
|
552
|
use Want; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
336
|
|
3574
|
6
|
|
|
6
|
|
621
|
our( $VERSION ) = '0.2.0'; |
3575
|
|
|
|
|
|
|
}; |
3576
|
|
|
|
|
|
|
|
3577
|
|
|
|
|
|
|
sub new |
3578
|
|
|
|
|
|
|
{ |
3579
|
1444
|
|
|
1444
|
|
2627
|
my $this = shift( @_ ); |
3580
|
1444
|
|
33
|
|
|
4912
|
my $class = ref( $this ) || $this; |
3581
|
1444
|
|
|
|
|
2345
|
my $error_object = shift( @_ ); |
3582
|
1444
|
50
|
33
|
|
|
4568
|
my $hash = ( @_ == 1 && ref( $_[0] ) ? shift( @_ ) : { @_ } ); |
3583
|
1444
|
|
|
|
|
3295
|
$hash->{has_error} = $error_object; |
3584
|
1444
|
|
|
|
|
9490
|
return( bless( $hash => $class ) ); |
3585
|
|
|
|
|
|
|
} |
3586
|
|
|
|
|
|
|
|
3587
|
|
|
|
|
|
|
sub _obj_eq |
3588
|
|
|
|
|
|
|
{ |
3589
|
|
|
|
|
|
|
##return overload::StrVal( $_[0] ) eq overload::StrVal( $_[1] ); |
3590
|
6
|
|
|
6
|
|
39
|
no overloading; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
1235
|
|
3591
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
3592
|
0
|
|
|
|
|
0
|
my $other = shift( @_ ); |
3593
|
0
|
|
|
|
|
0
|
my $me; |
3594
|
0
|
0
|
0
|
|
|
0
|
if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Null' ) ) |
|
|
0
|
|
|
|
|
|
3595
|
|
|
|
|
|
|
{ |
3596
|
0
|
|
|
|
|
0
|
return( $self eq $other ); |
3597
|
|
|
|
|
|
|
} |
3598
|
|
|
|
|
|
|
## Compare error message |
3599
|
|
|
|
|
|
|
elsif( !ref( $other ) ) |
3600
|
|
|
|
|
|
|
{ |
3601
|
0
|
|
|
|
|
0
|
return( '' eq $other ); |
3602
|
|
|
|
|
|
|
} |
3603
|
|
|
|
|
|
|
## Otherwise some reference data to which we cannot compare |
3604
|
0
|
|
|
|
|
0
|
return( 0 ) ; |
3605
|
|
|
|
|
|
|
} |
3606
|
|
|
|
|
|
|
|
3607
|
|
|
|
|
|
|
AUTOLOAD |
3608
|
|
|
|
|
|
|
{ |
3609
|
1444
|
|
|
1444
|
|
10282
|
my( $method ) = our $AUTOLOAD =~ /([^:]+)$/; |
3610
|
|
|
|
|
|
|
# my $debug = $_[0]->{debug}; |
3611
|
|
|
|
|
|
|
# my( $pack, $file, $file ) = caller; |
3612
|
|
|
|
|
|
|
# my $sub = ( caller( 1 ) )[3]; |
3613
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, ": Method $method called in package $pack in file $file at line $line from subroutine $sub (AUTOLOAD = $AUTOLOAD)\n" ) if( $debug ); |
3614
|
|
|
|
|
|
|
## If we are chained, return our null object, so the chain continues to work |
3615
|
1444
|
50
|
|
|
|
3956
|
if( want( 'OBJECT' ) ) |
3616
|
|
|
|
|
|
|
{ |
3617
|
|
|
|
|
|
|
## No, this is NOT a typo. rreturn() is a function of module Want |
3618
|
0
|
|
|
|
|
0
|
rreturn( $_[0] ); |
3619
|
|
|
|
|
|
|
} |
3620
|
|
|
|
|
|
|
## Otherwise, we return undef; Empty return returns undef in scalar context and empty list in list context |
3621
|
1444
|
|
|
|
|
67293
|
return; |
3622
|
|
|
|
|
|
|
}; |
3623
|
|
|
|
|
|
|
|
3624
|
|
|
|
0
|
|
|
DESTROY {}; |
3625
|
|
|
|
|
|
|
|
3626
|
|
|
|
|
|
|
package Module::Generic::Dynamic; |
3627
|
|
|
|
|
|
|
BEGIN |
3628
|
|
|
|
|
|
|
{ |
3629
|
6
|
|
|
6
|
|
58
|
use strict; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
156
|
|
3630
|
6
|
|
|
6
|
|
30
|
use parent qw( Module::Generic ); |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
29
|
|
3631
|
6
|
|
|
6
|
|
350
|
use warnings::register; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
801
|
|
3632
|
6
|
|
|
6
|
|
41
|
use Scalar::Util (); |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
157
|
|
3633
|
|
|
|
|
|
|
# use Class::ISA; |
3634
|
6
|
|
|
6
|
|
5270
|
our( $VERSION ) = '0.1.0'; |
3635
|
|
|
|
|
|
|
}; |
3636
|
|
|
|
|
|
|
|
3637
|
|
|
|
|
|
|
sub new |
3638
|
|
|
|
|
|
|
{ |
3639
|
0
|
|
|
0
|
|
0
|
my $this = shift( @_ ); |
3640
|
0
|
|
0
|
|
|
0
|
my $class = ref( $this ) || $this; |
3641
|
0
|
|
|
|
|
0
|
my $self = bless( {} => $class ); |
3642
|
0
|
|
|
|
|
0
|
my $data = $self->{_data} = {}; |
3643
|
|
|
|
|
|
|
## A Module::Generic object standard parameter |
3644
|
0
|
|
|
|
|
0
|
$self->{_data_repo} = '_data'; |
3645
|
0
|
|
|
|
|
0
|
my $hash = {}; |
3646
|
0
|
0
|
0
|
|
|
0
|
@_ = () if( scalar( @_ ) == 1 && !defined( $_[0] ) ); |
3647
|
0
|
0
|
0
|
|
|
0
|
if( scalar( @_ ) == 1 && Scalar::Util::reftype( $_[0] ) eq 'HASH' ) |
|
|
0
|
|
|
|
|
|
3648
|
|
|
|
|
|
|
{ |
3649
|
0
|
|
|
|
|
0
|
$hash = shift( @_ ); |
3650
|
|
|
|
|
|
|
} |
3651
|
|
|
|
|
|
|
elsif( @_ ) |
3652
|
|
|
|
|
|
|
{ |
3653
|
0
|
0
|
|
|
|
0
|
CORE::warn( "Parameter provided is not an hash reference: '", join( "', '", @_ ), "'\n" ) if( $this->_warnings_is_enabled ); |
3654
|
|
|
|
|
|
|
} |
3655
|
|
|
|
|
|
|
## $self->message( 3, "Data provided are: ", sub{ $self->dumper( $hash ) } ); |
3656
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__, "::new(): Got for hash: '", join( "', '", sort( keys( %$hash ) ) ), "'\n" ); |
3657
|
|
|
|
|
|
|
local $make_class = sub |
3658
|
|
|
|
|
|
|
{ |
3659
|
0
|
|
|
0
|
|
0
|
my $k = shift( @_ ); |
3660
|
0
|
|
|
|
|
0
|
my $new_class = $k; |
3661
|
0
|
|
|
|
|
0
|
$new_class =~ tr/-/_/; |
3662
|
0
|
|
|
|
|
0
|
$new_class =~ s/\_{2,}/_/g; |
3663
|
0
|
|
|
|
|
0
|
$new_class = join( '', map( ucfirst( lc( $_ ) ), split( /\_/, $new_class ) ) ); |
3664
|
0
|
|
|
|
|
0
|
$new_class = "${class}\::${new_class}"; |
3665
|
|
|
|
|
|
|
## Sanitise the key which will serve as a method name |
3666
|
0
|
|
|
|
|
0
|
my $clean_field = $k; |
3667
|
0
|
|
|
|
|
0
|
$clean_field =~ tr/-/_/; |
3668
|
0
|
|
|
|
|
0
|
$clean_field =~ s/\_{2,}/_/g; |
3669
|
0
|
|
|
|
|
0
|
$clean_field =~ s/[^a-zA-Z0-9\_]+//g; |
3670
|
0
|
|
|
|
|
0
|
$clean_field =~ s/^\d+//g; |
3671
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__, "::new(): \$clean_field now is '$clean_field'\n" ); |
3672
|
0
|
|
|
|
|
0
|
my $perl = <<EOT; |
3673
|
|
|
|
|
|
|
package $new_class; |
3674
|
|
|
|
|
|
|
BEGIN |
3675
|
|
|
|
|
|
|
{ |
3676
|
|
|
|
|
|
|
use strict; |
3677
|
|
|
|
|
|
|
use Module::Generic; |
3678
|
|
|
|
|
|
|
use parent -norequire, qw( Module::Generic::Dynamic ); |
3679
|
|
|
|
|
|
|
}; |
3680
|
|
|
|
|
|
|
|
3681
|
|
|
|
|
|
|
1; |
3682
|
|
|
|
|
|
|
|
3683
|
|
|
|
|
|
|
EOT |
3684
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Evaluating\n$perl\n" ); |
3685
|
0
|
|
|
|
|
0
|
my $rc = eval( $perl ); |
3686
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::_set_get_hash_as_object(): Returned $rc\n" ); |
3687
|
0
|
0
|
|
|
|
0
|
die( "Unable to dynamically create module $new_class: $@" ) if( $@ ); |
3688
|
0
|
|
|
|
|
0
|
return( $new_class, $clean_field ); |
3689
|
0
|
|
|
|
|
0
|
}; |
3690
|
|
|
|
|
|
|
|
3691
|
0
|
|
|
|
|
0
|
foreach my $k ( sort( keys( %$hash ) ) ) |
3692
|
|
|
|
|
|
|
{ |
3693
|
0
|
0
|
|
|
|
0
|
if( ref( $hash->{ $k } ) eq 'HASH' ) |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
3694
|
|
|
|
|
|
|
{ |
3695
|
0
|
|
|
|
|
0
|
my $clean_field = $k; |
3696
|
0
|
|
|
|
|
0
|
$clean_field =~ tr/-/_/; |
3697
|
0
|
|
|
|
|
0
|
$clean_field =~ s/\_{2,}/_/g; |
3698
|
0
|
|
|
|
|
0
|
$clean_field =~ s/[^a-zA-Z0-9\_]+//g; |
3699
|
0
|
|
|
|
|
0
|
$clean_field =~ s/^\d+//g; |
3700
|
|
|
|
|
|
|
# my( $new_class, $clean_field ) = $make_class->( $k ); |
3701
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::new(): Is hash looping? ", ( $hash->{ $k }->{_looping} ? 'yes' : 'no' ), " (", ref( $hash->{ $k }->{_looping} ), ")\n" ); |
3702
|
|
|
|
|
|
|
# my $o = $hash->{ $k }->{_looping} ? $hash->{ $k }->{_looping} : $new_class->new( $hash->{ $k } ); |
3703
|
|
|
|
|
|
|
# $data->{ $clean_field } = $o; |
3704
|
|
|
|
|
|
|
# $hash->{ $k }->{_looping} = $o; |
3705
|
0
|
|
|
|
|
0
|
eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_object( $clean_field, '$new_class', \@_ ) ); }" ); |
3706
|
0
|
0
|
|
|
|
0
|
die( $@ ) if( $@ ); |
3707
|
0
|
|
|
|
|
0
|
$self->$clean_field( $hash->{ $k } ); |
3708
|
|
|
|
|
|
|
} |
3709
|
|
|
|
|
|
|
elsif( ref( $hash->{ $k } ) eq 'ARRAY' ) |
3710
|
|
|
|
|
|
|
{ |
3711
|
0
|
|
|
|
|
0
|
my( $new_class, $clean_field ) = $make_class->( $k ); |
3712
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::new() found an array for key $k, creating objects for class $new_class\n" ); |
3713
|
|
|
|
|
|
|
## We take a peek at what we have to determine how we will handle the data |
3714
|
0
|
0
|
|
|
|
0
|
my $mode = lc( scalar( @{$hash->{ $k }} ) ? ref( $hash->{ $k }->[0] ) : '' ); |
|
0
|
|
|
|
|
0
|
|
3715
|
0
|
0
|
|
|
|
0
|
if( $mode eq 'hash' ) |
3716
|
|
|
|
|
|
|
{ |
3717
|
0
|
|
|
|
|
0
|
my $all = []; |
3718
|
0
|
|
|
|
|
0
|
foreach my $this ( @{$hash->{ $k }} ) |
|
0
|
|
|
|
|
0
|
|
3719
|
|
|
|
|
|
|
{ |
3720
|
0
|
0
|
|
|
|
0
|
my $o = $this->{_looping} ? $this->{_looping} : $new_class->new( $this ); |
3721
|
0
|
|
|
|
|
0
|
$this->{_looping} = $o; |
3722
|
0
|
|
|
|
|
0
|
CORE::push( @$all, $o ); |
3723
|
|
|
|
|
|
|
} |
3724
|
|
|
|
|
|
|
# $data->{ $clean_field } = $all; |
3725
|
0
|
|
|
|
|
0
|
eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_object_array_object( '$clean_field', '$new_class', \@_ ) ); }" ); |
3726
|
|
|
|
|
|
|
} |
3727
|
|
|
|
|
|
|
else |
3728
|
|
|
|
|
|
|
{ |
3729
|
|
|
|
|
|
|
# $data->{ $clean_field } = $hash->{ $k }; |
3730
|
0
|
|
|
|
|
0
|
eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_array_as_object( '$clean_field', \@_ ) ); }" ); |
3731
|
|
|
|
|
|
|
} |
3732
|
0
|
0
|
|
|
|
0
|
die( $@ ) if( $@ ); |
3733
|
0
|
|
|
|
|
0
|
$self->$clean_field( $hash->{ $k } ); |
3734
|
|
|
|
|
|
|
} |
3735
|
|
|
|
|
|
|
elsif( !ref( $hash->{ $k } ) ) |
3736
|
|
|
|
|
|
|
{ |
3737
|
0
|
|
|
|
|
0
|
my $clean_field = $k; |
3738
|
0
|
|
|
|
|
0
|
$clean_field =~ tr/-/_/; |
3739
|
0
|
|
|
|
|
0
|
$clean_field =~ s/\_{2,}/_/g; |
3740
|
0
|
|
|
|
|
0
|
$clean_field =~ s/[^a-zA-Z0-9\_]+//g; |
3741
|
0
|
|
|
|
|
0
|
$clean_field =~ s/^\d+//g; |
3742
|
0
|
|
|
|
|
0
|
eval( "sub ${new_class}::${clean_field} { return( shift->_set_get_scalar_as_object( '$clean_field', \@_ ) ); }" ); |
3743
|
0
|
|
|
|
|
0
|
$self->$clean_field( $hash->{ $k } ); |
3744
|
|
|
|
|
|
|
} |
3745
|
|
|
|
|
|
|
else |
3746
|
|
|
|
|
|
|
{ |
3747
|
0
|
|
|
|
|
0
|
$self->$k( $hash->{ $k } ); |
3748
|
|
|
|
|
|
|
} |
3749
|
|
|
|
|
|
|
} |
3750
|
0
|
|
|
|
|
0
|
return( $self ); |
3751
|
|
|
|
|
|
|
} |
3752
|
|
|
|
|
|
|
|
3753
|
|
|
|
|
|
|
AUTOLOAD |
3754
|
|
|
|
|
|
|
{ |
3755
|
0
|
|
|
0
|
|
0
|
my( $method ) = our $AUTOLOAD =~ /([^:]+)$/; |
3756
|
|
|
|
|
|
|
# my( $class, $method ) = our $AUTOLOAD =~ /^(.*?)::([^\:]+)$/; |
3757
|
6
|
|
|
6
|
|
52
|
no overloading; |
|
6
|
|
|
|
|
19
|
|
|
6
|
|
|
|
|
1445
|
|
3758
|
0
|
|
|
|
|
0
|
my $self = shift( @_ ); |
3759
|
0
|
|
0
|
|
|
0
|
my $class = ref( $self ) || $self; |
3760
|
0
|
|
|
|
|
0
|
my $code; |
3761
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::$method(): Called\n" ); |
3762
|
0
|
0
|
|
|
|
0
|
if( $code = $self->can( $method ) ) |
3763
|
|
|
|
|
|
|
{ |
3764
|
0
|
|
|
|
|
0
|
return( $code->( @_ ) ); |
3765
|
|
|
|
|
|
|
} |
3766
|
|
|
|
|
|
|
## elsif( CORE::exists( $self->{ $method } ) ) |
3767
|
|
|
|
|
|
|
else |
3768
|
|
|
|
|
|
|
{ |
3769
|
0
|
|
|
|
|
0
|
my $ref = lc( ref( $_[0] ) ); |
3770
|
0
|
|
|
|
|
0
|
my $handler = '_set_get_scalar_as_object'; |
3771
|
|
|
|
|
|
|
# if( @_ && ( $ref eq 'hash' || $ref eq 'array' ) ) |
3772
|
0
|
0
|
0
|
|
|
0
|
if( $ref eq 'hash' || $ref eq 'array' ) |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
3773
|
|
|
|
|
|
|
{ |
3774
|
|
|
|
|
|
|
# print( STDERR __PACKAGE__, "::$method(): using handler $handler for type $ref\n" ); |
3775
|
0
|
|
|
|
|
0
|
$handler = "_set_get_${ref}_as_object"; |
3776
|
|
|
|
|
|
|
} |
3777
|
|
|
|
|
|
|
elsif( $ref eq 'json::pp::boolean' || |
3778
|
|
|
|
|
|
|
$ref eq 'module::generic::boolean' || |
3779
|
|
|
|
|
|
|
( $ref eq 'scalar' && ( $$ref == 1 || $$ref == 0 ) ) ) |
3780
|
|
|
|
|
|
|
{ |
3781
|
0
|
|
|
|
|
0
|
$handler = '_set_get_boolean'; |
3782
|
|
|
|
|
|
|
} |
3783
|
0
|
|
|
|
|
0
|
eval( "sub ${class}::${method} { return( shift->$handler( '$method', \@_ ) ); }" ); |
3784
|
0
|
0
|
|
|
|
0
|
die( $@ ) if( $@ ); |
3785
|
|
|
|
|
|
|
## $self->message( 3, "Calling method '$method' with data: ", sub{ $self->printer( @_ ) } ); |
3786
|
0
|
|
|
|
|
0
|
return( $self->$method( @_ ) ); |
3787
|
|
|
|
|
|
|
} |
3788
|
|
|
|
|
|
|
}; |
3789
|
|
|
|
|
|
|
|
3790
|
|
|
|
|
|
|
package Module::Generic::Boolean; |
3791
|
|
|
|
|
|
|
BEGIN |
3792
|
|
|
|
|
|
|
{ |
3793
|
6
|
|
|
6
|
|
4308
|
use common::sense; |
|
6
|
|
|
|
|
95
|
|
|
6
|
|
|
|
|
33
|
|
3794
|
|
|
|
|
|
|
use overload |
3795
|
3736
|
|
|
3736
|
|
16211
|
"0+" => sub { ${$_[0]} }, |
|
3736
|
|
|
|
|
14614
|
|
3796
|
0
|
|
|
0
|
|
0
|
"++" => sub { $_[0] = ${$_[0]} + 1 }, |
|
0
|
|
|
|
|
0
|
|
3797
|
0
|
|
|
0
|
|
0
|
"--" => sub { $_[0] = ${$_[0]} - 1 }, |
|
0
|
|
|
|
|
0
|
|
3798
|
6
|
|
|
6
|
|
1247
|
fallback => 1; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
65
|
|
3799
|
|
|
|
|
|
|
# *Module::Generic::Boolean:: = *JSON::PP::Boolean::; |
3800
|
6
|
|
|
6
|
|
2485
|
our( $VERSION ) = '0.1.0'; |
3801
|
|
|
|
|
|
|
}; |
3802
|
|
|
|
|
|
|
|
3803
|
7
|
100
|
|
7
|
|
61
|
sub new { return( $_[1] ? $true : $false ); } |
3804
|
|
|
|
|
|
|
|
3805
|
0
|
|
|
0
|
|
0
|
sub defined { return( 1 ); } |
3806
|
|
|
|
|
|
|
|
3807
|
|
|
|
|
|
|
our $true = do{ bless( \( my $dummy = 1 ) => Module::Generic::Boolean ) }; |
3808
|
|
|
|
|
|
|
our $false = do{ bless( \( my $dummy = 0 ) => Module::Generic::Boolean ) }; |
3809
|
|
|
|
|
|
|
|
3810
|
282
|
|
|
282
|
|
709
|
sub true () { $true } |
3811
|
148
|
|
|
148
|
|
402
|
sub false () { $false } |
3812
|
|
|
|
|
|
|
|
3813
|
0
|
|
|
0
|
|
0
|
sub is_bool ($) { UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) } |
3814
|
0
|
0
|
|
0
|
|
0
|
sub is_true ($) { $_[0] && UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) } |
3815
|
0
|
0
|
|
0
|
|
0
|
sub is_false ($) { !$_[0] && UNIVERSAL::isa( $_[0], Module::Generic::Boolean ) } |
3816
|
|
|
|
|
|
|
|
3817
|
|
|
|
|
|
|
sub TO_JSON |
3818
|
|
|
|
|
|
|
{ |
3819
|
|
|
|
|
|
|
## JSON does not check that the value is a proper true or false. It stupidly assumes this is a string |
3820
|
|
|
|
|
|
|
## The only way to make it understand is to return a scalar ref of 1 or 0 |
3821
|
|
|
|
|
|
|
# return( $_[0] ? 'true' : 'false' ); |
3822
|
0
|
0
|
|
0
|
|
0
|
return( $_[0] ? \1 : \0 ); |
3823
|
|
|
|
|
|
|
} |
3824
|
|
|
|
|
|
|
|
3825
|
|
|
|
|
|
|
package Module::Generic::Array; |
3826
|
|
|
|
|
|
|
BEGIN |
3827
|
|
|
|
|
|
|
{ |
3828
|
6
|
|
|
6
|
|
46
|
use common::sense; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
26
|
|
3829
|
6
|
|
|
6
|
|
313
|
use warnings; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
195
|
|
3830
|
6
|
|
|
6
|
|
32
|
use warnings::register; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
603
|
|
3831
|
6
|
|
|
6
|
|
38
|
use Scalar::Util (); |
|
6
|
|
|
|
|
17
|
|
|
6
|
|
|
|
|
109
|
|
3832
|
6
|
|
|
6
|
|
30
|
use Want; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
1029
|
|
3833
|
|
|
|
|
|
|
## use Data::Dumper; |
3834
|
|
|
|
|
|
|
use overload ( |
3835
|
|
|
|
|
|
|
# Turned out to be not such a good ide as it create unexpected results, especially when this is an array of overloaded objects |
3836
|
|
|
|
|
|
|
# '""' => 'as_string', |
3837
|
0
|
|
|
0
|
|
0
|
'==' => sub { _obj_eq(@_) }, |
3838
|
0
|
|
|
0
|
|
0
|
'!=' => sub { !_obj_eq(@_) }, |
3839
|
2
|
|
|
2
|
|
661
|
'eq' => sub { _obj_eq(@_) }, |
3840
|
1
|
|
|
1
|
|
10
|
'ne' => sub { !_obj_eq(@_) }, |
3841
|
6
|
|
|
|
|
63
|
'%{}' => 'as_hash', |
3842
|
|
|
|
|
|
|
fallback => 1, |
3843
|
6
|
|
|
6
|
|
40
|
); |
|
6
|
|
|
|
|
13
|
|
3844
|
6
|
|
|
6
|
|
12635
|
our( $VERSION ) = 'v0.1.1'; |
3845
|
|
|
|
|
|
|
}; |
3846
|
|
|
|
|
|
|
|
3847
|
|
|
|
|
|
|
sub new |
3848
|
|
|
|
|
|
|
{ |
3849
|
37
|
|
|
37
|
|
770
|
my $this = CORE::shift( @_ ); |
3850
|
37
|
|
|
|
|
77
|
my $init = []; |
3851
|
37
|
50
|
33
|
|
|
403
|
$init = CORE::shift( @_ ) if( @_ && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ); |
|
|
|
66
|
|
|
|
|
3852
|
37
|
|
66
|
|
|
246
|
return( bless( $init => ( ref( $this ) || $this ) ) ); |
3853
|
|
|
|
|
|
|
} |
3854
|
|
|
|
|
|
|
|
3855
|
|
|
|
|
|
|
sub as_hash |
3856
|
|
|
|
|
|
|
{ |
3857
|
2
|
|
|
2
|
|
429
|
my $self = CORE::shift( @_ ); |
3858
|
|
|
|
|
|
|
## print( STDERR ref( $self ), "::as_hash\n" ); |
3859
|
2
|
|
|
|
|
4
|
my $ref = {}; |
3860
|
2
|
|
|
|
|
10
|
my( @offsets ) = $self->keys; |
3861
|
2
|
|
|
|
|
26
|
@$ref{ @$self } = @offsets; |
3862
|
|
|
|
|
|
|
## print( ref( $self ), "::as_hash -> dump: ", Data::Dumper::Dumper( $ref ), "\n" ); |
3863
|
2
|
|
|
|
|
11
|
return( Module::Generic::Hash->new( $ref ) ); |
3864
|
|
|
|
|
|
|
} |
3865
|
|
|
|
|
|
|
|
3866
|
|
|
|
|
|
|
sub as_string |
3867
|
|
|
|
|
|
|
{ |
3868
|
19
|
|
|
19
|
|
45
|
my $self = CORE::shift( @_ ); |
3869
|
19
|
|
|
|
|
33
|
my $sort = 0; |
3870
|
19
|
100
|
|
|
|
48
|
$sort = CORE::shift( @_ ) if( @_ ); |
3871
|
19
|
100
|
|
|
|
55
|
return( $self->sort->as_string ) if( $sort ); |
3872
|
13
|
|
|
|
|
82
|
return( "@$self" ); |
3873
|
|
|
|
|
|
|
} |
3874
|
|
|
|
|
|
|
|
3875
|
5
|
|
|
5
|
|
17
|
sub clone { return( $_[0]->new( [ @{$_[0]} ] ) ); } |
|
5
|
|
|
|
|
38
|
|
3876
|
|
|
|
|
|
|
|
3877
|
|
|
|
|
|
|
sub delete |
3878
|
|
|
|
|
|
|
{ |
3879
|
4
|
|
|
4
|
|
12
|
my $self = CORE::shift( @_ ); |
3880
|
4
|
|
|
|
|
11
|
my( $offset, $length ) = @_; |
3881
|
4
|
50
|
|
|
|
13
|
if( defined( $offset ) ) |
3882
|
|
|
|
|
|
|
{ |
3883
|
4
|
100
|
|
|
|
30
|
if( $offset !~ /^\-?\d+$/ ) |
3884
|
|
|
|
|
|
|
{ |
3885
|
1
|
50
|
|
|
|
7
|
warn( "Non integer offset \"$offset\" provided to delete array element\n" ) if( $self->_warnings_is_enabled ); |
3886
|
1
|
|
|
|
|
6
|
return( $self ); |
3887
|
|
|
|
|
|
|
} |
3888
|
3
|
50
|
66
|
|
|
21
|
if( CORE::defined( $length ) && $length !~ /^\-?\d+$/ ) |
3889
|
|
|
|
|
|
|
{ |
3890
|
0
|
0
|
|
|
|
0
|
warn( $self, "Non integer length \"$length\" provided to delete array element\n" ) if( $self->_warnings_is_enabled ); |
3891
|
0
|
|
|
|
|
0
|
return( $self ); |
3892
|
|
|
|
|
|
|
} |
3893
|
3
|
100
|
|
|
|
18
|
my @removed = CORE::splice( @$self, $offset, CORE::defined( $length ) ? CORE::int( $length ) : 1 ); |
3894
|
3
|
50
|
|
|
|
14
|
if( Want::want( 'LIST' ) ) |
3895
|
|
|
|
|
|
|
{ |
3896
|
0
|
|
|
|
|
0
|
rreturn( @removed ); |
3897
|
|
|
|
|
|
|
} |
3898
|
|
|
|
|
|
|
else |
3899
|
|
|
|
|
|
|
{ |
3900
|
3
|
|
|
|
|
196
|
rreturn( $self->new( \@removed ) ); |
3901
|
|
|
|
|
|
|
} |
3902
|
|
|
|
|
|
|
# Required to make the compiler happy, as per Want documentation |
3903
|
0
|
|
|
|
|
0
|
return; |
3904
|
|
|
|
|
|
|
} |
3905
|
0
|
|
|
|
|
0
|
return( $self ); |
3906
|
|
|
|
|
|
|
} |
3907
|
|
|
|
|
|
|
|
3908
|
|
|
|
|
|
|
sub each |
3909
|
|
|
|
|
|
|
{ |
3910
|
1
|
|
|
1
|
|
3
|
my $self = CORE::shift( @_ ); |
3911
|
|
|
|
|
|
|
my $code = CORE::shift( @_ ) || do |
3912
|
1
|
|
33
|
|
|
5
|
{ |
3913
|
|
|
|
|
|
|
warn( "No subroutine callback as provided for each\n" ) if( $self->_warnings_is_enabled ); |
3914
|
|
|
|
|
|
|
return; |
3915
|
|
|
|
|
|
|
}; |
3916
|
1
|
50
|
|
|
|
5
|
if( ref( $code ) ne 'CODE' ) |
3917
|
|
|
|
|
|
|
{ |
3918
|
0
|
0
|
|
|
|
0
|
warn( "I was expecting a reference to a subroutine for the callback to each, but got '$code' instead.\n" ) if( $self->_warnings_is_enabled ); |
3919
|
0
|
|
|
|
|
0
|
return; |
3920
|
|
|
|
|
|
|
} |
3921
|
|
|
|
|
|
|
## Index starts from 0 |
3922
|
1
|
|
|
|
|
8
|
while( my( $i, $v ) = CORE::each( @$self ) ) |
3923
|
|
|
|
|
|
|
{ |
3924
|
18
|
|
|
|
|
680
|
local $_ = $v; |
3925
|
18
|
50
|
|
|
|
35
|
CORE::defined( $code->( $i, $v ) ) || CORE::last; |
3926
|
|
|
|
|
|
|
} |
3927
|
1
|
|
|
|
|
8
|
return( $self ); |
3928
|
|
|
|
|
|
|
} |
3929
|
|
|
|
|
|
|
|
3930
|
|
|
|
|
|
|
sub exists |
3931
|
|
|
|
|
|
|
{ |
3932
|
4
|
|
|
4
|
|
12
|
my $self = CORE::shift( @_ ); |
3933
|
4
|
|
|
|
|
11
|
my $this = CORE::shift( @_ ); |
3934
|
4
|
|
|
|
|
221
|
return( $self->_number( CORE::scalar( CORE::grep( /^$this$/, @$self ) ) ) ); |
3935
|
|
|
|
|
|
|
} |
3936
|
|
|
|
|
|
|
|
3937
|
|
|
|
|
|
|
sub first |
3938
|
|
|
|
|
|
|
{ |
3939
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
3940
|
0
|
0
|
|
|
|
0
|
return( $self->[0] ) if( CORE::length( $self->[0] ) ); |
3941
|
0
|
0
|
|
|
|
0
|
if( Want::want( 'OBJECT' ) ) |
3942
|
|
|
|
|
|
|
{ |
3943
|
0
|
|
|
|
|
0
|
rreturn( Module::Generic::Null->new ); |
3944
|
|
|
|
|
|
|
} |
3945
|
0
|
|
|
|
|
0
|
return( $self->[0] ); |
3946
|
|
|
|
|
|
|
} |
3947
|
|
|
|
|
|
|
|
3948
|
|
|
|
|
|
|
sub for |
3949
|
|
|
|
|
|
|
{ |
3950
|
1
|
|
|
1
|
|
726
|
my $self = CORE::shift( @_ ); |
3951
|
1
|
|
|
|
|
3
|
my $code = CORE::shift( @_ ); |
3952
|
1
|
50
|
|
|
|
20
|
return if( ref( $code ) ne 'CODE' ); |
3953
|
1
|
|
|
|
|
7
|
CORE::for( my $i = 0; $i < scalar( @$self ); $i++ ) |
3954
|
|
|
|
|
|
|
{ |
3955
|
18
|
|
|
|
|
796
|
local $_ = $self->[ $i ]; |
3956
|
18
|
50
|
|
|
|
34
|
CORE::defined( $code->( $i, $self->[ $i ] ) ) || CORE::last; |
3957
|
|
|
|
|
|
|
} |
3958
|
1
|
|
|
|
|
8
|
return( $self ); |
3959
|
|
|
|
|
|
|
} |
3960
|
|
|
|
|
|
|
|
3961
|
|
|
|
|
|
|
sub foreach |
3962
|
|
|
|
|
|
|
{ |
3963
|
1
|
|
|
1
|
|
41
|
my $self = CORE::shift( @_ ); |
3964
|
1
|
|
|
|
|
3
|
my $code = CORE::shift( @_ ); |
3965
|
1
|
50
|
|
|
|
5
|
return if( ref( $code ) ne 'CODE' ); |
3966
|
1
|
|
|
|
|
4
|
CORE::foreach my $v ( @$self ) |
3967
|
|
|
|
|
|
|
{ |
3968
|
18
|
|
|
|
|
83
|
local $_ = $v; |
3969
|
18
|
50
|
|
|
|
26
|
CORE::defined( $code->( $v ) ) || CORE::last; |
3970
|
|
|
|
|
|
|
} |
3971
|
1
|
|
|
|
|
7
|
return( $self ); |
3972
|
|
|
|
|
|
|
} |
3973
|
|
|
|
|
|
|
|
3974
|
|
|
|
|
|
|
sub get |
3975
|
|
|
|
|
|
|
{ |
3976
|
1
|
|
|
1
|
|
364
|
my $self = CORE::shift( @_ ); |
3977
|
1
|
|
|
|
|
2
|
my $offset = CORE::shift( @_ ); |
3978
|
1
|
|
|
|
|
7
|
return( $self->[ CORE::int( $offset ) ] ); |
3979
|
|
|
|
|
|
|
} |
3980
|
|
|
|
|
|
|
|
3981
|
|
|
|
|
|
|
sub grep |
3982
|
|
|
|
|
|
|
{ |
3983
|
3
|
|
|
3
|
|
9
|
my $self = CORE::shift( @_ ); |
3984
|
3
|
|
|
|
|
7
|
my $expr = CORE::shift( @_ ); |
3985
|
3
|
|
|
|
|
5
|
my $ref; |
3986
|
3
|
100
|
|
|
|
15
|
if( ref( $expr ) eq 'CODE' ) |
3987
|
|
|
|
|
|
|
{ |
3988
|
1
|
|
|
|
|
8
|
$ref = [CORE::grep( $expr->( $_ ), @$self )]; |
3989
|
|
|
|
|
|
|
} |
3990
|
|
|
|
|
|
|
else |
3991
|
|
|
|
|
|
|
{ |
3992
|
2
|
100
|
|
|
|
29
|
$expr = ref( $expr ) eq 'Regexp' |
3993
|
|
|
|
|
|
|
? $expr |
3994
|
|
|
|
|
|
|
: qr/\Q$expr\E/; |
3995
|
2
|
|
|
|
|
45
|
$ref = [ CORE::grep( $_ =~ /$expr/, @$self ) ]; |
3996
|
|
|
|
|
|
|
} |
3997
|
3
|
50
|
|
|
|
56
|
if( Want::want( 'LIST' ) ) |
3998
|
|
|
|
|
|
|
{ |
3999
|
0
|
|
|
|
|
0
|
return( @$ref ); |
4000
|
|
|
|
|
|
|
} |
4001
|
|
|
|
|
|
|
else |
4002
|
|
|
|
|
|
|
{ |
4003
|
3
|
|
|
|
|
213
|
return( $self->new( $ref ) ); |
4004
|
|
|
|
|
|
|
} |
4005
|
|
|
|
|
|
|
} |
4006
|
|
|
|
|
|
|
|
4007
|
|
|
|
|
|
|
sub join |
4008
|
|
|
|
|
|
|
{ |
4009
|
4
|
|
|
4
|
|
1539
|
my $self = CORE::shift( @_ ); |
4010
|
4
|
|
|
|
|
35
|
return( $self->_scalar( CORE::join( $_[0], @$self ) ) ); |
4011
|
|
|
|
|
|
|
} |
4012
|
|
|
|
|
|
|
|
4013
|
|
|
|
|
|
|
sub keys |
4014
|
|
|
|
|
|
|
{ |
4015
|
5
|
|
|
5
|
|
345
|
my $self = CORE::shift( @_ ); |
4016
|
5
|
|
|
|
|
31
|
return( $self->new( [ CORE::keys( @$self ) ] ) ); |
4017
|
|
|
|
|
|
|
} |
4018
|
|
|
|
|
|
|
|
4019
|
|
|
|
|
|
|
sub last |
4020
|
|
|
|
|
|
|
{ |
4021
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
4022
|
0
|
0
|
|
|
|
0
|
return( $self->[-1] ) if( CORE::length( $self->[-1] ) ); |
4023
|
0
|
0
|
|
|
|
0
|
if( Want::want( 'OBJECT' ) ) |
4024
|
|
|
|
|
|
|
{ |
4025
|
0
|
|
|
|
|
0
|
rreturn( Module::Generic::Null->new ); |
4026
|
|
|
|
|
|
|
} |
4027
|
0
|
|
|
|
|
0
|
return( $self->[-1] ); |
4028
|
|
|
|
|
|
|
} |
4029
|
|
|
|
|
|
|
|
4030
|
14
|
|
|
14
|
|
1080
|
sub length { return( $_[0]->_number( scalar( @{$_[0]} ) ) ); } |
|
14
|
|
|
|
|
128
|
|
4031
|
|
|
|
|
|
|
|
4032
|
1
|
|
|
1
|
|
3
|
sub list { return( @{$_[0]} ); } |
|
1
|
|
|
|
|
16
|
|
4033
|
|
|
|
|
|
|
|
4034
|
|
|
|
|
|
|
sub map |
4035
|
|
|
|
|
|
|
{ |
4036
|
3
|
|
|
3
|
|
354
|
my $self = CORE::shift( @_ ); |
4037
|
3
|
|
|
|
|
4
|
my $code = CORE::shift( @_ ); |
4038
|
3
|
50
|
|
|
|
12
|
return if( ref( $code ) ne 'CODE' ); |
4039
|
3
|
|
|
|
|
15
|
my $ref = [ CORE::map( $code->( $_ ), @$self ) ]; |
4040
|
3
|
100
|
|
|
|
71
|
if( Want::want( 'OBJECT' ) ) |
|
|
100
|
|
|
|
|
|
4041
|
|
|
|
|
|
|
{ |
4042
|
1
|
|
|
|
|
58
|
return( $self->new( $ref ) ); |
4043
|
|
|
|
|
|
|
} |
4044
|
|
|
|
|
|
|
elsif( Want::want( 'LIST' ) ) |
4045
|
|
|
|
|
|
|
{ |
4046
|
1
|
|
|
|
|
107
|
return( @$ref ); |
4047
|
|
|
|
|
|
|
} |
4048
|
|
|
|
|
|
|
else |
4049
|
|
|
|
|
|
|
{ |
4050
|
1
|
|
|
|
|
110
|
return( $self->new( $ref ) ); |
4051
|
|
|
|
|
|
|
} |
4052
|
|
|
|
|
|
|
} |
4053
|
|
|
|
|
|
|
|
4054
|
|
|
|
|
|
|
sub pop |
4055
|
|
|
|
|
|
|
{ |
4056
|
2
|
|
|
2
|
|
582
|
my $self = CORE::shift( @_ ); |
4057
|
2
|
|
|
|
|
11
|
return( CORE::pop( @$self ) ); |
4058
|
|
|
|
|
|
|
} |
4059
|
|
|
|
|
|
|
|
4060
|
|
|
|
|
|
|
sub push |
4061
|
|
|
|
|
|
|
{ |
4062
|
1
|
|
|
1
|
|
4
|
my $self = CORE::shift( @_ ); |
4063
|
1
|
|
|
|
|
6
|
CORE::push( @$self, @_ ); |
4064
|
1
|
|
|
|
|
5
|
return( $self ); |
4065
|
|
|
|
|
|
|
} |
4066
|
|
|
|
|
|
|
|
4067
|
|
|
|
|
|
|
sub push_arrayref |
4068
|
|
|
|
|
|
|
{ |
4069
|
1
|
|
|
1
|
|
3
|
my $self = CORE::shift( @_ ); |
4070
|
1
|
|
|
|
|
3
|
my $ref = CORE::shift( @_ ); |
4071
|
1
|
50
|
|
|
|
5
|
return( $self->error( "Data provided ($ref) is not an array reference." ) ) if( !UNIVERSAL::isa( $ref, 'ARRAY' ) ); |
4072
|
1
|
|
|
|
|
10
|
CORE::push( @$self, @$ref ); |
4073
|
1
|
|
|
|
|
5
|
return( $self ); |
4074
|
|
|
|
|
|
|
} |
4075
|
|
|
|
|
|
|
|
4076
|
|
|
|
|
|
|
sub reset |
4077
|
|
|
|
|
|
|
{ |
4078
|
1
|
|
|
1
|
|
3
|
my $self = CORE::shift( @_ ); |
4079
|
1
|
|
|
|
|
3
|
@$self = (); |
4080
|
1
|
|
|
|
|
6
|
return( $self ); |
4081
|
|
|
|
|
|
|
} |
4082
|
|
|
|
|
|
|
|
4083
|
|
|
|
|
|
|
sub reverse |
4084
|
|
|
|
|
|
|
{ |
4085
|
1
|
|
|
1
|
|
3
|
my $self = CORE::shift( @_ ); |
4086
|
1
|
|
|
|
|
7
|
my $ref = [ CORE::reverse( @$self ) ]; |
4087
|
1
|
50
|
|
|
|
14
|
if( wantarray() ) |
4088
|
|
|
|
|
|
|
{ |
4089
|
0
|
|
|
|
|
0
|
return( @$ref ); |
4090
|
|
|
|
|
|
|
} |
4091
|
|
|
|
|
|
|
else |
4092
|
|
|
|
|
|
|
{ |
4093
|
1
|
|
|
|
|
7
|
return( $self->new( $ref ) ); |
4094
|
|
|
|
|
|
|
} |
4095
|
|
|
|
|
|
|
} |
4096
|
|
|
|
|
|
|
|
4097
|
0
|
|
|
0
|
|
0
|
sub scalar { return( shift->length ); } |
4098
|
|
|
|
|
|
|
|
4099
|
|
|
|
|
|
|
sub set |
4100
|
|
|
|
|
|
|
{ |
4101
|
1
|
|
|
1
|
|
3
|
my $self = CORE::shift( @_ ); |
4102
|
1
|
50
|
33
|
|
|
17
|
my $ref = ( scalar( @_ ) == 1 && ( ( Scalar::Util::blessed( $_[0] ) && $_[0]->isa( 'ARRAY' ) ) || ref( $_[0] ) eq 'ARRAY' ) ) ? CORE::shift( @_ ) : [ @_ ]; |
4103
|
1
|
|
|
|
|
5
|
@$self = @$ref; |
4104
|
1
|
|
|
|
|
3
|
return( $self ); |
4105
|
|
|
|
|
|
|
} |
4106
|
|
|
|
|
|
|
|
4107
|
|
|
|
|
|
|
sub shift |
4108
|
|
|
|
|
|
|
{ |
4109
|
1
|
|
|
1
|
|
3
|
my $self = CORE::shift( @_ ); |
4110
|
1
|
|
|
|
|
5
|
return( CORE::shift( @$self ) ); |
4111
|
|
|
|
|
|
|
} |
4112
|
|
|
|
|
|
|
|
4113
|
1
|
|
|
1
|
|
7
|
sub size { return( $_[0]->_number( $_[0]->length ) ); } |
4114
|
|
|
|
|
|
|
|
4115
|
|
|
|
|
|
|
sub sort |
4116
|
|
|
|
|
|
|
{ |
4117
|
8
|
|
|
8
|
|
19
|
my $self = CORE::shift( @_ ); |
4118
|
8
|
|
|
|
|
16
|
my $code = CORE::shift( @_ ); |
4119
|
8
|
|
|
|
|
13
|
my $ref; |
4120
|
8
|
100
|
|
|
|
24
|
if( ref( $code ) eq 'CODE' ) |
4121
|
|
|
|
|
|
|
{ |
4122
|
|
|
|
|
|
|
$ref = [sort |
4123
|
|
|
|
|
|
|
{ |
4124
|
1
|
|
|
|
|
10
|
$code->( $a, $b ); |
|
53
|
|
|
|
|
130
|
|
4125
|
|
|
|
|
|
|
} @$self]; |
4126
|
|
|
|
|
|
|
} |
4127
|
|
|
|
|
|
|
else |
4128
|
|
|
|
|
|
|
{ |
4129
|
7
|
|
|
|
|
63
|
$ref = [ CORE::sort( @$self ) ]; |
4130
|
|
|
|
|
|
|
} |
4131
|
8
|
50
|
|
|
|
33
|
if( Want::want( 'LIST' ) ) |
4132
|
|
|
|
|
|
|
{ |
4133
|
0
|
|
|
|
|
0
|
return( @$ref ); |
4134
|
|
|
|
|
|
|
} |
4135
|
|
|
|
|
|
|
else |
4136
|
|
|
|
|
|
|
{ |
4137
|
8
|
|
|
|
|
505
|
return( $self->new( $ref ) ); |
4138
|
|
|
|
|
|
|
} |
4139
|
|
|
|
|
|
|
} |
4140
|
|
|
|
|
|
|
|
4141
|
|
|
|
|
|
|
sub splice |
4142
|
|
|
|
|
|
|
{ |
4143
|
2
|
|
|
2
|
|
6
|
my $self = CORE::shift( @_ ); |
4144
|
2
|
|
|
|
|
8
|
my( $offset, $length, @list ) = @_; |
4145
|
2
|
50
|
66
|
|
|
18
|
if( defined( $offset ) && $offset !~ /^\-?\d+$/ ) |
4146
|
|
|
|
|
|
|
{ |
4147
|
0
|
0
|
|
|
|
0
|
warn( "Offset provided for splice \"$offset\" is not an integer.\n" ) if( $self->_warnings_is_enabled ); |
4148
|
|
|
|
|
|
|
## If a list was provided, the user is not looking to get an element removed, but add it, so we return out object |
4149
|
0
|
0
|
|
|
|
0
|
return( $self ) if( scalar( @list ) ); |
4150
|
0
|
|
|
|
|
0
|
return; |
4151
|
|
|
|
|
|
|
} |
4152
|
2
|
50
|
66
|
|
|
15
|
if( defined( $length ) && $length !~ /^\-?\d+$/ ) |
4153
|
|
|
|
|
|
|
{ |
4154
|
0
|
0
|
|
|
|
0
|
warn( "Length provided for splice \"$length\" is not an integer.\n" ) if( $self->_warnings_is_enabled ); |
4155
|
0
|
0
|
|
|
|
0
|
return( $self ) if( scalar( @list ) ); |
4156
|
0
|
|
|
|
|
0
|
return; |
4157
|
|
|
|
|
|
|
} |
4158
|
|
|
|
|
|
|
## Adding elements, so we return our object and allow chaining |
4159
|
|
|
|
|
|
|
## @_ = offset, length, replacement list |
4160
|
2
|
100
|
|
|
|
9
|
if( scalar( @_ ) > 2 ) |
|
|
50
|
|
|
|
|
|
4161
|
|
|
|
|
|
|
{ |
4162
|
1
|
|
|
|
|
6
|
CORE::splice( @$self, $offset, $length, @list ); |
4163
|
1
|
|
|
|
|
6
|
return( $self ); |
4164
|
|
|
|
|
|
|
} |
4165
|
|
|
|
|
|
|
elsif( !scalar( @_ ) ) |
4166
|
|
|
|
|
|
|
{ |
4167
|
1
|
|
|
|
|
3
|
CORE::splice( @$self ); |
4168
|
1
|
|
|
|
|
7
|
return( $self ); |
4169
|
|
|
|
|
|
|
} |
4170
|
|
|
|
|
|
|
else |
4171
|
|
|
|
|
|
|
{ |
4172
|
0
|
0
|
0
|
|
|
0
|
return( CORE::splice( @$self, $offset, $length ) ) if( CORE::defined( $offset ) && CORE::defined( $length ) ); |
4173
|
0
|
0
|
|
|
|
0
|
return( CORE::splice( @$self, $offset ) ) if( CORE::defined( $offset ) ); |
4174
|
|
|
|
|
|
|
} |
4175
|
|
|
|
|
|
|
} |
4176
|
|
|
|
|
|
|
|
4177
|
|
|
|
|
|
|
sub undef |
4178
|
|
|
|
|
|
|
{ |
4179
|
1
|
|
|
1
|
|
4
|
my $self = CORE::shift( @_ ); |
4180
|
1
|
|
|
|
|
5
|
@$self = (); |
4181
|
1
|
|
|
|
|
6
|
return( $self ); |
4182
|
|
|
|
|
|
|
} |
4183
|
|
|
|
|
|
|
|
4184
|
|
|
|
|
|
|
sub unshift |
4185
|
|
|
|
|
|
|
{ |
4186
|
1
|
|
|
1
|
|
4
|
my $self = CORE::shift( @_ ); |
4187
|
1
|
|
|
|
|
4
|
CORE::unshift( @$self, @_ ); |
4188
|
1
|
|
|
|
|
5
|
return( $self ); |
4189
|
|
|
|
|
|
|
} |
4190
|
|
|
|
|
|
|
|
4191
|
|
|
|
|
|
|
sub values |
4192
|
|
|
|
|
|
|
{ |
4193
|
1
|
|
|
1
|
|
3
|
my $self = CORE::shift( @_ ); |
4194
|
1
|
|
|
|
|
7
|
my $ref = [ CORE::values( @$self ) ]; |
4195
|
1
|
50
|
|
|
|
5
|
if( Want::want( 'LIST' ) ) |
4196
|
|
|
|
|
|
|
{ |
4197
|
0
|
|
|
|
|
0
|
return( @$ref ); |
4198
|
|
|
|
|
|
|
} |
4199
|
|
|
|
|
|
|
else |
4200
|
|
|
|
|
|
|
{ |
4201
|
1
|
|
|
|
|
70
|
return( $self->new( $ref ) ); |
4202
|
|
|
|
|
|
|
} |
4203
|
|
|
|
|
|
|
} |
4204
|
|
|
|
|
|
|
|
4205
|
|
|
|
|
|
|
sub _number |
4206
|
|
|
|
|
|
|
{ |
4207
|
19
|
|
|
19
|
|
74
|
my $self = CORE::shift( @_ ); |
4208
|
19
|
|
|
|
|
59
|
my $num = CORE::shift( @_ ); |
4209
|
19
|
50
|
|
|
|
77
|
return if( !defined( $num ) ); |
4210
|
19
|
50
|
|
|
|
72
|
return( $num ) if( !CORE::length( $num ) ); |
4211
|
19
|
|
|
|
|
95
|
return( Module::Generic::Number->new( $num ) ); |
4212
|
|
|
|
|
|
|
} |
4213
|
|
|
|
|
|
|
|
4214
|
|
|
|
|
|
|
sub _obj_eq |
4215
|
|
|
|
|
|
|
{ |
4216
|
6
|
|
|
6
|
|
66
|
no overloading; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
1481
|
|
4217
|
3
|
|
|
3
|
|
7
|
my $self = CORE::shift( @_ ); |
4218
|
3
|
|
|
|
|
37
|
my $other = CORE::shift( @_ ); |
4219
|
|
|
|
|
|
|
## Sorted |
4220
|
3
|
|
|
|
|
16
|
my $strA = $self->as_string(1); |
4221
|
3
|
|
|
|
|
13
|
my $strB; |
4222
|
3
|
100
|
66
|
|
|
26
|
if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Array' ) ) |
|
|
50
|
|
|
|
|
|
4223
|
|
|
|
|
|
|
{ |
4224
|
1
|
|
|
|
|
4
|
$strB = $other->as_string(1); |
4225
|
|
|
|
|
|
|
} |
4226
|
|
|
|
|
|
|
## Compare error message |
4227
|
|
|
|
|
|
|
elsif( Scalar::Util::reftype( $other ) eq 'ARRAY' ) |
4228
|
|
|
|
|
|
|
{ |
4229
|
2
|
|
|
|
|
6
|
$strB = $self->new( $other )->as_string(1); |
4230
|
|
|
|
|
|
|
} |
4231
|
|
|
|
|
|
|
else |
4232
|
|
|
|
|
|
|
{ |
4233
|
0
|
|
|
|
|
0
|
return( 0 ); |
4234
|
|
|
|
|
|
|
} |
4235
|
|
|
|
|
|
|
## print( STDERR ref( $self ), "::_obj_eq: Comparing array A (", CORE::scalar( @$self ), ") with '$strA' to array B (", CORE::scalar( @$other ), ") with '$strB'\n" ); |
4236
|
3
|
|
|
|
|
36
|
return( $strA eq $strB ) ; |
4237
|
|
|
|
|
|
|
} |
4238
|
|
|
|
|
|
|
|
4239
|
|
|
|
|
|
|
sub _scalar |
4240
|
|
|
|
|
|
|
{ |
4241
|
4
|
|
|
4
|
|
11
|
my $self = CORE::shift( @_ ); |
4242
|
4
|
|
|
|
|
12
|
my $str = CORE::shift( @_ ); |
4243
|
4
|
50
|
|
|
|
19
|
return if( !defined( $str ) ); |
4244
|
|
|
|
|
|
|
## Whether empty or not, return an object |
4245
|
4
|
|
|
|
|
18
|
return( Module::Generic::Scalar->new( $str ) ); |
4246
|
|
|
|
|
|
|
} |
4247
|
|
|
|
|
|
|
|
4248
|
1
|
|
33
|
1
|
|
107
|
sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); } |
4249
|
|
|
|
|
|
|
|
4250
|
|
|
|
|
|
|
package Module::Generic::Scalar; |
4251
|
|
|
|
|
|
|
BEGIN |
4252
|
|
|
|
|
|
|
{ |
4253
|
6
|
|
|
6
|
|
51
|
use common::sense; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
26
|
|
4254
|
6
|
|
|
6
|
|
479
|
use warnings; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
184
|
|
4255
|
6
|
|
|
6
|
|
98
|
use warnings::register; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
679
|
|
4256
|
|
|
|
|
|
|
## So that the user can say $obj->isa( 'Module::Generic::Scalar' ) and it would return true |
4257
|
|
|
|
|
|
|
## use parent -norequire, qw( Module::Generic::Scalar ); |
4258
|
6
|
|
|
6
|
|
42
|
use Scalar::Util (); |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
110
|
|
4259
|
6
|
|
|
6
|
|
28
|
use Want; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
545
|
|
4260
|
|
|
|
|
|
|
use overload ( |
4261
|
|
|
|
|
|
|
'""' => 'as_string', |
4262
|
|
|
|
|
|
|
'.=' => sub |
4263
|
|
|
|
|
|
|
{ |
4264
|
3
|
|
|
3
|
|
16
|
my( $self, $other, $swap ) = @_; |
4265
|
6
|
|
|
6
|
|
71
|
no warnings 'uninitialized'; |
|
6
|
|
|
|
|
21
|
|
|
6
|
|
|
|
|
1141
|
|
4266
|
3
|
50
|
|
|
|
18
|
if( !CORE::defined( $$self ) ) |
|
|
50
|
|
|
|
|
|
4267
|
|
|
|
|
|
|
{ |
4268
|
0
|
|
|
|
|
0
|
return( $other ); |
4269
|
|
|
|
|
|
|
} |
4270
|
|
|
|
|
|
|
elsif( !CORE::defined( $other ) ) |
4271
|
|
|
|
|
|
|
{ |
4272
|
0
|
|
|
|
|
0
|
return( $$self ); |
4273
|
|
|
|
|
|
|
} |
4274
|
|
|
|
|
|
|
## print( STDERR ref( $self ), "::concatenate: Got here with other = '$other', and swap = '$swap'\n" ); |
4275
|
|
|
|
|
|
|
## print( STDERR "Module::Generic::Scalar::overload->.=: Received arguments '", join( "', '", @_ ), "'\n" ); |
4276
|
3
|
|
|
|
|
7
|
my $expr; |
4277
|
3
|
50
|
|
|
|
10
|
if( $swap ) |
4278
|
|
|
|
|
|
|
{ |
4279
|
0
|
|
|
|
|
0
|
$expr = "\$other .= \$$self"; |
4280
|
0
|
|
|
|
|
0
|
return( $other ); |
4281
|
|
|
|
|
|
|
} |
4282
|
|
|
|
|
|
|
else |
4283
|
|
|
|
|
|
|
{ |
4284
|
3
|
|
|
|
|
11
|
$$self .= $other; |
4285
|
3
|
|
|
|
|
11
|
return( $self ); |
4286
|
|
|
|
|
|
|
} |
4287
|
|
|
|
|
|
|
}, |
4288
|
|
|
|
|
|
|
'x' => sub |
4289
|
|
|
|
|
|
|
{ |
4290
|
1
|
|
|
1
|
|
8
|
my( $self, $other, $swap ) = @_; |
4291
|
6
|
|
|
6
|
|
38
|
no warnings 'uninitialized'; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
975
|
|
4292
|
|
|
|
|
|
|
## print( STDERR "Module::Generic::Scalar::overload->x: Received arguments '", join( "', '", @_ ), "'\n" ); |
4293
|
1
|
50
|
|
|
|
7
|
my $expr = $swap ? "\"$other" x \"$$self\"" : "\"$$self\" x \"$other\""; |
4294
|
1
|
|
|
|
|
78
|
my $res = eval( $expr ); |
4295
|
1
|
50
|
|
|
|
10
|
if( $@ ) |
4296
|
|
|
|
|
|
|
{ |
4297
|
0
|
|
|
|
|
0
|
CORE::warn( $@ ); |
4298
|
0
|
|
|
|
|
0
|
return; |
4299
|
|
|
|
|
|
|
} |
4300
|
1
|
|
|
|
|
28
|
return( $self->new( $res ) ); |
4301
|
|
|
|
|
|
|
}, |
4302
|
|
|
|
|
|
|
'eq' => sub |
4303
|
|
|
|
|
|
|
{ |
4304
|
3238
|
|
|
3238
|
|
718127
|
my( $self, $other, $swap ) = @_; |
4305
|
6
|
|
|
6
|
|
38
|
no warnings 'uninitialized'; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
644
|
|
4306
|
3238
|
100
|
66
|
|
|
11108
|
if( Scalar::Util::blessed( $other ) && ref( $other ) eq ref( $self ) ) |
4307
|
|
|
|
|
|
|
{ |
4308
|
1
|
|
|
|
|
13
|
return( $$self eq $$other ); |
4309
|
|
|
|
|
|
|
} |
4310
|
|
|
|
|
|
|
else |
4311
|
|
|
|
|
|
|
{ |
4312
|
3237
|
|
|
|
|
11518
|
return( $$self eq "$other" ); |
4313
|
|
|
|
|
|
|
} |
4314
|
|
|
|
|
|
|
}, |
4315
|
6
|
|
|
|
|
75
|
fallback => 1, |
4316
|
6
|
|
|
6
|
|
37
|
); |
|
6
|
|
|
|
|
10
|
|
4317
|
6
|
|
|
6
|
|
17829
|
our( $VERSION ) = 'v0.2.3'; |
4318
|
|
|
|
|
|
|
}; |
4319
|
|
|
|
|
|
|
|
4320
|
|
|
|
|
|
|
## sub new { return( shift->_new( @_ ) ); } |
4321
|
|
|
|
|
|
|
sub new |
4322
|
|
|
|
|
|
|
{ |
4323
|
55698
|
|
|
55698
|
|
85400
|
my $this = shift( @_ ); |
4324
|
55698
|
|
|
|
|
89802
|
my $init = ''; |
4325
|
55698
|
100
|
66
|
|
|
222859
|
if( ref( $_[0] ) eq 'SCALAR' || UNIVERSAL::isa( $_[0], 'SCALAR' ) ) |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
4326
|
|
|
|
|
|
|
{ |
4327
|
53957
|
|
|
|
|
81707
|
$init = ${$_[0]}; |
|
53957
|
|
|
|
|
98895
|
|
4328
|
|
|
|
|
|
|
} |
4329
|
|
|
|
|
|
|
elsif( ref( $_[0] ) eq 'ARRAY' || UNIVERSAL::isa( $_[0], 'ARRAY' ) ) |
4330
|
|
|
|
|
|
|
{ |
4331
|
0
|
|
|
|
|
0
|
$init = CORE::join( '', @{$_[0]} ); |
|
0
|
|
|
|
|
0
|
|
4332
|
|
|
|
|
|
|
} |
4333
|
|
|
|
|
|
|
elsif( ref( $_[0] ) ) |
4334
|
|
|
|
|
|
|
{ |
4335
|
0
|
0
|
|
|
|
0
|
warn( "I do not know what to do with \"", $_[0], "\"\n" ) if( $this->_warnings_is_enabled ); |
4336
|
0
|
|
|
|
|
0
|
return; |
4337
|
|
|
|
|
|
|
} |
4338
|
|
|
|
|
|
|
elsif( @_ ) |
4339
|
|
|
|
|
|
|
{ |
4340
|
1741
|
|
|
|
|
3026
|
$init = $_[0]; |
4341
|
|
|
|
|
|
|
} |
4342
|
|
|
|
|
|
|
else |
4343
|
|
|
|
|
|
|
{ |
4344
|
0
|
|
|
|
|
0
|
$init = undef(); |
4345
|
|
|
|
|
|
|
} |
4346
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__, "::new: got here for value '$init' (defined? ", CORE::defined( $init ) ? 'yes' : 'no', ")\n" ); |
4347
|
|
|
|
|
|
|
# CORE::tie( $self, 'Module::Generic::Scalar::Tie', $init ); |
4348
|
55698
|
|
66
|
|
|
210091
|
return( bless( \$init => ( ref( $this ) || $this ) ) ); |
4349
|
|
|
|
|
|
|
} |
4350
|
|
|
|
|
|
|
|
4351
|
3
|
100
|
|
3
|
|
4
|
sub as_boolean { return( Module::Generic::Boolean->new( ${$_[0]} ? 1 : 0 ) ); } |
|
3
|
|
|
|
|
18
|
|
4352
|
|
|
|
|
|
|
|
4353
|
|
|
|
|
|
|
## sub as_string { CORE::defined( ${$_[0]} ) ? return( ${$_[0]} ) : return; } |
4354
|
6756
|
|
|
6756
|
|
12264
|
sub as_string { return( ${$_[0]} ); } |
|
6756
|
|
|
|
|
25738
|
|
4355
|
|
|
|
|
|
|
|
4356
|
|
|
|
|
|
|
## Credits: John Gruber, Aristotle Pagaltzis |
4357
|
|
|
|
|
|
|
## https://gist.github.com/gruber/9f9e8650d68b13ce4d78 |
4358
|
|
|
|
|
|
|
sub capitalise |
4359
|
|
|
|
|
|
|
{ |
4360
|
1
|
|
|
1
|
|
4
|
my $self = CORE::shift( @_ ); |
4361
|
1
|
|
|
|
|
9
|
my @small_words = qw( (?<!q&)a an and as at(?!&t) but by en for if in of on or the to v[.]? via vs[.]? ); |
4362
|
1
|
|
|
|
|
6
|
my $small_re = CORE::join( '|', @small_words ); |
4363
|
|
|
|
|
|
|
|
4364
|
1
|
|
|
|
|
5
|
my $apos = qr/ (?: ['’] [[:lower:]]* )? /x; |
4365
|
|
|
|
|
|
|
|
4366
|
1
|
|
|
|
|
4
|
my $copy = $$self; |
4367
|
1
|
|
|
|
|
6
|
$copy =~ s{\A\s+}{}, s{\s+\z}{}; |
4368
|
1
|
50
|
|
|
|
7
|
$copy = CORE::lc( $copy ) if( not /[[:lower:]]/ ); |
4369
|
1
|
|
|
|
|
276
|
$copy =~ s{ |
4370
|
|
|
|
|
|
|
\b (_*) (?: |
4371
|
|
|
|
|
|
|
( (?<=[ ][/\\]) [[:alpha:]]+ [-_[:alpha:]/\\]+ | # file path or |
4372
|
|
|
|
|
|
|
[-_[:alpha:]]+ [@.:] [-_[:alpha:]@.:/]+ $apos ) # URL, domain, or email |
4373
|
|
|
|
|
|
|
| |
4374
|
|
|
|
|
|
|
( (?i: $small_re ) $apos ) # or small word (case-insensitive) |
4375
|
|
|
|
|
|
|
| |
4376
|
|
|
|
|
|
|
( [[:alpha:]] [[:lower:]'’()\[\]{}]* $apos ) # or word w/o internal caps |
4377
|
|
|
|
|
|
|
| |
4378
|
|
|
|
|
|
|
( [[:alpha:]] [[:alpha:]'’()\[\]{}]* $apos ) # or some other word |
4379
|
|
|
|
|
|
|
) (_*) \b |
4380
|
|
|
|
|
|
|
}{ |
4381
|
18
|
50
|
|
|
|
187
|
$1 . ( |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
4382
|
|
|
|
|
|
|
defined $2 ? $2 # preserve URL, domain, or email |
4383
|
|
|
|
|
|
|
: defined $3 ? "\L$3" # lowercase small word |
4384
|
|
|
|
|
|
|
: defined $4 ? "\u\L$4" # capitalize word w/o internal caps |
4385
|
|
|
|
|
|
|
: $5 # preserve other kinds of word |
4386
|
|
|
|
|
|
|
) . $6 |
4387
|
|
|
|
|
|
|
}xeg; |
4388
|
|
|
|
|
|
|
|
4389
|
|
|
|
|
|
|
|
4390
|
|
|
|
|
|
|
# Exceptions for small words: capitalize at start and end of title |
4391
|
1
|
|
|
|
|
157
|
$copy =~ s{ |
4392
|
|
|
|
|
|
|
( \A [[:punct:]]* # start of title... |
4393
|
|
|
|
|
|
|
| [:.;?!][ ]+ # or of subsentence... |
4394
|
|
|
|
|
|
|
| [ ]['"“‘(\[][ ]* ) # or of inserted subphrase... |
4395
|
|
|
|
|
|
|
( $small_re ) \b # ... followed by small word |
4396
|
|
|
|
|
|
|
}{$1\u\L$2}xig; |
4397
|
|
|
|
|
|
|
|
4398
|
1
|
|
|
|
|
97
|
$copy =~ s{ |
4399
|
|
|
|
|
|
|
\b ( $small_re ) # small word... |
4400
|
|
|
|
|
|
|
(?= [[:punct:]]* \Z # ... at the end of the title... |
4401
|
|
|
|
|
|
|
| ['"’”)\]] [ ] ) # ... or of an inserted subphrase? |
4402
|
|
|
|
|
|
|
}{\u\L$1}xig; |
4403
|
|
|
|
|
|
|
|
4404
|
|
|
|
|
|
|
# Exceptions for small words in hyphenated compound words |
4405
|
|
|
|
|
|
|
## e.g. "in-flight" -> In-Flight |
4406
|
1
|
|
|
|
|
62
|
$copy =~ s{ |
4407
|
|
|
|
|
|
|
\b |
4408
|
|
|
|
|
|
|
(?<! -) # Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (in-flight) |
4409
|
|
|
|
|
|
|
( $small_re ) |
4410
|
|
|
|
|
|
|
(?= -[[:alpha:]]+) # lookahead for "-someword" |
4411
|
|
|
|
|
|
|
}{\u\L$1}xig; |
4412
|
|
|
|
|
|
|
|
4413
|
|
|
|
|
|
|
## # e.g. "Stand-in" -> "Stand-In" (Stand is already capped at this point) |
4414
|
1
|
|
|
|
|
50
|
$copy =~ s{ |
4415
|
|
|
|
|
|
|
\b |
4416
|
|
|
|
|
|
|
(?<!…) # Negative lookbehind for a hyphen; we don't want to match man-in-the-middle but do want (stand-in) |
4417
|
|
|
|
|
|
|
( [[:alpha:]]+- ) # $1 = first word and hyphen, should already be properly capped |
4418
|
|
|
|
|
|
|
( $small_re ) # ... followed by small word |
4419
|
|
|
|
|
|
|
(?! - ) # Negative lookahead for another '-' |
4420
|
|
|
|
|
|
|
}{$1\u$2}xig; |
4421
|
|
|
|
|
|
|
|
4422
|
1
|
|
|
|
|
9
|
return( $self->_new( $copy ) ); |
4423
|
|
|
|
|
|
|
} |
4424
|
|
|
|
|
|
|
|
4425
|
1
|
|
|
1
|
|
3
|
sub chomp { return( CORE::chomp( ${$_[0]} ) ); } |
|
1
|
|
|
|
|
7
|
|
4426
|
|
|
|
|
|
|
|
4427
|
1
|
|
|
1
|
|
3
|
sub chop { return( CORE::chop( ${$_[0]} ) ); } |
|
1
|
|
|
|
|
4
|
|
4428
|
|
|
|
|
|
|
|
4429
|
|
|
|
|
|
|
sub clone |
4430
|
|
|
|
|
|
|
{ |
4431
|
5
|
|
|
5
|
|
889
|
my $self = shift( @_ ); |
4432
|
5
|
100
|
|
|
|
23
|
if( @_ ) |
4433
|
|
|
|
|
|
|
{ |
4434
|
1
|
|
|
|
|
4
|
return( $self->_new( @_ ) ); |
4435
|
|
|
|
|
|
|
} |
4436
|
|
|
|
|
|
|
else |
4437
|
|
|
|
|
|
|
{ |
4438
|
4
|
|
|
|
|
13
|
return( $self->_new( ${$self} ) ); |
|
4
|
|
|
|
|
25
|
|
4439
|
|
|
|
|
|
|
} |
4440
|
|
|
|
|
|
|
} |
4441
|
|
|
|
|
|
|
|
4442
|
1
|
|
|
1
|
|
2
|
sub crypt { return( __PACKAGE__->_new( CORE::crypt( ${$_[0]}, $_[1] ) ) ); } |
|
1
|
|
|
|
|
618
|
|
4443
|
|
|
|
|
|
|
|
4444
|
55678
|
|
|
55678
|
|
76172
|
sub defined { return( CORE::defined( ${$_[0]} ) ); } |
|
55678
|
|
|
|
|
147233
|
|
4445
|
|
|
|
|
|
|
|
4446
|
1
|
|
|
1
|
|
322
|
sub fc { return( CORE::fc( ${$_[0]} ) eq CORE::fc( $_[1] ) ); } |
|
1
|
|
|
|
|
8
|
|
4447
|
|
|
|
|
|
|
|
4448
|
2
|
|
|
2
|
|
6
|
sub hex { return( $_[0]->_number( CORE::hex( ${$_[0]} ) ) ); } |
|
2
|
|
|
|
|
18
|
|
4449
|
|
|
|
|
|
|
|
4450
|
|
|
|
|
|
|
sub index |
4451
|
|
|
|
|
|
|
{ |
4452
|
2
|
|
|
2
|
|
7
|
my $self = shift( @_ ); |
4453
|
2
|
|
|
|
|
7
|
my( $substr, $pos ) = @_; |
4454
|
2
|
50
|
|
|
|
7
|
return( $self->_number( CORE::index( ${$self}, $substr, $pos ) ) ) if( CORE::defined( $pos ) ); |
|
0
|
|
|
|
|
0
|
|
4455
|
2
|
|
|
|
|
5
|
return( $self->_number( CORE::index( ${$self}, $substr ) ) ); |
|
2
|
|
|
|
|
10
|
|
4456
|
|
|
|
|
|
|
} |
4457
|
|
|
|
|
|
|
|
4458
|
2
|
|
|
2
|
|
5
|
sub is_alpha { return( ${$_[0]} =~ /^[[:alpha:]]+$/ ); } |
|
2
|
|
|
|
|
19
|
|
4459
|
|
|
|
|
|
|
|
4460
|
1
|
|
|
1
|
|
2
|
sub is_alpha_numeric { return( ${$_[0]} =~ /^[[:alnum:]]+$/ ); } |
|
1
|
|
|
|
|
11
|
|
4461
|
|
|
|
|
|
|
|
4462
|
1
|
|
|
1
|
|
3
|
sub is_empty { return( CORE::length( ${$_[0]} ) == 0 ); } |
|
1
|
|
|
|
|
5
|
|
4463
|
|
|
|
|
|
|
|
4464
|
1
|
|
|
1
|
|
4
|
sub is_lower { return( ${$_[0]} =~ /^[[:lower:]]+$/ ); } |
|
1
|
|
|
|
|
10
|
|
4465
|
|
|
|
|
|
|
|
4466
|
1
|
|
|
1
|
|
4
|
sub is_numeric { return( Scalar::Util::looks_like_number( ${$_[0]} ) ); } |
|
1
|
|
|
|
|
9
|
|
4467
|
|
|
|
|
|
|
|
4468
|
1
|
|
|
1
|
|
3
|
sub is_upper { return( ${$_[0]} =~ /^[[:upper:]]+$/ ); } |
|
1
|
|
|
|
|
12
|
|
4469
|
|
|
|
|
|
|
|
4470
|
1
|
|
|
1
|
|
2
|
sub lc { return( __PACKAGE__->_new( CORE::lc( ${$_[0]} ) ) ); } |
|
1
|
|
|
|
|
6
|
|
4471
|
|
|
|
|
|
|
|
4472
|
1
|
|
|
1
|
|
4
|
sub lcfirst { return( __PACKAGE__->_new( CORE::lcfirst( ${$_[0]} ) ) ); } |
|
1
|
|
|
|
|
7
|
|
4473
|
|
|
|
|
|
|
|
4474
|
1
|
|
|
1
|
|
3
|
sub left { return( $_[0]->_new( CORE::substr( ${$_[0]}, 0, CORE::int( $_[1] ) ) ) ); } |
|
1
|
|
|
|
|
7
|
|
4475
|
|
|
|
|
|
|
|
4476
|
2
|
|
|
2
|
|
8
|
sub length { return( $_[0]->_number( CORE::length( ${$_[0]} ) ) ); } |
|
2
|
|
|
|
|
10
|
|
4477
|
|
|
|
|
|
|
|
4478
|
|
|
|
|
|
|
sub like |
4479
|
|
|
|
|
|
|
{ |
4480
|
1
|
|
|
1
|
|
4
|
my $self = shift( @_ ); |
4481
|
1
|
|
|
|
|
2
|
my $str = shift( @_ ); |
4482
|
1
|
50
|
|
|
|
8
|
$str = CORE::defined( $str ) |
|
|
50
|
|
|
|
|
|
4483
|
|
|
|
|
|
|
? ref( $str ) eq 'Regexp' |
4484
|
|
|
|
|
|
|
? $str |
4485
|
|
|
|
|
|
|
: qr/(?:\Q$str\E)+/ |
4486
|
|
|
|
|
|
|
: qr/[[:blank:]\r\n]*/; |
4487
|
1
|
|
|
|
|
15
|
return( $$self =~ /$str/ ); |
4488
|
|
|
|
|
|
|
} |
4489
|
|
|
|
|
|
|
|
4490
|
|
|
|
|
|
|
sub ltrim |
4491
|
|
|
|
|
|
|
{ |
4492
|
1
|
|
|
1
|
|
3
|
my $self = shift( @_ ); |
4493
|
1
|
|
|
|
|
3
|
my $str = shift( @_ ); |
4494
|
1
|
0
|
|
|
|
7
|
$str = CORE::defined( $str ) |
|
|
50
|
|
|
|
|
|
4495
|
|
|
|
|
|
|
? ref( $str ) eq 'Regexp' |
4496
|
|
|
|
|
|
|
? $str |
4497
|
|
|
|
|
|
|
: qr/(?:\Q$str\E)+/ |
4498
|
|
|
|
|
|
|
: qr/[[:blank:]\r\n]*/; |
4499
|
1
|
|
|
|
|
31
|
$$self =~ s/^$str//g; |
4500
|
1
|
|
|
|
|
8
|
return( $self ); |
4501
|
|
|
|
|
|
|
} |
4502
|
|
|
|
|
|
|
|
4503
|
|
|
|
|
|
|
sub match |
4504
|
|
|
|
|
|
|
{ |
4505
|
1
|
|
|
1
|
|
4
|
my( $self, $re ) = @_; |
4506
|
1
|
50
|
|
|
|
7
|
$re = CORE::defined( $re ) |
|
|
50
|
|
|
|
|
|
4507
|
|
|
|
|
|
|
? ref( $re ) eq 'Regexp' |
4508
|
|
|
|
|
|
|
? $re |
4509
|
|
|
|
|
|
|
: qr/(?:\Q$re\E)+/ |
4510
|
|
|
|
|
|
|
: $re; |
4511
|
1
|
|
|
|
|
13
|
return( $$self =~ /$re/ ); |
4512
|
|
|
|
|
|
|
} |
4513
|
|
|
|
|
|
|
|
4514
|
1
|
|
|
1
|
|
3
|
sub ord { return( $_[0]->_number( CORE::ord( ${$_[0]} ) ) ); } |
|
1
|
|
|
|
|
6
|
|
4515
|
|
|
|
|
|
|
|
4516
|
|
|
|
|
|
|
sub pad |
4517
|
|
|
|
|
|
|
{ |
4518
|
2
|
|
|
2
|
|
5
|
my $self = shift( @_ ); |
4519
|
2
|
|
|
|
|
6
|
my( $n, $str ) = @_; |
4520
|
2
|
|
50
|
|
|
8
|
$str //= ' '; |
4521
|
2
|
50
|
|
|
|
16
|
if( !CORE::length( $n ) ) |
|
|
50
|
|
|
|
|
|
4522
|
|
|
|
|
|
|
{ |
4523
|
0
|
0
|
|
|
|
0
|
warn( "No number provided to pad the string object.\n" ) if( $self->_warnings_is_enabled ); |
4524
|
|
|
|
|
|
|
} |
4525
|
|
|
|
|
|
|
elsif( $n !~ /^\-?\d+$/ ) |
4526
|
|
|
|
|
|
|
{ |
4527
|
0
|
0
|
|
|
|
0
|
warn( "Number provided \"$n\" to pad string is not an integer.\n" ) if( $self->_warnings_is_enabled ); |
4528
|
|
|
|
|
|
|
} |
4529
|
|
|
|
|
|
|
|
4530
|
2
|
100
|
|
|
|
8
|
if( $n < 0 ) |
4531
|
|
|
|
|
|
|
{ |
4532
|
1
|
|
|
|
|
6
|
$$self .= ( "$str" x CORE::abs( $n ) ); |
4533
|
|
|
|
|
|
|
} |
4534
|
|
|
|
|
|
|
else |
4535
|
|
|
|
|
|
|
{ |
4536
|
1
|
|
|
|
|
6
|
CORE::substr( $$self, 0, 0 ) = ( "$str" x $n ); |
4537
|
|
|
|
|
|
|
} |
4538
|
2
|
|
|
|
|
29
|
return( $self ); |
4539
|
|
|
|
|
|
|
} |
4540
|
|
|
|
|
|
|
|
4541
|
0
|
0
|
|
0
|
|
0
|
sub pos { return( $_[0]->_number( @_ > 1 ? ( CORE::pos( ${$_[0]} ) = $_[1] ) : CORE::pos( ${$_[0]} ) ) ); } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
4542
|
|
|
|
|
|
|
|
4543
|
1
|
|
|
1
|
|
3
|
sub quotemeta { return( __PACKAGE__->_new( CORE::quotemeta( ${$_[0]} ) ) ); } |
|
1
|
|
|
|
|
8
|
|
4544
|
|
|
|
|
|
|
|
4545
|
0
|
|
|
0
|
|
0
|
sub right { return( $_[0]->_new( CORE::substr( ${$_[0]}, ( CORE::int( $_[1] ) * -1 ) ) ) ); } |
|
0
|
|
|
|
|
0
|
|
4546
|
|
|
|
|
|
|
|
4547
|
|
|
|
|
|
|
sub replace |
4548
|
|
|
|
|
|
|
{ |
4549
|
4
|
|
|
4
|
|
678
|
my( $self, $re, $replacement ) = @_; |
4550
|
4
|
100
|
|
|
|
109
|
$re = CORE::defined( $re ) |
|
|
50
|
|
|
|
|
|
4551
|
|
|
|
|
|
|
? ref( $re ) eq 'Regexp' |
4552
|
|
|
|
|
|
|
? $re |
4553
|
|
|
|
|
|
|
: qr/(?:\Q$re\E)+/ |
4554
|
|
|
|
|
|
|
: $re; |
4555
|
4
|
|
|
|
|
76
|
return( $$self =~ s/$re/$replacement/gs ); |
4556
|
|
|
|
|
|
|
} |
4557
|
|
|
|
|
|
|
|
4558
|
1
|
|
|
1
|
|
5
|
sub reset { ${$_[0]} = ''; return( $_[0] ); } |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
5
|
|
4559
|
|
|
|
|
|
|
|
4560
|
1
|
|
|
1
|
|
12
|
sub reverse { return( __PACKAGE__->_new( CORE::scalar( CORE::reverse( ${$_[0]} ) ) ) ); } |
|
1
|
|
|
|
|
9
|
|
4561
|
|
|
|
|
|
|
|
4562
|
|
|
|
|
|
|
sub rindex |
4563
|
|
|
|
|
|
|
{ |
4564
|
2
|
|
|
2
|
|
7
|
my $self = shift( @_ ); |
4565
|
2
|
|
|
|
|
8
|
my( $substr, $pos ) = @_; |
4566
|
2
|
100
|
|
|
|
9
|
return( $self->_number( CORE::rindex( ${$self}, $substr, $pos ) ) ) if( CORE::defined( $pos ) ); |
|
1
|
|
|
|
|
7
|
|
4567
|
1
|
|
|
|
|
3
|
return( $self->_number( CORE::rindex( ${$self}, $substr ) ) ); |
|
1
|
|
|
|
|
6
|
|
4568
|
|
|
|
|
|
|
} |
4569
|
|
|
|
|
|
|
|
4570
|
|
|
|
|
|
|
sub rtrim |
4571
|
|
|
|
|
|
|
{ |
4572
|
1
|
|
|
1
|
|
3
|
my $self = shift( @_ ); |
4573
|
1
|
|
|
|
|
3
|
my $str = shift( @_ ); |
4574
|
1
|
50
|
|
|
|
37
|
$str = CORE::defined( $str ) |
|
|
50
|
|
|
|
|
|
4575
|
|
|
|
|
|
|
? ref( $str ) eq 'Regexp' |
4576
|
|
|
|
|
|
|
? $str |
4577
|
|
|
|
|
|
|
: qr/(?:\Q$str\E)+/ |
4578
|
|
|
|
|
|
|
: qr/[[:blank:]\r\n]*/; |
4579
|
1
|
|
|
|
|
18
|
$$self =~ s/${str}$//g; |
4580
|
1
|
|
|
|
|
7
|
return( $self ); |
4581
|
|
|
|
|
|
|
} |
4582
|
|
|
|
|
|
|
|
4583
|
872
|
|
|
872
|
|
2958
|
sub scalar { return( shift->as_string ); } |
4584
|
|
|
|
|
|
|
|
4585
|
|
|
|
|
|
|
sub set |
4586
|
|
|
|
|
|
|
{ |
4587
|
3435
|
|
|
3435
|
|
5181
|
my $self = CORE::shift( @_ ); |
4588
|
3435
|
|
|
|
|
4994
|
my $init; |
4589
|
3435
|
50
|
33
|
|
|
22738
|
if( ref( $_[0] ) eq 'SCALAR' || UNIVERSAL::isa( $_[0], 'SCALAR' ) ) |
|
|
50
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
4590
|
|
|
|
|
|
|
{ |
4591
|
0
|
|
|
|
|
0
|
$init = ${$_[0]}; |
|
0
|
|
|
|
|
0
|
|
4592
|
|
|
|
|
|
|
} |
4593
|
|
|
|
|
|
|
elsif( ref( $_[0] ) eq 'ARRAY' || UNIVERSAL::isa( $_[0], 'ARRAY' ) ) |
4594
|
|
|
|
|
|
|
{ |
4595
|
0
|
|
|
|
|
0
|
$init = CORE::join( '', @{$_[0]} ); |
|
0
|
|
|
|
|
0
|
|
4596
|
|
|
|
|
|
|
} |
4597
|
|
|
|
|
|
|
elsif( ref( $_[0] ) ) |
4598
|
|
|
|
|
|
|
{ |
4599
|
0
|
0
|
|
|
|
0
|
warn( "I do not know what to do with \"", $_[0], "\"\n" ) if( $self->_warnings_is_enabled ); |
4600
|
0
|
|
|
|
|
0
|
return; |
4601
|
|
|
|
|
|
|
} |
4602
|
|
|
|
|
|
|
else |
4603
|
|
|
|
|
|
|
{ |
4604
|
3435
|
|
|
|
|
5802
|
$init = shift( @_ ); |
4605
|
|
|
|
|
|
|
} |
4606
|
3435
|
|
|
|
|
5470
|
$$self = $init; |
4607
|
3435
|
|
|
|
|
5701
|
return( $self ); |
4608
|
|
|
|
|
|
|
} |
4609
|
|
|
|
|
|
|
|
4610
|
|
|
|
|
|
|
sub split |
4611
|
|
|
|
|
|
|
{ |
4612
|
2
|
|
|
2
|
|
18
|
my $self = CORE::shift( @_ ); |
4613
|
2
|
|
|
|
|
8
|
my( $expr, $limit ) = @_; |
4614
|
2
|
|
|
|
|
4
|
my $ref; |
4615
|
2
|
|
|
|
|
5
|
$limit = "$limit"; |
4616
|
2
|
50
|
33
|
|
|
15
|
if( CORE::defined( $limit ) && $limit =~ /^\d+$/ ) |
4617
|
|
|
|
|
|
|
{ |
4618
|
0
|
|
|
|
|
0
|
$ref = [ CORE::split( $expr, $$self, $limit ) ]; |
4619
|
|
|
|
|
|
|
} |
4620
|
|
|
|
|
|
|
else |
4621
|
|
|
|
|
|
|
{ |
4622
|
2
|
|
|
|
|
80
|
$ref = [ CORE::split( $expr, $$self ) ]; |
4623
|
|
|
|
|
|
|
} |
4624
|
2
|
50
|
33
|
|
|
15
|
if( Want::want( 'OBJECT' ) || |
|
|
0
|
|
|
|
|
|
4625
|
|
|
|
|
|
|
Want::want( 'SCALAR' ) ) |
4626
|
|
|
|
|
|
|
{ |
4627
|
2
|
|
|
|
|
281
|
rreturn( $self->_array( $ref ) ); |
4628
|
|
|
|
|
|
|
} |
4629
|
|
|
|
|
|
|
elsif( Want::want( 'LIST' ) ) |
4630
|
|
|
|
|
|
|
{ |
4631
|
0
|
|
|
|
|
0
|
rreturn( @$ref ); |
4632
|
|
|
|
|
|
|
} |
4633
|
0
|
|
|
|
|
0
|
return; |
4634
|
|
|
|
|
|
|
} |
4635
|
|
|
|
|
|
|
|
4636
|
1
|
|
|
1
|
|
3
|
sub sprintf { return( __PACKAGE__->_new( CORE::sprintf( ${$_[0]}, @_[1..$#_] ) ) ); } |
|
1
|
|
|
|
|
13
|
|
4637
|
|
|
|
|
|
|
|
4638
|
|
|
|
|
|
|
sub substr |
4639
|
|
|
|
|
|
|
{ |
4640
|
2
|
|
|
2
|
|
6
|
my $self = CORE::shift( @_ ); |
4641
|
2
|
|
|
|
|
7
|
my( $offset, $length, $replacement ) = @_; |
4642
|
2
|
100
|
66
|
|
|
17
|
return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset, $length, $replacement ) ) ) if( CORE::defined( $length ) && CORE::defined( $replacement ) ); |
|
1
|
|
|
|
|
7
|
|
4643
|
1
|
50
|
|
|
|
5
|
return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset, $length ) ) ) if( CORE::defined( $length ) ); |
|
1
|
|
|
|
|
6
|
|
4644
|
0
|
|
|
|
|
0
|
return( __PACKAGE__->_new( CORE::substr( ${$self}, $offset ) ) ); |
|
0
|
|
|
|
|
0
|
|
4645
|
|
|
|
|
|
|
} |
4646
|
|
|
|
|
|
|
|
4647
|
|
|
|
|
|
|
## The 3 dash here are just so my editor does not get confused with colouring |
4648
|
|
|
|
|
|
|
sub tr ### |
4649
|
|
|
|
|
|
|
{ |
4650
|
1
|
|
|
1
|
|
7
|
my $self = CORE::shift( @_ ); |
4651
|
1
|
|
|
|
|
4
|
my( $search, $replace, $opts ) = @_; |
4652
|
1
|
|
|
|
|
78
|
eval( "\$\$self =~ CORE::tr/$search/$replace/$opts" ); |
4653
|
1
|
|
|
|
|
7
|
return( $self ); |
4654
|
|
|
|
|
|
|
} |
4655
|
|
|
|
|
|
|
|
4656
|
|
|
|
|
|
|
sub trim |
4657
|
|
|
|
|
|
|
{ |
4658
|
2
|
|
|
2
|
|
7
|
my $self = shift( @_ ); |
4659
|
2
|
|
|
|
|
5
|
my $str = shift( @_ ); |
4660
|
2
|
50
|
|
|
|
27
|
$str = CORE::defined( $str ) ? CORE::quotemeta( $str ) : qr/[[:blank:]\r\n]*/; |
4661
|
2
|
|
|
|
|
81
|
$$self =~ s/^$str|$str$//gs; |
4662
|
2
|
|
|
|
|
13
|
return( $self ); |
4663
|
|
|
|
|
|
|
} |
4664
|
|
|
|
|
|
|
|
4665
|
2
|
|
|
2
|
|
5
|
sub uc { return( __PACKAGE__->_new( CORE::uc( ${$_[0]} ) ) ); } |
|
2
|
|
|
|
|
13
|
|
4666
|
|
|
|
|
|
|
|
4667
|
0
|
|
|
0
|
|
0
|
sub ucfirst { return( __PACKAGE__->_new( CORE::ucfirst( ${$_[0]} ) ) ); } |
|
0
|
|
|
|
|
0
|
|
4668
|
|
|
|
|
|
|
|
4669
|
|
|
|
|
|
|
sub undef |
4670
|
|
|
|
|
|
|
{ |
4671
|
1
|
|
|
1
|
|
5
|
my $self = shift( @_ ); |
4672
|
1
|
|
|
|
|
2
|
$$self = undef; |
4673
|
1
|
|
|
|
|
3
|
return( $self ); |
4674
|
|
|
|
|
|
|
} |
4675
|
|
|
|
|
|
|
|
4676
|
|
|
|
|
|
|
sub _array |
4677
|
|
|
|
|
|
|
{ |
4678
|
2
|
|
|
2
|
|
8
|
my $self = shift( @_ ); |
4679
|
2
|
|
|
|
|
4
|
my $arr = shift( @_ ); |
4680
|
2
|
50
|
|
|
|
9
|
return if( !defined( $arr ) ); |
4681
|
2
|
50
|
|
|
|
14
|
return( $arr ) if( Scalar::Util::reftype( $arr ) ne 'ARRAY' ); |
4682
|
2
|
|
|
|
|
20
|
return( Module::Generic::Array->new( $arr ) ); |
4683
|
|
|
|
|
|
|
} |
4684
|
|
|
|
|
|
|
|
4685
|
|
|
|
|
|
|
sub _number |
4686
|
|
|
|
|
|
|
{ |
4687
|
9
|
|
|
9
|
|
36
|
my $self = shift( @_ ); |
4688
|
9
|
|
|
|
|
25
|
my $num = shift( @_ ); |
4689
|
9
|
50
|
|
|
|
45
|
return if( !defined( $num ) ); |
4690
|
9
|
50
|
|
|
|
33
|
return( $num ) if( !CORE::length( $num ) ); |
4691
|
9
|
|
|
|
|
62
|
return( Module::Generic::Number->new( $num ) ); |
4692
|
|
|
|
|
|
|
} |
4693
|
|
|
|
|
|
|
|
4694
|
17
|
|
|
17
|
|
71
|
sub _new { return( shift->Module::Generic::Scalar::new( @_ ) ); } |
4695
|
|
|
|
|
|
|
|
4696
|
0
|
|
0
|
0
|
|
0
|
sub _warnings_is_enabled { return( warnings::enabled( ref( $_[0] ) || $_[0] ) ); } |
4697
|
|
|
|
|
|
|
|
4698
|
|
|
|
|
|
|
package Module::Generic::Number; |
4699
|
|
|
|
|
|
|
BEGIN |
4700
|
|
|
|
|
|
|
{ |
4701
|
6
|
|
|
6
|
|
60
|
use strict; |
|
6
|
|
|
|
|
46
|
|
|
6
|
|
|
|
|
240
|
|
4702
|
6
|
|
|
6
|
|
36
|
use parent -norequire, qw( Module::Generic ); |
|
6
|
|
|
|
|
27
|
|
|
6
|
|
|
|
|
46
|
|
4703
|
6
|
|
|
6
|
|
317
|
use warnings::register; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
672
|
|
4704
|
6
|
|
|
6
|
|
74
|
use Number::Format; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
287
|
|
4705
|
6
|
|
|
6
|
|
33
|
use Nice::Try; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
61
|
|
4706
|
6
|
|
|
6
|
|
23773448
|
use Regexp::Common qw( number ); |
|
6
|
|
|
|
|
14221
|
|
|
6
|
|
|
|
|
23
|
|
4707
|
6
|
|
|
6
|
|
16729
|
use POSIX (); |
|
6
|
|
|
|
|
18
|
|
|
6
|
|
|
|
|
177
|
|
4708
|
6
|
|
|
6
|
|
4716
|
our( $VERSION ) = 'v0.3.3'; |
4709
|
|
|
|
|
|
|
}; |
4710
|
|
|
|
|
|
|
|
4711
|
|
|
|
|
|
|
use overload ( |
4712
|
|
|
|
|
|
|
## I know there is the nomethod feature, but I need to provide return_object set to true or false |
4713
|
|
|
|
|
|
|
## And I do not necessarily want to catch all the operation. |
4714
|
55
|
|
|
55
|
|
13290
|
'""' => sub { return( shift->{_number} ); }, |
4715
|
3
|
|
|
3
|
|
49
|
'-' => sub { return( shift->compute( @_, { op => '-', return_object => 1 }) ); }, |
4716
|
5
|
|
|
5
|
|
65
|
'+' => sub { return( shift->compute( @_, { op => '+', return_object => 1 }) ); }, |
4717
|
3
|
|
|
3
|
|
49
|
'*' => sub { return( shift->compute( @_, { op => '*', return_object => 1 }) ); }, |
4718
|
4
|
|
|
4
|
|
70
|
'/' => sub { return( shift->compute( @_, { op => '/', return_object => 1 }) ); }, |
4719
|
2
|
|
|
2
|
|
30
|
'%' => sub { return( shift->compute( @_, { op => '%', return_object => 1 }) ); }, |
4720
|
|
|
|
|
|
|
## Exponent |
4721
|
3
|
|
|
3
|
|
46
|
'**' => sub { return( shift->compute( @_, { op => '**', return_object => 1 }) ); }, |
4722
|
|
|
|
|
|
|
## Bitwise AND |
4723
|
1
|
|
|
1
|
|
25
|
'&' => sub { return( shift->compute( @_, { op => '&', return_object => 1 }) ); }, |
4724
|
|
|
|
|
|
|
## Bitwise OR |
4725
|
1
|
|
|
1
|
|
17
|
'|' => sub { return( shift->compute( @_, { op => '|', return_object => 1 }) ); }, |
4726
|
|
|
|
|
|
|
## Bitwise XOR |
4727
|
1
|
|
|
1
|
|
9
|
'^' => sub { return( shift->compute( @_, { op => '^', return_object => 1 }) ); }, |
4728
|
|
|
|
|
|
|
## Bitwise shift left |
4729
|
1
|
|
|
1
|
|
23
|
'<<' => sub { return( shift->compute( @_, { op => '<<', return_object => 1 }) ); }, |
4730
|
|
|
|
|
|
|
## Bitwise shift right |
4731
|
1
|
|
|
1
|
|
19
|
'>>' => sub { return( shift->compute( @_, { op => '>>', return_object => 1 }) ); }, |
4732
|
1
|
|
|
1
|
|
19
|
'x' => sub { return( shift->compute( @_, { op => 'x', return_object => 1, type => 'scalar' }) ); }, |
4733
|
2
|
|
|
2
|
|
26
|
'+=' => sub { return( shift->compute( @_, { op => '+=', return_object => 1 }) ); }, |
4734
|
1
|
|
|
1
|
|
24
|
'-=' => sub { return( shift->compute( @_, { op => '-=', return_object => 1 }) ); }, |
4735
|
2
|
|
|
2
|
|
1198
|
'*=' => sub { return( shift->compute( @_, { op => '*=', return_object => 1 }) ); }, |
4736
|
1
|
|
|
1
|
|
22
|
'/=' => sub { return( shift->compute( @_, { op => '/=', return_object => 1 }) ); }, |
4737
|
1
|
|
|
1
|
|
19
|
'%=' => sub { return( shift->compute( @_, { op => '%=', return_object => 1 }) ); }, |
4738
|
1
|
|
|
1
|
|
36
|
'**=' => sub { return( shift->compute( @_, { op => '**=', return_object => 1 }) ); }, |
4739
|
1
|
|
|
1
|
|
21
|
'<<=' => sub { return( shift->compute( @_, { op => '<<=', return_object => 1 }) ); }, |
4740
|
1
|
|
|
1
|
|
25
|
'>>=' => sub { return( shift->compute( @_, { op => '>>=', return_object => 1 }) ); }, |
4741
|
1
|
|
|
1
|
|
20
|
'x=' => sub { return( shift->compute( @_, { op => 'x=', return_object => 1 }) ); }, |
4742
|
|
|
|
|
|
|
## '.=' => sub { return( shift->compute( @_, { op => '.=', return_object => 1 }) ); }, |
4743
|
|
|
|
|
|
|
'.=' => sub |
4744
|
|
|
|
|
|
|
{ |
4745
|
2
|
|
|
2
|
|
8
|
my( $self, $other, $swap ) = @_; |
4746
|
2
|
|
|
|
|
14
|
my $op = '.='; |
4747
|
2
|
50
|
|
|
|
26
|
my $operation = $swap ? "${other} ${op} \$self->{_number}" : "\$self->{_number} ${op} ${other}"; |
4748
|
2
|
|
|
|
|
142
|
my $res = eval( $operation ); |
4749
|
2
|
50
|
33
|
|
|
28
|
warn( "Error with formula \"$operation\": $@" ) if( $@ && $self->_warnings_is_enabled ); |
4750
|
2
|
50
|
|
|
|
9
|
return if( $@ ); |
4751
|
|
|
|
|
|
|
## Concatenated something. If it still look like a number, we return it as an object |
4752
|
2
|
100
|
|
|
|
17
|
if( $res =~ /^$RE{num}{real}$/ ) |
4753
|
|
|
|
|
|
|
{ |
4754
|
1
|
|
|
|
|
274
|
return( $self->clone( $res ) ); |
4755
|
|
|
|
|
|
|
} |
4756
|
|
|
|
|
|
|
## Otherwise we pass it to the scalar module |
4757
|
|
|
|
|
|
|
else |
4758
|
|
|
|
|
|
|
{ |
4759
|
1
|
|
|
|
|
182
|
return( Module::Generic::Scalar->new( "$res" ) ); |
4760
|
|
|
|
|
|
|
} |
4761
|
|
|
|
|
|
|
}, |
4762
|
2
|
|
|
2
|
|
22
|
'<' => sub { return( shift->compute( @_, { op => '<', boolean => 1 }) ); }, |
4763
|
2
|
|
|
2
|
|
26
|
'<=' => sub { return( shift->compute( @_, { op => '<=', boolean => 1 }) ); }, |
4764
|
1
|
|
|
1
|
|
26
|
'>' => sub { return( shift->compute( @_, { op => '>', boolean => 1 }) ); }, |
4765
|
1
|
|
|
1
|
|
20
|
'>=' => sub { return( shift->compute( @_, { op => '>=', boolean => 1 }) ); }, |
4766
|
3
|
|
|
3
|
|
25
|
'<=>' => sub { return( shift->compute( @_, { op => '<=>', return_object => 0 }) ); }, |
4767
|
6
|
|
|
6
|
|
70
|
'==' => sub { return( shift->compute( @_, { op => '==', boolean => 1 }) ); }, |
4768
|
7
|
|
|
7
|
|
75
|
'!=' => sub { return( shift->compute( @_, { op => '!=', boolean => 1 }) ); }, |
4769
|
81
|
|
|
81
|
|
34983
|
'eq' => sub { return( shift->compute( @_, { op => 'eq', boolean => 1 }) ); }, |
4770
|
1
|
|
|
1
|
|
16
|
'ne' => sub { return( shift->compute( @_, { op => 'ne', boolean => 1 }) ); }, |
4771
|
|
|
|
|
|
|
'++' => sub |
4772
|
|
|
|
|
|
|
{ |
4773
|
3
|
|
|
3
|
|
441
|
my( $self ) = @_; |
4774
|
3
|
|
|
|
|
21
|
return( ++$self->{_number} ); |
4775
|
|
|
|
|
|
|
}, |
4776
|
|
|
|
|
|
|
'--' => sub |
4777
|
|
|
|
|
|
|
{ |
4778
|
2
|
|
|
2
|
|
6
|
my( $self ) = @_; |
4779
|
2
|
|
|
|
|
17
|
return( --$self->{_number} ); |
4780
|
|
|
|
|
|
|
}, |
4781
|
6
|
|
|
|
|
256
|
'fallback' => 1, |
4782
|
6
|
|
|
6
|
|
45
|
); |
|
6
|
|
|
|
|
16
|
|
4783
|
|
|
|
|
|
|
|
4784
|
|
|
|
|
|
|
our $SUPPORTED_LOCALES = |
4785
|
|
|
|
|
|
|
{ |
4786
|
|
|
|
|
|
|
aa_DJ => [qw( aa_DJ.UTF-8 aa_DJ.ISO-8859-1 aa_DJ.ISO8859-1 )], |
4787
|
|
|
|
|
|
|
aa_ER => [qw( aa_ER.UTF-8 )], |
4788
|
|
|
|
|
|
|
aa_ET => [qw( aa_ET.UTF-8 )], |
4789
|
|
|
|
|
|
|
af_ZA => [qw( af_ZA.UTF-8 af_ZA.ISO-8859-1 af_ZA.ISO8859-1 )], |
4790
|
|
|
|
|
|
|
ak_GH => [qw( ak_GH.UTF-8 )], |
4791
|
|
|
|
|
|
|
am_ET => [qw( am_ET.UTF-8 )], |
4792
|
|
|
|
|
|
|
an_ES => [qw( an_ES.UTF-8 an_ES.ISO-8859-15 an_ES.ISO8859-15 )], |
4793
|
|
|
|
|
|
|
anp_IN => [qw( anp_IN.UTF-8 )], |
4794
|
|
|
|
|
|
|
ar_AE => [qw( ar_AE.UTF-8 ar_AE.ISO-8859-6 ar_AE.ISO8859-6 )], |
4795
|
|
|
|
|
|
|
ar_BH => [qw( ar_BH.UTF-8 ar_BH.ISO-8859-6 ar_BH.ISO8859-6 )], |
4796
|
|
|
|
|
|
|
ar_DZ => [qw( ar_DZ.UTF-8 ar_DZ.ISO-8859-6 ar_DZ.ISO8859-6 )], |
4797
|
|
|
|
|
|
|
ar_EG => [qw( ar_EG.UTF-8 ar_EG.ISO-8859-6 ar_EG.ISO8859-6 )], |
4798
|
|
|
|
|
|
|
ar_IN => [qw( ar_IN.UTF-8 )], |
4799
|
|
|
|
|
|
|
ar_IQ => [qw( ar_IQ.UTF-8 ar_IQ.ISO-8859-6 ar_IQ.ISO8859-6 )], |
4800
|
|
|
|
|
|
|
ar_JO => [qw( ar_JO.UTF-8 ar_JO.ISO-8859-6 ar_JO.ISO8859-6 )], |
4801
|
|
|
|
|
|
|
ar_KW => [qw( ar_KW.UTF-8 ar_KW.ISO-8859-6 ar_KW.ISO8859-6 )], |
4802
|
|
|
|
|
|
|
ar_LB => [qw( ar_LB.UTF-8 ar_LB.ISO-8859-6 ar_LB.ISO8859-6 )], |
4803
|
|
|
|
|
|
|
ar_LY => [qw( ar_LY.UTF-8 ar_LY.ISO-8859-6 ar_LY.ISO8859-6 )], |
4804
|
|
|
|
|
|
|
ar_MA => [qw( ar_MA.UTF-8 ar_MA.ISO-8859-6 ar_MA.ISO8859-6 )], |
4805
|
|
|
|
|
|
|
ar_OM => [qw( ar_OM.UTF-8 ar_OM.ISO-8859-6 ar_OM.ISO8859-6 )], |
4806
|
|
|
|
|
|
|
ar_QA => [qw( ar_QA.UTF-8 ar_QA.ISO-8859-6 ar_QA.ISO8859-6 )], |
4807
|
|
|
|
|
|
|
ar_SA => [qw( ar_SA.UTF-8 ar_SA.ISO-8859-6 ar_SA.ISO8859-6 )], |
4808
|
|
|
|
|
|
|
ar_SD => [qw( ar_SD.UTF-8 ar_SD.ISO-8859-6 ar_SD.ISO8859-6 )], |
4809
|
|
|
|
|
|
|
ar_SS => [qw( ar_SS.UTF-8 )], |
4810
|
|
|
|
|
|
|
ar_SY => [qw( ar_SY.UTF-8 ar_SY.ISO-8859-6 ar_SY.ISO8859-6 )], |
4811
|
|
|
|
|
|
|
ar_TN => [qw( ar_TN.UTF-8 ar_TN.ISO-8859-6 ar_TN.ISO8859-6 )], |
4812
|
|
|
|
|
|
|
ar_YE => [qw( ar_YE.UTF-8 ar_YE.ISO-8859-6 ar_YE.ISO8859-6 )], |
4813
|
|
|
|
|
|
|
as_IN => [qw( as_IN.UTF-8 )], |
4814
|
|
|
|
|
|
|
ast_ES => [qw( ast_ES.UTF-8 ast_ES.ISO-8859-15 ast_ES.ISO8859-15 )], |
4815
|
|
|
|
|
|
|
ayc_PE => [qw( ayc_PE.UTF-8 )], |
4816
|
|
|
|
|
|
|
az_AZ => [qw( az_AZ.UTF-8 )], |
4817
|
|
|
|
|
|
|
be_BY => [qw( be_BY.UTF-8 be_BY.CP1251 )], |
4818
|
|
|
|
|
|
|
bem_ZM => [qw( bem_ZM.UTF-8 )], |
4819
|
|
|
|
|
|
|
ber_DZ => [qw( ber_DZ.UTF-8 )], |
4820
|
|
|
|
|
|
|
ber_MA => [qw( ber_MA.UTF-8 )], |
4821
|
|
|
|
|
|
|
bg_BG => [qw( bg_BG.UTF-8 bg_BG.CP1251 )], |
4822
|
|
|
|
|
|
|
bhb_IN => [qw( bhb_IN.UTF-8 )], |
4823
|
|
|
|
|
|
|
bho_IN => [qw( bho_IN.UTF-8 )], |
4824
|
|
|
|
|
|
|
bn_BD => [qw( bn_BD.UTF-8 )], |
4825
|
|
|
|
|
|
|
bn_IN => [qw( bn_IN.UTF-8 )], |
4826
|
|
|
|
|
|
|
bo_CN => [qw( bo_CN.UTF-8 )], |
4827
|
|
|
|
|
|
|
bo_IN => [qw( bo_IN.UTF-8 )], |
4828
|
|
|
|
|
|
|
br_FR => [qw( br_FR.UTF-8 br_FR.ISO-8859-1 br_FR.ISO8859-1 br_FR.ISO-8859-15 br_FR.ISO8859-15 )], |
4829
|
|
|
|
|
|
|
brx_IN => [qw( brx_IN.UTF-8 )], |
4830
|
|
|
|
|
|
|
bs_BA => [qw( bs_BA.UTF-8 bs_BA.ISO-8859-2 bs_BA.ISO8859-2 )], |
4831
|
|
|
|
|
|
|
byn_ER => [qw( byn_ER.UTF-8 )], |
4832
|
|
|
|
|
|
|
ca_AD => [qw( ca_AD.UTF-8 ca_AD.ISO-8859-15 ca_AD.ISO8859-15 )], |
4833
|
|
|
|
|
|
|
ca_ES => [qw( ca_ES.UTF-8 ca_ES.ISO-8859-1 ca_ES.ISO8859-1 ca_ES.ISO-8859-15 ca_ES.ISO8859-15 )], |
4834
|
|
|
|
|
|
|
ca_FR => [qw( ca_FR.UTF-8 ca_FR.ISO-8859-15 ca_FR.ISO8859-15 )], |
4835
|
|
|
|
|
|
|
ca_IT => [qw( ca_IT.UTF-8 ca_IT.ISO-8859-15 ca_IT.ISO8859-15 )], |
4836
|
|
|
|
|
|
|
ce_RU => [qw( ce_RU.UTF-8 )], |
4837
|
|
|
|
|
|
|
ckb_IQ => [qw( ckb_IQ.UTF-8 )], |
4838
|
|
|
|
|
|
|
cmn_TW => [qw( cmn_TW.UTF-8 )], |
4839
|
|
|
|
|
|
|
crh_UA => [qw( crh_UA.UTF-8 )], |
4840
|
|
|
|
|
|
|
cs_CZ => [qw( cs_CZ.UTF-8 cs_CZ.ISO-8859-2 cs_CZ.ISO8859-2 )], |
4841
|
|
|
|
|
|
|
csb_PL => [qw( csb_PL.UTF-8 )], |
4842
|
|
|
|
|
|
|
cv_RU => [qw( cv_RU.UTF-8 )], |
4843
|
|
|
|
|
|
|
cy_GB => [qw( cy_GB.UTF-8 cy_GB.ISO-8859-14 cy_GB.ISO8859-14 )], |
4844
|
|
|
|
|
|
|
da_DK => [qw( da_DK.UTF-8 da_DK.ISO-8859-1 da_DK.ISO8859-1 )], |
4845
|
|
|
|
|
|
|
de_AT => [qw( de_AT.UTF-8 de_AT.ISO-8859-1 de_AT.ISO8859-1 de_AT.ISO-8859-15 de_AT.ISO8859-15 )], |
4846
|
|
|
|
|
|
|
de_BE => [qw( de_BE.UTF-8 de_BE.ISO-8859-1 de_BE.ISO8859-1 de_BE.ISO-8859-15 de_BE.ISO8859-15 )], |
4847
|
|
|
|
|
|
|
de_CH => [qw( de_CH.UTF-8 de_CH.ISO-8859-1 de_CH.ISO8859-1 )], |
4848
|
|
|
|
|
|
|
de_DE => [qw( de_DE.UTF-8 de_DE.ISO-8859-1 de_DE.ISO8859-1 de_DE.ISO-8859-15 de_DE.ISO8859-15 )], |
4849
|
|
|
|
|
|
|
de_LI => [qw( de_LI.UTF-8 )], |
4850
|
|
|
|
|
|
|
de_LU => [qw( de_LU.UTF-8 de_LU.ISO-8859-1 de_LU.ISO8859-1 de_LU.ISO-8859-15 de_LU.ISO8859-15 )], |
4851
|
|
|
|
|
|
|
doi_IN => [qw( doi_IN.UTF-8 )], |
4852
|
|
|
|
|
|
|
dv_MV => [qw( dv_MV.UTF-8 )], |
4853
|
|
|
|
|
|
|
dz_BT => [qw( dz_BT.UTF-8 )], |
4854
|
|
|
|
|
|
|
el_CY => [qw( el_CY.UTF-8 el_CY.ISO-8859-7 el_CY.ISO8859-7 )], |
4855
|
|
|
|
|
|
|
el_GR => [qw( el_GR.UTF-8 el_GR.ISO-8859-7 el_GR.ISO8859-7 )], |
4856
|
|
|
|
|
|
|
en_AG => [qw( en_AG.UTF-8 )], |
4857
|
|
|
|
|
|
|
en_AU => [qw( en_AU.UTF-8 en_AU.ISO-8859-1 en_AU.ISO8859-1 )], |
4858
|
|
|
|
|
|
|
en_BW => [qw( en_BW.UTF-8 en_BW.ISO-8859-1 en_BW.ISO8859-1 )], |
4859
|
|
|
|
|
|
|
en_CA => [qw( en_CA.UTF-8 en_CA.ISO-8859-1 en_CA.ISO8859-1 )], |
4860
|
|
|
|
|
|
|
en_DK => [qw( en_DK.UTF-8 en_DK.ISO-8859-15 en_DK.ISO8859-15 )], |
4861
|
|
|
|
|
|
|
en_GB => [qw( en_GB.UTF-8 en_GB.ISO-8859-1 en_GB.ISO8859-1 en_GB.ISO-8859-15 en_GB.ISO8859-15 )], |
4862
|
|
|
|
|
|
|
en_HK => [qw( en_HK.UTF-8 en_HK.ISO-8859-1 en_HK.ISO8859-1 )], |
4863
|
|
|
|
|
|
|
en_IE => [qw( en_IE.UTF-8 en_IE.ISO-8859-1 en_IE.ISO8859-1 en_IE.ISO-8859-15 en_IE.ISO8859-15 )], |
4864
|
|
|
|
|
|
|
en_IN => [qw( en_IN.UTF-8 )], |
4865
|
|
|
|
|
|
|
en_NG => [qw( en_NG.UTF-8 )], |
4866
|
|
|
|
|
|
|
en_NZ => [qw( en_NZ.UTF-8 en_NZ.ISO-8859-1 en_NZ.ISO8859-1 )], |
4867
|
|
|
|
|
|
|
en_PH => [qw( en_PH.UTF-8 en_PH.ISO-8859-1 en_PH.ISO8859-1 )], |
4868
|
|
|
|
|
|
|
en_SG => [qw( en_SG.UTF-8 en_SG.ISO-8859-1 en_SG.ISO8859-1 )], |
4869
|
|
|
|
|
|
|
en_US => [qw( en_US.UTF-8 en_US.ISO-8859-1 en_US.ISO8859-1 en_US.ISO-8859-15 en_US.ISO8859-15 )], |
4870
|
|
|
|
|
|
|
en_ZA => [qw( en_ZA.UTF-8 en_ZA.ISO-8859-1 en_ZA.ISO8859-1 )], |
4871
|
|
|
|
|
|
|
en_ZM => [qw( en_ZM.UTF-8 )], |
4872
|
|
|
|
|
|
|
en_ZW => [qw( en_ZW.UTF-8 en_ZW.ISO-8859-1 en_ZW.ISO8859-1 )], |
4873
|
|
|
|
|
|
|
eo => [qw( eo.UTF-8 eo.ISO-8859-3 eo.ISO8859-3 )], |
4874
|
|
|
|
|
|
|
eo_US => [qw( eo_US.UTF-8 )], |
4875
|
|
|
|
|
|
|
es_AR => [qw( es_AR.UTF-8 es_AR.ISO-8859-1 es_AR.ISO8859-1 )], |
4876
|
|
|
|
|
|
|
es_BO => [qw( es_BO.UTF-8 es_BO.ISO-8859-1 es_BO.ISO8859-1 )], |
4877
|
|
|
|
|
|
|
es_CL => [qw( es_CL.UTF-8 es_CL.ISO-8859-1 es_CL.ISO8859-1 )], |
4878
|
|
|
|
|
|
|
es_CO => [qw( es_CO.UTF-8 es_CO.ISO-8859-1 es_CO.ISO8859-1 )], |
4879
|
|
|
|
|
|
|
es_CR => [qw( es_CR.UTF-8 es_CR.ISO-8859-1 es_CR.ISO8859-1 )], |
4880
|
|
|
|
|
|
|
es_CU => [qw( es_CU.UTF-8 )], |
4881
|
|
|
|
|
|
|
es_DO => [qw( es_DO.UTF-8 es_DO.ISO-8859-1 es_DO.ISO8859-1 )], |
4882
|
|
|
|
|
|
|
es_EC => [qw( es_EC.UTF-8 es_EC.ISO-8859-1 es_EC.ISO8859-1 )], |
4883
|
|
|
|
|
|
|
es_ES => [qw( es_ES.UTF-8 es_ES.ISO-8859-1 es_ES.ISO8859-1 es_ES.ISO-8859-15 es_ES.ISO8859-15 )], |
4884
|
|
|
|
|
|
|
es_GT => [qw( es_GT.UTF-8 es_GT.ISO-8859-1 es_GT.ISO8859-1 )], |
4885
|
|
|
|
|
|
|
es_HN => [qw( es_HN.UTF-8 es_HN.ISO-8859-1 es_HN.ISO8859-1 )], |
4886
|
|
|
|
|
|
|
es_MX => [qw( es_MX.UTF-8 es_MX.ISO-8859-1 es_MX.ISO8859-1 )], |
4887
|
|
|
|
|
|
|
es_NI => [qw( es_NI.UTF-8 es_NI.ISO-8859-1 es_NI.ISO8859-1 )], |
4888
|
|
|
|
|
|
|
es_PA => [qw( es_PA.UTF-8 es_PA.ISO-8859-1 es_PA.ISO8859-1 )], |
4889
|
|
|
|
|
|
|
es_PE => [qw( es_PE.UTF-8 es_PE.ISO-8859-1 es_PE.ISO8859-1 )], |
4890
|
|
|
|
|
|
|
es_PR => [qw( es_PR.UTF-8 es_PR.ISO-8859-1 es_PR.ISO8859-1 )], |
4891
|
|
|
|
|
|
|
es_PY => [qw( es_PY.UTF-8 es_PY.ISO-8859-1 es_PY.ISO8859-1 )], |
4892
|
|
|
|
|
|
|
es_SV => [qw( es_SV.UTF-8 es_SV.ISO-8859-1 es_SV.ISO8859-1 )], |
4893
|
|
|
|
|
|
|
es_US => [qw( es_US.UTF-8 es_US.ISO-8859-1 es_US.ISO8859-1 )], |
4894
|
|
|
|
|
|
|
es_UY => [qw( es_UY.UTF-8 es_UY.ISO-8859-1 es_UY.ISO8859-1 )], |
4895
|
|
|
|
|
|
|
es_VE => [qw( es_VE.UTF-8 es_VE.ISO-8859-1 es_VE.ISO8859-1 )], |
4896
|
|
|
|
|
|
|
et_EE => [qw( et_EE.UTF-8 et_EE.ISO-8859-1 et_EE.ISO8859-1 et_EE.ISO-8859-15 et_EE.ISO8859-15 )], |
4897
|
|
|
|
|
|
|
eu_ES => [qw( eu_ES.UTF-8 eu_ES.ISO-8859-1 eu_ES.ISO8859-1 eu_ES.ISO-8859-15 eu_ES.ISO8859-15 )], |
4898
|
|
|
|
|
|
|
eu_FR => [qw( eu_FR.UTF-8 eu_FR.ISO-8859-1 eu_FR.ISO8859-1 eu_FR.ISO-8859-15 eu_FR.ISO8859-15 )], |
4899
|
|
|
|
|
|
|
fa_IR => [qw( fa_IR.UTF-8 )], |
4900
|
|
|
|
|
|
|
ff_SN => [qw( ff_SN.UTF-8 )], |
4901
|
|
|
|
|
|
|
fi_FI => [qw( fi_FI.UTF-8 fi_FI.ISO-8859-1 fi_FI.ISO8859-1 fi_FI.ISO-8859-15 fi_FI.ISO8859-15 )], |
4902
|
|
|
|
|
|
|
fil_PH => [qw( fil_PH.UTF-8 )], |
4903
|
|
|
|
|
|
|
fo_FO => [qw( fo_FO.UTF-8 fo_FO.ISO-8859-1 fo_FO.ISO8859-1 )], |
4904
|
|
|
|
|
|
|
fr_BE => [qw( fr_BE.UTF-8 fr_BE.ISO-8859-1 fr_BE.ISO8859-1 fr_BE.ISO-8859-15 fr_BE.ISO8859-15 )], |
4905
|
|
|
|
|
|
|
fr_CA => [qw( fr_CA.UTF-8 fr_CA.ISO-8859-1 fr_CA.ISO8859-1 )], |
4906
|
|
|
|
|
|
|
fr_CH => [qw( fr_CH.UTF-8 fr_CH.ISO-8859-1 fr_CH.ISO8859-1 )], |
4907
|
|
|
|
|
|
|
fr_FR => [qw( fr_FR.UTF-8 fr_FR.ISO-8859-1 fr_FR.ISO8859-1 fr_FR.ISO-8859-15 fr_FR.ISO8859-15 )], |
4908
|
|
|
|
|
|
|
fr_LU => [qw( fr_LU.UTF-8 fr_LU.ISO-8859-1 fr_LU.ISO8859-1 fr_LU.ISO-8859-15 fr_LU.ISO8859-15 )], |
4909
|
|
|
|
|
|
|
fur_IT => [qw( fur_IT.UTF-8 )], |
4910
|
|
|
|
|
|
|
fy_DE => [qw( fy_DE.UTF-8 )], |
4911
|
|
|
|
|
|
|
fy_NL => [qw( fy_NL.UTF-8 )], |
4912
|
|
|
|
|
|
|
ga_IE => [qw( ga_IE.UTF-8 ga_IE.ISO-8859-1 ga_IE.ISO8859-1 ga_IE.ISO-8859-15 ga_IE.ISO8859-15 )], |
4913
|
|
|
|
|
|
|
gd_GB => [qw( gd_GB.UTF-8 gd_GB.ISO-8859-15 gd_GB.ISO8859-15 )], |
4914
|
|
|
|
|
|
|
gez_ER => [qw( gez_ER.UTF-8 )], |
4915
|
|
|
|
|
|
|
gez_ET => [qw( gez_ET.UTF-8 )], |
4916
|
|
|
|
|
|
|
gl_ES => [qw( gl_ES.UTF-8 gl_ES.ISO-8859-1 gl_ES.ISO8859-1 gl_ES.ISO-8859-15 gl_ES.ISO8859-15 )], |
4917
|
|
|
|
|
|
|
gu_IN => [qw( gu_IN.UTF-8 )], |
4918
|
|
|
|
|
|
|
gv_GB => [qw( gv_GB.UTF-8 gv_GB.ISO-8859-1 gv_GB.ISO8859-1 )], |
4919
|
|
|
|
|
|
|
ha_NG => [qw( ha_NG.UTF-8 )], |
4920
|
|
|
|
|
|
|
hak_TW => [qw( hak_TW.UTF-8 )], |
4921
|
|
|
|
|
|
|
he_IL => [qw( he_IL.UTF-8 he_IL.ISO-8859-8 he_IL.ISO8859-8 )], |
4922
|
|
|
|
|
|
|
hi_IN => [qw( hi_IN.UTF-8 )], |
4923
|
|
|
|
|
|
|
hne_IN => [qw( hne_IN.UTF-8 )], |
4924
|
|
|
|
|
|
|
hr_HR => [qw( hr_HR.UTF-8 hr_HR.ISO-8859-2 hr_HR.ISO8859-2 )], |
4925
|
|
|
|
|
|
|
hsb_DE => [qw( hsb_DE.UTF-8 hsb_DE.ISO-8859-2 hsb_DE.ISO8859-2 )], |
4926
|
|
|
|
|
|
|
ht_HT => [qw( ht_HT.UTF-8 )], |
4927
|
|
|
|
|
|
|
hu_HU => [qw( hu_HU.UTF-8 hu_HU.ISO-8859-2 hu_HU.ISO8859-2 )], |
4928
|
|
|
|
|
|
|
hy_AM => [qw( hy_AM.UTF-8 hy_AM.ARMSCII-8 hy_AM.ARMSCII8 )], |
4929
|
|
|
|
|
|
|
ia_FR => [qw( ia_FR.UTF-8 )], |
4930
|
|
|
|
|
|
|
id_ID => [qw( id_ID.UTF-8 id_ID.ISO-8859-1 id_ID.ISO8859-1 )], |
4931
|
|
|
|
|
|
|
ig_NG => [qw( ig_NG.UTF-8 )], |
4932
|
|
|
|
|
|
|
ik_CA => [qw( ik_CA.UTF-8 )], |
4933
|
|
|
|
|
|
|
is_IS => [qw( is_IS.UTF-8 is_IS.ISO-8859-1 is_IS.ISO8859-1 )], |
4934
|
|
|
|
|
|
|
it_CH => [qw( it_CH.UTF-8 it_CH.ISO-8859-1 it_CH.ISO8859-1 )], |
4935
|
|
|
|
|
|
|
it_IT => [qw( it_IT.UTF-8 it_IT.ISO-8859-1 it_IT.ISO8859-1 it_IT.ISO-8859-15 it_IT.ISO8859-15 )], |
4936
|
|
|
|
|
|
|
iu_CA => [qw( iu_CA.UTF-8 )], |
4937
|
|
|
|
|
|
|
iw_IL => [qw( iw_IL.UTF-8 iw_IL.ISO-8859-8 iw_IL.ISO8859-8 )], |
4938
|
|
|
|
|
|
|
ja_JP => [qw( ja_JP.UTF-8 ja_JP.EUC-JP ja_JP.EUCJP )], |
4939
|
|
|
|
|
|
|
ka_GE => [qw( ka_GE.UTF-8 ka_GE.GEORGIAN-PS ka_GE.GEORGIANPS )], |
4940
|
|
|
|
|
|
|
kk_KZ => [qw( kk_KZ.UTF-8 kk_KZ.PT154 kk_KZ.RK1048 )], |
4941
|
|
|
|
|
|
|
kl_GL => [qw( kl_GL.UTF-8 kl_GL.ISO-8859-1 kl_GL.ISO8859-1 )], |
4942
|
|
|
|
|
|
|
km_KH => [qw( km_KH.UTF-8 )], |
4943
|
|
|
|
|
|
|
kn_IN => [qw( kn_IN.UTF-8 )], |
4944
|
|
|
|
|
|
|
ko_KR => [qw( ko_KR.UTF-8 ko_KR.EUC-KR ko_KR.EUCKR )], |
4945
|
|
|
|
|
|
|
kok_IN => [qw( kok_IN.UTF-8 )], |
4946
|
|
|
|
|
|
|
ks_IN => [qw( ks_IN.UTF-8 )], |
4947
|
|
|
|
|
|
|
ku_TR => [qw( ku_TR.UTF-8 ku_TR.ISO-8859-9 ku_TR.ISO8859-9 )], |
4948
|
|
|
|
|
|
|
kw_GB => [qw( kw_GB.UTF-8 kw_GB.ISO-8859-1 kw_GB.ISO8859-1 )], |
4949
|
|
|
|
|
|
|
ky_KG => [qw( ky_KG.UTF-8 )], |
4950
|
|
|
|
|
|
|
lb_LU => [qw( lb_LU.UTF-8 )], |
4951
|
|
|
|
|
|
|
lg_UG => [qw( lg_UG.UTF-8 lg_UG.ISO-8859-10 lg_UG.ISO8859-10 )], |
4952
|
|
|
|
|
|
|
li_BE => [qw( li_BE.UTF-8 )], |
4953
|
|
|
|
|
|
|
li_NL => [qw( li_NL.UTF-8 )], |
4954
|
|
|
|
|
|
|
lij_IT => [qw( lij_IT.UTF-8 )], |
4955
|
|
|
|
|
|
|
ln_CD => [qw( ln_CD.UTF-8 )], |
4956
|
|
|
|
|
|
|
lo_LA => [qw( lo_LA.UTF-8 )], |
4957
|
|
|
|
|
|
|
lt_LT => [qw( lt_LT.UTF-8 lt_LT.ISO-8859-13 lt_LT.ISO8859-13 )], |
4958
|
|
|
|
|
|
|
lv_LV => [qw( lv_LV.UTF-8 lv_LV.ISO-8859-13 lv_LV.ISO8859-13 )], |
4959
|
|
|
|
|
|
|
lzh_TW => [qw( lzh_TW.UTF-8 )], |
4960
|
|
|
|
|
|
|
mag_IN => [qw( mag_IN.UTF-8 )], |
4961
|
|
|
|
|
|
|
mai_IN => [qw( mai_IN.UTF-8 )], |
4962
|
|
|
|
|
|
|
mg_MG => [qw( mg_MG.UTF-8 mg_MG.ISO-8859-15 mg_MG.ISO8859-15 )], |
4963
|
|
|
|
|
|
|
mhr_RU => [qw( mhr_RU.UTF-8 )], |
4964
|
|
|
|
|
|
|
mi_NZ => [qw( mi_NZ.UTF-8 mi_NZ.ISO-8859-13 mi_NZ.ISO8859-13 )], |
4965
|
|
|
|
|
|
|
mk_MK => [qw( mk_MK.UTF-8 mk_MK.ISO-8859-5 mk_MK.ISO8859-5 )], |
4966
|
|
|
|
|
|
|
ml_IN => [qw( ml_IN.UTF-8 )], |
4967
|
|
|
|
|
|
|
mn_MN => [qw( mn_MN.UTF-8 )], |
4968
|
|
|
|
|
|
|
mni_IN => [qw( mni_IN.UTF-8 )], |
4969
|
|
|
|
|
|
|
mr_IN => [qw( mr_IN.UTF-8 )], |
4970
|
|
|
|
|
|
|
ms_MY => [qw( ms_MY.UTF-8 ms_MY.ISO-8859-1 ms_MY.ISO8859-1 )], |
4971
|
|
|
|
|
|
|
mt_MT => [qw( mt_MT.UTF-8 mt_MT.ISO-8859-3 mt_MT.ISO8859-3 )], |
4972
|
|
|
|
|
|
|
my_MM => [qw( my_MM.UTF-8 )], |
4973
|
|
|
|
|
|
|
nan_TW => [qw( nan_TW.UTF-8 )], |
4974
|
|
|
|
|
|
|
nb_NO => [qw( nb_NO.UTF-8 nb_NO.ISO-8859-1 nb_NO.ISO8859-1 )], |
4975
|
|
|
|
|
|
|
nds_DE => [qw( nds_DE.UTF-8 )], |
4976
|
|
|
|
|
|
|
nds_NL => [qw( nds_NL.UTF-8 )], |
4977
|
|
|
|
|
|
|
ne_NP => [qw( ne_NP.UTF-8 )], |
4978
|
|
|
|
|
|
|
nhn_MX => [qw( nhn_MX.UTF-8 )], |
4979
|
|
|
|
|
|
|
niu_NU => [qw( niu_NU.UTF-8 )], |
4980
|
|
|
|
|
|
|
niu_NZ => [qw( niu_NZ.UTF-8 )], |
4981
|
|
|
|
|
|
|
nl_AW => [qw( nl_AW.UTF-8 )], |
4982
|
|
|
|
|
|
|
nl_BE => [qw( nl_BE.UTF-8 nl_BE.ISO-8859-1 nl_BE.ISO8859-1 nl_BE.ISO-8859-15 nl_BE.ISO8859-15 )], |
4983
|
|
|
|
|
|
|
nl_NL => [qw( nl_NL.UTF-8 nl_NL.ISO-8859-1 nl_NL.ISO8859-1 nl_NL.ISO-8859-15 nl_NL.ISO8859-15 )], |
4984
|
|
|
|
|
|
|
nn_NO => [qw( nn_NO.UTF-8 nn_NO.ISO-8859-1 nn_NO.ISO8859-1 )], |
4985
|
|
|
|
|
|
|
nr_ZA => [qw( nr_ZA.UTF-8 )], |
4986
|
|
|
|
|
|
|
nso_ZA => [qw( nso_ZA.UTF-8 )], |
4987
|
|
|
|
|
|
|
oc_FR => [qw( oc_FR.UTF-8 oc_FR.ISO-8859-1 oc_FR.ISO8859-1 )], |
4988
|
|
|
|
|
|
|
om_ET => [qw( om_ET.UTF-8 )], |
4989
|
|
|
|
|
|
|
om_KE => [qw( om_KE.UTF-8 om_KE.ISO-8859-1 om_KE.ISO8859-1 )], |
4990
|
|
|
|
|
|
|
or_IN => [qw( or_IN.UTF-8 )], |
4991
|
|
|
|
|
|
|
os_RU => [qw( os_RU.UTF-8 )], |
4992
|
|
|
|
|
|
|
pa_IN => [qw( pa_IN.UTF-8 )], |
4993
|
|
|
|
|
|
|
pa_PK => [qw( pa_PK.UTF-8 )], |
4994
|
|
|
|
|
|
|
pap_AN => [qw( pap_AN.UTF-8 )], |
4995
|
|
|
|
|
|
|
pap_AW => [qw( pap_AW.UTF-8 )], |
4996
|
|
|
|
|
|
|
pap_CW => [qw( pap_CW.UTF-8 )], |
4997
|
|
|
|
|
|
|
pl_PL => [qw( pl_PL.UTF-8 pl_PL.ISO-8859-2 pl_PL.ISO8859-2 )], |
4998
|
|
|
|
|
|
|
ps_AF => [qw( ps_AF.UTF-8 )], |
4999
|
|
|
|
|
|
|
pt_BR => [qw( pt_BR.UTF-8 pt_BR.ISO-8859-1 pt_BR.ISO8859-1 )], |
5000
|
|
|
|
|
|
|
pt_PT => [qw( pt_PT.UTF-8 pt_PT.ISO-8859-1 pt_PT.ISO8859-1 pt_PT.ISO-8859-15 pt_PT.ISO8859-15 )], |
5001
|
|
|
|
|
|
|
quz_PE => [qw( quz_PE.UTF-8 )], |
5002
|
|
|
|
|
|
|
raj_IN => [qw( raj_IN.UTF-8 )], |
5003
|
|
|
|
|
|
|
ro_RO => [qw( ro_RO.UTF-8 ro_RO.ISO-8859-2 ro_RO.ISO8859-2 )], |
5004
|
|
|
|
|
|
|
ru_RU => [qw( ru_RU.UTF-8 ru_RU.KOI8-R ru_RU.KOI8R ru_RU.ISO-8859-5 ru_RU.ISO8859-5 ru_RU.CP1251 )], |
5005
|
|
|
|
|
|
|
ru_UA => [qw( ru_UA.UTF-8 ru_UA.KOI8-U ru_UA.KOI8U )], |
5006
|
|
|
|
|
|
|
rw_RW => [qw( rw_RW.UTF-8 )], |
5007
|
|
|
|
|
|
|
sa_IN => [qw( sa_IN.UTF-8 )], |
5008
|
|
|
|
|
|
|
sat_IN => [qw( sat_IN.UTF-8 )], |
5009
|
|
|
|
|
|
|
sc_IT => [qw( sc_IT.UTF-8 )], |
5010
|
|
|
|
|
|
|
sd_IN => [qw( sd_IN.UTF-8 )], |
5011
|
|
|
|
|
|
|
sd_PK => [qw( sd_PK.UTF-8 )], |
5012
|
|
|
|
|
|
|
se_NO => [qw( se_NO.UTF-8 )], |
5013
|
|
|
|
|
|
|
shs_CA => [qw( shs_CA.UTF-8 )], |
5014
|
|
|
|
|
|
|
si_LK => [qw( si_LK.UTF-8 )], |
5015
|
|
|
|
|
|
|
sid_ET => [qw( sid_ET.UTF-8 )], |
5016
|
|
|
|
|
|
|
sk_SK => [qw( sk_SK.UTF-8 sk_SK.ISO-8859-2 sk_SK.ISO8859-2 )], |
5017
|
|
|
|
|
|
|
sl_SI => [qw( sl_SI.UTF-8 sl_SI.ISO-8859-2 sl_SI.ISO8859-2 )], |
5018
|
|
|
|
|
|
|
so_DJ => [qw( so_DJ.UTF-8 so_DJ.ISO-8859-1 so_DJ.ISO8859-1 )], |
5019
|
|
|
|
|
|
|
so_ET => [qw( so_ET.UTF-8 )], |
5020
|
|
|
|
|
|
|
so_KE => [qw( so_KE.UTF-8 so_KE.ISO-8859-1 so_KE.ISO8859-1 )], |
5021
|
|
|
|
|
|
|
so_SO => [qw( so_SO.UTF-8 so_SO.ISO-8859-1 so_SO.ISO8859-1 )], |
5022
|
|
|
|
|
|
|
sq_AL => [qw( sq_AL.UTF-8 sq_AL.ISO-8859-1 sq_AL.ISO8859-1 )], |
5023
|
|
|
|
|
|
|
sq_MK => [qw( sq_MK.UTF-8 )], |
5024
|
|
|
|
|
|
|
sr_ME => [qw( sr_ME.UTF-8 )], |
5025
|
|
|
|
|
|
|
sr_RS => [qw( sr_RS.UTF-8 )], |
5026
|
|
|
|
|
|
|
ss_ZA => [qw( ss_ZA.UTF-8 )], |
5027
|
|
|
|
|
|
|
st_ZA => [qw( st_ZA.UTF-8 st_ZA.ISO-8859-1 st_ZA.ISO8859-1 )], |
5028
|
|
|
|
|
|
|
sv_FI => [qw( sv_FI.UTF-8 sv_FI.ISO-8859-1 sv_FI.ISO8859-1 sv_FI.ISO-8859-15 sv_FI.ISO8859-15 )], |
5029
|
|
|
|
|
|
|
sv_SE => [qw( sv_SE.UTF-8 sv_SE.ISO-8859-1 sv_SE.ISO8859-1 sv_SE.ISO-8859-15 sv_SE.ISO8859-15 )], |
5030
|
|
|
|
|
|
|
sw_KE => [qw( sw_KE.UTF-8 )], |
5031
|
|
|
|
|
|
|
sw_TZ => [qw( sw_TZ.UTF-8 )], |
5032
|
|
|
|
|
|
|
szl_PL => [qw( szl_PL.UTF-8 )], |
5033
|
|
|
|
|
|
|
ta_IN => [qw( ta_IN.UTF-8 )], |
5034
|
|
|
|
|
|
|
ta_LK => [qw( ta_LK.UTF-8 )], |
5035
|
|
|
|
|
|
|
tcy_IN => [qw( tcy_IN.UTF-8 )], |
5036
|
|
|
|
|
|
|
te_IN => [qw( te_IN.UTF-8 )], |
5037
|
|
|
|
|
|
|
tg_TJ => [qw( tg_TJ.UTF-8 tg_TJ.KOI8-T tg_TJ.KOI8T )], |
5038
|
|
|
|
|
|
|
th_TH => [qw( th_TH.UTF-8 th_TH.TIS-620 th_TH.TIS620 )], |
5039
|
|
|
|
|
|
|
the_NP => [qw( the_NP.UTF-8 )], |
5040
|
|
|
|
|
|
|
ti_ER => [qw( ti_ER.UTF-8 )], |
5041
|
|
|
|
|
|
|
ti_ET => [qw( ti_ET.UTF-8 )], |
5042
|
|
|
|
|
|
|
tig_ER => [qw( tig_ER.UTF-8 )], |
5043
|
|
|
|
|
|
|
tk_TM => [qw( tk_TM.UTF-8 )], |
5044
|
|
|
|
|
|
|
tl_PH => [qw( tl_PH.UTF-8 tl_PH.ISO-8859-1 tl_PH.ISO8859-1 )], |
5045
|
|
|
|
|
|
|
tn_ZA => [qw( tn_ZA.UTF-8 )], |
5046
|
|
|
|
|
|
|
tr_CY => [qw( tr_CY.UTF-8 tr_CY.ISO-8859-9 tr_CY.ISO8859-9 )], |
5047
|
|
|
|
|
|
|
tr_TR => [qw( tr_TR.UTF-8 tr_TR.ISO-8859-9 tr_TR.ISO8859-9 )], |
5048
|
|
|
|
|
|
|
ts_ZA => [qw( ts_ZA.UTF-8 )], |
5049
|
|
|
|
|
|
|
tt_RU => [qw( tt_RU.UTF-8 )], |
5050
|
|
|
|
|
|
|
ug_CN => [qw( ug_CN.UTF-8 )], |
5051
|
|
|
|
|
|
|
uk_UA => [qw( uk_UA.UTF-8 uk_UA.KOI8-U uk_UA.KOI8U )], |
5052
|
|
|
|
|
|
|
unm_US => [qw( unm_US.UTF-8 )], |
5053
|
|
|
|
|
|
|
ur_IN => [qw( ur_IN.UTF-8 )], |
5054
|
|
|
|
|
|
|
ur_PK => [qw( ur_PK.UTF-8 )], |
5055
|
|
|
|
|
|
|
uz_UZ => [qw( uz_UZ.UTF-8 uz_UZ.ISO-8859-1 uz_UZ.ISO8859-1 )], |
5056
|
|
|
|
|
|
|
ve_ZA => [qw( ve_ZA.UTF-8 )], |
5057
|
|
|
|
|
|
|
vi_VN => [qw( vi_VN.UTF-8 )], |
5058
|
|
|
|
|
|
|
wa_BE => [qw( wa_BE.UTF-8 wa_BE.ISO-8859-1 wa_BE.ISO8859-1 wa_BE.ISO-8859-15 wa_BE.ISO8859-15 )], |
5059
|
|
|
|
|
|
|
wae_CH => [qw( wae_CH.UTF-8 )], |
5060
|
|
|
|
|
|
|
wal_ET => [qw( wal_ET.UTF-8 )], |
5061
|
|
|
|
|
|
|
wo_SN => [qw( wo_SN.UTF-8 )], |
5062
|
|
|
|
|
|
|
xh_ZA => [qw( xh_ZA.UTF-8 xh_ZA.ISO-8859-1 xh_ZA.ISO8859-1 )], |
5063
|
|
|
|
|
|
|
yi_US => [qw( yi_US.UTF-8 yi_US.CP1255 )], |
5064
|
|
|
|
|
|
|
yo_NG => [qw( yo_NG.UTF-8 )], |
5065
|
|
|
|
|
|
|
yue_HK => [qw( yue_HK.UTF-8 )], |
5066
|
|
|
|
|
|
|
zh_CN => [qw( zh_CN.UTF-8 zh_CN.GB18030 zh_CN.GBK zh_CN.GB2312 )], |
5067
|
|
|
|
|
|
|
zh_HK => [qw( zh_HK.UTF-8 zh_HK.BIG5-HKSCS zh_HK.BIG5HKSCS )], |
5068
|
|
|
|
|
|
|
zh_SG => [qw( zh_SG.UTF-8 zh_SG.GBK zh_SG.GB2312 )], |
5069
|
|
|
|
|
|
|
zh_TW => [qw( zh_TW.UTF-8 zh_TW.EUC-TW zh_TW.EUCTW zh_TW.BIG5 )], |
5070
|
|
|
|
|
|
|
zu_ZA => [qw( zu_ZA.UTF-8 zu_ZA.ISO-8859-1 zu_ZA.ISO8859-1 )], |
5071
|
|
|
|
|
|
|
}; |
5072
|
|
|
|
|
|
|
|
5073
|
|
|
|
|
|
|
our $DEFAULT = |
5074
|
|
|
|
|
|
|
{ |
5075
|
|
|
|
|
|
|
## The local currency symbol. |
5076
|
|
|
|
|
|
|
currency_symbol => '€', |
5077
|
|
|
|
|
|
|
## The decimal point character, except for currency values, cannot be an empty string |
5078
|
|
|
|
|
|
|
decimal_point => '.', |
5079
|
|
|
|
|
|
|
## The number of digits after the decimal point in the local style for currency values. |
5080
|
|
|
|
|
|
|
frac_digits => 2, |
5081
|
|
|
|
|
|
|
## The sizes of the groups of digits, except for currency values. unpack( "C*", $grouping ) will give the number |
5082
|
|
|
|
|
|
|
grouping => (CORE::chr(3) x 2), |
5083
|
|
|
|
|
|
|
## The standardized international currency symbol. |
5084
|
|
|
|
|
|
|
int_curr_symbol => '€', |
5085
|
|
|
|
|
|
|
## The number of digits after the decimal point in an international-style currency value. |
5086
|
|
|
|
|
|
|
int_frac_digits => 2, |
5087
|
|
|
|
|
|
|
## Same as n_cs_precedes, but for internationally formatted monetary quantities. |
5088
|
|
|
|
|
|
|
int_n_cs_precedes => '', |
5089
|
|
|
|
|
|
|
## Same as n_sep_by_space, but for internationally formatted monetary quantities. |
5090
|
|
|
|
|
|
|
int_n_sep_by_space => '', |
5091
|
|
|
|
|
|
|
## Same as n_sign_posn, but for internationally formatted monetary quantities. |
5092
|
|
|
|
|
|
|
int_n_sign_posn => 1, |
5093
|
|
|
|
|
|
|
## Same as p_cs_precedes, but for internationally formatted monetary quantities. |
5094
|
|
|
|
|
|
|
int_p_cs_precedes => 1, |
5095
|
|
|
|
|
|
|
## Same as p_sep_by_space, but for internationally formatted monetary quantities. |
5096
|
|
|
|
|
|
|
int_p_sep_by_space => 0, |
5097
|
|
|
|
|
|
|
## Same as p_sign_posn, but for internationally formatted monetary quantities. |
5098
|
|
|
|
|
|
|
int_p_sign_posn => 1, |
5099
|
|
|
|
|
|
|
## The decimal point character for currency values. |
5100
|
|
|
|
|
|
|
mon_decimal_point => '.', |
5101
|
|
|
|
|
|
|
## Like grouping but for currency values. |
5102
|
|
|
|
|
|
|
mon_grouping => (CORE::chr(3) x 2), |
5103
|
|
|
|
|
|
|
## The separator for digit groups in currency values. |
5104
|
|
|
|
|
|
|
mon_thousands_sep => ',', |
5105
|
|
|
|
|
|
|
## Like p_cs_precedes but for negative values. |
5106
|
|
|
|
|
|
|
n_cs_precedes => 1, |
5107
|
|
|
|
|
|
|
## Like p_sep_by_space but for negative values. |
5108
|
|
|
|
|
|
|
n_sep_by_space => 0, |
5109
|
|
|
|
|
|
|
## Like p_sign_posn but for negative currency values. |
5110
|
|
|
|
|
|
|
n_sign_posn => 1, |
5111
|
|
|
|
|
|
|
## The character used to denote negative currency values, usually a minus sign. |
5112
|
|
|
|
|
|
|
negative_sign => '-', |
5113
|
|
|
|
|
|
|
## 1 if the currency symbol precedes the currency value for nonnegative values, 0 if it follows. |
5114
|
|
|
|
|
|
|
p_cs_precedes => 1, |
5115
|
|
|
|
|
|
|
## 1 if a space is inserted between the currency symbol and the currency value for nonnegative values, 0 otherwise. |
5116
|
|
|
|
|
|
|
p_sep_by_space => 0, |
5117
|
|
|
|
|
|
|
## The location of the positive_sign with respect to a nonnegative quantity and the currency_symbol, coded as follows: |
5118
|
|
|
|
|
|
|
## 0 Parentheses around the entire string. |
5119
|
|
|
|
|
|
|
## 1 Before the string. |
5120
|
|
|
|
|
|
|
## 2 After the string. |
5121
|
|
|
|
|
|
|
## 3 Just before currency_symbol. |
5122
|
|
|
|
|
|
|
## 4 Just after currency_symbol. |
5123
|
|
|
|
|
|
|
p_sign_posn => 1, |
5124
|
|
|
|
|
|
|
## The character used to denote nonnegative currency values, usually the empty string. |
5125
|
|
|
|
|
|
|
positive_sign => '', |
5126
|
|
|
|
|
|
|
## The separator between groups of digits before the decimal point, except for currency values |
5127
|
|
|
|
|
|
|
thousands_sep => ',', |
5128
|
|
|
|
|
|
|
}; |
5129
|
|
|
|
|
|
|
|
5130
|
|
|
|
|
|
|
my $map = |
5131
|
|
|
|
|
|
|
{ |
5132
|
|
|
|
|
|
|
decimal => [qw( decimal_point mon_decimal_point )], |
5133
|
|
|
|
|
|
|
grouping => [qw( grouping mon_grouping )], |
5134
|
|
|
|
|
|
|
position_neg => [qw( n_sign_posn int_n_sign_posn )], |
5135
|
|
|
|
|
|
|
position_pos => [qw( n_sign_posn int_p_sign_posn )], |
5136
|
|
|
|
|
|
|
precede => [qw( p_cs_precedes int_p_cs_precedes )], |
5137
|
|
|
|
|
|
|
precede_neg => [qw( n_cs_precedes int_n_cs_precedes )], |
5138
|
|
|
|
|
|
|
precision => [qw( frac_digits int_frac_digits )], |
5139
|
|
|
|
|
|
|
sign_neg => [qw( negative_sign )], |
5140
|
|
|
|
|
|
|
sign_pos => [qw( positive_sign )], |
5141
|
|
|
|
|
|
|
space_pos => [qw( p_sep_by_space int_p_sep_by_space )], |
5142
|
|
|
|
|
|
|
space_neg => [qw( n_sep_by_space int_n_sep_by_space )], |
5143
|
|
|
|
|
|
|
symbol => [qw( currency_symbol int_curr_symbol )], |
5144
|
|
|
|
|
|
|
thousand => [qw( thousands_sep mon_thousands_sep )], |
5145
|
|
|
|
|
|
|
}; |
5146
|
|
|
|
|
|
|
|
5147
|
|
|
|
|
|
|
sub init |
5148
|
|
|
|
|
|
|
{ |
5149
|
131
|
|
|
131
|
|
355
|
my $self = shift( @_ ); |
5150
|
131
|
|
|
|
|
410
|
my $num = shift( @_ ); |
5151
|
131
|
50
|
|
|
|
706
|
return( $self->error( "No number was provided." ) ) if( !CORE::length( $num ) ); |
5152
|
131
|
100
|
|
|
|
813
|
return( Module::Generic::Infinity->new( $num ) ) if( POSIX::isinf( $num ) ); |
5153
|
130
|
100
|
|
|
|
581
|
return( Module::Generic::Nan->new( $num ) ) if( POSIX::isnan( $num ) ); |
5154
|
6
|
|
|
6
|
|
9491
|
use utf8; |
|
6
|
|
|
|
|
44
|
|
|
6
|
|
|
|
|
52
|
|
5155
|
129
|
|
|
|
|
840
|
my @k = keys( %$map ); |
5156
|
129
|
|
|
|
|
1374
|
@$self{ @k } = ( '' x scalar( @k ) ); |
5157
|
129
|
|
|
|
|
523
|
$self->{lang} = ''; |
5158
|
129
|
|
|
|
|
359
|
$self->{default} = $DEFAULT; |
5159
|
129
|
|
|
|
|
533
|
$self->{_init_strict_use_sub} = 1; |
5160
|
129
|
|
|
|
|
847
|
$self->SUPER::init( @_ ); |
5161
|
129
|
|
|
|
|
616
|
my $default = $self->default; |
5162
|
|
|
|
|
|
|
# $self->message( 3, "Getting current locale" ); |
5163
|
129
|
|
|
|
|
961
|
my $curr_locale = POSIX::setlocale( &POSIX::LC_ALL ); |
5164
|
|
|
|
|
|
|
## $self->message( 3, "Current locale is '$curr_locale'" ); |
5165
|
129
|
100
|
33
|
|
|
1117
|
if( $self->{lang} ) |
|
|
50
|
|
|
|
|
|
5166
|
|
|
|
|
|
|
{ |
5167
|
|
|
|
|
|
|
# $self->message( 3, "Language requested '$self->{lang}'." ); |
5168
|
67
|
|
|
|
|
158
|
try |
5169
|
67
|
|
|
67
|
|
133
|
{ |
5170
|
|
|
|
|
|
|
# $self->message( 3, "Current locale found is '$curr_locale'" ); |
5171
|
|
|
|
|
|
|
local $try_locale = sub |
5172
|
|
|
|
|
|
|
{ |
5173
|
67
|
|
|
|
|
125
|
my $loc; |
5174
|
|
|
|
|
|
|
# $self->message( 3, "Checking language '$_[0]'" ); |
5175
|
|
|
|
|
|
|
## The user provided only a language code such as fr_FR. We try it, and also other known combination like fr_FR.UTF-8 and fr_FR.ISO-8859-1, fr_FR.ISO8859-1 |
5176
|
|
|
|
|
|
|
## Try several possibilities |
5177
|
|
|
|
|
|
|
## RT https://rt.cpan.org/Public/Bug/Display.html?id=132664 |
5178
|
67
|
50
|
|
|
|
214
|
if( index( $_[0], '.' ) == -1 ) |
5179
|
|
|
|
|
|
|
{ |
5180
|
|
|
|
|
|
|
# $self->message( 3, "Language '$_[0]' is a bareword, check if it works as is." ); |
5181
|
67
|
|
|
|
|
294
|
$loc = POSIX::setlocale( &POSIX::LC_ALL, $_[0] ); |
5182
|
|
|
|
|
|
|
# $self->message( 3, "Succeeded to set up locale for language '$_[0]'" ) if( $loc ); |
5183
|
67
|
|
|
|
|
246
|
$_[0] =~ s/^(?<locale>[a-z]{2,3})_(?<country>[a-z]{2})$/$+{locale}_\U$+{country}\E/; |
5184
|
67
|
50
|
33
|
|
|
323
|
if( !$loc && CORE::exists( $SUPPORTED_LOCALES->{ $_[0] } ) ) |
5185
|
|
|
|
|
|
|
{ |
5186
|
|
|
|
|
|
|
# $self->message( 3, "Language '$_[0]' is supported, let's check for right variation" ); |
5187
|
0
|
|
|
|
|
0
|
foreach my $supported ( @{$SUPPORTED_LOCALES->{ $_[0] }} ) |
|
0
|
|
|
|
|
0
|
|
5188
|
|
|
|
|
|
|
{ |
5189
|
0
|
0
|
|
|
|
0
|
if( ( $loc = POSIX::setlocale( &POSIX::LC_ALL, $supported ) ) ) |
5190
|
|
|
|
|
|
|
{ |
5191
|
0
|
|
|
|
|
0
|
$_[0] = $supported; |
5192
|
|
|
|
|
|
|
# $self->message( "-> Language variation '$supported' found." ); |
5193
|
0
|
|
|
|
|
0
|
last; |
5194
|
|
|
|
|
|
|
} |
5195
|
|
|
|
|
|
|
} |
5196
|
|
|
|
|
|
|
} |
5197
|
|
|
|
|
|
|
} |
5198
|
|
|
|
|
|
|
## We got something like fr_FR.ISO-8859 |
5199
|
|
|
|
|
|
|
## The user is specific, so we try as is |
5200
|
|
|
|
|
|
|
else |
5201
|
|
|
|
|
|
|
{ |
5202
|
|
|
|
|
|
|
# $self->message( 3, "Language '$_[0]' is specific enough, let's try it." ); |
5203
|
0
|
|
|
|
|
0
|
$loc = POSIX::setlocale( &POSIX::LC_ALL, $_[0] ); |
5204
|
|
|
|
|
|
|
} |
5205
|
67
|
|
|
|
|
300
|
return( $loc ); |
5206
|
67
|
|
|
|
|
378
|
}; |
5207
|
|
|
|
|
|
|
|
5208
|
|
|
|
|
|
|
## $self->message( 3, "Current locale is: '$curr_locale'" ); |
5209
|
67
|
50
|
|
|
|
258
|
if( my $loc = $try_locale->( $self->{lang} ) ) |
5210
|
|
|
|
|
|
|
{ |
5211
|
|
|
|
|
|
|
# $self->message( 3, "Succeeded in setting locale for language '$self->{lang}'" ); |
5212
|
|
|
|
|
|
|
## $self->message( 3, "Succeeded in setting locale to '$self->{lang}'." ); |
5213
|
67
|
|
|
|
|
507
|
my $lconv = POSIX::localeconv(); |
5214
|
|
|
|
|
|
|
## Set back the LC_ALL to what it was, because we do not want to disturb the user environment |
5215
|
67
|
|
|
|
|
767
|
POSIX::setlocale( &POSIX::LC_ALL, $curr_locale ); |
5216
|
|
|
|
|
|
|
## $self->messagef( 3, "POSIX::localeconv() returned %d items", scalar( keys( %$lconv ) ) ); |
5217
|
67
|
50
|
50
|
|
|
1158
|
$default = $lconv if( $lconv && scalar( keys( %$lconv ) ) ); |
5218
|
|
|
|
|
|
|
} |
5219
|
|
|
|
|
|
|
else |
5220
|
|
|
|
|
|
|
{ |
5221
|
0
|
|
|
|
|
0
|
return( $self->error( "Language \"$self->{lang}\" is not supported by your system." ) ); |
5222
|
|
|
|
|
|
|
} |
5223
|
|
|
|
|
|
|
} |
5224
|
67
|
50
|
|
|
|
550
|
catch( $e ) |
|
67
|
50
|
|
|
|
233
|
|
|
67
|
50
|
|
|
|
277
|
|
|
67
|
0
|
|
|
|
169
|
|
|
67
|
50
|
|
|
|
172
|
|
|
67
|
|
|
|
|
171
|
|
|
67
|
|
|
|
|
135
|
|
|
67
|
|
|
|
|
134
|
|
|
67
|
|
|
|
|
304
|
|
|
0
|
|
|
|
|
0
|
|
|
67
|
|
|
|
|
144
|
|
|
0
|
|
|
|
|
0
|
|
|
67
|
|
|
|
|
293
|
|
|
67
|
|
|
|
|
148
|
|
|
67
|
|
|
|
|
173
|
|
|
67
|
|
|
|
|
256
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5225
|
0
|
|
|
0
|
|
0
|
{ |
5226
|
0
|
|
|
|
|
0
|
return( $self->error( "An error occurred while getting the locale information for \"$self->{lang}\": $e" ) ); |
5227
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
67
|
|
|
|
|
1190
|
|
|
0
|
|
|
|
|
0
|
|
5228
|
|
|
|
|
|
|
} |
5229
|
|
|
|
|
|
|
elsif( $curr_locale && ( my $lconv = POSIX::localeconv() ) ) |
5230
|
|
|
|
|
|
|
{ |
5231
|
62
|
50
|
|
|
|
336
|
$default = $lconv if( scalar( keys( %$lconv ) ) ); |
5232
|
|
|
|
|
|
|
## To simulate running on Windows |
5233
|
|
|
|
|
|
|
# my $fail = [qw( |
5234
|
|
|
|
|
|
|
# frac_digits |
5235
|
|
|
|
|
|
|
# int_frac_digits |
5236
|
|
|
|
|
|
|
# n_cs_precedes |
5237
|
|
|
|
|
|
|
# n_sep_by_space |
5238
|
|
|
|
|
|
|
# n_sign_posn |
5239
|
|
|
|
|
|
|
# p_cs_precedes |
5240
|
|
|
|
|
|
|
# p_sep_by_space |
5241
|
|
|
|
|
|
|
# p_sign_posn |
5242
|
|
|
|
|
|
|
# )]; |
5243
|
|
|
|
|
|
|
# @$lconv{ @$fail } = ( -1 ) x scalar( @$fail ); |
5244
|
|
|
|
|
|
|
## $self->message( 3, "No language provided, but current locale '$curr_locale' found" ); |
5245
|
62
|
|
|
|
|
204
|
$self->{lang} = $curr_locale; |
5246
|
|
|
|
|
|
|
} |
5247
|
|
|
|
|
|
|
|
5248
|
|
|
|
|
|
|
## This serves 2 purposes: |
5249
|
|
|
|
|
|
|
## 1) to silence warnings issued from Number::Format when it uses an empty string when evaluating a number, e.g. '' == 1 |
5250
|
|
|
|
|
|
|
## 2) to ensure that blank numerical values are not interpreted to anything else than equivalent of empty |
5251
|
|
|
|
|
|
|
## For example, an empty frac_digits will default to 2 in Number::Format even if the user does not want any. Of course, said user could also have set it to 0 |
5252
|
|
|
|
|
|
|
## So here we use this hash reference of numeric properties to ensure the option parameters are set to a numeric value (0) when they are empty. |
5253
|
129
|
|
|
|
|
1677
|
my $numerics = |
5254
|
|
|
|
|
|
|
{ |
5255
|
|
|
|
|
|
|
grouping => 0, |
5256
|
|
|
|
|
|
|
frac_digits => 0, |
5257
|
|
|
|
|
|
|
int_frac_digits => 0, |
5258
|
|
|
|
|
|
|
int_n_cs_precedes => 0, |
5259
|
|
|
|
|
|
|
int_p_cs_precedes => 0, |
5260
|
|
|
|
|
|
|
int_n_sep_by_space => 0, |
5261
|
|
|
|
|
|
|
int_p_sep_by_space => 0, |
5262
|
|
|
|
|
|
|
int_n_sign_posn => 1, |
5263
|
|
|
|
|
|
|
int_p_sign_posn => 1, |
5264
|
|
|
|
|
|
|
mon_grouping => 0, |
5265
|
|
|
|
|
|
|
n_cs_precedes => 0, |
5266
|
|
|
|
|
|
|
n_sep_by_space => 0, |
5267
|
|
|
|
|
|
|
n_sign_posn => 1, |
5268
|
|
|
|
|
|
|
p_cs_precedes => 0, |
5269
|
|
|
|
|
|
|
p_sep_by_space => 0, |
5270
|
|
|
|
|
|
|
## Position of positive sign. 1 = before (0 = parentheses) |
5271
|
|
|
|
|
|
|
p_sign_posn => 1, |
5272
|
|
|
|
|
|
|
}; |
5273
|
|
|
|
|
|
|
|
5274
|
129
|
|
|
|
|
713
|
foreach my $prop ( keys( %$map ) ) |
5275
|
|
|
|
|
|
|
{ |
5276
|
1677
|
|
|
|
|
3953
|
my $ref = $map->{ $prop }; |
5277
|
|
|
|
|
|
|
## Already set by user |
5278
|
1677
|
100
|
|
|
|
5136
|
next if( CORE::length( $self->{ $prop } ) ); |
5279
|
1505
|
|
|
|
|
3752
|
foreach my $lconv_prop ( @$ref ) |
5280
|
|
|
|
|
|
|
{ |
5281
|
2690
|
100
|
|
|
|
6617
|
if( CORE::defined( $default->{ $lconv_prop } ) ) |
5282
|
|
|
|
|
|
|
{ |
5283
|
|
|
|
|
|
|
## Number::Format bug RT #71044 when running on Windows |
5284
|
|
|
|
|
|
|
## https://rt.cpan.org/Ticket/Display.html?id=71044 |
5285
|
|
|
|
|
|
|
## This is a workaround when values are lower than 0 (i.e. -1) |
5286
|
62
|
0
|
33
|
|
|
380
|
if( CORE::exists( $numerics->{ $lconv_prop } ) && |
|
|
|
33
|
|
|
|
|
5287
|
|
|
|
|
|
|
CORE::length( $default->{ $lconv_prop } ) && |
5288
|
|
|
|
|
|
|
$default->{ $lconv_prop } < 0 ) |
5289
|
|
|
|
|
|
|
{ |
5290
|
0
|
|
|
|
|
0
|
$default->{ $lconv_prop } = $numerics->{ $lconv_prop }; |
5291
|
|
|
|
|
|
|
} |
5292
|
62
|
|
|
|
|
289
|
$self->$prop( $default->{ $lconv_prop } ); |
5293
|
62
|
|
|
|
|
253
|
last; |
5294
|
|
|
|
|
|
|
} |
5295
|
|
|
|
|
|
|
else |
5296
|
|
|
|
|
|
|
{ |
5297
|
2628
|
|
|
|
|
10753
|
$self->$prop( $default->{ $lconv_prop } ); |
5298
|
|
|
|
|
|
|
} |
5299
|
|
|
|
|
|
|
} |
5300
|
|
|
|
|
|
|
} |
5301
|
|
|
|
|
|
|
|
5302
|
|
|
|
|
|
|
# $Number::Format::DEFAULT_LOCALE->{int_curr_symbol} = 'EUR'; |
5303
|
129
|
|
|
|
|
607
|
try |
5304
|
0
|
|
|
|
|
0
|
{ |
5305
|
|
|
|
|
|
|
## Those are unsupported by Number::Format |
5306
|
129
|
|
|
|
|
991
|
my $skip = |
5307
|
|
|
|
|
|
|
{ |
5308
|
|
|
|
|
|
|
int_n_cs_precedes => 1, |
5309
|
|
|
|
|
|
|
int_p_cs_precedes => 1, |
5310
|
|
|
|
|
|
|
int_n_sep_by_space => 1, |
5311
|
|
|
|
|
|
|
int_p_sep_by_space => 1, |
5312
|
|
|
|
|
|
|
int_n_sign_posn => 1, |
5313
|
|
|
|
|
|
|
int_p_sign_posn => 1, |
5314
|
|
|
|
|
|
|
}; |
5315
|
129
|
|
|
|
|
305
|
my $opts = {}; |
5316
|
129
|
|
|
|
|
662
|
foreach my $prop ( CORE::keys( %$map ) ) |
5317
|
|
|
|
|
|
|
{ |
5318
|
|
|
|
|
|
|
## $self->message( 3, "Checking property \"$prop\" value \"", overload::StrVal( $self->{ $prop } ), "\" (", $self->$prop->defined ? 'defined' : 'undefined', ")." ); |
5319
|
1677
|
|
|
|
|
2496
|
my $prop_val; |
5320
|
1677
|
100
|
|
|
|
4843
|
if( $self->$prop->defined ) |
5321
|
|
|
|
|
|
|
{ |
5322
|
234
|
|
|
|
|
612
|
$prop_val = $self->$prop; |
5323
|
|
|
|
|
|
|
} |
5324
|
|
|
|
|
|
|
## To prevent Number::Format from defaulting to property values not in sync with ours |
5325
|
|
|
|
|
|
|
## Because it seems the POSIX::setlocale only affect one module |
5326
|
|
|
|
|
|
|
else |
5327
|
|
|
|
|
|
|
{ |
5328
|
1443
|
|
|
|
|
2520
|
$prop_val = ''; |
5329
|
|
|
|
|
|
|
} |
5330
|
|
|
|
|
|
|
## $self->message( 3, "Using property \"$prop\" value \"$prop_val\" (", CORE::defined( $prop_val ) ? 'defined' : 'undefined', ") [ref=", ref( $prop_val ), "]." ); |
5331
|
|
|
|
|
|
|
## Need to set all the localeconv properties for Number::Format, because it uses mon_thousand_sep intsead of just thousand_sep |
5332
|
1677
|
|
|
|
|
3747
|
foreach my $lconv_prop ( @{$map->{ $prop }} ) |
|
1677
|
|
|
|
|
4501
|
|
5333
|
|
|
|
|
|
|
{ |
5334
|
3096
|
100
|
|
|
|
7342
|
CORE::next if( CORE::exists( $skip->{ $lconv_prop } ) ); |
5335
|
|
|
|
|
|
|
## Cannot be undefined, but can be empty string |
5336
|
2322
|
|
|
|
|
5467
|
$opts->{ $lconv_prop } = "$prop_val"; |
5337
|
2322
|
100
|
100
|
|
|
9637
|
if( !CORE::length( $opts->{ $lconv_prop } ) && CORE::exists( $numerics->{ $lconv_prop } ) ) |
5338
|
|
|
|
|
|
|
{ |
5339
|
1156
|
|
|
|
|
2884
|
$opts->{ $lconv_prop } = $numerics->{ $lconv_prop }; |
5340
|
|
|
|
|
|
|
} |
5341
|
|
|
|
|
|
|
} |
5342
|
|
|
|
|
|
|
} |
5343
|
|
|
|
|
|
|
## $self->message( 3, "Using following options for Number::Format: ", sub{ $self->dumper( $opts ) } ); |
5344
|
6
|
|
|
6
|
|
5654
|
no warnings qw( uninitialized ); |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
324
|
|
5345
|
129
|
|
|
|
|
1333
|
$self->{_fmt} = Number::Format->new( %$opts ); |
5346
|
6
|
|
|
6
|
|
36
|
use warnings; |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
6212
|
|
5347
|
129
|
|
|
129
|
|
292
|
} |
5348
|
129
|
100
|
|
|
|
1149
|
catch( $e ) |
|
129
|
50
|
|
|
|
39710
|
|
|
129
|
50
|
|
|
|
457
|
|
|
129
|
0
|
|
|
|
316
|
|
|
129
|
50
|
|
|
|
376
|
|
|
129
|
|
|
|
|
257
|
|
|
129
|
|
|
|
|
283
|
|
|
129
|
|
|
|
|
328
|
|
|
129
|
|
|
|
|
635
|
|
|
2
|
|
|
|
|
10
|
|
|
127
|
|
|
|
|
335
|
|
|
0
|
|
|
|
|
0
|
|
|
129
|
|
|
|
|
631
|
|
|
129
|
|
|
|
|
352
|
|
|
129
|
|
|
|
|
375
|
|
|
129
|
|
|
|
|
491
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5349
|
0
|
|
|
0
|
|
0
|
{ |
5350
|
|
|
|
|
|
|
## $self->message( 3, "Error trapped in creating a Number::Format object: '$e'" ); |
5351
|
0
|
|
|
|
|
0
|
return( $self->error( "Unable to create a Number::Format object: $e" ) ); |
5352
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
129
|
|
|
|
|
2780
|
|
|
0
|
|
|
|
|
0
|
|
5353
|
129
|
|
|
|
|
623
|
$self->{_original} = $num; |
5354
|
129
|
|
|
|
|
257
|
try |
5355
|
129
|
|
|
129
|
|
284
|
{ |
5356
|
129
|
100
|
|
|
|
1820
|
if( $num !~ /^$RE{num}{real}$/ ) |
5357
|
|
|
|
|
|
|
{ |
5358
|
1
|
|
|
|
|
241
|
$self->{_number} = $self->{_fmt}->unformat_number( $num ); |
5359
|
|
|
|
|
|
|
} |
5360
|
|
|
|
|
|
|
else |
5361
|
|
|
|
|
|
|
{ |
5362
|
128
|
|
|
|
|
30741
|
$self->{_number} = $num; |
5363
|
|
|
|
|
|
|
} |
5364
|
|
|
|
|
|
|
## $self->message( 3, "Unformatted number is: '$self->{_number}'" ); |
5365
|
129
|
100
|
|
|
|
1921
|
return( $self->error( "Invalid number: $num" ) ) if( !defined( $self->{_number} ) ); |
5366
|
|
|
|
|
|
|
} |
5367
|
129
|
100
|
|
|
|
872
|
catch( $e ) |
|
128
|
50
|
|
|
|
479
|
|
|
129
|
50
|
|
|
|
432
|
|
|
129
|
0
|
|
|
|
325
|
|
|
129
|
50
|
|
|
|
345
|
|
|
129
|
|
|
|
|
266
|
|
|
129
|
|
|
|
|
242
|
|
|
129
|
|
|
|
|
347
|
|
|
129
|
|
|
|
|
566
|
|
|
2
|
|
|
|
|
7
|
|
|
127
|
|
|
|
|
362
|
|
|
0
|
|
|
|
|
0
|
|
|
129
|
|
|
|
|
499
|
|
|
129
|
|
|
|
|
307
|
|
|
129
|
|
|
|
|
342
|
|
|
129
|
|
|
|
|
435
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5368
|
0
|
|
|
0
|
|
0
|
{ |
5369
|
0
|
|
|
|
|
0
|
return( $self->error( "Invalid number: $num" ) ); |
5370
|
0
|
0
|
66
|
|
|
0
|
} |
|
0
|
0
|
66
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
100
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
129
|
|
|
|
|
2254
|
|
|
1
|
|
|
|
|
49
|
|
5371
|
128
|
|
|
|
|
3774
|
return( $self ); |
5372
|
|
|
|
|
|
|
} |
5373
|
|
|
|
|
|
|
|
5374
|
3
|
|
|
3
|
|
20
|
sub abs { return( shift->_func( 'abs' ) ); } |
5375
|
|
|
|
|
|
|
|
5376
|
|
|
|
|
|
|
# sub asin { return( shift->_func( 'asin', { posix => 1 } ) ); } |
5377
|
|
|
|
|
|
|
|
5378
|
1
|
|
|
1
|
|
372
|
sub atan { return( shift->_func( 'atan', { posix => 1 } ) ); } |
5379
|
|
|
|
|
|
|
|
5380
|
1
|
|
|
1
|
|
14
|
sub atan2 { return( shift->_func( 'atan2', @_ ) ); } |
5381
|
|
|
|
|
|
|
|
5382
|
4
|
100
|
|
4
|
|
43
|
sub as_boolean { return( Module::Generic::Boolean->new( shift->{_number} ? 1 : 0 ) ); } |
5383
|
|
|
|
|
|
|
|
5384
|
0
|
|
|
0
|
|
0
|
sub as_string { return( shift->{_number} ) } |
5385
|
|
|
|
|
|
|
|
5386
|
1
|
|
|
1
|
|
17
|
sub cbrt { return( shift->_func( 'cbrt', { posix => 1 } ) ); } |
5387
|
|
|
|
|
|
|
|
5388
|
1
|
|
|
1
|
|
7
|
sub ceil { return( shift->_func( 'ceil', { posix => 1 } ) ); } |
5389
|
|
|
|
|
|
|
|
5390
|
1
|
|
|
1
|
|
7
|
sub chr { return( Module::Generic::Scalar->new( CORE::chr( $_[0]->{_number} ) ) ); } |
5391
|
|
|
|
|
|
|
|
5392
|
|
|
|
|
|
|
sub clone |
5393
|
|
|
|
|
|
|
{ |
5394
|
67
|
|
|
67
|
|
214
|
my $self = shift( @_ ); |
5395
|
67
|
100
|
|
|
|
295
|
my $num = @_ ? shift( @_ ) : $self->{_number}; |
5396
|
67
|
50
|
|
|
|
309
|
return( Module::Generic::Infinity->new( $num ) ) if( POSIX::isinf( $num ) ); |
5397
|
67
|
50
|
|
|
|
245
|
return( Module::Generic::Nan->new( $num ) ) if( POSIX::isnan( $num ) ); |
5398
|
67
|
|
|
|
|
467
|
my @keys = keys( %$map ); |
5399
|
67
|
|
|
|
|
270
|
push( @keys, qw( lang debug ) ); |
5400
|
67
|
|
|
|
|
162
|
my $hash = {}; |
5401
|
67
|
|
|
|
|
818
|
@$hash{ @keys } = @$self{ @keys }; |
5402
|
67
|
|
|
|
|
346
|
return( $self->new( $num, $hash ) ); |
5403
|
|
|
|
|
|
|
} |
5404
|
|
|
|
|
|
|
|
5405
|
|
|
|
|
|
|
sub compute |
5406
|
|
|
|
|
|
|
{ |
5407
|
141
|
|
|
141
|
|
630
|
my( $self, $other, $swap, $opts ) = @_; |
5408
|
141
|
100
|
|
|
|
928
|
my $other_val = Scalar::Util::blessed( $other ) ? $other : "\"$other\""; |
5409
|
141
|
100
|
|
|
|
839
|
my $operation = $swap ? "${other_val} $opts->{op} \$self->{_number}" : "\$self->{_number} $opts->{op} ${other_val}"; |
5410
|
141
|
100
|
|
|
|
686
|
if( $opts->{return_object} ) |
|
|
100
|
|
|
|
|
|
5411
|
|
|
|
|
|
|
{ |
5412
|
37
|
|
|
|
|
2921
|
my $res = eval( $operation ); |
5413
|
6
|
|
|
6
|
|
55
|
no overloading; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
770
|
|
5414
|
37
|
50
|
33
|
|
|
287
|
warn( "Error with return formula \"$operation\" using object $self having number '$self->{_number}': $@" ) if( $@ && $self->_warnings_is_enabled ); |
5415
|
37
|
50
|
|
|
|
117
|
return if( $@ ); |
5416
|
37
|
100
|
|
|
|
185
|
return( Module::Generic::Scalar->new( $res ) ) if( $opts->{type} eq 'scalar' ); |
5417
|
36
|
100
|
|
|
|
250
|
return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) ); |
5418
|
31
|
100
|
|
|
|
167
|
return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) ); |
5419
|
|
|
|
|
|
|
## undef may be returned for example on platform supporting NaN when using <=> |
5420
|
27
|
50
|
|
|
|
180
|
return( $self->clone( $res ) ) if( defined( $res ) ); |
5421
|
0
|
|
|
|
|
0
|
return; |
5422
|
|
|
|
|
|
|
} |
5423
|
|
|
|
|
|
|
elsif( $opts->{boolean} ) |
5424
|
|
|
|
|
|
|
{ |
5425
|
101
|
|
|
|
|
8067
|
my $res = eval( $operation ); |
5426
|
6
|
|
|
6
|
|
40
|
no overloading; |
|
6
|
|
|
|
|
50
|
|
|
6
|
|
|
|
|
1667
|
|
5427
|
101
|
50
|
33
|
|
|
730
|
warn( "Error with boolean formula \"$operation\" using object $self having number '$self->{_number}': $@" ) if( $@ && $self->_warnings_is_enabled ); |
5428
|
101
|
50
|
|
|
|
363
|
return if( $@ ); |
5429
|
101
|
100
|
|
|
|
682
|
return( $res ? $self->true : $self->false ); |
5430
|
|
|
|
|
|
|
} |
5431
|
|
|
|
|
|
|
else |
5432
|
|
|
|
|
|
|
{ |
5433
|
3
|
|
|
|
|
211
|
return( eval( $operation ) ); |
5434
|
|
|
|
|
|
|
} |
5435
|
|
|
|
|
|
|
} |
5436
|
|
|
|
|
|
|
|
5437
|
1
|
|
|
1
|
|
15
|
sub cos { return( shift->_func( 'cos' ) ); } |
5438
|
|
|
|
|
|
|
|
5439
|
4
|
|
|
4
|
|
19
|
sub currency { return( shift->_set_get_prop( 'symbol', @_ ) ); } |
5440
|
|
|
|
|
|
|
|
5441
|
3951
|
|
|
3951
|
|
9202
|
sub decimal { return( shift->_set_get_prop( 'decimal', @_ ) ); } |
5442
|
|
|
|
|
|
|
|
5443
|
129
|
|
|
129
|
|
665
|
sub default { return( shift->_set_get_hash_as_mix_object( 'default', @_ ) ); } |
5444
|
|
|
|
|
|
|
|
5445
|
1
|
|
|
1
|
|
17
|
sub exp { return( shift->_func( 'exp' ) ); } |
5446
|
|
|
|
|
|
|
|
5447
|
2
|
|
|
2
|
|
18
|
sub floor { return( shift->_func( 'floor', { posix => 1 } ) ); } |
5448
|
|
|
|
|
|
|
|
5449
|
|
|
|
|
|
|
sub format |
5450
|
|
|
|
|
|
|
{ |
5451
|
2
|
|
|
2
|
|
5
|
my $self = shift( @_ ); |
5452
|
2
|
50
|
33
|
|
|
16
|
my $precision = ( @_ && $_[0] =~ /^\d+$/ ) ? shift( @_ ) : $self->precision; |
5453
|
6
|
|
|
6
|
|
52
|
no overloading; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
8484
|
|
5454
|
2
|
|
|
|
|
14
|
my $num = $self->{_number}; |
5455
|
|
|
|
|
|
|
## If value provided was undefined, we leave it undefined, otherwise we would be at risk of returning 0, and 0 is very different from undefined |
5456
|
2
|
50
|
|
|
|
10
|
return( $num ) if( !defined( $num ) ); |
5457
|
2
|
|
|
|
|
8
|
my $fmt = $self->{_fmt}; |
5458
|
2
|
|
|
|
|
5
|
try |
5459
|
2
|
|
|
2
|
|
6
|
{ |
5460
|
|
|
|
|
|
|
## Amazingly enough, when a precision > 0 is provided, format_number will discard it if the number, before formatting, did not have decimals... Then, what is the point of formatting a number then? |
5461
|
|
|
|
|
|
|
## To circumvent this, we provide the precision along with the "add trailing zeros" parameter expected by Number::Format |
5462
|
|
|
|
|
|
|
## return( $fmt->format_number( $num, $precision, 1 ) ); |
5463
|
2
|
|
|
|
|
19
|
my $res = $fmt->format_number( "$num", $precision, 1 ); |
5464
|
2
|
50
|
|
|
|
70
|
return if( !defined( $res ) ); |
5465
|
2
|
|
|
|
|
19
|
return( Module::Generic::Scalar->new( $res ) ); |
5466
|
|
|
|
|
|
|
} |
5467
|
2
|
50
|
|
|
|
29
|
catch( $e ) |
|
0
|
50
|
|
|
|
0
|
|
|
2
|
50
|
|
|
|
8
|
|
|
2
|
0
|
|
|
|
10
|
|
|
2
|
50
|
|
|
|
13
|
|
|
2
|
|
|
|
|
9
|
|
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
10
|
|
|
0
|
|
|
|
|
0
|
|
|
2
|
|
|
|
|
6
|
|
|
0
|
|
|
|
|
0
|
|
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
5
|
|
|
2
|
|
|
|
|
7
|
|
|
2
|
|
|
|
|
7
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5468
|
0
|
|
|
0
|
|
0
|
{ |
5469
|
0
|
|
|
|
|
0
|
return( $self->error( "Error formatting number \"$num\": $e" ) ); |
5470
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
2
|
|
|
|
|
44
|
|
|
2
|
|
|
|
|
26
|
|
5471
|
|
|
|
|
|
|
} |
5472
|
|
|
|
|
|
|
|
5473
|
2
|
|
|
2
|
|
21
|
sub format_binary { return( Module::Generic::Scalar->new( CORE::sprintf( '%b', shift->{_number} ) ) ); } |
5474
|
|
|
|
|
|
|
|
5475
|
|
|
|
|
|
|
sub format_bytes |
5476
|
|
|
|
|
|
|
{ |
5477
|
1
|
|
|
1
|
|
4
|
my $self = shift( @_ ); |
5478
|
|
|
|
|
|
|
# no overloading; |
5479
|
1
|
|
|
|
|
5
|
my $num = $self->{_number}; |
5480
|
|
|
|
|
|
|
## See comment in format() method |
5481
|
1
|
50
|
|
|
|
5
|
return( $num ) if( !defined( $num ) ); |
5482
|
1
|
|
|
|
|
5
|
my $fmt = $self->{_fmt}; |
5483
|
1
|
|
|
|
|
1
|
try |
5484
|
1
|
|
|
1
|
|
2
|
{ |
5485
|
|
|
|
|
|
|
## return( $fmt->format_bytes( $num, @_ ) ); |
5486
|
1
|
|
|
|
|
8
|
my $res = $fmt->format_bytes( "$num", @_ ); |
5487
|
1
|
50
|
|
|
|
252
|
return if( !defined( $res ) ); |
5488
|
1
|
|
|
|
|
5
|
return( Module::Generic::Scalar->new( $res ) ); |
5489
|
|
|
|
|
|
|
} |
5490
|
1
|
50
|
|
|
|
21
|
catch( $e ) |
|
0
|
50
|
|
|
|
0
|
|
|
1
|
50
|
|
|
|
4
|
|
|
1
|
0
|
|
|
|
4
|
|
|
1
|
50
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
6
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
4
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
5
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5491
|
0
|
|
|
0
|
|
0
|
{ |
5492
|
0
|
|
|
|
|
0
|
return( $self->error( "Error formatting number \"$num\": $e" ) ); |
5493
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
33
|
|
|
1
|
|
|
|
|
19
|
|
5494
|
|
|
|
|
|
|
} |
5495
|
|
|
|
|
|
|
|
5496
|
2
|
|
|
2
|
|
17
|
sub format_hex { return( Module::Generic::Scalar->new( CORE::sprintf( '0x%X', shift->{_number} ) ) ); } |
5497
|
|
|
|
|
|
|
|
5498
|
|
|
|
|
|
|
sub format_money |
5499
|
|
|
|
|
|
|
{ |
5500
|
1
|
|
|
1
|
|
4
|
my $self = shift( @_ ); |
5501
|
1
|
50
|
33
|
|
|
22
|
my $precision = ( @_ && $_[0] =~ /^\d+$/ ) ? shift( @_ ) : $self->precision; |
5502
|
1
|
50
|
|
|
|
6
|
my $currency_symbol = @_ ? shift( @_ ) : $self->currency; |
5503
|
|
|
|
|
|
|
# no overloading; |
5504
|
1
|
|
|
|
|
5
|
my $num = $self->{_number}; |
5505
|
|
|
|
|
|
|
## See comment in format() method |
5506
|
1
|
50
|
|
|
|
10
|
return( $num ) if( !defined( $num ) ); |
5507
|
1
|
|
|
|
|
7
|
my $fmt = $self->{_fmt}; |
5508
|
1
|
|
|
|
|
21
|
try |
5509
|
1
|
|
|
1
|
|
2
|
{ |
5510
|
|
|
|
|
|
|
## Even though the Number::Format instantiated is set with a currency symbol, |
5511
|
|
|
|
|
|
|
## Number::Format will not respect it, and revert to USD if nothing was provided as argument |
5512
|
|
|
|
|
|
|
## This highlights that Number::Format is designed to be used more for exporting function rather than object methods |
5513
|
|
|
|
|
|
|
## $self->message( 3, "Passing Number = '$num', precision = '$precision', currency symbol = '$currency_symbol'." ); |
5514
|
|
|
|
|
|
|
## return( $fmt->format_price( $num, $precision, $currency_symbol ) ); |
5515
|
1
|
|
|
|
|
11
|
my $res = $fmt->format_price( "$num", "$precision", "$currency_symbol" ); |
5516
|
1
|
50
|
|
|
|
241
|
return if( !defined( $res ) ); |
5517
|
1
|
|
|
|
|
6
|
return( Module::Generic::Scalar->new( $res ) ); |
5518
|
|
|
|
|
|
|
} |
5519
|
1
|
50
|
|
|
|
13
|
catch( $e ) |
|
0
|
50
|
|
|
|
0
|
|
|
1
|
50
|
|
|
|
2
|
|
|
1
|
0
|
|
|
|
3
|
|
|
1
|
50
|
|
|
|
5
|
|
|
1
|
|
|
|
|
8
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
10
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
6
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
11
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
5
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5520
|
0
|
|
|
0
|
|
0
|
{ |
5521
|
0
|
|
|
|
|
0
|
return( $self->error( "Error formatting number \"$num\": $e" ) ); |
5522
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
25
|
|
|
1
|
|
|
|
|
18
|
|
5523
|
|
|
|
|
|
|
} |
5524
|
|
|
|
|
|
|
|
5525
|
|
|
|
|
|
|
sub format_negative |
5526
|
|
|
|
|
|
|
{ |
5527
|
1
|
|
|
1
|
|
406
|
my $self = shift( @_ ); |
5528
|
|
|
|
|
|
|
# no overloading; |
5529
|
1
|
|
|
|
|
3
|
my $num = $self->{_number}; |
5530
|
|
|
|
|
|
|
## See comment in format() method |
5531
|
1
|
50
|
|
|
|
11
|
return( $num ) if( !defined( $num ) ); |
5532
|
1
|
|
|
|
|
9
|
my $fmt = $self->{_fmt}; |
5533
|
1
|
|
|
|
|
4
|
try |
5534
|
1
|
|
|
1
|
|
2
|
{ |
5535
|
1
|
|
|
|
|
5
|
my $new = $self->format; |
5536
|
|
|
|
|
|
|
## $self->message( 3, "Formatted number '$self->{_number}' now is '$new'" ); |
5537
|
|
|
|
|
|
|
## return( $fmt->format_negative( $new, @_ ) ); |
5538
|
1
|
|
|
|
|
5
|
my $res = $fmt->format_negative( "$new", @_ ); |
5539
|
|
|
|
|
|
|
## $self->message( 3, "Result is '$res'" ); |
5540
|
1
|
50
|
|
|
|
23
|
return if( !defined( $res ) ); |
5541
|
1
|
|
|
|
|
4
|
return( Module::Generic::Scalar->new( $res ) ); |
5542
|
|
|
|
|
|
|
} |
5543
|
1
|
50
|
|
|
|
17
|
catch( $e ) |
|
0
|
50
|
|
|
|
0
|
|
|
1
|
50
|
|
|
|
4
|
|
|
1
|
0
|
|
|
|
2
|
|
|
1
|
50
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
12
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
10
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
15
|
|
|
1
|
|
|
|
|
15
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
5
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5544
|
0
|
|
|
0
|
|
0
|
{ |
5545
|
0
|
|
|
|
|
0
|
return( $self->error( "Error formatting number \"$num\": $e" ) ); |
5546
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
31
|
|
|
1
|
|
|
|
|
64
|
|
5547
|
|
|
|
|
|
|
} |
5548
|
|
|
|
|
|
|
|
5549
|
|
|
|
|
|
|
sub format_picture |
5550
|
|
|
|
|
|
|
{ |
5551
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
5552
|
6
|
|
|
6
|
|
53
|
no overloading; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
12468
|
|
5553
|
0
|
|
|
|
|
0
|
my $num = $self->{_number}; |
5554
|
|
|
|
|
|
|
## See comment in format() method |
5555
|
0
|
0
|
|
|
|
0
|
return( $num ) if( !defined( $num ) ); |
5556
|
0
|
|
|
|
|
0
|
my $fmt = $self->{_fmt}; |
5557
|
0
|
|
|
|
|
0
|
try |
5558
|
0
|
|
|
0
|
|
0
|
{ |
5559
|
|
|
|
|
|
|
## return( $fmt->format_picture( $num, @_ ) ); |
5560
|
0
|
|
|
|
|
0
|
my $res = $fmt->format_picture( "$num", @_ ); |
5561
|
0
|
0
|
|
|
|
0
|
return if( !defined( $res ) ); |
5562
|
0
|
|
|
|
|
0
|
return( Module::Generic::Scalar->new( $res ) ); |
5563
|
|
|
|
|
|
|
} |
5564
|
0
|
0
|
|
|
|
0
|
catch( $e ) |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5565
|
0
|
|
|
0
|
|
0
|
{ |
5566
|
0
|
|
|
|
|
0
|
return( $self->error( "Error formatting number \"$num\": $e" ) ); |
5567
|
0
|
0
|
0
|
|
|
0
|
} |
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5568
|
|
|
|
|
|
|
} |
5569
|
|
|
|
|
|
|
|
5570
|
3563
|
|
|
3563
|
|
10393
|
sub formatter { return( shift->_set_get_object( 'formatter', 'Number::Format', @_ ) ); } |
5571
|
|
|
|
|
|
|
|
5572
|
|
|
|
|
|
|
## https://stackoverflow.com/a/483708/4814971 |
5573
|
|
|
|
|
|
|
sub from_binary |
5574
|
|
|
|
|
|
|
{ |
5575
|
1
|
|
|
1
|
|
3
|
my $self = shift( @_ ); |
5576
|
1
|
|
|
|
|
3
|
my $binary = shift( @_ ); |
5577
|
1
|
50
|
33
|
|
|
15
|
return if( !defined( $binary ) || !CORE::length( $binary ) ); |
5578
|
1
|
|
|
|
|
3
|
try |
5579
|
1
|
|
|
1
|
|
2
|
{ |
5580
|
|
|
|
|
|
|
## Nice trick to convert from binary to decimal. See perlfunc -> oct |
5581
|
1
|
|
|
|
|
4
|
my $res = CORE::oct( "0b${binary}" ); |
5582
|
1
|
50
|
|
|
|
4
|
return if( !defined( $res ) ); |
5583
|
1
|
|
|
|
|
5
|
return( $self->clone( $res ) ); |
5584
|
|
|
|
|
|
|
} |
5585
|
1
|
50
|
|
|
|
18
|
catch( $e ) |
|
0
|
50
|
|
|
|
0
|
|
|
1
|
50
|
|
|
|
4
|
|
|
1
|
0
|
|
|
|
2
|
|
|
1
|
50
|
|
|
|
4
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
5
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
4
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
4
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5586
|
0
|
|
|
0
|
|
0
|
{ |
5587
|
0
|
|
|
|
|
0
|
return( $self->error( "Error while getting number from hexadecimal value \"$hex\": $e" ) ); |
5588
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
32
|
|
|
1
|
|
|
|
|
20
|
|
5589
|
|
|
|
|
|
|
} |
5590
|
|
|
|
|
|
|
|
5591
|
|
|
|
|
|
|
sub from_hex |
5592
|
|
|
|
|
|
|
{ |
5593
|
1
|
|
|
1
|
|
4
|
my $self = shift( @_ ); |
5594
|
1
|
|
|
|
|
3
|
my $hex = shift( @_ ); |
5595
|
1
|
50
|
33
|
|
|
16
|
return if( !defined( $hex ) || !CORE::length( $hex ) ); |
5596
|
1
|
|
|
|
|
3
|
try |
5597
|
1
|
|
|
1
|
|
2
|
{ |
5598
|
1
|
|
|
|
|
3
|
my $res = CORE::hex( $hex ); |
5599
|
1
|
50
|
|
|
|
4
|
return if( !defined( $res ) ); |
5600
|
1
|
|
|
|
|
6
|
return( $self->clone( $res ) ); |
5601
|
|
|
|
|
|
|
} |
5602
|
1
|
50
|
|
|
|
18
|
catch( $e ) |
|
0
|
50
|
|
|
|
0
|
|
|
1
|
50
|
|
|
|
4
|
|
|
1
|
0
|
|
|
|
3
|
|
|
1
|
50
|
|
|
|
3
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
7
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
4
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
6
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
5
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5603
|
0
|
|
|
0
|
|
0
|
{ |
5604
|
0
|
|
|
|
|
0
|
return( $self->error( "Error while getting number from hexadecimal value \"$hex\": $e" ) ); |
5605
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
33
|
|
|
1
|
|
|
|
|
20
|
|
5606
|
|
|
|
|
|
|
} |
5607
|
|
|
|
|
|
|
|
5608
|
4017
|
|
|
4017
|
|
9742
|
sub grouping { return( shift->_set_get_prop( 'grouping', @_ ) ); } |
5609
|
|
|
|
|
|
|
|
5610
|
1
|
|
|
1
|
|
445
|
sub int { return( shift->_func( 'int' ) ); } |
5611
|
|
|
|
|
|
|
|
5612
|
|
|
|
|
|
|
*is_decimal = \&is_float; |
5613
|
|
|
|
|
|
|
|
5614
|
1
|
|
|
1
|
|
8
|
sub is_finite { return( shift->_func( 'isfinite', { posix => 1 }) ); } |
5615
|
|
|
|
|
|
|
|
5616
|
1
|
|
|
1
|
|
17
|
sub is_float { return( (POSIX::modf( shift->{_number} ))[0] != 0 ); } |
5617
|
|
|
|
|
|
|
|
5618
|
|
|
|
|
|
|
# sub is_infinite { return( !(shift->is_finite) ); } |
5619
|
0
|
|
|
0
|
|
0
|
sub is_infinite { return( shift->_func( 'isinf', { posix => 1 }) ); } |
5620
|
|
|
|
|
|
|
|
5621
|
1
|
|
|
1
|
|
12
|
sub is_int { return( (POSIX::modf( shift->{_number} ))[0] == 0 ); } |
5622
|
|
|
|
|
|
|
|
5623
|
1
|
|
|
1
|
|
7
|
sub is_nan { return( shift->_func( 'isnan', { posix => 1}) ); } |
5624
|
|
|
|
|
|
|
|
5625
|
|
|
|
|
|
|
*is_neg = \&is_negative; |
5626
|
|
|
|
|
|
|
|
5627
|
4
|
|
|
4
|
|
304
|
sub is_negative { return( shift->_func( 'signbit', { posix => 1 }) != 0 ); } |
5628
|
|
|
|
|
|
|
|
5629
|
1
|
|
|
1
|
|
8
|
sub is_normal { return( shift->_func( 'isnormal', { posix => 1}) ); } |
5630
|
|
|
|
|
|
|
|
5631
|
|
|
|
|
|
|
*is_pos = \&is_positive; |
5632
|
|
|
|
|
|
|
|
5633
|
4
|
|
|
4
|
|
28
|
sub is_positive { return( shift->_func( 'signbit', { posix => 1 }) == 0 ); } |
5634
|
|
|
|
|
|
|
|
5635
|
68
|
|
|
68
|
|
262
|
sub lang { return( shift->_set_get_scalar_as_object( 'lang', @_ ) ); } |
5636
|
|
|
|
|
|
|
|
5637
|
1
|
|
|
1
|
|
16
|
sub length { return( $_[0]->clone( CORE::length( $_[0]->{_number} ) ) ); } |
5638
|
|
|
|
|
|
|
|
5639
|
1
|
|
|
1
|
|
12
|
sub locale { return( shift->_set_get_scalar_as_object( 'lang', @_ ) ); } |
5640
|
|
|
|
|
|
|
|
5641
|
1
|
|
|
1
|
|
6
|
sub log { return( shift->_func( 'log' ) ); } |
5642
|
|
|
|
|
|
|
|
5643
|
1
|
|
|
1
|
|
7
|
sub log2 { return( shift->_func( 'log2', { posix => 1 } ) ); } |
5644
|
|
|
|
|
|
|
|
5645
|
1
|
|
|
1
|
|
7
|
sub log10 { return( shift->_func( 'log10', { posix => 1 } ) ); } |
5646
|
|
|
|
|
|
|
|
5647
|
3
|
|
|
3
|
|
30
|
sub max { return( shift->_func( 'fmax', @_, { posix => 1 } ) ); } |
5648
|
|
|
|
|
|
|
|
5649
|
2
|
|
|
2
|
|
16
|
sub min { return( shift->_func( 'fmin', @_, { posix => 1 } ) ); } |
5650
|
|
|
|
|
|
|
|
5651
|
1
|
|
|
1
|
|
8
|
sub mod { return( shift->_func( 'fmod', @_, { posix => 1 } ) ); } |
5652
|
|
|
|
|
|
|
|
5653
|
|
|
|
|
|
|
## This is used so that we can change formatter when the user changes thousand separator, decimal separator, precision or currency |
5654
|
|
|
|
|
|
|
sub new_formatter |
5655
|
|
|
|
|
|
|
{ |
5656
|
3563
|
|
|
3563
|
|
6314
|
my $self = shift( @_ ); |
5657
|
3563
|
|
|
|
|
6384
|
my $hash = {}; |
5658
|
3563
|
50
|
|
|
|
7400
|
if( @_ ) |
5659
|
|
|
|
|
|
|
{ |
5660
|
0
|
0
|
0
|
|
|
0
|
if( @_ == 1 && $self->_is_hash( $_[0] ) ) |
|
|
0
|
|
|
|
|
|
5661
|
|
|
|
|
|
|
{ |
5662
|
0
|
|
|
|
|
0
|
$hash = shift( @_ ); |
5663
|
|
|
|
|
|
|
} |
5664
|
|
|
|
|
|
|
elsif( !( @_ % 2 ) ) |
5665
|
|
|
|
|
|
|
{ |
5666
|
0
|
|
|
|
|
0
|
$hash = { @_ }; |
5667
|
|
|
|
|
|
|
} |
5668
|
|
|
|
|
|
|
else |
5669
|
|
|
|
|
|
|
{ |
5670
|
0
|
|
|
|
|
0
|
return( $self->error( "Invalid parameters provided: '", join( "', '", @_ ), "'." ) ); |
5671
|
|
|
|
|
|
|
} |
5672
|
|
|
|
|
|
|
} |
5673
|
|
|
|
|
|
|
else |
5674
|
|
|
|
|
|
|
{ |
5675
|
3563
|
|
|
|
|
15170
|
my @keys = keys( %$map ); |
5676
|
|
|
|
|
|
|
# @$hash{ @keys } = @$self{ @keys }; |
5677
|
3563
|
|
|
|
|
7455
|
for( @keys ) |
5678
|
|
|
|
|
|
|
{ |
5679
|
46319
|
|
|
|
|
130654
|
$hash->{ $_ } = $self->$_(); |
5680
|
|
|
|
|
|
|
} |
5681
|
|
|
|
|
|
|
} |
5682
|
3563
|
|
|
|
|
5963
|
try |
5683
|
3563
|
|
|
3563
|
|
4857
|
{ |
5684
|
3563
|
|
|
|
|
6425
|
my $opts = {}; |
5685
|
3563
|
|
|
|
|
17623
|
foreach my $prop ( keys( %$map ) ) |
5686
|
|
|
|
|
|
|
{ |
5687
|
46319
|
100
|
|
|
|
92038
|
$opts->{ $map->{ $prop }->[0] } = $hash->{ $prop } if( CORE::defined( $hash->{ $prop } ) ); |
5688
|
|
|
|
|
|
|
} |
5689
|
3563
|
|
|
|
|
17820
|
return( Number::Format->new( %$opts ) ); |
5690
|
|
|
|
|
|
|
} |
5691
|
3563
|
50
|
|
|
|
18423
|
catch( $e ) |
|
0
|
0
|
|
|
|
0
|
|
|
3563
|
50
|
|
|
|
8978
|
|
|
3563
|
0
|
|
|
|
5533
|
|
|
3563
|
50
|
|
|
|
7201
|
|
|
3563
|
|
|
|
|
5147
|
|
|
3563
|
|
|
|
|
5138
|
|
|
3563
|
|
|
|
|
5991
|
|
|
3563
|
|
|
|
|
6563
|
|
|
3563
|
|
|
|
|
6898
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
3563
|
|
|
|
|
450943
|
|
|
3563
|
|
|
|
|
7130
|
|
|
3563
|
|
|
|
|
7565
|
|
|
3563
|
|
|
|
|
7984
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5692
|
0
|
|
|
0
|
|
0
|
{ |
5693
|
0
|
|
|
|
|
0
|
return( $self->error( "Error while trying to get a Number::Format object: $e" ) ); |
5694
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
3563
|
|
|
|
|
32171
|
|
|
3563
|
|
|
|
|
34670
|
|
5695
|
|
|
|
|
|
|
} |
5696
|
|
|
|
|
|
|
|
5697
|
1
|
|
|
1
|
|
6
|
sub oct { return( shift->_func( 'oct' ) ); } |
5698
|
|
|
|
|
|
|
|
5699
|
4017
|
|
|
4017
|
|
9048
|
sub position_neg { return( shift->_set_get_prop( 'position_neg', @_ ) ); } |
5700
|
|
|
|
|
|
|
|
5701
|
4017
|
|
|
4017
|
|
9480
|
sub position_pos { return( shift->_set_get_prop( 'position_pos', @_ ) ); } |
5702
|
|
|
|
|
|
|
|
5703
|
0
|
|
|
0
|
|
0
|
sub pow { return( shift->_func( 'pow', @_, { posix => 1 } ) ); } |
5704
|
|
|
|
|
|
|
|
5705
|
4018
|
|
|
4018
|
|
9150
|
sub precede { return( shift->_set_get_prop( 'precede', @_ ) ); } |
5706
|
|
|
|
|
|
|
|
5707
|
4017
|
|
|
4017
|
|
9241
|
sub precede_neg { return( shift->_set_get_prop( 'precede_neg', @_ ) ); } |
5708
|
|
|
|
|
|
|
|
5709
|
0
|
|
|
0
|
|
0
|
sub precede_pos { return( shift->_set_get_prop( 'precede', @_ ) ); } |
5710
|
|
|
|
|
|
|
|
5711
|
3956
|
|
|
3956
|
|
8743
|
sub precision { return( shift->_set_get_prop( 'precision', @_ ) ); } |
5712
|
|
|
|
|
|
|
|
5713
|
0
|
|
|
0
|
|
0
|
sub rand { return( shift->_func( 'rand' ) ); } |
5714
|
|
|
|
|
|
|
|
5715
|
1
|
50
|
|
1
|
|
33
|
sub round { return( $_[0]->clone( CORE::sprintf( '%.*f', CORE::int( CORE::length( $_[1] ) ? $_[1] : 0 ), $_[0]->{_number} ) ) ); } |
5716
|
|
|
|
|
|
|
|
5717
|
0
|
|
|
0
|
|
0
|
sub round_zero { return( shift->_func( 'round', @_, { posix => 1 } ) ); } |
5718
|
|
|
|
|
|
|
|
5719
|
|
|
|
|
|
|
sub round2 |
5720
|
|
|
|
|
|
|
{ |
5721
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
5722
|
6
|
|
|
6
|
|
56
|
no overloading; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
9718
|
|
5723
|
0
|
|
|
|
|
0
|
my $num = $self->{_number}; |
5724
|
|
|
|
|
|
|
## See comment in format() method |
5725
|
0
|
0
|
|
|
|
0
|
return( $num ) if( !defined( $num ) ); |
5726
|
0
|
|
|
|
|
0
|
my $fmt = $self->{_fmt}; |
5727
|
0
|
|
|
|
|
0
|
try |
5728
|
0
|
|
|
0
|
|
0
|
{ |
5729
|
|
|
|
|
|
|
## return( $fmt->round( $num, @_ ) ); |
5730
|
0
|
|
|
|
|
0
|
my $res = $fmt->round( $num, @_ ); |
5731
|
0
|
0
|
|
|
|
0
|
return if( !defined( $res ) ); |
5732
|
0
|
|
|
|
|
0
|
my $clone = $self->clone; |
5733
|
0
|
|
|
|
|
0
|
$clone->{_number} = $res; |
5734
|
0
|
|
|
|
|
0
|
return( $clone ); |
5735
|
|
|
|
|
|
|
} |
5736
|
0
|
0
|
|
|
|
0
|
catch( $e ) |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5737
|
0
|
|
|
0
|
|
0
|
{ |
5738
|
0
|
|
|
|
|
0
|
return( $self->error( "Error rounding number \"$num\": $e" ) ); |
5739
|
0
|
0
|
0
|
|
|
0
|
} |
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5740
|
|
|
|
|
|
|
} |
5741
|
|
|
|
|
|
|
|
5742
|
0
|
|
|
0
|
|
0
|
sub scalar { return( shift->as_string ); } |
5743
|
|
|
|
|
|
|
|
5744
|
3888
|
|
|
3888
|
|
9135
|
sub sign_neg { return( shift->_set_get_prop( 'sign_neg', @_ ) ); } |
5745
|
|
|
|
|
|
|
|
5746
|
3888
|
|
|
3888
|
|
9260
|
sub sign_pos { return( shift->_set_get_prop( 'sign_pos', @_ ) ); } |
5747
|
|
|
|
|
|
|
|
5748
|
1
|
|
|
1
|
|
6
|
sub sin { return( shift->_func( 'sin' ) ); } |
5749
|
|
|
|
|
|
|
|
5750
|
|
|
|
|
|
|
*space = \&space_pos; |
5751
|
|
|
|
|
|
|
|
5752
|
4017
|
|
|
4017
|
|
9888
|
sub space_neg { return( shift->_set_get_prop( 'space_neg', @_ ) ); } |
5753
|
|
|
|
|
|
|
|
5754
|
4017
|
|
|
4017
|
|
9294
|
sub space_pos { return( shift->_set_get_prop( 'space_pos', @_ ) ); } |
5755
|
|
|
|
|
|
|
|
5756
|
1
|
|
|
1
|
|
5
|
sub sqrt { return( shift->_func( 'sqrt' ) ); } |
5757
|
|
|
|
|
|
|
|
5758
|
3980
|
|
|
3980
|
|
8891
|
sub symbol { return( shift->_set_get_prop( 'symbol', @_ ) ); } |
5759
|
|
|
|
|
|
|
|
5760
|
1
|
|
|
1
|
|
7
|
sub tan { return( shift->_func( 'tan', { posix => 1 } ) ); } |
5761
|
|
|
|
|
|
|
|
5762
|
4018
|
|
|
4018
|
|
9162
|
sub thousand { return( shift->_set_get_prop( 'thousand', @_ ) ); } |
5763
|
|
|
|
|
|
|
|
5764
|
|
|
|
|
|
|
sub unformat |
5765
|
|
|
|
|
|
|
{ |
5766
|
1
|
|
|
1
|
|
12
|
my $self = shift( @_ ); |
5767
|
1
|
|
|
|
|
3
|
my $num = shift( @_ ); |
5768
|
1
|
50
|
|
|
|
6
|
return if( !defined( $num ) ); |
5769
|
1
|
|
|
|
|
8
|
try |
5770
|
1
|
|
|
1
|
|
7
|
{ |
5771
|
1
|
|
|
|
|
29
|
my $num2 = $self->{_fmt}->unformat_number( $num ); |
5772
|
1
|
|
|
|
|
52
|
my $clone = $self->clone; |
5773
|
1
|
|
|
|
|
5
|
$clone->{_original} = $num; |
5774
|
1
|
|
|
|
|
3
|
$clone->{_number} = $num2; |
5775
|
1
|
|
|
|
|
17
|
return( $clone ); |
5776
|
|
|
|
|
|
|
} |
5777
|
1
|
50
|
|
|
|
20
|
catch( $e ) |
|
0
|
50
|
|
|
|
0
|
|
|
1
|
50
|
|
|
|
11
|
|
|
1
|
0
|
|
|
|
4
|
|
|
1
|
50
|
|
|
|
3
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
11
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
5
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
4
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5778
|
0
|
|
|
0
|
|
0
|
{ |
5779
|
0
|
|
|
|
|
0
|
return( $self->error( "Unable to unformat the number \"$num\": $e" ) ); |
5780
|
0
|
0
|
33
|
|
|
0
|
} |
|
0
|
0
|
33
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
1
|
|
|
|
|
41
|
|
|
1
|
|
|
|
|
16
|
|
5781
|
|
|
|
|
|
|
} |
5782
|
|
|
|
|
|
|
|
5783
|
|
|
|
|
|
|
sub _func |
5784
|
|
|
|
|
|
|
{ |
5785
|
29
|
|
|
29
|
|
98
|
my $self = shift( @_ ); |
5786
|
29
|
|
50
|
|
|
231
|
my $func = shift( @_ ) || return( $self->error( "No function was provided." ) ); |
5787
|
|
|
|
|
|
|
## $self->message( 3, "Arguments received are: '", join( "', '", @_ ), "'." ); |
5788
|
29
|
|
|
|
|
103
|
my $opts = {}; |
5789
|
29
|
100
|
|
|
|
169
|
$opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' ); |
5790
|
29
|
100
|
|
|
|
154
|
my $namespace = $opts->{posix} ? 'POSIX' : 'CORE'; |
5791
|
29
|
100
|
|
|
|
135
|
my $val = @_ ? shift( @_ ) : undef; |
5792
|
29
|
100
|
|
|
|
171
|
my $expr = defined( $val ) ? "${namespace}::${func}( \$self->{_number}, $val )" : "${namespace}::${func}( \$self->{_number} )"; |
5793
|
|
|
|
|
|
|
## $self->message( 3, "Evaluating '$expr'" ); |
5794
|
29
|
|
|
|
|
2513
|
my $res = eval( $expr ); |
5795
|
|
|
|
|
|
|
## $self->message( 3, "Result for number '$self->{_number}' is '$res'" ); |
5796
|
29
|
50
|
|
|
|
196
|
$self->message( 3, "Error: $@" ) if( $@ ); |
5797
|
29
|
50
|
|
|
|
106
|
return( $self->pass_error( $@ ) ) if( $@ ); |
5798
|
29
|
50
|
|
|
|
107
|
return if( !defined( $res ) ); |
5799
|
29
|
50
|
|
|
|
173
|
return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) ); |
5800
|
29
|
50
|
|
|
|
134
|
return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) ); |
5801
|
29
|
|
|
|
|
164
|
return( $self->clone( $res ) ); |
5802
|
|
|
|
|
|
|
} |
5803
|
|
|
|
|
|
|
|
5804
|
|
|
|
|
|
|
sub _set_get_prop |
5805
|
|
|
|
|
|
|
{ |
5806
|
51805
|
|
|
51805
|
|
78275
|
my $self = shift( @_ ); |
5807
|
51805
|
|
|
|
|
75323
|
my $prop = shift( @_ ); |
5808
|
51805
|
100
|
|
|
|
99550
|
if( @_ ) |
5809
|
|
|
|
|
|
|
{ |
5810
|
3563
|
|
|
|
|
7616
|
my $val = shift( @_ ); |
5811
|
3563
|
100
|
66
|
|
|
7869
|
$val = $val->scalar if( $self->_is_object( $val ) && $val->isa( 'Module::Generic::Scalar' ) ); |
5812
|
|
|
|
|
|
|
## $self->message( 3, "Setting value \"$val\" (", defined( $val ) ? 'defined' : 'undefined', ") for property \"$prop\"." ); |
5813
|
3563
|
50
|
66
|
|
|
11600
|
if( $val ne $self->{ $prop } || !CORE::defined( $val ) ) |
5814
|
|
|
|
|
|
|
{ |
5815
|
|
|
|
|
|
|
# $self->{ $prop } = $val; |
5816
|
3563
|
|
|
|
|
9415
|
$self->_set_get_scalar_as_object( $prop, $val ); |
5817
|
|
|
|
|
|
|
## If an error was set, we return nothing |
5818
|
3563
|
50
|
|
|
|
10682
|
$self->formatter( $self->new_formatter ) || return; |
5819
|
|
|
|
|
|
|
} |
5820
|
|
|
|
|
|
|
} |
5821
|
|
|
|
|
|
|
# return( $self->{ $prop } ); |
5822
|
51805
|
|
|
|
|
95782
|
return( $self->_set_get_scalar_as_object( $prop ) ); |
5823
|
|
|
|
|
|
|
} |
5824
|
|
|
|
|
|
|
|
5825
|
|
|
|
|
|
|
AUTOLOAD |
5826
|
|
|
|
|
|
|
{ |
5827
|
0
|
|
|
0
|
|
0
|
my( $method ) = our $AUTOLOAD =~ /([^:]+)$/; |
5828
|
0
|
|
0
|
|
|
0
|
my $self = shift( @_ ) || return; |
5829
|
0
|
|
0
|
|
|
0
|
my $fmt_obj = $self->{_fmt} || return; |
5830
|
0
|
|
|
|
|
0
|
my $code = $fmt_obj->can( $method ); |
5831
|
0
|
0
|
|
|
|
0
|
if( $code ) |
5832
|
|
|
|
|
|
|
{ |
5833
|
0
|
|
|
|
|
0
|
try |
5834
|
0
|
|
|
0
|
|
0
|
{ |
5835
|
0
|
|
|
|
|
0
|
return( $code->( $fmt_obj, @_ ) ); |
5836
|
|
|
|
|
|
|
} |
5837
|
0
|
0
|
|
|
|
0
|
catch( $e ) |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5838
|
0
|
|
|
0
|
|
0
|
{ |
5839
|
0
|
|
|
|
|
0
|
CORE::warn( $e ); |
5840
|
0
|
|
|
|
|
0
|
return; |
5841
|
0
|
0
|
0
|
|
|
0
|
} |
|
0
|
0
|
0
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
5842
|
|
|
|
|
|
|
} |
5843
|
0
|
|
|
|
|
0
|
return; |
5844
|
|
|
|
|
|
|
}; |
5845
|
|
|
|
|
|
|
|
5846
|
|
|
|
|
|
|
package Module::Generic::NumberSpecial; |
5847
|
|
|
|
|
|
|
BEGIN |
5848
|
|
|
|
|
|
|
{ |
5849
|
6
|
|
|
6
|
|
61
|
use strict; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
171
|
|
5850
|
6
|
|
|
6
|
|
33
|
use warnings; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
275
|
|
5851
|
6
|
|
|
6
|
|
41
|
use parent -norequire, qw( Module::Generic::Number ); |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
71
|
|
5852
|
5
|
|
|
5
|
|
963
|
use overload ('""' => sub{ $_[0]->{_number} }, |
5853
|
0
|
|
|
0
|
|
0
|
'+=' => sub{ &_catchall( @_[0..2], '+' ) }, |
5854
|
0
|
|
|
0
|
|
0
|
'-=' => sub{ &_catchall( @_[0..2], '-' ) }, |
5855
|
1
|
|
|
1
|
|
8
|
'*=' => sub{ &_catchall( @_[0..2], '*' ) }, |
5856
|
0
|
|
|
0
|
|
0
|
'/=' => sub{ &_catchall( @_[0..2], '/' ) }, |
5857
|
0
|
|
|
0
|
|
0
|
'%=' => sub{ &_catchall( @_[0..2], '%' ) }, |
5858
|
0
|
|
|
0
|
|
0
|
'**=' => sub{ &_catchall( @_[0..2], '**' ) }, |
5859
|
0
|
|
|
0
|
|
0
|
'<<=' => sub{ &_catchall( @_[0..2], '<<' ) }, |
5860
|
0
|
|
|
0
|
|
0
|
'>>=' => sub{ &_catchall( @_[0..2], '>>' ) }, |
5861
|
0
|
|
|
0
|
|
0
|
'x=' => sub{ &_catchall( @_[0..2], 'x' ) }, |
5862
|
0
|
|
|
0
|
|
0
|
'.=' => sub{ &_catchall( @_[0..2], '.' ) }, |
5863
|
6
|
|
|
|
|
140
|
nomethod => \&_catchall, |
5864
|
|
|
|
|
|
|
fallback => 1, |
5865
|
6
|
|
|
6
|
|
2098
|
); |
|
6
|
|
|
|
|
13
|
|
5866
|
6
|
|
|
6
|
|
1168
|
use Want; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
483
|
|
5867
|
6
|
|
|
6
|
|
39
|
use POSIX (); |
|
6
|
|
|
|
|
21
|
|
|
6
|
|
|
|
|
154
|
|
5868
|
6
|
|
|
6
|
|
3853
|
our( $VERSION ) = '0.1.0'; |
5869
|
|
|
|
|
|
|
}; |
5870
|
|
|
|
|
|
|
|
5871
|
|
|
|
|
|
|
sub new |
5872
|
|
|
|
|
|
|
{ |
5873
|
17
|
|
|
17
|
|
49
|
my $this = shift( @_ ); |
5874
|
17
|
|
66
|
|
|
201
|
return( bless( { _number => CORE::shift( @_ ) } => ( ref( $this ) || $this ) ) ); |
5875
|
|
|
|
|
|
|
} |
5876
|
|
|
|
|
|
|
|
5877
|
1
|
|
|
1
|
|
38
|
sub clone { return( shift->new( @_ ) ); } |
5878
|
|
|
|
|
|
|
|
5879
|
0
|
|
|
0
|
|
0
|
sub is_finite { return( 0 ); } |
5880
|
|
|
|
|
|
|
|
5881
|
0
|
|
|
0
|
|
0
|
sub is_float { return( 0 ); } |
5882
|
|
|
|
|
|
|
|
5883
|
0
|
|
|
0
|
|
0
|
sub is_infinite { return( 0 ); } |
5884
|
|
|
|
|
|
|
|
5885
|
0
|
|
|
0
|
|
0
|
sub is_int { return( 0 ); } |
5886
|
|
|
|
|
|
|
|
5887
|
0
|
|
|
0
|
|
0
|
sub is_nan { return( 0 ); } |
5888
|
|
|
|
|
|
|
|
5889
|
2
|
|
|
2
|
|
11
|
sub is_normal { return( 0 ); } |
5890
|
|
|
|
|
|
|
|
5891
|
0
|
|
|
0
|
|
0
|
sub length { return( CORE::length( $self->{_number} ) ); } |
5892
|
|
|
|
|
|
|
|
5893
|
|
|
|
|
|
|
sub _catchall |
5894
|
|
|
|
|
|
|
{ |
5895
|
1
|
|
|
1
|
|
9
|
my( $self, $other, $swap, $op ) = @_; |
5896
|
1
|
50
|
|
|
|
13
|
my $expr = $swap ? "$other $op $self->{_number}" : "$self->{_number} $op $other"; |
5897
|
1
|
|
|
|
|
70
|
my $res = eval( $expr ); |
5898
|
|
|
|
|
|
|
## print( ref( $self ), "::_catchall: evaluating $expr => $res\n" ); |
5899
|
1
|
50
|
|
|
|
9
|
CORE::warn( "Error evaluating expression \"$expr\": $@" ) if( $@ ); |
5900
|
1
|
50
|
|
|
|
3
|
return if( $@ ); |
5901
|
1
|
50
|
|
|
|
7
|
return( Module::Generic::Number->new( $res ) ) if( POSIX::isnormal( $res ) ); |
5902
|
1
|
50
|
|
|
|
8
|
return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) ); |
5903
|
0
|
0
|
|
|
|
0
|
return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) ); |
5904
|
0
|
|
|
|
|
0
|
return( $res ); |
5905
|
|
|
|
|
|
|
} |
5906
|
|
|
|
|
|
|
|
5907
|
|
|
|
|
|
|
sub _func |
5908
|
|
|
|
|
|
|
{ |
5909
|
7
|
|
|
7
|
|
19
|
my $self = shift( @_ ); |
5910
|
7
|
|
50
|
|
|
30
|
my $func = shift( @_ ) || return( $self->error( "No function was provided." ) ); |
5911
|
7
|
|
|
|
|
14
|
my $opts = {}; |
5912
|
7
|
100
|
|
|
|
31
|
$opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' ); |
5913
|
7
|
100
|
|
|
|
25
|
my $namespace = $opts->{posix} ? 'POSIX' : 'CORE'; |
5914
|
7
|
100
|
|
|
|
23
|
my $val = @_ ? shift( @_ ) : undef; |
5915
|
7
|
100
|
|
|
|
42
|
my $expr = defined( $val ) ? "${namespace}::${func}( $self->{_number}, $val )" : "${namespace}::${func}( $self->{_number} )"; |
5916
|
7
|
|
|
|
|
468
|
my $res = eval( $expr ); |
5917
|
|
|
|
|
|
|
## $self->message( 3, "Error: $@" ) if( $@ ); |
5918
|
|
|
|
|
|
|
## print( STDERR ref( $self ), "::_func -> evaluating '$expr' -> '$res'\n" ); |
5919
|
7
|
50
|
|
|
|
94
|
CORE::warn( $@ ) if( $@ ); |
5920
|
7
|
50
|
|
|
|
27
|
return if( !defined( $res ) ); |
5921
|
7
|
100
|
|
|
|
39
|
return( Module::Generic::Number->new( $res ) ) if( POSIX::isnormal( $res ) ); |
5922
|
4
|
50
|
|
|
|
21
|
return( Module::Generic::Infinity->new( $res ) ) if( POSIX::isinf( $res ) ); |
5923
|
0
|
0
|
|
|
|
0
|
return( Module::Generic::Nan->new( $res ) ) if( POSIX::isnan( $res ) ); |
5924
|
0
|
|
|
|
|
0
|
return( $res ); |
5925
|
|
|
|
|
|
|
} |
5926
|
|
|
|
|
|
|
|
5927
|
|
|
|
|
|
|
AUTOLOAD |
5928
|
|
|
|
|
|
|
{ |
5929
|
0
|
|
|
0
|
|
0
|
my( $method ) = our $AUTOLOAD =~ /([^:]+)$/; |
5930
|
|
|
|
|
|
|
## print( STDERR "$AUTOLOAD: called for method \"$method\"\n" ); |
5931
|
|
|
|
|
|
|
## If we are chained, return our null object, so the chain continues to work |
5932
|
0
|
0
|
|
|
|
0
|
if( want( 'OBJECT' ) ) |
5933
|
|
|
|
|
|
|
{ |
5934
|
|
|
|
|
|
|
## No, this is NOT a typo. rreturn() is a function of module Want |
5935
|
0
|
|
|
|
|
0
|
print( STDERR "$AUTOLOAD: Returning the object itself (", ref( $_[0] ), ")\n" ); |
5936
|
0
|
|
|
|
|
0
|
rreturn( $_[0] ); |
5937
|
|
|
|
|
|
|
} |
5938
|
|
|
|
|
|
|
## Otherwise, we return infinity, whether positive or negative or NaN depending on what was set |
5939
|
|
|
|
|
|
|
## print( STDERR "$AUTOLOAD: returning '", $_[0]->{_number}, "'\n" ); |
5940
|
0
|
|
|
|
|
0
|
return( $_[0]->{_number} ); |
5941
|
|
|
|
|
|
|
}; |
5942
|
|
|
|
|
|
|
|
5943
|
|
|
|
0
|
|
|
DESTROY {}; |
5944
|
|
|
|
|
|
|
|
5945
|
|
|
|
|
|
|
## Purpose is to allow chaining of methods when infinity is returned |
5946
|
|
|
|
|
|
|
## At the end of the chain, Inf or -Inf is returned |
5947
|
|
|
|
|
|
|
package Module::Generic::Infinity; |
5948
|
|
|
|
|
|
|
BEGIN |
5949
|
|
|
|
|
|
|
{ |
5950
|
6
|
|
|
6
|
|
53
|
use strict; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
143
|
|
5951
|
6
|
|
|
6
|
|
35
|
use warnings; |
|
6
|
|
|
|
|
22
|
|
|
6
|
|
|
|
|
217
|
|
5952
|
6
|
|
|
6
|
|
32
|
use parent -norequire, qw( Module::Generic::NumberSpecial ); |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
29
|
|
5953
|
6
|
|
|
6
|
|
563
|
our( $VERSION ) = '0.1.0'; |
5954
|
|
|
|
|
|
|
}; |
5955
|
|
|
|
|
|
|
|
5956
|
1
|
|
|
1
|
|
6
|
sub is_infinite { return( 1 ); } |
5957
|
|
|
|
|
|
|
|
5958
|
|
|
|
|
|
|
package Module::Generic::Nan; |
5959
|
|
|
|
|
|
|
BEGIN |
5960
|
|
|
|
|
|
|
{ |
5961
|
6
|
|
|
6
|
|
35
|
use strict; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
185
|
|
5962
|
6
|
|
|
6
|
|
29
|
use warnings; |
|
6
|
|
|
|
|
10
|
|
|
6
|
|
|
|
|
182
|
|
5963
|
6
|
|
|
6
|
|
30
|
use parent -norequire, qw( Module::Generic::NumberSpecial ); |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
26
|
|
5964
|
6
|
|
|
6
|
|
507
|
our( $VERSION ) = '0.1.0'; |
5965
|
|
|
|
|
|
|
}; |
5966
|
|
|
|
|
|
|
|
5967
|
1
|
|
|
1
|
|
7
|
sub is_nan { return( 1 ); } |
5968
|
|
|
|
|
|
|
|
5969
|
|
|
|
|
|
|
|
5970
|
|
|
|
|
|
|
package Module::Generic::Hash; |
5971
|
|
|
|
|
|
|
BEGIN |
5972
|
|
|
|
|
|
|
{ |
5973
|
6
|
|
|
6
|
|
34
|
use strict; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
127
|
|
5974
|
6
|
|
|
6
|
|
31
|
use warnings::register; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
814
|
|
5975
|
6
|
|
|
6
|
|
37
|
use parent -norequire, qw( Module::Generic ); |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
28
|
|
5976
|
|
|
|
|
|
|
use overload ( |
5977
|
|
|
|
|
|
|
## '""' => 'as_string', |
5978
|
1
|
|
|
1
|
|
11
|
'eq' => sub { _obj_eq(@_) }, |
5979
|
1
|
|
|
1
|
|
4
|
'ne' => sub { !_obj_eq(@_) }, |
5980
|
4
|
|
|
4
|
|
21
|
'<' => sub { _obj_comp( @_, '<') }, |
5981
|
3
|
|
|
3
|
|
26
|
'>' => sub { _obj_comp( @_, '>') }, |
5982
|
1
|
|
|
1
|
|
6
|
'<=' => sub { _obj_comp( @_, '<=') }, |
5983
|
2
|
|
|
2
|
|
12
|
'>=' => sub { _obj_comp( @_, '>=') }, |
5984
|
0
|
|
|
0
|
|
0
|
'==' => sub { _obj_comp( @_, '>=') }, |
5985
|
0
|
|
|
0
|
|
0
|
'!=' => sub { _obj_comp( @_, '>=') }, |
5986
|
1
|
|
|
1
|
|
5
|
'lt' => sub { _obj_comp( @_, 'lt') }, |
5987
|
1
|
|
|
1
|
|
6
|
'gt' => sub { _obj_comp( @_, 'gt') }, |
5988
|
0
|
|
|
0
|
|
0
|
'le' => sub { _obj_comp( @_, 'le') }, |
5989
|
0
|
|
|
0
|
|
0
|
'ge' => sub { _obj_comp( @_, 'ge') }, |
5990
|
6
|
|
|
|
|
110
|
fallback => 1, |
5991
|
6
|
|
|
6
|
|
1476
|
); |
|
6
|
|
|
|
|
12
|
|
5992
|
6
|
|
|
6
|
|
1253
|
use Data::Dumper; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
342
|
|
5993
|
6
|
|
|
6
|
|
4669
|
use JSON; |
|
6
|
|
|
|
|
55704
|
|
|
6
|
|
|
|
|
39
|
|
5994
|
6
|
|
|
6
|
|
930
|
use Clone (); |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
116
|
|
5995
|
6
|
|
|
6
|
|
33
|
use Regexp::Common; |
|
6
|
|
|
|
|
12
|
|
|
6
|
|
|
|
|
59
|
|
5996
|
|
|
|
|
|
|
}; |
5997
|
|
|
|
|
|
|
|
5998
|
|
|
|
|
|
|
sub new |
5999
|
|
|
|
|
|
|
{ |
6000
|
134
|
|
|
134
|
|
468
|
my $that = shift( @_ ); |
6001
|
134
|
|
66
|
|
|
647
|
my $class = ref( $that ) || $that; |
6002
|
134
|
|
50
|
|
|
517
|
my $data = shift( @_ ) || |
6003
|
|
|
|
|
|
|
return( $that->error( "No hash was provided to initiate a $class hash object." ) ); |
6004
|
134
|
50
|
|
|
|
624
|
return( $that->error( "I was expecting an hash, but instead got '$data'." ) ) if( Scalar::Util::reftype( $data ) ne 'HASH' ); |
6005
|
134
|
|
|
|
|
343
|
my $tied = tied( %$data ); |
6006
|
134
|
50
|
|
|
|
356
|
return( $that->error( "Hash provided is already tied to ", ref( $tied ), " and our package $class cannot use it, or it would disrupt the tie." ) ) if( $tied ); |
6007
|
134
|
|
|
|
|
313
|
my %hash = (); |
6008
|
|
|
|
|
|
|
## This enables access to the hash just like a real hash while still the user an call our object methods |
6009
|
134
|
|
|
|
|
1469
|
my $obj = tie( %hash, 'Module::Generic::TieHash', { |
6010
|
|
|
|
|
|
|
disable => ['Module::Generic'], |
6011
|
|
|
|
|
|
|
debug => 0, |
6012
|
|
|
|
|
|
|
}); |
6013
|
134
|
|
|
|
|
564
|
my $self = bless( \%hash => $class ); |
6014
|
134
|
|
|
|
|
706
|
$obj->enable( 1 ); |
6015
|
134
|
|
|
|
|
1141
|
my @keys = CORE::keys( %$data ); |
6016
|
134
|
|
|
|
|
4744
|
@hash{ @keys } = @$data{ @keys }; |
6017
|
134
|
|
|
|
|
1310
|
$obj->enable( 0 ); |
6018
|
134
|
|
|
|
|
832
|
$self->SUPER::init( @_ ); |
6019
|
134
|
|
|
|
|
515
|
$obj->enable( 1 ); |
6020
|
134
|
|
|
|
|
748
|
return( $self ); |
6021
|
|
|
|
|
|
|
} |
6022
|
|
|
|
|
|
|
|
6023
|
1
|
|
|
1
|
|
6
|
sub as_string { return( shift->dump ); } |
6024
|
|
|
|
|
|
|
|
6025
|
|
|
|
|
|
|
sub clone |
6026
|
|
|
|
|
|
|
{ |
6027
|
1
|
|
|
1
|
|
5
|
my $self = shift( @_ ); |
6028
|
1
|
|
|
|
|
5
|
$self->_tie_object->enable( 0 ); |
6029
|
1
|
|
|
|
|
5
|
my $data = $self->{data}; |
6030
|
1
|
|
|
|
|
31
|
my $clone = Clone::clone( $data ); |
6031
|
1
|
|
|
|
|
6
|
$self->_tie_object->enable( 1 ); |
6032
|
1
|
|
|
|
|
8
|
return( $self->new( $clone ) ); |
6033
|
|
|
|
|
|
|
} |
6034
|
|
|
|
|
|
|
|
6035
|
4
|
|
|
4
|
|
19
|
sub debug { return( shift->_internal( 'debug', '_set_get_number', @_ ) ); } |
6036
|
|
|
|
|
|
|
|
6037
|
2
|
|
|
2
|
|
583
|
sub defined { CORE::defined( $_[0]->{ $_[1] } ); } |
6038
|
|
|
|
|
|
|
|
6039
|
1
|
|
|
1
|
|
12
|
sub delete { return( CORE::delete( shift->{ shift( @_ ) } ) ); } |
6040
|
|
|
|
|
|
|
|
6041
|
|
|
|
|
|
|
sub dump |
6042
|
|
|
|
|
|
|
{ |
6043
|
3
|
|
|
3
|
|
9
|
my $self = shift( @_ ); |
6044
|
3
|
|
|
|
|
10
|
return( $self->_dumper( $self ) ); |
6045
|
|
|
|
|
|
|
} |
6046
|
|
|
|
|
|
|
|
6047
|
|
|
|
|
|
|
sub each |
6048
|
|
|
|
|
|
|
{ |
6049
|
1
|
|
|
1
|
|
3
|
my $self = shift( @_ ); |
6050
|
1
|
|
50
|
|
|
5
|
my $code = shift( @_ ) || return( $self->error( "No subroutine callback as provided for each" ) ); |
6051
|
1
|
50
|
|
|
|
6
|
return( $self->error( "I was expecting a reference to a subroutine for the callback to each, but got '$code' instead." ) ) if( ref( $code ) ne 'CODE' ); |
6052
|
1
|
|
|
|
|
5
|
while( my( $k, $v ) = CORE::each( %$self ) ) |
6053
|
|
|
|
|
|
|
{ |
6054
|
4
|
50
|
|
|
|
13
|
CORE::defined( $code->( $k, $v ) ) || CORE::last; |
6055
|
|
|
|
|
|
|
} |
6056
|
1
|
|
|
|
|
4
|
return( $self ); |
6057
|
|
|
|
|
|
|
} |
6058
|
|
|
|
|
|
|
|
6059
|
1
|
|
|
1
|
|
6
|
sub exists { return( CORE::exists( shift->{ shift( @_ ) } ) ); } |
6060
|
|
|
|
|
|
|
|
6061
|
1
|
|
|
1
|
|
6
|
sub for { return( shift->foreach( @_ ) ); } |
6062
|
|
|
|
|
|
|
|
6063
|
|
|
|
|
|
|
sub foreach |
6064
|
|
|
|
|
|
|
{ |
6065
|
1
|
|
|
1
|
|
3
|
my $self = shift( @_ ); |
6066
|
1
|
|
50
|
|
|
5
|
my $code = shift( @_ ) || return( $self->error( "No subroutine callback as provided for each" ) ); |
6067
|
1
|
50
|
|
|
|
5
|
return( $self->error( "I was expecting a reference to a subroutine for the callback to each, but got '$code' instead." ) ) if( ref( $code ) ne 'CODE' ); |
6068
|
1
|
|
|
|
|
5
|
CORE::foreach my $k ( CORE::keys( %$self ) ) |
6069
|
|
|
|
|
|
|
{ |
6070
|
4
|
|
|
|
|
1742
|
local $_ = $self->{ $k }; |
6071
|
4
|
50
|
|
|
|
20
|
CORE::defined( $code->( $k, $self->{ $k } ) ) || CORE::last; |
6072
|
|
|
|
|
|
|
} |
6073
|
1
|
|
|
|
|
556
|
return( $self ); |
6074
|
|
|
|
|
|
|
} |
6075
|
|
|
|
|
|
|
|
6076
|
0
|
|
|
0
|
|
0
|
sub get { return( $_[0]->{ $_[1] } ); } |
6077
|
|
|
|
|
|
|
|
6078
|
|
|
|
|
|
|
sub json |
6079
|
|
|
|
|
|
|
{ |
6080
|
2
|
|
|
2
|
|
4
|
my $self = shift( @_ ); |
6081
|
2
|
|
|
|
|
5
|
my $opts = {}; |
6082
|
2
|
100
|
|
|
|
10
|
$opts = pop( @_ ) if( ref( $_[-1] ) eq 'HASH' ); |
6083
|
2
|
|
|
|
|
8
|
$self->_tie_object->enable( 0 ); |
6084
|
2
|
|
|
|
|
11
|
my $data = $self->{data}; |
6085
|
2
|
|
|
|
|
6
|
my $json; |
6086
|
2
|
100
|
|
|
|
6
|
if( $opts->{pretty} ) |
6087
|
|
|
|
|
|
|
{ |
6088
|
1
|
|
|
|
|
60
|
$json = JSON->new->pretty->utf8->indent(1)->relaxed(1)->canonical(1)->allow_nonref->encode( $data ); |
6089
|
|
|
|
|
|
|
} |
6090
|
|
|
|
|
|
|
else |
6091
|
|
|
|
|
|
|
{ |
6092
|
1
|
|
|
|
|
17
|
$json = JSON->new->utf8->canonical(1)->allow_nonref->encode( $data ); |
6093
|
|
|
|
|
|
|
} |
6094
|
2
|
|
|
|
|
30
|
$self->_tie_object->enable( 1 ); |
6095
|
2
|
|
|
|
|
9
|
return( Module::Generic::Scalar->new( $json ) ); |
6096
|
|
|
|
|
|
|
} |
6097
|
|
|
|
|
|
|
|
6098
|
|
|
|
|
|
|
# $h->keys->sort |
6099
|
1
|
|
|
1
|
|
655
|
sub keys { return( Module::Generic::Array->new( [ CORE::keys( %{$_[0]} ) ] ) ); } |
|
1
|
|
|
|
|
7
|
|
6100
|
|
|
|
|
|
|
|
6101
|
21
|
|
|
21
|
|
53
|
sub length { return( Module::Generic::Number->new( CORE::scalar( CORE::keys( %{$_[0]} ) ) ) ); } |
|
21
|
|
|
|
|
155
|
|
6102
|
|
|
|
|
|
|
|
6103
|
|
|
|
|
|
|
sub merge |
6104
|
|
|
|
|
|
|
{ |
6105
|
2
|
|
|
2
|
|
6
|
my $self = shift( @_ ); |
6106
|
2
|
|
|
|
|
4
|
my $hash = {}; |
6107
|
2
|
|
|
|
|
5
|
$hash = shift( @_ ); |
6108
|
2
|
50
|
33
|
|
|
21
|
return( $self->error( "No valid hash provided." ) ) if( !$hash || Scalar::Util::reftype( $hash ) ne 'HASH' ); |
6109
|
|
|
|
|
|
|
## $self->message( 3, "Hash provided is: ", sub{ $self->dumper( $hash ) } ); |
6110
|
2
|
|
|
|
|
5
|
my $opts = {}; |
6111
|
2
|
100
|
66
|
|
|
12
|
$opts = pop( @_ ) if( @_ && ref( $_[-1] ) eq 'HASH' ); |
6112
|
2
|
100
|
|
|
|
7
|
$opts->{overwrite} = 1 unless( CORE::exists( $opts->{overwrite} ) ); |
6113
|
2
|
|
|
|
|
7
|
$self->_tie_object->enable( 0 ); |
6114
|
2
|
|
|
|
|
9
|
my $data = $self->{data}; |
6115
|
2
|
|
|
|
|
6
|
my $seen = {}; |
6116
|
|
|
|
|
|
|
local $copy = sub |
6117
|
|
|
|
|
|
|
{ |
6118
|
4
|
|
|
4
|
|
8
|
my $this = shift( @_ ); |
6119
|
4
|
|
|
|
|
7
|
my $to = shift( @_ ); |
6120
|
4
|
|
|
|
|
7
|
my $p = {}; |
6121
|
4
|
100
|
66
|
|
|
18
|
$p = shift( @_ ) if( @_ && ref( $_[-1] ) eq 'HASH' ); |
6122
|
|
|
|
|
|
|
## $self->message( 3, "Merging hash ", sub{ $self->dumper( $this ) }, " to hash ", sub{ $self->dumper( $to ) }, " and with parameters ", sub{ $self->dumper( $p ) } ); |
6123
|
4
|
|
|
|
|
16
|
CORE::foreach my $k ( CORE::keys( %$this ) ) |
6124
|
|
|
|
|
|
|
{ |
6125
|
|
|
|
|
|
|
# $self->message( 3, "Skipping existing property '$k'." ) if( CORE::exists( $to->{ $k } ) && !$p->{overwrite} ); |
6126
|
14
|
100
|
100
|
|
|
44
|
next if( CORE::exists( $to->{ $k } ) && !$p->{overwrite} ); |
6127
|
8
|
100
|
33
|
|
|
34
|
if( ref( $this->{ $k } ) eq 'HASH' || |
|
|
|
66
|
|
|
|
|
6128
|
|
|
|
|
|
|
( Scalar::Util::blessed( $this->{ $k } ) && $this->{ $k }->isa( 'Module::Generic::Hash' ) ) ) |
6129
|
|
|
|
|
|
|
{ |
6130
|
2
|
|
|
|
|
9
|
my $addr = Scalar::Util::refaddr( $this->{ $k } ); |
6131
|
|
|
|
|
|
|
# $self->message( 3, "Checking if hash in property '$k' was already processed with address '$addr'." ); |
6132
|
2
|
50
|
|
|
|
8
|
if( CORE::exists( $seen->{ $addr } ) ) |
6133
|
|
|
|
|
|
|
{ |
6134
|
0
|
|
|
|
|
0
|
$to->{ $k } = $seen->{ $addr }; |
6135
|
0
|
|
|
|
|
0
|
next; |
6136
|
|
|
|
|
|
|
} |
6137
|
|
|
|
|
|
|
else |
6138
|
|
|
|
|
|
|
{ |
6139
|
2
|
100
|
|
|
|
12
|
$to->{ $k } = {} unless( Scalar::Util::reftype( $to->{ $k } ) eq 'HASH' ); |
6140
|
2
|
|
|
|
|
11
|
$copy->( $this->{ $k }, $to->{ $k } ); |
6141
|
|
|
|
|
|
|
} |
6142
|
2
|
|
|
|
|
6
|
$seen->{ $addr } = $this->{ $k }; |
6143
|
|
|
|
|
|
|
} |
6144
|
|
|
|
|
|
|
else |
6145
|
|
|
|
|
|
|
{ |
6146
|
6
|
|
|
|
|
19
|
$to->{ $k } = $this->{ $k }; |
6147
|
|
|
|
|
|
|
} |
6148
|
|
|
|
|
|
|
} |
6149
|
2
|
|
|
|
|
14
|
}; |
6150
|
|
|
|
|
|
|
## $self->message( 3, "Propagating hash ", sub{ $self->dumper( $hash ) }, " to hash ", sub{ $self->dumper( $data ) } ); |
6151
|
2
|
|
|
|
|
8
|
$copy->( $hash, $data, $opts ); |
6152
|
2
|
|
|
|
|
8
|
$self->_tie_object->enable( 1 ); |
6153
|
2
|
|
|
|
|
26
|
return( $self ); |
6154
|
|
|
|
|
|
|
} |
6155
|
|
|
|
|
|
|
|
6156
|
0
|
|
|
0
|
|
0
|
sub reset { %{$_[0]} = () }; |
|
0
|
|
|
|
|
0
|
|
6157
|
|
|
|
|
|
|
|
6158
|
0
|
|
|
0
|
|
0
|
sub set { $_[0]->{ $_[1] } = $_[2]; } |
6159
|
|
|
|
|
|
|
|
6160
|
0
|
|
|
0
|
|
0
|
sub undef { %{$_[0]} = () }; |
|
0
|
|
|
|
|
0
|
|
6161
|
|
|
|
|
|
|
|
6162
|
|
|
|
|
|
|
sub values |
6163
|
|
|
|
|
|
|
{ |
6164
|
1
|
|
|
1
|
|
3
|
my $self = shift( @_ ); |
6165
|
1
|
|
|
|
|
3
|
my $code; |
6166
|
1
|
50
|
33
|
|
|
10
|
$code = shift( @_ ) if( @_ && ref( $_[0] ) eq 'CODE' ); |
6167
|
1
|
|
|
|
|
3
|
my $opts = {}; |
6168
|
1
|
50
|
|
|
|
8
|
$opts = pop( @_ ) if( Scalar::Util::reftype( $_[-1] ) eq 'HASH' ); |
6169
|
1
|
50
|
|
|
|
4
|
if( $code ) |
6170
|
|
|
|
|
|
|
{ |
6171
|
1
|
50
|
|
|
|
4
|
if( $opts->{sort} ) |
6172
|
|
|
|
|
|
|
{ |
6173
|
1
|
|
|
|
|
7
|
return( Module::Generic::Array->new( [ CORE::map( $code->( $_ ), CORE::sort( CORE::values( %$self ) ) ) ] ) ); |
6174
|
|
|
|
|
|
|
} |
6175
|
|
|
|
|
|
|
else |
6176
|
|
|
|
|
|
|
{ |
6177
|
0
|
|
|
|
|
0
|
return( Module::Generic::Array->new( [ CORE::map( $code->( $_ ), CORE::values( %$self ) ) ] ) ); |
6178
|
|
|
|
|
|
|
} |
6179
|
|
|
|
|
|
|
} |
6180
|
|
|
|
|
|
|
else |
6181
|
|
|
|
|
|
|
{ |
6182
|
0
|
0
|
|
|
|
0
|
if( $opts->{sort} ) |
6183
|
|
|
|
|
|
|
{ |
6184
|
0
|
|
|
|
|
0
|
return( Module::Generic::Array->new( [ CORE::sort( CORE::values( %$self ) ) ] ) ); |
6185
|
|
|
|
|
|
|
} |
6186
|
|
|
|
|
|
|
else |
6187
|
|
|
|
|
|
|
{ |
6188
|
0
|
|
|
|
|
0
|
return( Module::Generic::Array->new( [ CORE::values( %$self ) ] ) ); |
6189
|
|
|
|
|
|
|
} |
6190
|
|
|
|
|
|
|
} |
6191
|
|
|
|
|
|
|
} |
6192
|
|
|
|
|
|
|
|
6193
|
|
|
|
|
|
|
# sub _dumper |
6194
|
|
|
|
|
|
|
# { |
6195
|
|
|
|
|
|
|
# my $self = shift( @_ ); |
6196
|
|
|
|
|
|
|
# if( !$self->{_dumper} ) |
6197
|
|
|
|
|
|
|
# { |
6198
|
|
|
|
|
|
|
# my $d = Data::Dumper->new; |
6199
|
|
|
|
|
|
|
# $d->Indent( 1 ); |
6200
|
|
|
|
|
|
|
# $d->Useqq( 1 ); |
6201
|
|
|
|
|
|
|
# $d->Terse( 1 ); |
6202
|
|
|
|
|
|
|
# $d->Sortkeys( 1 ); |
6203
|
|
|
|
|
|
|
# $self->{_dumper} = $d; |
6204
|
|
|
|
|
|
|
# } |
6205
|
|
|
|
|
|
|
# return( $self->{_dumper}->Dumper( @_ ) ); |
6206
|
|
|
|
|
|
|
# } |
6207
|
|
|
|
|
|
|
# |
6208
|
|
|
|
|
|
|
sub _dumper |
6209
|
|
|
|
|
|
|
{ |
6210
|
5
|
|
|
5
|
|
10
|
my $self = shift( @_ ); |
6211
|
5
|
|
|
|
|
12
|
$self->_tie_object->enable( 0 ); |
6212
|
5
|
|
|
|
|
28
|
my $data = $self->{data}; |
6213
|
5
|
|
|
|
|
36
|
my $d = Data::Dumper->new( [ $data ] ); |
6214
|
5
|
|
|
|
|
179
|
$d->Indent( 1 ); |
6215
|
5
|
|
|
|
|
77
|
$d->Useqq( 1 ); |
6216
|
5
|
|
|
|
|
83
|
$d->Terse( 1 ); |
6217
|
5
|
|
|
|
|
36
|
$d->Sortkeys( 1 ); |
6218
|
|
|
|
|
|
|
# $d->Freezer( '' ); |
6219
|
5
|
|
|
|
|
36
|
$d->Bless( '' ); |
6220
|
|
|
|
|
|
|
# return( $d->Dump ); |
6221
|
5
|
|
|
|
|
34
|
my $str = $d->Dump; |
6222
|
5
|
|
|
|
|
259
|
$self->_tie_object->enable( 1 ); |
6223
|
5
|
|
|
|
|
52
|
return( $str ); |
6224
|
|
|
|
|
|
|
} |
6225
|
|
|
|
|
|
|
|
6226
|
|
|
|
|
|
|
sub _internal |
6227
|
|
|
|
|
|
|
{ |
6228
|
4
|
|
|
4
|
|
11
|
my $self = shift( @_ ); |
6229
|
4
|
|
|
|
|
10
|
my $field = shift( @_ ); |
6230
|
4
|
|
|
|
|
8
|
my $meth = shift( @_ ); |
6231
|
|
|
|
|
|
|
# print( STDERR ref( $self ), "::_internal -> Caling method '$meth' for field '$field' with value '", join( "', '", @_ ), "'\n" ); |
6232
|
4
|
|
|
|
|
15
|
$self->_tie_object->enable( 0 ); |
6233
|
4
|
|
|
|
|
12
|
my( @resA, $resB ); |
6234
|
4
|
50
|
|
|
|
12
|
if( wantarray ) |
6235
|
|
|
|
|
|
|
{ |
6236
|
0
|
|
|
|
|
0
|
@resA = $self->$meth( $field, @_ ); |
6237
|
|
|
|
|
|
|
# $self->message( "Resturn list value is: '@resA'" ); |
6238
|
|
|
|
|
|
|
} |
6239
|
|
|
|
|
|
|
else |
6240
|
|
|
|
|
|
|
{ |
6241
|
4
|
|
|
|
|
21
|
$resB = $self->$meth( $field, @_ ); |
6242
|
|
|
|
|
|
|
# $self->message( "Resturn scalar value is: '$resB'" ); |
6243
|
|
|
|
|
|
|
} |
6244
|
4
|
|
|
|
|
14
|
$self->_tie_object->enable( 1 ); |
6245
|
4
|
50
|
|
|
|
26
|
return( wantarray ? @resA : $resB ); |
6246
|
|
|
|
|
|
|
} |
6247
|
|
|
|
|
|
|
|
6248
|
|
|
|
|
|
|
sub _obj_comp |
6249
|
|
|
|
|
|
|
{ |
6250
|
12
|
|
|
12
|
|
47
|
my( $self, $other, $swap, $op ) = @_; |
6251
|
12
|
|
|
|
|
32
|
my( $lA, $lB ); |
6252
|
12
|
|
|
|
|
48
|
$lA = $self->length; |
6253
|
12
|
100
|
66
|
|
|
153
|
if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Hash' ) ) |
|
|
50
|
|
|
|
|
|
6254
|
|
|
|
|
|
|
{ |
6255
|
7
|
|
|
|
|
35
|
$lB = $other->length; |
6256
|
|
|
|
|
|
|
} |
6257
|
|
|
|
|
|
|
elsif( $other =~ /^$RE{num}{real}$/ ) |
6258
|
|
|
|
|
|
|
{ |
6259
|
5
|
|
|
|
|
764
|
$lB = $other; |
6260
|
|
|
|
|
|
|
} |
6261
|
|
|
|
|
|
|
else |
6262
|
|
|
|
|
|
|
{ |
6263
|
0
|
|
|
|
|
0
|
return; |
6264
|
|
|
|
|
|
|
} |
6265
|
12
|
100
|
|
|
|
129
|
my $expr = $swap ? "$lB $op $lA" : "$lA $op $lB"; |
6266
|
12
|
|
|
|
|
1316
|
return( eval( $expr ) ); |
6267
|
|
|
|
|
|
|
} |
6268
|
|
|
|
|
|
|
|
6269
|
0
|
|
|
0
|
|
0
|
sub _printer { return( shift->printer( @_ ) ); } |
6270
|
|
|
|
|
|
|
|
6271
|
|
|
|
|
|
|
sub _obj_eq |
6272
|
|
|
|
|
|
|
{ |
6273
|
6
|
|
|
6
|
|
919920
|
no overloading; |
|
6
|
|
|
|
|
18
|
|
|
6
|
|
|
|
|
1027
|
|
6274
|
2
|
|
|
2
|
|
6
|
my $self = shift( @_ ); |
6275
|
2
|
|
|
|
|
4
|
my $other = shift( @_ ); |
6276
|
2
|
|
|
|
|
10
|
my $strA = $self->_dumper( $self ); |
6277
|
2
|
|
|
|
|
5
|
my $strB; |
6278
|
2
|
50
|
33
|
|
|
17
|
if( Scalar::Util::blessed( $other ) && $other->isa( 'Module::Generic::Hash' ) ) |
|
|
0
|
|
|
|
|
|
6279
|
|
|
|
|
|
|
{ |
6280
|
2
|
|
|
|
|
8
|
$strB = $other->dump; |
6281
|
|
|
|
|
|
|
} |
6282
|
|
|
|
|
|
|
elsif( Scalar::Util::reftype( $other ) eq 'HASH' ) |
6283
|
|
|
|
|
|
|
{ |
6284
|
0
|
|
|
|
|
0
|
$strB = $self->_dumper( $other ) |
6285
|
|
|
|
|
|
|
} |
6286
|
|
|
|
|
|
|
else |
6287
|
|
|
|
|
|
|
{ |
6288
|
0
|
|
|
|
|
0
|
return( 0 ); |
6289
|
|
|
|
|
|
|
} |
6290
|
2
|
|
|
|
|
17
|
return( $strA eq $strB ); |
6291
|
|
|
|
|
|
|
} |
6292
|
|
|
|
|
|
|
|
6293
|
|
|
|
|
|
|
sub _tie_object |
6294
|
|
|
|
|
|
|
{ |
6295
|
28
|
|
|
28
|
|
51
|
my $self = shift( @_ ); |
6296
|
28
|
|
|
|
|
111
|
return( tied( %$self ) ); |
6297
|
|
|
|
|
|
|
} |
6298
|
|
|
|
|
|
|
|
6299
|
|
|
|
|
|
|
package Module::Generic::TieHash; |
6300
|
|
|
|
|
|
|
BEGIN |
6301
|
|
|
|
|
|
|
{ |
6302
|
6
|
|
|
6
|
|
47
|
use strict; |
|
6
|
|
|
|
|
16
|
|
|
6
|
|
|
|
|
153
|
|
6303
|
6
|
|
|
6
|
|
38
|
use warnings::register; |
|
6
|
|
|
|
|
15
|
|
|
6
|
|
|
|
|
910
|
|
6304
|
6
|
|
|
6
|
|
45
|
use parent -norequire, qw( Module::Generic ); |
|
6
|
|
|
|
|
19
|
|
|
6
|
|
|
|
|
68
|
|
6305
|
6
|
|
|
6
|
|
348
|
use Scalar::Util (); |
|
6
|
|
|
|
|
17
|
|
|
6
|
|
|
|
|
156
|
|
6306
|
6
|
|
|
6
|
|
4217
|
our( $VERSION ) = '0.1.0'; |
6307
|
|
|
|
|
|
|
}; |
6308
|
|
|
|
|
|
|
|
6309
|
|
|
|
|
|
|
sub TIEHASH |
6310
|
|
|
|
|
|
|
{ |
6311
|
134
|
|
|
134
|
|
480
|
my $self = shift( @_ ); |
6312
|
134
|
|
|
|
|
288
|
my $opts = {}; |
6313
|
134
|
50
|
|
|
|
584
|
$opts = shift( @_ ) if( @_ ); |
6314
|
134
|
50
|
|
|
|
675
|
if( Scalar::Util::reftype( $opts ) ne 'HASH' ) |
6315
|
|
|
|
|
|
|
{ |
6316
|
0
|
0
|
|
|
|
0
|
warn( "Parameters provided ($opts) is not an hash reference.\n" ) if( $self->_warnings_is_enabled ); |
6317
|
0
|
|
|
|
|
0
|
return; |
6318
|
|
|
|
|
|
|
} |
6319
|
134
|
|
|
|
|
308
|
my $disable = []; |
6320
|
134
|
50
|
|
|
|
811
|
$disable = $opts->{disable} if( Scalar::Util::reftype( $opts->{disable} ) ); |
6321
|
134
|
|
|
|
|
309
|
my $list = {}; |
6322
|
134
|
|
|
|
|
718
|
@$list{ @$disable } = ( 1 ) x scalar( @$disable ); |
6323
|
|
|
|
|
|
|
my $hash = |
6324
|
|
|
|
|
|
|
{ |
6325
|
|
|
|
|
|
|
## The caller sets this to its class, so we can differentiate calls from inside and outside our caller's package |
6326
|
|
|
|
|
|
|
disable => $list, |
6327
|
|
|
|
|
|
|
debug => $opts->{debug}, |
6328
|
|
|
|
|
|
|
## When disabled, the Tie::Hash system will return hash key values directly under $self instead of $self->{data} |
6329
|
|
|
|
|
|
|
## Disabled by default so the new() method can access its setup data directly under $self |
6330
|
|
|
|
|
|
|
## Then new() can call enable to active it |
6331
|
134
|
|
|
|
|
808
|
enable => 0, |
6332
|
|
|
|
|
|
|
## Where to store the actual hash data |
6333
|
|
|
|
|
|
|
data => {}, |
6334
|
|
|
|
|
|
|
}; |
6335
|
134
|
|
33
|
|
|
770
|
my $class = ref( $self ) || $self; |
6336
|
134
|
|
|
|
|
625
|
return( bless( $hash => $class ) ); |
6337
|
|
|
|
|
|
|
} |
6338
|
|
|
|
|
|
|
|
6339
|
|
|
|
|
|
|
sub CLEAR |
6340
|
|
|
|
|
|
|
{ |
6341
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
6342
|
0
|
|
|
|
|
0
|
my $data = $self->{data}; |
6343
|
0
|
|
|
|
|
0
|
%$data = (); |
6344
|
|
|
|
|
|
|
} |
6345
|
|
|
|
|
|
|
|
6346
|
|
|
|
|
|
|
sub DELETE |
6347
|
|
|
|
|
|
|
{ |
6348
|
1
|
|
|
1
|
|
3
|
my $self = shift( @_ ); |
6349
|
1
|
|
|
|
|
3
|
my $data = $self->{data}; |
6350
|
1
|
|
|
|
|
3
|
my $key = shift( @_ ); |
6351
|
1
|
|
|
|
|
5
|
my $caller = caller; |
6352
|
1
|
50
|
33
|
|
|
4
|
if( $self->_exclude( $caller ) || !$self->{enable} ) |
6353
|
|
|
|
|
|
|
# if( !$self->{enable} ) |
6354
|
|
|
|
|
|
|
{ |
6355
|
0
|
|
|
|
|
0
|
CORE::delete( $self->{ $key } ); |
6356
|
|
|
|
|
|
|
} |
6357
|
|
|
|
|
|
|
else |
6358
|
|
|
|
|
|
|
{ |
6359
|
1
|
|
|
|
|
8
|
CORE::delete( $data->{ $key } ); |
6360
|
|
|
|
|
|
|
} |
6361
|
|
|
|
|
|
|
} |
6362
|
|
|
|
|
|
|
|
6363
|
|
|
|
|
|
|
sub EXISTS |
6364
|
|
|
|
|
|
|
{ |
6365
|
3
|
|
|
3
|
|
8
|
my $self = shift( @_ ); |
6366
|
3
|
|
|
|
|
8
|
my $data = $self->{data}; |
6367
|
3
|
|
|
|
|
8
|
my $key = shift( @_ ); |
6368
|
3
|
|
|
|
|
7
|
my $caller = caller; |
6369
|
3
|
50
|
33
|
|
|
10
|
if( $self->_exclude( $caller ) || !$self->{enable} ) |
6370
|
|
|
|
|
|
|
# if( !$self->{enable} ) |
6371
|
|
|
|
|
|
|
{ |
6372
|
0
|
|
|
|
|
0
|
CORE::exists( $self->{ $key } ); |
6373
|
|
|
|
|
|
|
} |
6374
|
|
|
|
|
|
|
else |
6375
|
|
|
|
|
|
|
{ |
6376
|
3
|
|
|
|
|
24
|
CORE::exists( $data->{ $key } ); |
6377
|
|
|
|
|
|
|
} |
6378
|
|
|
|
|
|
|
} |
6379
|
|
|
|
|
|
|
|
6380
|
|
|
|
|
|
|
sub FETCH |
6381
|
|
|
|
|
|
|
{ |
6382
|
576
|
|
|
576
|
|
1124
|
my $self = shift( @_ ); |
6383
|
576
|
|
|
|
|
1027
|
my $data = $self->{data}; |
6384
|
576
|
|
|
|
|
956
|
my $key = shift( @_ ); |
6385
|
576
|
|
|
|
|
1020
|
my $caller = caller; |
6386
|
|
|
|
|
|
|
## print( STDERR "FETCH($caller)[enable=$self->{enable}] <- '$key''\n" ); |
6387
|
576
|
100
|
100
|
|
|
1152
|
if( $self->_exclude( $caller ) || !$self->{enable} ) |
6388
|
|
|
|
|
|
|
# if( !$self->{enable} ) |
6389
|
|
|
|
|
|
|
{ |
6390
|
|
|
|
|
|
|
#print( STDERR "FETCH($caller)[owner calling, enable=$self->{enable}] <- '$key' <- '$self->{$key}'\n" ); |
6391
|
554
|
|
|
|
|
2178
|
return( $self->{ $key } ) |
6392
|
|
|
|
|
|
|
} |
6393
|
|
|
|
|
|
|
else |
6394
|
|
|
|
|
|
|
{ |
6395
|
|
|
|
|
|
|
#print( STDERR "FETCH($caller)[enable=$self->{enable}] <- '$key' <- '$data->{$key}'\n" ); |
6396
|
22
|
|
|
|
|
104
|
return( $data->{ $key } ); |
6397
|
|
|
|
|
|
|
} |
6398
|
|
|
|
|
|
|
} |
6399
|
|
|
|
|
|
|
|
6400
|
|
|
|
|
|
|
sub FIRSTKEY |
6401
|
|
|
|
|
|
|
{ |
6402
|
26
|
|
|
26
|
|
73
|
my $self = shift( @_ ); |
6403
|
26
|
|
|
|
|
74
|
my $data = $self->{data}; |
6404
|
26
|
|
|
|
|
59
|
my @keys = (); |
6405
|
26
|
|
|
|
|
80
|
my $caller = caller; |
6406
|
26
|
50
|
33
|
|
|
112
|
if( $self->_exclude( $caller ) || !$self->{enable} ) |
6407
|
|
|
|
|
|
|
# if( !$self->{enable} ) |
6408
|
|
|
|
|
|
|
{ |
6409
|
0
|
|
|
|
|
0
|
@keys = keys( %$self ); |
6410
|
|
|
|
|
|
|
} |
6411
|
|
|
|
|
|
|
else |
6412
|
|
|
|
|
|
|
{ |
6413
|
26
|
|
|
|
|
125
|
@keys = keys( %$data ); |
6414
|
|
|
|
|
|
|
} |
6415
|
26
|
|
|
|
|
89
|
$self->{ITERATOR} = \@keys; |
6416
|
26
|
|
|
|
|
134
|
return( shift( @keys ) ); |
6417
|
|
|
|
|
|
|
} |
6418
|
|
|
|
|
|
|
|
6419
|
|
|
|
|
|
|
sub NEXTKEY |
6420
|
|
|
|
|
|
|
{ |
6421
|
88
|
|
|
88
|
|
2428
|
my $self = shift( @_ ); |
6422
|
88
|
|
|
|
|
144
|
my $data = $self->{data}; |
6423
|
88
|
50
|
|
|
|
219
|
my $keys = ref( $self->{ITERATOR} ) ? $self->{ITERATOR} : []; |
6424
|
88
|
|
|
|
|
244
|
return( shift( @$keys ) ); |
6425
|
|
|
|
|
|
|
} |
6426
|
|
|
|
|
|
|
|
6427
|
|
|
|
|
|
|
sub SCALAR |
6428
|
|
|
|
|
|
|
{ |
6429
|
0
|
|
|
0
|
|
0
|
my $self = shift( @_ ); |
6430
|
0
|
|
|
|
|
0
|
my $data = $self->{data}; |
6431
|
0
|
|
|
|
|
0
|
my $caller = caller; |
6432
|
0
|
0
|
0
|
|
|
0
|
if( $self->_exclude( $caller ) || !$self->{enable} ) |
6433
|
|
|
|
|
|
|
# if( !$self->{enable} ) |
6434
|
|
|
|
|
|
|
{ |
6435
|
0
|
|
|
|
|
0
|
return( scalar( keys( %$self ) ) ); |
6436
|
|
|
|
|
|
|
} |
6437
|
|
|
|
|
|
|
else |
6438
|
|
|
|
|
|
|
{ |
6439
|
0
|
|
|
|
|
0
|
return( scalar( keys( %$data ) ) ); |
6440
|
|
|
|
|
|
|
} |
6441
|
|
|
|
|
|
|
} |
6442
|
|
|
|
|
|
|
|
6443
|
|
|
|
|
|
|
sub STORE |
6444
|
|
|
|
|
|
|
{ |
6445
|
3947
|
|
|
3947
|
|
6450
|
my $self = shift( @_ ); |
6446
|
3947
|
|
|
|
|
5631
|
my $data = $self->{data}; |
6447
|
3947
|
|
|
|
|
6916
|
my( $key, $val ) = @_; |
6448
|
3947
|
|
|
|
|
5967
|
my $caller = caller; |
6449
|
3947
|
100
|
66
|
|
|
6436
|
if( $self->_exclude( $caller ) || !$self->{enable} ) |
6450
|
|
|
|
|
|
|
# if( !$self->{enable} ) |
6451
|
|
|
|
|
|
|
{ |
6452
|
|
|
|
|
|
|
#print( STDERR "STORE($caller)[owner calling] <- '$key' -> '$val'\n" ); |
6453
|
807
|
|
|
|
|
2574
|
$self->{ $key } = $val; |
6454
|
|
|
|
|
|
|
} |
6455
|
|
|
|
|
|
|
else |
6456
|
|
|
|
|
|
|
{ |
6457
|
|
|
|
|
|
|
#print( STDERR "STORE($caller)[enable=$self->{enable}] <- '$key' -> '$val'\n" ); |
6458
|
3140
|
|
|
|
|
11819
|
$data->{ $key } = $val; |
6459
|
|
|
|
|
|
|
} |
6460
|
|
|
|
|
|
|
} |
6461
|
|
|
|
|
|
|
|
6462
|
430
|
|
|
430
|
|
1448
|
sub enable { return( shift->_set_get_boolean( 'enable', @_ ) ); } |
6463
|
|
|
|
|
|
|
|
6464
|
|
|
|
|
|
|
sub _exclude |
6465
|
|
|
|
|
|
|
{ |
6466
|
4553
|
|
|
4553
|
|
6317
|
my $self = shift( @_ ); |
6467
|
4553
|
|
|
|
|
5977
|
my $caller = shift( @_ ); |
6468
|
|
|
|
|
|
|
## $self->message( 3, "Disable hash contains: ", sub{ $self->dump( $self->{disable} ) }); |
6469
|
4553
|
|
|
|
|
13296
|
return( CORE::exists( $self->{disable}->{ $caller } ) ); |
6470
|
|
|
|
|
|
|
} |
6471
|
|
|
|
|
|
|
|
6472
|
|
|
|
|
|
|
package Module::Generic::Tie; |
6473
|
|
|
|
|
|
|
BEGIN |
6474
|
|
|
|
|
|
|
{ |
6475
|
6
|
|
|
6
|
|
49
|
use Tie::Hash; |
|
6
|
|
|
|
|
14
|
|
|
6
|
|
|
|
|
314
|
|
6476
|
6
|
|
|
6
|
|
118
|
our( @ISA ) = qw( Tie::Hash ); |
6477
|
6
|
|
|
|
|
5902
|
our( $VERSION ) = '0.1.0'; |
6478
|
|
|
|
|
|
|
}; |
6479
|
|
|
|
|
|
|
|
6480
|
|
|
|
|
|
|
sub TIEHASH |
6481
|
|
|
|
|
|
|
{ |
6482
|
0
|
|
|
0
|
|
|
my $self = shift( @_ ); |
6483
|
0
|
|
|
|
|
|
my $pkg = ( caller() )[ 0 ]; |
6484
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::TIEHASH() called with following arguments: '", join( ', ', @_ ), "'.\n" ); |
6485
|
0
|
|
|
|
|
|
my %arg = ( @_ ); |
6486
|
0
|
|
|
|
|
|
my $auth = [ $pkg, __PACKAGE__ ]; |
6487
|
0
|
0
|
|
|
|
|
if( $arg{ 'pkg' } ) |
6488
|
|
|
|
|
|
|
{ |
6489
|
0
|
|
|
|
|
|
my $ok = delete( $arg{ 'pkg' } ); |
6490
|
0
|
0
|
|
|
|
|
push( @$auth, ref( $ok ) eq 'ARRAY' ? @$ok : $ok ); |
6491
|
|
|
|
|
|
|
} |
6492
|
0
|
|
|
|
|
|
my $priv = { 'pkg' => $auth }; |
6493
|
0
|
|
|
|
|
|
my $data = { '__priv__' => $priv }; |
6494
|
0
|
|
|
|
|
|
my @keys = keys( %arg ); |
6495
|
0
|
|
|
|
|
|
@$priv{ @keys } = @arg{ @keys }; |
6496
|
0
|
|
0
|
|
|
|
return( bless( $data, ref( $self ) || $self ) ); |
6497
|
|
|
|
|
|
|
} |
6498
|
|
|
|
|
|
|
|
6499
|
|
|
|
|
|
|
sub CLEAR |
6500
|
|
|
|
|
|
|
{ |
6501
|
0
|
|
|
0
|
|
|
my $self = shift( @_ ); |
6502
|
0
|
|
|
|
|
|
my $pkg = ( caller() )[ 0 ]; |
6503
|
|
|
|
|
|
|
## print( $err __PACKAGE__ . "::CLEAR() called by package '$pkg'.\n" ); |
6504
|
0
|
|
|
|
|
|
my $data = $self->{ '__priv__' }; |
6505
|
0
|
0
|
0
|
|
|
|
return() if( $data->{ 'readonly' } && $pkg ne __PACKAGE__ ); |
6506
|
|
|
|
|
|
|
## if( $data->{ 'readonly' } || $data->{ 'protect' } ) |
6507
|
0
|
0
|
|
|
|
|
if( !( $data->{ 'perms' } & 2 ) ) |
6508
|
|
|
|
|
|
|
{ |
6509
|
0
|
0
|
|
|
|
|
return if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) ); |
|
0
|
|
|
|
|
|
|
6510
|
|
|
|
|
|
|
} |
6511
|
0
|
|
|
|
|
|
my $key = $self->FIRSTKEY( @_ ); |
6512
|
0
|
|
|
|
|
|
my @keys = (); |
6513
|
0
|
|
|
|
|
|
while( defined( $key ) ) |
6514
|
|
|
|
|
|
|
{ |
6515
|
0
|
|
|
|
|
|
push( @keys, $key ); |
6516
|
0
|
|
|
|
|
|
$key = $self->NEXTKEY( @_, $key ); |
6517
|
|
|
|
|
|
|
} |
6518
|
0
|
|
|
|
|
|
foreach $key ( @keys ) |
6519
|
|
|
|
|
|
|
{ |
6520
|
0
|
|
|
|
|
|
$self->DELETE( @_, $key ); |
6521
|
|
|
|
|
|
|
} |
6522
|
|
|
|
|
|
|
} |
6523
|
|
|
|
|
|
|
|
6524
|
|
|
|
|
|
|
sub DELETE |
6525
|
|
|
|
|
|
|
{ |
6526
|
0
|
|
|
0
|
|
|
my $self = shift( @_ ); |
6527
|
0
|
|
|
|
|
|
my $pkg = ( caller() )[ 0 ]; |
6528
|
0
|
0
|
|
|
|
|
$pkg = ( caller( 1 ) )[ 0 ] if( $pkg eq 'Module::Generic' ); |
6529
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::DELETE() package '$pkg' tries to delete '$_[ 0 ]'\n" ); |
6530
|
0
|
|
|
|
|
|
my $data = $self->{ '__priv__' }; |
6531
|
0
|
0
|
0
|
|
|
|
return if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ ); |
6532
|
|
|
|
|
|
|
## if( $data->{ 'readonly' } || $data->{ 'protect' } ) |
6533
|
0
|
0
|
|
|
|
|
if( !( $data->{ 'perms' } & 2 ) ) |
6534
|
|
|
|
|
|
|
{ |
6535
|
0
|
0
|
|
|
|
|
return() if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) ); |
|
0
|
|
|
|
|
|
|
6536
|
|
|
|
|
|
|
} |
6537
|
0
|
|
|
|
|
|
return( delete( $self->{ shift( @_ ) } ) ); |
6538
|
|
|
|
|
|
|
} |
6539
|
|
|
|
|
|
|
|
6540
|
|
|
|
|
|
|
sub EXISTS |
6541
|
|
|
|
|
|
|
{ |
6542
|
0
|
|
|
0
|
|
|
my $self = shift( @_ ); |
6543
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::EXISTS() called from package '", ( caller() )[ 0 ], "'.\n" ); |
6544
|
0
|
0
|
0
|
|
|
|
return( 0 ) if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ ); |
6545
|
0
|
|
|
|
|
|
my $data = $self->{ '__priv__' }; |
6546
|
0
|
0
|
|
|
|
|
if( !( $data->{ 'perms' } & 4 ) ) |
6547
|
|
|
|
|
|
|
{ |
6548
|
0
|
|
|
|
|
|
my $pkg = ( caller() )[ 0 ]; |
6549
|
0
|
0
|
|
|
|
|
return( 0 ) if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) ); |
|
0
|
|
|
|
|
|
|
6550
|
|
|
|
|
|
|
} |
6551
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::EXISTS() returns: '", exists( $self->{ $_[ 0 ] } ), "'.\n" ); |
6552
|
0
|
|
|
|
|
|
return( exists( $self->{ shift( @_ ) } ) ); |
6553
|
|
|
|
|
|
|
} |
6554
|
|
|
|
|
|
|
|
6555
|
|
|
|
|
|
|
sub FETCH |
6556
|
|
|
|
|
|
|
{ |
6557
|
|
|
|
|
|
|
## return( shift->{ shift( @_ ) } ); |
6558
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::FETCH() called with arguments: '", join( ', ', @_ ), "'.\n" ); |
6559
|
0
|
|
|
0
|
|
|
my $self = shift( @_ ); |
6560
|
|
|
|
|
|
|
## This is a hidden entry, we return nothing |
6561
|
0
|
0
|
0
|
|
|
|
return() if( $_[ 0 ] eq '__priv__' && $pkg ne __PACKAGE__ ); |
6562
|
0
|
|
|
|
|
|
my $data = $self->{ '__priv__' }; |
6563
|
|
|
|
|
|
|
## If we have to protect our object, we hide its inner content if our caller is not our creator |
6564
|
|
|
|
|
|
|
## if( $data->{ 'protect' } ) |
6565
|
0
|
0
|
|
|
|
|
if( !( $data->{ 'perms' } & 4 ) ) |
6566
|
|
|
|
|
|
|
{ |
6567
|
0
|
|
|
|
|
|
my $pkg = ( caller() )[ 0 ]; |
6568
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::FETCH() package '$pkg' wants to fetch the value of '$_[ 0 ]'\n" ); |
6569
|
0
|
0
|
|
|
|
|
return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) ); |
|
0
|
|
|
|
|
|
|
6570
|
|
|
|
|
|
|
} |
6571
|
0
|
|
|
|
|
|
return( $self->{ shift( @_ ) } ); |
6572
|
|
|
|
|
|
|
} |
6573
|
|
|
|
|
|
|
|
6574
|
|
|
|
|
|
|
sub FIRSTKEY |
6575
|
|
|
|
|
|
|
{ |
6576
|
0
|
|
|
0
|
|
|
my $self = shift( @_ ); |
6577
|
|
|
|
|
|
|
## my $a = scalar( keys( %$hash ) ); |
6578
|
|
|
|
|
|
|
## return( each( %$hash ) ); |
6579
|
0
|
|
|
|
|
|
my $data = $self->{ '__priv__' }; |
6580
|
|
|
|
|
|
|
## if( $data->{ 'protect' } ) |
6581
|
0
|
0
|
|
|
|
|
if( !( $data->{ 'perms' } & 4 ) ) |
6582
|
|
|
|
|
|
|
{ |
6583
|
0
|
|
|
|
|
|
my $pkg = ( caller( 0 ) )[ 0 ]; |
6584
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::FIRSTKEY() called by package '$pkg'\n" ); |
6585
|
0
|
0
|
|
|
|
|
return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) ); |
|
0
|
|
|
|
|
|
|
6586
|
|
|
|
|
|
|
} |
6587
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::FIRSTKEY(): gathering object's keys.\n" ); |
6588
|
0
|
|
|
|
|
|
my( @keys ) = grep( !/^__priv__$/, keys( %$self ) ); |
6589
|
0
|
|
|
|
|
|
$self->{ '__priv__' }->{ 'ITERATOR' } = \@keys; |
6590
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::FIRSTKEY(): keys are: '", join( ', ', @keys ), "'.\n" ); |
6591
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::FIRSTKEY() returns '$keys[ 0 ]'.\n" ); |
6592
|
0
|
|
|
|
|
|
return( shift( @keys ) ); |
6593
|
|
|
|
|
|
|
} |
6594
|
|
|
|
|
|
|
|
6595
|
|
|
|
|
|
|
sub NEXTKEY |
6596
|
|
|
|
|
|
|
{ |
6597
|
0
|
|
|
0
|
|
|
my $self = shift( @_ ); |
6598
|
|
|
|
|
|
|
## return( each( %$hash ) ); |
6599
|
0
|
|
|
|
|
|
my $data = $self->{ '__priv__' }; |
6600
|
|
|
|
|
|
|
## if( $data->{ 'protect' } ) |
6601
|
0
|
0
|
|
|
|
|
if( !( $data->{ 'perms' } & 4 ) ) |
6602
|
|
|
|
|
|
|
{ |
6603
|
0
|
|
|
|
|
|
my $pkg = ( caller( 0 ) )[ 0 ]; |
6604
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::NEXTKEY() called by package '$pkg'\n" ); |
6605
|
0
|
0
|
|
|
|
|
return if( !grep( /^$pkg$/, @{$data->{ 'pkg' }} ) ); |
|
0
|
|
|
|
|
|
|
6606
|
|
|
|
|
|
|
} |
6607
|
0
|
|
|
|
|
|
my $keys = $self->{ '__priv__' }->{ 'ITERATOR' }; |
6608
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::NEXTKEY() returns '$_[ 0 ]'.\n" ); |
6609
|
0
|
|
|
|
|
|
return( shift( @$keys ) ); |
6610
|
|
|
|
|
|
|
} |
6611
|
|
|
|
|
|
|
|
6612
|
|
|
|
|
|
|
sub STORE |
6613
|
|
|
|
|
|
|
{ |
6614
|
0
|
|
|
0
|
|
|
my $self = shift( @_ ); |
6615
|
0
|
0
|
|
|
|
|
return() if( $_[ 0 ] eq '__priv__' ); |
6616
|
0
|
|
|
|
|
|
my $data = $self->{ '__priv__' }; |
6617
|
|
|
|
|
|
|
#if( $data->{ 'readonly' } || |
6618
|
|
|
|
|
|
|
# $data->{ 'protect' } ) |
6619
|
0
|
0
|
|
|
|
|
if( !( $data->{ 'perms' } & 2 ) ) |
6620
|
|
|
|
|
|
|
{ |
6621
|
0
|
|
|
|
|
|
my $pkg = ( caller() )[ 0 ]; |
6622
|
0
|
0
|
|
|
|
|
$pkg = ( caller( 1 ) )[ 0 ] if( $pkg eq 'Module::Generic' ); |
6623
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::STORE() package '$pkg' is trying to STORE the value '$_[ 1 ]' to key '$_[ 0 ]'\n" ); |
6624
|
0
|
0
|
|
|
|
|
return if( !grep( /^$pkg$/, @{ $data->{ 'pkg' } } ) ); |
|
0
|
|
|
|
|
|
|
6625
|
|
|
|
|
|
|
} |
6626
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::STORE() ", ( caller() )[ 0 ], " is storing value '$_[ 1 ]' for key '$_[ 0 ]'.\n" ); |
6627
|
|
|
|
|
|
|
## $self->{ shift( @_ ) } = shift( @_ ); |
6628
|
0
|
|
|
|
|
|
$self->{ $_[ 0 ] } = $_[ 1 ]; |
6629
|
|
|
|
|
|
|
## print( STDERR __PACKAGE__ . "::STORE(): object '$self' now contains: '", join( ', ', map{ "$_, $self->{ $_ }" } keys( %$self ) ), "'.\n" ); |
6630
|
|
|
|
|
|
|
} |
6631
|
|
|
|
|
|
|
|
6632
|
|
|
|
|
|
|
1; |
6633
|
|
|
|
|
|
|
|
6634
|
|
|
|
|
|
|
__END__ |
6635
|
|
|
|
|
|
|
|
6636
|
|
|
|
|
|
|
=encoding utf8 |
6637
|
|
|
|
|
|
|
|
6638
|
|
|
|
|
|
|
=head1 NAME |
6639
|
|
|
|
|
|
|
|
6640
|
|
|
|
|
|
|
Module::Generic - Generic Module to inherit from |
6641
|
|
|
|
|
|
|
|
6642
|
|
|
|
|
|
|
=head1 SYNOPSIS |
6643
|
|
|
|
|
|
|
|
6644
|
|
|
|
|
|
|
package MyModule; |
6645
|
|
|
|
|
|
|
BEGIN |
6646
|
|
|
|
|
|
|
{ |
6647
|
|
|
|
|
|
|
use strict; |
6648
|
|
|
|
|
|
|
use Module::Generic; |
6649
|
|
|
|
|
|
|
our( @ISA ) = qw( Module::Generic ); |
6650
|
|
|
|
|
|
|
}; |
6651
|
|
|
|
|
|
|
|
6652
|
|
|
|
|
|
|
=head1 VERSION |
6653
|
|
|
|
|
|
|
|
6654
|
|
|
|
|
|
|
v0.12.16 |
6655
|
|
|
|
|
|
|
|
6656
|
|
|
|
|
|
|
=head1 DESCRIPTION |
6657
|
|
|
|
|
|
|
|
6658
|
|
|
|
|
|
|
L<Module::Generic> as its name says it all, is a generic module to inherit from. |
6659
|
|
|
|
|
|
|
It is designed to provide a useful framework and speed up coding and debugging. |
6660
|
|
|
|
|
|
|
It contains standard and support methods that may be superseded by your the module using |
6661
|
|
|
|
|
|
|
L<Module::Generic>. |
6662
|
|
|
|
|
|
|
|
6663
|
|
|
|
|
|
|
As an added benefit, it also contains a powerfull AUTOLOAD transforming any hash |
6664
|
|
|
|
|
|
|
object key into dynamic methods and also recognize the dynamic routine a la AutoLoader |
6665
|
|
|
|
|
|
|
from which I have shamelessly copied in the AUTOLOAD code. The reason is that while |
6666
|
|
|
|
|
|
|
C<AutoLoader> provides the user with a convenient AUTOLOAD, I wanted a way to also |
6667
|
|
|
|
|
|
|
keep the functionnality of L<Module::Generic> AUTOLOAD that were not included in |
6668
|
|
|
|
|
|
|
C<AutoLoader>. So the only solution was a merger. |
6669
|
|
|
|
|
|
|
|
6670
|
|
|
|
|
|
|
=head1 METHODS |
6671
|
|
|
|
|
|
|
|
6672
|
|
|
|
|
|
|
=head2 import |
6673
|
|
|
|
|
|
|
|
6674
|
|
|
|
|
|
|
B<import>() is used for the AutoLoader mechanism and hence is not a public method. |
6675
|
|
|
|
|
|
|
It is just mentionned here for info only. |
6676
|
|
|
|
|
|
|
|
6677
|
|
|
|
|
|
|
=head2 new |
6678
|
|
|
|
|
|
|
|
6679
|
|
|
|
|
|
|
B<new> will create a new object for the package, pass any argument it might receive |
6680
|
|
|
|
|
|
|
to the special standard routine B<init> that I<must> exist. |
6681
|
|
|
|
|
|
|
Then it returns what returns L</"init">. |
6682
|
|
|
|
|
|
|
|
6683
|
|
|
|
|
|
|
To protect object inner content from sneaking by third party, you can declare the |
6684
|
|
|
|
|
|
|
package global variable I<OBJECT_PERMS> and give it a Unix permission, but only 1 digit. |
6685
|
|
|
|
|
|
|
It will then work just like Unix permission. That is, if permission is 7, then only the |
6686
|
|
|
|
|
|
|
module who generated the object may read/write content of the object. However, if |
6687
|
|
|
|
|
|
|
you set 5, the, other may look into the content of the object, but may not modify it. |
6688
|
|
|
|
|
|
|
7, as you would have guessed, allow other to modify the content of an object. |
6689
|
|
|
|
|
|
|
If I<OBJECT_PERMS> is not defined, permissions system is not activated and hence anyone |
6690
|
|
|
|
|
|
|
may access and possibly modify the content of your object. |
6691
|
|
|
|
|
|
|
|
6692
|
|
|
|
|
|
|
If the module runs under mod_perl, it is recognised and a clean up registered routine is |
6693
|
|
|
|
|
|
|
declared to Apache to clean up the content of the object. |
6694
|
|
|
|
|
|
|
|
6695
|
|
|
|
|
|
|
=head2 as_hash |
6696
|
|
|
|
|
|
|
|
6697
|
|
|
|
|
|
|
This will recursively transform the object into an hash suitable to be encoded in json. |
6698
|
|
|
|
|
|
|
|
6699
|
|
|
|
|
|
|
It does this by calling each method of the object and build an hash reference with the |
6700
|
|
|
|
|
|
|
method name as the key and the method returned value as the value. |
6701
|
|
|
|
|
|
|
|
6702
|
|
|
|
|
|
|
If the method returned value is an object, it will call its L</"as_hash"> method if it supports it. |
6703
|
|
|
|
|
|
|
|
6704
|
|
|
|
|
|
|
It returns the hash reference built |
6705
|
|
|
|
|
|
|
|
6706
|
|
|
|
|
|
|
=head2 clear_error |
6707
|
|
|
|
|
|
|
|
6708
|
|
|
|
|
|
|
Clear all error from the object and from the available global variable C<$ERROR>. |
6709
|
|
|
|
|
|
|
|
6710
|
|
|
|
|
|
|
This is a handy method to use at the beginning of other methods of calling package, |
6711
|
|
|
|
|
|
|
so the end user may do a test such as: |
6712
|
|
|
|
|
|
|
|
6713
|
|
|
|
|
|
|
$obj->some_method( 'some arguments' ); |
6714
|
|
|
|
|
|
|
die( $obj->error() ) if( $obj->error() ); |
6715
|
|
|
|
|
|
|
|
6716
|
|
|
|
|
|
|
## some_method() would then contain something like: |
6717
|
|
|
|
|
|
|
sub some_method |
6718
|
|
|
|
|
|
|
{ |
6719
|
|
|
|
|
|
|
my $self = shift( @_ ); |
6720
|
|
|
|
|
|
|
## Clear all previous error, so we may set our own later one eventually |
6721
|
|
|
|
|
|
|
$self->clear_error(); |
6722
|
|
|
|
|
|
|
## ... |
6723
|
|
|
|
|
|
|
} |
6724
|
|
|
|
|
|
|
|
6725
|
|
|
|
|
|
|
This way the end user may be sure that if C<$obj->error()> returns true something |
6726
|
|
|
|
|
|
|
wrong has occured. |
6727
|
|
|
|
|
|
|
|
6728
|
|
|
|
|
|
|
=head2 clone |
6729
|
|
|
|
|
|
|
|
6730
|
|
|
|
|
|
|
Clone the current object if it is of type hash or array reference. It returns an error if the type is neither. |
6731
|
|
|
|
|
|
|
|
6732
|
|
|
|
|
|
|
It returns the clone. |
6733
|
|
|
|
|
|
|
|
6734
|
|
|
|
|
|
|
=head2 colour_closest |
6735
|
|
|
|
|
|
|
|
6736
|
|
|
|
|
|
|
Provided with a colour, this returns the closest standard one supported by terminal. |
6737
|
|
|
|
|
|
|
|
6738
|
|
|
|
|
|
|
A colour provided can be a colour name, or a 9 digits rgb value or an hexadecimal value |
6739
|
|
|
|
|
|
|
|
6740
|
|
|
|
|
|
|
=head2 colour_format |
6741
|
|
|
|
|
|
|
|
6742
|
|
|
|
|
|
|
Provided with a hash reference of parameters, this will return a string properly formatted to display colours on the command line. |
6743
|
|
|
|
|
|
|
|
6744
|
|
|
|
|
|
|
Parameters are: |
6745
|
|
|
|
|
|
|
|
6746
|
|
|
|
|
|
|
=over 4 |
6747
|
|
|
|
|
|
|
|
6748
|
|
|
|
|
|
|
=item I<text> or I<message> |
6749
|
|
|
|
|
|
|
|
6750
|
|
|
|
|
|
|
This is the text to be formatted in colour. |
6751
|
|
|
|
|
|
|
|
6752
|
|
|
|
|
|
|
=item I<bgcolour> or I<bgcolor> or I<bg_colour> or I<bg_color> |
6753
|
|
|
|
|
|
|
|
6754
|
|
|
|
|
|
|
The value for the background colour. |
6755
|
|
|
|
|
|
|
|
6756
|
|
|
|
|
|
|
=item I<colour> or I<color> or I<fg_colour> or I<fg_color> or I<fgcolour> or I<fgcolor> |
6757
|
|
|
|
|
|
|
|
6758
|
|
|
|
|
|
|
The value for the foreground colour. |
6759
|
|
|
|
|
|
|
|
6760
|
|
|
|
|
|
|
Valid value can be a colour name, an rgb value like C<255255255>, a rgb annotation like C<rgb(255, 255, 255)> or a rgba annotation like C<rgba(255,255,255,0.5)> |
6761
|
|
|
|
|
|
|
|
6762
|
|
|
|
|
|
|
A colour can be preceded by the words C<light> or C<bright> to provide slightly lighter colour where supported. |
6763
|
|
|
|
|
|
|
|
6764
|
|
|
|
|
|
|
Similarly, if an rgba value is provided, and the opacity is less than 1, this is equivalent to using the keyword C<light> |
6765
|
|
|
|
|
|
|
|
6766
|
|
|
|
|
|
|
It returns the text properly formatted to be outputted in a terminal. |
6767
|
|
|
|
|
|
|
|
6768
|
|
|
|
|
|
|
=item I<style> |
6769
|
|
|
|
|
|
|
|
6770
|
|
|
|
|
|
|
The possible values are: I<bold>, I<italic>, I<underline>, I<blink>, I<reverse>, I<conceal>, I<strike> |
6771
|
|
|
|
|
|
|
|
6772
|
|
|
|
|
|
|
=back |
6773
|
|
|
|
|
|
|
|
6774
|
|
|
|
|
|
|
=head2 colour_parse |
6775
|
|
|
|
|
|
|
|
6776
|
|
|
|
|
|
|
Provided with a string, this will parse the string for colour formatting. Formatting can be encapsulated in another formatting, and can be expressed in 2 different ways. For example: |
6777
|
|
|
|
|
|
|
|
6778
|
|
|
|
|
|
|
$self->colour_parse( "And {style => 'i|b', color => green}what about{/} {style => 'blink', color => yellow}me{/} ?" ); |
6779
|
|
|
|
|
|
|
|
6780
|
|
|
|
|
|
|
would result with the words C<what about> in italic, bold and green colour and the word C<me> in yellow colour blinking (if supported). |
6781
|
|
|
|
|
|
|
|
6782
|
|
|
|
|
|
|
Another way is: |
6783
|
|
|
|
|
|
|
|
6784
|
|
|
|
|
|
|
$self->colour_parse( "And {bold light red on white}what about{/} {underline yellow}me too{/} ?" ); |
6785
|
|
|
|
|
|
|
|
6786
|
|
|
|
|
|
|
would return a string with the words C<what about> in light red bold text on a white background, and the words C<me too> in yellow with an underline. |
6787
|
|
|
|
|
|
|
|
6788
|
|
|
|
|
|
|
$self->colour_parse( "Hello {bold red on white}everyone! This is {underline rgb(0,0,255)}embedded{/}{/} text..." ); |
6789
|
|
|
|
|
|
|
|
6790
|
|
|
|
|
|
|
would return a string with the words C<everyone! This is> in bold red characters on white background and the word C<embedded> in underline blue color |
6791
|
|
|
|
|
|
|
|
6792
|
|
|
|
|
|
|
The idea for this syntax, not the code, is taken from L<Term::ANSIColor> |
6793
|
|
|
|
|
|
|
|
6794
|
|
|
|
|
|
|
=head2 coloured |
6795
|
|
|
|
|
|
|
|
6796
|
|
|
|
|
|
|
Provided with a colouring preference expressed as the first argument as string, and followed by 1 or more arguments that are concatenated to form the text string to format. For example: |
6797
|
|
|
|
|
|
|
|
6798
|
|
|
|
|
|
|
print( $o->coloured( 'bold white on red', "Hello it's me!\n" ) ); |
6799
|
|
|
|
|
|
|
|
6800
|
|
|
|
|
|
|
A colour can be expressed as a rgb, such as : |
6801
|
|
|
|
|
|
|
|
6802
|
|
|
|
|
|
|
print( $o->coloured( 'underline rgb( 0, 0, 255 ) on white', "Hello everyone!" ), "\n" ); |
6803
|
|
|
|
|
|
|
|
6804
|
|
|
|
|
|
|
rgb can also be rgba with the last decimal, normally an opacity used here to set light color if the value is less than 1. For example : |
6805
|
|
|
|
|
|
|
|
6806
|
|
|
|
|
|
|
print( $o->coloured( 'underline rgba(255, 0, 0, 0.5)', "Hello everyone!" ), "\n" ); |
6807
|
|
|
|
|
|
|
|
6808
|
|
|
|
|
|
|
=head2 debug |
6809
|
|
|
|
|
|
|
|
6810
|
|
|
|
|
|
|
Set or get the debug level. This takes and return an integer. |
6811
|
|
|
|
|
|
|
|
6812
|
|
|
|
|
|
|
Based on the value, L</"message"> will or will not print out messages. For example : |
6813
|
|
|
|
|
|
|
|
6814
|
|
|
|
|
|
|
$self->debug( 2 ); |
6815
|
|
|
|
|
|
|
$self->message( 2, "Debugging message here." ); |
6816
|
|
|
|
|
|
|
|
6817
|
|
|
|
|
|
|
Since C<2> used in L</"message"> is equal to the debug value, the debugging message is printed. |
6818
|
|
|
|
|
|
|
|
6819
|
|
|
|
|
|
|
If the debug value is switched to 1, the message will be silenced. |
6820
|
|
|
|
|
|
|
|
6821
|
|
|
|
|
|
|
=head2 dump |
6822
|
|
|
|
|
|
|
|
6823
|
|
|
|
|
|
|
Provided with some data, this will return a string representation of the data formatted by L<Data::Printer> |
6824
|
|
|
|
|
|
|
|
6825
|
|
|
|
|
|
|
=head2 dump_print |
6826
|
|
|
|
|
|
|
|
6827
|
|
|
|
|
|
|
Provided with a file to write to and some data, this will format the string representation of the data using L<Data::Printer> and save it to the given file. |
6828
|
|
|
|
|
|
|
|
6829
|
|
|
|
|
|
|
=head2 dumper |
6830
|
|
|
|
|
|
|
|
6831
|
|
|
|
|
|
|
Provided with some data, and optionally an hash reference of parameters as last argument, this will create a string representation of the data using L<Data::Dumper> and return it. |
6832
|
|
|
|
|
|
|
|
6833
|
|
|
|
|
|
|
This sets L<Data::Dumper> to be terse, to indent, to use C<qq> and optionally to not exceed a maximum I<depth> if it is provided in the argument hash reference. |
6834
|
|
|
|
|
|
|
|
6835
|
|
|
|
|
|
|
=head2 printer |
6836
|
|
|
|
|
|
|
|
6837
|
|
|
|
|
|
|
Same as L</"dumper">, but using L<Data::Printer> to format the data. |
6838
|
|
|
|
|
|
|
|
6839
|
|
|
|
|
|
|
=head2 dumpto_printer |
6840
|
|
|
|
|
|
|
|
6841
|
|
|
|
|
|
|
Same as L</"dump_print"> above that is an alias of this method. |
6842
|
|
|
|
|
|
|
|
6843
|
|
|
|
|
|
|
=head2 dumpto_dumper |
6844
|
|
|
|
|
|
|
|
6845
|
|
|
|
|
|
|
Same as L</"dumpto_printer"> above, but using L<Data::Dumper> |
6846
|
|
|
|
|
|
|
|
6847
|
|
|
|
|
|
|
=head2 error |
6848
|
|
|
|
|
|
|
|
6849
|
|
|
|
|
|
|
Set the current error issuing a L<Module::Generic::Exception> object, call L<perlfunc/"warn">, or C<$r->warn> under Apache2 modperl, and returns undef() or an empty list in list context: |
6850
|
|
|
|
|
|
|
|
6851
|
|
|
|
|
|
|
if( $some_condition ) |
6852
|
|
|
|
|
|
|
{ |
6853
|
|
|
|
|
|
|
return( $self->error( "Some error." ) ); |
6854
|
|
|
|
|
|
|
} |
6855
|
|
|
|
|
|
|
|
6856
|
|
|
|
|
|
|
Note that you do not have to worry about a trailing line feed sequence. |
6857
|
|
|
|
|
|
|
B<error>() takes care of it. |
6858
|
|
|
|
|
|
|
|
6859
|
|
|
|
|
|
|
The script calling your module could write calls to your module methods like this: |
6860
|
|
|
|
|
|
|
|
6861
|
|
|
|
|
|
|
my $cust_name = $object->customer->name || |
6862
|
|
|
|
|
|
|
die( "Got an error in file ", $object->error->file, " at line ", $object->error->line, ": ", $object->error->trace, "\n" ); |
6863
|
|
|
|
|
|
|
# or simply: |
6864
|
|
|
|
|
|
|
my $cust_name = $object->customer->name || |
6865
|
|
|
|
|
|
|
die( "Got an error: ", $object->error, "\n" ); |
6866
|
|
|
|
|
|
|
|
6867
|
|
|
|
|
|
|
Note also that by calling B<error>() it will not clear the current error. For that |
6868
|
|
|
|
|
|
|
you have to call B<clear_error>() explicitly. |
6869
|
|
|
|
|
|
|
|
6870
|
|
|
|
|
|
|
Also, when an error is set, the global variable I<ERROR> is set accordingly. This is |
6871
|
|
|
|
|
|
|
especially usefull, when your initiating an object and that an error occured. At that |
6872
|
|
|
|
|
|
|
time, since the object could not be initiated, the end user can not use the object to |
6873
|
|
|
|
|
|
|
get the error message, and then can get it using the global module variable |
6874
|
|
|
|
|
|
|
I<ERROR>, for example: |
6875
|
|
|
|
|
|
|
|
6876
|
|
|
|
|
|
|
my $obj = Some::Package->new || |
6877
|
|
|
|
|
|
|
die( $Some::Package::ERROR, "\n" ); |
6878
|
|
|
|
|
|
|
|
6879
|
|
|
|
|
|
|
If the caller has disabled warnings using the pragma C<no warnings>, L</"error"> will |
6880
|
|
|
|
|
|
|
respect it and not call B<warn>. Calling B<warn> can also be silenced if the object has |
6881
|
|
|
|
|
|
|
a property I<quiet> set to true. |
6882
|
|
|
|
|
|
|
|
6883
|
|
|
|
|
|
|
The error message can be split in multiple argument. L</"error"> will concatenate each argument to form a complete string. An argument can even be a reference to a sub routine and will get called to get the resulting string, unless the object property I<_msg_no_exec_sub> is set to false. This can switched off with the method L</"noexec"> |
6884
|
|
|
|
|
|
|
|
6885
|
|
|
|
|
|
|
If perl runs under Apache2 modperl, and an error handler is set with L</"error_handler">, this will call the error handler with the error string. |
6886
|
|
|
|
|
|
|
|
6887
|
|
|
|
|
|
|
If an Apache2 modperl log handler has been set, this will also be called to log the error. |
6888
|
|
|
|
|
|
|
|
6889
|
|
|
|
|
|
|
If the object property I<fatal> is set to true, this will call die instead of L<perlfunc/"warn">. |
6890
|
|
|
|
|
|
|
|
6891
|
|
|
|
|
|
|
Last, but not least since L</"error"> returns undef in scalar context or an empty list in list context, if the method that triggered the error is chained, it would normally generate a perl error that the following method cannot be called on an undefined value. To solve this, when an object is expected, L</"error"> returns a special object from module L<Module::Generic::Null> that will enable all the chained methods to be performed and return the error when requested to. For example : |
6892
|
|
|
|
|
|
|
|
6893
|
|
|
|
|
|
|
my $o = My::Package->new; |
6894
|
|
|
|
|
|
|
my $total $o->get_customer(10)->products->total || die( $o->error, "\n" ); |
6895
|
|
|
|
|
|
|
|
6896
|
|
|
|
|
|
|
Assuming this method here C<get_customer> returns an error, the chaining will continue, but produce nothing and ultimately returns undef. |
6897
|
|
|
|
|
|
|
|
6898
|
|
|
|
|
|
|
=head2 errors |
6899
|
|
|
|
|
|
|
|
6900
|
|
|
|
|
|
|
Used by B<error>() to store the error sent to him for history. |
6901
|
|
|
|
|
|
|
|
6902
|
|
|
|
|
|
|
It returns an array of all error that have occured in lsit context, and the last |
6903
|
|
|
|
|
|
|
error in scalar context. |
6904
|
|
|
|
|
|
|
|
6905
|
|
|
|
|
|
|
=head2 errstr |
6906
|
|
|
|
|
|
|
|
6907
|
|
|
|
|
|
|
Set/get the error string, period. It does not produce any warning like B<error> would do. |
6908
|
|
|
|
|
|
|
|
6909
|
|
|
|
|
|
|
=head2 get |
6910
|
|
|
|
|
|
|
|
6911
|
|
|
|
|
|
|
Uset to get an object data key value: |
6912
|
|
|
|
|
|
|
|
6913
|
|
|
|
|
|
|
$obj->set( 'verbose' => 1, 'debug' => 0 ); |
6914
|
|
|
|
|
|
|
## ... |
6915
|
|
|
|
|
|
|
my $verbose = $obj->get( 'verbose' ); |
6916
|
|
|
|
|
|
|
my @vals = $obj->get( qw( verbose debug ) ); |
6917
|
|
|
|
|
|
|
print( $out "Verbose level is $vals[ 0 ] and debug level is $vals[ 1 ]\n" ); |
6918
|
|
|
|
|
|
|
|
6919
|
|
|
|
|
|
|
This is no more needed, as it has been more conveniently bypassed by the AUTOLOAD |
6920
|
|
|
|
|
|
|
generic routine with chich you may say: |
6921
|
|
|
|
|
|
|
|
6922
|
|
|
|
|
|
|
$obj->verbose( 1 ); |
6923
|
|
|
|
|
|
|
$obj->debug( 0 ); |
6924
|
|
|
|
|
|
|
## ... |
6925
|
|
|
|
|
|
|
my $verbose = $obj->verbose(); |
6926
|
|
|
|
|
|
|
|
6927
|
|
|
|
|
|
|
Much better, no? |
6928
|
|
|
|
|
|
|
|
6929
|
|
|
|
|
|
|
=head2 init |
6930
|
|
|
|
|
|
|
|
6931
|
|
|
|
|
|
|
This is the L</"new"> package object initializer. It is called by L</"new"> |
6932
|
|
|
|
|
|
|
and is used to set up any parameter provided in a hash like fashion: |
6933
|
|
|
|
|
|
|
|
6934
|
|
|
|
|
|
|
my $obj My::Module->new( 'verbose' => 1, 'debug' => 0 ); |
6935
|
|
|
|
|
|
|
|
6936
|
|
|
|
|
|
|
You may want to superseed L</"init"> to have suit your needs. |
6937
|
|
|
|
|
|
|
|
6938
|
|
|
|
|
|
|
L</"init"> needs to returns the object it received in the first place or an error if |
6939
|
|
|
|
|
|
|
something went wrong, such as: |
6940
|
|
|
|
|
|
|
|
6941
|
|
|
|
|
|
|
sub init |
6942
|
|
|
|
|
|
|
{ |
6943
|
|
|
|
|
|
|
my $self = shift( @_ ); |
6944
|
|
|
|
|
|
|
my $dbh = DB::Object->connect() || |
6945
|
|
|
|
|
|
|
return( $self->error( "Unable to connect to database server." ) ); |
6946
|
|
|
|
|
|
|
$self->{ 'dbh' } = $dbh; |
6947
|
|
|
|
|
|
|
return( $self ); |
6948
|
|
|
|
|
|
|
} |
6949
|
|
|
|
|
|
|
|
6950
|
|
|
|
|
|
|
In this example, using L</"error"> will set the global variable C<$ERROR> that will |
6951
|
|
|
|
|
|
|
contain the error, so user can say: |
6952
|
|
|
|
|
|
|
|
6953
|
|
|
|
|
|
|
my $obj = My::Module->new() || die( $My::Module::ERROR ); |
6954
|
|
|
|
|
|
|
|
6955
|
|
|
|
|
|
|
If the global variable I<VERBOSE>, I<DEBUG>, I<VERSION> are defined in the module, |
6956
|
|
|
|
|
|
|
and that they do not exist as an object key, they will be set automatically and |
6957
|
|
|
|
|
|
|
accordingly to those global variable. |
6958
|
|
|
|
|
|
|
|
6959
|
|
|
|
|
|
|
The supported data type of the object generated by the L</"new"> method may either be |
6960
|
|
|
|
|
|
|
a hash reference or a glob reference. Those supported data types may very well be |
6961
|
|
|
|
|
|
|
extended to an array reference in a near future. |
6962
|
|
|
|
|
|
|
|
6963
|
|
|
|
|
|
|
When provided with an hash reference, and when object property I<_init_strict_use_sub> is set to true, L</"init"> will call each method corresponding to the key name and pass it the key value and it will set an error and skip it if the corresponding method does not exist. Otherwise if the object property I<_init_strict> is set to true, it will check the object property matching the hash key for the default value type and set an error and return undef if it does not match. Foe example, L</"init"> in your module could be like this: |
6964
|
|
|
|
|
|
|
|
6965
|
|
|
|
|
|
|
sub init |
6966
|
|
|
|
|
|
|
{ |
6967
|
|
|
|
|
|
|
my $self = shift( @_ ); |
6968
|
|
|
|
|
|
|
$self->{_init_strict} = 1; |
6969
|
|
|
|
|
|
|
$self->{products} = []; |
6970
|
|
|
|
|
|
|
return( $self->SUPER::init( @_ ) ); |
6971
|
|
|
|
|
|
|
} |
6972
|
|
|
|
|
|
|
|
6973
|
|
|
|
|
|
|
Then, if init is called like this: |
6974
|
|
|
|
|
|
|
|
6975
|
|
|
|
|
|
|
$object->init({ products => $some_string_but_not_array }) || die( $object->error, "\n" ); |
6976
|
|
|
|
|
|
|
|
6977
|
|
|
|
|
|
|
This would cause your script to die, because C<products> value is a string and not an array reference. |
6978
|
|
|
|
|
|
|
|
6979
|
|
|
|
|
|
|
Otherwise, if none of those special object properties are set, the init will create an object property matching the key of the hash and set its value accordingly. For example : |
6980
|
|
|
|
|
|
|
|
6981
|
|
|
|
|
|
|
sub init |
6982
|
|
|
|
|
|
|
{ |
6983
|
|
|
|
|
|
|
my $self = shift( @_ ); |
6984
|
|
|
|
|
|
|
return( $self->SUPER::init( @_ ) ); |
6985
|
|
|
|
|
|
|
} |
6986
|
|
|
|
|
|
|
|
6987
|
|
|
|
|
|
|
Then, if init is called like this: |
6988
|
|
|
|
|
|
|
|
6989
|
|
|
|
|
|
|
$object->init( products => $array_ref, first_name => 'John', last_name => 'Doe' }); |
6990
|
|
|
|
|
|
|
|
6991
|
|
|
|
|
|
|
The object would then contain the properties I<products>, I<first_name> and I<last_name> and can be accessed as methods, such as : |
6992
|
|
|
|
|
|
|
|
6993
|
|
|
|
|
|
|
my $fname = $object->first_name; |
6994
|
|
|
|
|
|
|
|
6995
|
|
|
|
|
|
|
=head2 log_handler |
6996
|
|
|
|
|
|
|
|
6997
|
|
|
|
|
|
|
Provided a reference to a sub routine or an anonymous sub routine, this will set the handler that is called by L</"message"> |
6998
|
|
|
|
|
|
|
|
6999
|
|
|
|
|
|
|
It returns the current value set. |
7000
|
|
|
|
|
|
|
|
7001
|
|
|
|
|
|
|
=head2 message |
7002
|
|
|
|
|
|
|
|
7003
|
|
|
|
|
|
|
B<message>() is used to display verbose/debug output. It will display something |
7004
|
|
|
|
|
|
|
to the extend that either I<verbose> or I<debug> are toggled on. |
7005
|
|
|
|
|
|
|
|
7006
|
|
|
|
|
|
|
If so, all debugging message will be prepended by C<## > to highlight the fact |
7007
|
|
|
|
|
|
|
that this is a debugging message. |
7008
|
|
|
|
|
|
|
|
7009
|
|
|
|
|
|
|
Addionally, if a number is provided as first argument to B<message>(), it will be |
7010
|
|
|
|
|
|
|
treated as the minimum required level of debugness. So, if the current debug |
7011
|
|
|
|
|
|
|
state level is not equal or superior to the one provided as first argument, the |
7012
|
|
|
|
|
|
|
message will not be displayed. |
7013
|
|
|
|
|
|
|
|
7014
|
|
|
|
|
|
|
For example: |
7015
|
|
|
|
|
|
|
|
7016
|
|
|
|
|
|
|
## Set debugness to 3 |
7017
|
|
|
|
|
|
|
$obj->debug( 3 ); |
7018
|
|
|
|
|
|
|
## This message will not be printed |
7019
|
|
|
|
|
|
|
$obj->message( 4, "Some detailed debugging stuff that we might not want." ); |
7020
|
|
|
|
|
|
|
## This will be displayed |
7021
|
|
|
|
|
|
|
$obj->message( 2, "Some more common message we want the user to see." ); |
7022
|
|
|
|
|
|
|
|
7023
|
|
|
|
|
|
|
Now, why debug is used and not verbose level? Well, because mostly, the verbose level |
7024
|
|
|
|
|
|
|
needs only to be true, that is equal to 1 to be efficient. You do not really need to have |
7025
|
|
|
|
|
|
|
a verbose level greater than 1. However, the debug level usually may have various level. |
7026
|
|
|
|
|
|
|
|
7027
|
|
|
|
|
|
|
Also, the text provided can be separated by comma, and even be a code reference, such as: |
7028
|
|
|
|
|
|
|
|
7029
|
|
|
|
|
|
|
$self->message( 2, "I have found", "something weird here:", sub{ $self->dumper( $data ) } ); |
7030
|
|
|
|
|
|
|
|
7031
|
|
|
|
|
|
|
If the object has a property I<_msg_no_exec_sub> set to true, then a code reference will not be called and instead be added to the string as is. This can be done simply like this: |
7032
|
|
|
|
|
|
|
|
7033
|
|
|
|
|
|
|
$self->noexec->message( 2, "I have found", "something weird here:", sub{ $self->dumper( $data ) } ); |
7034
|
|
|
|
|
|
|
|
7035
|
|
|
|
|
|
|
=head2 message_colour |
7036
|
|
|
|
|
|
|
|
7037
|
|
|
|
|
|
|
This is the same as L</"message">, except this will check for colour formatting, which |
7038
|
|
|
|
|
|
|
L</"message"> does not do. For example: |
7039
|
|
|
|
|
|
|
|
7040
|
|
|
|
|
|
|
$self->message_colour( 3, "And {bold light white on red}what about{/} {underline green}me again{/} ?" ); |
7041
|
|
|
|
|
|
|
|
7042
|
|
|
|
|
|
|
L</"message_colour"> can also be called as B<message_color> |
7043
|
|
|
|
|
|
|
|
7044
|
|
|
|
|
|
|
See also L</"colour_format"> and L</"colour_parse"> |
7045
|
|
|
|
|
|
|
|
7046
|
|
|
|
|
|
|
=head2 messagef |
7047
|
|
|
|
|
|
|
|
7048
|
|
|
|
|
|
|
This works like L<perlfunc/"sprintf">, so provided with a format and a list of arguments, this print out the message. For example : |
7049
|
|
|
|
|
|
|
|
7050
|
|
|
|
|
|
|
$self->messagef( 1, "Customer name is %s", $cust->name ); |
7051
|
|
|
|
|
|
|
|
7052
|
|
|
|
|
|
|
Where 1 is the debug level set with L</"debug"> |
7053
|
|
|
|
|
|
|
|
7054
|
|
|
|
|
|
|
=head2 message_check |
7055
|
|
|
|
|
|
|
|
7056
|
|
|
|
|
|
|
This is called by L</"message"> |
7057
|
|
|
|
|
|
|
|
7058
|
|
|
|
|
|
|
Provided with a list of arguments, this method will check if the first argument is an integer and find out if a debug message should be printed out or not. It returns the list of arguments as an array reference. |
7059
|
|
|
|
|
|
|
|
7060
|
|
|
|
|
|
|
=head2 message_log |
7061
|
|
|
|
|
|
|
|
7062
|
|
|
|
|
|
|
This is called from L</"message">. |
7063
|
|
|
|
|
|
|
|
7064
|
|
|
|
|
|
|
Provided with a message to log, this will check if L</"message_log_io"> returns a valid file handler, presumably to log file, and if so print the message to it. |
7065
|
|
|
|
|
|
|
|
7066
|
|
|
|
|
|
|
If no file handle is set, this returns undef, other it returns the value from C<$io->print> |
7067
|
|
|
|
|
|
|
|
7068
|
|
|
|
|
|
|
=head2 message_log_io |
7069
|
|
|
|
|
|
|
|
7070
|
|
|
|
|
|
|
Set or get the message log file handle. If set, L</"message_log"> will use it to print messages received from L</"message"> |
7071
|
|
|
|
|
|
|
|
7072
|
|
|
|
|
|
|
If no argument is provided bu your module has a global variable C<LOG_DEBUG> set to true and global variable C<DEB_LOG> set presumably to the file path of a log file, then this attempts to open in write mode the log file. |
7073
|
|
|
|
|
|
|
|
7074
|
|
|
|
|
|
|
It returns the current log file handle, if any. |
7075
|
|
|
|
|
|
|
|
7076
|
|
|
|
|
|
|
=head2 message_switch |
7077
|
|
|
|
|
|
|
|
7078
|
|
|
|
|
|
|
Provided with a boolean value, this toggles on or off all the calls to L</"message"> by replacing the message method in your package with a dummy one that will ignore any call. Actually it aliases L</"message"> to L</"message_off"> |
7079
|
|
|
|
|
|
|
|
7080
|
|
|
|
|
|
|
In reality this is not really needed, because L</"message"> will, at the beginning check if the object has the debug flag on and if not returns undef. |
7081
|
|
|
|
|
|
|
|
7082
|
|
|
|
|
|
|
=head2 new_array |
7083
|
|
|
|
|
|
|
|
7084
|
|
|
|
|
|
|
Instantiate a new L<Module::Generic::Array> object. If any arguments are provided, it will pass it to L<Module::Generic::Array/new> and return the object. |
7085
|
|
|
|
|
|
|
|
7086
|
|
|
|
|
|
|
=head2 new_hash |
7087
|
|
|
|
|
|
|
|
7088
|
|
|
|
|
|
|
Instantiate a new L<Module::Generic::Hash> object. If any arguments are provided, it will pass it to L<Module::Generic::Hash/new> and return the object. |
7089
|
|
|
|
|
|
|
|
7090
|
|
|
|
|
|
|
=head2 new_number |
7091
|
|
|
|
|
|
|
|
7092
|
|
|
|
|
|
|
Instantiate a new L<Module::Generic::Number> object. If any arguments are provided, it will pass it to L<Module::Generic::Number/new> and return the object. |
7093
|
|
|
|
|
|
|
|
7094
|
|
|
|
|
|
|
=head2 new_scalar |
7095
|
|
|
|
|
|
|
|
7096
|
|
|
|
|
|
|
Instantiate a new L<Module::Generic::Scalar> object. If any arguments are provided, it will pass it to L<Module::Generic::Scalar/new> and return the object. |
7097
|
|
|
|
|
|
|
|
7098
|
|
|
|
|
|
|
=head2 noexec |
7099
|
|
|
|
|
|
|
|
7100
|
|
|
|
|
|
|
Sets the module property I<_msg_no_exec_sub> to true, so that any call to L</"message"> whose arguments include a reference to a sub routine, will not try to execute the code. For example, imagine you have a sub routine such as: |
7101
|
|
|
|
|
|
|
|
7102
|
|
|
|
|
|
|
sub hello |
7103
|
|
|
|
|
|
|
{ |
7104
|
|
|
|
|
|
|
return( "Hello !" ); |
7105
|
|
|
|
|
|
|
} |
7106
|
|
|
|
|
|
|
|
7107
|
|
|
|
|
|
|
And in your code, you write: |
7108
|
|
|
|
|
|
|
|
7109
|
|
|
|
|
|
|
$self->message( 2, "Someone said: ", \&hello ); |
7110
|
|
|
|
|
|
|
|
7111
|
|
|
|
|
|
|
If I<_msg_no_exec_sub> is set to false (by default), then the above would print out the following message: |
7112
|
|
|
|
|
|
|
|
7113
|
|
|
|
|
|
|
Someone said Hello ! |
7114
|
|
|
|
|
|
|
|
7115
|
|
|
|
|
|
|
But if I<_msg_no_exec_sub> is set to true, then the same would rather produce the following : |
7116
|
|
|
|
|
|
|
|
7117
|
|
|
|
|
|
|
Someone said CODE(0x7f9103801700) |
7118
|
|
|
|
|
|
|
|
7119
|
|
|
|
|
|
|
=head2 pass_error |
7120
|
|
|
|
|
|
|
|
7121
|
|
|
|
|
|
|
Provided with an error, typically a L<Module::Generic::Exception> object, but it could be anything as long as it is an object, hopefully an exception object, this will set the error value to the error provided, and without issuing any new warning nor creating a new L<Module::Generic::Exception> object. |
7122
|
|
|
|
|
|
|
|
7123
|
|
|
|
|
|
|
It makes it possible to pass the error along so the caller can retrieve it later. This is typically used by a method calling another one in another module that produced an error. For example : |
7124
|
|
|
|
|
|
|
|
7125
|
|
|
|
|
|
|
sub getCustomerInfo |
7126
|
|
|
|
|
|
|
{ |
7127
|
|
|
|
|
|
|
my $self = shift( @_ ); |
7128
|
|
|
|
|
|
|
# Maybe a LWP::UserAgent sub class? |
7129
|
|
|
|
|
|
|
my $client = $self->lwp_client_object; |
7130
|
|
|
|
|
|
|
my $res = $client->get( $remote_api_endpoint ) || |
7131
|
|
|
|
|
|
|
return( $self->pass_error( $client->error ) ); |
7132
|
|
|
|
|
|
|
} |
7133
|
|
|
|
|
|
|
|
7134
|
|
|
|
|
|
|
Then : |
7135
|
|
|
|
|
|
|
|
7136
|
|
|
|
|
|
|
my $client_info = $object->getCustomerInfo || die( $object->error, "\n" ); |
7137
|
|
|
|
|
|
|
|
7138
|
|
|
|
|
|
|
Which would return the http client error that has been passed along |
7139
|
|
|
|
|
|
|
|
7140
|
|
|
|
|
|
|
=head2 quiet |
7141
|
|
|
|
|
|
|
|
7142
|
|
|
|
|
|
|
Set or get the object property I<quiet> to true or false. If this is true, no warning will be issued when L</"error"> is called. |
7143
|
|
|
|
|
|
|
|
7144
|
|
|
|
|
|
|
=head2 save |
7145
|
|
|
|
|
|
|
|
7146
|
|
|
|
|
|
|
Provided with some data and a file path, or alternatively an hash reference of options with the properties I<data>, I<encoding> and I<file>, this will write to the given file the provided I<data> using the encoding I<encoding>. |
7147
|
|
|
|
|
|
|
|
7148
|
|
|
|
|
|
|
This is designed to simplify the tedious task of write to files. |
7149
|
|
|
|
|
|
|
|
7150
|
|
|
|
|
|
|
If it cannot open the file in write mode, or cannot print to it, this will set an error and return undef. Otherwise this returns the size of the file in bytes. |
7151
|
|
|
|
|
|
|
|
7152
|
|
|
|
|
|
|
=head2 set |
7153
|
|
|
|
|
|
|
|
7154
|
|
|
|
|
|
|
B<set>() sets object inner data type and takes arguments in a hash like fashion: |
7155
|
|
|
|
|
|
|
|
7156
|
|
|
|
|
|
|
$obj->set( 'verbose' => 1, 'debug' => 0 ); |
7157
|
|
|
|
|
|
|
|
7158
|
|
|
|
|
|
|
=head2 subclasses |
7159
|
|
|
|
|
|
|
|
7160
|
|
|
|
|
|
|
Provided with a I<CLASS> value, this method try to guess all the existing sub classes of the provided I<CLASS>. |
7161
|
|
|
|
|
|
|
|
7162
|
|
|
|
|
|
|
If I<CLASS> is not provided, the class into which was blessed the calling object will |
7163
|
|
|
|
|
|
|
be used instead. |
7164
|
|
|
|
|
|
|
|
7165
|
|
|
|
|
|
|
It returns an array of subclasses in list context and a reference to an array of those |
7166
|
|
|
|
|
|
|
subclasses in scalar context. |
7167
|
|
|
|
|
|
|
|
7168
|
|
|
|
|
|
|
If an error occured, undef is returned and an error is set accordingly. The latter can |
7169
|
|
|
|
|
|
|
be retrieved using the B<error> method. |
7170
|
|
|
|
|
|
|
|
7171
|
|
|
|
|
|
|
=head2 true |
7172
|
|
|
|
|
|
|
|
7173
|
|
|
|
|
|
|
Returns a C<true> variable from L<Module::Generic::Boolean> |
7174
|
|
|
|
|
|
|
|
7175
|
|
|
|
|
|
|
=head2 false |
7176
|
|
|
|
|
|
|
|
7177
|
|
|
|
|
|
|
Returns a C<false> variable from L<Module::Generic::Boolean> |
7178
|
|
|
|
|
|
|
|
7179
|
|
|
|
|
|
|
=head2 verbose |
7180
|
|
|
|
|
|
|
|
7181
|
|
|
|
|
|
|
Set or get the verbosity level with an integer. |
7182
|
|
|
|
|
|
|
|
7183
|
|
|
|
|
|
|
=head2 will |
7184
|
|
|
|
|
|
|
|
7185
|
|
|
|
|
|
|
This will try to find out if an object supports a given method call and returns the code reference to it or undef if none is found. |
7186
|
|
|
|
|
|
|
|
7187
|
|
|
|
|
|
|
=head2 AUTOLOAD |
7188
|
|
|
|
|
|
|
|
7189
|
|
|
|
|
|
|
The special B<AUTOLOAD>() routine is called by perl when no matching routine was found |
7190
|
|
|
|
|
|
|
in the module. |
7191
|
|
|
|
|
|
|
|
7192
|
|
|
|
|
|
|
B<AUTOLOAD>() will then try hard to process the request. |
7193
|
|
|
|
|
|
|
For example, let's assue we have a routine B<foo>. |
7194
|
|
|
|
|
|
|
|
7195
|
|
|
|
|
|
|
It will first, check if an equivalent entry of the routine name that was called exist in |
7196
|
|
|
|
|
|
|
the hash reference of the object. If there is and that more than one argument were |
7197
|
|
|
|
|
|
|
passed to this non existing routine, those arguments will be stored as a reference to an |
7198
|
|
|
|
|
|
|
array as a value of the key in the object. Otherwise the single argument will simply be stored |
7199
|
|
|
|
|
|
|
as the value of the key of the object. |
7200
|
|
|
|
|
|
|
|
7201
|
|
|
|
|
|
|
Then, if called in list context, it will return a array if the value of the key entry was an array |
7202
|
|
|
|
|
|
|
reference, or a hash list if the value of the key entry was a hash reference, or finally the value |
7203
|
|
|
|
|
|
|
of the key entry. |
7204
|
|
|
|
|
|
|
|
7205
|
|
|
|
|
|
|
If this non existing routine that was called is actually defined, the routine will be redeclared and |
7206
|
|
|
|
|
|
|
the arguments passed to it. |
7207
|
|
|
|
|
|
|
|
7208
|
|
|
|
|
|
|
If this fails too, it will try to check for an AutoLoadable file in C<auto/PackageName/routine_name.al> |
7209
|
|
|
|
|
|
|
|
7210
|
|
|
|
|
|
|
If the filed exists, it will be required, the routine name linked into the package name space and finally |
7211
|
|
|
|
|
|
|
called with the arguments. |
7212
|
|
|
|
|
|
|
|
7213
|
|
|
|
|
|
|
If the require process failed or if the AutoLoadable routine file did not exist, B<AUTOLOAD>() will |
7214
|
|
|
|
|
|
|
check if the special routine B<EXTRA_AUTOLOAD>() exists in the module. If it does, it will call it and pass |
7215
|
|
|
|
|
|
|
it the arguments. Otherwise, B<AUTOLOAD> will die with a message explaining that the called routine did |
7216
|
|
|
|
|
|
|
not exist and could not be found in the current class. |
7217
|
|
|
|
|
|
|
|
7218
|
|
|
|
|
|
|
=head1 SPECIAL METHODS |
7219
|
|
|
|
|
|
|
|
7220
|
|
|
|
|
|
|
=head2 __instantiate_object |
7221
|
|
|
|
|
|
|
|
7222
|
|
|
|
|
|
|
Provided with an object property name, and a class/package name, this will attempt to load the module if it is not already loaded. It does so using L<Class::Load/"load_class">. Once loaded, it will init an object passing it the other arguments received. It returns the object instantiated upon success or undef and sets an L</"error"> |
7223
|
|
|
|
|
|
|
|
7224
|
|
|
|
|
|
|
This is a support method used by L</"_instantiate_object"> |
7225
|
|
|
|
|
|
|
|
7226
|
|
|
|
|
|
|
=head2 _instantiate_object |
7227
|
|
|
|
|
|
|
|
7228
|
|
|
|
|
|
|
This does the same thing as L</"__instantiate_object"> and the purpose is for this method to be potentially superseded in your own module. In your own module, you would call L</"__instantiate_object"> |
7229
|
|
|
|
|
|
|
|
7230
|
|
|
|
|
|
|
=head2 _is_a |
7231
|
|
|
|
|
|
|
|
7232
|
|
|
|
|
|
|
Provided with an object and a package name and this will return true if the object is a blessed object from this package name (or a sub package of it), or false if not. |
7233
|
|
|
|
|
|
|
|
7234
|
|
|
|
|
|
|
The value of this is to reduce the burden of having to check whether the object actually exists, i.e. is not null or undef, if it is an object and if it is from that class. This allows to do it in just one method call like this: |
7235
|
|
|
|
|
|
|
|
7236
|
|
|
|
|
|
|
if( $self->_is_a( $obj, 'My::Package' ) ) |
7237
|
|
|
|
|
|
|
{ |
7238
|
|
|
|
|
|
|
# Do something |
7239
|
|
|
|
|
|
|
} |
7240
|
|
|
|
|
|
|
|
7241
|
|
|
|
|
|
|
Of course, if you are sure the object is actually an object, then you can directly do: |
7242
|
|
|
|
|
|
|
|
7243
|
|
|
|
|
|
|
if( $obj->isa( 'My::Package' ) ) |
7244
|
|
|
|
|
|
|
{ |
7245
|
|
|
|
|
|
|
# Do something |
7246
|
|
|
|
|
|
|
} |
7247
|
|
|
|
|
|
|
|
7248
|
|
|
|
|
|
|
=head2 _is_class_loaded |
7249
|
|
|
|
|
|
|
|
7250
|
|
|
|
|
|
|
Provided with a class/package name, this returns true if the module is already loaded or false otherwise. |
7251
|
|
|
|
|
|
|
|
7252
|
|
|
|
|
|
|
=head2 _is_array |
7253
|
|
|
|
|
|
|
|
7254
|
|
|
|
|
|
|
Provided with some data, this checks if the data is of type array, even if it is an object. |
7255
|
|
|
|
|
|
|
|
7256
|
|
|
|
|
|
|
This uses L<Scalar::Util/"reftype"> to achieve that purpose. So for example, an object such as : |
7257
|
|
|
|
|
|
|
|
7258
|
|
|
|
|
|
|
package My::Module; |
7259
|
|
|
|
|
|
|
|
7260
|
|
|
|
|
|
|
sub new |
7261
|
|
|
|
|
|
|
{ |
7262
|
|
|
|
|
|
|
return( bless( [] => ( ref( $_[0] ) || $_[0] ) ) ); |
7263
|
|
|
|
|
|
|
} |
7264
|
|
|
|
|
|
|
|
7265
|
|
|
|
|
|
|
This would produce an object like : |
7266
|
|
|
|
|
|
|
|
7267
|
|
|
|
|
|
|
My::Module=ARRAY(0x7f8f3b035c20) |
7268
|
|
|
|
|
|
|
|
7269
|
|
|
|
|
|
|
When checked with L</"_is_array"> this, would return true just like an ordinary array. |
7270
|
|
|
|
|
|
|
|
7271
|
|
|
|
|
|
|
If you would use : |
7272
|
|
|
|
|
|
|
|
7273
|
|
|
|
|
|
|
ref( $object ); |
7274
|
|
|
|
|
|
|
|
7275
|
|
|
|
|
|
|
It would rather return the module package name: C<My::Module> |
7276
|
|
|
|
|
|
|
|
7277
|
|
|
|
|
|
|
=head2 _is_hash |
7278
|
|
|
|
|
|
|
|
7279
|
|
|
|
|
|
|
Same as L</"_is_array">, but for hash reference. |
7280
|
|
|
|
|
|
|
|
7281
|
|
|
|
|
|
|
=head2 _is_object |
7282
|
|
|
|
|
|
|
|
7283
|
|
|
|
|
|
|
Provided with some data, this checks if the data is an object. It uses L<Scalar::Util/"blessed"> to achieve that purpose. |
7284
|
|
|
|
|
|
|
|
7285
|
|
|
|
|
|
|
=head2 _is_scalar |
7286
|
|
|
|
|
|
|
|
7287
|
|
|
|
|
|
|
Provided with some data, this checks if the data is of type scalar reference, e.g. C<SCALAR(0x7fc0d3b7cea0)>, even if it is an object. |
7288
|
|
|
|
|
|
|
|
7289
|
|
|
|
|
|
|
=head2 _load_class |
7290
|
|
|
|
|
|
|
|
7291
|
|
|
|
|
|
|
Provided with a class/package name and this will attempt to load the module. This uses L<Class::Load/"load_class"> to achieve that purpose and return whatever value L<Class::Load/"load_class"> returns. |
7292
|
|
|
|
|
|
|
|
7293
|
|
|
|
|
|
|
=head2 _obj2h |
7294
|
|
|
|
|
|
|
|
7295
|
|
|
|
|
|
|
This ensures the module object is an hash reference, such as when the module object is based on a file handle for example. This permits L<Module::Generic> to work no matter what is the underlying data type blessed into an object. |
7296
|
|
|
|
|
|
|
|
7297
|
|
|
|
|
|
|
=head2 _parse_timestamp |
7298
|
|
|
|
|
|
|
|
7299
|
|
|
|
|
|
|
Provided with a string representing a date or datetime, and this will try to parse it and return a L<DateTime> object. It will also create a L<DateTime::Format::Strptime> to preserve the original date/datetime string representation and assign it to the L<DateTime> object. So when the L<DateTime> object is stringified, it displays the same string that was originally parsed. |
7300
|
|
|
|
|
|
|
|
7301
|
|
|
|
|
|
|
=head2 _set_get |
7302
|
|
|
|
|
|
|
|
7303
|
|
|
|
|
|
|
Provided with an object property name and some value and this will set or get that value for that property. |
7304
|
|
|
|
|
|
|
|
7305
|
|
|
|
|
|
|
However, if the value stored is an array and is called in list context, it will return the array as a list and not the array reference. Same thing for an hash reference. It will return an hash in list context. In scalar context, it returns whatever the value is, such as array reference, hash reference or string, etc. |
7306
|
|
|
|
|
|
|
|
7307
|
|
|
|
|
|
|
=head2 _set_get_array |
7308
|
|
|
|
|
|
|
|
7309
|
|
|
|
|
|
|
Provided with an object property name and some data and this will store the data as an array reference. |
7310
|
|
|
|
|
|
|
|
7311
|
|
|
|
|
|
|
It returns the current value stored, such as an array reference notwithstanding it is called in list or scalar context. |
7312
|
|
|
|
|
|
|
|
7313
|
|
|
|
|
|
|
Example : |
7314
|
|
|
|
|
|
|
|
7315
|
|
|
|
|
|
|
sub products { return( shift->_set_get_array( 'products', @_ ) ); } |
7316
|
|
|
|
|
|
|
|
7317
|
|
|
|
|
|
|
=head2 _set_get_array_as_object |
7318
|
|
|
|
|
|
|
|
7319
|
|
|
|
|
|
|
Provided with an object property name and some data and this will store the data as an object of L<Module::Generic::Array> |
7320
|
|
|
|
|
|
|
|
7321
|
|
|
|
|
|
|
If this is called with no data set, an object is created with no data inside and returned |
7322
|
|
|
|
|
|
|
|
7323
|
|
|
|
|
|
|
Example : |
7324
|
|
|
|
|
|
|
|
7325
|
|
|
|
|
|
|
# In your module |
7326
|
|
|
|
|
|
|
sub products { return( shift->_set_get_array_as_object( 'products', @_ ) ); } |
7327
|
|
|
|
|
|
|
|
7328
|
|
|
|
|
|
|
And using your method: |
7329
|
|
|
|
|
|
|
|
7330
|
|
|
|
|
|
|
printf( "There are %d products\n", $object->products->length ); |
7331
|
|
|
|
|
|
|
$object->products->push( $new_product ); |
7332
|
|
|
|
|
|
|
|
7333
|
|
|
|
|
|
|
=head2 _set_get_boolean |
7334
|
|
|
|
|
|
|
|
7335
|
|
|
|
|
|
|
Provided with an object property name and some data and this will store the data as a boolean value. |
7336
|
|
|
|
|
|
|
|
7337
|
|
|
|
|
|
|
If the data provided is a L<JSON::PP::Boolean> or L<Module::Generic::Boolean> object, the data is stored as is. |
7338
|
|
|
|
|
|
|
|
7339
|
|
|
|
|
|
|
If the data is a scalar reference, its referenced value is check and L<Module::Generic::Boolean/"true"> or L<Module::Generic::Boolean/"false"> is set accordingly. |
7340
|
|
|
|
|
|
|
|
7341
|
|
|
|
|
|
|
If the data is a string with value of C<true> or C<val> L<Module::Generic::Boolean/"true"> or L<Module::Generic::Boolean/"false"> is set accordingly. |
7342
|
|
|
|
|
|
|
|
7343
|
|
|
|
|
|
|
Otherwise the data provided is checked if it is a true value or not and L<Module::Generic::Boolean/"true"> or L<Module::Generic::Boolean/"false"> is set accordingly. |
7344
|
|
|
|
|
|
|
|
7345
|
|
|
|
|
|
|
If no value is provided, and the object property has already been set, this performs the same checks as above and returns either a L<JSON::PP::Boolean> or a L<Module::Generic::Boolean> object. |
7346
|
|
|
|
|
|
|
|
7347
|
|
|
|
|
|
|
=head2 __create_class |
7348
|
|
|
|
|
|
|
|
7349
|
|
|
|
|
|
|
Provided with an object property name and an hash reference representing a dictionary and this will produce a dynamically created class/module. |
7350
|
|
|
|
|
|
|
|
7351
|
|
|
|
|
|
|
If a property I<_class> exists in the dictionary, it will be used as the class/package name, otherwise a name will be derived from the calling object class and the object property name. For example, in your module : |
7352
|
|
|
|
|
|
|
|
7353
|
|
|
|
|
|
|
sub products { return( 'products', shift->_set_get_class( |
7354
|
|
|
|
|
|
|
{ |
7355
|
|
|
|
|
|
|
name => { type => 'scalar' }, |
7356
|
|
|
|
|
|
|
customer => { type => 'object', class => 'My::Customer' }, |
7357
|
|
|
|
|
|
|
orders => { type => 'array_as_object' }, |
7358
|
|
|
|
|
|
|
active => { type => 'boolean' }, |
7359
|
|
|
|
|
|
|
created => { type => 'datetime' }, |
7360
|
|
|
|
|
|
|
metadata => { type => 'hash' }, |
7361
|
|
|
|
|
|
|
stock => { type => 'number' }, |
7362
|
|
|
|
|
|
|
url => { type => 'uri' }, |
7363
|
|
|
|
|
|
|
}, @_ ) ); } |
7364
|
|
|
|
|
|
|
|
7365
|
|
|
|
|
|
|
Then calling your module method B<products> such as : |
7366
|
|
|
|
|
|
|
|
7367
|
|
|
|
|
|
|
my $prod = $object->products({ |
7368
|
|
|
|
|
|
|
name => 'Cool product', |
7369
|
|
|
|
|
|
|
customer => { first_name => 'John', last_name => 'Doe', email => 'john.doe@example.com' }, |
7370
|
|
|
|
|
|
|
orders => [qw( 123 987 456 654 )], |
7371
|
|
|
|
|
|
|
active => 1, |
7372
|
|
|
|
|
|
|
metadata => { transaction_id => 123, api_call_id => 456 }, |
7373
|
|
|
|
|
|
|
stock => 10, |
7374
|
|
|
|
|
|
|
uri => 'https://example.com/p/20' |
7375
|
|
|
|
|
|
|
}); |
7376
|
|
|
|
|
|
|
|
7377
|
|
|
|
|
|
|
Using the resulting object C<$prod>, we can access this dynamically created class/module such as : |
7378
|
|
|
|
|
|
|
|
7379
|
|
|
|
|
|
|
printf( <<EOT, $prod->name, $prod->orders->length, $prod->customer->last_name,, $prod->url->path ) |
7380
|
|
|
|
|
|
|
Product name: %s |
7381
|
|
|
|
|
|
|
No of orders: %d |
7382
|
|
|
|
|
|
|
Customer name: %s |
7383
|
|
|
|
|
|
|
Product page path: %s |
7384
|
|
|
|
|
|
|
EOT |
7385
|
|
|
|
|
|
|
|
7386
|
|
|
|
|
|
|
=head2 _set_get_class |
7387
|
|
|
|
|
|
|
|
7388
|
|
|
|
|
|
|
Given an object property name, a dynamic class fiels definition hash (dictionary), and optional arguments, this special method will create perl packages on the fly by calling the support method L</"__create_class"> |
7389
|
|
|
|
|
|
|
|
7390
|
|
|
|
|
|
|
For example, consider the following: |
7391
|
|
|
|
|
|
|
|
7392
|
|
|
|
|
|
|
#!/usr/local/bin/perl |
7393
|
|
|
|
|
|
|
BEGIN |
7394
|
|
|
|
|
|
|
{ |
7395
|
|
|
|
|
|
|
use strict; |
7396
|
|
|
|
|
|
|
use Data::Dumper; |
7397
|
|
|
|
|
|
|
}; |
7398
|
|
|
|
|
|
|
|
7399
|
|
|
|
|
|
|
{ |
7400
|
|
|
|
|
|
|
my $o = MyClass->new( debug => 3 ); |
7401
|
|
|
|
|
|
|
$o->setup->age( 42 ); |
7402
|
|
|
|
|
|
|
print( "Age is: ", $o->setup->age, "\n" ); |
7403
|
|
|
|
|
|
|
print( "Setup object is: ", $o->setup, "\n" ); |
7404
|
|
|
|
|
|
|
$o->setup->billing->interval( 'month' ); |
7405
|
|
|
|
|
|
|
print( "Billing interval is: ", $o->setup->billing->interval, "\n" ); |
7406
|
|
|
|
|
|
|
print( "Billing object is: ", $o->setup->billing, "\n" ); |
7407
|
|
|
|
|
|
|
$o->setup->rgb( 255, 122, 100 ); |
7408
|
|
|
|
|
|
|
print( "rgb: ", join( ', ', @{$o->setup->rgb} ), "\n" ); |
7409
|
|
|
|
|
|
|
exit( 0 ); |
7410
|
|
|
|
|
|
|
} |
7411
|
|
|
|
|
|
|
|
7412
|
|
|
|
|
|
|
package MyClass; |
7413
|
|
|
|
|
|
|
BEGIN |
7414
|
|
|
|
|
|
|
{ |
7415
|
|
|
|
|
|
|
use strict; |
7416
|
|
|
|
|
|
|
use lib './lib'; |
7417
|
|
|
|
|
|
|
use parent qw( Module::Generic ); |
7418
|
|
|
|
|
|
|
}; |
7419
|
|
|
|
|
|
|
|
7420
|
|
|
|
|
|
|
sub setup |
7421
|
|
|
|
|
|
|
{ |
7422
|
|
|
|
|
|
|
return( shift->_set_get_class( 'setup', |
7423
|
|
|
|
|
|
|
{ |
7424
|
|
|
|
|
|
|
name => { type => 'scalar' }, |
7425
|
|
|
|
|
|
|
age => { type => 'number' }, |
7426
|
|
|
|
|
|
|
metadata => { type => 'hash' }, |
7427
|
|
|
|
|
|
|
rgb => { type => 'array' }, |
7428
|
|
|
|
|
|
|
url => { type => 'uri' }, |
7429
|
|
|
|
|
|
|
online => { type => 'boolean' }, |
7430
|
|
|
|
|
|
|
created => { type => 'datetime' }, |
7431
|
|
|
|
|
|
|
billing => { type => 'class', definition => |
7432
|
|
|
|
|
|
|
{ |
7433
|
|
|
|
|
|
|
interval => { type => 'scalar' }, |
7434
|
|
|
|
|
|
|
frequency => { type => 'number' }, |
7435
|
|
|
|
|
|
|
nickname => { type => 'scalar' }, |
7436
|
|
|
|
|
|
|
}} |
7437
|
|
|
|
|
|
|
}) ); |
7438
|
|
|
|
|
|
|
} |
7439
|
|
|
|
|
|
|
|
7440
|
|
|
|
|
|
|
1; |
7441
|
|
|
|
|
|
|
|
7442
|
|
|
|
|
|
|
__END__ |
7443
|
|
|
|
|
|
|
|
7444
|
|
|
|
|
|
|
This will yield: |
7445
|
|
|
|
|
|
|
|
7446
|
|
|
|
|
|
|
Age is: 42 |
7447
|
|
|
|
|
|
|
Setup object is: MyClass::Setup=HASH(0x7fa805abcb20) |
7448
|
|
|
|
|
|
|
Billing interval is: month |
7449
|
|
|
|
|
|
|
Billing object is: MyClass::Setup::Billing=HASH(0x7fa804ec3f40) |
7450
|
|
|
|
|
|
|
rgb: 255, 122, 100 |
7451
|
|
|
|
|
|
|
|
7452
|
|
|
|
|
|
|
The advantage of this over B<_set_get_hash_as_object> is that here one controls what fields / method are supported and with which data type. |
7453
|
|
|
|
|
|
|
|
7454
|
|
|
|
|
|
|
=head2 _set_get_class_array |
7455
|
|
|
|
|
|
|
|
7456
|
|
|
|
|
|
|
Provided with an object property name, a dictionary to create a dynamic class with L</"__create_class"> and an array reference of hash references and this will create an array of object, each one matching a set of data provided in the array reference. So for example, imagine you had a method such as below in your module : |
7457
|
|
|
|
|
|
|
|
7458
|
|
|
|
|
|
|
sub products { return( shift->_set_get_class_array( 'products', |
7459
|
|
|
|
|
|
|
{ |
7460
|
|
|
|
|
|
|
name => { type => 'scalar' }, |
7461
|
|
|
|
|
|
|
customer => { type => 'object', class => 'My::Customer' }, |
7462
|
|
|
|
|
|
|
orders => { type => 'array_as_object' }, |
7463
|
|
|
|
|
|
|
active => { type => 'boolean' }, |
7464
|
|
|
|
|
|
|
created => { type => 'datetime' }, |
7465
|
|
|
|
|
|
|
metadata => { type => 'hash' }, |
7466
|
|
|
|
|
|
|
stock => { type => 'number' }, |
7467
|
|
|
|
|
|
|
url => { type => 'uri' }, |
7468
|
|
|
|
|
|
|
}, @_ ) ); } |
7469
|
|
|
|
|
|
|
|
7470
|
|
|
|
|
|
|
Then your script would call this method like this : |
7471
|
|
|
|
|
|
|
|
7472
|
|
|
|
|
|
|
$object->products([ |
7473
|
|
|
|
|
|
|
{ name => 'Cool product', customer => { first_name => 'John', last_name => 'Doe', email => 'john.doe@example.com' }, active => 1, stock => 10, created => '2020-04-12T07:10:30' }, |
7474
|
|
|
|
|
|
|
{ name => 'Awesome tool', customer => { first_name => 'Mary', last_name => 'Donald', email => 'm.donald@example.com' }, active => 1, stock => 15, created => '2020-05-12T15:20:10' }, |
7475
|
|
|
|
|
|
|
]); |
7476
|
|
|
|
|
|
|
|
7477
|
|
|
|
|
|
|
And this would store an array reference containing 2 objects with the above data. |
7478
|
|
|
|
|
|
|
|
7479
|
|
|
|
|
|
|
=head2 _set_get_code |
7480
|
|
|
|
|
|
|
|
7481
|
|
|
|
|
|
|
Provided with an object property name and some code reference and this stores and retrieve the current value. |
7482
|
|
|
|
|
|
|
|
7483
|
|
|
|
|
|
|
It returns under and set an error if the provided value is not a code reference. |
7484
|
|
|
|
|
|
|
|
7485
|
|
|
|
|
|
|
=head2 _set_get_datetime |
7486
|
|
|
|
|
|
|
|
7487
|
|
|
|
|
|
|
Provided with an object property name and asome date or datetime string and this will attempt to parse it and save it as a L<DateTime> object. |
7488
|
|
|
|
|
|
|
|
7489
|
|
|
|
|
|
|
If the data is a 10 digits integer, this will treat it as a unix timestamp. |
7490
|
|
|
|
|
|
|
|
7491
|
|
|
|
|
|
|
Parsing also recognise special word such as C<now> |
7492
|
|
|
|
|
|
|
|
7493
|
|
|
|
|
|
|
The created L<DateTime> object is associated a L<DateTime::Format::Strptime> object which enables the L<DateTime> object to be stringified as a unix timestamp using local time stamp, whatever it is. |
7494
|
|
|
|
|
|
|
|
7495
|
|
|
|
|
|
|
Even if there is no value set, and this method is called in chain, it returns a L<Module::Generic::Null> whose purpose is to enable chaining without doing anything meaningful. For example, assuming the property I<created> of your object is not set yet, but in your script you call it like this: |
7496
|
|
|
|
|
|
|
|
7497
|
|
|
|
|
|
|
$object->created->iso8601 |
7498
|
|
|
|
|
|
|
|
7499
|
|
|
|
|
|
|
Of course, the value of C<iso8601> will be empty since this is a fake method produced by L<Module::Generic::Null>. The return value of a method should always be checked. |
7500
|
|
|
|
|
|
|
|
7501
|
|
|
|
|
|
|
=head2 _set_get_hash |
7502
|
|
|
|
|
|
|
|
7503
|
|
|
|
|
|
|
Provided with an object property name and an hash reference and this set the property name with this hash reference. |
7504
|
|
|
|
|
|
|
|
7505
|
|
|
|
|
|
|
You can even pass it an associative array, and it will be saved as a hash reference, such as : |
7506
|
|
|
|
|
|
|
|
7507
|
|
|
|
|
|
|
$object->metadata( |
7508
|
|
|
|
|
|
|
transaction_id => 123, |
7509
|
|
|
|
|
|
|
customer_id => 456 |
7510
|
|
|
|
|
|
|
); |
7511
|
|
|
|
|
|
|
|
7512
|
|
|
|
|
|
|
my $hash = $object->metadata; |
7513
|
|
|
|
|
|
|
|
7514
|
|
|
|
|
|
|
=head2 _set_get_hash_as_object |
7515
|
|
|
|
|
|
|
|
7516
|
|
|
|
|
|
|
Provided with an object property name, an optional class name and an hash reference and this does the same as in L</"_set_get_hash">, except it will create a class/package dynamically with a method for each of the hash keys, so that you can call the hash keys as method. |
7517
|
|
|
|
|
|
|
|
7518
|
|
|
|
|
|
|
Also it does this recursively while handling looping, in which case, it will reuse the object previously created, and also it takes care of adapting the hash key to a proper field name, so something like C<99more-options> would become C<more_options>. If the value itself is a hash, it processes it recursively transforming C<99more-options> to a proper package name C<MoreOptions> prepended by C<$class_name> provided as argument or whatever upper package was used in recursion processing. |
7519
|
|
|
|
|
|
|
|
7520
|
|
|
|
|
|
|
For example in your module : |
7521
|
|
|
|
|
|
|
|
7522
|
|
|
|
|
|
|
sub metadata { return( shift->_set_get_hash_as_object( 'metadata', @_ ) ); } |
7523
|
|
|
|
|
|
|
|
7524
|
|
|
|
|
|
|
Then populating the data : |
7525
|
|
|
|
|
|
|
|
7526
|
|
|
|
|
|
|
$object->metadata({ |
7527
|
|
|
|
|
|
|
first_name => 'John', |
7528
|
|
|
|
|
|
|
last_name => 'Doe', |
7529
|
|
|
|
|
|
|
email => 'john.doe@example.com', |
7530
|
|
|
|
|
|
|
}); |
7531
|
|
|
|
|
|
|
|
7532
|
|
|
|
|
|
|
printf( "Customer name is %s\n", $object->metadata->last_name ); |
7533
|
|
|
|
|
|
|
|
7534
|
|
|
|
|
|
|
=head2 _set_get_number |
7535
|
|
|
|
|
|
|
|
7536
|
|
|
|
|
|
|
Provided with an object property name and a number, and this will create a L<Module::Generic::Number> object and return it. |
7537
|
|
|
|
|
|
|
|
7538
|
|
|
|
|
|
|
=head2 _set_get_number_or_object |
7539
|
|
|
|
|
|
|
|
7540
|
|
|
|
|
|
|
Provided with an object property name and a number or an object and this call the value using L</"_set_get_number"> or L</"_set_get_object"> respectively |
7541
|
|
|
|
|
|
|
|
7542
|
|
|
|
|
|
|
=head2 _set_get_object |
7543
|
|
|
|
|
|
|
|
7544
|
|
|
|
|
|
|
Provided with an object property name, a class/package name and some data and this will initiate a new object of the given class passing it the data. |
7545
|
|
|
|
|
|
|
|
7546
|
|
|
|
|
|
|
If you pass an undefined value, it will set the property as undefined, removing whatever was set before. |
7547
|
|
|
|
|
|
|
|
7548
|
|
|
|
|
|
|
You can also provide an existing object of the given class. L</"_set_get_object"> will check the object provided does belong to the specified class or it will set an error and return undef. |
7549
|
|
|
|
|
|
|
|
7550
|
|
|
|
|
|
|
It returns the object currently set, if any. |
7551
|
|
|
|
|
|
|
|
7552
|
|
|
|
|
|
|
=head2 _set_get_object_array2 |
7553
|
|
|
|
|
|
|
|
7554
|
|
|
|
|
|
|
Provided with an object property name, a class/package name and some array reference itself containing array references each containing hash references or objects, and this will create an array of array of objects. |
7555
|
|
|
|
|
|
|
|
7556
|
|
|
|
|
|
|
=head2 _set_get_object_array |
7557
|
|
|
|
|
|
|
|
7558
|
|
|
|
|
|
|
Provided with an object property name and a class/package name and similar to L</"_set_get_object_array2"> this will create an array reference of objects. |
7559
|
|
|
|
|
|
|
|
7560
|
|
|
|
|
|
|
=head2 _set_get_object_array_object |
7561
|
|
|
|
|
|
|
|
7562
|
|
|
|
|
|
|
Provided with an object property name, a class/package name and some data and this will create an array of object similar to L</"_set_get_object_array">, except the array produced is a L<Module::Generic::Array> |
7563
|
|
|
|
|
|
|
|
7564
|
|
|
|
|
|
|
=head2 _set_get_object_variant |
7565
|
|
|
|
|
|
|
|
7566
|
|
|
|
|
|
|
Provided with an object property name, a class/package name and some data, and depending whether the data provided is an hash reference or an array reference, this will either instantiate an object for the given hash reference or an array of objects with the hash references in the given array. |
7567
|
|
|
|
|
|
|
|
7568
|
|
|
|
|
|
|
This means the value stored for the object property will vary between an hash or array reference. |
7569
|
|
|
|
|
|
|
|
7570
|
|
|
|
|
|
|
=head2 _set_get_scalar |
7571
|
|
|
|
|
|
|
|
7572
|
|
|
|
|
|
|
Provided with an object property name, and a string, possibly a number or anything really and this will set the property value accordingly. Very straightforward. |
7573
|
|
|
|
|
|
|
|
7574
|
|
|
|
|
|
|
It returns the currently value stored. |
7575
|
|
|
|
|
|
|
|
7576
|
|
|
|
|
|
|
=head2 _set_get_scalar_as_object |
7577
|
|
|
|
|
|
|
|
7578
|
|
|
|
|
|
|
Provided with an object property name, and a string or a scalar reference and this stores it as an object of L<Module::Generic::Scalar> |
7579
|
|
|
|
|
|
|
|
7580
|
|
|
|
|
|
|
If there is already an object set for this property, the value provided will be assigned to it using L<Module::Generic::Scalar/"set"> |
7581
|
|
|
|
|
|
|
|
7582
|
|
|
|
|
|
|
If it is called and not value is set yet, this will instantiate a L<Module::Generic::Scalar> object with no value. |
7583
|
|
|
|
|
|
|
|
7584
|
|
|
|
|
|
|
So a call to this method can safely be chained to access the L<Module::Generic::Scalar> methods. For example : |
7585
|
|
|
|
|
|
|
|
7586
|
|
|
|
|
|
|
sub name { return( shift->_set_get_scalar_as_object( 'name', @_ ) ); } |
7587
|
|
|
|
|
|
|
|
7588
|
|
|
|
|
|
|
Then, calling it : |
7589
|
|
|
|
|
|
|
|
7590
|
|
|
|
|
|
|
$object->name( 'John Doe' ); |
7591
|
|
|
|
|
|
|
|
7592
|
|
|
|
|
|
|
Getting the value : |
7593
|
|
|
|
|
|
|
|
7594
|
|
|
|
|
|
|
my $cust_name = $object->name; |
7595
|
|
|
|
|
|
|
print( "Nothing set yet.\n" ) if( !$cust_name->length ); |
7596
|
|
|
|
|
|
|
|
7597
|
|
|
|
|
|
|
=head2 _set_get_scalar_or_object |
7598
|
|
|
|
|
|
|
|
7599
|
|
|
|
|
|
|
Provided with an object property name, and a class/package name and this stores the value as an object calling L</"_set_get_object"> if the value is an object of class I<class> or as a string calling L</"_set_get_scalar"> |
7600
|
|
|
|
|
|
|
|
7601
|
|
|
|
|
|
|
If no value has been set yet, this returns a L<Module::Generic::Null> object to enable chaining. |
7602
|
|
|
|
|
|
|
|
7603
|
|
|
|
|
|
|
=head2 _set_get_uri |
7604
|
|
|
|
|
|
|
|
7605
|
|
|
|
|
|
|
Provided with an object property name, and an uri and this creates a L<URI> object and sets the property value accordingly. |
7606
|
|
|
|
|
|
|
|
7607
|
|
|
|
|
|
|
It accepts an L<URI> object, an uri or urn string, or an absolute path, i.e. a string starting with C</>. |
7608
|
|
|
|
|
|
|
|
7609
|
|
|
|
|
|
|
It returns the current value, if any, so the return value could be undef, thus it cannot be chained. Maybe it should return a L<Module::Generic::Null> object ? |
7610
|
|
|
|
|
|
|
|
7611
|
|
|
|
|
|
|
=head2 __dbh |
7612
|
|
|
|
|
|
|
|
7613
|
|
|
|
|
|
|
if your module has the global variables C<DB_DSN>, this will create a database handler using L<DBI> |
7614
|
|
|
|
|
|
|
|
7615
|
|
|
|
|
|
|
It will also use the following global variables in your module to set the database object: C<DB_RAISE_ERROR>, C<DB_AUTO_COMMIT>, C<DB_PRINT_ERROR>, C<DB_SHOW_ERROR_STATEMENT>, C<DB_CLIENT_ENCODING>, C<DB_SERVER_PREPARE> |
7616
|
|
|
|
|
|
|
|
7617
|
|
|
|
|
|
|
If C<DB_SERVER_PREPARE> is provided and true, C<pg_server_prepare> will be set to true in the database handler. |
7618
|
|
|
|
|
|
|
|
7619
|
|
|
|
|
|
|
It returns the database handler object. |
7620
|
|
|
|
|
|
|
|
7621
|
|
|
|
|
|
|
=head2 DEBUG |
7622
|
|
|
|
|
|
|
|
7623
|
|
|
|
|
|
|
Return the value of your global variable I<DEBUG>, if any. |
7624
|
|
|
|
|
|
|
|
7625
|
|
|
|
|
|
|
=head2 VERBOSE |
7626
|
|
|
|
|
|
|
|
7627
|
|
|
|
|
|
|
Return the value of your global variable I<VERBOSE>, if any. |
7628
|
|
|
|
|
|
|
|
7629
|
|
|
|
|
|
|
=head1 SEE ALSO |
7630
|
|
|
|
|
|
|
|
7631
|
|
|
|
|
|
|
L<Module::Generic::Exception>, L<Module::Generic::Array>, L<Module::Generic::Scalar>, L<Module::Generic::Boolean>, L<Module::Generic::Number>, L<Module::Generic::Null>, L<Module::Generic::Dynamic> and L<Module::Generic::Tie> |
7632
|
|
|
|
|
|
|
|
7633
|
|
|
|
|
|
|
L<Number::Format>, L<Class::Load>, L<Scalar::Util> |
7634
|
|
|
|
|
|
|
|
7635
|
|
|
|
|
|
|
=head1 AUTHOR |
7636
|
|
|
|
|
|
|
|
7637
|
|
|
|
|
|
|
Jacques Deguest E<lt>F<jack@deguest.jp>E<gt> |
7638
|
|
|
|
|
|
|
|
7639
|
|
|
|
|
|
|
=head1 COPYRIGHT & LICENSE |
7640
|
|
|
|
|
|
|
|
7641
|
|
|
|
|
|
|
Copyright (c) 2000-2020 DEGUEST Pte. Ltd. |
7642
|
|
|
|
|
|
|
|
7643
|
|
|
|
|
|
|
You can use, copy, modify and redistribute this package and associated |
7644
|
|
|
|
|
|
|
files under the same terms as Perl itself. |
7645
|
|
|
|
|
|
|
|
7646
|
|
|
|
|
|
|
=cut |