File Coverage

blib/lib/String/Incremental.pm
Criterion Covered Total %
statement 101 101 100.0
branch 16 18 88.8
condition n/a
subroutine 24 24 100.0
pod 5 8 62.5
total 146 151 96.6


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__