Skip to content

Commit a494500

Browse files
NSCoding generator
1 parent 11f1a51 commit a494500

File tree

4 files changed

+169
-0
lines changed

4 files changed

+169
-0
lines changed

CodeGenerator.xcodeproj/project.pbxproj

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@
5151
A07FE2781E106D5C00809837 /* FuncMocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A01E469F1E105EE900395AED /* FuncMocker.swift */; };
5252
A07FE2791E107AA900809837 /* InterfaceMocker.swift in Sources */ = {isa = PBXBuildFile; fileRef = A01E46821E0FF78300395AED /* InterfaceMocker.swift */; };
5353
A07FE2821E108D6900809837 /* InterfaceMockerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A07FE2811E108D6900809837 /* InterfaceMockerTests.swift */; };
54+
A083A3851ED45DD500C9B024 /* CodingGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A083A3841ED45DD500C9B024 /* CodingGenerator.swift */; };
55+
A083A3861ED45DD900C9B024 /* CodingGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A083A3841ED45DD500C9B024 /* CodingGenerator.swift */; };
56+
A083A3B31ED6DC2400C9B024 /* GeneratedNSCoder.txt in Resources */ = {isa = PBXBuildFile; fileRef = A083A3B21ED6DC2400C9B024 /* GeneratedNSCoder.txt */; };
57+
A083A3B51ED6E17D00C9B024 /* NSCodingGeneratorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A083A3B41ED6E17D00C9B024 /* NSCodingGeneratorTest.swift */; };
5458
A08C585B1E13C5AA00034B76 /* ClosureType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08C585A1E13C5AA00034B76 /* ClosureType.swift */; };
5559
A08C585C1E13C5AA00034B76 /* ClosureType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08C585A1E13C5AA00034B76 /* ClosureType.swift */; };
5660
A08C585E1E13CB8300034B76 /* SwiftType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A08C585D1E13CB8300034B76 /* SwiftType.swift */; };
@@ -153,6 +157,9 @@
153157
A0636FD91E1299A80008CE98 /* GeneratedEquals.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GeneratedEquals.txt; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
154158
A07FE2761E106CFE00809837 /* FuncMockTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FuncMockTests.swift; sourceTree = "<group>"; };
155159
A07FE2811E108D6900809837 /* InterfaceMockerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterfaceMockerTests.swift; sourceTree = "<group>"; };
160+
A083A3841ED45DD500C9B024 /* CodingGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodingGenerator.swift; sourceTree = "<group>"; };
161+
A083A3B21ED6DC2400C9B024 /* GeneratedNSCoder.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GeneratedNSCoder.txt; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
162+
A083A3B41ED6E17D00C9B024 /* NSCodingGeneratorTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSCodingGeneratorTest.swift; sourceTree = "<group>"; };
156163
A08C585A1E13C5AA00034B76 /* ClosureType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ClosureType.swift; sourceTree = "<group>"; };
157164
A08C585D1E13CB8300034B76 /* SwiftType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftType.swift; sourceTree = "<group>"; };
158165
A0A02CC21E1A60EA001900DC /* Generator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Generator.swift; sourceTree = "<group>"; };
@@ -276,12 +283,14 @@
276283
A0A82AEE1E11676B00F27EA3 /* SwiftTypeTests.swift */,
277284
A0636FD51E1299100008CE98 /* EquatableGeneratorTests.swift */,
278285
A0A02CC61E1A6868001900DC /* HashableGeneratorTest.swift */,
286+
A083A3B41ED6E17D00C9B024 /* NSCodingGeneratorTest.swift */,
279287
A031BD3F1E8D191E003235D5 /* InitGeneratorTests.swift */,
280288
A0A82AEA1E1159C200F27EA3 /* NSObject+file.swift */,
281289
A0A82AE61E11571200F27EA3 /* interface1.txt */,
282290
A0A82AE81E11593800F27EA3 /* interface1Mock.txt */,
283291
A03920701E0F3A7B005A6E89 /* Info.plist */,
284292
A0636FD71E12997C0008CE98 /* EquatableClazz.txt */,
293+
A083A3B21ED6DC2400C9B024 /* GeneratedNSCoder.txt */,
285294
A0636FD91E1299A80008CE98 /* GeneratedEquals.txt */,
286295
A031BD3D1E8D187C003235D5 /* GeneratedInit.txt */,
287296
A0A02CC81E1A68D8001900DC /* GeneratedHash.txt */,
@@ -334,6 +343,7 @@
334343
A0636FD31E1294650008CE98 /* EquatableGenerator.swift */,
335344
A0A02CC41E1A616C001900DC /* HashableGenerator.swift */,
336345
A031BD3A1E8D11D6003235D5 /* InitGenerator.swift */,
346+
A083A3841ED45DD500C9B024 /* CodingGenerator.swift */,
337347
);
338348
name = Generator;
339349
sourceTree = "<group>";
@@ -462,6 +472,7 @@
462472
A0636FDA1E1299A80008CE98 /* GeneratedEquals.txt in Resources */,
463473
A0A82AE71E11571200F27EA3 /* interface1.txt in Resources */,
464474
A0636FD81E12997C0008CE98 /* EquatableClazz.txt in Resources */,
475+
A083A3B31ED6DC2400C9B024 /* GeneratedNSCoder.txt in Resources */,
465476
A031BD3E1E8D187C003235D5 /* GeneratedInit.txt in Resources */,
466477
A04453D31E156A080063CB99 /* funcMock.txt in Resources */,
467478
);
@@ -497,6 +508,7 @@
497508
A031BD411E8D19E9003235D5 /* InitGenerator.swift in Sources */,
498509
A07FE2791E107AA900809837 /* InterfaceMocker.swift in Sources */,
499510
A0A82B1D1E127F1000F27EA3 /* AccessLevel.swift in Sources */,
511+
A083A3861ED45DD900C9B024 /* CodingGenerator.swift in Sources */,
500512
A08C585E1E13CB8300034B76 /* SwiftType.swift in Sources */,
501513
A0636FDB1E129B3E0008CE98 /* EquatableGenerator.swift in Sources */,
502514
A0A02CCA1E1A6A16001900DC /* HashableGenerator.swift in Sources */,
@@ -514,6 +526,7 @@
514526
A0A82AEF1E11676B00F27EA3 /* SwiftTypeTests.swift in Sources */,
515527
A0A02CC71E1A6868001900DC /* HashableGeneratorTest.swift in Sources */,
516528
A0636FD61E1299100008CE98 /* EquatableGeneratorTests.swift in Sources */,
529+
A083A3B51ED6E17D00C9B024 /* NSCodingGeneratorTest.swift in Sources */,
517530
A01E467E1E0FE57A00395AED /* InterfaceSignatureTests.swift in Sources */,
518531
A01E46911E1017F100395AED /* FuncSignatureTests.swift in Sources */,
519532
A07FE2771E106CFE00809837 /* FuncMockTests.swift in Sources */,
@@ -543,6 +556,7 @@
543556
A031BD3B1E8D11D6003235D5 /* InitGenerator.swift in Sources */,
544557
A0A82B1A1E127BEE00F27EA3 /* AccessLevel.swift in Sources */,
545558
A031BD451E8D2B19003235D5 /* GenerateAfterVarCommand.swift in Sources */,
559+
A083A3851ED45DD500C9B024 /* CodingGenerator.swift in Sources */,
546560
A01E46871E0FF94C00395AED /* FuncSignature.swift in Sources */,
547561
A0E276591E141ED8003CC557 /* SwiftParamMocker.swift in Sources */,
548562
A0E276531E13F1F6003CC557 /* TypeParser.swift in Sources */,
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
2+
required init?(coder aDecoder: NSCoder) {
3+
guard let var1 = aDecoder.decodeObject(forKey: "var1") as? String else { return nil }
4+
if aDecoder.containsValue(forKey: "var0") {
5+
var0 = aDecoder.decodeInteger(forKey: "var0")
6+
}
7+
self.var1 = var1
8+
if aDecoder.containsValue(forKey: "var2") {
9+
var2 = aDecoder.decodeBool(forKey: "var2")
10+
}
11+
}
12+
13+
func encode(with aCoder: NSCoder) {
14+
aCoder.encode(var0, forKey: "var0")
15+
aCoder.encode(var1, forKey: "var1")
16+
aCoder.encode(var2, forKey: "var2")
17+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//
2+
// NSCodingGeneratorTest.swift
3+
// CodeGenerator
4+
//
5+
// Created by WANG Jie on 25/05/2017.
6+
// Copyright © 2017 wangjie. All rights reserved.
7+
//
8+
9+
import XCTest
10+
@testable import CodeGenerator
11+
12+
class NSCodingGeneratorTest: XCTestCase {
13+
14+
override func setUp() {
15+
super.setUp()
16+
// Put setup code here. This method is called before the invocation of each test method in the class.
17+
}
18+
19+
override func tearDown() {
20+
// Put teardown code here. This method is called after the invocation of each test method in the class.
21+
super.tearDown()
22+
}
23+
24+
func testNSCodingGenerator() {
25+
let source = string(from: "EquatableClazz", ofType: "txt")
26+
let interface = InterfaceSignature(interfaceSource: source, lines: source.components(separatedBy: "\n"))
27+
let codingGenerator = CodingGenerator(interfaceSignature: interface, indentation: " ")
28+
29+
var expectedCodingSource = string(from: "GeneratedNSCoder", ofType: "txt").components(separatedBy: "\n")
30+
expectedCodingSource.removeLast()
31+
32+
XCTAssertEqual(codingGenerator.lines.count, expectedCodingSource.count)
33+
let count = min(codingGenerator.lines.count, expectedCodingSource.count)
34+
for i in 0..<count {
35+
XCTAssertEqual(codingGenerator.lines[i], expectedCodingSource[i])
36+
}
37+
}
38+
39+
}

Generate.../CodingGenerator.swift

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//
2+
// CodingGenerator.swift
3+
// CodeGenerator
4+
//
5+
// Created by WANG Jie on 23/05/2017.
6+
// Copyright © 2017 wangjie. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
struct CodingGenerator: Generator {
12+
let varSignatures: [VarSignature]
13+
let indentation: String
14+
let interfaceDefinition: InterfaceDefinition
15+
16+
var interfaceName: String {
17+
return interfaceDefinition.name
18+
}
19+
20+
init(interfaceSignature: InterfaceSignature, indentation: String) {
21+
self.varSignatures = interfaceSignature.varSignatures
22+
self.interfaceDefinition = interfaceSignature.definition
23+
self.indentation = indentation
24+
}
25+
26+
init(interfaceDefinition: InterfaceDefinition, varSignatures: [VarSignature], indentation: String) {
27+
self.varSignatures = varSignatures
28+
self.interfaceDefinition = interfaceDefinition
29+
self.indentation = indentation
30+
}
31+
32+
var lines: [String] {
33+
var lines = [String]()
34+
lines.append(contentsOf: decodeLines)
35+
lines.append(contentsOf: encodeLines)
36+
return lines
37+
}
38+
39+
var encodeLines: [String] {
40+
var lines = [String]()
41+
lines.append("")
42+
lines.append("\(indentation)func encode(with aCoder: NSCoder) {")
43+
for varSignature in varSignatures {
44+
lines.append("\(indentation.repeating(2))aCoder.encode(\(varSignature.name), forKey: \"\(varSignature.name)\")")
45+
}
46+
lines.append("\(indentation)}")
47+
return lines
48+
}
49+
50+
var decodeLines: [String] {
51+
52+
var lines = [String]()
53+
lines.append("")
54+
lines.append("\(indentation)required init?(coder aDecoder: NSCoder) {")
55+
var guards = "guard "
56+
varSignatures.filter { $0.shouldGuard }.forEach { varSignature in
57+
let guardVar = "let \(varSignature.name) = aDecoder.\(varSignature.decodeName), "
58+
guards.append(guardVar)
59+
}
60+
guards.removeSubrange(Range(uncheckedBounds: (lower: guards.index(guards.endIndex, offsetBy: -2), upper: guards.endIndex)))
61+
guards.append(" else { return nil }")
62+
lines.append(indentation.repeating(2) + guards)
63+
for varSignature in varSignatures {
64+
if varSignature.shouldGuard {
65+
lines.append(indentation.repeating(2) + "self.\(varSignature.name) = \(varSignature.name)")
66+
continue
67+
}
68+
if varSignature.type.isOptional {
69+
lines.append(indentation.repeating(2) + "if aDecoder.containsValue(forKey: \"\(varSignature.name)\") {")
70+
lines.append(indentation.repeating(3) + "\(varSignature.name) = aDecoder.\(varSignature.decodeName)")
71+
lines.append(indentation.repeating(2) + "}")
72+
continue
73+
}
74+
lines.append(indentation.repeating(2) + "\(varSignature.name) = aDecoder.\(varSignature.decodeName)")
75+
76+
}
77+
lines.append("\(indentation)}")
78+
return lines
79+
}
80+
81+
}
82+
83+
private extension VarSignature {
84+
var shouldGuard: Bool {
85+
return isObject && !type.isOptional
86+
}
87+
88+
var isObject: Bool {
89+
return decodeName.contains("decodeObject")
90+
}
91+
92+
var decodeName: String {
93+
let types = ["Bool": "decodeBool", "Int32": "decodeInt32", "Int64": "decodeInt64", "Float": "decodeFloat", "Double": "decodeDouble", "Int": "decodeInteger"]
94+
guard let _ = types.index(forKey: type.unwrappedName) else {
95+
return "decodeObject(forKey: \"\(name)\") as? \(type.unwrappedName)"
96+
}
97+
return "\(types[type.unwrappedName]!)(forKey: \"\(name)\")"
98+
}
99+
}

0 commit comments

Comments
 (0)