NAME
Developer::Dashboard::PathIdentity - shared canonical path identity helper
SYNOPSIS
use Developer::Dashboard::PathIdentity qw(
_path_identity _same_or_descendant_path current_working_directory
);
my $id = _path_identity( $path, empty_fallback => 1 );
my $is_descendant = _same_or_descendant_path( $path, $root, empty_fallback => 1 );
my $cwd = current_working_directory();
DESCRIPTION
Provides _path_identity and _same_or_descendant_path, the single home for a path-normalization pair that used to be written out twice, once in Developer::Dashboard::PathRegistry (as instance methods) and once in Developer::Dashboard::EnvLoader (as class methods) (DD-903) - the same "small helper reimplemented per file instead of shared" pattern this project already fixed in Developer::Dashboard::DirEntries (DD-762), Developer::Dashboard::TextUtils (DD-891), Developer::Dashboard::TimeUtils (DD-894), and Developer::Dashboard::IsoTimestamp (DD-904).
PURPOSE
Give every module that needs to compare filesystem paths for identity or ancestry one canonical implementation to call, in either of the two edge-case behaviors this project's two former copies actually used, rather than each maintaining its own private copy that can silently drift.
WHY IT EXISTS
PathRegistry.pm's _path_identity and EnvLoader.pm's _path_identity were nearly byte-identical, differing only in invocation style ($self vs $class) - except for one genuine behavioral divergence: when Cwd::abs_path() returns an empty string (as opposed to undef) for a path, PathRegistry.pm's version falls back to File::Spec->canonpath($path), while EnvLoader.pm's version returns the empty string as-is. Both versions already agreed on the undef case (both fall back to canonpath).
Rather than silently pick one behavior and risk changing the other file's real (if rare) semantics, this module takes an explicit empty_fallback => 1|0 parameter with no default, mirroring this project's TimeUtils.pm tz and IsoTimestamp.pm on_error precedent: empty_fallback => 1 reproduces PathRegistry.pm's historical behavior, empty_fallback => 0 reproduces EnvLoader.pm's.
WHEN TO USE
Whenever code needs to compare two filesystem paths for identity or ancestry across possible symlink aliases (e.g. /var vs /private/var on macOS), rather than comparing raw path strings.
HOW TO USE
use Developer::Dashboard::PathIdentity qw(_path_identity _same_or_descendant_path);
my $id = _path_identity( $path, empty_fallback => 1 );
if ( _same_or_descendant_path( $candidate, $root, empty_fallback => 1 ) ) {
...
}
Both functions require empty_fallback to be passed explicitly; there is no default, so a caller cannot silently inherit the wrong edge-case behavior for its own historical call sites.
The internal _same_or_descendant_identity helper compares already-resolved identities. It is used when one candidate must be checked against several runtime roots, so the candidate can be canonicalized once while each root still receives its own filesystem-aware resolution. Component-boundary matching uses the active File::Spec root separator and case-sensitivity policy for the root's volume. This is required on Windows, where canonical paths use backslashes and ordinary volumes are case-tolerant; the relevant drive is queried rather than assuming C:, and drive roots are handled without adding a duplicate separator.
WHAT USES IT
Developer::Dashboard::PathRegistry (via empty_fallback => 1) and Developer::Dashboard::EnvLoader (via empty_fallback => 0). The current-directory helper is used by the switchboard and path and prompt helpers. It calls native Cwd::getcwd on each lookup. An exact PWD match returns that physical result immediately; a distinct absolute PWD is accepted only when device/inode identity matches the process directory, preserving logical symlinks. Invalid values use the physical path, and Cwd::cwd is the fallback when getcwd cannot resolve the directory.
EXAMPLES
_path_identity( '/var/tmp', empty_fallback => 1 );
# => '/private/var/tmp' on macOS (a real existing path resolves via abs_path)
_same_or_descendant_path( '/home/me/project/sub', '/home/me/project', empty_fallback => 0 );
# => 1 (true)
current_working_directory();
# => matching physical $ENV{PWD}, validated logical symlink path, or physical cwd