From ddf73c23a4b727fc69c269d3131292913a7d7b6b Mon Sep 17 00:00:00 2001 From: Pete Schaffner Date: Tue, 12 May 2020 11:22:13 +0200 Subject: [PATCH] Add ability to remove items from a section (#75) --- Sources/Publish/API/PublishingStep.swift | 20 ++++++++++++ Sources/Publish/API/Section.swift | 31 +++++++++++++------ .../Tests/ContentMutationTests.swift | 16 ++++++++++ 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/Sources/Publish/API/PublishingStep.swift b/Sources/Publish/API/PublishingStep.swift index abb22b41..0742e780 100644 --- a/Sources/Publish/API/PublishingStep.swift +++ b/Sources/Publish/API/PublishingStep.swift @@ -134,6 +134,26 @@ public extension PublishingStep { try MarkdownFileHandler().addMarkdownFiles(in: folder, to: &context) } } + + /// Remove all items matching a predicate, optionally within a specific section. + /// - parameter section: Any specific section to remove all items within. + /// - parameter predicate: Any predicate to filter the items using. + static func removeAllItems( + in section: Site.SectionID? = nil, + matching predicate: Predicate> = .any + ) -> Self { + let nameSuffix = section.map { " in '\($0)'" } ?? "" + + return step(named: "Remove items" + nameSuffix) { context in + if let section = section { + context.sections[section].removeItems(matching: predicate) + } else { + for section in context.sections.ids { + context.sections[section].removeItems(matching: predicate) + } + } + } + } /// Mutate all items matching a predicate, optionally within a specific section. /// - parameter section: Any specific section to mutate all items within. diff --git a/Sources/Publish/API/Section.swift b/Sources/Publish/API/Section.swift index 530da9bd..75e6c76d 100644 --- a/Sources/Publish/API/Section.swift +++ b/Sources/Publish/API/Section.swift @@ -94,21 +94,19 @@ public extension Section { return item } } + + /// Remove all items within this section matching a given predicate. + /// - Parameter predicate: Any predicate to filter the items based on. + mutating func removeItems(matching predicate: Predicate> = .any) { + items.removeAll(where: predicate.matches) + rebuildIndexes() + } /// Sort all items within this section using a closure. /// - Parameter sorter: The closure to use to sort the items. mutating func sortItems(by sorter: (Item, Item) throws -> Bool) rethrows { try items.sort(by: sorter) - itemIndexesByPath = [:] - itemIndexesByTag = [:] - - for (index, item) in items.enumerated() { - itemIndexesByPath[item.relativePath] = index - - for tag in item.tags { - itemIndexesByTag[tag, default: []].insert(index) - } - } + rebuildIndexes() } } @@ -169,4 +167,17 @@ private extension Section { lastItemModificationDate = newDate } + + mutating func rebuildIndexes() { + itemIndexesByPath = [:] + itemIndexesByTag = [:] + + for (index, item) in items.enumerated() { + itemIndexesByPath[item.relativePath] = index + + for tag in item.tags { + itemIndexesByTag[tag, default: []].insert(index) + } + } + } } diff --git a/Tests/PublishTests/Tests/ContentMutationTests.swift b/Tests/PublishTests/Tests/ContentMutationTests.swift index 6273b929..a6575a5d 100644 --- a/Tests/PublishTests/Tests/ContentMutationTests.swift +++ b/Tests/PublishTests/Tests/ContentMutationTests.swift @@ -32,6 +32,21 @@ final class ContentMutationTests: PublishTestCase { XCTAssertEqual(site.sections[.one].items.first?.body.html, "
Plot!
") } + func testRemovingItemsMatchingPredicate() throws { + let items = [ + Item.stub(withPath: "a").setting(\.tags, to: ["one"]), + Item.stub(withPath: "b").setting(\.tags, to: ["one", "two"]) + ] + + let site = try publishWebsite(using: [ + .addItems(in: items), + .removeAllItems(matching: \.tags ~= "two") + ]) + + XCTAssertEqual(site.sections[.one].items, [items[0]]) + XCTAssertNil(site.sections[.one].item(at: "b"), "Item indexes not updated") + } + func testMutatingAllSections() throws { let site = try publishWebsite(using: [ .step(named: "Set section titles") { context in @@ -280,6 +295,7 @@ extension ContentMutationTests { [ ("testAddingItemUsingClosureAPI", testAddingItemUsingClosureAPI), ("testAddingItemUsingPlotHierarchy", testAddingItemUsingPlotHierarchy), + ("testRemovingItemsMatchingPredicate", testRemovingItemsMatchingPredicate), ("testMutatingAllSections", testMutatingAllSections), ("testMutatingAllItems", testMutatingAllItems), ("testMutatingItemsInSection", testMutatingItemsInSection),