File Coverage

blib/lib/Catmandu/Fix/include.pm
Criterion Covered Total %
statement 62 66 93.9
branch 10 18 55.5
condition n/a
subroutine 13 13 100.0
pod 0 1 0.0
total 85 98 86.7


line stmt bran cond sub pod time code
1             package Catmandu::Fix::include;
2              
3 1     1   107269 use Catmandu::Sane;
  1         3  
  1         7  
4              
5             our $VERSION = '1.2020';
6              
7 1     1   7 use Moo;
  1         3  
  1         7  
8 1     1   903 use Catmandu;
  1         5  
  1         5  
9 1     1   237 use Catmandu::Fix;
  1         2  
  1         23  
10 1     1   6 use File::Spec;
  1         2  
  1         22  
11 1     1   5 use Cwd qw(realpath);
  1         60  
  1         54  
12 1     1   7 use namespace::clean;
  1         2  
  1         7  
13 1     1   792 use Catmandu::Fix::Has;
  1         3  
  1         5  
14              
15             with 'Catmandu::Fix::Inlineable';
16              
17             has path => (fix_arg => 1);
18             has _files => (is => 'lazy');
19             has _fixer => (is => 'lazy');
20              
21             sub _build__files {
22 4     4   66 my ($self) = @_;
23 4         14 my $path = $self->path;
24              
25 4 100       16 if ($path =~ /\*/) { # path is glob pattern
26 1         4 return $self->_find_glob($path);
27             }
28              
29 3         9 [$self->_find_file($path)];
30             }
31              
32             sub _find_file {
33 3     3   8 my ($self, $path) = @_;
34 3         23 my $roots = Catmandu->roots;
35 3         7 my $file;
36              
37 3 50       28 if (File::Spec->file_name_is_absolute($path)) {
38 0         0 $file = $path;
39             }
40             else {
41 3         8 for my $root (@$roots) {
42 3         37 my $f = File::Spec->catfile($root, $path);
43 3 50       79 if (-r $f) {
44 3         10 $file = $f;
45 3         8 last;
46             }
47             }
48              
49             }
50              
51 3 50       12 Catmandu::Error->throw(
52             "unable to find $path in " . join(',', @$roots) . ")")
53             unless defined $file;
54              
55 3         159 realpath($file);
56             }
57              
58             sub _find_glob {
59 1     1   4 my ($self, $path) = @_;
60 1         6 my $roots = Catmandu->roots;
61              
62 1 50       9 if (File::Spec->file_name_is_absolute($path)) {
63 0         0 return [sort map {realpath($_)} grep {-r $_} glob $path];
  0         0  
  0         0  
64             }
65              
66 1         3 my %seen;
67 1         3 my $files = [];
68              
69 1         3 for my $root (@$roots) {
70 1         12 my $glob = File::Spec->catfile($root, $path);
71 1         253 for my $file (glob $glob) {
72 3         202 my $rel_path = File::Spec->abs2rel($file, $root);
73 3 50       11 next if $seen{$rel_path};
74 3 50       54 if (-r $file) {
75 3         140 push @$files, realpath($file);
76 3         15 $seen{$rel_path} = 1;
77             }
78             }
79             }
80              
81 1         10 [sort @$files];
82             }
83              
84             sub _build__fixer {
85 4     4   49 my ($self) = @_;
86 4         67 my $files = $self->_files;
87 4 50       18 return unless @$files;
88 4         94 Catmandu::Fix->new(fixes => $files);
89             }
90              
91             sub fix {
92 4     4 0 52 my ($self, $data) = @_;
93 4         78 my $fixer = $self->_fixer;
94 4 50       1749 return $data unless $fixer;
95 4         21 $fixer->fix($data);
96             }
97              
98             1;
99              
100             __END__
101              
102             =pod
103              
104             =head1 NAME
105              
106             Catmandu::Fix::include - include fixes from another file
107              
108             =head1 SYNOPSIS
109              
110             include('/path/to/myfixes.txt')
111             include('fixes/*.fix')
112              
113             =head1 NOTES
114              
115             =over 4
116              
117             =item path is relative to a Catmandu load path
118              
119             #1. a catmandu load path is a directory where a catmandu configuration file can be found
120             #2. as there are multiple load paths, it will loop through all the path, and include the first file it can find
121             #3. in catmandu, the default_load_path is either
122             # 3.1. the directory of the running script
123             # 3.2. the parent directory of the running script if the directory is 'bin'
124              
125             #use default load_path
126             #called from script "/opt/catmandu-project/fix.pl"
127             #default_load_path: /opt/catmandu-project
128             #file must be located at "/opt/catmandu-project/fixes/myfixes.txt"
129             Catmandu->fixer("include('fixes/myfixes.txt')");
130              
131             #use default load_path
132             #called from script "/opt/catmandu-project/bin/fix.pl"
133             #default_load_path: /opt/catmandu-project (notice the absence of 'bin')
134             #file must be located at "/opt/catmandu-project/fixes/myfixes.txt"
135             Catmandu->fixer("include('fixes/myfixes.txt')");
136              
137             #load fixes, located at /opt/catmandu-project/fixes/myfixes.txt
138             Catmandu->load("/opt/catmandu-project");
139             Catmandu->fixer("include('fixes/myfixes.txt')");
140              
141             #look for 'fixes/myfixes.txt' in /opt/catmandu-project2, and if that fails in /opt/catmandu-project-1
142             Catmandu->load("/opt/catmandu-project2","/opt/catmandu-project-1");
143             Catmandu->fixer("include('fixes/myfixes.txt')");
144              
145             #if "/opt/catmandu-project/fixes/myfixes2.txt" does not exists, the fix will fail
146             Catmandu->load("/opt/catmandu-project");
147             Catmandu->fixer("include('fixes/myfixes2.txt)");
148              
149              
150             =item circular references are not detected
151              
152             =item if the 'include' is enclosed within an if-statement, the fixes are inserted in the control structure, but only executed if the if-statement evaluates to 'true'.
153              
154             #the fixes in the file 'add_address_fields.txt' are only executed when field 'name' has content,
155             #but, the fixes are included in the control structure.
156             if all_match('name','.+')
157             include('add_address_fields.txt')
158             end
159              
160             =back
161              
162             =head1 SEE ALSO
163              
164             L<Catmandu::Fix>
165              
166             =cut