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