Skip to content

Commit

Permalink
#114: Simplify PathMatcherSyntax
Browse files Browse the repository at this point in the history
  • Loading branch information
pathikrit committed Feb 21, 2017
1 parent 58af5bc commit 54e91ba
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 43 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -261,13 +261,13 @@ dir.listRecursively.filter(f => f.extension == Some(".java") || f.extension == S

You can even use more advanced regex syntax instead of [glob syntax](http://docs.oracle.com/javase/tutorial/essential/io/fileOps.html#glob):
```scala
val matches = dir.glob("^\\w*$")(syntax = File.PathMatcherSyntax.regex)
val matches = dir.glob("*.txt")(syntax = File.PathMatcherSyntax.regex)
```

Note that the default glob syntax in `better-files` is [different from](https://github.com/pathikrit/better-files/issues/114)
the default glob syntax. To use the default behaviour:
the default glob syntax since it always includes path. To use the default behaviour:
```scala
file.pathMatcher(syntax = File.PathMatcherSyntax.Glob)
dir.glob("**/*.txt", includePath = false) // this is equivalent to dir.glob("*.txt", includePath = true)
```
You can also extend the `File.PathMatcherSyntax` to create your own matchers.

Expand Down
70 changes: 35 additions & 35 deletions core/src/main/scala/better/files/File.scala
Original file line number Diff line number Diff line change
Expand Up @@ -472,16 +472,19 @@ class File private(val path: Path) {
def walk(maxDepth: Int = Int.MaxValue)(implicit visitOptions: File.VisitOptions = File.VisitOptions.default): Files =
Files.walk(path, maxDepth, visitOptions: _*) //TODO: that ignores I/O errors?

def pathMatcher(syntax: File.PathMatcherSyntax)(pattern: String): PathMatcher =
syntax(pattern, this)
def pathMatcher(syntax: File.PathMatcherSyntax, includePath: Boolean)(pattern: String): PathMatcher =
syntax(this, pattern, includePath)

/**
* Util to glob from this file's path
*
*
* @param includePath If true, we don't need to set path glob patterns
* e.g. instead of **//*.txt we just use *.txt
* @return Set of files that matched
*/
def glob(pattern: String)(implicit syntax: File.PathMatcherSyntax = File.PathMatcherSyntax.default, visitOptions: File.VisitOptions = File.VisitOptions.default): Files =
pathMatcher(syntax)(pattern).matches(this)(visitOptions)
def glob(pattern: String, includePath: Boolean = true)(implicit syntax: File.PathMatcherSyntax = File.PathMatcherSyntax.default, visitOptions: File.VisitOptions = File.VisitOptions.default): Files =
pathMatcher(syntax, includePath)(pattern).matches(this)(visitOptions)

/**
* More Scala friendly way of doing Files.walk
Expand Down Expand Up @@ -992,44 +995,41 @@ object File {
val default : Order = byDirectoriesFirst
}

class PathMatcherSyntax private (val name: String) {
def apply(pattern: String, file: File): PathMatcher =
file.fileSystem.getPathMatcher(s"$name:$pattern")
}
object PathMatcherSyntax {
case object Glob extends PathMatcherSyntax("glob")
case object Regex extends PathMatcherSyntax("regex")
abstract class PathMatcherSyntax private (val name: String) {

/**
* Combine glob with path so that it will match relative path without leading glob-pattern.
* Return PathMatcher from this file
*
* @param file
* @param pattern
* @param includePath If this is true, no need to include path matchers
* e.g. instead of "**//*.txt" we can simply use *.txt
* @return
*/
case object PathGlob extends PathMatcherSyntax("glob") {
override def apply(pattern: String, file: File) = {
val path = file.path.toString + file.fileSystem.getSeparator
val escapedPath = path
.replaceAllLiterally("""\\""", """\\\\""")
.replaceAllLiterally("*", "\\*")
.replaceAllLiterally("?", "\\?")
.replaceAllLiterally("{", "\\{")
.replaceAllLiterally("}", "\\}")
.replaceAllLiterally("[", "\\[")
.replaceAllLiterally("]", "\\]")
super.apply(s"$escapedPath$pattern", file)
}
def apply(file: File, pattern: String, includePath: Boolean): PathMatcher = {
val escapedPath = if (includePath) escapePath(file.path.toString + file.fileSystem.getSeparator) else ""
file.fileSystem.getPathMatcher(s"$name:$escapedPath$pattern")
}

/**
* Combine regex with path so that it will match relative path without leading regex-pattern.
*/
case object PathRegex extends PathMatcherSyntax("regex") {
override def apply(pattern: String, file: File) = {
val path = file.path.toString + file.fileSystem.getSeparator
super.apply(s"${Pattern.quote(path)}$pattern", file)
}
def escapePath(path: String): String
}
object PathMatcherSyntax {
val glob: PathMatcherSyntax = new PathMatcherSyntax("glob") {
override def escapePath(path: String) = path
.replaceAllLiterally("""\\""", """\\\\""")
.replaceAllLiterally("*", "\\*")
.replaceAllLiterally("?", "\\?")
.replaceAllLiterally("{", "\\{")
.replaceAllLiterally("}", "\\}")
.replaceAllLiterally("[", "\\[")
.replaceAllLiterally("]", "\\]")
}

val regex: PathMatcherSyntax = new PathMatcherSyntax("regex") {
override def escapePath(path: String) = Pattern.quote(path)
}

val default = PathGlob
def other(syntax: String) = new PathMatcherSyntax(syntax)
val default = glob
}

class RandomAccessMode private(val value: String)
Expand Down
10 changes: 5 additions & 5 deletions core/src/test/scala/better/files/GlobSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ class GlobSpec extends CommonSpec with BeforeAndAfterAll {
)
val paths = globTree.glob("*.txt")
verify(paths, refPaths, globTree)
assert(globTree.glob("*.txt")(File.PathMatcherSyntax.Glob).isEmpty)
assert(globTree.glob("*.txt", includePath = false)(File.PathMatcherSyntax.glob).isEmpty)
}

it should "match fixed sub dir and file-glob (e.g. '**/subdir/*.ext')" in {
Expand Down Expand Up @@ -318,7 +318,7 @@ class GlobSpec extends CommonSpec with BeforeAndAfterAll {
"b/b.txt",
"b/a/ba.txt"
)
val paths = globTree.glob(".*/.*\\.txt")(File.PathMatcherSyntax.PathRegex)
val paths = globTree.glob(".*/.*\\.txt")(File.PathMatcherSyntax.regex)

verify(paths, refPaths, globTree)
}
Expand All @@ -331,15 +331,15 @@ class GlobSpec extends CommonSpec with BeforeAndAfterAll {
"a/a2/a2.txt",
"a/a2/x.txt"
)
val paths = globTree.glob("a/.*\\.txt")(File.PathMatcherSyntax.PathRegex)
val paths = globTree.glob("a/.*\\.txt")(File.PathMatcherSyntax.regex)

verify(paths, refPaths, globTree)
assert(globTree.glob("a/.*\\.txt")(File.PathMatcherSyntax.Regex).isEmpty)
assert(globTree.glob("a/.*\\.txt", includePath = false)(File.PathMatcherSyntax.regex).isEmpty)
}

it should "not use dir name as wildcard (e.g. dirname is .*)" in {
val d = regexWildcardPath // "path" / "with" / ".*"
val paths = d.glob("a\\.txt")(File.PathMatcherSyntax.PathRegex)
val paths = d.glob("a\\.txt")(File.PathMatcherSyntax.regex)
assert(paths.isEmpty)
}
}

0 comments on commit 54e91ba

Please sign in to comment.