diff --git a/JSONHelper.podspec b/JSONHelper.podspec index 6eb65a5..e8c9424 100644 --- a/JSONHelper.podspec +++ b/JSONHelper.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'JSONHelper' - s.version = '1.7.0' + s.version = '2.0.0' s.license = { :type => 'zlib', :file => 'LICENSE' } s.summary = 'Lightning fast JSON deserialization and value conversion library for iOS & OS X written in Swift.' @@ -12,7 +12,7 @@ Pod::Spec.new do |s| s.osx.deployment_target = '10.9' s.tvos.deployment_target = '9.0' s.source = { :git => 'https://github.com/isair/JSONHelper.git', :tag => s.version } - s.source_files = 'JSONHelper' + s.source_files = 'JSONHelper/**/*.swift' s.frameworks = 'Foundation' s.requires_arc = true end diff --git a/JSONHelper.xcodeproj/project.pbxproj b/JSONHelper.xcodeproj/project.pbxproj index 2de969b..705a22e 100644 --- a/JSONHelper.xcodeproj/project.pbxproj +++ b/JSONHelper.xcodeproj/project.pbxproj @@ -7,8 +7,41 @@ objects = { /* Begin PBXBuildFile section */ + 5F024AE11B4127C900EF50C4 /* IntTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F024AE01B4127C900EF50C4 /* IntTests.swift */; }; + 5F024AE31B412BA900EF50C4 /* BoolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F024AE21B412BA900EF50C4 /* BoolTests.swift */; }; + 5F133DA21C3840BB00EF50C4 /* JSONAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F133DA11C3840BB00EF50C4 /* JSONAPI.swift */; }; + 5F133DA31C3840C800EF50C4 /* JSONAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F133DA11C3840BB00EF50C4 /* JSONAPI.swift */; }; + 5F133DA41C3840CA00EF50C4 /* JSONAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F133DA11C3840BB00EF50C4 /* JSONAPI.swift */; }; + 5F31FF561C5339B900EF50C4 /* NSDateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF551C5339B900EF50C4 /* NSDateTests.swift */; }; + 5F31FF581C5339CE00EF50C4 /* NSURLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF571C5339CE00EF50C4 /* NSURLTests.swift */; }; + 5F31FF5C1C533AD400EF50C4 /* Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF5B1C533AD400EF50C4 /* Conversion.swift */; }; + 5F31FF5E1C533AE000EF50C4 /* Deserialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF5D1C533AE000EF50C4 /* Deserialization.swift */; }; + 5F31FF601C533E9900EF50C4 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF5F1C533E9900EF50C4 /* Color.swift */; }; + 5F31FF611C533E9900EF50C4 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF5F1C533E9900EF50C4 /* Color.swift */; }; + 5F31FF631C533E9D00EF50C4 /* Deserialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF5D1C533AE000EF50C4 /* Deserialization.swift */; }; + 5F31FF641C533E9D00EF50C4 /* Deserialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF5D1C533AE000EF50C4 /* Deserialization.swift */; }; + 5F31FF651C533EA000EF50C4 /* Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF5B1C533AD400EF50C4 /* Conversion.swift */; }; + 5F31FF661C533EA100EF50C4 /* Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF5B1C533AD400EF50C4 /* Conversion.swift */; }; + 5F31FF6C1C533F1600EF50C4 /* ColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF6B1C533F1600EF50C4 /* ColorTests.swift */; }; + 5F31FF6E1C5348F000EF50C4 /* NSDecimalNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF6D1C5348F000EF50C4 /* NSDecimalNumber.swift */; }; + 5F31FF6F1C5348F000EF50C4 /* NSDecimalNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF6D1C5348F000EF50C4 /* NSDecimalNumber.swift */; }; + 5F31FF721C5348FE00EF50C4 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF711C5348FE00EF50C4 /* Double.swift */; }; + 5F31FF731C5348FE00EF50C4 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF711C5348FE00EF50C4 /* Double.swift */; }; + 5F31FF761C53490B00EF50C4 /* Float.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF751C53490B00EF50C4 /* Float.swift */; }; + 5F31FF771C53490B00EF50C4 /* Float.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF751C53490B00EF50C4 /* Float.swift */; }; + 5F31FF7A1C53496B00EF50C4 /* DoubleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF791C53496B00EF50C4 /* DoubleTests.swift */; }; + 5F31FF7C1C53497600EF50C4 /* FloatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF7B1C53497600EF50C4 /* FloatTests.swift */; }; + 5F31FF7E1C53499000EF50C4 /* NSDecimalNumberTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF7D1C53499000EF50C4 /* NSDecimalNumberTests.swift */; }; + 5F6A2F4A1CC0116D00EF50C4 /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F491CC0116D00EF50C4 /* JSONHelper.swift */; }; + 5F6A2F4B1CC0116D00EF50C4 /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F491CC0116D00EF50C4 /* JSONHelper.swift */; }; + 5F6A2F4C1CC0116D00EF50C4 /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F491CC0116D00EF50C4 /* JSONHelper.swift */; }; + 5F6A2F4E1CC096DA00EF50C4 /* Serialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F4D1CC096DA00EF50C4 /* Serialization.swift */; }; + 5F6A2F4F1CC096DA00EF50C4 /* Serialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F4D1CC096DA00EF50C4 /* Serialization.swift */; }; + 5F6A2F501CC096DA00EF50C4 /* Serialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F4D1CC096DA00EF50C4 /* Serialization.swift */; }; + 5F6A2F531CC09B9A00EF50C4 /* DeserializableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F6A2F521CC09B9A00EF50C4 /* DeserializableTests.swift */; }; + 5F8F88231CA5F32E00EF50C4 /* DictionaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F8F88221CA5F32E00EF50C4 /* DictionaryTests.swift */; }; + 5F8F88251CA5F33500EF50C4 /* EnumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F8F88241CA5F33500EF50C4 /* EnumTests.swift */; }; 5F928D991C0D469F00EF50C4 /* JSONHelper-tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 5F928D981C0D469F00EF50C4 /* JSONHelper-tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5F928D9E1C0D46BE00EF50C4 /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC4468E1A70F3750038EE4E /* JSONHelper.swift */; }; 5FAD076A1A70F2FC00C4D09E /* JSONHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FAD07691A70F2FC00C4D09E /* JSONHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5FAD07701A70F2FC00C4D09E /* JSONHelper.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5FAD07641A70F2FC00C4D09E /* JSONHelper.framework */; }; 5FAD07771A70F2FC00C4D09E /* JSONHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FAD07761A70F2FC00C4D09E /* JSONHelperTests.swift */; }; @@ -17,9 +50,27 @@ 5FAD078E1A70F31300C4D09E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5FAD078C1A70F31300C4D09E /* Main.storyboard */; }; 5FAD07901A70F31300C4D09E /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5FAD078F1A70F31300C4D09E /* Images.xcassets */; }; 5FAD07931A70F31300C4D09E /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5FAD07911A70F31300C4D09E /* LaunchScreen.xib */; }; - 5FAD079F1A70F31300C4D09E /* JSONHelperExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FAD079E1A70F31300C4D09E /* JSONHelperExampleTests.swift */; }; - 5FC4468F1A70F3750038EE4E /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC4468E1A70F3750038EE4E /* JSONHelper.swift */; }; - D76C52021ACD46B100B49735 /* JSONHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC4468E1A70F3750038EE4E /* JSONHelper.swift */; }; + 5FB9D4E01B38007C00EF50C4 /* StringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FB9D4DF1B38007C00EF50C4 /* StringTests.swift */; }; + 5FC1A4871B1CFFB500EF50C4 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A4861B1CFFB500EF50C4 /* String.swift */; }; + 5FC1A4891B1D024500EF50C4 /* Int.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A4881B1D024500EF50C4 /* Int.swift */; }; + 5FC1A48B1B1D036400EF50C4 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A4861B1CFFB500EF50C4 /* String.swift */; }; + 5FC1A48C1B1D036700EF50C4 /* Int.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A4881B1D024500EF50C4 /* Int.swift */; }; + 5FC1A48E1B1D057B00EF50C4 /* Bool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A48D1B1D057B00EF50C4 /* Bool.swift */; }; + 5FC1A4901B1D082500EF50C4 /* NSDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A48F1B1D082500EF50C4 /* NSDate.swift */; }; + 5FC1A4911B1D082B00EF50C4 /* Bool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A48D1B1D057B00EF50C4 /* Bool.swift */; }; + 5FC1A4921B1D082D00EF50C4 /* NSDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A48F1B1D082500EF50C4 /* NSDate.swift */; }; + 5FC1A4941B1D1D8B00EF50C4 /* NSURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A4931B1D1D8B00EF50C4 /* NSURL.swift */; }; + 5FC1A4951B1D1D8B00EF50C4 /* NSURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A4931B1D1D8B00EF50C4 /* NSURL.swift */; }; + 5FD3A0A01CA5F5C300EF50C4 /* ArrayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FD3A09F1CA5F5C300EF50C4 /* ArrayTests.swift */; }; + 5FDBD51A1CC46C2A00EF50C4 /* Bool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A48D1B1D057B00EF50C4 /* Bool.swift */; }; + 5FDBD51B1CC46C2A00EF50C4 /* Int.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A4881B1D024500EF50C4 /* Int.swift */; }; + 5FDBD51C1CC46C2A00EF50C4 /* Float.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF751C53490B00EF50C4 /* Float.swift */; }; + 5FDBD51D1CC46C2A00EF50C4 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF711C5348FE00EF50C4 /* Double.swift */; }; + 5FDBD51E1CC46C2A00EF50C4 /* NSDecimalNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF6D1C5348F000EF50C4 /* NSDecimalNumber.swift */; }; + 5FDBD51F1CC46C2A00EF50C4 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A4861B1CFFB500EF50C4 /* String.swift */; }; + 5FDBD5201CC46C2A00EF50C4 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F31FF5F1C533E9900EF50C4 /* Color.swift */; }; + 5FDBD5211CC46C2A00EF50C4 /* NSDate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A48F1B1D082500EF50C4 /* NSDate.swift */; }; + 5FDBD5221CC46C2A00EF50C4 /* NSURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC1A4931B1D1D8B00EF50C4 /* NSURL.swift */; }; D76C52051ACD46B100B49735 /* JSONHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 5FAD07691A70F2FC00C4D09E /* JSONHelper.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ @@ -38,25 +89,37 @@ remoteGlobalIDString = 5FAD07631A70F2FC00C4D09E; remoteInfo = JSONHelper; }; - 5FAD07991A70F31300C4D09E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5FAD075B1A70F2FC00C4D09E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 5FAD07831A70F31300C4D09E; - remoteInfo = JSONHelperExample; - }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 5F024AE01B4127C900EF50C4 /* IntTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntTests.swift; sourceTree = ""; }; + 5F024AE21B412BA900EF50C4 /* BoolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoolTests.swift; sourceTree = ""; }; 5F0E6F961ACDE06400D92679 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 5F928D961C0D469F00EF50C4 /* JSONHelper_tvOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JSONHelper_tvOS.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5F133DA11C3840BB00EF50C4 /* JSONAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = JSONAPI.swift; path = Support/JSONAPI.swift; sourceTree = ""; }; + 5F31FF551C5339B900EF50C4 /* NSDateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDateTests.swift; sourceTree = ""; }; + 5F31FF571C5339CE00EF50C4 /* NSURLTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSURLTests.swift; sourceTree = ""; }; + 5F31FF5B1C533AD400EF50C4 /* Conversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Conversion.swift; sourceTree = ""; }; + 5F31FF5D1C533AE000EF50C4 /* Deserialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Deserialization.swift; sourceTree = ""; }; + 5F31FF5F1C533E9900EF50C4 /* Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Color.swift; path = Extensions/Color.swift; sourceTree = ""; }; + 5F31FF6B1C533F1600EF50C4 /* ColorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorTests.swift; sourceTree = ""; }; + 5F31FF6D1C5348F000EF50C4 /* NSDecimalNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NSDecimalNumber.swift; path = Extensions/NSDecimalNumber.swift; sourceTree = ""; }; + 5F31FF711C5348FE00EF50C4 /* Double.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Double.swift; path = Extensions/Double.swift; sourceTree = ""; }; + 5F31FF751C53490B00EF50C4 /* Float.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Float.swift; path = Extensions/Float.swift; sourceTree = ""; }; + 5F31FF791C53496B00EF50C4 /* DoubleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DoubleTests.swift; sourceTree = ""; }; + 5F31FF7B1C53497600EF50C4 /* FloatTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FloatTests.swift; sourceTree = ""; }; + 5F31FF7D1C53499000EF50C4 /* NSDecimalNumberTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSDecimalNumberTests.swift; sourceTree = ""; }; + 5F6A2F491CC0116D00EF50C4 /* JSONHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONHelper.swift; sourceTree = ""; }; + 5F6A2F4D1CC096DA00EF50C4 /* Serialization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Serialization.swift; sourceTree = ""; }; + 5F6A2F521CC09B9A00EF50C4 /* DeserializableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeserializableTests.swift; sourceTree = ""; }; + 5F8F88221CA5F32E00EF50C4 /* DictionaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DictionaryTests.swift; sourceTree = ""; }; + 5F8F88241CA5F33500EF50C4 /* EnumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnumTests.swift; sourceTree = ""; }; + 5F928D961C0D469F00EF50C4 /* JSONHelper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JSONHelper.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5F928D981C0D469F00EF50C4 /* JSONHelper-tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JSONHelper-tvOS.h"; sourceTree = ""; }; 5F928D9A1C0D469F00EF50C4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5FAD07641A70F2FC00C4D09E /* JSONHelper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JSONHelper.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 5FAD07681A70F2FC00C4D09E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5FAD07691A70F2FC00C4D09E /* JSONHelper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JSONHelper.h; sourceTree = ""; }; 5FAD076F1A70F2FC00C4D09E /* JSONHelperTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JSONHelperTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 5FAD07751A70F2FC00C4D09E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5FAD07761A70F2FC00C4D09E /* JSONHelperTests.swift */ = {isa = PBXFileReference; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = JSONHelperTests.swift; sourceTree = ""; tabWidth = 2; }; 5FAD07841A70F31300C4D09E /* JSONHelperExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JSONHelperExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5FAD07871A70F31300C4D09E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -65,10 +128,15 @@ 5FAD078D1A70F31300C4D09E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 5FAD078F1A70F31300C4D09E /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 5FAD07921A70F31300C4D09E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 5FAD07981A70F31300C4D09E /* JSONHelperExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = JSONHelperExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 5FAD079D1A70F31300C4D09E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 5FAD079E1A70F31300C4D09E /* JSONHelperExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JSONHelperExampleTests.swift; sourceTree = ""; }; - 5FC4468E1A70F3750038EE4E /* JSONHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = JSONHelper.swift; sourceTree = ""; tabWidth = 2; }; + 5FB9D4DF1B38007C00EF50C4 /* StringTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringTests.swift; sourceTree = ""; }; + 5FC1A4861B1CFFB500EF50C4 /* String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = String.swift; path = Extensions/String.swift; sourceTree = ""; }; + 5FC1A4881B1D024500EF50C4 /* Int.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Int.swift; path = Extensions/Int.swift; sourceTree = ""; }; + 5FC1A48D1B1D057B00EF50C4 /* Bool.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bool.swift; path = Extensions/Bool.swift; sourceTree = ""; }; + 5FC1A48F1B1D082500EF50C4 /* NSDate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NSDate.swift; path = Extensions/NSDate.swift; sourceTree = ""; }; + 5FC1A4931B1D1D8B00EF50C4 /* NSURL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NSURL.swift; path = Extensions/NSURL.swift; sourceTree = ""; }; + 5FD3A09F1CA5F5C300EF50C4 /* ArrayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArrayTests.swift; sourceTree = ""; }; D76C520A1ACD46B100B49735 /* JSONHelper.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = JSONHelper.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -102,13 +170,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5FAD07951A70F31300C4D09E /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; D76C52031ACD46B100B49735 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -135,6 +196,37 @@ path = iOS; sourceTree = ""; }; + 5F133DA01C3840A200EF50C4 /* Support */ = { + isa = PBXGroup; + children = ( + 5F133DA11C3840BB00EF50C4 /* JSONAPI.swift */, + ); + name = Support; + sourceTree = ""; + }; + 5F6A2F511CC09B6000EF50C4 /* Extension Tests */ = { + isa = PBXGroup; + children = ( + 5F024AE21B412BA900EF50C4 /* BoolTests.swift */, + 5F024AE01B4127C900EF50C4 /* IntTests.swift */, + 5F31FF7B1C53497600EF50C4 /* FloatTests.swift */, + 5F31FF791C53496B00EF50C4 /* DoubleTests.swift */, + 5F31FF7D1C53499000EF50C4 /* NSDecimalNumberTests.swift */, + 5FB9D4DF1B38007C00EF50C4 /* StringTests.swift */, + 5F31FF6B1C533F1600EF50C4 /* ColorTests.swift */, + 5F31FF551C5339B900EF50C4 /* NSDateTests.swift */, + 5F31FF571C5339CE00EF50C4 /* NSURLTests.swift */, + ); + name = "Extension Tests"; + sourceTree = ""; + }; + 5F6A2F541CC09BB500EF50C4 /* Support Tests */ = { + isa = PBXGroup; + children = ( + ); + name = "Support Tests"; + sourceTree = ""; + }; 5F928D9F1C0D478800EF50C4 /* tvOS */ = { isa = PBXGroup; children = ( @@ -148,9 +240,9 @@ isa = PBXGroup; children = ( 5FAD07661A70F2FC00C4D09E /* JSONHelper */, + 5FAD07731A70F2FC00C4D09E /* JSONHelperTests */, 5FAD07851A70F31300C4D09E /* JSONHelperExample */, 5FAD079B1A70F31300C4D09E /* JSONHelperExampleTests */, - 5FAD07731A70F2FC00C4D09E /* JSONHelperTests */, 5FAD07651A70F2FC00C4D09E /* Products */, ); sourceTree = ""; @@ -161,9 +253,8 @@ 5FAD07641A70F2FC00C4D09E /* JSONHelper.framework */, 5FAD076F1A70F2FC00C4D09E /* JSONHelperTests.xctest */, 5FAD07841A70F31300C4D09E /* JSONHelperExample.app */, - 5FAD07981A70F31300C4D09E /* JSONHelperExampleTests.xctest */, D76C520A1ACD46B100B49735 /* JSONHelper.framework */, - 5F928D961C0D469F00EF50C4 /* JSONHelper_tvOS.framework */, + 5F928D961C0D469F00EF50C4 /* JSONHelper.framework */, ); name = Products; sourceTree = ""; @@ -171,9 +262,14 @@ 5FAD07661A70F2FC00C4D09E /* JSONHelper */ = { isa = PBXGroup; children = ( - 5FAD07671A70F2FC00C4D09E /* Supporting Files */, 5FAD07691A70F2FC00C4D09E /* JSONHelper.h */, - 5FC4468E1A70F3750038EE4E /* JSONHelper.swift */, + 5F6A2F491CC0116D00EF50C4 /* JSONHelper.swift */, + 5F31FF5B1C533AD400EF50C4 /* Conversion.swift */, + 5F31FF5D1C533AE000EF50C4 /* Deserialization.swift */, + 5F6A2F4D1CC096DA00EF50C4 /* Serialization.swift */, + 5FC1A4851B1CFBE500EF50C4 /* Extensions */, + 5F133DA01C3840A200EF50C4 /* Support */, + 5FAD07671A70F2FC00C4D09E /* Supporting Files */, ); path = JSONHelper; sourceTree = ""; @@ -191,20 +287,17 @@ 5FAD07731A70F2FC00C4D09E /* JSONHelperTests */ = { isa = PBXGroup; children = ( - 5FAD07741A70F2FC00C4D09E /* Supporting Files */, 5FAD07761A70F2FC00C4D09E /* JSONHelperTests.swift */, + 5F6A2F511CC09B6000EF50C4 /* Extension Tests */, + 5F8F88241CA5F33500EF50C4 /* EnumTests.swift */, + 5F6A2F521CC09B9A00EF50C4 /* DeserializableTests.swift */, + 5FD3A09F1CA5F5C300EF50C4 /* ArrayTests.swift */, + 5F8F88221CA5F32E00EF50C4 /* DictionaryTests.swift */, + 5F6A2F541CC09BB500EF50C4 /* Support Tests */, ); path = JSONHelperTests; sourceTree = ""; }; - 5FAD07741A70F2FC00C4D09E /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 5FAD07751A70F2FC00C4D09E /* Info.plist */, - ); - path = "Supporting Files"; - sourceTree = ""; - }; 5FAD07851A70F31300C4D09E /* JSONHelperExample */ = { isa = PBXGroup; children = ( @@ -243,6 +336,22 @@ path = "Supporting Files"; sourceTree = ""; }; + 5FC1A4851B1CFBE500EF50C4 /* Extensions */ = { + isa = PBXGroup; + children = ( + 5FC1A48D1B1D057B00EF50C4 /* Bool.swift */, + 5FC1A4881B1D024500EF50C4 /* Int.swift */, + 5F31FF751C53490B00EF50C4 /* Float.swift */, + 5F31FF711C5348FE00EF50C4 /* Double.swift */, + 5F31FF6D1C5348F000EF50C4 /* NSDecimalNumber.swift */, + 5FC1A4861B1CFFB500EF50C4 /* String.swift */, + 5F31FF5F1C533E9900EF50C4 /* Color.swift */, + 5FC1A48F1B1D082500EF50C4 /* NSDate.swift */, + 5FC1A4931B1D1D8B00EF50C4 /* NSURL.swift */, + ); + name = Extensions; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -273,9 +382,9 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 5F928D951C0D469F00EF50C4 /* JSONHelper_tvOS */ = { + 5F928D951C0D469F00EF50C4 /* JSONHelper-tvOS */ = { isa = PBXNativeTarget; - buildConfigurationList = 5F928D9B1C0D469F00EF50C4 /* Build configuration list for PBXNativeTarget "JSONHelper_tvOS" */; + buildConfigurationList = 5F928D9B1C0D469F00EF50C4 /* Build configuration list for PBXNativeTarget "JSONHelper-tvOS" */; buildPhases = ( 5F928D911C0D469F00EF50C4 /* Sources */, 5F928D921C0D469F00EF50C4 /* Frameworks */, @@ -286,14 +395,14 @@ ); dependencies = ( ); - name = JSONHelper_tvOS; + name = "JSONHelper-tvOS"; productName = "JSONHelper-tvOS"; - productReference = 5F928D961C0D469F00EF50C4 /* JSONHelper_tvOS.framework */; + productReference = 5F928D961C0D469F00EF50C4 /* JSONHelper.framework */; productType = "com.apple.product-type.framework"; }; - 5FAD07631A70F2FC00C4D09E /* JSONHelper */ = { + 5FAD07631A70F2FC00C4D09E /* JSONHelper-iOS */ = { isa = PBXNativeTarget; - buildConfigurationList = 5FAD077A1A70F2FC00C4D09E /* Build configuration list for PBXNativeTarget "JSONHelper" */; + buildConfigurationList = 5FAD077A1A70F2FC00C4D09E /* Build configuration list for PBXNativeTarget "JSONHelper-iOS" */; buildPhases = ( 5FAD075F1A70F2FC00C4D09E /* Sources */, 5FAD07601A70F2FC00C4D09E /* Frameworks */, @@ -304,7 +413,7 @@ ); dependencies = ( ); - name = JSONHelper; + name = "JSONHelper-iOS"; productName = JSONHelper; productReference = 5FAD07641A70F2FC00C4D09E /* JSONHelper.framework */; productType = "com.apple.product-type.framework"; @@ -345,27 +454,9 @@ productReference = 5FAD07841A70F31300C4D09E /* JSONHelperExample.app */; productType = "com.apple.product-type.application"; }; - 5FAD07971A70F31300C4D09E /* JSONHelperExampleTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 5FAD07A31A70F31300C4D09E /* Build configuration list for PBXNativeTarget "JSONHelperExampleTests" */; - buildPhases = ( - 5FAD07941A70F31300C4D09E /* Sources */, - 5FAD07951A70F31300C4D09E /* Frameworks */, - 5FAD07961A70F31300C4D09E /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 5FAD079A1A70F31300C4D09E /* PBXTargetDependency */, - ); - name = JSONHelperExampleTests; - productName = JSONHelperExampleTests; - productReference = 5FAD07981A70F31300C4D09E /* JSONHelperExampleTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - D76C52001ACD46B100B49735 /* JSONHelper_Mac */ = { + D76C52001ACD46B100B49735 /* JSONHelper-Mac */ = { isa = PBXNativeTarget; - buildConfigurationList = D76C52071ACD46B100B49735 /* Build configuration list for PBXNativeTarget "JSONHelper_Mac" */; + buildConfigurationList = D76C52071ACD46B100B49735 /* Build configuration list for PBXNativeTarget "JSONHelper-Mac" */; buildPhases = ( D76C52011ACD46B100B49735 /* Sources */, D76C52031ACD46B100B49735 /* Frameworks */, @@ -376,7 +467,7 @@ ); dependencies = ( ); - name = JSONHelper_Mac; + name = "JSONHelper-Mac"; productName = JSONHelper; productReference = D76C520A1ACD46B100B49735 /* JSONHelper.framework */; productType = "com.apple.product-type.framework"; @@ -387,8 +478,7 @@ 5FAD075B1A70F2FC00C4D09E /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0710; - LastUpgradeCheck = 0610; + LastUpgradeCheck = 0710; ORGANIZATIONNAME = "Baris Sencan"; TargetAttributes = { 5F928D951C0D469F00EF50C4 = { @@ -403,10 +493,6 @@ 5FAD07831A70F31300C4D09E = { CreatedOnToolsVersion = 6.1.1; }; - 5FAD07971A70F31300C4D09E = { - CreatedOnToolsVersion = 6.1.1; - TestTargetID = 5FAD07831A70F31300C4D09E; - }; }; }; buildConfigurationList = 5FAD075E1A70F2FC00C4D09E /* Build configuration list for PBXProject "JSONHelper" */; @@ -422,12 +508,11 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 5FAD07631A70F2FC00C4D09E /* JSONHelper */, - D76C52001ACD46B100B49735 /* JSONHelper_Mac */, - 5F928D951C0D469F00EF50C4 /* JSONHelper_tvOS */, + 5FAD07631A70F2FC00C4D09E /* JSONHelper-iOS */, + D76C52001ACD46B100B49735 /* JSONHelper-Mac */, + 5F928D951C0D469F00EF50C4 /* JSONHelper-tvOS */, 5FAD076E1A70F2FC00C4D09E /* JSONHelperTests */, 5FAD07831A70F31300C4D09E /* JSONHelperExample */, - 5FAD07971A70F31300C4D09E /* JSONHelperExampleTests */, ); }; /* End PBXProject section */ @@ -464,13 +549,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5FAD07961A70F31300C4D09E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; D76C52061ACD46B100B49735 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -485,7 +563,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 5F928D9E1C0D46BE00EF50C4 /* JSONHelper.swift in Sources */, + 5FDBD5221CC46C2A00EF50C4 /* NSURL.swift in Sources */, + 5F31FF641C533E9D00EF50C4 /* Deserialization.swift in Sources */, + 5FDBD51F1CC46C2A00EF50C4 /* String.swift in Sources */, + 5F31FF661C533EA100EF50C4 /* Conversion.swift in Sources */, + 5F133DA41C3840CA00EF50C4 /* JSONAPI.swift in Sources */, + 5FDBD51B1CC46C2A00EF50C4 /* Int.swift in Sources */, + 5FDBD5201CC46C2A00EF50C4 /* Color.swift in Sources */, + 5FDBD51C1CC46C2A00EF50C4 /* Float.swift in Sources */, + 5FDBD51E1CC46C2A00EF50C4 /* NSDecimalNumber.swift in Sources */, + 5F6A2F501CC096DA00EF50C4 /* Serialization.swift in Sources */, + 5F6A2F4C1CC0116D00EF50C4 /* JSONHelper.swift in Sources */, + 5FDBD5211CC46C2A00EF50C4 /* NSDate.swift in Sources */, + 5FDBD51D1CC46C2A00EF50C4 /* Double.swift in Sources */, + 5FDBD51A1CC46C2A00EF50C4 /* Bool.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -493,7 +584,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 5FC4468F1A70F3750038EE4E /* JSONHelper.swift in Sources */, + 5FC1A4941B1D1D8B00EF50C4 /* NSURL.swift in Sources */, + 5F31FF6E1C5348F000EF50C4 /* NSDecimalNumber.swift in Sources */, + 5F6A2F4E1CC096DA00EF50C4 /* Serialization.swift in Sources */, + 5FC1A4891B1D024500EF50C4 /* Int.swift in Sources */, + 5FC1A48E1B1D057B00EF50C4 /* Bool.swift in Sources */, + 5F31FF601C533E9900EF50C4 /* Color.swift in Sources */, + 5FC1A4871B1CFFB500EF50C4 /* String.swift in Sources */, + 5F31FF5E1C533AE000EF50C4 /* Deserialization.swift in Sources */, + 5F133DA21C3840BB00EF50C4 /* JSONAPI.swift in Sources */, + 5F6A2F4A1CC0116D00EF50C4 /* JSONHelper.swift in Sources */, + 5FC1A4901B1D082500EF50C4 /* NSDate.swift in Sources */, + 5F31FF761C53490B00EF50C4 /* Float.swift in Sources */, + 5F31FF5C1C533AD400EF50C4 /* Conversion.swift in Sources */, + 5F31FF721C5348FE00EF50C4 /* Double.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -501,7 +605,20 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5F024AE11B4127C900EF50C4 /* IntTests.swift in Sources */, + 5F6A2F531CC09B9A00EF50C4 /* DeserializableTests.swift in Sources */, + 5F024AE31B412BA900EF50C4 /* BoolTests.swift in Sources */, + 5F31FF7A1C53496B00EF50C4 /* DoubleTests.swift in Sources */, + 5F31FF7E1C53499000EF50C4 /* NSDecimalNumberTests.swift in Sources */, + 5F31FF581C5339CE00EF50C4 /* NSURLTests.swift in Sources */, + 5FB9D4E01B38007C00EF50C4 /* StringTests.swift in Sources */, 5FAD07771A70F2FC00C4D09E /* JSONHelperTests.swift in Sources */, + 5F31FF7C1C53497600EF50C4 /* FloatTests.swift in Sources */, + 5F8F88231CA5F32E00EF50C4 /* DictionaryTests.swift in Sources */, + 5F31FF6C1C533F1600EF50C4 /* ColorTests.swift in Sources */, + 5F8F88251CA5F33500EF50C4 /* EnumTests.swift in Sources */, + 5FD3A0A01CA5F5C300EF50C4 /* ArrayTests.swift in Sources */, + 5F31FF561C5339B900EF50C4 /* NSDateTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -514,19 +631,24 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 5FAD07941A70F31300C4D09E /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 5FAD079F1A70F31300C4D09E /* JSONHelperExampleTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; D76C52011ACD46B100B49735 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - D76C52021ACD46B100B49735 /* JSONHelper.swift in Sources */, + 5FC1A4951B1D1D8B00EF50C4 /* NSURL.swift in Sources */, + 5F31FF6F1C5348F000EF50C4 /* NSDecimalNumber.swift in Sources */, + 5F6A2F4F1CC096DA00EF50C4 /* Serialization.swift in Sources */, + 5FC1A48C1B1D036700EF50C4 /* Int.swift in Sources */, + 5F31FF611C533E9900EF50C4 /* Color.swift in Sources */, + 5F31FF651C533EA000EF50C4 /* Conversion.swift in Sources */, + 5FC1A4911B1D082B00EF50C4 /* Bool.swift in Sources */, + 5F31FF631C533E9D00EF50C4 /* Deserialization.swift in Sources */, + 5F133DA31C3840C800EF50C4 /* JSONAPI.swift in Sources */, + 5F6A2F4B1CC0116D00EF50C4 /* JSONHelper.swift in Sources */, + 5F31FF771C53490B00EF50C4 /* Float.swift in Sources */, + 5FC1A48B1B1D036400EF50C4 /* String.swift in Sources */, + 5F31FF731C5348FE00EF50C4 /* Double.swift in Sources */, + 5FC1A4921B1D082D00EF50C4 /* NSDate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -535,19 +657,14 @@ /* Begin PBXTargetDependency section */ 5F0E6F951ACDD94E00D92679 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 5FAD07631A70F2FC00C4D09E /* JSONHelper */; + target = 5FAD07631A70F2FC00C4D09E /* JSONHelper-iOS */; targetProxy = 5F0E6F941ACDD94E00D92679 /* PBXContainerItemProxy */; }; 5FAD07721A70F2FC00C4D09E /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 5FAD07631A70F2FC00C4D09E /* JSONHelper */; + target = 5FAD07631A70F2FC00C4D09E /* JSONHelper-iOS */; targetProxy = 5FAD07711A70F2FC00C4D09E /* PBXContainerItemProxy */; }; - 5FAD079A1A70F31300C4D09E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 5FAD07831A70F31300C4D09E /* JSONHelperExample */; - targetProxy = 5FAD07991A70F31300C4D09E /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -582,11 +699,11 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_TESTABILITY = YES; GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "JSONHelper-tvOS/Info.plist"; + INFOPLIST_FILE = "JSONHelper/Supporting Files/tvOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.bsencan.JSONHelper; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = JSONHelper; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; @@ -604,11 +721,11 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_NO_COMMON_BLOCKS = YES; - INFOPLIST_FILE = "JSONHelper-tvOS/Info.plist"; + INFOPLIST_FILE = "JSONHelper/Supporting Files/tvOS/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.bsencan.JSONHelper; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = JSONHelper; SDKROOT = appletvos; SKIP_INSTALL = YES; TARGETED_DEVICE_FAMILY = 3; @@ -637,6 +754,7 @@ COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -714,9 +832,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.bsencan.JSONHelper; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = JSONHelper; SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; @@ -733,7 +850,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.bsencan.JSONHelper; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = JSONHelper; SKIP_INSTALL = YES; }; name = Release; @@ -751,6 +868,7 @@ ); INFOPLIST_FILE = "JSONHelperTests/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.bsencan.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -764,6 +882,7 @@ ); INFOPLIST_FILE = "JSONHelperTests/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.bsencan.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; @@ -778,6 +897,7 @@ ); INFOPLIST_FILE = "JSONHelperExample/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.bsencan.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -788,48 +908,16 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = "JSONHelperExample/Supporting Files/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.bsencan.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; }; - 5FAD07A41A70F31300C4D09E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = "JSONHelperExampleTests/Supporting Files/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JSONHelperExample.app/JSONHelperExample"; - }; - name = Debug; - }; - 5FAD07A51A70F31300C4D09E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); - INFOPLIST_FILE = "JSONHelperExampleTests/Supporting Files/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/JSONHelperExample.app/JSONHelperExample"; - }; - name = Release; - }; D76C52081ACD46B100B49735 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -842,7 +930,6 @@ PRODUCT_NAME = JSONHelper; SDKROOT = macosx; SKIP_INSTALL = YES; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; @@ -850,6 +937,7 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; @@ -868,7 +956,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 5F928D9B1C0D469F00EF50C4 /* Build configuration list for PBXNativeTarget "JSONHelper_tvOS" */ = { + 5F928D9B1C0D469F00EF50C4 /* Build configuration list for PBXNativeTarget "JSONHelper-tvOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 5F928D9C1C0D469F00EF50C4 /* Debug */, @@ -886,7 +974,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 5FAD077A1A70F2FC00C4D09E /* Build configuration list for PBXNativeTarget "JSONHelper" */ = { + 5FAD077A1A70F2FC00C4D09E /* Build configuration list for PBXNativeTarget "JSONHelper-iOS" */ = { isa = XCConfigurationList; buildConfigurations = ( 5FAD077B1A70F2FC00C4D09E /* Debug */, @@ -913,16 +1001,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 5FAD07A31A70F31300C4D09E /* Build configuration list for PBXNativeTarget "JSONHelperExampleTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 5FAD07A41A70F31300C4D09E /* Debug */, - 5FAD07A51A70F31300C4D09E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - D76C52071ACD46B100B49735 /* Build configuration list for PBXNativeTarget "JSONHelper_Mac" */ = { + D76C52071ACD46B100B49735 /* Build configuration list for PBXNativeTarget "JSONHelper-Mac" */ = { isa = XCConfigurationList; buildConfigurations = ( D76C52081ACD46B100B49735 /* Debug */, diff --git a/JSONHelper.xcodeproj/project.xcworkspace/xcshareddata/JSONHelper.xccheckout b/JSONHelper.xcodeproj/project.xcworkspace/xcshareddata/JSONHelper.xccheckout index 392c957..c6609dc 100644 --- a/JSONHelper.xcodeproj/project.xcworkspace/xcshareddata/JSONHelper.xccheckout +++ b/JSONHelper.xcodeproj/project.xcworkspace/xcshareddata/JSONHelper.xccheckout @@ -11,7 +11,7 @@ IDESourceControlProjectOriginsDictionary 9540366943750F418CA1A28462EA7F786EC07683 - https://github.com/isair/JSONHelper.git + github.com:isair/JSONHelper.git IDESourceControlProjectPath JSONHelper.xcodeproj @@ -21,7 +21,7 @@ ../.. IDESourceControlProjectURL - https://github.com/isair/JSONHelper.git + github.com:isair/JSONHelper.git IDESourceControlProjectVersion 111 IDESourceControlProjectWCCIdentifier diff --git a/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-Mac.xcscheme b/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-Mac.xcscheme index c0690fd..c26d3a1 100644 --- a/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-Mac.xcscheme +++ b/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-Mac.xcscheme @@ -1,6 +1,6 @@ + + + + @@ -26,9 +40,29 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> + + + + + + + + @@ -47,7 +81,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "D76C52001ACD46B100B49735" BuildableName = "JSONHelper.framework" - BlueprintName = "JSONHelper_Mac" + BlueprintName = "JSONHelper-Mac" ReferencedContainer = "container:JSONHelper.xcodeproj"> @@ -65,7 +99,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "D76C52001ACD46B100B49735" BuildableName = "JSONHelper.framework" - BlueprintName = "JSONHelper_Mac" + BlueprintName = "JSONHelper-Mac" ReferencedContainer = "container:JSONHelper.xcodeproj"> diff --git a/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-iOS.xcscheme b/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-iOS.xcscheme index a070507..38285a7 100644 --- a/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-iOS.xcscheme +++ b/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-iOS.xcscheme @@ -1,6 +1,6 @@ @@ -37,10 +37,11 @@ + codeCoverageEnabled = "YES"> @@ -58,26 +59,29 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "5FAD07631A70F2FC00C4D09E" BuildableName = "JSONHelper.framework" - BlueprintName = "JSONHelper" + BlueprintName = "JSONHelper-iOS" ReferencedContainer = "container:JSONHelper.xcodeproj"> + + @@ -85,17 +89,17 @@ diff --git a/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-tvOS.xcscheme b/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-tvOS.xcscheme index bc31816..d11baab 100644 --- a/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-tvOS.xcscheme +++ b/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelper-tvOS.xcscheme @@ -15,8 +15,22 @@ + + + + @@ -26,9 +40,29 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> + + + + + + + + @@ -46,8 +80,8 @@ @@ -64,8 +98,8 @@ diff --git a/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelperExample.xcscheme b/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelperExample.xcscheme index 1f8acf0..75bed48 100644 --- a/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelperExample.xcscheme +++ b/JSONHelper.xcodeproj/xcshareddata/xcschemes/JSONHelperExample.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -62,15 +62,18 @@ ReferencedContainer = "container:JSONHelper.xcodeproj"> + + @@ -86,10 +89,10 @@ diff --git a/JSONHelper/Conversion.swift b/JSONHelper/Conversion.swift new file mode 100644 index 0000000..b40bbce --- /dev/null +++ b/JSONHelper/Conversion.swift @@ -0,0 +1,171 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation + +/// Operator for use in right hand side to left hand side conversion. +infix operator <-- { associativity right precedence 150 } + +/// Thrown when a conversion operation fails. +public enum ConversionError: ErrorType { + + /// TODOC + case UnsupportedType + + /// TODOC + case InvalidValue +} + +/// An object that can attempt to convert values of unknown types to its own type. +public protocol Convertible { + + /// TODOC + static func convertFromValue(value: T?) throws -> Self? +} + +// MARK: - Basic Conversion + +public func <-- (inout lhs: T?, rhs: U?) throws -> T? { + if !(lhs is NSNull) { + lhs = JSONHelper.convertToNilIfNull(rhs) as? T + } else { + lhs = rhs as? T + } + return lhs +} + +public func <-- (inout lhs: T, rhs: U?) throws -> T { + var newValue: T? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} + +public func <-- (inout lhs: C?, rhs: T?) throws -> C? { + lhs = try C.convertFromValue(JSONHelper.convertToNilIfNull(rhs)) + return lhs +} + +public func <-- (inout lhs: C, rhs: T?) throws -> C { + var newValue: C? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} + +// MARK: - Array Conversion + +public func <-- (inout lhs: [C]?, rhs: [T]?) throws -> [C]? { + guard let rhs = rhs else { + lhs = nil + return lhs + } + + lhs = [C]() + for element in rhs { + var convertedElement: C? + try convertedElement <-- element + if let convertedElement = convertedElement { + lhs?.append(convertedElement) + } + } + + return lhs +} + +public func <-- (inout lhs: [C], rhs: [T]?) throws -> [C] { + var newValue: [C]? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} + +public func <-- (inout lhs: [C]?, rhs: T?) throws -> [C]? { + guard let rhs = rhs else { + lhs = nil + return lhs + } + + if let elements = rhs as? NSArray as? [AnyObject] { + return try lhs <-- elements + } + + throw ConversionError.UnsupportedType +} + +public func <-- (inout lhs: [C], rhs: T?) throws -> [C] { + var newValue: [C]? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} + +// MARK: - Dictionary Conversion + +public func <-- (inout lhs: [T : C]?, rhs: [T : U]?) throws -> [T : C]? { + guard let rhs = rhs else { + lhs = nil + return lhs + } + + lhs = [T : C]() + for (key, value) in rhs { + var convertedValue: C? + try convertedValue <-- value + if let convertedValue = convertedValue { + lhs?[key] = convertedValue + } + } + + return lhs +} + +public func <-- (inout lhs: [T : C], rhs: [T : U]?) throws -> [T : C] { + var newValue: [T : C]? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} + +public func <-- (inout lhs: [T : C]?, rhs: U?) throws -> [T : C]? { + guard let rhs = rhs else { + lhs = nil + return lhs + } + + if let elements = rhs as? NSDictionary as? [T : AnyObject] { + return try lhs <-- elements + } + + throw ConversionError.UnsupportedType +} + +public func <-- (inout lhs: [T : C], rhs: U?) throws -> [T : C] { + var newValue: [T : C]? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} + +// MARK: - Enum Conversion + +public func <-- (inout lhs: T?, rhs: U?) throws -> T? { + var newValue: T? + + if let + rawValue = rhs as? T.RawValue, + enumValue = T(rawValue: rawValue) { + newValue = enumValue + } + lhs = newValue + + return lhs +} + +public func <-- (inout lhs: T, rhs: U?) throws -> T { + var newValue: T? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} diff --git a/JSONHelper/Deserialization.swift b/JSONHelper/Deserialization.swift new file mode 100644 index 0000000..9fb7646 --- /dev/null +++ b/JSONHelper/Deserialization.swift @@ -0,0 +1,134 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation + +/// TODOC +public protocol Deserializable { + + /// TODOC + init(dictionary: [String : AnyObject]) throws +} + +// MARK: - Helper Methods + +private func dataStringToObject(dataString: String) -> AnyObject? { + guard let data: NSData = dataString.dataUsingEncoding(NSUTF8StringEncoding) else { return nil } + var jsonObject: AnyObject? + do { + jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0)) + } catch {} + return jsonObject +} + +// MARK: - Basic Deserialization + +public func <-- (inout lhs: D?, rhs: T?) throws -> D? { + let cleanedValue = JSONHelper.convertToNilIfNull(rhs) + + if let jsonObject = cleanedValue as? NSDictionary as? [String : AnyObject] { + lhs = try D(dictionary: jsonObject) + } else if let string = cleanedValue as? String { + try lhs <-- dataStringToObject(string) + } else { + lhs = nil + } + + return lhs +} + +public func <-- (inout lhs: D, rhs: T?) throws -> D { + var newValue: D? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} + +// MARK: - Array Deserialization + +public func <-- (inout lhs: [D]?, rhs: [T]?) throws -> [D]? { + guard let rhs = rhs else { return nil } + + lhs = [D]() + for element in rhs { + var convertedElement: D? + try convertedElement <-- element + if let convertedElement = convertedElement { + lhs?.append(convertedElement) + } + } + + return lhs +} + +public func <-- (inout lhs: [D], rhs: [T]?) throws -> [D] { + var newValue: [D]? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} + +public func <-- (inout lhs: [D]?, rhs: T?) throws -> [D]? { + guard let rhs = rhs else { return nil } + + if let elements = rhs as? NSArray as? [AnyObject] { + return try lhs <-- elements + } + + throw ConversionError.UnsupportedType +} + +public func <-- (inout lhs: [D], rhs: T?) throws -> [D] { + var newValue: [D]? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} + +// MARK: - Dictionary Deserialization + +public func <-- (inout lhs: [T : D]?, rhs: [T : U]?) throws -> [T : D]? { + guard let rhs = rhs else { + lhs = nil + return lhs + } + + lhs = [T : D]() + for (key, value) in rhs { + var convertedValue: D? + try convertedValue <-- value + if let convertedValue = convertedValue { + lhs?[key] = convertedValue + } + } + + return lhs +} + +public func <-- (inout lhs: [T : D], rhs: [T : U]?) throws -> [T : D] { + var newValue: [T : D]? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} + +public func <-- (inout lhs: [T : D]?, rhs: U?) throws -> [T : D]? { + guard let rhs = rhs else { + lhs = nil + return lhs + } + + if let elements = rhs as? NSDictionary as? [T : AnyObject] { + return try lhs <-- elements + } + + throw ConversionError.UnsupportedType +} + +public func <-- (inout lhs: [T : D], rhs: U?) throws -> [T : D] { + var newValue: [T : D]? + try newValue <-- rhs + lhs = newValue ?? lhs + return lhs +} diff --git a/JSONHelper/Extensions/Bool.swift b/JSONHelper/Extensions/Bool.swift new file mode 100644 index 0000000..b6fd410 --- /dev/null +++ b/JSONHelper/Extensions/Bool.swift @@ -0,0 +1,29 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation + +extension Bool: Convertible { + + public static func convertFromValue(value: T?) throws -> Bool? { + guard let value = value else { return nil } + + if let boolValue = value as? Bool { + return boolValue + } else if let intValue = value as? Int { + return intValue > 0 + } else if let stringValue = value as? String { + switch stringValue.lowercaseString { + case "true", "t", "yes", "y": + return true + case "false", "f", "no", "n": + return false + default: + throw ConversionError.InvalidValue + } + } + + throw ConversionError.UnsupportedType + } +} diff --git a/JSONHelper/Extensions/Color.swift b/JSONHelper/Extensions/Color.swift new file mode 100644 index 0000000..748a4b1 --- /dev/null +++ b/JSONHelper/Extensions/Color.swift @@ -0,0 +1,84 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +private struct ColorConversionHelper { + + private static func hexStringToRGBA(hexString: String) throws -> (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { + var red = CGFloat(0) + var green = CGFloat(0) + var blue = CGFloat(0) + var alpha = CGFloat(1) + + if hexString.hasPrefix("#") { + let index = hexString.startIndex.advancedBy(1) + let hex = hexString.substringFromIndex(index) + let scanner = NSScanner(string: hex) + var hexValue = CUnsignedLongLong(0) + + if scanner.scanHexLongLong(&hexValue) { + switch (hex.characters.count) { + case 3: + red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 + green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 + blue = CGFloat(hexValue & 0x00F) / 15.0 + case 4: + red = CGFloat((hexValue & 0xF000) >> 12) / 15.0 + green = CGFloat((hexValue & 0x0F00) >> 8) / 15.0 + blue = CGFloat((hexValue & 0x00F0) >> 4) / 15.0 + alpha = CGFloat(hexValue & 0x000F) / 15.0 + case 6: + red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0 + green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 + blue = CGFloat(hexValue & 0x0000FF) / 255.0 + case 8: + red = CGFloat((hexValue & 0xFF000000) >> 24) / 255.0 + green = CGFloat((hexValue & 0x00FF0000) >> 16) / 255.0 + blue = CGFloat((hexValue & 0x0000FF00) >> 8) / 255.0 + alpha = CGFloat(hexValue & 0x000000FF) / 255.0 + default: + throw ConversionError.InvalidValue + } + } + } + return (red: red, green: green, blue: blue, alpha: alpha) + } +} + +#if os(OSX) + +import AppKit + +extension NSColor: Convertible { + + public static func convertFromValue(value: T?) throws -> Self? { + guard let value = value else { return nil } + + if let stringValue = value as? String { + let rgba = try ColorConversionHelper.hexStringToRGBA(stringValue) + return self.init(red: rgba.red, green: rgba.green, blue: rgba.blue, alpha: rgba.alpha) + } + + throw ConversionError.UnsupportedType + } +} + +#else + +import UIKit + +extension UIColor: Convertible { + + public static func convertFromValue(value: T?) throws -> Self? { + guard let value = value else { return nil } + + if let stringValue = value as? String { + let rgba = try ColorConversionHelper.hexStringToRGBA(stringValue) + return self.init(red: rgba.red, green: rgba.green, blue: rgba.blue, alpha: rgba.alpha) + } + + throw ConversionError.UnsupportedType + } +} + +#endif diff --git a/JSONHelper/Extensions/Double.swift b/JSONHelper/Extensions/Double.swift new file mode 100644 index 0000000..7e4f9c4 --- /dev/null +++ b/JSONHelper/Extensions/Double.swift @@ -0,0 +1,24 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation + +extension Double: Convertible { + + public static func convertFromValue(value: T?) throws -> Double? { + guard let value = value else { return nil } + + if let doubleValue = value as? Double { + return doubleValue + } else if let stringValue = value as? String { + return Double(stringValue) + } else if let floatValue = value as? Float { + return Double(floatValue) + } else if let intValue = value as? Int { + return Double(intValue) + } + + throw ConversionError.UnsupportedType + } +} diff --git a/JSONHelper/Extensions/Float.swift b/JSONHelper/Extensions/Float.swift new file mode 100644 index 0000000..fde0518 --- /dev/null +++ b/JSONHelper/Extensions/Float.swift @@ -0,0 +1,24 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation + +extension Float: Convertible { + + public static func convertFromValue(value: T?) throws -> Float? { + guard let value = value else { return nil } + + if let floatValue = value as? Float { + return floatValue + } else if let stringValue = value as? String { + return Float(stringValue) + } else if let doubleValue = value as? Double { + return Float(doubleValue) + } else if let intValue = value as? Int { + return Float(intValue) + } + + throw ConversionError.UnsupportedType + } +} diff --git a/JSONHelper/Extensions/Int.swift b/JSONHelper/Extensions/Int.swift new file mode 100644 index 0000000..95c5187 --- /dev/null +++ b/JSONHelper/Extensions/Int.swift @@ -0,0 +1,24 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation + +extension Int: Convertible { + + public static func convertFromValue(value: T?) throws -> Int? { + guard let value = value else { return nil } + + if let intValue = value as? Int { + return intValue + } else if let stringValue = value as? String { + return Int(stringValue) + } else if let floatValue = value as? Float { + return Int(floatValue) + } else if let doubleValue = value as? Double { + return Int(doubleValue) + } + + throw ConversionError.UnsupportedType + } +} diff --git a/JSONHelper/Extensions/NSDate.swift b/JSONHelper/Extensions/NSDate.swift new file mode 100644 index 0000000..51d8690 --- /dev/null +++ b/JSONHelper/Extensions/NSDate.swift @@ -0,0 +1,25 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation + +extension NSDate: Convertible { + private static let sharedFormatter = NSDateFormatter() + + public static func convertFromValue(value: T?) throws -> Self? { + guard let value = value else { return nil } + + if let unixTimestamp = value as? Int { + return self.init(timeIntervalSince1970: NSTimeInterval(unixTimestamp)) + } else if let dateString = value as? String { + if let convertedDate = JSONHelper.dateFormatter.dateFromString(dateString) { + return self.init(timeIntervalSince1970: convertedDate.timeIntervalSince1970) + } else { + throw ConversionError.InvalidValue + } + } + + throw ConversionError.UnsupportedType + } +} diff --git a/JSONHelper/Extensions/NSDecimalNumber.swift b/JSONHelper/Extensions/NSDecimalNumber.swift new file mode 100644 index 0000000..ed93304 --- /dev/null +++ b/JSONHelper/Extensions/NSDecimalNumber.swift @@ -0,0 +1,24 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation + +extension NSDecimalNumber: Convertible { + + public static func convertFromValue(value: T?) throws -> Self? { + guard let value = value else { return nil } + + if let doubleValue = value as? Double { + return self.init(double: doubleValue) + } else if let stringValue = value as? String { + return self.init(string: stringValue) + } else if let floatValue = value as? Float { + return self.init(float: floatValue) + } else if let intValue = value as? Int { + return self.init(integer: intValue) + } + + throw ConversionError.UnsupportedType + } +} diff --git a/JSONHelper/Extensions/NSURL.swift b/JSONHelper/Extensions/NSURL.swift new file mode 100644 index 0000000..55c5c91 --- /dev/null +++ b/JSONHelper/Extensions/NSURL.swift @@ -0,0 +1,20 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation + +extension NSURL: Convertible { + + public static func convertFromValue(value: T?) throws -> Self? { + guard let value = value else { return nil } + + if let urlValue = value as? NSURL { + return self.init(string: urlValue.absoluteString) + } else if let stringValue = value as? String { + return self.init(string: stringValue) + } + + throw ConversionError.UnsupportedType + } +} diff --git a/JSONHelper/Extensions/String.swift b/JSONHelper/Extensions/String.swift new file mode 100644 index 0000000..720b12c --- /dev/null +++ b/JSONHelper/Extensions/String.swift @@ -0,0 +1,22 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation + +extension String: Convertible { + + public static func convertFromValue(value: T?) throws -> String? { + guard let value = value else { return nil } + + if let stringValue = value as? String { + return stringValue + } else if let intValue = value as? Int { + return "\(intValue)" + } else if let dateValue = value as? NSDate { + return JSONHelper.dateFormatter.stringFromDate(dateValue) + } + + throw ConversionError.UnsupportedType + } +} diff --git a/JSONHelper/JSONHelper.swift b/JSONHelper/JSONHelper.swift index 561ab39..f3e86a3 100644 --- a/JSONHelper/JSONHelper.swift +++ b/JSONHelper/JSONHelper.swift @@ -1,545 +1,20 @@ // -// JSONHelper.swift -// -// Created by Baris Sencan on 28/08/2014. -// Copyright 2014 Baris Sencan -// -// Distributed under the permissive zlib license -// Get the latest version from here: -// -// https://github.com/isair/JSONHelper -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// -// 3. This notice may not be removed or altered from any source distribution. +// Copyright © 2016 Baris Sencan. All rights reserved. // import Foundation -/// A type of dictionary that only uses strings for keys and can contain any -/// type of object as a value. -public typealias JSONDictionary = [String: AnyObject] - -/// Operator for use in deserialization operations. -infix operator <-- { associativity right precedence 150 } - -/// Returns nil if given object is of type NSNull. -/// -/// :param: object Object to convert. -/// -/// :returns: nil if object is of type NSNull, else returns the object itself. -private func convertToNilIfNull(object: AnyObject?) -> AnyObject? { - if object is NSNull { - return nil - } - return object -} - -// MARK: Primitive Type Deserialization - -// For optionals. -public func <-- (inout property: T?, value: AnyObject?) -> T? { - var newValue: T? - "" - if let unwrappedValue: AnyObject = convertToNilIfNull(value) { - // We unwrapped the given value successfully, try to convert. - if let convertedValue = unwrappedValue as? T { - // Convert by just type-casting. - newValue = convertedValue - } else { - // Convert by processing the value first. - switch property { - case is NSURL?: - newValue = NSURL(string: "\(unwrappedValue)") as? T - case is NSDate?: - if let timestamp = unwrappedValue as? Int { - newValue = NSDate(timeIntervalSince1970: Double(timestamp)) as? T - } else if let timestamp = unwrappedValue as? Double { - newValue = NSDate(timeIntervalSince1970: timestamp) as? T - } else if let timestamp = unwrappedValue as? NSNumber { - newValue = NSDate(timeIntervalSince1970: timestamp.doubleValue) as? T - } - case is Int?: - if unwrappedValue is String { - if let intValue = Int("\(unwrappedValue)") { - newValue = intValue as? T - } - } - default: - break - } - } - } - property = newValue - return property -} - -// For non-optionals. -public func <-- (inout property: T, value: AnyObject?) -> T { - var newValue: T? - newValue <-- value - if let newValue = newValue { property = newValue } - return property -} - -// Special handling for value and format pair to NSDate conversion. -public func <-- (inout property: NSDate?, valueAndFormat: (AnyObject?, AnyObject?)) -> NSDate? { - var newValue: NSDate? - if let dateString = convertToNilIfNull(valueAndFormat.0) as? String { - if let formatString = convertToNilIfNull(valueAndFormat.1) as? String { - let dateFormatter = NSDateFormatter() - dateFormatter.dateFormat = formatString - if let newDate = dateFormatter.dateFromString(dateString) { - newValue = newDate - } - } - } - property = newValue - return property -} - -public func <-- (inout property: NSDate, valueAndFormat: (AnyObject?, AnyObject?)) -> NSDate { - var date: NSDate? - date <-- valueAndFormat - if let date = date { property = date } - return property -} - -// MARK: Primitive Array Deserialization - -public func <-- (inout array: [String]?, value: AnyObject?) -> [String]? { - if let stringArray = convertToNilIfNull(value) as? [String] { - array = stringArray - } else { - array = nil - } - return array -} - -public func <-- (inout array: [String], value: AnyObject?) -> [String] { - var newValue: [String]? - newValue <-- value - if let newValue = newValue { array = newValue } - return array -} - -public func <-- (inout array: [Int]?, value: AnyObject?) -> [Int]? { - if let intArray = convertToNilIfNull(value) as? [Int] { - array = intArray - } else { - array = nil - } - return array -} - -public func <-- (inout array: [Int], value: AnyObject?) -> [Int] { - var newValue: [Int]? - newValue <-- value - if let newValue = newValue { array = newValue } - return array -} - -public func <-- (inout array: [Float]?, value: AnyObject?) -> [Float]? { - if let floatArray = convertToNilIfNull(value) as? [Float] { - array = floatArray - } else { - array = nil - } - return array -} - -public func <-- (inout array: [Float], value: AnyObject?) -> [Float] { - var newValue: [Float]? - newValue <-- value - if let newValue = newValue { array = newValue } - return array -} - -public func <-- (inout array: [Double]?, value: AnyObject?) -> [Double]? { - if let doubleArrayDoubleExcitement = convertToNilIfNull(value) as? [Double] { - array = doubleArrayDoubleExcitement - } else { - array = nil - } - return array -} - -public func <-- (inout array: [Double], value: AnyObject?) -> [Double] { - var newValue: [Double]? - newValue <-- value - if let newValue = newValue { array = newValue } - return array -} - -public func <-- (inout array: [Bool]?, value: AnyObject?) -> [Bool]? { - if let boolArray = convertToNilIfNull(value) as? [Bool] { - array = boolArray - } else { - array = nil - } - return array -} - -public func <-- (inout array: [Bool], value: AnyObject?) -> [Bool] { - var newValue: [Bool]? - newValue <-- value - if let newValue = newValue { array = newValue } - return array -} - -public func <-- (inout array: [NSURL]?, value: AnyObject?) -> [NSURL]? { - if let stringURLArray = convertToNilIfNull(value) as? [String] { - array = [NSURL]() - for stringURL in stringURLArray { - if let url = NSURL(string: stringURL) { - array!.append(url) - } - } - } else { - array = nil - } - return array -} - -public func <-- (inout array: [NSURL], value: AnyObject?) -> [NSURL] { - var newValue: [NSURL]? - newValue <-- value - if let newValue = newValue { array = newValue } - return array -} - -public func <-- (inout array: [NSDate]?, valueAndFormat: (AnyObject?, AnyObject?)) -> [NSDate]? { - var newValue: [NSDate]? - if let dateStringArray = convertToNilIfNull(valueAndFormat.0) as? [String] { - if let formatString = convertToNilIfNull(valueAndFormat.1) as? String { - let dateFormatter = NSDateFormatter() - dateFormatter.dateFormat = formatString - newValue = [NSDate]() - for dateString in dateStringArray { - if let date = dateFormatter.dateFromString(dateString) { - newValue!.append(date) - } - } - } - } - array = newValue - return array -} - -public func <-- (inout array: [NSDate], valueAndFormat: (AnyObject?, AnyObject?)) -> [NSDate] { - var newValue: [NSDate]? - newValue <-- valueAndFormat - if let newValue = newValue { array = newValue } - return array -} - -public func <-- (inout array: [NSDate]?, value: AnyObject?) -> [NSDate]? { - if let timestamps = convertToNilIfNull(value) as? [AnyObject] { - array = [NSDate]() - for timestamp in timestamps { - var date: NSDate? - date <-- timestamp - if date != nil { array!.append(date!) } - } - } else { - array = nil - } - return array -} - -public func <-- (inout array: [NSDate], value: AnyObject?) -> [NSDate] { - var newValue: [NSDate]? - newValue <-- value - if let newValue = newValue { array = newValue } - return array -} - - -// MARK: Primitive Map Deserialization - -public func <-- (inout map: [String: String]?, value: AnyObject?) -> [String: String]? { - if let stringMap = convertToNilIfNull(value) as? [String: String] { - map = stringMap - } else { - map = nil - } - return map -} - -public func <-- (inout map: [String: String], value: AnyObject?) -> [String: String] { - var newValue: [String: String]? - newValue <-- value - if let newValue = newValue { map = newValue } - return map -} - -public func <-- (inout map: [String: Int]?, value: AnyObject?) -> [String: Int]? { - if let intMap = convertToNilIfNull(value) as? [String: Int] { - map = intMap - } else { - map = nil - } - return map -} - -public func <-- (inout map: [String: Int], value: AnyObject?) -> [String: Int] { - var newValue: [String: Int]? - newValue <-- value - if let newValue = newValue { map = newValue } - return map -} - -public func <-- (inout map: [String: Float]?, value: AnyObject?) -> [String: Float]? { - if let floatMap = convertToNilIfNull(value) as? [String: Float] { - map = floatMap - } else { - map = nil - } - return map -} +public class JSONHelper { -public func <-- (inout map: [String: Float], value: AnyObject?) -> [String: Float] { - var newValue: [String: Float]? - newValue <-- value - if let newValue = newValue { map = newValue } - return map -} + /// Date formatter that is used when converting strings to NSDate objects. + public static var dateFormatter = NSDateFormatter() -public func <-- (inout map: [String: Double]?, value: AnyObject?) -> [String: Double]? { - if let doubleMapDoubleExcitement = convertToNilIfNull(value) as? [String: Double] { - map = doubleMapDoubleExcitement - } else { - map = nil + /// Filters out values of type NSNull. + /// + /// :param: value Value to check. + /// + /// :returns: nil if value is of type NSNull, else the value is returned as-is. + public static func convertToNilIfNull(value: T?) -> T? { + return (value is NSNull) ? nil : value } - return map -} - -public func <-- (inout map: [String: Double], value: AnyObject?) -> [String: Double] { - var newValue: [String: Double]? - newValue <-- value - if let newValue = newValue { map = newValue } - return map -} - -public func <-- (inout map: [String: Bool]?, value: AnyObject?) -> [String: Bool]? { - if let boolMap = convertToNilIfNull(value) as? [String: Bool] { - map = boolMap - } else { - map = nil - } - return map -} - -public func <-- (inout map: [String: Bool], value: AnyObject?) -> [String: Bool] { - var newValue: [String: Bool]? - newValue <-- value - if let newValue = newValue { map = newValue } - return map -} - -public func <-- (inout map: [String: NSURL]?, value: AnyObject?) -> [String: NSURL]? { - if let stringURLMap = convertToNilIfNull(value) as? [String: String] { - map = [String: NSURL]() - for (key, stringURL) in stringURLMap { - if let url = NSURL(string: stringURL) { - map![key] = url - } - } - } else { - map = nil - } - return map -} - -public func <-- (inout map: [String: NSURL], value: AnyObject?) -> [String: NSURL] { - var newValue: [String: NSURL]? - newValue <-- value - if let newValue = newValue { map = newValue } - return map } - -public func <-- (inout map: [String: NSDate]?, valueAndFormat: (AnyObject?, AnyObject?)) -> [String: NSDate]? { - var newValue: [String: NSDate]? - if let dateStringMap = convertToNilIfNull(valueAndFormat.0) as? [String: String] { - if let formatString = convertToNilIfNull(valueAndFormat.1) as? String { - let dateFormatter = NSDateFormatter() - dateFormatter.dateFormat = formatString - newValue = [String: NSDate]() - for (key, dateString) in dateStringMap { - if let date = dateFormatter.dateFromString(dateString) { - newValue![key] = date - } - } - } - } - map = newValue - return map -} - -public func <-- (inout map: [String: NSDate], valueAndFormat: (AnyObject?, AnyObject?)) -> [String: NSDate] { - var newValue: [String: NSDate]? - newValue <-- valueAndFormat - if let newValue = newValue { map = newValue } - return map -} - -public func <-- (inout map: [String: NSDate]?, value: AnyObject?) -> [String: NSDate]? { - if let timestamps = convertToNilIfNull(value) as? [String: AnyObject] { - map = [String: NSDate]() - for (key, timestamp) in timestamps { - var date: NSDate? - date <-- timestamp - if date != nil { map![key] = date! } - } - } else { - map = nil - } - return map -} - -public func <-- (inout map: [String: NSDate], value: AnyObject?) -> [String: NSDate] { - var newValue: [String: NSDate]? - newValue <-- value - if let newValue = newValue { map = newValue } - return map -} - - -// MARK: Custom Object Deserialization - -public protocol Deserializable { - init(data: JSONDictionary) -} - -public func <-- (inout instance: T?, dataObject: AnyObject?) -> T? { - if let data = convertToNilIfNull(dataObject) as? JSONDictionary { - instance = T(data: data) - } else { - instance = nil - } - return instance -} - -public func <-- (inout instance: T, dataObject: AnyObject?) -> T { - var newInstance: T? - newInstance <-- dataObject - if let newInstance = newInstance { instance = newInstance } - return instance -} - -// MARK: Custom Object Array Deserialization - -public func <-- (inout array: [T]?, dataObject: AnyObject?) -> [T]? { - if let dataArray = convertToNilIfNull(dataObject) as? [JSONDictionary] { - array = [T]() - for data in dataArray { - array!.append(T(data: data)) - } - } else { - array = nil - } - return array -} - -public func <-- (inout array: [T], dataObject: AnyObject?) -> [T] { - var newArray: [T]? - newArray <-- dataObject - if let newArray = newArray { array = newArray } - return array -} - -// MARK: Custom Object Map Deserialization - -public func <-- (inout map: [String: T]?, dataObject: AnyObject?) -> [String: T]? { - if let dataMap = convertToNilIfNull(dataObject) as? [String: JSONDictionary] { - map = [String: T]() - for (key, data) in dataMap { - map![key] = T(data: data) - } - } else { - map = nil - } - return map -} - -public func <-- (inout map: [String: T], dataObject: AnyObject?) -> [String: T] { - var newMap: [String: T]? - newMap <-- dataObject - if let newMap = newMap { map = newMap } - return map -} - -// MARK: Raw Value Representable (Enum) Deserialization - -public func <-- (inout property: T?, value: AnyObject?) -> T? { - var newEnumValue: T? - var newRawEnumValue: T.RawValue? - newRawEnumValue <-- value - if let unwrappedNewRawEnumValue = newRawEnumValue { - if let enumValue = T(rawValue: unwrappedNewRawEnumValue) { - newEnumValue = enumValue - } - } - property = newEnumValue - return property -} - -// For non-optionals. -public func <-- (inout property: T, value: AnyObject?) -> T { - var newValue: T? - newValue <-- value - if let newValue = newValue { property = newValue } - return property -} - -// MARK: JSON String Deserialization - -private func dataStringToObject(dataString: String) -> AnyObject? { - let data: NSData = dataString.dataUsingEncoding(NSUTF8StringEncoding)! - do { - let jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0)) - return jsonObject - } catch { - return nil - } -} - -public func <-- (inout instance: T?, dataString: String) -> T? { - return instance <-- dataStringToObject(dataString) -} - -public func <-- (inout instance: T, dataString: String) -> T { - return instance <-- dataStringToObject(dataString) -} - -public func <-- (inout array: [T]?, dataString: String) -> [T]? { - return array <-- dataStringToObject(dataString) -} - -public func <-- (inout array: [T], dataString: String) -> [T] { - return array <-- dataStringToObject(dataString) -} - -public func <-- (inout map: [String: T]?, dataString: String) -> [String:T]? { - return map <-- dataStringToObject(dataString) -} - -public func <-- (inout map: [String: T], dataString: String) -> [String:T] { - return map <-- dataStringToObject(dataString) -} - - diff --git a/JSONHelper/Serialization.swift b/JSONHelper/Serialization.swift new file mode 100644 index 0000000..cab6854 --- /dev/null +++ b/JSONHelper/Serialization.swift @@ -0,0 +1,14 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation + +/// TODOC +public protocol Serializable { + + /// TODOC + func toDictionary() throws -> [String : AnyObject] +} + +// TODO diff --git a/JSONHelper/Support/JSONAPI.swift b/JSONHelper/Support/JSONAPI.swift new file mode 100644 index 0000000..884cecb --- /dev/null +++ b/JSONHelper/Support/JSONAPI.swift @@ -0,0 +1,292 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +//import Foundation +// +///// Structure for holding a response returned by a JSON API server. +//public struct JSONAPIResponse: Deserializable { +// private(set) public var jsonapi = JSONAPISpecification() +// private(set) public var links = JSONAPILinks() +// private(set) public var data: AnyObject? = nil +// private(set) public var included = [[String : AnyObject]]() +// private(set) public var errors = [JSONAPIError]() +// private(set) public var meta = [String : AnyObject]() +// +// /// The original raw response data, read-only. +// public let raw: [String : AnyObject] +// +// public enum Fields: String { +// case jsonapi, links, data, included, errors, meta +// } +// +// public init(dictionary: [String : AnyObject]) throws { +// try jsonapi <-- dictionary[Fields.jsonapi.rawValue] +// try links <-- dictionary[Fields.links.rawValue] +// self.data = dictionary[Fields.data.rawValue] +// try included <-- dictionary[Fields.included.rawValue] +// try errors <-- dictionary[Fields.errors.rawValue] +// try meta <-- dictionary[Fields.meta.rawValue] +// raw = dictionary +// } +// +// public init() { +// raw = [String : AnyObject]() +// } +// +// /// Traverses the response `data` and replaces objects in `relationships` with +// /// full objects from the `included` section of the response. +// /// +// /// This is an expensive operation and should only be used if needed. +// public mutating func replaceRelationshipsInDataWithIncluded() { +// if let dataDictionary = data as? [String : AnyObject] { +// data = processDataDictionary(dataDictionary) +// } else if let dataArray = data as? [[String : AnyObject]] { +// var newData = [[String : AnyObject]]() +// for dataDictionary in dataArray { +// newData.append(processDataDictionary(dataDictionary)) +// } +// data = newData +// } +// } +// +// private func processDataDictionary(dataDictionary: [String : AnyObject]) -> [String : AnyObject] { +// let resourceObject = (try? JSONAPIResourceObject(dictionary: dataDictionary)) ?? JSONAPIResourceObject() +// var newData = [String : AnyObject]() +// +// for (key, value) in dataDictionary { +// newData[key] = value +// } +// +// var newRelationships = [String: [String : AnyObject]]() +// for (relationshipName, relationshipObject) in resourceObject.relationships { +// var newRelationship = [String : AnyObject]() +// +// if let links = dataDictionary["relationships"]?[relationshipName]??["links"] { +// newRelationship["links"] = links +// } +// +// if let relationshipDataDictionary = relationshipObject.data as? [String : AnyObject] { +// newRelationship["data"] = processRelationshipDataDictionary(relationshipDataDictionary) +// } else if let relationshipDataArray = relationshipObject.data as? [[String : AnyObject]] { +// var newRelationshipData = [[String : AnyObject]]() +// +// for relationshipDataDictionary in relationshipDataArray { +// newRelationshipData.append(processRelationshipDataDictionary(relationshipDataDictionary) ?? relationshipDataDictionary) +// } +// newRelationship["data"] = newRelationshipData +// } +// +// if let meta = dataDictionary["relationships"]?[relationshipName]??["meta"] { +// newRelationship["meta"] = meta +// } +// +// newRelationships[relationshipName] = newRelationship +// } +// +// newData["relationships"] = newRelationships +// +// return newData +// } +// +// private func processRelationshipDataDictionary(relationshipDataDictionary: [String : AnyObject]) -> [String : AnyObject]? { +// let idKey = JSONAPIResourceObject.BaseFields.id.rawValue +// let typeKey = JSONAPIResourceObject.BaseFields.type.rawValue +// +// if let +// relationshipObjectID = relationshipDataDictionary[idKey] as? String, +// relationshipObjectType = relationshipDataDictionary[typeKey] as? String, +// includedObject = getIncludedObjectOfType(relationshipObjectType, withID: relationshipObjectID) { +// return includedObject +// } +// return nil +// } +// +// public func getIncludedObjectOfType(type: String, withID id: String) -> [String : AnyObject]? { +// let idKey = JSONAPIResourceObject.BaseFields.id.rawValue +// let typeKey = JSONAPIResourceObject.BaseFields.type.rawValue +// +// for include in included { +// if ((include[idKey] as? String) == id) && ((include[typeKey] as? String) == type) { +// return include +// } +// } +// return nil +// } +//} +// +//public struct JSONAPISpecification: Deserializable { +// private(set) public var version = "1.0" +// +// public enum Field: String { +// case version +// } +// +// public init(dictionary: [String : AnyObject]) throws { +// try version <-- dictionary[Field.version.rawValue] +// } +// +// public init() {} +//} +// +///// A JSON API links object. http://jsonapi.org/format/#fetching-pagination +//public struct JSONAPILinks: Deserializable { +// private(set) public var current: JSONAPILink? = nil +// private(set) public var about: JSONAPILink? = nil +// private(set) public var related: JSONAPILink? = nil +// private(set) public var first: JSONAPILink? = nil +// private(set) public var last: JSONAPILink? = nil +// private(set) public var prev: JSONAPILink? = nil +// private(set) public var next: JSONAPILink? = nil +// +// public enum Field: String { +// case current = "self" +// case about = "about" +// case related = "related" +// case first = "first" +// case last = "last" +// case prev = "prev" +// case next = "next" +// } +// +// public init(dictionary: [String : AnyObject]) { +// current = deserializeLink(dictionary[Field.current.rawValue]) +// about = deserializeLink(dictionary[Field.about.rawValue]) +// related = deserializeLink(dictionary[Field.related.rawValue]) +// first = deserializeLink(dictionary[Field.first.rawValue]) +// last = deserializeLink(dictionary[Field.last.rawValue]) +// prev = deserializeLink(dictionary[Field.prev.rawValue]) +// next = deserializeLink(dictionary[Field.next.rawValue]) +// } +// +// private func deserializeLink(data: AnyObject?) -> JSONAPILink? { +// do { +// if let urlString = data as? String { +// return try JSONAPILink(dictionary: [JSONAPILink.Field.href.rawValue: urlString]) +// } +// return try JSONAPILink(dictionary: (data as? [String : AnyObject]) ?? [:]) +// } catch { +// return nil +// } +// } +// +// public init() {} +//} +// +///// A JSON API link object. http://jsonapi.org/format/#document-links +//public struct JSONAPILink: Deserializable { +// private(set) public var href: NSURL? +// private(set) public var meta = [String : AnyObject]() +// +// public enum Field: String { +// case href, meta +// } +// +// public init(dictionary: [String : AnyObject]) throws { +// try href <-- dictionary[Field.href.rawValue] +// try meta <-- dictionary[Field.meta.rawValue] +// } +//} +// +///// A JSON API error object. http://jsonapi.org/format/#errors +//public struct JSONAPIError: Deserializable { +// private(set) public var id: String? +// private(set) public var links = JSONAPILinks() +// private(set) public var status: String? +// private(set) public var code: String? +// private(set) public var title: String? +// private(set) public var detail: String? +// private(set) public var source = JSONAPIErrorSource() +// private(set) public var meta = [String : AnyObject]() +// +// public enum Field: String { +// case id, links, status, code, title, detail, source, meta +// } +// +// public init(dictionary: [String : AnyObject]) throws { +// try id <-- dictionary[Field.id.rawValue] +// try links <-- dictionary[Field.links.rawValue] +// try status <-- dictionary[Field.status.rawValue] +// try code <-- dictionary[Field.code.rawValue] +// try title <-- dictionary[Field.title.rawValue] +// try detail <-- dictionary[Field.detail.rawValue] +// try source <-- dictionary[Field.source.rawValue] +// try meta <-- dictionary[Field.meta.rawValue] +// } +//} +// +///// A JSON API error source object. http://jsonapi.org/format/#errors +//public struct JSONAPIErrorSource: Deserializable { +// private(set) public var pointer: String? +// private(set) public var parameter: String? +// +// public enum Field: String { +// case pointer, parameter +// } +// +// public init(dictionary: [String : AnyObject]) throws { +// try pointer <-- dictionary[Field.pointer.rawValue] +// try parameter <-- dictionary[Field.parameter.rawValue] +// } +// +// public init() {} +//} +// +///// A JSON API resource object. http://jsonapi.org/format/#document-resource-objects +//public struct JSONAPIResourceObject: Deserializable, Serializable { +// private(set) public var id: String? +// private(set) public var type: String? +// private(set) public var attributes = [String : AnyObject]() +// private(set) public var relationships = [String: JSONAPIRelationship]() +// private(set) public var links = JSONAPILinks() +// +// // FIXME: Rename to Fields if possible. +// public enum BaseFields: String { +// case id, type, attributes, relationships, links +// } +// +// public init(dictionary: [String : AnyObject]) throws { +// try id <-- (dictionary[BaseFields.id.rawValue] ?? id) +// try type <-- (dictionary[BaseFields.type.rawValue] ?? type) +// try attributes <-- dictionary[BaseFields.attributes.rawValue] +// try relationships <-- dictionary[BaseFields.relationships.rawValue] +// try links <-- dictionary[BaseFields.links.rawValue] +// } +// +// public init() {} +// +// public func toDictionary() -> [String : AnyObject] { +// var dictionary = [String : AnyObject]() +// +// dictionary[BaseFields.id.rawValue] = id +// dictionary[BaseFields.type.rawValue] = type +// dictionary[BaseFields.attributes.rawValue] = attributes +// +// // TODO: relationships +// +// // TODO: links +// +// return dictionary +// } +// +// public var description: String { +// return toDictionary().description +// } +//} +// +///// A JSON API relationship object. http://jsonapi.org/format/#document-resource-object-relationships +//public struct JSONAPIRelationship: Deserializable { +// private(set) public var links = JSONAPILinks() +// private(set) public var data: AnyObject? +// private(set) public var meta = [String : AnyObject]() +// +// public enum Field: String { +// case links, data, meta +// } +// +// public init(dictionary: [String : AnyObject]) throws { +// try links <-- dictionary[Field.links.rawValue] +// self.data = dictionary[Field.data.rawValue] +// try meta <-- dictionary[Field.meta.rawValue] +// } +//} diff --git a/JSONHelper/Supporting Files/Mac/Info.plist b/JSONHelper/Supporting Files/Mac/Info.plist index 01a700f..7e7479f 100644 --- a/JSONHelper/Supporting Files/Mac/Info.plist +++ b/JSONHelper/Supporting Files/Mac/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.7.0 + 2.0.0 CFBundleSignature ???? CFBundleVersion diff --git a/JSONHelper/Supporting Files/iOS/Info.plist b/JSONHelper/Supporting Files/iOS/Info.plist index 01a700f..7e7479f 100644 --- a/JSONHelper/Supporting Files/iOS/Info.plist +++ b/JSONHelper/Supporting Files/iOS/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.7.0 + 2.0.0 CFBundleSignature ???? CFBundleVersion diff --git a/JSONHelper/Supporting Files/tvOS/Info.plist b/JSONHelper/Supporting Files/tvOS/Info.plist index 01a700f..7e7479f 100644 --- a/JSONHelper/Supporting Files/tvOS/Info.plist +++ b/JSONHelper/Supporting Files/tvOS/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.7.0 + 2.0.0 CFBundleSignature ???? CFBundleVersion diff --git a/JSONHelperExample/Supporting Files/Info.plist b/JSONHelperExample/Supporting Files/Info.plist index 165b640..40c6215 100644 --- a/JSONHelperExample/Supporting Files/Info.plist +++ b/JSONHelperExample/Supporting Files/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.bsencan.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/JSONHelperExampleTests/Supporting Files/Info.plist b/JSONHelperExampleTests/Supporting Files/Info.plist index dca6fe6..ba72822 100644 --- a/JSONHelperExampleTests/Supporting Files/Info.plist +++ b/JSONHelperExampleTests/Supporting Files/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.bsencan.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/JSONHelperTests/ArrayTests.swift b/JSONHelperTests/ArrayTests.swift new file mode 100644 index 0000000..4334098 --- /dev/null +++ b/JSONHelperTests/ArrayTests.swift @@ -0,0 +1,64 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class ArrayTests: XCTestCase { + + // MARK: - Convertable Tests + + let urlStrings = ["http://apple.com", "http://google.com", "http://facebook.com"] + let urlHosts = ["apple.com", "google.com", "facebook.com"] + + func testArrayToConvertibleArray() { + var urls = [NSURL]() + try! urls <-- urlStrings + + XCTAssertEqual(urls[0].host, urlHosts[0]) + XCTAssertEqual(urls[1].host, urlHosts[1]) + XCTAssertEqual(urls[2].host, urlHosts[2]) + } + + func testArrayAsAnyToConvertibleArray() { + var urls = [NSURL]() + try! urls <-- (urlStrings as Any) + + XCTAssertEqual(urls[0].host, urlHosts[0]) + XCTAssertEqual(urls[1].host, urlHosts[1]) + XCTAssertEqual(urls[2].host, urlHosts[2]) + } + + // MARK: - Deserializable Tests + + struct Item: Deserializable { + static let nameKey = "name" + + var name: String? + + init(dictionary: [String: AnyObject]) throws { + try name <-- dictionary[Item.nameKey] + } + } + + let dictionaries = [ + [Item.nameKey : "a"], + [Item.nameKey : "b"] + ] + + func testArrayToDeserializableArray() { + var items = [Item]() + try! items <-- dictionaries + XCTAssertEqual(items[0].name, "a") + XCTAssertEqual(items[1].name, "b") + } + + func testArrayAsAnyToDeserializableArray() { + var items = [Item]() + try! items <-- (dictionaries as Any) + XCTAssertEqual(items[0].name, "a") + XCTAssertEqual(items[1].name, "b") + } +} diff --git a/JSONHelperTests/BoolTests.swift b/JSONHelperTests/BoolTests.swift new file mode 100644 index 0000000..3d8d6f7 --- /dev/null +++ b/JSONHelperTests/BoolTests.swift @@ -0,0 +1,38 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class BoolTests: XCTestCase { + let testBool = true + let testIntsAndResults = [(-1, false), (0, false), (1, true), (2, true)] + let testStringsAndResults = [("true", true), ("t", true), ("false", false), ("f", false), ("yes", true), ("y", true), ("no", false), ("n", false)] + + var value: Bool? + + override func setUp() { + value = nil + } + + func testBoolConversion() { + try! value <-- (testBool as Any) + XCTAssertEqual(value, testBool) + } + + func testIntConversion() { + for intAndResult in testIntsAndResults { + try! value <-- (intAndResult.0 as Any) + XCTAssertEqual(value, intAndResult.1) + } + } + + func testStringConversion() { + for stringAndResult in testStringsAndResults { + try! value <-- (stringAndResult.0 as Any) + XCTAssertEqual(value, stringAndResult.1) + } + } +} diff --git a/JSONHelperTests/ColorTests.swift b/JSONHelperTests/ColorTests.swift new file mode 100644 index 0000000..c8eafca --- /dev/null +++ b/JSONHelperTests/ColorTests.swift @@ -0,0 +1,40 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import XCTest +import JSONHelper + +#if os(OSX) +import AppKit +#else +import UIKit +#endif + +class ColorTests: XCTestCase { + let testStringAndResult = ("#ffffff", (r: CGFloat(1), g: CGFloat(1), b: CGFloat(1), a: CGFloat(1))) + + #if os(OSX) + var value: NSColor? + #else + var value: UIColor? + #endif + + override func setUp() { + value = nil + } + + func testStringConversion() { + try! value <-- (testStringAndResult.0 as Any) + + var r: CGFloat = 0 + var g: CGFloat = 0 + var b: CGFloat = 0 + var a: CGFloat = 0 + value?.getRed(&r, green: &g, blue: &b, alpha: &a) + + XCTAssert( + (r == testStringAndResult.1.r) && (g == testStringAndResult.1.g) && (b == testStringAndResult.1.b) && (a == testStringAndResult.1.a), + "String to (UI/NS)Color conversion failed") + } +} diff --git a/JSONHelperTests/DeserializableTests.swift b/JSONHelperTests/DeserializableTests.swift new file mode 100644 index 0000000..31c9c50 --- /dev/null +++ b/JSONHelperTests/DeserializableTests.swift @@ -0,0 +1,41 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class DeserializableTests: XCTestCase { + + struct Item: Deserializable { + static let nameKey = "name" + + var name = "" + + init(dictionary: [String : AnyObject]) throws { + try name <-- dictionary[Item.nameKey] + } + + init() {} + } + + let itemDictionary = [Item.nameKey : "a"] + let itemString = "{ \"name\": \"a\" }" + + var item = Item() + + override func setUp() { + item = Item() + } + + func testDictionaryDeserialization() { + try! item <-- itemDictionary + XCTAssertEqual(item.name, itemDictionary[Item.nameKey]) + } + + func testStringDeserialization() { + try! item <-- itemString + XCTAssertEqual(item.name, itemDictionary[Item.nameKey]) + } +} diff --git a/JSONHelperTests/DictionaryTests.swift b/JSONHelperTests/DictionaryTests.swift new file mode 100644 index 0000000..f49c6b8 --- /dev/null +++ b/JSONHelperTests/DictionaryTests.swift @@ -0,0 +1,61 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class DictionaryTests: XCTestCase { + + // MARK: - Convertible Tests + + let dateStringDictionary = ["one" : "2014-11-02", "two" : "2015-04-24"] + + override func setUp() { + JSONHelper.dateFormatter.dateFormat = "yyyy-MM-dd" + } + + func testDictionaryToConvertibleDictionary() { + var value = [String : NSDate]() + try! value <-- dateStringDictionary + XCTAssertEqual(JSONHelper.dateFormatter.stringFromDate(value["one"]!), dateStringDictionary["one"]) + } + + func testDictionaryAsAnyToConvertibleDictionary() { + var value = [String : NSDate]() + try! value <-- (dateStringDictionary as Any) + XCTAssertEqual(JSONHelper.dateFormatter.stringFromDate(value["one"]!), dateStringDictionary["one"]) + } + + // MARK: - Deserializable Tests + + let dictionary = [ + "one" : ["name" : "a"], + "two" : ["name" : "b"] + ] + + struct Item: Deserializable { + static let nameKey = "name" + + var name = "" + + init(dictionary: [String : AnyObject]) throws { + try name <-- dictionary["name"] + } + } + + func testDictionaryToMappableDictionary() { + var value = [String : Item]() + try! value <-- dictionary + XCTAssertEqual(value["one"]?.name, dictionary["one"]?["name"]) + XCTAssertEqual(value["two"]?.name, dictionary["two"]?["name"]) + } + + func testDictionaryAsAnyToMappableDictionary() { + var value = [String : Item]() + try! value <-- (dictionary as Any) + XCTAssertEqual(value["one"]?.name, dictionary["one"]?["name"]) + XCTAssertEqual(value["two"]?.name, dictionary["two"]?["name"]) + } +} diff --git a/JSONHelperTests/DoubleTests.swift b/JSONHelperTests/DoubleTests.swift new file mode 100644 index 0000000..385b230 --- /dev/null +++ b/JSONHelperTests/DoubleTests.swift @@ -0,0 +1,52 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class DoubleTests: XCTestCase { + let testInt = 1 + let testFloat = Float(1.2) + let testDouble = Double(1.2) + let testNSNumber = NSNumber(double: 1.2) + let testNSDecimalNumber = NSDecimalNumber(double: 1.2) + let testString = "1.2" + + var value = 0.0 + + override func setUp() { + value = 0.0 + } + + func testIntConversion() { + try! value <-- (testInt as Any) + XCTAssert(Int(value) == testInt) + } + + func testFloatConversion() { + try! value <-- (testFloat as Any) + XCTAssertEqual(value, testDouble) + } + + func testDoubleConversion() { + try! value <-- (testDouble as Any) + XCTAssertEqual(value, testDouble) + } + + func testNSNumberConversion() { + try! value <-- (testNSNumber as Any) + XCTAssertEqual(value, testDouble) + } + + func testNSDecimalNumberConversion() { + try! value <-- (testNSDecimalNumber as Any) + XCTAssertEqual(value, testDouble) + } + + func testStringConversion() { + try! value <-- (testString as Any) + XCTAssertEqual(value, testDouble) + } +} diff --git a/JSONHelperTests/EnumTests.swift b/JSONHelperTests/EnumTests.swift new file mode 100644 index 0000000..63f60ac --- /dev/null +++ b/JSONHelperTests/EnumTests.swift @@ -0,0 +1,25 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class EnumTests: XCTestCase { + + enum TestEnum: String { + case Hello, Darkness, My, Old, Friend + } + + var value = TestEnum.Hello + + override func setUp() { + value = .Hello + } + + func testStringConversion() { + try! value <-- (TestEnum.Friend.rawValue as Any) + XCTAssertEqual(value, TestEnum.Friend) + } +} diff --git a/JSONHelperTests/FloatTests.swift b/JSONHelperTests/FloatTests.swift new file mode 100644 index 0000000..03546d6 --- /dev/null +++ b/JSONHelperTests/FloatTests.swift @@ -0,0 +1,52 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class FloatTests: XCTestCase { + let testInt = 1 + let testFloat = Float(1.2) + let testDouble = Double(1.2) + let testNSNumber = NSNumber(double: 1.2) + let testNSDecimalNumber = NSDecimalNumber(double: 1.2) + let testString = "1.2" + + var value = Float(0) + + override func setUp() { + value = Float(0) + } + + func testIntConversion() { + try! value <-- (testInt as Any) + XCTAssert(Int(value) == testInt) + } + + func testFloatConversion() { + try! value <-- (testFloat as Any) + XCTAssertEqual(value, testFloat) + } + + func testDoubleConversion() { + try! value <-- (testDouble as Any) + XCTAssertEqual(value, testFloat) + } + + func testNSNumberConversion() { + try! value <-- (testNSNumber as Any) + XCTAssertEqual(value, testFloat) + } + + func testNSDecimalNumberConversion() { + try! value <-- (testNSDecimalNumber as Any) + XCTAssertEqual(value, testFloat) + } + + func testStringConversion() { + try! value <-- (testString as Any) + XCTAssertEqual(value, testFloat) + } +} diff --git a/JSONHelperTests/IntTests.swift b/JSONHelperTests/IntTests.swift new file mode 100644 index 0000000..c1f6028 --- /dev/null +++ b/JSONHelperTests/IntTests.swift @@ -0,0 +1,56 @@ +// +// IntTests.swift +// JSONHelper +// +// Created by Baris Sencan on 6/29/15. +// Copyright (c) 2015 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class IntTests: XCTestCase { + let testInt = 1 + let testFloat = Float(1) + let testDouble = Double(1) + let testNSNumber = NSNumber(integer: 1) + let testNSDecimalNumber = NSDecimalNumber(integer: 1) + let testString = "1" + + var value = 0 + + override func setUp() { + value = 0 + } + + func testIntConversion() { + try! value <-- (testInt as Any) + XCTAssertEqual(value, testInt) + } + + func testFloatConversion() { + try! value <-- (testFloat as Any) + XCTAssertEqual(value, testInt) + } + + func testDoubleConversion() { + try! value <-- (testDouble as Any) + XCTAssertEqual(value, testInt) + } + + func testNSNumberConversion() { + try! value <-- (testNSNumber as Any) + XCTAssertEqual(value, testInt) + } + + func testNSDecimalNumberConversion() { + try! value <-- (testNSDecimalNumber as Any) + XCTAssertEqual(value, testInt) + } + + func testStringConversion() { + try! value <-- (testString as Any) + XCTAssertEqual(value, testInt) + } +} diff --git a/JSONHelperTests/JSONHelperTests.swift b/JSONHelperTests/JSONHelperTests.swift index 47e01ac..fa5d4c9 100644 --- a/JSONHelperTests/JSONHelperTests.swift +++ b/JSONHelperTests/JSONHelperTests.swift @@ -1,9 +1,5 @@ // -// JSONHelperTests.swift -// JSONHelperTests -// -// Created by Baris Sencan on 28/08/14. -// Copyright (c) 2014 Baris Sencan. All rights reserved. +// Copyright © 2016 Baris Sencan. All rights reserved. // import UIKit @@ -11,220 +7,17 @@ import XCTest import JSONHelper class JSONHelperTests: XCTestCase { - let dummyResponse = [ - "string": "a", - "int": 1, - "int_string": "1", - "bool": true, - "date": "2014-09-19", - "url": "http://github.com/", - "stringArray": ["a", "b", "c"], - "intArray": [1, 2, 3, 4, 5], - "boolArray": [true, false], - "instance": [ - "name": "b" - ], - "instanceArray": [ - [ - "name": "c" - ], [ - "name": "d" - ] - ], - "instanceMap": [ - "ePerson": [ - "name": "e" - ], - "fPerson": [ - "name": "f" - ] - ] - ] - struct Person: Deserializable { - var name = "" + func testConvertToNilIfNull() { + let nilValues: [AnyObject?] = [NSNull(), nil] + let nonNilValues = [0, "", false, [], [:]] - init(data: [String: AnyObject]) { - name <-- data["name"] + for nilValue in nilValues { + XCTAssert(JSONHelper.convertToNilIfNull(nilValue) == nil) } - init() {} - } - - enum EnumTest: Int { - case Zero = 0 - case One = 1 - } - - func testOptionalString() { - var property: String? - property <-- dummyResponse["string"] - XCTAssertEqual(property!, "a", "String? property should equal 'a'") - property <-- dummyResponse["invalidKey"] - XCTAssertNil(property, "String? property should equal nil after invalid assignment") - } - - func testString() { - var property = "b" - property <-- dummyResponse["invalidKey"] - XCTAssertEqual(property, "b", "String property should have the default value 'b'") - property <-- dummyResponse["string"] - XCTAssertEqual(property, "a", "String property should equal 'a'") - } - - func testOptionalInt() { - var property: Int? - property <-- dummyResponse["int"] - XCTAssertEqual(property!, 1, "Int? property should equal 1") - property <-- dummyResponse["invalidKey"] - XCTAssertNil(property, "Int? property should equal nil after invalid assignment") - } - - func testInt() { - var property = 2 - property <-- dummyResponse["invalidKey"] - XCTAssertEqual(property, 2, "Int property should have the default value 2") - property <-- dummyResponse["int"] - XCTAssertEqual(property, 1, "Int property should equal 1") - } - - func testStringToOptionalInt() { - var number: Int? - number <-- dummyResponse["int_string"] - XCTAssertEqual(number!, 1, "Strings containing numbers should successfully deserialize into optional Ints.") - } - - func testStringToInt() { - var number = 0 - number <-- dummyResponse["int_string"] - XCTAssertEqual(number, 1, "Strings containing numbers should successfully deserialize into Ints.") - } - - func testOptionalBool() { - var property: Bool? - property <-- dummyResponse["bool"] - XCTAssertEqual(property!, true, "Bool? property should equal true") - property <-- dummyResponse["invalidKey"] - XCTAssertNil(property, "Bool? property should equal nil after invalid assignment") - } - - func testBool() { - var property = true - property <-- dummyResponse["invalidKey"] - XCTAssertEqual(property, true, "Bool property should have the default value true") - property <-- dummyResponse["bool"] - XCTAssertEqual(property, true, "Bool property should equal true") - } - - func testOptionalNSDate() { - var property: NSDate? - property <-- (dummyResponse["date"], "yyyy-MM-dd") - let dateFormatter = NSDateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd" - let testDate = dateFormatter.dateFromString("2014-09-19") - XCTAssertEqual(property!.compare(testDate!), NSComparisonResult.OrderedSame, "NSDate? property should equal 2014-09-19") - property <-- dummyResponse["invalidKey"] - XCTAssertNil(property, "NSDate? property should equal nil after invalid assignment") - } - - func testNSDate() { - let dateFormatter = NSDateFormatter() - dateFormatter.dateFormat = "yyyy-MM-dd" - let defaultTestDate = dateFormatter.dateFromString("2015-09-19") - var property = defaultTestDate! - property <-- (dummyResponse["invalidKey"], "yyyy-MM-dd") - XCTAssertEqual(property.compare(defaultTestDate!), NSComparisonResult.OrderedSame, "NSDate should have the default value 2015-09-19") - property <-- (dummyResponse["date"], "yyyy-MM-dd") - let testDate = dateFormatter.dateFromString("2014-09-19") - XCTAssertEqual(property.compare(testDate!), NSComparisonResult.OrderedSame, "NSDate should have the value 2015-09-19") - } - - func testOptionalNSURL() { - var property: NSURL? - property <-- dummyResponse["url"] - XCTAssertEqual(property!.host!, "github.com", "NSURL? property should equal github.com") - property <-- dummyResponse["invalidKey"] - XCTAssertNil(property, "NSURL? property should equal nil after invalid assignment") - } - - func testNSURL() { - var property = NSURL(string: "http://google.com")! - property <-- dummyResponse["invalidKey"] - XCTAssertEqual(property.host!, "google.com", "NSURL should have the default value google.com") - property <-- dummyResponse["url"] - XCTAssertEqual(property.host!, "github.com", "NSURL should have the value github.com") - } - - func testStringArray() { - var property = [String]() - property <-- dummyResponse["stringArray"] - XCTAssertEqual(property.count, 3, "[String] property should have 3 members") - } - - func testIntArray() { - var property = [Int]() - property <-- dummyResponse["intArray"] - XCTAssertEqual(property.count, 5, "[Int] property should have 5 members") - } - - func testBoolArray() { - var property = [Bool]() - property <-- dummyResponse["boolArray"] - XCTAssertEqual(property.count, 2, "[Bool] property should have 2 members") - } - - func testInstance() { - var instance = Person() - instance <-- dummyResponse["instance"] - XCTAssertEqual(instance.name, "b", "Person instance's name property should equal 'b'") - } - - func testInstanceArray() { - var property = [Person]() - property <-- dummyResponse["instanceArray"] - XCTAssertEqual(property.count, 2, "[Person] property should have 2 members") - } - - func testInstanceMap() { - var property = [String:Person]() - property <-- dummyResponse["instanceMap"] - XCTAssertEqual(property["ePerson"]!.name, "e", "member \"ePerson\" of [String:Person] property should have \"e\" for name") - } - - func testRawValueEnum() { - var property = EnumTest.Zero - property <-- dummyResponse["int"] - XCTAssertEqual(property, EnumTest.One, "EnumTest should be equal to .One") - } - - func testJSONStringArrayParsing() { - var jsonString = "[{\"name\": \"I am \"},{\"name\": \"Groot!\"}]" - var people = [Person]() - var areYouGroot = "" - - people <-- jsonString - - for person in people { - areYouGroot += person.name - } - - XCTAssertEqual(areYouGroot, "I am Groot!", "Groot should be Groot") - } - - func testJSONStringMapParsing() { - var jsonString = "{\"person one\": {\"name\": \"I am \"}, \"person two\": {\"name\": \"Groot!\"}}" - var people = [String:Person]() - var areYouGroot = "" - var keys = "" - - people <-- jsonString - - for (personKey, person) in people { - areYouGroot += person.name - keys += personKey + for nonNilValue in nonNilValues { + XCTAssert(JSONHelper.convertToNilIfNull(nonNilValue) != nil) } - - XCTAssertEqual(keys, "person oneperson two", "keys should be correctly picked up") - XCTAssertEqual(areYouGroot, "I am Groot!", "Groot should be Groot") } } diff --git a/JSONHelperTests/NSDateTests.swift b/JSONHelperTests/NSDateTests.swift new file mode 100644 index 0000000..f19851c --- /dev/null +++ b/JSONHelperTests/NSDateTests.swift @@ -0,0 +1,30 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class NSDateTests: XCTestCase { + let dateString = "2016-04-14" + let dateStringFormat = "yyyy-MM-dd" + let epochTimestamp = 1460592000 + + override func setUp() { + JSONHelper.dateFormatter.dateFormat = dateStringFormat + JSONHelper.dateFormatter.timeZone = NSTimeZone(forSecondsFromGMT: 0) + } + + func testEpochTimestampConversion() { + var date = NSDate() + try! date <-- (epochTimestamp as Any) + XCTAssertEqual(JSONHelper.dateFormatter.stringFromDate(date), dateString) + } + + func testStringConversion() { + var date = NSDate() + try! date <-- (dateString as Any) + XCTAssertEqual(JSONHelper.dateFormatter.stringFromDate(date), dateString) + } +} diff --git a/JSONHelperTests/NSDecimalNumberTests.swift b/JSONHelperTests/NSDecimalNumberTests.swift new file mode 100644 index 0000000..046b247 --- /dev/null +++ b/JSONHelperTests/NSDecimalNumberTests.swift @@ -0,0 +1,52 @@ +// +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class NSDecimalNumberTests: XCTestCase { + let testInt = 1 + let testFloat = Float(1.2) + let testDouble = Double(1.2) + let testNSNumber = NSNumber(double: 1.2) + let testNSDecimalNumber = NSDecimalNumber(double: 1.2) + let testString = "1.2" + + var value = NSDecimalNumber(integer: 0) + + override func setUp() { + value = NSDecimalNumber(integer: 0) + } + + func testIntConversion() { + try! value <-- (testInt as Any) + XCTAssert(Int(value) == testInt) + } + + func testFloatConversion() { + try! value <-- (testFloat as Any) + XCTAssertEqual(value, testNSDecimalNumber) + } + + func testDoubleConversion() { + try! value <-- (testDouble as Any) + XCTAssertEqual(value, testNSDecimalNumber) + } + + func testNSNumberConversion() { + try! value <-- (testNSNumber as Any) + XCTAssertEqual(value, testNSDecimalNumber) + } + + func testNSDecimalNumberConversion() { + try! value <-- (testNSDecimalNumber as Any) + XCTAssertEqual(value, testNSDecimalNumber) + } + + func testStringConversion() { + try! value <-- (testString as Any) + XCTAssertEqual(value, testNSDecimalNumber) + } +} diff --git a/JSONHelperTests/NSURLTests.swift b/JSONHelperTests/NSURLTests.swift new file mode 100644 index 0000000..0cfac35 --- /dev/null +++ b/JSONHelperTests/NSURLTests.swift @@ -0,0 +1,22 @@ +// +// NSURLTests.swift +// JSONHelper +// +// Created by Baris Sencan on 22/01/2016. +// Copyright © 2016 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class NSURLTests: XCTestCase { + let urlString = "https://facebook.com" + let urlHost = "facebook.com" + + func testStringConversion() { + var url = NSURL() + try! url <-- (urlString as Any) + XCTAssertEqual(url.host, urlHost) + } +} diff --git a/JSONHelperTests/StringTests.swift b/JSONHelperTests/StringTests.swift new file mode 100644 index 0000000..b0b29a7 --- /dev/null +++ b/JSONHelperTests/StringTests.swift @@ -0,0 +1,42 @@ +// +// StringTests.swift +// JSONHelper +// +// Created by Baris Sencan on 6/22/15. +// Copyright (c) 2015 Baris Sencan. All rights reserved. +// + +import Foundation +import XCTest +import JSONHelper + +class StringTests: XCTestCase { + let testString = "test" + let testIntAndResult = (1, "1") + let testDateAndResult = (NSDate(timeIntervalSince1970: 0), "1970-01-01") + let testDateFormat = "yyyy-MM-dd" + + var value = "" + + override func setUp() { + value = "" + } + + func testStringConversion() { + try! value <-- (testString as Any) + XCTAssertEqual(value, testString) + } + + func testIntConversion() { + try! value <-- (testIntAndResult.0 as Any) + XCTAssertEqual(value, testIntAndResult.1) + } + + func testDateConversion() { + JSONHelper.dateFormatter.dateFormat = testDateFormat + JSONHelper.dateFormatter.timeZone = NSTimeZone(forSecondsFromGMT: 0) + + try! value <-- (testDateAndResult.0 as Any) + XCTAssertEqual(value, testDateAndResult.1) + } +} diff --git a/JSONHelperTests/Supporting Files/Info.plist b/JSONHelperTests/Supporting Files/Info.plist index dca6fe6..ba72822 100644 --- a/JSONHelperTests/Supporting Files/Info.plist +++ b/JSONHelperTests/Supporting Files/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.bsencan.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/README.md b/README.md index 90ec380..0399381 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,37 @@ - -#JSONHelper [![CocoaPods](https://img.shields.io/cocoapods/l/JSONHelper.svg)](https://github.com/isair/JSONHelper/blob/master/LICENSE) ![CocoaPods](https://img.shields.io/cocoapods/p/JSONHelper.svg) - +# JSONHelper +[![CocoaPods](https://img.shields.io/cocoapods/l/JSONHelper.svg)](https://github.com/isair/JSONHelper/blob/master/LICENSE) +![CocoaPods](https://img.shields.io/cocoapods/p/JSONHelper.svg) [![Build Status](https://travis-ci.org/isair/JSONHelper.svg?branch=master)](https://travis-ci.org/isair/JSONHelper) [![CocoaPods](https://img.shields.io/cocoapods/v/JSONHelper.svg)](https://cocoapods.org/pods/JSONHelper) -[![Stories in Ready](https://badge.waffle.io/isair/JSONHelper.png?label=ready&title=Ready)](https://waffle.io/isair/JSONHelper) + [![Gratipay](https://img.shields.io/gratipay/bsencan91.svg)](https://gratipay.com/bsencan91/) [![Gitter](https://badges.gitter.im/JOIN CHAT.svg)](https://gitter.im/isair/JSONHelper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -Lightning fast JSON deserialization for iOS, OS X, and tvOS written in Swift. A much improved version, and a rewrite, is under development in branch [dev-2.0.0](https://github.com/isair/JSONHelper/tree/dev-2.0.0) and any contributions to it are welcome as my personal time is currently very limited. +Convert anything into anything in one line; hex strings into UIColor/NSColor, JSON strings into class instances, numbers to strings, etc, anything you can make sense of! -##Table of Contents +__Latest version requires iOS 8+ and Xcode 7.3+__ -1. [Introduction](#introduction) -2. [Installation](#installation) -3. [Operator List](#operator-list) -4. [Simple Tutorial](#simple-tutorial) -5. [Assigning Default Values](#assigning-default-values) -6. [NSDate and NSURL Deserialization](#nsdate-and-nsurl-deserialization) -7. [JSON String Deserialization](#json-string-deserialization) +## Table of Contents -##Introduction +1. [Installation](#installation) +2. [The <-- Operator](#the----operator) + - [Overview](#overview) + - [Convertible Protocol](#convertible-protocol) + - [Deserializable Protocol](#deserializable-protocol) + - [Serializable Protocol](#serializable-protocol) +3. [JSON Deserialization Example](#simple-tutorial) -JSONHelper is a library written to make sure that deserializing data obtained from an API is as easy as possible. It doesn't depend on any networking libraries, and works equally well with any of them. +## Installation -__Requires iOS 7 or later and Xcode 6.1+__ +### [CocoaPods](https://github.com/CocoaPods/CocoaPods) -##Installation +Add the following line in your `Podfile`. -###[Carthage](https://github.com/Carthage/Carthage#installing-carthage) +``` +pod "JSONHelper" +``` + +### [Carthage](https://github.com/Carthage/Carthage#installing-carthage) Add the following line to your [Cartfile](https://github.com/Carthage/Carthage/blob/master/Documentation/Artifacts.md#cartfile). @@ -37,151 +41,91 @@ github "isair/JSONHelper" Then do `carthage update`. After that, add the framework to your project. -###[CocoaPods](https://github.com/CocoaPods/CocoaPods) +## The <-- Operator -Add the following line in your `Podfile`. +### Overview -``` -pod "JSONHelper" -``` - -###Drag & Drop - -You can also add [JSONHelper.swift](https://raw.githubusercontent.com/isair/JSONHelper/master/JSONHelper/JSONHelper.swift) directly into your project. - -##Basic Tutorial - -First of all I'm going to assume you use [AFNetworking](https://github.com/AFNetworking/AFNetworking) as your networking library; for simplicity. Let's say we have an endpoint at __http://yoursite.com/movies/__ which gives the following response when a simple __GET__ request is sent to it. - -```json -{ - "movies": [ - { - "name": "Filth", - "release_date": "2014-05-30", - "cast": { - "Bruce": "James McAvoy", - "Lennox": "Jamie Bell" - } - }, - { - "name": "American Psycho", - "release_date": "2000-04-14", - "cast": { - "Patrick Bateman": "Christian Bale", - "Timothy Bryce": "Justin Theroux" - } - } - ] -} -``` +The `<--` operator takes the value on its right hand side and tries to convert it into the type of the value on its left hand side. If the conversion fails, an error is thrown. If it's successful, the value of the left hand side variable is overwritten. It's chainable as well. -From this response it is clear that we have a movie model similar to the implementation below. - -```swift -struct Movie { - var name: String? - var releaseDate: NSDate? - var cast: [String: String]? -} -``` +If the right hand side value is nil, and the left hand side variable is an optional, then nil is assigned to it. When the left hand side is non-optional, in the case where the right hand side value is nil, the current value of the left hand side variable is left untouched. -We now have to make it extend the protocol __Deserializable__ and implement the __required init(data: [String: AnyObject])__ initializer and use our deserialization operator (`<--`) in it. The complete model should look like this: +Using this specification let's assume you have a dictionary response that you retrieved from some API with hex color strings in it, under the key `colors`, that you want to convert into an array of UIColor instances. Also, to fully use everything we know, let's also assume that we want to have a default value for our color array in case the value for the key we're looking for does not exist (is nil). ```swift -struct Movie: Deserializable { - var name: String? - var releaseDate: NSDate? - var cast: [String: String]? - - init(data: [String: AnyObject]) { - name <-- data["name"] - releaseDate <-- (data["release_date"], "yyyy-MM-dd") // Refer to the next section for more info. - cast <-- data["cast"] - } -} +var colors = [UIColor.blackColor()] +// Assume we have response { "colors": ["#fff"] } +try colors <-- response[colorsKey] ``` -And finally, requesting and deserializing the response from our endpoint becomes as easy as the following piece of code. +It's really that simple. If you want to ignore any conversion errors instead of having to catch them, you can replace the last line with the following. ```swift -AFHTTPRequestOperationManager().GET( - "http://yoursite.com/movies/" - parameters: nil, - success: { operation, data in - var movies: [Movie]? - movies <-- data["movies"] - - if let movies = movies { - // Response contained a movies array, and we deserialized it. Do what you want here. - } else { - // Server gave us a response but there was no "movies" key in it, so the movies variable - // is equal to nil. Do some error handling here. - } - }, - failure: { operation, error in - // Handle error. -}) +_ = try? colors <-- response[colorsKey] ``` -##Assigning Default Values +### Convertible Protocol -You can easily assign default values to variables in cases where you want them to have a certain value when deserialization fails. +If your type is a simple value-like type, adopting the Convertible protocol is the way to make your type work with the `<--` operator. -````swift -struct User: Deserializable { - var name = "Guest" - - init(data: [String: AnyObject]) { - name <-- data["name"] - } -} -```` - -##NSDate and NSURL Deserialization - -NSURL deserialization works very much like a primitive type deserialization. - -````swift -let website: NSURL? -let imageURLs: [NSURL]? +Example: +```swift +struct Vector2D: Convertible { + var x: Double = 0 + var y: Double = 0 -website <-- "http://mywebsite.com" -imageURLs <-- ["http://mywebsite.com/image.png", "http://mywebsite.com/anotherImage.png"] -```` + init(x: Double, y: Double) { + self.x = x + self.y = y + } -NSDate deserialization however, requires a format to be provided most of the time. + static func convertFromValue(value: T?) throws -> Self? { + guard let value = value else { return nil } -````swift -let meetingDate: NSDate? -let partyDates: [NSDate]? + if let doubleTupleValue = value as? (Double, Double) { + return self.init(x: doubleTupleValue.0, y: doubleTupleValue.1) + } -meetingDate <-- ("2014-09-18", "yyyy-MM-dd") -partyDates <-- (["2014-09-19", "2014-09-20"], "yyyy-MM-dd") + throw ConversionError.UnsupportedType + } +} +``` -let myDayOff: NSDate? -myDayOff <-- 1414172803 // You can also use unix timestamps. -```` +```swift +var myVector: Vector2D? +try myVector <-- (1.0, 2.7) +``` -##JSON String Deserialization +### Deserializable Protocol -You can deserialize instances and arrays of instances directly from a JSON string as well. Here is a quick example. +While you can basically adopt the `Convertible` protocol for any type, if your type is always converted from a dictionary things can get a lot easier with the `Deserializable` protocol. -````swift -struct Person: Deserializable { - var name = "" +Example: +```swift +class User: Deserializable { + let idKey = "id" + let emailKey = "email" + let nameKey = "name" + let avatarURLKey = "avatar_url" + + var id: String? + var email: String? + var name = "Guest" + var avatarURL = NSURL(string: "https://mysite.com/assets/default-avatar.png") - init(data: [String: AnyObject]) { - name <-- data["name"] + required init(dictionary: [String : AnyObject]) throws { + id <-- dictionary[idKey] + email <-- dictionary[emailKey] + name <-- dictionary[nameKey] + avatarURL <-- dictionary[avatarURLKey] } } +``` -let jsonString = "[{\"name\": \"Rocket Raccoon\"}, {\"name\": \"Groot\"}]" -var people = [Person]() +```swift +var myUser: User? +try user <-- apiResponse["user"] +``` -people <-- jsonString +### Serializable Protocol -for person in people { - println(person.name) -} -```` +// Serialization is coming soon. I'll probably not add a new protocol and just rename and update the Deserializable protocol.