Refactor FilePathComponents: rename properties, deprecate constructor, rename filePathComponents extension.

This commit is contained in:
Ilya Gorbunov
2015-12-07 20:50:29 +03:00
parent 8deefd56db
commit 52eb9e4276
3 changed files with 45 additions and 33 deletions
@@ -81,30 +81,39 @@ public val File.root: File?
/**
* Represents the path to a file as a collection of directories.
*
* @property rootName the name of the root of the path (for example, `/` or `C:`).
* @property fileList the list of [File] objects representing every directory in the path to the file,
* @property root the [File] object representing root of the path (for example, `/` or `C:` or empty for relative paths).
* @property segments the list of [File] objects representing every directory in the path to the file,
* up to an including the file itself.
*/
public data class FilePathComponents(public val rootName: String, public val fileList: List<File>) {
public data class FilePathComponents
internal constructor(public val root: File, public val segments: List<File>) {
@Deprecated("This constructor will be removed soon. Use File.toComponents() extension to create an instance of FilePathComponents.")
constructor (rootName: String, fileList: List<File>): this(File(rootName), fileList)
@Deprecated("Use 'root' property or 'root.path' instead.", ReplaceWith("root.path"))
public val rootName: String get() = root.path
@Deprecated("Use 'segments' property instead.", ReplaceWith("segments"))
public val fileList: List<File> get() = segments
/**
* Returns the number of elements in the path to the file.
*/
public fun size(): Int = fileList.size
public val size: Int get() = segments.size
/**
* [File] representing root of the path (for example, `/` or `C:` or empty for relative paths).
*/
public val root: File = File(rootName)
@Deprecated("Use 'size' property instead.", ReplaceWith("size"))
public fun size(): Int = size
/**
* Returns a sub-path of the path, starting with the directory at the specified [beginIndex] and up
* to the specified [endIndex].
*/
public fun subPath(beginIndex: Int, endIndex: Int): File {
if (beginIndex < 0 || beginIndex > endIndex || endIndex > size())
if (beginIndex < 0 || beginIndex > endIndex || endIndex > size)
throw IllegalArgumentException()
return File(fileList.subList(beginIndex, endIndex).joinToString(File.separator))
return File(segments.subList(beginIndex, endIndex).joinToString(File.separator))
}
}
@@ -112,7 +121,7 @@ public data class FilePathComponents(public val rootName: String, public val fil
* Splits the file into path components (the names of containing directories and the name of the file
* itself) and returns the resulting collection of components.
*/
public fun File.filePathComponents(): FilePathComponents {
public fun File.toComponents(): FilePathComponents {
val path = separatorsToSystem()
val rootName = path.getRootName()
val subPath = path.substring(rootName.length)
@@ -121,9 +130,12 @@ public fun File.filePathComponents(): FilePathComponents {
val list = if (subPath.isEmpty()) listOf() else
// Looks awful but we split just by /+ or \+ depending on OS
subPath.split(Regex.fromLiteral(File.separatorChar.toString())).map { it -> File(it) }
return FilePathComponents(rootName, list)
return FilePathComponents(File(rootName), list)
}
@Deprecated("Use 'toComponents' instead.", ReplaceWith("toComponents()"))
public fun File.filePathComponents(): FilePathComponents = toComponents()
/**
* Returns a relative pathname which is a subsequence of this pathname,
* beginning from component [beginIndex], inclusive,
@@ -134,4 +146,4 @@ public fun File.filePathComponents(): FilePathComponents {
* or [endIndex] is greater than existing number of components,
* or [beginIndex] is greater than [endIndex].
*/
public fun File.subPath(beginIndex: Int, endIndex: Int): File = filePathComponents().subPath(beginIndex, endIndex)
public fun File.subPath(beginIndex: Int, endIndex: Int): File = toComponents().subPath(beginIndex, endIndex)
+19 -19
View File
@@ -129,19 +129,19 @@ public fun File.relativeTo(base: File): String
private fun File.relativeToOrNull(base: File): String? {
// Check roots
val thisComponents = this.filePathComponents().normalize()
val baseComponents = base.filePathComponents().normalize()
val thisComponents = this.toComponents().normalize()
val baseComponents = base.toComponents().normalize()
if (thisComponents.root != baseComponents.root) {
return null
}
val baseCount = baseComponents.size()
val thisCount = thisComponents.size()
val baseCount = baseComponents.size
val thisCount = thisComponents.size
val sameCount = run countSame@ {
var i = 0
val maxSameCount = Math.min(thisCount, baseCount)
while (i < maxSameCount && thisComponents.fileList[i] == baseComponents.fileList[i])
while (i < maxSameCount && thisComponents.segments[i] == baseComponents.segments[i])
i++
return@countSame i
}
@@ -149,7 +149,7 @@ private fun File.relativeToOrNull(base: File): String? {
// Annihilate differing base components by adding required number of .. parts
val res = StringBuilder()
for (i in baseCount - 1 downTo sameCount) {
if (baseComponents.fileList[i].name == "..") {
if (baseComponents.segments[i].name == "..") {
return null
}
@@ -166,7 +166,7 @@ private fun File.relativeToOrNull(base: File): String? {
if (sameCount < baseCount)
res.append(File.separatorChar)
res.append(thisComponents.subPath(sameCount, thisCount))
thisComponents.segments.drop(sameCount).joinTo(res, File.separator)
}
return res.toString()
@@ -331,12 +331,12 @@ public fun File.listFiles(filter: (file: File) -> Boolean): Array<File>? = listF
* @return `true` if this path starts with [other] path, `false` otherwise.
*/
public fun File.startsWith(other: File): Boolean {
val components = filePathComponents()
val otherComponents = other.filePathComponents()
val components = toComponents()
val otherComponents = other.toComponents()
if (components.root != otherComponents.root && otherComponents.rootName != "")
return false
return if (components.size() < otherComponents.size()) false
else components.fileList.subList(0, otherComponents.size()).equals(otherComponents.fileList)
return if (components.size < otherComponents.size) false
else components.segments.subList(0, otherComponents.size).equals(otherComponents.segments)
}
/**
@@ -358,13 +358,13 @@ public fun File.startsWith(other: String): Boolean = startsWith(File(other))
* @return `true` if this path ends with [other] path, `false` otherwise.
*/
public fun File.endsWith(other: File): Boolean {
val components = filePathComponents()
val otherComponents = other.filePathComponents()
val components = toComponents()
val otherComponents = other.toComponents()
if (components.root != otherComponents.root && otherComponents.rootName != "")
return false
val shift = components.size() - otherComponents.size()
val shift = components.size - otherComponents.size
return if (shift < 0) false
else components.fileList.subList(shift, components.size()).equals(otherComponents.fileList)
else components.segments.subList(shift, components.size).equals(otherComponents.segments)
}
/**
@@ -384,10 +384,10 @@ public fun File.endsWith(other: String): Boolean = endsWith(File(other))
* @return normalized pathname with . and possibly .. removed.
*/
public fun File.normalize(): File
= filePathComponents().let { File(it.fileList.normalize().joinToString(File.separator, it.rootName)) }
= with (toComponents()) { root.resolve(segments.normalize().joinToString(File.separator)) }
private fun FilePathComponents.normalize(): FilePathComponents
= FilePathComponents(rootName, fileList.normalize())
= FilePathComponents(root, segments.normalize())
private fun List<File>.normalize(): List<File> {
val list: MutableList<File> = ArrayList(this.size)
@@ -434,8 +434,8 @@ public fun File.resolve(relative: String): File = resolve(File(relative))
* @return concatenated this.parent and [relative] paths, or just [relative] if it's absolute or this has no parent.
*/
public fun File.resolveSibling(relative: File): File {
val components = filePathComponents()
val parentSubPath = if (components.size() == 0) File("..") else components.subPath(0, components.size() - 1)
val components = this.toComponents()
val parentSubPath = if (components.size == 0) File("..") else components.subPath(0, components.size - 1)
return components.root.resolve(parentSubPath).resolve(relative)
}
+1 -1
View File
@@ -189,7 +189,7 @@ class FilesTest {
private fun checkFileElements(f: File, root: File?, elements: List<String>) {
var i = 0
assertEquals(root, f.root)
for (elem in f.filePathComponents().fileList) {
for (elem in f.toComponents().segments) {
assertTrue(i < elements.size, i.toString())
assertEquals(elements[i++], elem.toString())
}