Skip to content

Commit 3951ee4

Browse files
authored
result builder (#53)
1 parent 295b17e commit 3951ee4

8 files changed

+145
-2
lines changed

Package.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// swift-tools-version:5.1
1+
// swift-tools-version:5.4
22

33
import PackageDescription
44

SwiftyAttributes.podspec

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ Pod::Spec.new do |s|
2626
s.tvos.deployment_target = '9.0'
2727
s.watchos.deployment_target = '2.0'
2828

29-
s.swift_versions = ['5.0', '5.1']
29+
s.swift_versions = ['5.0', '5.1', '5.4']
3030
end

SwiftyAttributes.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
9E04C4D126EA09A5009BA429 /* SwiftyAttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04C4D026EA09A5009BA429 /* SwiftyAttributedStringBuilder.swift */; };
1011
9E0DA889229B2F8600E29BFD /* UIKit+SwiftyAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E0DA888229B2F8600E29BFD /* UIKit+SwiftyAttributes.swift */; };
1112
9E0DA88E229B34D800E29BFD /* UIKit+SwiftyAttributes_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E0DA88D229B34D800E29BFD /* UIKit+SwiftyAttributes_Tests.swift */; };
1213
9E28077022A424320097CE8A /* NSString+macOS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E28076F22A424320097CE8A /* NSString+macOS.swift */; };
@@ -74,6 +75,7 @@
7475
/* End PBXContainerItemProxy section */
7576

7677
/* Begin PBXFileReference section */
78+
9E04C4D026EA09A5009BA429 /* SwiftyAttributedStringBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftyAttributedStringBuilder.swift; path = common/SwiftyAttributedStringBuilder.swift; sourceTree = "<group>"; };
7779
9E0DA888229B2F8600E29BFD /* UIKit+SwiftyAttributes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIKit+SwiftyAttributes.swift"; sourceTree = "<group>"; };
7880
9E0DA88D229B34D800E29BFD /* UIKit+SwiftyAttributes_Tests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIKit+SwiftyAttributes_Tests.swift"; sourceTree = "<group>"; };
7981
9E28076F22A424320097CE8A /* NSString+macOS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSString+macOS.swift"; sourceTree = "<group>"; };
@@ -249,6 +251,7 @@
249251
9EB6D1A222A1CAC200D00CFC /* NSString+SwiftyAttributes.swift */,
250252
C05082241DFA72F700D39B3B /* Operators.swift */,
251253
C05082251DFA72F700D39B3B /* String+SwiftyAttributes.swift */,
254+
9E04C4D026EA09A5009BA429 /* SwiftyAttributedStringBuilder.swift */,
252255
C05082261DFA72F700D39B3B /* TextEffect.swift */,
253256
C05082271DFA72F700D39B3B /* VerticalGlyphForm.swift */,
254257
C05082281DFA72F700D39B3B /* WritingDirection.swift */,
@@ -479,6 +482,7 @@
479482
isa = PBXSourcesBuildPhase;
480483
buildActionMask = 2147483647;
481484
files = (
485+
9E04C4D126EA09A5009BA429 /* SwiftyAttributedStringBuilder.swift in Sources */,
482486
C050822A1DFA72F700D39B3B /* Attribute.swift in Sources */,
483487
C050822F1DFA72F700D39B3B /* Operators.swift in Sources */,
484488
C050822E1DFA72F700D39B3B /* NSMutableAttributedString+SwiftyAttributes.swift in Sources */,

SwiftyAttributes/Sources/common/NSAttributedString+SwiftyAttributes.swift

+26
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ extension NSAttributedString {
2828
self.init(string: str, attributes: dictionary(from: attrs))
2929
}
3030

31+
#if swift(>=5.4)
32+
/**
33+
Creates a new `NSAttributedString` with the specified attributes.
34+
35+
- parameter str: The string for the new attributed string.
36+
- parameter swiftyAttributes: The attributes for the new attributed string.
37+
*/
38+
public convenience init(string str: String, @SwiftyAttributedStringBuilder swiftyAttributes attrs: () -> [NSAttributedString.Key: Any]) {
39+
self.init(string: str, attributes: attrs())
40+
}
41+
#endif
42+
3143
/**
3244
Returns an attributed string with the specified attributes added.
3345

@@ -40,6 +52,20 @@ extension NSAttributedString {
4052
return mutable
4153
}
4254

55+
#if swift(>=5.4)
56+
/**
57+
Returns an attributed string with the specified attributes added.
58+
59+
- parameter attributes: The attributes to add to the new attributed string.
60+
- returns: An `NSMutableAttributedString` with the new attributes applied.
61+
*/
62+
public func withAttributes(@SwiftyAttributedStringBuilder _ attributes: () -> [NSAttributedString.Key: Any]) -> NSMutableAttributedString {
63+
let mutable = mutableCopy() as! NSMutableAttributedString
64+
mutable.addAttributes(attributes(), range: NSRange(location: 0, length: length))
65+
return mutable
66+
}
67+
#endif
68+
4369
/**
4470
Returns an attributed string with the specified attribute added.
4571

SwiftyAttributes/Sources/common/String+SwiftyAttributes.swift

+12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ extension String {
2020
return attributedString.withAttributes(attributes)
2121
}
2222

23+
#if swift(>=5.4)
24+
/**
25+
Returns an attributed string with the specified attributes added.
26+
27+
- parameter attributes: The attributes to add to the new attributed string.
28+
- returns: An `NSMutableAttributedString` with the new attributes applied.
29+
*/
30+
public func withAttributes(@SwiftyAttributedStringBuilder _ attributes: () -> [NSAttributedString.Key: Any]) -> NSMutableAttributedString {
31+
return attributedString.withAttributes(attributes)
32+
}
33+
#endif
34+
2335
/**
2436
Returns an attributed string with the specified attribute added.
2537

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// SwiftyAttributedStringBuilder.swift
3+
// SwiftyAttributes
4+
//
5+
// Created by Roman Podymov on 09/09/21.
6+
// Copyright © 2021 Roman Podymov. All rights reserved.
7+
//
8+
9+
#if swift(>=5.4)
10+
import Foundation
11+
12+
public protocol AttributesProvider {
13+
var attributes: [Attribute] { get }
14+
}
15+
16+
extension Attribute: AttributesProvider {
17+
public var attributes: [Attribute] { [self] }
18+
}
19+
20+
extension Array: AttributesProvider where Element == Attribute {
21+
public var attributes: [Attribute] { self }
22+
}
23+
24+
@resultBuilder
25+
public struct SwiftyAttributedStringBuilder {
26+
public static func buildBlock(_ components: AttributesProvider...) -> [Attribute] {
27+
components.flatMap { $0.attributes }
28+
}
29+
30+
public static func buildEither(first components: [AttributesProvider]) -> [Attribute] {
31+
components.flatMap { $0.attributes }
32+
}
33+
34+
public static func buildEither(second components: [AttributesProvider]) -> [Attribute] {
35+
components.flatMap { $0.attributes }
36+
}
37+
38+
public static func buildOptional(_ components: [Attribute]?) -> [Attribute] {
39+
components?.flatMap { $0.attributes } ?? []
40+
}
41+
42+
public static func buildFinalResult(_ components: [Attribute]) -> [NSAttributedString.Key: Any] {
43+
dictionary(from: components)
44+
}
45+
}
46+
#endif

SwiftyAttributesTests/NSAttributedString_Tests.swift

+36
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,42 @@ class NSAttributedString_Tests: XCTestCase {
1717
XCTAssertEqual(subject, expected)
1818
}
1919

20+
#if swift(>=5.4)
21+
func testInit_withSwiftyAttributedStringBuilder() {
22+
let shouldAddStrokeWidth = true
23+
let subject = NSAttributedString(string: "Hello World") {
24+
Attribute.strokeColor(.green)
25+
if let link = URL(string: "").map { Attribute.link($0) } {
26+
link
27+
}
28+
if shouldAddStrokeWidth {
29+
Attribute.strokeWidth(3)
30+
} else {
31+
Attribute.strokeColor(.yellow)
32+
}
33+
}
34+
let expected = NSAttributedString(string: "Hello World", attributes: [.strokeColor: Color.green, .strokeWidth: 3])
35+
XCTAssertEqual(subject, expected)
36+
}
37+
38+
func testWithAttributes_SwiftyAttributedStringBuilder() {
39+
let shouldAddStrokeWidth = true
40+
let subject = NSAttributedString(string: "Hello World").withAttributes {
41+
Attribute.strokeColor(.green)
42+
if let link = URL(string: "").map { Attribute.link($0) } {
43+
link
44+
}
45+
if shouldAddStrokeWidth {
46+
Attribute.strokeWidth(3)
47+
} else {
48+
Attribute.strokeColor(.yellow)
49+
}
50+
}
51+
let expected = NSAttributedString(string: "Hello World", attributes: [.strokeColor: Color.green, .strokeWidth: 3])
52+
XCTAssertEqual(subject, expected)
53+
}
54+
#endif
55+
2056
func testSubstringFromRange() {
2157
let str = "Hello".withStrikethroughColor(.blue).withUnderlineStyle(.patternDash)
2258
str.addAttributes([.backgroundColor(.brown)], range: 0 ..< 3)

SwiftyAttributesTests/SwiftyAttributes_Tests.swift

+19
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,25 @@ import SwiftyAttributes
1111

1212
class SwiftyAttributesTests: XCTestCase {
1313

14+
#if swift(>=5.4)
15+
func testString_withAttributes_SwiftyAttributedStringBuilder() {
16+
let shouldAddStrokeWidth = true
17+
let subject = "Hello".withAttributes {
18+
Attribute.strokeColor(.green)
19+
if let link = URL(string: "").map { Attribute.link($0) } {
20+
link
21+
}
22+
if shouldAddStrokeWidth {
23+
Attribute.strokeWidth(3)
24+
} else {
25+
Attribute.strokeColor(.yellow)
26+
}
27+
}
28+
let expected = NSAttributedString(string: "Hello", attributes: [.strokeColor: Color.green, .strokeWidth: 3])
29+
XCTAssertEqual(subject, expected)
30+
}
31+
#endif
32+
1433
func testString_withAttribute() {
1534
let subject = "Hello".withAttribute(.strokeWidth(4))
1635
let expected = NSAttributedString(string: "Hello", attributes: [.strokeWidth: NSNumber(value: 4)])

0 commit comments

Comments
 (0)