File Coverage

blib/lib/HashDataRole/Source/LinesInDATA.pm
Criterion Covered Total %
statement 84 98 85.7
branch 15 22 68.1
condition 2 6 33.3
subroutine 15 20 75.0
pod 3 13 23.0
total 119 159 74.8


line stmt bran cond sub pod time code
1             package HashDataRole::Source::LinesInDATA;
2              
3             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2021-05-21'; # DATE
5             our $DIST = 'HashDataRoles-Standard'; # DIST
6             our $VERSION = '0.001'; # VERSION
7              
8 1     1   523 use Role::Tiny;
  1         3  
  1         5  
9 1     1   160 use Role::Tiny::With;
  1         2  
  1         56  
10             with 'HashDataRole::Spec::Basic';
11              
12             sub new {
13 1     1   6 no strict 'refs';
  1         2  
  1         325  
14              
15 1     1 0 90 my $class = shift;
16              
17 1         3 my $fh = \*{"$class\::DATA"};
  1         5  
18 1         5 my $fhpos_data_begin = tell $fh;
19              
20 1         7 bless {
21             fh => $fh,
22             fhpos_data_begin => $fhpos_data_begin,
23             pos => 0, # iterator
24             }, $class;
25             }
26              
27             sub get_next_item {
28 17     17 0 77 my $self = shift;
29 17 100       80 die "StopIteration" if eof($self->{fh});
30 16         30 $self->{fhpos_cur_item} = tell($self->{fh});
31 16         42 chomp(my $line = readline($self->{fh}));
32 16 50       64 my ($key, $value) = split /:/, $line, 2 or die "Invalid line at position $self->{pos}: no separator ':'";
33 16         31 $self->{pos}++;
34 16         57 [$key, $value];
35             }
36              
37             sub has_next_item {
38 12     12 0 19 my $self = shift;
39 12         62 !eof($self->{fh});
40             }
41              
42             sub get_iterator_pos {
43 0     0 0 0 my $self = shift;
44 0         0 $self->{pos};
45             }
46              
47             sub reset_iterator {
48 4     4 0 13 my $self = shift;
49 4         47 seek $self->{fh}, $self->{fhpos_data_begin}, 0;
50 4         30 $self->{pos} = 0;
51             }
52              
53             sub _get_pos_cache {
54 1     1   8 no strict 'refs';
  1         2  
  1         160  
55              
56 6     6   12 my $self = shift;
57              
58 6   33     30 my $class = $self->{orig_class} // ref($self);
59 5         16 return ${"$class\::_HashData_pos_cache"}
60 6 100       9 if defined ${"$class\::_HashData_pos_cache"};
  6         34  
61              
62             # build
63 1         3 my $pos_cache = [];
64 1         4 $self->reset_iterator;
65 1         4 while ($self->has_next_item) {
66 5         16 $self->get_next_item;
67 5         13 push @$pos_cache, $self->{fhpos_cur_item};
68             }
69             #use DD; dd $pos_cache;
70 1         3 ${"$class\::_HashData_pos_cache"} = $pos_cache;
  1         7  
71             }
72              
73             sub _get_hash_cache {
74 1     1   7 no strict 'refs';
  1         2  
  1         651  
75              
76 4     4   7 my $self = shift;
77              
78 4   33     21 my $class = $self->{orig_class} // ref($self);
79 3         13 return ${"$class\::_HashData_hash_cache"}
80 4 100       7 if defined ${"$class\::_HashData_hash_cache"};
  4         24  
81              
82 1         3 my $hash_cache = {};
83 1         4 $self->reset_iterator;
84 1         5 while ($self->has_next_item) {
85 5         12 my $item = $self->get_next_item;
86 5         17 $hash_cache->{$item->[0]} = $self->{fhpos_cur_item};
87             }
88             #use DD; dd $hash_cache;
89 1         4 ${"$class\::_HashData_hash_cache"} = $hash_cache;
  1         10  
90             }
91              
92             sub get_item_at_pos {
93 3     3 0 37 my ($self, $pos) = @_;
94              
95 3         7 my $pos_cache = $self->_get_pos_cache;
96 3 50       9 if ($pos < 0) {
97 0 0       0 die "Out of range" unless -$pos <= @{ $pos_cache };
  0         0  
98             } else {
99 3 100       5 die "Out of range" unless $pos < @{ $pos_cache };
  3         18  
100             }
101              
102 2         7 my $oldfhpos = tell $self->{fh};
103 2         19 seek $self->{fh}, $pos_cache->[$pos], 0;
104 2         21 chomp(my $line = readline($self->{fh}));
105 2         11 my ($key, $value) = split /:/, $line, 2;
106 2         19 seek $self->{fh}, $oldfhpos, 0;
107 2         17 [$key, $value];
108             }
109              
110             sub has_item_at_pos {
111 3     3 0 8 my ($self, $pos) = @_;
112              
113 3         8 my $pos_cache = $self->_get_pos_cache;
114 3 50       8 if ($pos < 0) {
115 0 0       0 return -$pos <= @{ $pos_cache } ? 1:0;
  0         0  
116             } else {
117 3 100       7 return $pos < @{ $pos_cache } ? 1:0;
  3         18  
118             }
119             }
120              
121             sub get_item_at_key {
122 2     2 0 38 my ($self, $key) = @_;
123              
124 2         6 my $hash_cache = $self->_get_hash_cache;
125 2 100       16 die "No such key '$key'" unless exists $hash_cache->{$key};
126              
127 1         4 my $oldfhpos = tell $self->{fh};
128 1         10 seek $self->{fh}, $hash_cache->{$key}, 0;
129 1         11 chomp(my $line = readline($self->{fh}));
130 1         7 my (undef, $value) = split /:/, $line, 2;
131 1         12 seek $self->{fh}, $oldfhpos, 0;
132 1         7 $value;
133             }
134              
135             sub has_item_at_key {
136 2     2 0 7 my ($self, $key) = @_;
137              
138 2         6 my $hash_cache = $self->_get_hash_cache;
139 2         11 exists $hash_cache->{$key};
140             }
141              
142             sub get_all_keys {
143 0     0 0   my ($self, $key) = @_;
144              
145 0           my $hash_cache = $self->_get_hash_cache;
146 0           @$hash_cache;
147             }
148              
149              
150             sub fh {
151 0     0 1   my $self = shift;
152 0           $self->{fh};
153             }
154              
155             sub fh_min_offset {
156 0     0 1   my $self = shift;
157 0           $self->{fhpos_data_begin};
158             }
159              
160 0     0 1   sub fh_max_offset { undef }
161              
162             1;
163             # ABSTRACT: Role to access hash data from DATA section, one line per item
164              
165             __END__