Refactor FilePathComponents: rename properties, deprecate constructor, rename filePathComponents extension.
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user