-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
418 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
// swift-tools-version: 6.0 | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "StringBuilder", | ||
platforms: [ | ||
.macOS(.v10_15), | ||
.iOS(.v13), | ||
.tvOS(.v13), | ||
.watchOS(.v6), | ||
.macCatalyst(.v13) | ||
], | ||
products: [ | ||
.library( | ||
name: "StringBuilder", | ||
targets: [ | ||
"StringBuilder" | ||
] | ||
), | ||
], | ||
targets: [ | ||
.target( | ||
name: "StringBuilder" | ||
), | ||
.testTarget( | ||
name: "StringBuilderTests", | ||
dependencies: [ | ||
"StringBuilder" | ||
] | ||
), | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,129 @@ | ||
# StringBuilder | ||
Build strings with resultBuilders | ||
|
||
<p align="center"> | ||
<img src="https://img.shields.io/badge/Swift-orange.svg" alt="Swift" /> | ||
<a href="https://swift.org/package-manager"> | ||
<img src="https://img.shields.io/badge/swiftpm-compatible-brightgreen.svg?style=flat" alt="Swift Package Manager" /> | ||
</a> | ||
</p> | ||
|
||
Welcome to **StringBuilder**, a Swift package for dynamically building strings | ||
using a `resultBuilder`. | ||
|
||
## Usage | ||
|
||
### Basic String Building | ||
To build a basic multi-line string: | ||
```swift | ||
String { | ||
"Line 1" | ||
"Line 2" | ||
} | ||
``` | ||
|
||
Becomes... | ||
```swift | ||
""" | ||
Line 1 | ||
Line 2 | ||
""" | ||
``` | ||
|
||
### Custom Separator | ||
A custom separator can be used to control how the strings are joined: | ||
```swift | ||
String(separator: " != ") { | ||
"String 1" | ||
"String 2" | ||
} | ||
``` | ||
|
||
Becomes... | ||
```swift | ||
"String 1 != String 2" | ||
``` | ||
|
||
### String Convertible Types | ||
Any type that conforms to `CustomStringConvertible` can be added to the | ||
string builder: | ||
```swift | ||
String { | ||
1234 | ||
true | ||
UUID() | ||
} | ||
``` | ||
|
||
Becomes... | ||
```swift | ||
1234 | ||
true | ||
3D5E76E1-CB1D-4FEF-A5CA-3C67AA08BF47 | ||
``` | ||
|
||
### Nested String Builders | ||
String builders can be nested with different separators at each level: | ||
```swift | ||
String { | ||
"One" | ||
|
||
String(separator: ".") { | ||
"Two" | ||
"Three" | ||
} | ||
|
||
"Four" | ||
|
||
String { | ||
String { | ||
"Five" | ||
|
||
String(separator: "\n\n") { | ||
"Six" | ||
"Seven" | ||
} | ||
|
||
"Eight" | ||
} | ||
|
||
"Nine" | ||
} | ||
|
||
"Ten" | ||
} | ||
``` | ||
|
||
Becomes... | ||
```swift | ||
One | ||
Two.Three | ||
Four | ||
Five | ||
Six | ||
|
||
Seven | ||
Eight | ||
Nine | ||
Ten | ||
``` | ||
|
||
## Installation | ||
|
||
StringBuilder is distributed using the [Swift Package Manager](https://swift.org/package-manager). To install it within another Swift package, add it as a dependency within your `Package.swift` manifest: | ||
|
||
```swift | ||
let package = Package( | ||
// . . . | ||
dependencies: [ | ||
.package(url: "https://github.com/mattcox/StringBuilder.git", branch: "main") | ||
], | ||
// . . . | ||
) | ||
``` | ||
|
||
If you’d like to use StringBuilder within an iOS, macOS, watchOS or tvOS app, then use Xcode’s `File > Add Packages...` menu command to add it to your project. | ||
|
||
Import `StringBuilder` wherever you’d like to use it: | ||
```swift | ||
import StringBuilder | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// | ||
// String+StringBuilder.swift | ||
// StringBuilder | ||
// | ||
// Created by Matt Cox on 13/08/2024. | ||
// Copyright © 2024 Matt Cox. All rights reserved. | ||
// | ||
|
||
extension String { | ||
/// Initialize a String from multiple Strings or string convertible types. | ||
/// | ||
/// A result builder allows the string to be composed from multiple types, | ||
/// and a separator can be specified to control how the strings are joined | ||
/// together. | ||
/// | ||
/// - Parameters: | ||
/// - separator: The separator to insert between each string. This | ||
/// defaults to a new line. | ||
/// - contents: A result builder that will be called to populate the | ||
/// string. | ||
/// | ||
/// **Example** | ||
/// ```swift | ||
/// String(separator: "\n\n") { | ||
/// "String" | ||
/// 1234 | ||
/// true | ||
/// } | ||
/// | ||
/// // String | ||
/// // | ||
/// // 1234 | ||
/// // | ||
/// // true | ||
/// ``` | ||
/// | ||
public init(separator: String = "\n", @StringBuilder _ contents: () -> [String]) { | ||
self = contents().joined(separator: separator) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// | ||
// StringBuilder.swift | ||
// StringBuilder | ||
// | ||
// Created by Matt Cox on 13/08/2024. | ||
// Copyright © 2024 Matt Cox. All rights reserved. | ||
// | ||
|
||
@resultBuilder | ||
public enum StringBuilder { | ||
public static func buildBlock() -> String { | ||
"" | ||
} | ||
} | ||
|
||
public extension StringBuilder { | ||
static func buildPartialBlock(first: CustomStringConvertible) -> [String] { | ||
[first.description] | ||
} | ||
|
||
static func buildPartialBlock(accumulated: [String], next: CustomStringConvertible) -> [String] { | ||
accumulated + [next.description] | ||
} | ||
|
||
static func buildPartialBlock(first: String) -> [String] { | ||
[first] | ||
} | ||
|
||
static func buildPartialBlock(accumulated: [String], next: String) -> [String] { | ||
accumulated + [next] | ||
} | ||
|
||
static func buildPartialBlock(first: [String]) -> [String] { | ||
first | ||
} | ||
|
||
static func buildPartialBlock(accumulated: [String], next: [String]) -> [String] { | ||
accumulated + next | ||
} | ||
} | ||
|
||
public extension StringBuilder { | ||
static func buildOptional(_ component: String?) -> [String] { | ||
if let component { | ||
return [component] | ||
} | ||
|
||
return [] | ||
} | ||
|
||
static func buildOptional(_ component: [String]?) -> [String] { | ||
component ?? [] | ||
} | ||
} | ||
|
||
public extension StringBuilder { | ||
static func buildEither(first component: [String]) -> [String] { | ||
component | ||
} | ||
|
||
static func buildEither(second component: [String]) -> [String] { | ||
component | ||
} | ||
} | ||
|
||
public extension StringBuilder { | ||
static func buildArray(_ components: [[String]]) -> [String] { | ||
components.flatMap { | ||
$0 | ||
} | ||
} | ||
} |
Oops, something went wrong.