Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Multi-Attribute Strings #6

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,35 @@ let builder = NSAttributedStringAttributeBuilder()
builder.setAttribute(.Font(UIFont(name: "HelveticaNeue", size: 18)!))
builder.setAttribute(NSAttributedStringAttribute.Kerning(1))

let attString = NSAttributedString(string: string, attributes: builder.attributedStringAttributesDictionary())
let attString = NSAttributedString(string: string, attributes: builder.currentAttributes)

```

###Creating strings with multiple attributes for ranges

```Swift
let attributedString = NSAttributedString.make(make: { (make: NSAttributedStringAttributeBuilder) -> Void in
make.nextString("This is a regular string")
make.setAttribute(.Font(UIFont.systemFontOfSize(20)))
make.nextString("This is a bold string")
make.setAttribute(.Font(UIFont.boldSystemFontOfSize(20)))
make.clearAttributesOnNextString = true
make.nextString("This is a default string")
})
```

###Available builder methods

```Swift
builder.setAttribute(attribute: NSAttributedStringAttribute)
builder.clearAttributes()
builder.addAttributes(attributes: [String: AnyObject])
builder.removeAttribute(attribute: NSAttributedStringAttribute)
builder.removeAttributes(attributes: [String: AnyObject])
builder.nextString(string: String)
builder.clearAttributesOnNextString = Bool (Default is false)
```

###Tests
Verona is currently unit tested using FBSnapshotTestCase for all cases. To run the unit tests, be sure to run cocoapods first.
Test results can be found here: https://github.com/SRandazzo/Verona/tree/master/VeronaTests/ReferenceImages/VeronaTests.VeronaTests
Expand Down
74 changes: 68 additions & 6 deletions Verona/Verona.swift
Original file line number Diff line number Diff line change
Expand Up @@ -102,25 +102,87 @@ public enum NSAttributedStringAttribute {

public class NSAttributedStringAttributeBuilder {

private var attributesDictionary: [String : AnyObject] = [ : ]
private var clearAttributesOnNextString: Bool = false

private var currentString: String = ""
private var strings = [String]()

var currentAttributes: [String : AnyObject] = [ : ]
var attributes = [[String: AnyObject]]()

public init() { }

public func setAttribute(attribute: NSAttributedStringAttribute) {
// Builder functions

public func setAttribute(attribute: NSAttributedStringAttribute) throws {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why this function throws?

let keyValuePair = attribute.attributedStringKeyValuePair
attributesDictionary.updateValue(keyValuePair.value, forKey: keyValuePair.key)
currentAttributes.updateValue(keyValuePair.value, forKey: keyValuePair.key)
}

public func attributedStringAttributesDictionary() -> [String: AnyObject]? {
return attributesDictionary
public func clearAttributes() {
currentAttributes.removeAll()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add test coverage for this function

}

public func addAttributes(attributes: [String: AnyObject]) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially we should rename this to updateCurrentAttributes as it will replace existing attributes, and also only applies to the current nextString

for (key, value) in attributes {
currentAttributes.updateValue(value, forKey: key)
}
}

public func removeAttribute(attribute: NSAttributedStringAttribute) throws {
let keyValuePair = attribute.attributedStringKeyValuePair
currentAttributes.removeValueForKey(keyValuePair.key)
}

public func removeAttributes(attributes: [String: AnyObject]) {
for (key, _) in attributes {
currentAttributes.removeValueForKey(key)
}
}

public func nextString(string: String) {
endCurrent()
currentString = string
}


// Internal helpers

private func endCurrent() {
attributes.append(currentAttributes)
strings.append(currentString)
if (clearAttributesOnNextString) {
clearAttributes()
}
currentString = ""
}

private func finalize() -> NSAttributedString {
let attrStrings = zip(strings, attributes)
.map { (str: String, attr: [String: AnyObject]) in
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow cool use of zip, learned something new today 😎

return NSAttributedString(string: str, attributes: attr)
}

// TODO: Get reduce to work instead of whats below. Was showing ambiguous errors with mutable string as accumulator
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not 100% sure if reduce will work

what about something like this to encapsulate the logic

        let finalString: NSAttributedString = {
            let mut = NSMutableAttributedString()
            attrStrings.forEach{ mut.appendAttributedString($0) }
            return NSAttributedString(attributedString: mut)
        }()

        return finalString

let mut = NSMutableAttributedString()
for attr in attrStrings {
mut.appendAttributedString(attr)
}
return mut
}
}

public extension NSAttributedString {

public class func make(string: String, make: ((make: NSAttributedStringAttributeBuilder) -> Void)) -> NSAttributedString {
let builder = NSAttributedStringAttributeBuilder()
builder.nextString(string)
make(make: builder)
return NSAttributedString(string: string, attributes: builder.attributedStringAttributesDictionary())
return builder.finalize()
}

public class func make(make: ((make: NSAttributedStringAttributeBuilder) -> Void)) -> NSAttributedString {
let builder = NSAttributedStringAttributeBuilder()
return builder.finalize()
}
}