File Coverage

blib/lib/Catmandu/DirectoryIndex/UUID.pm
Criterion Covered Total %
statement 86 86 100.0
branch 18 26 69.2
condition 5 12 41.6
subroutine 20 20 100.0
pod 0 6 0.0
total 129 150 86.0


line stmt bran cond sub pod time code
1             package Catmandu::DirectoryIndex::UUID;
2              
3             our $VERSION = '1.16';
4              
5 9     9   107447 use Catmandu::Sane;
  9         187960  
  9         101  
6 9     9   2009 use Catmandu::Util qw(:is :check);
  9         91  
  9         3379  
7 9     9   69 use Moo;
  9         22  
  9         54  
8 9     9   5734 use Cwd;
  9         21  
  9         606  
9 9     9   96 use Path::Tiny;
  9         18  
  9         481  
10 9     9   5677 use Path::Iterator::Rule;
  9         82907  
  9         355  
11 9     9   73 use File::Spec;
  9         32  
  9         258  
12 9     9   53 use Catmandu::BadArg;
  9         18  
  9         299  
13 9     9   50 use Catmandu::Error;
  9         19  
  9         308  
14 9     9   53 use Data::Dumper;
  9         18  
  9         562  
15 9     9   51 use namespace::clean;
  9         22  
  9         75  
16              
17             with "Catmandu::DirectoryIndex";
18              
19             sub is_uuid {
20 14     14 0 28 my $id = $_[0];
21 14 50       171 is_string($id)
22             && $id
23             =~ /^[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}$/o;
24             }
25              
26             sub _to_path {
27 9     9   22 my ($self, $id) = @_;
28              
29 9 100       22 Catmandu::BadArg->throw("need valid uuid") unless is_uuid($id);
30              
31 8         134 File::Spec->catdir($self->base_dir, unpack("(A3)*", $id));
32             }
33              
34             sub _from_path {
35 5     5   26 my ($self, $path) = @_;
36              
37 5         64 my @split_path = File::Spec->splitdir($path);
38 5         45 my $id = join("",
39             splice(@split_path, scalar(File::Spec->splitdir($self->base_dir))));
40              
41 5         18 $id = uc($id);
42              
43 5 100       14 Catmandu::BadArg->throw("invalid uuid detected: $id") unless is_uuid($id);
44              
45 4         14 $id;
46             }
47              
48             sub get {
49 3     3 0 334 my ($self, $id) = @_;
50              
51 3         8 my $f_id = uc($id);
52 3         11 my $path = $self->_to_path($f_id);
53              
54 3 50 33     105 is_string($path) && -d $path ? {_id => $f_id, _path => $path} : undef;
55              
56             }
57              
58             sub add {
59 5     5 0 16814 my ($self, $id) = @_;
60              
61 5         14 my $f_id = uc($id);
62 5         17 my $path = $self->_to_path($f_id);
63              
64 4 100       99 unless (-d $path) {
65              
66 3         10 my $err;
67 3         16 path($path)->mkpath({error => \$err});
68              
69 3 50 50     3333 Catmandu::Error->throw(
70             "unable to create directory $path: " . Dumper($err))
71             if defined($err) && scalar(@$err);
72              
73             }
74              
75 4         34 {_id => $f_id, _path => $path};
76              
77             }
78              
79             sub delete {
80 1     1 0 986 my ($self, $id) = @_;
81              
82 1         4 my $f_id = uc($id);
83 1         4 my $path = $self->_to_path($f_id);
84              
85 1 50 33     27 if (is_string($path) && -d $path) {
86              
87 1         4 my $err;
88 1         4 path($path)->remove_tree({error => \$err});
89              
90 1 50 50     436 Catmandu::Error->throw(
91             "unable to remove directory $path: " . Dumper($err))
92             if defined($err) && scalar(@$err);
93              
94             }
95              
96 1         6 1;
97             }
98              
99             sub delete_all {
100 1     1 0 355 my $self = $_[0];
101              
102 1 50       21 if (-d $self->base_dir) {
103              
104 1         4 my $err;
105 1         6 path($self->base_dir)->remove_tree({keep_root => 1, error => \$err});
106              
107 1 50 50     3744 Catmandu::Error->throw("unable to remove entries from base directory "
108             . $self->base_dir . ": "
109             . Dumper($err))
110             if defined($err) && scalar(@$err);
111              
112             }
113              
114 1         6 1;
115             }
116              
117             sub generator {
118 5     5 0 445 my $self = $_[0];
119              
120             return sub {
121              
122 9     9   31 state $rule;
123 9         16 state $iter;
124 9         30 state $base_dir = $self->base_dir();
125              
126 9 100       25 unless ($iter) {
127              
128 5         34 $rule = Path::Iterator::Rule->new();
129 5         56 $rule->min_depth(12);
130 5         188 $rule->max_depth(12);
131 5         152 $rule->directory();
132 5         124 $iter = $rule->iter($base_dir, {depthfirst => 1});
133              
134             }
135              
136 9         523 my $path = $iter->();
137              
138 9 100       18820 return unless defined $path;
139              
140             #Path::Iterator::Rule hardcodes forward slashes
141 5 50       23 $path =~ s/\//\\/go if $^O eq "MSWin32";
142              
143             #TODO: does not throw an error when directory is less than 12 levels (because no directories are validated)
144 5         19 my $id = $self->_from_path($path);
145              
146 4         21 +{_id => $id, _path => $path};
147 5         31 };
148             }
149              
150             1;
151              
152             __END__
153              
154             =pod
155              
156             =head1 NAME
157              
158             Catmandu::DirectoryIndex::UUID - A uuid based path translator
159              
160             =head1 SYNOPSIS
161              
162             use Catmandu::DirectoryIndex::UUID;
163              
164             my $p = Catmandu::DirectoryIndex::UUID->new(
165             base_dir => "/data"
166             );
167              
168             # Returns mapping like { _id => "9A581C80-1189-11E8-AB6D-46BC153F89DB", "/data/9A5/81C/80-/118/9-1/1E8/-AB/6D-/46B/C15/3F8/9DB" }
169             # Can be undef
170             my $mapping = $p->get("9A581C80-1189-11E8-AB6D-46BC153F89DB");
171              
172             # Create path and return mapping
173             my $mapping = $p->add("9A581C80-1189-11E8-AB6D-46BC153F89DB");
174              
175             # Catmandu::DirectoryIndex::Number is a Catmandu::Iterable
176             # Returns list of records: [{ _id => 1234, _path => "/data/000/001/234" }]
177             my $mappings = $p->to_array();
178              
179             =head1 METHODS
180              
181             =head2 new( base_dir => $base_dir )
182              
183             Create a new Catmandu::DirectoryIndex::UUID with the following configuration
184             parameters:
185              
186             =over
187              
188             =item base_dir
189              
190             See L<Catmandu::DirectoryIndex>
191              
192             =back
193              
194             =head1 LIMITATIONS
195              
196             The keys in this directory can only be UUID identifiers.
197              
198             =head1 INHERITED METHODS
199              
200             This Catmandu::DirectoryIndex::Number implements:
201              
202             =over 3
203              
204             =item L<Catmandu::DirectoryIndex>
205              
206             =back
207              
208             =head1 SEE ALSO
209              
210             L<Catmandu::DirectoryIndex>
211              
212             =cut