diff --git a/Sources/Files.swift b/Sources/Files.swift index d01aa33..4abd37f 100644 --- a/Sources/Files.swift +++ b/Sources/Files.swift @@ -237,47 +237,112 @@ public class FileSystem { self.name = pathComponents[pathComponents.count - 2] } } - + + /** + * Rename the item + * + * - parameter newName: The new name that the item should have + * - parameter keepExtension: Whether the file should keep the same extension as it had before + * + * - throws: `FileSystem.Item.OperationError.renameFailed` if the item couldn't be renamed + */ + public func rename(to newName: String, keepExtension: Bool) throws { + if keepExtension { + try rename(to: newName, extension: .keep) + } else { + let nameComponents = newName.components(separatedBy: ".") + let nameComponent = nameComponents[0] + let action: ExtensionAction + if nameComponents.count > 1 { + action = .change(to: nameComponents.last!) + } else { + action = .remove + } + try rename(to: nameComponent, extension: action) + } + } + + /// Actions that can be taken on an extension while renaming an item + public enum ExtensionAction { + /// Keep the item's current extension + case keep + /// Remove the item's current extenion + case remove + /// Change the item's extension to the contained String + case change(to: String) + } + /** * Rename the item * * - parameter newName: The new name that the item should have - * - parameter keepExtension: Whether the file should keep the same extension as it had before (defaults to `true`) + * - parameter extension: The action to take on the item's extension (defaults to .keep) * * - throws: `FileSystem.Item.OperationError.renameFailed` if the item couldn't be renamed */ - public func rename(to newName: String, keepExtension: Bool = true) throws { + public func rename(to newName: String, extension extensionAction: ExtensionAction = .keep) throws { guard let parent = parent else { throw OperationError.renameFailed(self) } - + var newName = newName - - if keepExtension { + + switch extensionAction { + case .keep: if let `extension` = `extension` { let extensionString = ".\(`extension`)" - + if !newName.hasSuffix(extensionString) { newName += extensionString } } + + case .remove: + if let `extension` = `extension` { + let extensionString = ".\(`extension`)" + + if newName.hasSuffix(extensionString) { + newName = String(newName.dropLast(extensionString.count)) + } + } + + case .change(var newExtension): + if !newExtension.hasPrefix(".") { + newExtension = "." + newExtension + } + + if !newName.hasSuffix(newExtension) { + newName += newExtension + } } - + var newPath = parent.path + newName - + if kind == .folder && !newPath.hasSuffix("/") { newPath += "/" } - + do { try fileManager.moveItem(atPath: path, toPath: newPath) - + name = newName path = newPath } catch { throw OperationError.renameFailed(self) } } + + /** + * Rename the item + * + * - parameter newName: The new name that the item should have + * - parameter newExtension: The new extension that the item should have + * + * - throws: `FileSystem.Item.OperationError.renameFailed` if the item couldn't be renamed + */ + public func rename(to newName: String, extension newExtension: String) throws { + try rename(to: newName, extension: .change(to: newExtension)) + } /** * Move this item to a new folder diff --git a/Tests/FilesTests/FilesTests.swift b/Tests/FilesTests/FilesTests.swift index 4bd4e2c..5e92e41 100644 --- a/Tests/FilesTests/FilesTests.swift +++ b/Tests/FilesTests/FilesTests.swift @@ -129,6 +129,32 @@ class FilesTests: XCTestCase { XCTAssertEqual(file.name, "other.txt") XCTAssertEqual(file.path, folder.path + "other.txt") XCTAssertEqual(file.extension, "txt") + + // Now try renaming the file using the extension actions + try file.rename(to: "some", extension: .keep) + XCTAssertEqual(file.name, "some.txt") + XCTAssertEqual(file.path, folder.path + "some.txt") + XCTAssertEqual(file.extension, "txt") + + try file.rename(to: "different", extension: .change(to: "pdf")) + XCTAssertEqual(file.name, "different.pdf") + XCTAssertEqual(file.path, folder.path + "different.pdf") + XCTAssertEqual(file.extension, "pdf") + + try file.rename(to: "oneMore.txt", extension: .change(to: "txt")) + XCTAssertEqual(file.name, "oneMore.txt") + XCTAssertEqual(file.path, folder.path + "oneMore.txt") + XCTAssertEqual(file.extension, "txt") + + try file.rename(to: "another", extension: .remove) + XCTAssertEqual(file.name, "another") + XCTAssertEqual(file.path, folder.path + "another") + XCTAssertNil(file.extension) + + try file.rename(to: "lastOne", extension: ".png") + XCTAssertEqual(file.name, "lastOne.png") + XCTAssertEqual(file.path, folder.path + "lastOne.png") + XCTAssertEqual(file.extension, "png") } }