File Coverage

blib/lib/String/Secret.pm
Criterion Covered Total %
statement 34 39 87.1
branch 6 6 100.0
condition n/a
subroutine 13 18 72.2
pod 0 12 0.0
total 53 75 70.6


line stmt bran cond sub pod time code
1             package String::Secret;
2 5     5   278395 use 5.008001;
  5         56  
3 5     5   27 use strict;
  5         9  
  5         95  
4 5     5   23 use warnings;
  5         8  
  5         151  
5              
6 5     5   25 use Scalar::Util qw/refaddr/;
  5         9  
  5         413  
7              
8             our $VERSION = "0.01";
9              
10             use overload
11 5         28 '""' => 'to_string',
12 5     5   5295 fallback => 1;
  5         4129  
13              
14             our $DISABLE_MASK = 0;
15             our $MASKED_STRING = '*' x 8;
16              
17             my %SECRETS;
18              
19             sub new {
20 8     8 0 3815 my ($class, $secret) = @_;
21 8         18 my $masked = $MASKED_STRING;
22 8         21 my $self = bless \$masked, $class;
23 8         47 $SECRETS{refaddr($self)} = $secret;
24 8         24 return $self;
25             }
26              
27 0     0 0 0 sub from_serializable { $_[0]->new($_[1]->unwrap) }
28              
29 19     19 0 2473 sub unwrap { $SECRETS{refaddr($_[0])} }
30              
31             sub to_serializable {
32 4     4 0 9144 require String::Secret::Serializable;
33 4         30 String::Secret::Serializable->new(shift->unwrap);
34             }
35              
36             sub to_string {
37 7 100   7 0 2035 return shift->unwrap if $DISABLE_MASK;
38 4         99 return $MASKED_STRING;
39             }
40              
41             # for Storable
42             sub STORABLE_freeze {
43 4     4 0 1584 my ($self, $cloning) = @_;
44 4 100       14 return $self->unwrap if $cloning;
45 2         6 return $self->to_string;
46             }
47             sub STORABLE_thaw {
48 7     7 0 3908 my ($self, $cloning, $masked) = @_;
49 7 100       20 if ($cloning) {
50 5         16 $SECRETS{refaddr($self)} = $masked; # $masked is unwrapped value
51 5         133 return $self;
52             }
53              
54 2         19 die "cannot deserialize it, should convert it as serializable by \$secret->to_serializable";
55             }
56              
57             # for JSON modules
58 2     2 0 2271 sub TO_JSON { shift->to_string }
59              
60             # for CBOR
61 0     0 0 0 sub TO_CBOR { shift->to_string }
62              
63             # for JSON, CBOR, Sereal, ...
64 0     0 0 0 sub FREEZE { shift->to_string }
65             sub THAW {
66 0     0 0 0 die "cannot deserialize it, should convert it as serializable by \$secret->to_serializable";
67             }
68              
69             # for Data::Clone
70 0     0 0 0 sub clone { shift } # immutable
71              
72 13     13   16676 sub DESTROY { delete $SECRETS{refaddr($_[0])} }
73              
74             1;
75             __END__