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   274937 use Moo;
  4         44561  
  4         21  
10 4     4   5764 use strict;
  4         11  
  4         76  
11 4     4   20 use warnings;
  4         8  
  4         100  
12 4     4   2002 use autodie;
  4         59526  
  4         18  
13 4     4   30355 use Data::Dumper qw/Dumper/;
  4         26891  
  4         280  
14 4     4   2291 use English qw/ -no_match_vars /;
  4         14235  
  4         26  
15 4     4   3771 use Type::Tiny;
  4         68678  
  4         175  
16 4     4   2289 use Types::Standard -types;
  4         240479  
  4         44  
17 4     4   20817 use File::ShareDir qw/dist_dir/;
  4         81725  
  4         232  
18 4     4   1775 use YAML qw/LoadFile/;
  4         27164  
  4         6005  
19              
20             our $VERSION = 0.08;
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 396 my ($self) = @_;
58              
59 10 100       41 if (!$ENV{HOME}) {
60 1         9 $ENV{HOME} = $ENV{USERPROFILE};
61             }
62 10         24 my $dir = eval { dist_dir('File-TypeCategories'); };
  10         63  
63 10         1328 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         40 for my $config_dir ($dir, $ENV{HOME}, '.') {
68 30 50 33     1334 next if ! $config_dir || !-d $config_dir;
69 30         165 my $config_file = "$config_dir/$config_name";
70 30 100       417 next if !-f $config_file;
71              
72 21         128 my ($conf) = LoadFile($config_file);
73              
74             # import each type
75 21         1922147 for my $file_type ( keys %{ $conf } ) {
  21         354  
76 903   100     19760 $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         7496 for my $setting ( keys %{ $conf->{$file_type} } ) {
  903         2761  
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       3377 if ( $setting =~ s/^[+]//xms ) {
90 2         33 push @{ $self->type_suffixes->{$file_type}{$setting} }
91             , ref $conf->{$file_type}{"+$setting"} eq 'ARRAY'
92 1         15 ? @{ $conf->{$file_type}{"+$setting"} }
93 2 100       5 : $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       18982 : [ $conf->{$file_type}{$setting} ];
100             }
101             }
102             }
103             }
104              
105 10         218 return;
106             }
107              
108             sub file_ok {
109 22     22 1 4243 my ($self, $file) = @_;
110              
111 22         41 for my $ignore (@{ $self->ignore }) {
  22         539  
112 22 100       199 return 0 if $self->types_match($file, $ignore);
113             }
114              
115 17 100       295 return 1 if -d $file;
116              
117 16         47 my $possible = 0;
118 16         31 my $matched = 0;
119 16         30 my $includes = 0;
120              
121 16 100       26 if ( @{ $self->include_type }) {
  16         400  
122 3         26 for my $type (@{ $self->include_type }) {
  3         48  
123 9         33 my $match = $self->types_match($file, $type);
124 9 100       26 $possible-- if $match == 2;
125 9         19 $matched += $match;
126             }
127 3         7 $includes++;
128             }
129              
130 16 100       147 if (!$matched) {
131 14         24 for my $type (@{ $self->exclude_type }) {
  14         302  
132 5         25 my $match = $self->types_match($file, $type);
133 5 100 100     31 return 0 if $match && $match != 2;
134 4 100       11 $possible++ if $match == 2;
135             }
136 13 100       107 return 0 if $possible > 0;
137             }
138              
139 14 100       252 if ($self->include) {
140 2         15 my $matches = 0;
141 2         3 for my $include (@{ $self->include }) {
  2         32  
142 2         23 $matches = $file =~ /$include/;
143 2 100       8 last if $matches;
144             }
145 2 100       12 return 0 if !$matches;
146 1         3 $includes++;
147             }
148              
149 13 100       285 if ($self->exclude) {
150 2         16 for my $exclude (@{ $self->exclude }) {
  2         29  
151 2 100       32 return 0 if $file =~ /$exclude/;
152             }
153             }
154              
155 12   66     157 return !$includes || $matched || $possible;
156             }
157              
158             sub types_match {
159 274     274 1 10465 my ($self, $file, $type) = @_;
160              
161 274         4940 my $types = $self->type_suffixes;
162              
163 274 100       1740 if ( !exists $types->{$type} ) {
164 2 100       23 warn "No type '$type'\n" if !$warned_once{$type}++;
165 2         11 return 0;
166             }
167              
168 272         381 for my $suffix ( @{ $types->{$type}{definite} } ) {
  272         749  
169 846 100       11308 return 3 if $file =~ /$suffix/;
170             }
171              
172 236         459 for my $suffix ( @{ $types->{$type}{possible} } ) {
  236         617  
173 31 100       328 return 2 if $file =~ /$suffix/;
174             }
175              
176 229 100 100     933 if ( $types->{$type}{bang} && -r $file && -f $file && -s $file ) {
      100        
      100        
177 4         32 open my $fh, '<', $file;
178 4         3274 my $line = <$fh>;
179 4         22 close $fh;
180 4         1114 for my $bang ( @{ $types->{$type}{bang} } ) {
  4         23  
181 4 100       51 return 3 if $line =~ /$bang/;
182             }
183             }
184              
185 226 100 100     582 return 1 if $types->{$type}{none} && $file !~ m{ [^/] [.] [^/]+ $}xms;
186              
187 225         300 for my $other ( @{ $types->{$type}{other_types} } ) {
  225         487  
188 197         450 my $match = $self->types_match($file, $other);
189 197 100       446 return $match if $match;
190             }
191              
192 218         510 return 0;
193             }
194              
195             1;
196              
197             __END__