From 579122b2e4a4fe7775fa5bb5acf248009c1ecc66 Mon Sep 17 00:00:00 2001
From: ykyouhei <kyouhei.lab@gmail.com>
Date: Thu, 7 Jul 2016 00:10:26 +0900
Subject: [PATCH] add project.

---
 SwiftyConfiguration.xcodeproj/project.pbxproj | 29 ++++++-
 .../xcschemes/SwiftyConfiguration.xcscheme    |  0
 .../xcschemes/xcschememanagement.plist        | 27 ------
 .../Classes/Configuration.swift               | 84 +++++++++++++++++++
 SwiftyConfigurationTests/Configuration.plist  | 30 +++++++
 .../SwiftyConfiguration.swift                 | 62 ++++++++++++++
 .../SwiftyConfigurationTests.swift            | 36 --------
 7 files changed, 201 insertions(+), 67 deletions(-)
 rename SwiftyConfiguration.xcodeproj/{xcuserdata/kyouhei.xcuserdatad => xcshareddata}/xcschemes/SwiftyConfiguration.xcscheme (100%)
 delete mode 100644 SwiftyConfiguration.xcodeproj/xcuserdata/kyouhei.xcuserdatad/xcschemes/xcschememanagement.plist
 create mode 100644 SwiftyConfiguration/Classes/Configuration.swift
 create mode 100644 SwiftyConfigurationTests/Configuration.plist
 create mode 100644 SwiftyConfigurationTests/SwiftyConfiguration.swift
 delete mode 100644 SwiftyConfigurationTests/SwiftyConfigurationTests.swift

diff --git a/SwiftyConfiguration.xcodeproj/project.pbxproj b/SwiftyConfiguration.xcodeproj/project.pbxproj
index 8384911..734fc85 100644
--- a/SwiftyConfiguration.xcodeproj/project.pbxproj
+++ b/SwiftyConfiguration.xcodeproj/project.pbxproj
@@ -9,7 +9,9 @@
 /* Begin PBXBuildFile section */
 		413897FE1D2BEC9700DD13B1 /* SwiftyConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 413897FD1D2BEC9700DD13B1 /* SwiftyConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		413898051D2BEC9700DD13B1 /* SwiftyConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 413897FA1D2BEC9600DD13B1 /* SwiftyConfiguration.framework */; };
-		4138980A1D2BEC9700DD13B1 /* SwiftyConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 413898091D2BEC9700DD13B1 /* SwiftyConfigurationTests.swift */; };
+		4138980A1D2BEC9700DD13B1 /* SwiftyConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 413898091D2BEC9700DD13B1 /* SwiftyConfiguration.swift */; };
+		413898161D2BEE2200DD13B1 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 413898151D2BEE2200DD13B1 /* Configuration.swift */; };
+		413898181D2BF25800DD13B1 /* Configuration.plist in Resources */ = {isa = PBXBuildFile; fileRef = 413898171D2BF25800DD13B1 /* Configuration.plist */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -27,8 +29,10 @@
 		413897FD1D2BEC9700DD13B1 /* SwiftyConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SwiftyConfiguration.h; sourceTree = "<group>"; };
 		413897FF1D2BEC9700DD13B1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		413898041D2BEC9700DD13B1 /* SwiftyConfigurationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftyConfigurationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
-		413898091D2BEC9700DD13B1 /* SwiftyConfigurationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftyConfigurationTests.swift; sourceTree = "<group>"; };
+		413898091D2BEC9700DD13B1 /* SwiftyConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftyConfiguration.swift; sourceTree = "<group>"; };
 		4138980B1D2BEC9700DD13B1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		413898151D2BEE2200DD13B1 /* Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
+		413898171D2BF25800DD13B1 /* Configuration.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Configuration.plist; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -71,6 +75,7 @@
 		413897FC1D2BEC9700DD13B1 /* SwiftyConfiguration */ = {
 			isa = PBXGroup;
 			children = (
+				413898141D2BEDDA00DD13B1 /* Classes */,
 				413897FD1D2BEC9700DD13B1 /* SwiftyConfiguration.h */,
 				413897FF1D2BEC9700DD13B1 /* Info.plist */,
 			);
@@ -80,12 +85,21 @@
 		413898081D2BEC9700DD13B1 /* SwiftyConfigurationTests */ = {
 			isa = PBXGroup;
 			children = (
-				413898091D2BEC9700DD13B1 /* SwiftyConfigurationTests.swift */,
+				413898091D2BEC9700DD13B1 /* SwiftyConfiguration.swift */,
 				4138980B1D2BEC9700DD13B1 /* Info.plist */,
+				413898171D2BF25800DD13B1 /* Configuration.plist */,
 			);
 			path = SwiftyConfigurationTests;
 			sourceTree = "<group>";
 		};
+		413898141D2BEDDA00DD13B1 /* Classes */ = {
+			isa = PBXGroup;
+			children = (
+				413898151D2BEE2200DD13B1 /* Configuration.swift */,
+			);
+			path = Classes;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXHeadersBuildPhase section */
@@ -184,6 +198,7 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				413898181D2BF25800DD13B1 /* Configuration.plist in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -194,6 +209,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				413898161D2BEE2200DD13B1 /* Configuration.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -201,7 +217,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				4138980A1D2BEC9700DD13B1 /* SwiftyConfigurationTests.swift in Sources */,
+				4138980A1D2BEC9700DD13B1 /* SwiftyConfiguration.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -310,28 +326,33 @@
 		4138980F1D2BEC9700DD13B1 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				INFOPLIST_FILE = SwiftyConfiguration/Info.plist;
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.kyo--hei.SwiftyConfiguration";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 			};
 			name = Debug;
 		};
 		413898101D2BEC9700DD13B1 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
 				DEFINES_MODULE = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1;
 				DYLIB_CURRENT_VERSION = 1;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				INFOPLIST_FILE = SwiftyConfiguration/Info.plist;
 				INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = "com.kyo--hei.SwiftyConfiguration";
 				PRODUCT_NAME = "$(TARGET_NAME)";
diff --git a/SwiftyConfiguration.xcodeproj/xcuserdata/kyouhei.xcuserdatad/xcschemes/SwiftyConfiguration.xcscheme b/SwiftyConfiguration.xcodeproj/xcshareddata/xcschemes/SwiftyConfiguration.xcscheme
similarity index 100%
rename from SwiftyConfiguration.xcodeproj/xcuserdata/kyouhei.xcuserdatad/xcschemes/SwiftyConfiguration.xcscheme
rename to SwiftyConfiguration.xcodeproj/xcshareddata/xcschemes/SwiftyConfiguration.xcscheme
diff --git a/SwiftyConfiguration.xcodeproj/xcuserdata/kyouhei.xcuserdatad/xcschemes/xcschememanagement.plist b/SwiftyConfiguration.xcodeproj/xcuserdata/kyouhei.xcuserdatad/xcschemes/xcschememanagement.plist
deleted file mode 100644
index d531f5e..0000000
--- a/SwiftyConfiguration.xcodeproj/xcuserdata/kyouhei.xcuserdatad/xcschemes/xcschememanagement.plist
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>SchemeUserState</key>
-	<dict>
-		<key>SwiftyConfiguration.xcscheme</key>
-		<dict>
-			<key>orderHint</key>
-			<integer>0</integer>
-		</dict>
-	</dict>
-	<key>SuppressBuildableAutocreation</key>
-	<dict>
-		<key>413897F91D2BEC9600DD13B1</key>
-		<dict>
-			<key>primary</key>
-			<true/>
-		</dict>
-		<key>413898031D2BEC9700DD13B1</key>
-		<dict>
-			<key>primary</key>
-			<true/>
-		</dict>
-	</dict>
-</dict>
-</plist>
diff --git a/SwiftyConfiguration/Classes/Configuration.swift b/SwiftyConfiguration/Classes/Configuration.swift
new file mode 100644
index 0000000..5a54f06
--- /dev/null
+++ b/SwiftyConfiguration/Classes/Configuration.swift
@@ -0,0 +1,84 @@
+//
+//  Configuration.swift
+//  SwiftyConfiguration
+//
+//  Created by kyo__hei on 2016/07/05.
+//  Copyright © 2016年 kyo__hei. All rights reserved.
+//
+
+import Foundation
+
+public protocol PlistValueType {}
+
+extension String: PlistValueType {}
+extension NSNumber: PlistValueType {}
+extension Int: PlistValueType {}
+extension Float: PlistValueType {}
+extension Double: PlistValueType {}
+extension Bool: PlistValueType {}
+extension NSDate: PlistValueType {}
+extension NSData: PlistValueType {}
+extension Array: PlistValueType {}
+extension Dictionary: PlistValueType {}
+
+public class Keys {}
+
+public class Key<ValueType: PlistValueType>: Keys {
+    
+    public let key: String
+    
+    internal var separatedKeys: [String] {
+        return key.componentsSeparatedByString(".")
+    }
+    
+    public init(_ key: String) {
+        self.key = key
+    }
+    
+}
+
+
+public struct Configuration {
+    
+    private let dictionary: NSDictionary
+    
+    public init?(plistPath: String) {
+        guard let plist = NSDictionary(contentsOfFile: plistPath) else {
+            assertionFailure("could not read plist file.")
+            return nil
+        }
+        dictionary = plist
+    }
+    
+    public func get<T>(key: Key<T>) -> T? {
+        var object: AnyObject = dictionary
+        
+        key.separatedKeys.enumerate().forEach { idx, separatedKey in
+            if let index = Int(separatedKey) {
+                let array = object as! Array<AnyObject>
+                object = array[index]
+            } else {
+                let dictionary = object as! NSDictionary
+                object = dictionary[separatedKey]!
+            }
+        }
+        
+        let optionalValue: T?
+        
+        switch T.self {
+        case is Int.Type:    optionalValue = object.integerValue as? T
+        case is Float.Type:  optionalValue = object.floatValue as? T
+        case is Double.Type: optionalValue = object.doubleValue as? T
+        case is NSURL.Type:  optionalValue = NSURL(string: (object as? String) ?? "") as? T
+        default:             optionalValue = object as? T
+        }
+        
+        guard let value = optionalValue else {
+            assertionFailure("Could not cast value of type \(object.dynamicType) to \(T.self)")
+            return nil
+        }
+        
+        return value
+    }
+    
+}
diff --git a/SwiftyConfigurationTests/Configuration.plist b/SwiftyConfigurationTests/Configuration.plist
new file mode 100644
index 0000000..37c247a
--- /dev/null
+++ b/SwiftyConfigurationTests/Configuration.plist
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>dictionary</key>
+	<dict>
+		<key>innerString</key>
+		<string>moge</string>
+	</dict>
+	<key>array</key>
+	<array>
+		<integer>0</integer>
+		<array>
+			<string>array.1.0</string>
+		</array>
+	</array>
+	<key>string</key>
+	<string>hoge</string>
+	<key>int</key>
+	<integer>1</integer>
+	<key>float</key>
+	<real>1.1</real>
+	<key>double</key>
+	<string>3.14</string>
+	<key>bool</key>
+	<true/>
+	<key>date</key>
+	<date>1970-01-01T00:00:00Z</date>
+</dict>
+</plist>
diff --git a/SwiftyConfigurationTests/SwiftyConfiguration.swift b/SwiftyConfigurationTests/SwiftyConfiguration.swift
new file mode 100644
index 0000000..ee6d910
--- /dev/null
+++ b/SwiftyConfigurationTests/SwiftyConfiguration.swift
@@ -0,0 +1,62 @@
+//
+//  SwiftyConfigurationTests.swift
+//  SwiftyConfigurationTests
+//
+//  Created by kyo__hei on 2016/07/05.
+//  Copyright © 2016年 kyo__hei. All rights reserved.
+//
+
+import XCTest
+@testable import SwiftyConfiguration
+
+private extension Keys {
+    
+    static let string = Key<String>("string")
+    static let int    = Key<Int>("int")
+    static let float  = Key<Float>("float")
+    static let double = Key<Double>("double")
+    static let date   = Key<NSDate>("date")
+    static let bool   = Key<Bool>("bool")
+    
+    static let array      = Key<Array<NSObject>>("array")
+    static let innerInt   = Key<Int>("array.0")
+    static let innerArray = Key<String>("array.1.0")
+    
+    static let dictionary  = Key<[String : String]>("dictionary")
+    static let innerString = Key<String>("dictionary.innerString")
+}
+
+class SwiftyConfigurationTests: XCTestCase {
+    
+    private lazy var plistPath: String = {
+        return NSBundle(forClass: self.dynamicType).pathForResource("Configuration", ofType: "plist")!
+    }()
+    
+    override func setUp() {
+        super.setUp()
+        
+    }
+    
+    override func tearDown() {
+        super.tearDown()
+    }
+    
+    func testGetValue() {
+        let config = Configuration(plistPath: plistPath)!
+        
+        XCTAssertTrue("hoge" == config.get(.string)!)
+        XCTAssertTrue(1 == config.get(.int)!)
+        XCTAssertTrue(1.1 == config.get(.float)!)
+        XCTAssertTrue(3.14 == config.get(.double)!)
+        XCTAssertTrue(config.get(.bool)!)
+        XCTAssertTrue(NSDate(timeIntervalSince1970: 0).timeIntervalSince1970 == config.get(.date)!.timeIntervalSince1970)
+        
+        XCTAssertTrue([0,["array.1.0"]] == config.get(.array)!)
+        XCTAssertTrue(0 == config.get(.innerInt)!)
+        XCTAssertTrue("array.1.0" == config.get(.innerArray)!)
+        
+        XCTAssertTrue(["innerString" : "moge"] == config.get(.dictionary)!)
+        XCTAssertTrue("moge" == config.get(.innerString)!)
+    }
+    
+}
diff --git a/SwiftyConfigurationTests/SwiftyConfigurationTests.swift b/SwiftyConfigurationTests/SwiftyConfigurationTests.swift
deleted file mode 100644
index 9b2fccd..0000000
--- a/SwiftyConfigurationTests/SwiftyConfigurationTests.swift
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-//  SwiftyConfigurationTests.swift
-//  SwiftyConfigurationTests
-//
-//  Created by kyo__hei on 2016/07/05.
-//  Copyright © 2016年 kyo__hei. All rights reserved.
-//
-
-import XCTest
-@testable import SwiftyConfiguration
-
-class SwiftyConfigurationTests: 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 testExample() {
-        // This is an example of a functional test case.
-        // Use XCTAssert and related functions to verify your tests produce the correct results.
-    }
-    
-    func testPerformanceExample() {
-        // This is an example of a performance test case.
-        self.measureBlock {
-            // Put the code you want to measure the time of here.
-        }
-    }
-    
-}