File Coverage

blib/lib/File/TypeCategories.pm
Criterion Covered Total %
statement 112 112 100.0
branch 53 54 98.1
condition 20 23 86.9
subroutine 13 13 100.0
pod 3 3 100.0
total 201 205 98.0


line stmt bran cond sub pod time code
1             package File::TypeCategories;
2              
3             # Created on: 2014-11-07 16:39:51
4             # Create by: Ivan Wills
5             # $Id$
6             # $Revision$, $HeadURL$, $Date$
7             # $Revision$, $Source$, $Date$
8              
9 4     4   298612 use Moo;
  4         46525  
  4         23  
10 4     4   5976 use strict;
  4         12  
  4         88  
11 4     4   23 use warnings;
  4         10  
  4         113  
12 4     4   2008 use autodie;
  4         63764  
  4         23  
13 4     4   34597 use Data::Dumper qw/Dumper/;
  4         29632  
  4         322  
14 4     4   1961 use English qw/ -no_match_vars /;
  4         14753  
  4         27  
15 4     4   3856 use Type::Tiny;
  4         75611  
  4         199  
16 4     4   2343 use Types::Standard -types;
  4         236985  
  4         44  
17 4     4   18767 use File::ShareDir qw/dist_dir/;
  4         72769  
  4         216  
18 4     4   1468 use YAML qw/LoadFile/;
  4         24259  
  4         5205  
19              
20             our $VERSION = 0.07;
21             our %warned_once;
22              
23             has ignore => (
24             is => 'rw',
25             isa => ArrayRef[Str],
26             default => sub{[qw{ ignore }]},
27             );
28             has include => (
29             is => 'rw',
30             isa => ArrayRef[Str],
31             );
32             has exclude => (
33             is => 'rw',
34             isa => ArrayRef[Str],
35             );
36             has include_type => (
37             is => 'rw',
38             isa => ArrayRef[Str],
39             default => sub{[]},
40             );
41             has exclude_type => (
42             is => 'rw',
43             isa => ArrayRef[Str],
44             default => sub{[]},
45             );
46             has symlinks => (
47             is => 'rw',
48             isa => Bool,
49             );
50             has type_suffixes => (
51             is => 'rw',
52             isa => HashRef,
53             default => sub {{}},
54             );
55              
56             sub BUILD {
57 10     10 1 339 my ($self) = @_;
58              
59 10 100       33 if (!$ENV{HOME}) {
60 1         6 $ENV{HOME} = $ENV{USERPROFILE};
61             }
62 10         17 my $dir = eval { dist_dir('File-TypeCategories'); };
  10         55  
63 10         1072 my $config_name = '.type_categories.yml';
64              
65             # import each config file the each subsiquent config overwrites the
66             # previous more general config.
67 10         33 for my $config_dir ($dir, $ENV{HOME}, '.') {
68 30 50 33     983 next if ! $config_dir || !-d $config_dir;
69 30         140 my $config_file = "$config_dir/$config_name";
70 30 100       363 next if !-f $config_file;
71              
72 21         122 my ($conf) = LoadFile($config_file);
73              
74             # import each type
75 21         1433020 for my $file_type ( keys %{ $conf } ) {
  21         302  
76 903   100     14180 $self->type_suffixes->{$file_type} ||= {
77             definite => [],
78             possible => [],
79             other_types => [],
80             none => 0,
81             bang => '',
82             };
83              
84             # add each of the settings found
85 903         5677 for my $setting ( keys %{ $conf->{$file_type} } ) {
  903         2170  
86              
87             # if a plus (+) is prepended to possible, definite or other_types
88             # we add it here other wise it's replaced
89 1084 100       2822 if ( $setting =~ s/^[+]//xms ) {
90 2         24 push @{ $self->type_suffixes->{$file_type}{$setting} }
91             , ref $conf->{$file_type}{"+$setting"} eq 'ARRAY'
92 1         10 ? @{ $conf->{$file_type}{"+$setting"} }
93 2 100       3 : $conf->{$file_type}{"+$setting"};
94             }
95             else {
96             $self->type_suffixes->{$file_type}{$setting}
97             = ref $conf->{$file_type}{$setting} eq 'ARRAY'
98             ? $conf->{$file_type}{$setting}
99 1082 100       13933 : [ $conf->{$file_type}{$setting} ];
100             }
101             }
102             }
103             }
104              
105 10         188 return;
106             }
107              
108             sub file_ok {
109 22     22 1 4318 my ($self, $file) = @_;
110              
111 22         33 for my $ignore (@{ $self->ignore }) {
  22         425  
112 22 100       158 return 0 if $self->types_match($file, $ignore);
113             }
114              
115 17 100       270 return 1 if -d $file;
116              
117 16         42 my $possible = 0;
118 16         27 my $matched = 0;
119 16         21 my $includes = 0;
120              
121 16 100       19 if ( @{ $self->include_type }) {
  16         323  
122 3         20 for my $type (@{ $self->include_type }) {
  3         33  
123 9         27 my $match = $self->types_match($file, $type);
124 9 100       20 $possible-- if $match == 2;
125 9         12 $matched += $match;
126             }
127 3         6 $includes++;
128             }
129              
130 16 100       109 if (!$matched) {
131 14         23 for my $type (@{ $self->exclude_type }) {
  14         209  
132 5         21 my $match = $self->types_match($file, $type);
133 5 100 100     25 return 0 if $match && $match != 2;
134 4 100       8 $possible++ if $match == 2;
135             }
136 13 100       100 return 0 if $possible > 0;
137             }
138              
139 14 100       215 if ($self->include) {
140 2         10 my $matches = 0;
141 2         4 for my $include (@{ $self->include }) {
  2         21  
142 2         18 $matches = $file =~ /$include/;
143 2 100       6 last if $matches;
144             }
145 2 100       10 return 0 if !$matches;
146 1         2 $includes++;
147             }
148              
149 13 100       250 if ($self->exclude) {
150 2         13 for my $exclude (@{ $self->exclude }) {
  2         30  
151 2 100       32 return 0 if $file =~ /$exclude/;
152             }
153             }
154              
155 12   66     131 return !$includes || $matched || $possible;
156             }
157              
158             sub types_match {
159 274     274 1 9017 my ($self, $file, $type) = @_;
160              
161 274         3793 my $types = $self->type_suffixes;
162              
163 274 100       1477 if ( !exists $types->{$type} ) {
164 2 100       18 warn "No type '$type'\n" if !$warned_once{$type}++;
165 2         8 return 0;
166             }
167              
168 272         299 for my $suffix ( @{ $types->{$type}{definite} } ) {
  272         549  
169 846 100       9019 return 3 if $file =~ /$suffix/;
170             }
171              
172 236         329 for my $suffix ( @{ $types->{$type}{possible} } ) {
  236         451  
173 31 100       257 return 2 if $file =~ /$suffix/;
174             }
175              
176 229 100 100     725 if ( $types->{$type}{bang} && -r $file && -f $file && -s $file ) {
      100        
      100        
177 4         27 open my $fh, '<', $file;
178 4         2517 my $line = <$fh>;
179 4         19 close $fh;
180 4         837 for my $bang ( @{ $types->{$type}{bang} } ) {
  4         16  
181 4 100       38 return 3 if $line =~ /$bang/;
182             }
183             }
184              
185 226 100 100     417 return 1 if $types->{$type}{none} && $file !~ m{ [^/] [.] [^/]+ $}xms;
186              
187 225         231 for my $other ( @{ $types->{$type}{other_types} } ) {
  225         362  
188 197         462 my $match = $self->types_match($file, $other);
189 197 100       343 return $match if $match;
190             }
191              
192 218         366 return 0;
193             }
194              
195             1;
196              
197             __END__