1Path::ScanINC(3) User Contributed Perl Documentation Path::ScanINC(3)
2
3
4
6 Path::ScanINC - Emulate Perls internal handling of @INC.
7
9 version 1.000003
10
12 The Aim of this module is to fully implement everything Perl does with
13 @INC, to be feature compatible with it, including the behavior with
14 regard to "sub refs" in @INC.
15
16 use Path::ScanINC;
17
18 # Normal usage.
19 my $inc = Path::ScanINC->new( );
20
21 # In case you need something that isn't @INC
22 # but works like it
23
24 my $inc = Path::ScanINC->new( inc => \@INC );
25
26 # Freeze the value of @INC at the time of object instantiation
27 # with regard to behaviour so later changes to @INC have no effect
28
29 my $inc = Path::ScanINC->new( immutable => 1 );
30
31 # Return the first file in @INC that matches.
32
33 my $file = $inc->first_file('Path', 'ScanINC.pm' );
34
35 # Find all possible versions of modules in @INC
36 my ( @files ) = $inc->all_files('Path', 'ScanINC.pm');
37
38 # Try to discover a File::ShareDir 'module' root.
39 my $dir = $inc->first_dir('auto','share','module');
40
41 # Should return the same as File::ShareDir::module_dir('Path::ScanINC')
42 # ( assuming such a directory existed, which there is presently no plans of )
43 my $dir = $inc->first_dir('auto','share','module','Path-ScanINC');
44
45
46 # Find All File::ShareDir roots in @INC
47 my ( @dirs ) = $inc->all_dirs('auto', 'share');
48
50 "Path::ScanINC" is a basic tool for traversing @INC in a "perl"-like
51 manner, stepping over some common pitfalls with using it. It also has
52 the property of being able to capture @INC states to emulate a portable
53 isolated library resolver.
54
56 This module has elemental support for discovery of results in @INC
57 using "CODE"/"ARRAY"/"BLESSED" entries in @INC. However, due to a
58 limitation as to how "perl" itself implements this functionality, the
59 best we can do at present is simply return what the above are expected
60 to return. This means if you have any of the above ref-types in @INC,
61 and one of those returns "a true value", you'll get handed back an
62 "ARRAY" reference instead of the file you were expecting.
63
64 Fortunately, @INC barely ever has refs in it. But in the event you need
65 to work with refs in @INC and you expect that those refs will return
66 "true", you have to pick one of two options, either :
67
68 a. Write your code to work with the "array-ref" returned by the
69 respective reference on a match
70 b. Use the "all_" family of methods and try pretending that there are
71 no "array-refs" in the list it returns.
72
73 Its possible in a future release we may have better choices how to
74 handle this situation in future, but don't bet on it.
75
76 Given that the API as defined by Perl mandates "code-ref"'s return
77 lists containing "file-handles" or iterative "code-ref"'s , not actual
78 files, the best I can foresee at this time we'd be able to do to make
79 life easier for you is creating a fake library somewhere in a "tempdir"
80 and stuffing the result of the "code-ref"'s into files in that
81 directory prior to returning a path to the generated file.
82
83 ( And it also tells me that they have to be "Real" file handles, not
84 tied or blessed ones, so being able to ask a "filehandle" what file it
85 represents is equally slim.... if that is of course what you require )
86
87 For more details, see "perldoc perlfunc" or "perldoc -f require" .
88
90 new
91 my $object = $class->new(
92 inc => [ 'x', 'y', 'z' , ],
93 immutable => 1 | undef
94 );
95
96 immutable
97 if( $inc->immutable ) {
98 print "We're working with a snapshotted version of @INC";
99 }
100
101 inc
102 for my $i ( $inc->inc ) {
103 say "Plain: $incer" if not ref $incer;
104 say "Callback: $incer" if ref $incer;
105 }
106
107 Returns a copy of the internal version of @INC it will be using.
108
109 If the object is "immutable", then this method will continue to report
110 the same value as c<@INC>, or will be updated every time the original
111 array reference passed during construction gets updated:
112
113 my $ref = [];
114 my $a = Path::ScanINC->new( inc => $ref );
115 my $b = Path::ScanINC->new( inc => $ref, immutable => 1 );
116
117 push @{$ref} , 'a';
118
119 is( [ $a->inc ]->[0] , 'a' , "non-immutable references keep tracking their original" );
120 isnt( [ $b->inc ]->[0] , 'a' , "immutable references are shallow-copied at construction" );
121
122 Do note of course that is a SHALLOW copy, so if you have multiple @INC
123 copies sharing the same "array"/"bless" references, changes to those
124 references will be shared amongst all @INC's .
125
126 first_file
127 if( defined ( my $file = $inc->first_file('Moose.pm') ) {
128 print "Yep, Moose seems to be available in \@INC , its at $file, but its not loaded (yet)\n";
129 }
130
131 This proves to be a handy little gem that replaces the oft used
132
133 if( try { require Moose ; 1 } ){
134 Yadayadayada
135 }
136
137 And adds the benefit of not needing to actually source the file to see
138 if it exists or not.
139
140 IMPORTANT: PORTABILITIY
141
142 For best system portability, where possible, its suggested you specify
143 paths as arrays of strings, not slash-separated strings.
144
145 $inc->first_file('MooseX' , 'Declare.pm') # Good
146 $inc->first_file('MooseX/Declare.pm') # Bad.
147
148 This is for several reasons, all of which can be summarized as
149 "Windows".
150
151 · %INC keys all use Unix notation.
152
153 · @INC callbacks expect Unix notation.
154
155 · "\" is a valid path part on Unix.
156
157 · On Win32, we have to use "\" Separation, not "/" for resolving
158 physical files.
159
160 The sum of these means if you do this:
161
162 $inc->first_file('MooseX/Declare.pm')
163
164 On win32, it might just end up doing:
165
166 C:\some\path\here/MooseX/Declare.pm
167
168 Which may or may not work.
169
170 And additionally, if the above module is loaded, it will be loaded as
171
172 "MooseX/Declare.pm"
173
174 in %INC, not what you'd expect, "MooseX\Declare.pm"
175
176 all_files
177 Returns all matches in all @INC paths.
178
179 my $inc = Path::ScanINC->new();
180 push @INC, 'lib';
181 my ( @files ) = $inc->all_files('Something','Im','Working','On.pm');
182 pp(\@files );
183
184 # [
185 # '/something/........./lib/Something/Im/Working/On.pm',
186 # '/something/....../share/per5/lib/site_perl/5.15.9/Something/Im/Working/On.pm',
187 # ]
188
189 Chances are if you understand how this can be useful, you'll do so
190 immediately.
191
192 Useful for debugging what module is being loaded, and possibly
193 introspecting information about multiple parallel installs of modules
194 in %ENV, such as frequently the case with 'dual-life' modules.
195
196 perl -MPath::ScanINC -E 'my $scanner = Path::ScanINC->new(); say for $scanner->all_files(qw( Scalar Util.pm ))'
197 /usr/lib64/perl5/vendor_perl/5.12.4/x86_64-linux/Scalar/Util.pm
198 /usr/lib64/perl5/5.12.4/x86_64-linux/Scalar/Util.pm
199
200 Sort-of like ye' olde' "perldoc -l", but more like "man -a"
201
202 I might even be tempted to make a sub-module to make one-liners easier
203 like
204
205 perl -MPath::ScanINC::All=Scalar/Util.pm
206
207 REMINDER: If there are "REFS" in @INC that match, they'll return
208 "array-ref"'s, not strings.
209
210 first_dir
211 Just like "first_file" except for locating directories.
212
213 all_dirs
214 Just like "all_dirs" except for locating directories.
215
217 Kent Fredric <kentnl@cpan.org>
218
220 This software is copyright (c) 2017 by Kent Fredric <kentnl@cpan.org>.
221
222 This is free software; you can redistribute it and/or modify it under
223 the same terms as the Perl 5 programming language system itself.
224
225
226
227perl v5.30.0 2019-07-26 Path::ScanINC(3)