diff --git a/core/src/main/scala/better/files/File.scala b/core/src/main/scala/better/files/File.scala index c3bcd6ba..d80f602e 100644 --- a/core/src/main/scala/better/files/File.scala +++ b/core/src/main/scala/better/files/File.scala @@ -891,6 +891,39 @@ object File { def apply(path: String, fragments: String*): File = Paths.get(path, fragments: _*) + /** + * Get File to path with help of reference anchor. + * + * Anchor is used as a reference in case that path + * is not absolute. Anchor could be path to directory or + * path to file. If anchor is file, then file's parent dir + * is used as an anchor. + * + * If anchor itself is relative, then anchor is used together + * with current working directory. + * + * NOTE: If anchor is non-existing path on filesystem, + * then it's always treated as file, e.g. it's last component + * is removed when it is used as an anchor. + * + * @param anchor path to be used as anchor + * @param path as string + * @param fragments optional path fragments + * @return absolute, normalize path + */ + def apply(anchor: File, path: String, fragments: String*): File = { + val p = Paths.get(path, fragments: _*) + if (p.isAbsolute) { + p + } else { + if (anchor.isDirectory) { + anchor / p.toString + } else { + anchor.parent / p.toString + } + } + } + def apply(url: URL): File = apply(url.toURI) diff --git a/core/src/test/scala/better/files/FileSpec.scala b/core/src/test/scala/better/files/FileSpec.scala index 46a98014..94a8cfdc 100644 --- a/core/src/test/scala/better/files/FileSpec.scala +++ b/core/src/test/scala/better/files/FileSpec.scala @@ -93,6 +93,50 @@ class FileSpec extends FlatSpec with BeforeAndAfterEach with Matchers { Seq(f, f1, f2, f4, /*f5,*/ f6, f8, f9).map(_.toString).toSet shouldBe Set(f.toString) } + it can "be instantiated with anchor" in { + // testRoot / a / a1 / t1.txt + val basedir = a1 + File(basedir, "/abs/path/to/loc").toString should be("/abs/path/to/loc") + File(basedir, "/abs", "path", "to", "loc").toString should be("/abs/path/to/loc") + + File(basedir, "rel/path/to/loc").toString should be (basedir.toString + "/rel/path/to/loc") + File(basedir, "../rel/path/to/loc").toString should be (fa.toString + "/rel/path/to/loc") + File(basedir, "../", "rel", "path", "to", "loc").toString should be (fa.toString + "/rel/path/to/loc") + + val baseref = t1 + File(baseref, "/abs/path/to/loc").toString should be("/abs/path/to/loc") + File(baseref, "/abs", "path", "to", "loc").toString should be("/abs/path/to/loc") + + File(baseref, "rel/path/to/loc").toString should be (a1.toString + "/rel/path/to/loc") + File(baseref, "../rel/path/to/loc").toString should be (fa.toString + "/rel/path/to/loc") + File(basedir, "../", "rel", "path", "to", "loc").toString should be (fa.toString + "/rel/path/to/loc") + } + + it can "be instantiated with non-existing abs anchor" in { + val anchorStr = "/abs/to/nowhere" + val anchorStr_a = anchorStr + "/a" + val basedir = File(anchorStr_a + "/last") + + File(basedir, "/abs/path/to/loc").toString should be("/abs/path/to/loc") + File(basedir, "/abs", "path", "to", "loc").toString should be("/abs/path/to/loc") + + File(basedir, "rel/path/to/loc").toString should be (anchorStr_a + "/rel/path/to/loc") + File(basedir, "../rel/path/to/loc").toString should be (anchorStr + "/rel/path/to/loc") + File(basedir, "../", "rel", "path", "to", "loc").toString should be (anchorStr + "/rel/path/to/loc") + } + + it can "be instantiated with non-existing relative anchor" in { + val relAnchor = File("rel/anc/b/last") + val basedir = relAnchor + + File(basedir, "/abs/path/to/loc").toString should be("/abs/path/to/loc") + File(basedir, "/abs", "path", "to", "loc").toString should be("/abs/path/to/loc") + + File(basedir, "rel/path/to/loc").toString should be (File("rel/anc/b").toString + "/rel/path/to/loc") + File(basedir, "../rel/path/to/loc").toString should be (File("rel/anc").toString + "/rel/path/to/loc") + File(basedir, "../", "rel", "path", "to", "loc").toString should be (File("rel/anc").toString + "/rel/path/to/loc") + } + it should "do basic I/O" in { t1 < "hello" t1.contentAsString shouldEqual "hello"