diff --git a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net47.verified.txt b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net47.verified.txt
index e785eeb..59d6d04 100644
--- a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net47.verified.txt
+++ b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net47.verified.txt
@@ -4,5 +4,6 @@ namespace Pathy
public static class ChainablePathExtensions
{
public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, string globPattern) { }
+ public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, params string[] globPatterns) { }
}
}
\ No newline at end of file
diff --git a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net8.0.verified.txt b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net8.0.verified.txt
index e785eeb..59d6d04 100644
--- a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net8.0.verified.txt
+++ b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.net8.0.verified.txt
@@ -4,5 +4,6 @@ namespace Pathy
public static class ChainablePathExtensions
{
public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, string globPattern) { }
+ public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, params string[] globPatterns) { }
}
}
\ No newline at end of file
diff --git a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.0.verified.txt b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.0.verified.txt
index e785eeb..59d6d04 100644
--- a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.0.verified.txt
+++ b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.0.verified.txt
@@ -4,5 +4,6 @@ namespace Pathy
public static class ChainablePathExtensions
{
public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, string globPattern) { }
+ public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, params string[] globPatterns) { }
}
}
\ No newline at end of file
diff --git a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.1.verified.txt b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.1.verified.txt
index e785eeb..59d6d04 100644
--- a/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.1.verified.txt
+++ b/Pathy.ApiVerificationTests/ApprovedApi/pathy.globbing.netstandard2.1.verified.txt
@@ -4,5 +4,6 @@ namespace Pathy
public static class ChainablePathExtensions
{
public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, string globPattern) { }
+ public static Pathy.ChainablePath[] GlobFiles(this Pathy.ChainablePath path, params string[] globPatterns) { }
}
}
\ No newline at end of file
diff --git a/Pathy.Globbing/PathyGlobbing.cs b/Pathy.Globbing/PathyGlobbing.cs
index 74a13f5..e3ca735 100644
--- a/Pathy.Globbing/PathyGlobbing.cs
+++ b/Pathy.Globbing/PathyGlobbing.cs
@@ -31,8 +31,39 @@ internal static class ChainablePathExtensions
/// The glob pattern used to match file paths, e.g. **/*.md or dir/**/*
public static ChainablePath[] GlobFiles(this ChainablePath path, string globPattern)
{
+ return GlobFiles(path, new[] { globPattern });
+ }
+
+ ///
+ /// Matches files in the specified directory or subdirectories according to the provided glob patterns
+ /// and returns them as an array of objects.
+ ///
+ ///
+ /// See also
+ ///
+ /// The base directory path to start the glob search from.
+ /// One or more glob patterns used to match file paths, e.g. **/*.md or dir/**/*
+ /// Thrown if no glob patterns are provided or if any pattern is null or empty.
+ public static ChainablePath[] GlobFiles(this ChainablePath path, params string[] globPatterns)
+ {
+ if (globPatterns == null || globPatterns.Length == 0)
+ {
+ throw new ArgumentException("At least one glob pattern must be provided", nameof(globPatterns));
+ }
+
+ foreach (string pattern in globPatterns)
+ {
+ if (string.IsNullOrWhiteSpace(pattern))
+ {
+ throw new ArgumentException("Glob patterns cannot be null or empty", nameof(globPatterns));
+ }
+ }
+
Matcher matcher = new(StringComparison.OrdinalIgnoreCase);
- matcher.AddInclude(globPattern);
+ foreach (string pattern in globPatterns)
+ {
+ matcher.AddInclude(pattern);
+ }
return matcher
.Execute(new DirectoryInfoWrapper(path.ToDirectoryInfo()))
diff --git a/Pathy.Specs/ChainablePathSpecs.cs b/Pathy.Specs/ChainablePathSpecs.cs
index 94fa5f3..babbf68 100644
--- a/Pathy.Specs/ChainablePathSpecs.cs
+++ b/Pathy.Specs/ChainablePathSpecs.cs
@@ -465,6 +465,98 @@ public void Can_find_files_using_globbing_patterns()
], options => options.ComparingRecordsByValue());
}
+ [Fact]
+ public void Can_find_files_using_multiple_globbing_patterns()
+ {
+ // Arrange
+ var temp = ChainablePath.Temp / "dir1" / "dir2" / "dir3" / "file.txt";
+
+ temp.CreateDirectoryRecursively();
+ File.WriteAllText(temp / "file.txt", "Hello World!");
+ File.WriteAllText(temp / "file2.txt", "Hello World!");
+ File.WriteAllText(temp / "file3.doc", "Hello World!");
+ File.WriteAllText(temp / "file4.md", "# Markdown");
+
+ // Act
+ var files = (ChainablePath.Temp / "dir1").GlobFiles("**/*.txt", "**/*.doc");
+
+ // Assert
+ files.Should().BeEquivalentTo([
+ temp / "file.txt",
+ temp / "file2.txt",
+ temp / "file3.doc"
+ ], options => options.ComparingRecordsByValue());
+ }
+
+ [Fact]
+ public void Can_find_files_using_multiple_globbing_patterns_with_different_depths()
+ {
+ // Arrange
+ var baseDir = testFolder / "MultiPatternTest";
+ var deepDir = baseDir / "level1" / "level2";
+ deepDir.CreateDirectoryRecursively();
+
+ File.WriteAllText(baseDir / "root.txt", "Root");
+ File.WriteAllText(baseDir / "root.md", "# Root");
+ File.WriteAllText(deepDir / "deep.txt", "Deep");
+ File.WriteAllText(deepDir / "deep.json", "{}");
+
+ // Act
+ var files = baseDir.GlobFiles("**/*.txt", "**/*.json");
+
+ // Assert
+ files.Should().BeEquivalentTo([
+ baseDir / "root.txt",
+ deepDir / "deep.txt",
+ deepDir / "deep.json"
+ ], options => options.ComparingRecordsByValue());
+ }
+
+ [Fact]
+ public void GlobFiles_with_multiple_patterns_throws_when_no_patterns_provided()
+ {
+ // Arrange
+ var temp = ChainablePath.Temp / "dir1";
+ temp.CreateDirectoryRecursively();
+
+ // Act & Assert
+ var act = () => temp.GlobFiles(new string[0]);
+
+ act.Should().Throw()
+ .WithMessage("*At least one glob pattern must be provided*")
+ .WithParameterName("globPatterns");
+ }
+
+ [Fact]
+ public void GlobFiles_with_multiple_patterns_throws_when_pattern_is_null()
+ {
+ // Arrange
+ var temp = ChainablePath.Temp / "dir1";
+ temp.CreateDirectoryRecursively();
+
+ // Act & Assert
+ var act = () => temp.GlobFiles("**/*.txt", null, "**/*.doc");
+
+ act.Should().Throw()
+ .WithMessage("*Glob patterns cannot be null or empty*")
+ .WithParameterName("globPatterns");
+ }
+
+ [Fact]
+ public void GlobFiles_with_multiple_patterns_throws_when_pattern_is_empty()
+ {
+ // Arrange
+ var temp = ChainablePath.Temp / "dir1";
+ temp.CreateDirectoryRecursively();
+
+ // Act & Assert
+ var act = () => temp.GlobFiles("**/*.txt", "", "**/*.doc");
+
+ act.Should().Throw()
+ .WithMessage("*Glob patterns cannot be null or empty*")
+ .WithParameterName("globPatterns");
+ }
+
[Fact]
public void Can_convert_to_directory_info()
{
diff --git a/README.md b/README.md
index 8b086c0..c4871d9 100644
--- a/README.md
+++ b/README.md
@@ -131,7 +131,11 @@ If you add the `Pathy.Globbing` NuGet source-only package as well, you'll get ac
```csharp
+// Match files with a single pattern
ChainablePath[] files = (ChainablePath.Current / "Artifacts").GlobFiles("**/*.json");
+
+// Match files with multiple patterns
+ChainablePath[] files = (ChainablePath.Current / "Artifacts").GlobFiles("**/*.txt", "**/*.md", "**/*.json");
```
### File system operations