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   80192 use Moo;
  4         47426  
  4         24  
10 4     4   5163 use strict;
  4         8  
  4         85  
11 4     4   17 use warnings;
  4         11  
  4         114  
12 4     4   2193 use autodie;
  4         57286  
  4         17  
13 4     4   21707 use Data::Dumper qw/Dumper/;
  4         32061  
  4         274  
14 4     4   2111 use English qw/ -no_match_vars /;
  4         12918  
  4         38  
15 4     4   4135 use Type::Tiny;
  4         59679  
  4         151  
16 4     4   2564 use Types::Standard -types;
  4         180520  
  4         63  
17 4     4   18107 use File::ShareDir qw/dist_dir/;
  4         24875  
  4         330  
18 4     4   2114 use YAML qw/LoadFile/;
  4         24540  
  4         5293  
19              
20             our $VERSION = 0.06;
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 313 my ($self) = @_;
58              
59 10 100       47 if (!$ENV{HOME}) {
60 1         60 $ENV{HOME} = $ENV{USERPROFILE};
61             }
62 10         16 my $dir = eval { dist_dir('File-TypeCategories'); };
  10         64  
63 10         1119 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         28 for my $config_dir ($dir, $ENV{HOME}, '.') {
68 30 50 33     1165 next if ! $config_dir || !-d $config_dir;
69 30         95 my $config_file = "$config_dir/$config_name";
70 30 100       400 next if !-f $config_file;
71              
72 21         114 my ($conf) = LoadFile($config_file);
73              
74             # import each type
75 21         1273614 for my $file_type ( keys %{ $conf } ) {
  21         325  
76 903   100     17457 $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         8294 for my $setting ( keys %{ $conf->{$file_type} } ) {
  903         2367  
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       2329 if ( $setting =~ s/^[+]//xms ) {
90 2         34 push @{ $self->type_suffixes->{$file_type}{$setting} }
91             , ref $conf->{$file_type}{"+$setting"} eq 'ARRAY'
92 1         12 ? @{ $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       18319 : [ $conf->{$file_type}{$setting} ];
100             }
101             }
102             }
103             }
104              
105 10         216 return;
106             }
107              
108             sub file_ok {
109 22     22 1 5462 my ($self, $file) = @_;
110              
111 22         40 for my $ignore (@{ $self->ignore }) {
  22         457  
112 22 100       1584 return 0 if $self->types_match($file, $ignore);
113             }
114              
115 17 100       329 return 1 if -d $file;
116              
117 16         26 my $possible = 0;
118 16         18 my $matched = 0;
119 16         19 my $includes = 0;
120              
121 16 100       17 if ( @{ $self->include_type }) {
  16         308  
122 3         32 for my $type (@{ $self->include_type }) {
  3         46  
123 9         22 my $match = $self->types_match($file, $type);
124 9 100       19 $possible-- if $match == 2;
125 9         15 $matched += $match;
126             }
127 3         5 $includes++;
128             }
129              
130 16 100       1384 if (!$matched) {
131 14         18 for my $type (@{ $self->exclude_type }) {
  14         199  
132 5         20 my $match = $self->types_match($file, $type);
133 5 100 100     30 return 0 if $match && $match != 2;
134 4 100       9 $possible++ if $match == 2;
135             }
136 13 100       1216 return 0 if $possible > 0;
137             }
138              
139 14 100       206 if ($self->include) {
140 2         11 my $matches = 0;
141 2         3 for my $include (@{ $self->include }) {
  2         31  
142 2         38 $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       1283 if ($self->exclude) {
150 2         15 for my $exclude (@{ $self->exclude }) {
  2         30  
151 2 100       26 return 0 if $file =~ /$exclude/;
152             }
153             }
154              
155 12   66     1217 return !$includes || $matched || $possible;
156             }
157              
158             sub types_match {
159 274     274 1 8281 my ($self, $file, $type) = @_;
160              
161 274         4796 my $types = $self->type_suffixes;
162              
163 274 100       1392 if ( !exists $types->{$type} ) {
164 2 100       35 warn "No type '$type'\n" if !$warned_once{$type}++;
165 2         10 return 0;
166             }
167              
168 272         220 for my $suffix ( @{ $types->{$type}{definite} } ) {
  272         615  
169 846 100       8831 return 3 if $file =~ /$suffix/;
170             }
171              
172 236         239 for my $suffix ( @{ $types->{$type}{possible} } ) {
  236         490  
173 31 100       266 return 2 if $file =~ /$suffix/;
174             }
175              
176 229 100 100     766 if ( $types->{$type}{bang} && -r $file && -f $file && -s $file ) {
      100        
      100        
177 4         45 open my $fh, '<', $file;
178 4         3174 my $line = <$fh>;
179 4         17 close $fh;
180 4         932 for my $bang ( @{ $types->{$type}{bang} } ) {
  4         18  
181 4 100       55 return 3 if $line =~ /$bang/;
182             }
183             }
184              
185 226 100 100     481 return 1 if $types->{$type}{none} && $file !~ m{ [^/] [.] [^/]+ $}xms;
186              
187 225         190 for my $other ( @{ $types->{$type}{other_types} } ) {
  225         368  
188 197         334 my $match = $self->types_match($file, $other);
189 197 100       370 return $match if $match;
190             }
191              
192 218         328 return 0;
193             }
194              
195             1;
196              
197             __END__