diff --git a/os/src-jvm/ResourcePath.scala b/os/src-jvm/ResourcePath.scala index 6e7160e2..cb97dde2 100644 --- a/os/src-jvm/ResourcePath.scala +++ b/os/src-jvm/ResourcePath.scala @@ -23,7 +23,7 @@ class ResourcePath private[os](val resRoot: ResourceRoot, segments0: Array[Strin def toSource = new Source.WritableSource(getInputStream) val segments: IndexedSeq[String] = segments0 type ThisType = ResourcePath - def last = segments0.last + def lastOpt = segments0.lastOption override def toString = resRoot.errorName + "/" + segments0.mkString("/") protected[this] def make(p: Seq[String], ups: Int) = { if (ups > 0){ diff --git a/os/src/Path.scala b/os/src/Path.scala index 10717e0b..b34a3da6 100644 --- a/os/src/Path.scala +++ b/os/src/Path.scala @@ -182,9 +182,14 @@ trait BasePathImpl extends BasePath{ def /(chunk: PathChunk): ThisType def ext = { - val li = last.lastIndexOf('.') - if (li == -1) "" - else last.slice(li+1, last.length) + lastOpt match{ + case None => "" + case Some(lastSegment) => + val li = lastSegment.lastIndexOf('.') + if (li == -1) "" + else last.slice(li+1, last.length) + } + } override def baseName: String = { @@ -193,7 +198,9 @@ trait BasePathImpl extends BasePath{ else last.slice(0, li) } - def last: String + def last: String = lastOpt.getOrElse(throw PathError.LastOnEmptyPath()) + + def lastOpt: Option[String] } object PathError{ @@ -208,6 +215,9 @@ object PathError{ case class NoRelativePath(src: RelPath, base: RelPath) extends IAE(s"Can't relativize relative paths $src from $base") + + case class LastOnEmptyPath() + extends IAE("empty path has no last segment") } /** @@ -239,7 +249,7 @@ object FilePath { */ class RelPath private[os](segments0: Array[String], val ups: Int) extends FilePath with BasePathImpl with SegmentedPath { - def last = segments.last + def lastOpt = segments.lastOption val segments: IndexedSeq[String] = segments0 type ThisType = RelPath require(ups >= 0) @@ -305,7 +315,7 @@ object RelPath { */ class SubPath private[os](val segments0: Array[String]) extends FilePath with BasePathImpl with SegmentedPath { - def last = segments.last + def lastOpt = segments.lastOption val segments: IndexedSeq[String] = segments0 type ThisType = SubPath protected[this] def make(p: Seq[String], ups: Int) = { @@ -433,7 +443,7 @@ class Path private[os](val wrapped: java.nio.file.Path) def segmentCount = wrapped.getNameCount type ThisType = Path - def last = wrapped.getFileName.toString + def lastOpt = Option(wrapped.getFileName).map(_.toString) def /(chunk: PathChunk): ThisType = { if (chunk.ups > wrapped.getNameCount) throw PathError.AbsolutePathOutsideRoot diff --git a/os/test/src/PathTests.scala b/os/test/src/PathTests.scala index 37c2e363..d96a664d 100644 --- a/os/test/src/PathTests.scala +++ b/os/test/src/PathTests.scala @@ -47,6 +47,24 @@ object PathTests extends TestSuite{ assert((base / "baseOnly").ext == "") assert((base / "baseOnly.").ext == "") } + + test("emptyExt"){ + os.root.ext ==> "" + os.rel.ext ==> "" + os.sub.ext ==> "" + os.up.ext ==> "" + } + + test("emptyLast"){ + intercept[PathError.LastOnEmptyPath](os.root.last).getMessage ==> + "empty path has no last segment" + intercept[PathError.LastOnEmptyPath](os.rel.last).getMessage ==> + "empty path has no last segment" + intercept[PathError.LastOnEmptyPath](os.sub.last).getMessage ==> + "empty path has no last segment" + intercept[PathError.LastOnEmptyPath](os.up.last).getMessage ==> + "empty path has no last segment" + } } test("RelPath"){