1File::ShareDir::ProjectUDsiesrtDCiorn(t3r)ibuted Perl DoFciulmee:n:tSahtairoenDir::ProjectDistDir(3)
2
3
4
6 File::ShareDir::ProjectDistDir - Simple set-and-forget using of a
7 '/share' directory in your projects root
8
10 version 1.000009
11
13 STOP!. Before using this distribution, some warnings MUST be
14 considered.
15
16 The primary use-case for this module is targeted at development
17 projects that are NOT intended for "CPAN".
18
19 As such, using it for "CPAN" is generally a bad idea, and better
20 solutions generally involve the less fragile "Test::File::ShareDir",
21 constraining any magical behavior exclusively to where it is needed:
22 Tests.
23
24 Why?
25
26 • Determining whether or not we are "dev" during "runtime" is a
27 perilous heuristic that routinely fails with even slightly unusual
28 file system layouts.
29
30 • Auto-magical changing of behavior at "runtime" based on the above
31 leads to many surprising and hard to debug problems.
32
33 For these reason, it is dangerous to rely on this distribution while
34 striving to produce quality code.
35
36 If this documentation is not sufficient to dissuade you, I must
37 strongly implore you to choose the "strict" mechanism, because that
38 substantially reduces the possibilities with regards to false-positive
39 of potential "dev" directories.
40
41 I have in mind to find a better mechanism to deliver the same
42 objective, but no solutions are forthcoming at this time.
43
45 package An::Example::Package;
46
47 use File::ShareDir::ProjectDistDir;
48
49 # during development, $dir will be $projectroot/share
50 # but once installed, it will be wherever File::Sharedir thinks it is.
51 my $dir = dist_dir('An-Example')
52
53 Project layout requirements:
54
55 $project/
56 $project/lib/An/Example/Package.pm
57 $project/share/ # files for package 'An-Example' go here.
58
59 You can use a directory name other than 'share' ( Assuming you make
60 sure when you install that, you specify the different directory there
61 also ) as follows:
62
63 use File::ShareDir::ProjectDistDir ':all', defaults => {
64 projectdir => 'templates',
65 };
66
68 import
69 use File::ShareDir::ProjectDistDir (@args);
70
71 This uses "Sub::Exporter" to do the heavy lifting, so most usage of
72 this module can be maximized by understanding that first.
73
74 • ":all"
75
76 ->import( ':all' , .... )
77
78 Import both "dist_dir" and "dist_file"
79
80 • "dist_dir"
81
82 ->import('dist_dir' , .... )
83
84 Import the dist_dir method
85
86 • "dist_file"
87
88 ->import('dist_file' , .... )
89
90 Import the dist_file method
91
92 • "projectdir"
93
94 ->import( .... , projectdir => 'share' )
95
96 Specify what the project directory is as a path relative to the
97 base of your distributions source, and this directory will be used
98 as a "ShareDir" simulation path for the exported methods During
99 development.
100
101 If not specified, the default value 'share' is used.
102
103 • "filename"
104
105 ->import( .... , filename => 'some/path/to/foo.pm' );
106
107 Generally you don't want to set this, as its worked out by caller()
108 to work out the name of the file its being called from. This file's
109 path is walked up to find the 'lib' element with a sibling of the
110 name of your "projectdir".
111
112 • "distname"
113
114 ->import( .... , distname => 'somedistname' );
115
116 Specifying this argument changes the way the functions are emitted
117 at installed "runtime", so that instead of taking the standard
118 arguments File::ShareDir does, the specification of the "distname"
119 in those functions is eliminated.
120
121 i.e:
122
123 # without this flag
124 use File::ShareDir::ProjectDistDir qw( :all );
125
126 my $dir = dist_dir('example');
127 my $file = dist_file('example', 'path/to/file.pm' );
128
129 # with this flag
130 use File::ShareDir::ProjectDistDir ( qw( :all ), distname => 'example' );
131
132 my $dir = dist_dir();
133 my $file = dist_file('path/to/file.pm' );
134
135 • "strict"
136
137 ->import( ... , strict => 1 );
138
139 This parameter specifies that all "dist" "sharedirs" will occur
140 within the "projectdir" directory using the following layout:
141
142 <root>/<projectdir>/dist/<DISTNAME>/
143
144 As opposed to
145
146 <root>/<projectdir>
147
148 This means if Heuristics misfire and accidentally find another
149 distributions "share" directory, it will not pick up on it unless
150 that "share" directory also has that layout, and will instead
151 revert to the "installdir" path in @INC
152
153 This parameter may become the default option in the future
154
155 Specifying this parameter also mandates you MUST declare the
156 "DISTNAME" value in your file somewhere. Doing otherwise is
157 considered insanity anyway.
158
159 • "defaults"
160
161 ->import( ... , defaults => {
162 filename => ....,
163 projectdir => ....,
164 });
165
166 This is mostly an alternative syntax for specifying "filename" and
167 "projectdir", which is mostly used internally, and their
168 corresponding other values are packed into this one.
169
170 Sub::Exporter tricks of note.
171
172 Make your own sharedir util
173
174 package Foo::Util;
175
176 sub import {
177 my ($caller_class, $caller_file, $caller_line ) = caller();
178 if ( grep { /share/ } @_ ) {
179 require File::ShareDir::ProjectDistDir;
180 File::ShareDir::ProjectDistDir->import(
181 filename => $caller_file,
182 dist_dir => { distname => 'myproject' , -as => 'share' },
183 dist_dir => { distname => 'otherproject' , -as => 'other_share' , projectdir => 'share2' },
184 -into => $caller_class,
185 );
186 }
187 }
188
189 ....
190
191 package Foo;
192 use Foo::Util qw( share );
193
194 my $dir = share();
195 my $other_dir => other_share();
196
197 build_dist_dir
198 use File::ShareDir::ProjectDirDir ( : all );
199
200 # this calls
201 my $coderef = File::ShareDir::ProjectDistDir->build_dist_dir(
202 'dist_dir' => {},
203 { defaults => { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } }
204 );
205
206 use File::ShareDir::ProjectDirDir ( qw( :all ), distname => 'example-dist' );
207
208 # this calls
209 my $coderef = File::ShareDir::ProjectDistDir->build_dist_dir(
210 'dist_dir' => {},
211 { distname => 'example-dist', defaults => { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } }
212 );
213
214 use File::ShareDir::ProjectDirDir
215 dist_dir => { distname => 'example-dist', -as => 'mydistdir' },
216 dist_dir => { distname => 'other-dist', -as => 'otherdistdir' };
217
218 # This calls
219 my $coderef = File::ShareDir::ProjectDistDir->build_dist_dir(
220 'dist_dir',
221 { distname => 'example-dist' },
222 { defaults => { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } },
223 );
224 my $othercoderef = File::ShareDir::ProjectDistDir->build_dist_dir(
225 'dist_dir',
226 { distname => 'other-dist' },
227 { defaults => { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } },
228 );
229
230 # And leverages Sub::Exporter to create 2 subs in your package.
231
232 Generates the exported 'dist_dir' method. In development environments,
233 the generated method will return a path to the development directories
234 'share' directory. In non-development environments, this simply returns
235 "File::ShareDir::dist_dir".
236
237 As a result of this, specifying the Distribution name is not required
238 during development ( unless in "strict" mode ), however, it will start
239 to matter once it is installed. This is a potential avenues for bugs if
240 you happen to name it wrong.
241
242 In "strict" mode, the distribution name is ALWAYS REQUIRED, either at
243 least at "import" or dist_dir() time.
244
245 build_dist_file
246 use File::ShareDir::ProjectDirDir ( : all );
247
248 # this calls
249 my $coderef = File::ShareDir::ProjectDistDir->build_dist_file(
250 'dist_file' => {},
251 { defaults => { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } }
252 );
253
254 use File::ShareDir::ProjectDirDir ( qw( :all ), distname => 'example-dist' );
255
256 # this calls
257 my $coderef = File::ShareDir::ProjectDistDir->build_dist_file(
258 'dist_file' => {},
259 { distname => 'example-dist', defaults => { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } }
260 );
261
262 use File::ShareDir::ProjectDirDir
263 dist_file => { distname => 'example-dist', -as => 'mydistfile' },
264 dist_file => { distname => 'other-dist', -as => 'otherdistfile' };
265
266 # This calls
267 my $coderef = File::ShareDir::ProjectDistDir->build_dist_file(
268 'dist_file',
269 { distname => 'example-dist' },
270 { defaults => { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } },
271 );
272 my $othercoderef = File::ShareDir::ProjectDistDir->build_dist_file(
273 'dist_file',
274 { distname => 'other-dist' },
275 { defaults => { filename => 'path/to/yourcallingfile.pm', projectdir => 'share' } },
276 );
277
278 # And leverages Sub::Exporter to create 2 subs in your package.
279
280 Generates the 'dist_file' method.
281
282 In development environments, the generated method will return a path to
283 the development directories 'share' directory. In non-development
284 environments, this simply returns "File::ShareDir::dist_file".
285
286 Caveats as a result of package-name as stated in "build_dist_dir" also
287 apply to this method.
288
290 1.000000
291 Strict Mode.
292
293 Using Strict Mode
294
295 use File::ShareDir::ProjectDistDir ':all', strict => 1;
296 use File::ShareDir::ProjectDistDir 'dist_dir' => { strict => 1 };
297
298 Why you should use strict mode
299
300 Starting with 1.000000, there is a parameter "strict" that changes how
301 "sharedir" resolution performs.
302
303 Without strict:
304
305 lib/...
306 share/...
307
308 With strict
309
310 lib/...
311 share/dist/Dist-Name-Here/...
312
313 This technique greatly builds resilience to the long standing problem
314 with "develop" vs "install" heuristic ambiguity.
315
316 Here at least,
317
318 dist_dir('Dist-Name')
319
320 Will instead fall back to
321
322 @INC/auto/share/dist/Dist-Name
323
324 When
325
326 share/dist/Dist-Name
327
328 Does not exist.
329
330 This means if you have a layout like this:
331
332 <DEVROOT>/inc/<a local::lib path here>
333 <DEVROOT>/lib/<development files here>
334
335 Then when "Foo-Bar-Baz" is installed as:
336
337 <DEVROOT>/inc/lib/Foo/Bar/Baz.pm
338 <DEVROOT>/inc/lib/auto/share/dist/Foo-Bar-Baz
339
340 Then "Baz.pm" will not see the "DEVROOT" and assume "Hey, this is
341 development" and then proceed to try finding files in "DEVROOT/share"
342
343 Instead, "DEVROOT" must have "DEVROOT/share/dist/Foo-Bar-Baz" too,
344 otherwise it reverts to "DEVROOT/inc/lib/auto..."
345
346 "Path::Class" interfaces deprecated and dependency dropped.
347
348 If you have any dependence on this function, now is the time to get
349 yourself off it.
350
351 Minimum Changes to stay with "Path::Class" short term.
352
353 As the dependency has been dropped on "Path::Class", if you have "CPAN"
354 modules relying on "Path::Class" interface, you should now at a very
355 minimum start declaring
356
357 { requires => "Path::Class" }
358
359 This will keep your dist working, but will not be future proof against
360 further changes.
361
362 Staying with "Path::Class" long term.
363
364 Recommended approach if you want to stay using the "Path::Class"
365 interface:
366
367 use File::ShareDir::... etc
368 use Path::Class qw( dir file );
369
370 my $dir = dir( dist_dir('Dist-Name') );
371
372 This should future-proof you against anything File::ShareDir may do in
373 the future.
374
375 "Versioning Scheme arbitrary converted to float"
376
377 This change is a superficial one, and should have no bearing on how
378 significant you think this release is.
379
380 It is a significant release, but the primary reason for the version
381 change is simply to avoid compatibility issues in versions themselves.
382
383 However, outside that, "x.y.z" semantics are still intended to be semi-
384 meaningful, just with less "." and more 0 ☺
385
386 "dev" path determination now deferred to call time instead of "use"
387
388 This was essentially a required change to make "strict" mode plausible,
389 because strict mode _requires_ the "distname" to be known, even in the
390 development environment.
391
392 This should not have any user visible effects, but please, if you have
393 any problems, file a bug.
394
395 "file" component determination wrested from "File::ShareDir".
396
397 dist_file('foo','bar')
398
399 Is now simply sugar syntax for
400
401 path(dist_dir('foo'))->child('bar')
402
403 This should have no side effects in your code, but please file any bugs
404 you experience.
405
406 ( return value is still "undef" if the file does not exist, and still
407 "croak"'s if the file is not a file, or unreadable, but these may both
408 be subject to change )
409
410 0.5.0 - Heuristics and Return type changes
411 New "devdir" heuristic
412
413 Starting with 0.5.0, instead of using our simple "lib/../share" pattern
414 heuristic, a more advanced heuristic is used from the new
415 "Path::FindDev" and "Path::IsDev".
416
417 This relies on a more "concrete" marker somewhere at the top of your
418 development tree, and more importantly, checks for the existence of
419 specific files that are not likely to occur outside a project root.
420
421 "lib" and "share" based heuristics were a little fragile, for a few
422 reasons:
423
424 • "lib" can, and does appear all over UNIX file systems, for purposes
425 other than development project roots.
426
427 For instance, have a look in "/usr/"
428
429 /usr/bin
430 /usr/lib
431 /usr/share ## UHOH.
432
433 This would have the very bad side effect of anything installed in
434 "/usr/lib" thinking its "in development".
435
436 Fortunately, nobody seems to have hit this specific bug, which I
437 suspect is due only to "/usr/lib" being a symbolic link on most
438 x86_64 systems.
439
440 • "lib" is also reasonably common within "CPAN" package names.
441
442 For instance:
443
444 lib::abs
445
446 Which means you'll have a hierarchy like:
447
448 $PREFIX/lib/lib/abs
449
450 All you need for something to go horribly wrong would be for
451 somebody to install a "CPAN" module named:
452
453 share::mystuff
454
455 Or similar, and instantly, you have:
456
457 $PREFIX/lib/lib/
458 $PREFIX/lib/share/
459
460 Which would mean any module calling itself "lib::*" would be unable
461 to use this module.
462
463 So instead, as of 0.5.0, the heuristic revolves around certain specific
464 files being in the "dev" directory.
465
466 Which is hopefully a more fault resilient mechanism.
467
468 New Return Types
469
470 Starting with 0.5.0, the internals are now based on "Path::Tiny"
471 instead of "Path::Class", and as a result, there may be a few glitches
472 in transition.
473
474 Also, previously you could get a "Path::Class::*" object back from
475 "dist_dir" and "dist_file" by importing it as such:
476
477 use File::ShareDir::ProjectDistDir
478 qw( dist_dir dist_file ),
479 defaults => { pathclass => 1 };
480
481 Now you can also get "Path::Tiny" objects back, by passing:
482
483 use File::ShareDir::ProjectDistDir
484 qw( dist_dir dist_file ),
485 defaults => { pathtiny => 1 };
486
487 For the time being, you can still get Path::Class objects back, it is
488 deprecated since 1.000000
489
490 ( In fact, I may even make 2 specific sub-classes of "PDD" for people
491 who want objects back, as it will make the "API" and the code much
492 cleaner )
493
495 Kent Fredric <kentnl@cpan.org>
496
498 This software is copyright (c) 2017 by Kent Fredric <kentnl@cpan.org>.
499
500 This is free software; you can redistribute it and/or modify it under
501 the same terms as the Perl 5 programming language system itself.
502
503
504
505perl v5.36.0 2023-01-20 File::ShareDir::ProjectDistDir(3)