Skip to content

Commit

Permalink
Support Implicit Member Expression for Key #9 #13
Browse files Browse the repository at this point in the history
  • Loading branch information
nmdias committed Jun 10, 2018
1 parent 32a4564 commit 4dee17b
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 45 deletions.
16 changes: 16 additions & 0 deletions DefaultsKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@
A0AC4AAF1F43853D0070F91D /* DefaultsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0AC4AAE1F43853D0070F91D /* DefaultsTests.swift */; };
A0AC4AB11F43853D0070F91D /* DefaultsKit.h in Headers */ = {isa = PBXBuildFile; fileRef = A0AC4AA31F43853D0070F91D /* DefaultsKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
A0AC4ABB1F4385500070F91D /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0AC4ABA1F4385500070F91D /* Defaults.swift */; };
A0DFDB0A20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0920CD8C4E004A4C2F /* DefaultsKey + keys.swift */; };
A0DFDB0B20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0920CD8C4E004A4C2F /* DefaultsKey + keys.swift */; };
A0DFDB0C20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0920CD8C4E004A4C2F /* DefaultsKey + keys.swift */; };
A0DFDB0E20CD8C58004A4C2F /* PersonMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0D20CD8C58004A4C2F /* PersonMock.swift */; };
A0DFDB0F20CD8C58004A4C2F /* PersonMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0D20CD8C58004A4C2F /* PersonMock.swift */; };
A0DFDB1020CD8C58004A4C2F /* PersonMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0DFDB0D20CD8C58004A4C2F /* PersonMock.swift */; };
A0F000F61F48CEE500617715 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0AC4ABA1F4385500070F91D /* Defaults.swift */; };
A0F001041F48CF9D00617715 /* Defaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0AC4ABA1F4385500070F91D /* Defaults.swift */; };
A0F0011E1F48D0BD00617715 /* DefaultsKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A0F000E91F48CECE00617715 /* DefaultsKit.framework */; };
Expand Down Expand Up @@ -51,6 +57,8 @@
A0AC4AAE1F43853D0070F91D /* DefaultsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultsTests.swift; sourceTree = "<group>"; };
A0AC4AB01F43853D0070F91D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A0AC4ABA1F4385500070F91D /* Defaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Defaults.swift; sourceTree = "<group>"; };
A0DFDB0920CD8C4E004A4C2F /* DefaultsKey + keys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DefaultsKey + keys.swift"; sourceTree = "<group>"; };
A0DFDB0D20CD8C58004A4C2F /* PersonMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersonMock.swift; sourceTree = "<group>"; };
A0F000E91F48CECE00617715 /* DefaultsKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DefaultsKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A0F000FC1F48CF8200617715 /* DefaultsKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DefaultsKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A0F001191F48D0BD00617715 /* DefaultsKit macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "DefaultsKit macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -141,8 +149,10 @@
A0AC4AAD1F43853D0070F91D /* Tests */ = {
isa = PBXGroup;
children = (
A0DFDB0920CD8C4E004A4C2F /* DefaultsKey + keys.swift */,
A0AC4AAE1F43853D0070F91D /* DefaultsTests.swift */,
A0AC4AB01F43853D0070F91D /* Info.plist */,
A0DFDB0D20CD8C58004A4C2F /* PersonMock.swift */,
);
path = Tests;
sourceTree = "<group>";
Expand Down Expand Up @@ -396,6 +406,8 @@
buildActionMask = 2147483647;
files = (
A0AC4AAF1F43853D0070F91D /* DefaultsTests.swift in Sources */,
A0DFDB0A20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */,
A0DFDB0E20CD8C58004A4C2F /* PersonMock.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -420,6 +432,8 @@
buildActionMask = 2147483647;
files = (
A0F001271F48D12900617715 /* DefaultsTests.swift in Sources */,
A0DFDB0C20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */,
A0DFDB1020CD8C58004A4C2F /* PersonMock.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -428,6 +442,8 @@
buildActionMask = 2147483647;
files = (
A0F001381F48D35700617715 /* DefaultsTests.swift in Sources */,
A0DFDB0B20CD8C4F004A4C2F /* DefaultsKey + keys.swift in Sources */,
A0DFDB0F20CD8C58004A4C2F /* PersonMock.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@ if defaults.has(key) {
```
> If you just need to know that a key/value pair exists, **without actually using the value**, use the `has()` method instead of the optional `get(for:key)`. For complex objects it will prevent any unnecessary deserialization.
### Implicit Member Expression

You can find a convenience wrapper for your keys by extending `DefaultsKey`. This allows you use [Implicit Member Expression](https://docs.swift.org/swift-book/ReferenceManual/Expressions.html#//appleref/swift/grammar/implicit-member-expression):
```swift
// Extend with a custom key
extension DefaultsKey {
static let someKey = Key<String>("someKey")
}

// Then use it like this
defaults.set("Some key", for: .someKey)
defaults.get(for: .someKey) // Output: Some key
```

### Complex objects

To store a complex object just conform to the [Codable](https://developer.apple.com/documentation/swift/codable) protocol:
Expand Down
4 changes: 3 additions & 1 deletion Sources/Defaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@

import Foundation

public class DefaultsKey {}

/// Represents a `Key` with an associated generic value type conforming to the
/// `Codable` protocol.
///
/// static let someKey = Key<ValueType>("someKey")
public final class Key<ValueType: Codable> {
public final class Key<ValueType: Codable>: DefaultsKey {
fileprivate let _key: String
public init(_ key: String) {
_key = key
Expand Down
21 changes: 21 additions & 0 deletions Tests/DefaultsKey + keys.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// DefaultsKey + keys.swift
// DefaultsKit
//
// Created by Nuno Dias on 10/06/2018.
// Copyright © 2018 Nuno Dias. All rights reserved.
//

import Foundation
@testable import DefaultsKit

extension DefaultsKey {
static let integerKey = Key<Int>("integerKey")
static let floatKey = Key<Float>("floatKey")
static let doubleKey = Key<Double>("doubleKey")
static let stringKey = Key<String>("stringKey")
static let boolKey = Key<Bool>("boolKey")
static let dateKey = Key<Date>("dateKey")
static let arrayOfIntegersKey = Key<[Int]>("arrayOfIntegersKey")
static let personMockKey = Key<PersonMock>("personMockKey")
}
72 changes: 28 additions & 44 deletions Tests/DefaultsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,15 @@ class DefaultsKitTests: XCTestCase {

// Given
let value = 123
let key = Key<Int>("key")

// When
defaults.set(value, for: key)
defaults.set(value, for: .integerKey)

// Then
let hasKey = defaults.has(key)
let hasKey = defaults.has(.integerKey)
XCTAssertTrue(hasKey)

let savedValue = defaults.get(for: key)
let savedValue = defaults.get(for: .integerKey)
XCTAssertEqual(savedValue, value)

}
Expand All @@ -61,16 +60,15 @@ class DefaultsKitTests: XCTestCase {

// Given
let value: Float = 123.1
let key = Key<Float>("key")

// When
defaults.set(value, for: key)
defaults.set(value, for: .floatKey)

// Then
let hasKey = defaults.has(key)
let hasKey = defaults.has(.floatKey)
XCTAssertTrue(hasKey)

let savedValue = defaults.get(for: key)
let savedValue = defaults.get(for: .floatKey)
XCTAssertEqual(savedValue, value)

}
Expand All @@ -79,16 +77,15 @@ class DefaultsKitTests: XCTestCase {

// Given
let value: Double = 123.1
let key = Key<Double>("key")

// When
defaults.set(value, for: key)
defaults.set(value, for: .doubleKey)

// Then
let hasKey = defaults.has(key)
let hasKey = defaults.has(.doubleKey)
XCTAssertTrue(hasKey)

let savedValue = defaults.get(for: key)
let savedValue = defaults.get(for: .doubleKey)
XCTAssertEqual(savedValue, value)

}
Expand All @@ -97,16 +94,15 @@ class DefaultsKitTests: XCTestCase {

// Given
let value = "a string"
let key = Key<String>("key")

// When
defaults.set(value, for: key)
defaults.set(value, for: .stringKey)

// Then
let hasKey = defaults.has(key)
let hasKey = defaults.has(.stringKey)
XCTAssertTrue(hasKey)

let savedValue = defaults.get(for: key)
let savedValue = defaults.get(for: .stringKey)
XCTAssertEqual(savedValue, value)

}
Expand All @@ -115,16 +111,15 @@ class DefaultsKitTests: XCTestCase {

// Given
let value = true
let key = Key<Bool>("key")

// When
defaults.set(value, for: key)
defaults.set(value, for: .boolKey)

// Then
let hasKey = defaults.has(key)
let hasKey = defaults.has(.boolKey)
XCTAssertTrue(hasKey)

let savedValue = defaults.get(for: key)
let savedValue = defaults.get(for: .boolKey)
XCTAssertEqual(savedValue, value)

}
Expand All @@ -133,16 +128,15 @@ class DefaultsKitTests: XCTestCase {

// Given
let value = Date()
let key = Key<Date>("key")

// When
defaults.set(value, for: key)
defaults.set(value, for: .dateKey)

// Then
let hasKey = defaults.has(key)
let hasKey = defaults.has(.dateKey)
XCTAssertTrue(hasKey)

let savedValue = defaults.get(for: key)
let savedValue = defaults.get(for: .dateKey)
XCTAssertEqual(savedValue, value)

}
Expand All @@ -151,16 +145,15 @@ class DefaultsKitTests: XCTestCase {

// Given
let values = [1,2,3,4]
let key = Key<[Int]>("key")

// When
defaults.set(values, for: key)
defaults.set(values, for: .arrayOfIntegersKey)

// Then
let hasKey = defaults.has(key)
let hasKey = defaults.has(.arrayOfIntegersKey)
XCTAssertTrue(hasKey)

let savedValues = defaults.get(for: key)
let savedValues = defaults.get(for: .arrayOfIntegersKey)
XCTAssertNotNil(savedValues)
savedValues?.forEach({ (value) in
XCTAssertTrue(savedValues?.contains(value) ?? false)
Expand All @@ -172,43 +165,34 @@ class DefaultsKitTests: XCTestCase {

// Given
let values = [1,2,3,4]
let key = Key<[Int]>("key")

// When
defaults.set(values, for: key)
defaults.clear(key)
defaults.set(values, for: .arrayOfIntegersKey)
defaults.clear(.arrayOfIntegersKey)

// Then
let hasKey = defaults.has(key)
let hasKey = defaults.has(.arrayOfIntegersKey)
XCTAssertFalse(hasKey)

let savedValues = defaults.get(for: key)
let savedValues = defaults.get(for: .arrayOfIntegersKey)
XCTAssertNil(savedValues)

}

func testSetObject() {

// Mocks
struct PersonMock: Codable {
let name: String
let age: Int
let children: [PersonMock]
}

// Given
let child = PersonMock(name: "Anne Greenwell", age: 30, children: [])
let person = PersonMock(name: "Bonnie Greenwell", age: 80, children: [child])
let key = Key<PersonMock>("personKey")

// When
defaults.set(person, for: key)
defaults.set(person, for: .personMockKey)

// Then
let hasKey = defaults.has(key)
let hasKey = defaults.has(.personMockKey)
XCTAssertTrue(hasKey)

let savedPerson = defaults.get(for: key)
let savedPerson = defaults.get(for: .personMockKey)
XCTAssertEqual(savedPerson?.name, "Bonnie Greenwell")
XCTAssertEqual(savedPerson?.age, 80)
XCTAssertEqual(savedPerson?.children.first?.name, "Anne Greenwell")
Expand Down
15 changes: 15 additions & 0 deletions Tests/PersonMock.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// PersonMock.swift
// DefaultsKit
//
// Created by Nuno Dias on 10/06/2018.
// Copyright © 2018 Nuno Dias. All rights reserved.
//

import Foundation

struct PersonMock: Codable {
let name: String
let age: Int
let children: [PersonMock]
}

0 comments on commit 4dee17b

Please sign in to comment.