line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Const::Dual; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
284020
|
use 5.006; |
|
5
|
|
|
|
|
47
|
|
4
|
5
|
|
|
5
|
|
21
|
use strict; |
|
5
|
|
|
|
|
6
|
|
|
5
|
|
|
|
|
84
|
|
5
|
5
|
|
|
5
|
|
17
|
use warnings; |
|
5
|
|
|
|
|
6
|
|
|
5
|
|
|
|
|
93
|
|
6
|
|
|
|
|
|
|
|
7
|
5
|
|
|
5
|
|
27
|
use Carp (); |
|
5
|
|
|
|
|
15
|
|
|
5
|
|
|
|
|
103
|
|
8
|
5
|
|
|
5
|
|
21
|
use Scalar::Util (); |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
347
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
Const::Dual - numeric constants that know their names |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=cut |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 SYNOPSIS |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# create constants |
22
|
|
|
|
|
|
|
use Const::Dual ( |
23
|
|
|
|
|
|
|
TYPE_FOO => 1, |
24
|
|
|
|
|
|
|
TYPE_BAR => 2, |
25
|
|
|
|
|
|
|
# ... more constants ... |
26
|
|
|
|
|
|
|
TYPE_BAZ => 99, |
27
|
|
|
|
|
|
|
); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
$type = TYPE_BAR; |
30
|
|
|
|
|
|
|
print $type + 0; # 2 |
31
|
|
|
|
|
|
|
print $type == 2 ? "bar" : "not bar"; # bar |
32
|
|
|
|
|
|
|
print $type == TYPE_BAR ? "bar" : "not bar"; # bar |
33
|
|
|
|
|
|
|
print "type = $type"; # type = TYPE_BAR |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# create constants and store them in %TYPES |
36
|
|
|
|
|
|
|
use Const::Dual \%TYPES => ( |
37
|
|
|
|
|
|
|
TYPE_FOO => 1, |
38
|
|
|
|
|
|
|
TYPE_BAR => 2, |
39
|
|
|
|
|
|
|
# ... more constants ... |
40
|
|
|
|
|
|
|
TYPE_BAZ => 99, |
41
|
|
|
|
|
|
|
); |
42
|
|
|
|
|
|
|
@EXPORT_OK = keys %TYPES; |
43
|
|
|
|
|
|
|
@EXPORT_TAGS = (types => [ keys %TYPES ]); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# get dual value from non-dual value |
46
|
|
|
|
|
|
|
my $type = $ARGV[0] // 99; |
47
|
|
|
|
|
|
|
my %TYPES_REVERSE; @TYPES_REVERSE{ map { int $_ } values %TYPES } = values %TYPES; |
48
|
|
|
|
|
|
|
die "Invalid type $type" unless exists $TYPES_REVERSE{$type}; |
49
|
|
|
|
|
|
|
$type = $TYPES_REVERSE{$type}; |
50
|
|
|
|
|
|
|
print int $type; # 99 |
51
|
|
|
|
|
|
|
print "type = $type"; # type = TYPE_BAZ |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=cut |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
BEGIN { |
56
|
|
|
|
|
|
|
# forbid utf8 constant names on old perl |
57
|
5
|
50
|
33
|
5
|
|
1093
|
*_DOWNGRADE = $] >= 5.008 && $] < 5.015004 ? sub { 1 } : sub { 0 }; |
|
0
|
|
|
14
|
|
0
|
|
|
14
|
|
|
|
|
37
|
|
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# some names are evil choices |
61
|
|
|
|
|
|
|
my %forbidden = map { $_ => 1 } qw/BEGIN INIT CHECK UNITCHECK END DESTROY AUTOLOAD/, qw/STDIN STDOUT STDERR ARGV ARGVOUT ENV INC SIG/; |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
sub import { |
64
|
12
|
|
|
12
|
|
13902
|
my $class = shift; |
65
|
|
|
|
|
|
|
|
66
|
12
|
100
|
|
|
|
40
|
my $storehash = ref $_[0] ? shift : undef; |
67
|
12
|
100
|
100
|
|
|
155
|
Carp::croak "Only hashref accepted to store constants" if $storehash && ref $storehash ne 'HASH'; |
68
|
11
|
100
|
|
|
|
138
|
Carp::croak "Odd number of elements provided" if @_ % 2; |
69
|
|
|
|
|
|
|
|
70
|
10
|
|
|
|
|
38
|
while (@_) { |
71
|
16
|
|
|
|
|
44
|
my ($name, $value) = splice @_, 0, 2; |
72
|
16
|
100
|
66
|
|
|
279
|
Carp::croak "Invalid constant name '$name'" if ref $name || $name !~ /^[a-zA-Z_][a-zA-Z0-9_]*$/; |
73
|
15
|
100
|
|
|
|
117
|
Carp::croak "Invalid constant name '$name': registered keyword" if $forbidden{$name}; #TODO utf? |
74
|
|
|
|
|
|
|
|
75
|
14
|
100
|
|
|
|
54
|
my $value_copy = Scalar::Util::looks_like_number($value) ? Scalar::Util::dualvar($value, $name) : $value; |
76
|
14
|
100
|
|
|
|
33
|
$storehash->{$name} = $value_copy if $storehash; |
77
|
|
|
|
|
|
|
|
78
|
14
|
50
|
33
|
|
|
26
|
utf8::encode $name if _DOWNGRADE && utf8::is_utf8 $name; |
79
|
14
|
|
|
|
|
45
|
$name = caller() . '::' . $name; |
80
|
|
|
|
|
|
|
|
81
|
5
|
|
|
5
|
|
32
|
no strict 'refs'; |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
463
|
|
82
|
14
|
|
|
0
|
|
106
|
*{ $name } = sub () { $value_copy }; |
|
14
|
|
|
|
|
159
|
|
|
0
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
=head1 DESCRIPTION |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
This module can be helpful when you use a lot of constants and really tired to deal with them. Numeric constants created |
89
|
|
|
|
|
|
|
with this module are dual (see L). They have their given numeric values when are used in numeric |
90
|
|
|
|
|
|
|
context. When used in string context, such constants are strings with constants' names. This can be useful for debug purposes: |
91
|
|
|
|
|
|
|
constant's value "knows" constant's name and it can be printed. This behavior does not apply to non-numberic constants, |
92
|
|
|
|
|
|
|
they are created as usual. |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
=head1 CAVEATS |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
Developer should ALWAYS keep in mind that he works with dual values and should force numeric context when necessary. |
97
|
|
|
|
|
|
|
This is strict rule and it's violation can lead to bugs. Common ways to force numeric context is C or C<$value+0>. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
=head1 SOURCE |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
The development version is on github at L |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head1 AUTHOR |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
Sergey Panteleev, Ebambr@cpan.orgE |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
Copyright (C) 2018 by Sergey Panteleev |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or modify |
112
|
|
|
|
|
|
|
it under the same terms as Perl itself, either Perl version 5.8.8 or, |
113
|
|
|
|
|
|
|
at your option, any later version of Perl 5 you may have available. |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=cut |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
1; |