Skip to content

Commit

Permalink
Support *class claster* pattern by CustomDecodable<T>.
Browse files Browse the repository at this point in the history
  • Loading branch information
es-kumagai committed Apr 26, 2016
1 parent 91fc16a commit 66f15c8
Show file tree
Hide file tree
Showing 3 changed files with 204 additions and 0 deletions.
18 changes: 18 additions & 0 deletions Himotoki.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@
objects = {

/* Begin PBXBuildFile section */
B1601CCA1CCEF5E80066002F /* CustomDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1601CC91CCEF5E80066002F /* CustomDecodable.swift */; };
B1601CCB1CCEF5E80066002F /* CustomDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1601CC91CCEF5E80066002F /* CustomDecodable.swift */; };
B1601CCC1CCEF5E80066002F /* CustomDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1601CC91CCEF5E80066002F /* CustomDecodable.swift */; };
B1601CCD1CCEF5E80066002F /* CustomDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1601CC91CCEF5E80066002F /* CustomDecodable.swift */; };
B1601CD31CCEF77A0066002F /* CustomDecodableTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1601CD21CCEF77A0066002F /* CustomDecodableTest.swift */; };
B1601CD41CCEF77A0066002F /* CustomDecodableTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1601CD21CCEF77A0066002F /* CustomDecodableTest.swift */; };
B1601CD51CCEF77A0066002F /* CustomDecodableTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1601CD21CCEF77A0066002F /* CustomDecodableTest.swift */; };
CD07B5231C8408A40065883E /* TransformerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC356901C819DE7004F6E47 /* TransformerTest.swift */; };
CD07B5241C8408A50065883E /* TransformerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC356901C819DE7004F6E47 /* TransformerTest.swift */; };
CD07B5251C8408A60065883E /* TransformerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC356901C819DE7004F6E47 /* TransformerTest.swift */; };
Expand Down Expand Up @@ -106,6 +113,8 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
B1601CC91CCEF5E80066002F /* CustomDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomDecodable.swift; sourceTree = "<group>"; };
B1601CD21CCEF77A0066002F /* CustomDecodableTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomDecodableTest.swift; sourceTree = "<group>"; };
CD181ED81AF4F7C20065963F /* Operators.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operators.swift; sourceTree = "<group>"; };
CD182A0F1C93CB640072E0B5 /* KeyPathTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyPathTest.swift; sourceTree = "<group>"; };
CD5E68F81BD766BE00417C84 /* DecodeErrorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DecodeErrorTest.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -341,6 +350,7 @@
isa = PBXGroup;
children = (
CD929A571AF4A915002F5C53 /* DecodableTest.swift */,
B1601CD21CCEF77A0066002F /* CustomDecodableTest.swift */,
CD5E68F81BD766BE00417C84 /* DecodeErrorTest.swift */,
CDBFDC641BF1F19200231C5D /* DecodeWithRootKeyPathTest.swift */,
CD182A0F1C93CB640072E0B5 /* KeyPathTest.swift */,
Expand All @@ -366,6 +376,7 @@
children = (
CD9ADBF81B00F8F600406AA5 /* Builder.swift */,
CD929A531AF4A488002F5C53 /* Decodable.swift */,
B1601CC91CCEF5E80066002F /* CustomDecodable.swift */,
CDC4E7861B0ACB42007F8F88 /* decode.swift */,
CD8620E21B914C60006DCCDC /* DecodeError.swift */,
CD929A551AF4A4C9002F5C53 /* Extractor.swift */,
Expand Down Expand Up @@ -672,6 +683,7 @@
CD8F0DCC1B6D014B0021196A /* Builder.swift in Sources */,
CD8F0DCD1B6D014B0021196A /* Operators.swift in Sources */,
CD8620E51B914C60006DCCDC /* DecodeError.swift in Sources */,
B1601CCC1CCEF5E80066002F /* CustomDecodable.swift in Sources */,
CD7450201BB7FC7B0092EED3 /* RawRepresentable.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -690,6 +702,7 @@
CD9ADBF91B00F8F600406AA5 /* Builder.swift in Sources */,
CD181ED91AF4F7C20065963F /* Operators.swift in Sources */,
CD8620E31B914C60006DCCDC /* DecodeError.swift in Sources */,
B1601CCA1CCEF5E80066002F /* CustomDecodable.swift in Sources */,
CD74501E1BB7FC7B0092EED3 /* RawRepresentable.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -700,6 +713,7 @@
files = (
CD929A581AF4A915002F5C53 /* DecodableTest.swift in Sources */,
CD7450221BB7FE900092EED3 /* RawRepresentableTest.swift in Sources */,
B1601CD31CCEF77A0066002F /* CustomDecodableTest.swift in Sources */,
CD5E68F91BD766BE00417C84 /* DecodeErrorTest.swift in Sources */,
CDD3962B1C0C0CD000A3A3DD /* NestedObjectParsingTest.swift in Sources */,
CDBFDC651BF1F19200231C5D /* DecodeWithRootKeyPathTest.swift in Sources */,
Expand All @@ -722,6 +736,7 @@
CDE423931BF2E9B000C9473F /* Builder.swift in Sources */,
CDE423941BF2E9B000C9473F /* Operators.swift in Sources */,
CDE423951BF2E9B000C9473F /* DecodeError.swift in Sources */,
B1601CCD1CCEF5E80066002F /* CustomDecodable.swift in Sources */,
CDE423961BF2E9B000C9473F /* RawRepresentable.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -732,6 +747,7 @@
files = (
CDE423B51BF2F0C200C9473F /* DecodeErrorTest.swift in Sources */,
CDE423B61BF2F0C600C9473F /* DecodeWithRootKeyPathTest.swift in Sources */,
B1601CD51CCEF77A0066002F /* CustomDecodableTest.swift in Sources */,
CDE423B41BF2F0BD00C9473F /* DecodableTest.swift in Sources */,
CDD3962D1C0C0CD000A3A3DD /* NestedObjectParsingTest.swift in Sources */,
CDE423B71BF2F0C900C9473F /* RawRepresentableTest.swift in Sources */,
Expand All @@ -754,6 +770,7 @@
CD9ADBFA1B00F8F600406AA5 /* Builder.swift in Sources */,
CDF03E4E1AF607650041C3AA /* Operators.swift in Sources */,
CD8620E41B914C60006DCCDC /* DecodeError.swift in Sources */,
B1601CCB1CCEF5E80066002F /* CustomDecodable.swift in Sources */,
CD74501F1BB7FC7B0092EED3 /* RawRepresentable.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -764,6 +781,7 @@
files = (
CDF03E4F1AF607A20041C3AA /* DecodableTest.swift in Sources */,
CD7450231BB7FE900092EED3 /* RawRepresentableTest.swift in Sources */,
B1601CD41CCEF77A0066002F /* CustomDecodableTest.swift in Sources */,
CD5E68FA1BD766BE00417C84 /* DecodeErrorTest.swift in Sources */,
CDD3962C1C0C0CD000A3A3DD /* NestedObjectParsingTest.swift in Sources */,
CDBFDC661BF1F19200231C5D /* DecodeWithRootKeyPathTest.swift in Sources */,
Expand Down
60 changes: 60 additions & 0 deletions Sources/CustomDecodable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// CustomDecodable.swift
// Himotoki
//
// Created by Tomohiro Kumagai on 4/26/16.
// Copyright © 2016 Syo Ikeda. All rights reserved.
//

public protocol CustomDecodableType {

associatedtype DecodeType

static func decode(e: Extractor) throws -> DecodeType
}

public struct CustomDecodable<T:CustomDecodableType> : Decodable {

private var _value: Any

private init(_ value: T.DecodeType) {

_value = value
}

public var value: T.DecodeType {

return _value as! T.DecodeType
}

public static func decode(e: Extractor) throws -> CustomDecodable {

return try CustomDecodable(T.decode(e))
}
}

// MARK: - Extensions

extension CustomDecodable : CustomStringConvertible {

public var description: String {

return String(_value)
}
}

extension CustomDecodable : CustomDebugStringConvertible {

public var debugDescription: String {

return String(reflecting: _value)
}
}

extension CustomDecodable : CustomPlaygroundQuickLookable {

public func customPlaygroundQuickLook() -> PlaygroundQuickLook {

return PlaygroundQuickLook(reflecting: _value)
}
}
126 changes: 126 additions & 0 deletions Tests/Himotoki/CustomDecodableTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//
// CustomDecodableTest.swift
// Himotoki
//
// Created by Tomohiro Kumagai on 4/26/16.
// Copyright © 2016 Syo Ikeda. All rights reserved.
//

import XCTest
import Himotoki

/// Using non final class Decodable #118

private class A: CustomDecodableType {
var type : Int = 0
var title: String = ""

init (e: Extractor) {
type = try! e <| "type"
title = try! e <| "title"
}

static func decode(e: Extractor) throws -> A {
let type : Int = try e <| "type"
switch type {
case 0:
return B(e: e)
case 1:
return C(e: e)
case 2:
return A(e: e)
default:
fatalError()
}
}
}

private class B: A {
var total : Double = 0.0
override init(e: Extractor) {
total = try! e <| "total"
super.init(e: e)
}
}

private class C: A {
var link : String = ""
override init(e: Extractor) {
link = try! e <| "link"
super.init(e: e)
}
}

class CustomDecodableTest: XCTestCase {

override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}

override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}

func testDecode() {

let json0: [String : AnyJSON] = [ "type" : 0, "title" : "TITLE 0", "total" : 0.5, "link" : "LINK 1" ]
let json1: [String : AnyJSON] = [ "type" : 1, "title" : "TITLE 1", "total" : 1.8, "link" : "LINK 2" ]
let json2: [String : AnyJSON] = [ "type" : 2, "title" : "TITLE 2", "total" : 2.3, "link" : "LINK 3" ]

let instance0 = try! decodeValue(json0) as CustomDecodable<A>
let instance1 = try! decodeValue(json1) as CustomDecodable<A>
let instance2 = try! decodeValue(json2) as CustomDecodable<A>

// Check `type` and `title`

XCTAssertEqual(instance0.value.type, 0)
XCTAssertEqual(instance0.value.title, "TITLE 0")

XCTAssertEqual(instance1.value.type, 1)
XCTAssertEqual(instance1.value.title, "TITLE 1")

XCTAssertEqual(instance2.value.type, 2)
XCTAssertEqual(instance2.value.title, "TITLE 2")

// Check Inheritance

XCTAssertTrue(instance0.value is B)
XCTAssertFalse(instance0.value is C)

XCTAssertFalse(instance1.value is B)
XCTAssertTrue(instance1.value is C)

XCTAssertFalse(instance2.value is B)
XCTAssertFalse(instance2.value is C)

XCTAssertEqual(String(instance0.value.dynamicType), String(B.self))
XCTAssertNotEqual(String(instance0.value.dynamicType), String(A.self))
XCTAssertNotEqual(String(instance0.value.dynamicType), String(C.self))

XCTAssertEqual(String(instance1.value.dynamicType), String(C.self))
XCTAssertNotEqual(String(instance1.value.dynamicType), String(A.self))
XCTAssertNotEqual(String(instance1.value.dynamicType), String(B.self))

XCTAssertEqual(String(instance2.value.dynamicType), String(A.self))
XCTAssertNotEqual(String(instance2.value.dynamicType), String(B.self))
XCTAssertNotEqual(String(instance2.value.dynamicType), String(C.self))

let b0 = instance0.value as? B
let b1 = instance1.value as? B
let b2 = instance2.value as? B

let c0 = instance0.value as? C
let c1 = instance1.value as? C
let c2 = instance2.value as? C

XCTAssertEqual(b0?.total, 0.5)
XCTAssertEqual(b1?.total, nil)
XCTAssertEqual(b2?.total, nil)

XCTAssertEqual(c0?.link, nil)
XCTAssertEqual(c1?.link, "LINK 2")
XCTAssertEqual(c2?.link, nil)
}
}

0 comments on commit 66f15c8

Please sign in to comment.