File Coverage

blib/lib/Directory/relative/to.pm
Criterion Covered Total %
statement 23 23 100.0
branch 8 8 100.0
condition 3 3 100.0
subroutine 6 6 100.0
pod 1 1 100.0
total 41 41 100.0


line stmt bran cond sub pod time code
1             package Directory::relative::to;
2              
3 5     5   2594 use strict;
  5         11  
  5         123  
4 5     5   20 use warnings;
  5         10  
  5         98  
5              
6 5     5   20 use lib::relative::to ();
  5         9  
  5         57  
7              
8 5     5   16 use Cwd;
  5         8  
  5         237  
9 5     5   24 use Exporter 'import';
  5         8  
  5         935  
10              
11             our @EXPORT_OK = qw(relative_dir);
12             our $VERSION = '1.1000';
13              
14             =head1 NAME
15              
16             Directory::relative::to
17              
18             =head1 DESCRIPTION
19              
20             Find paths relative to something else
21              
22             =head1 SYNOPSIS
23              
24             Both of these will look up through the parent directories of the file that
25             contains this code until it finds the root of a git repository, then return
26             the absolute paths of the 'lib' and 't/lib' directories in that repository.
27              
28             use Directory::relative::to (relative_dir);
29              
30             my @dirs = relative_dir( GitRepository => qw(lib t/lib) );
31              
32             or:
33              
34             use Directory::relative::to;
35              
36             my @dirs = Directory::relative::to->relative_dir(
37             ParentContaining => '.git/config' => qw(lib t/lib)
38             );
39              
40             Yes, it's practically identical to how you'd invoke C.
41             This module is just a very thin wrapper around that.
42              
43             =head1 WHY?
44              
45             Just like how I got fed up with Sam for the reasons explained in
46             L I have a new colleague who wrote:
47              
48             use FindBin qw($Bin);
49             ...
50             my $fixture_path = "$Bin/../../fixtures";
51              
52             That string of repeated C<../>s is an abomination unto the Lord.
53              
54             =head1 FUNCTIONS
55              
56             =head2 relative_dir
57              
58             Can be invoked either as a class method or can I be exported
59             and called as a normal function.
60              
61             This takes the several arguments, the first of which is the name of a
62             C plugin, the remainder being arguments to that plugin.
63             In general the argument list will take the form:
64              
65             =over
66              
67             =item plugin_name
68              
69             =item plugin_configuration
70              
71             =item list_of_directories
72              
73             =back
74              
75             Note that under the bonnet this function uses L's undocumented private functions.
76              
77             It normally returns a list of fully-qualified directory names,
78             but if there is only one directory to be returned and you call
79             it in scalar context you will get a scalar name.
80              
81             If there aer multiple directory names but you use scalar
82             context that is a fatal error.
83              
84             =cut
85              
86             sub relative_dir {
87 8 100   8 1 18615 shift if($_[0] eq __PACKAGE__);
88 8         61 my($plugin, @plugin_args) = @_;
89              
90             # l::r::to needs to know where *this code* is being called
91             # from instead of from where *it* is called.
92 8         315 $lib::relative::to::called_from = Cwd::abs_path((caller(0))[1]);
93 8         211 my @results = lib::relative::to->_load_plugin($plugin)
94             ->_find(@plugin_args);
95              
96             # this isn't done on function entry cos we might want to
97             # throw exceptions because the user did something silly
98 6 100       36 return if(!defined(wantarray));
99              
100 5 100 100     55 if(@results > 1 && !wantarray) {
101 1         7 die(__PACKAGE__.": Multiple results but you wanted a scalar\n");
102             }
103              
104 4 100       92 return wantarray ? @results : $results[0];
105             }
106              
107             1;
108              
109             =head1 BUGS
110              
111             I only have access to Unix machines for development and debugging. There may be
112             bugs lurking that affect users of exotic platforms like Amiga, Windows, and
113             VMS. I welcome patches, preferably in the form of a pull request. Ideally any
114             patches will be accompanied by tests, and those tests will either skip or pass
115             on Unix.
116              
117             =head1 AUTHOR, COPYRIGHT and LICENCE
118              
119             Copyright 2022 David Cantrell Edavid@cantrell.org.ukE.
120              
121             This software is free-as-in-speech as well as free-as-in-beer, and may be used,
122             distributed, and modified under the terms of either the GNU General Public
123             Licence version 2 or the Artistic Licence. It's up to you which one you use.
124             The full text of the licences can be found in the files GPL2.txt and
125             ARTISTIC.txt, respectively.
126              
127             =head1 CONSPIRACY
128              
129             This software is also free-as-in-mason.
130              
131             =cut