Skip to content

Add Matches(pattern) for pattern matching without touching the file system - #162

Merged
dennisdoomen merged 2 commits into
mainfrom
dennisdoomen-issue-142-matches-pattern
Aug 10, 2026
Merged

Add Matches(pattern) for pattern matching without touching the file system#162
dennisdoomen merged 2 commits into
mainfrom
dennisdoomen-issue-142-matches-pattern

Conversation

@dennisdoomen

Copy link
Copy Markdown
Owner

Fixes #142

Summary

Adds Matches(this ChainablePath path, string globPattern) and Matches(this ChainablePath path, params string[] globPatterns) to Pathy.Globbing (ChainablePathGlobbingExtensions), next to the existing GlobFiles. This lets you test a path against one or more glob patterns without any file-system access — the path does not need to exist, and no directory is enumerated.

changedFile.Matches("**/*.cs");                 // true for src/Pathy/ChainablePath.cs
changedFile.Matches("**/bin/**", "**/obj/**");  // filter out build output
var relevant = changedFiles.Where(x => x.Matches("src/**/*.cs")).ToArray();

Note on base branch

CONTRIBUTING.md says PRs should target develop, but that branch does not currently exist in this repository, and all recent merged PRs target main. I opened this against main to match actual practice — happy to retarget if a develop branch gets created.

No file-system access — how I verified it

I read the Microsoft.Extensions.FileSystemGlobbing source (Matcher, MatcherExtensions, InMemoryDirectoryInfo) rather than assuming behavior:

  • MatcherExtensions.Match(this Matcher, string root, string file) executes the matcher against an InMemoryDirectoryInfo, which only does pure string operations (Path.GetFullPath, Path.IsPathRooted, etc.) on the given file path — it never enumerates a real directory or hits disk, even for a rooted/absolute path.
  • The convenience single-arg Match(string file) overload just forwards to the two-arg one using Directory.GetCurrentDirectory() as root — but that only works correctly when file is actually under the current working directory (MatcherContext walks from the root down, so a file outside the root is silently never matched). Since ChainablePath values are typically absolute and unrelated to CWD, I did not use that overload directly.
  • Instead, Matches computes the root itself: for a rooted path it uses Path.GetPathRoot(file) (the drive/volume root, e.g. C:\), guaranteeing the file is always "under" the root so patterns like src/**/*.cs match anywhere on that drive. For a relative path it falls back to Directory.GetCurrentDirectory(), matching GlobFiles's existing behavior. Path.GetPathRoot/Path.IsPathRooted are pure string operations, so this remains fully I/O-free.
  • Verified empirically with unit tests, including one that points at a path that doesn't exist on disk at all (Matches_does_not_require_the_path_to_exist_on_disk).

Case sensitivity

Uses the same new Matcher(StringComparison.OrdinalIgnoreCase) construction as GlobFiles, for consistency. Covered by a Matches_is_case_insensitive test.

Relationship to closed issue #35

#35 requested a Match(wildcard) method and was closed without a public API being approved/shipped. This PR delivers that capability, but:

  • named Matches (plural-safe) instead of Match, with a companion params string[] overload that returns true if any pattern matches
  • lives in Pathy.Globbing (not core Pathy), since it depends on Microsoft.Extensions.FileSystemGlobbing, same as GlobFiles

This is called out in the XML doc comments on both new members.

Changes

  • Pathy.Globbing/PathyGlobbing.cs: new Matches overloads, same argument validation as GlobFiles (throws ArgumentException for missing/null/empty patterns)
  • Pathy.Specs/ChainablePathSpecs.cs: new specs — suffix match, unrelated pattern no-match, non-existent path, multi-pattern any-match / no-match, case-insensitivity, argument validation
  • Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.*.verified.txt: updated approved public API surface via AcceptApiChanges.ps1
  • README.md: documented Matches under the Globbing section

Testing

  • dotnet test Pathy.Specs — 119/119 passing
  • dotnet test Pathy.ApiVerificationTests — 8/8 passing
  • dotnet build (full solution) — 0 warnings, 0 errors

Note on process

This issue is labeled enhancement only (no api-approved label), and CONTRIBUTING.md normally requires that label before opening a PR for an API change. The repo owner explicitly asked for this PR to be opened directly, so I'm proceeding, but flagging it here for visibility: this implements an as-yet-unapproved API proposal.

Dennis Doomen and others added 2 commits November 26, 2025 15:21
Adds ChainablePathGlobbingExtensions.Matches(string) and
Matches(params string[]) to Pathy.Globbing, letting a ChainablePath be
tested against one or more glob patterns without touching the file
system (the path does not need to exist).

Implementation uses Matcher.Match(root, file), which performs a pure
in-memory string match via InMemoryDirectoryInfo and never enumerates
or reads from disk. Rooted paths are matched relative to their
drive/volume root so patterns like `src/**/*.cs` match regardless of
where on that drive the path lives; relative paths fall back to the
current working directory, consistent with GlobFiles. Matching uses
the same StringComparison.OrdinalIgnoreCase as GlobFiles.

This delivers the capability requested (but not shipped as public API)
in the closed issue #35, using the plural-safe name Matches with a
multi-pattern overload that returns true if any pattern matches.

Fixes #142

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

Test Results

127 tests  +10   127 ✅ +10   1s ⏱️ ±0s
  3 suites ± 0     0 💤 ± 0 
  3 files   ± 0     0 ❌ ± 0 

Results for commit 835b479. ± Comparison against base commit adc85ae.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[API Proposal]: Matches(pattern) for pattern matching without touching the file system

1 participant