File Coverage

blib/lib/ful.pm
Criterion Covered Total %
statement 42 42 100.0
branch 16 16 100.0
condition 24 24 100.0
subroutine 11 11 100.0
pod 1 1 100.0
total 94 94 100.0


line stmt bran cond sub pod time code
1 7     7   575616 use strict;
  7         59  
  7         176  
2 7     7   27 use warnings;
  7         11  
  7         405  
3              
4             package ful;
5              
6             =pod
7              
8             =encoding utf-8
9              
10             =head1 NAME
11              
12             ful - a useI "Bind Bpper Bib" pragma that ascends dirs to include
13             module directories in C<@INC>.
14              
15             =head1 SYNOPSIS
16              
17             =begin HTML
18              
19            
20            
21             CPAN Module Quality
22            
23            
24             Build Status
25            
26            
27             Coverage Status
28            
29            
30              
31             =end HTML
32              
33             One line to rule them all.
34              
35             use ful;
36              
37             Brings the first C directory found by directory ascencion and adds it to
38             C<@INC>.
39              
40             Instead of:
41              
42             use lib::relative '../../lib';
43             # or
44             use FindBin;
45             use lib "$FindBin::Bin/../lib";
46             # or even
47             BEGIN {
48             use Path::Tiny;
49             my $base = path(__FILE__)->parent;
50             $base = $base->parent until -d "$base/lib" or $base->is_rootdir;
51             unshift @INC, "$base/lib";
52             }
53              
54             =head1 USAGE
55              
56             When you're working within C when your project looks like this:
57              
58             project-root/
59             ├── bin/
60             │ └── utils/
61             │ └── a-script.pl
62             ├── lib/
63             │ └── Some/
64             │ └── Module.pm
65             ├── vendor/
66             │ └── SomeOrg/
67             │ └── Some/
68             │ └── Module.pm
69              
70             Just drop the line before your other C statements:
71              
72             use ful;
73             use Some::Module;
74              
75             And that's all.
76              
77             If you need more than just the C dir, you can do this:
78              
79             use ful qw/vendor lib/;
80             use Some::Module;
81             use SomeOrg::Some::Module;
82              
83             =head1 METHODS
84              
85             =over 4
86              
87             =item * crum()
88              
89             Returns the parent directory for the latest addition to C<@INC>.
90              
91             =back
92              
93             =head1 ADVANCED
94              
95             use ful \%options;
96              
97             =head2 OPTIONS
98              
99             =over 4
100              
101             =item * C \@dirs>
102              
103             Equivalent to C but can be combined with all other
104             options.
105              
106             # multiple @INC dirs
107             use ful { libdirs => [qw/lib vendor/] };
108              
109             # combined with another option
110             use ful {
111             libdirs => [qw(lib vendor/lib)],
112             dir => 'vendor/lib',
113             };
114              
115             =item * C $file>, C $file>, C $file>
116              
117             Finds an existing file to add a sibling directory to C<@INC>.
118              
119             # adds 'lib'
120             use ful { file => '.file-in-project-root' };
121              
122             =item * C $dname>, C $dname>, C $dname>
123              
124             Finds an existing directory to add a sibling directory to C<@INC>.
125              
126             # adds 'lib'
127             use ful { dir => 'bin' };
128              
129             =item * C 1>
130              
131             Finds a git repository to add a sibling directory to C<@INC>.
132              
133             # adds 'lib'
134             use ful { git => 1 };
135              
136             =back
137              
138             =head1 LICENSE
139              
140             MIT License
141              
142             Copyright (c) 2020 Ryan Willis
143              
144             Permission is hereby granted, free of charge, to any person obtaining a copy
145             of this software and associated documentation files (the "Software"), to deal
146             in the Software without restriction, including without limitation the rights
147             to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
148             copies of the Software, and to permit persons to whom the Software is
149             furnished to do so, subject to the following conditions:
150              
151             The above copyright notice and this permission notice shall be included in all
152             copies or substantial portions of the Software.
153              
154             THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
155             IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
156             FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
157             AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
158             LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
159             OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
160             SOFTWARE.
161              
162             =head1 VERSION
163              
164             0.10
165              
166             =head1 SUPPORT
167              
168             Support is by the author. Please file bug reports or ask questions at
169             L.
170              
171             =cut
172              
173             our $VERSION = '0.10';
174              
175 7     7   33 use Cwd;
  7         8  
  7         380  
176 7     7   38 use File::Spec;
  7         10  
  7         3305  
177              
178             my $cursor;
179              
180             my $FS = 'File::Spec';
181              
182             our $crum = undef;
183              
184 2     2 1 813 sub crum { $crum }
185              
186             sub import {
187 15     15   4790 my $me = shift;
188              
189 15         42 my @user = caller();
190 15         261 my $used_me = $user[1];
191              
192 15         491 $cursor = Cwd::abs_path($used_me);
193              
194 15         34 my %args = ();
195 15         26 my @libdirs = ('lib');
196              
197 15 100 100     86 if (@_ && ref($_[0]) eq 'HASH') {
    100          
198 11         13 %args = %{$_[0]};
  11         39  
199             }
200             elsif(@_) {
201 2         5 @libdirs = @_;
202             }
203              
204 15 100       42 @libdirs = @{$args{libdirs}} if ref($args{libdirs}) eq 'ARRAY';
  2         4  
205              
206 15 100 100     106 if (my $file = $args{file} // $args{target_file} // $args{target}) {
    100 100        
    100 100        
      100        
207 4   100     9 $me->_ascend until $me->_is_file($file) or $me->_heaven;
208             }
209             elsif (my $dir = $args{dir} // $args{has_dir} // $args{child_dir}) {
210 4   100     10 $me->_ascend until $me->_is_dir($dir) or $me->_heaven;
211             }
212             elsif ($args{git}) {
213 2         5 my @gitparts = qw(.git config);
214 2   100     6 $me->_ascend until $me->_is_file(@gitparts) or $me->_heaven;
215             }
216             else {
217 5         12 while (!$me->_heaven) {
218 18 100       32 last if scalar @libdirs == grep { $me->_is_dir($_) } @libdirs;
  32         62  
219 15         40 $me->_ascend;
220             }
221             }
222              
223 15 100       49 return if $me->_heaven;
224 8         15 $crum = $me->_comb($cursor);
225 8         23 unshift @INC => $me->_comb($cursor, $_) for @libdirs;
226             }
227              
228 35     35   68 sub _is_file { -f shift->_comb($cursor, @_) }
229 49     49   79 sub _is_dir { -d shift->_comb($cursor, @_) }
230 102     102   8453 sub _comb { $FS->catfile(@_[1..$#_]) }
231              
232 57     57   721 sub _ascend { $cursor = $FS->catdir(($FS->splitpath($cursor))[0..1]) }
233 82     82   467 sub _heaven { $cursor eq $FS->rootdir }
234              
235             1;
236              
237             __END__