line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package String::Incremental; |
2
|
12
|
|
|
12
|
|
605596
|
use 5.008005; |
|
12
|
|
|
|
|
49
|
|
|
12
|
|
|
|
|
493
|
|
3
|
12
|
|
|
12
|
|
67
|
use strict; |
|
12
|
|
|
|
|
25
|
|
|
12
|
|
|
|
|
454
|
|
4
|
12
|
|
|
12
|
|
71
|
use warnings; |
|
12
|
|
|
|
|
22
|
|
|
12
|
|
|
|
|
341
|
|
5
|
12
|
|
|
12
|
|
11920
|
use Mouse; |
|
12
|
|
|
|
|
758547
|
|
|
12
|
|
|
|
|
65
|
|
6
|
12
|
|
|
12
|
|
40095
|
use MouseX::Types::Mouse qw( Str ArrayRef is_Str ); |
|
12
|
|
|
|
|
32487
|
|
|
12
|
|
|
|
|
85
|
|
7
|
12
|
|
|
12
|
|
25910
|
use String::Incremental::Types qw( Char ); |
|
12
|
|
|
|
|
112
|
|
|
12
|
|
|
|
|
55
|
|
8
|
12
|
|
|
12
|
|
11448
|
use String::Incremental::FormatParser; |
|
12
|
|
|
|
|
875
|
|
|
12
|
|
|
|
|
922
|
|
9
|
12
|
|
|
12
|
|
81
|
use String::Incremental::Char; |
|
12
|
|
|
|
|
29
|
|
|
12
|
|
|
|
|
283
|
|
10
|
12
|
|
|
12
|
|
62
|
use Data::Validator; |
|
12
|
|
|
|
|
30
|
|
|
12
|
|
|
|
|
2238
|
|
11
|
12
|
|
|
12
|
|
64
|
use Try::Tiny; |
|
12
|
|
|
|
|
33886
|
|
|
12
|
|
|
|
|
4955
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
use overload ( |
14
|
|
|
|
|
|
|
'""' => \&as_string, |
15
|
|
|
|
|
|
|
'++' => \&increment, |
16
|
|
|
|
|
|
|
'--' => \&decrement, |
17
|
11
|
|
|
11
|
|
1738
|
'=' => sub { $_[0] }, |
18
|
12
|
|
|
12
|
|
273
|
); |
|
12
|
|
|
|
|
1323
|
|
|
12
|
|
|
|
|
3009
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
extends qw( Exporter Tie::Scalar ); |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
our $VERSION = "0.01"; |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
our @EXPORT_OK = qw( incremental_string ); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
has 'format' => ( is => 'ro', isa => Str ); |
27
|
|
|
|
|
|
|
has 'items' => ( is => 'ro', isa => ArrayRef ); |
28
|
|
|
|
|
|
|
has 'chars' => ( is => 'ro', isa => ArrayRef['String::Incremental::Char'] ); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub BUILDARGS { |
31
|
44
|
|
|
44
|
0
|
100899
|
my ($class, %args) = @_; |
32
|
44
|
|
|
|
|
242
|
my $v = Data::Validator->new( |
33
|
|
|
|
|
|
|
format => { isa => Str }, |
34
|
|
|
|
|
|
|
orders => { isa => ArrayRef, default => [] }, |
35
|
|
|
|
|
|
|
); |
36
|
44
|
|
|
|
|
6128
|
%args = %{$v->validate( \%args )}; |
|
44
|
|
|
|
|
194
|
|
37
|
|
|
|
|
|
|
|
38
|
43
|
|
|
|
|
2387
|
my $p = String::Incremental::FormatParser->new( $args{format}, @{$args{orders}} ); |
|
43
|
|
|
|
|
427
|
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
return +{ |
41
|
42
|
|
|
|
|
1240
|
format => $p->format, |
42
|
|
|
|
|
|
|
items => $p->items, |
43
|
42
|
|
|
|
|
244
|
chars => [ grep $_->isa( __PACKAGE__ . '::Char' ), @{$p->items} ], |
44
|
|
|
|
|
|
|
}; |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
sub incremental_string { |
48
|
3
|
|
|
3
|
1
|
1864
|
my ($format, @orders) = @_; |
49
|
3
|
|
|
|
|
56
|
return __PACKAGE__->new( format => $format, orders => \@orders ); |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub char { |
53
|
16
|
|
|
16
|
0
|
1728
|
my ($self, $i) = @_; |
54
|
16
|
|
|
|
|
18
|
my $ch; |
55
|
16
|
100
|
|
|
|
38
|
unless ( defined $i ) { |
56
|
1
|
|
|
|
|
15
|
die 'index to set must be specified'; |
57
|
|
|
|
|
|
|
} |
58
|
15
|
100
|
|
|
|
80
|
unless ( $i =~ /^\d+$/ ) { |
59
|
1
|
|
|
|
|
7
|
die 'must be specified as Int'; |
60
|
|
|
|
|
|
|
} |
61
|
14
|
100
|
|
|
|
64
|
unless ( defined ( $ch = $self->chars->[$i] ) ) { |
62
|
1
|
|
|
|
|
8
|
die 'out of index'; |
63
|
|
|
|
|
|
|
} |
64
|
13
|
|
|
|
|
32
|
return $ch; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub as_string { |
68
|
99
|
|
|
99
|
1
|
2416
|
my ($self) = @_; |
69
|
99
|
|
|
|
|
262
|
my @vals = map "$_", @{$self->items}; |
|
99
|
|
|
|
|
1154
|
|
70
|
99
|
|
|
|
|
901
|
return sprintf( $self->format, @vals ); |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
sub set { |
74
|
11
|
|
|
11
|
1
|
3818
|
my $v = Data::Validator->new( |
75
|
|
|
|
|
|
|
val => { isa => Str }, |
76
|
|
|
|
|
|
|
)->with( 'Method', 'StrictSequenced' ); |
77
|
11
|
|
|
|
|
35528
|
my ($self, $args) = $v->validate( @_ ); |
78
|
|
|
|
|
|
|
|
79
|
10
|
|
|
|
|
1112
|
my @ch = $self->_extract_incremental_chars( $args->{val} ); |
80
|
4
|
|
|
|
|
912
|
for ( my $i = 0; $i < @ch; $i++ ) { |
81
|
8
|
|
|
|
|
28
|
my $char = $self->char( $i ); |
82
|
8
|
|
|
|
|
40
|
$char->set( $ch[$i] ); |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
4
|
|
|
|
|
339
|
return "$self"; |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
sub increment { |
89
|
25
|
|
|
25
|
1
|
59
|
my ($self) = @_; |
90
|
25
|
|
|
|
|
34
|
my ($last_ch) = grep $_->isa( __PACKAGE__ . '::Char' ), reverse @{$self->items}; |
|
25
|
|
|
|
|
318
|
|
91
|
25
|
50
|
|
|
|
63
|
if ( defined $last_ch ) { |
92
|
25
|
|
|
|
|
587
|
$last_ch++; |
93
|
|
|
|
|
|
|
} |
94
|
22
|
|
|
|
|
157
|
return "$self"; |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
sub decrement { |
98
|
21
|
|
|
21
|
1
|
64
|
my ($self) = @_; |
99
|
21
|
|
|
|
|
35
|
my ($last_ch) = grep $_->isa( __PACKAGE__ . '::Char' ), reverse @{$self->items}; |
|
21
|
|
|
|
|
293
|
|
100
|
21
|
50
|
|
|
|
60
|
if ( defined $last_ch ) { |
101
|
21
|
|
|
|
|
366
|
$last_ch--; |
102
|
|
|
|
|
|
|
} |
103
|
20
|
|
|
|
|
271
|
return "$self"; |
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub re { |
107
|
52
|
|
|
52
|
0
|
203
|
my ($self) = @_; |
108
|
52
|
|
|
|
|
70
|
my ($re, @re); |
109
|
|
|
|
|
|
|
|
110
|
185
|
|
|
|
|
283
|
@re = map { |
111
|
52
|
|
|
|
|
211
|
my $i = $_; |
112
|
185
|
|
|
|
|
745
|
my $_re = $i->re(); |
113
|
185
|
|
|
|
|
336
|
my $ref = ref $_; |
114
|
185
|
100
|
|
|
|
801
|
$ref eq __PACKAGE__ . '::Char' ? "(${_re})" : $_re; |
115
|
52
|
|
|
|
|
88
|
} @{$self->items}; |
116
|
|
|
|
|
|
|
|
117
|
52
|
|
|
|
|
2714
|
(my $fmt = $self->format) =~ s/%(?:\d+(?:\.?\d+)?)?\S/\%s/g; |
118
|
52
|
|
|
|
|
209
|
$re = sprintf $fmt, @re; |
119
|
|
|
|
|
|
|
|
120
|
52
|
|
|
|
|
899
|
return qr/^(${re})$/; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
sub _extract_incremental_chars { |
124
|
44
|
|
|
44
|
|
44866
|
my $v = Data::Validator->new( |
125
|
|
|
|
|
|
|
val => { isa => Str }, |
126
|
|
|
|
|
|
|
)->with( 'Method', 'StrictSequenced' ); |
127
|
44
|
|
|
|
|
71414
|
my ($self, $args) = $v->validate( @_ ); |
128
|
43
|
|
|
|
|
3218
|
my @ch; |
129
|
|
|
|
|
|
|
|
130
|
43
|
|
|
|
|
190
|
(my $match, @ch) = $args->{val} =~ $self->re(); |
131
|
43
|
100
|
|
|
|
168
|
unless ( defined $match ) { |
132
|
22
|
|
|
|
|
40
|
my $msg = 'specified value does not match with me'; |
133
|
22
|
|
|
|
|
519
|
die $msg; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
21
|
100
|
|
|
|
330
|
return wantarray ? @ch : \@ch; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub TIESCALAR { |
140
|
4
|
|
|
4
|
|
5962
|
my ($class, @args) = @_; |
141
|
4
|
|
|
|
|
63
|
return $class->new( @args ); |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
|
144
|
48
|
|
|
48
|
|
4828
|
sub FETCH { $_[0] } |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub STORE { |
147
|
11
|
|
|
11
|
|
2835
|
my ($self, @args) = @_; |
148
|
11
|
100
|
|
|
|
68
|
if ( ref( $args[0] ) eq '' ) { # ignore when ++/-- |
149
|
4
|
|
|
|
|
22
|
$self->set( @args ); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable(); |
154
|
|
|
|
|
|
|
__END__ |