├── US2MapperKit ├── Shared Test Cases │ ├── Classes │ │ ├── TestObjectFive.swift │ │ ├── TestObjectFour.swift │ │ ├── TestObjectNine.swift │ │ ├── TestObjectSix.swift │ │ ├── TestObjectTen.swift │ │ ├── TestObjectTwo.swift │ │ ├── TestObjectEight.swift │ │ ├── TestObjectEleven.swift │ │ ├── TestObjectSeven.swift │ │ ├── TestObjectThree.swift │ │ ├── TestObjectTwelve.swift │ │ ├── TestObjectThirteen.swift │ │ ├── Internal │ │ │ ├── _TestObjectOne.swift │ │ │ ├── _TestObjectTwo.swift │ │ │ ├── _TestObjectFive.swift │ │ │ ├── _TestObjectSeven.swift │ │ │ ├── _TestObjectSix.swift │ │ │ ├── _TestObjectEight.swift │ │ │ ├── _TestObjectThirteen.swift │ │ │ ├── US2Instantiator.swift │ │ │ ├── _TestObjectFour.swift │ │ │ ├── _TestObjectEleven.swift │ │ │ ├── _TestObjectThree.swift │ │ │ ├── _TestObjectTwelve.swift │ │ │ ├── _TestObjectNine.swift │ │ │ └── _TestObjectTen.swift │ │ └── TestObjectOne.swift │ ├── Mapping │ │ ├── TestObjectTwo.plist │ │ ├── TestObjectFive.plist │ │ ├── TestObjectSeven.plist │ │ ├── TestObjectEight.plist │ │ ├── TestObjectSix.plist │ │ ├── TestObjectThirteen.plist │ │ ├── TestObjectFour.plist │ │ ├── TestObjectNine.plist │ │ ├── TestObjectTwelve.plist │ │ ├── TestObjectTen.plist │ │ ├── TestObjectEleven.plist │ │ └── TestObjectThree.plist │ └── Test Case Objects │ │ ├── ValueTypeDefinitions.swift │ │ ├── US2ExampleEnumTransformer.swift │ │ ├── US2ExampleTupleTransformer.swift │ │ ├── US2ExampleStructTransformer.swift │ │ └── US2ExampleClosureTransformer.swift └── US2MapperKit │ ├── US2MapperKitOSX │ ├── US2MapperKitOSX.h │ └── Info.plist │ ├── US2MapperKitiOS │ ├── US2MapperKitiOS.h │ └── Info.plist │ ├── US2MapperKitOSXTests │ └── Info.plist │ ├── US2MapperKitiOSTests │ └── Info.plist │ └── US2MapperKit.xcodeproj │ └── xcshareddata │ └── xcschemes │ ├── US2MapperKit - OSX.xcscheme │ └── US2MapperKit - iOS.xcscheme ├── documentation ├── readme_assets │ ├── debug_flag.png │ ├── closure_example.png │ ├── location_plist.png │ ├── mapperkit_header.png │ ├── basic_concept_image.png │ ├── enum_example_plist.png │ ├── struct_example_plist.png │ ├── transformer_example.png │ ├── default_value_example.png │ ├── nested_mapping_example.png │ ├── non_optional_business.png │ ├── ratings_array_example.png │ ├── tuple_mapping_example.png │ ├── basic data_types_business.png │ ├── business_location_example.png │ └── transformer_fullname_example.png ├── default_values.md ├── compatibility_issues.md ├── troubleshooting.md ├── enable_debug_mode.md ├── nested_mapping.md ├── changelog.md ├── complex_value_types.md ├── non_optional_value_types.md ├── collection_types.md ├── custom_transforms_tuples.md ├── custom_transforms_struct.md ├── custom_transforms_enums.md ├── custom_transforms.md ├── custom_transforms_closures.md ├── optional_value_types.md └── installation.md ├── .gitignore ├── Source ├── US2MapperKit │ ├── Parsers │ │ ├── ComplexTypeParser.swift │ │ ├── NativeValueArrayParser.swift │ │ ├── NativeValueDictionaryParser.swift │ │ ├── ComplexValueArrayParser.swift │ │ ├── NativeTypeParser.swift │ │ ├── ComplexValueDictionaryParser.swift │ │ ├── CollectionParser.swift │ │ └── Parser.swift │ ├── US2CompoundValueTransformer.swift │ ├── Transformer │ │ └── Transformer.swift │ ├── Validator │ │ └── Validator.swift │ └── US2Mapper.swift └── ModelScript │ └── modelgen-swift.py ├── US2MapperKit.podspec ├── LICENSE.txt └── README.md /US2MapperKit/Shared Test Cases/Classes/TestObjectFive.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectFive : _TestObjectFive { 4 | 5 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectFour.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectFour : _TestObjectFour { 4 | 5 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectNine.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectNine : _TestObjectNine { 4 | 5 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectSix.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectSix : _TestObjectSix { 4 | 5 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectTen.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectTen : _TestObjectTen { 4 | 5 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectTwo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectTwo : _TestObjectTwo { 4 | 5 | } -------------------------------------------------------------------------------- /documentation/readme_assets/debug_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/debug_flag.png -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectEight.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectEight : _TestObjectEight { 4 | 5 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectEleven.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectEleven : _TestObjectEleven { 4 | 5 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectSeven.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectSeven : _TestObjectSeven { 4 | 5 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectThree.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectThree : _TestObjectThree { 4 | 5 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectTwelve.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectTwelve : _TestObjectTwelve { 4 | 5 | } -------------------------------------------------------------------------------- /documentation/readme_assets/closure_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/closure_example.png -------------------------------------------------------------------------------- /documentation/readme_assets/location_plist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/location_plist.png -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectThirteen.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | class TestObjectThirteen : _TestObjectThirteen { 4 | 5 | } -------------------------------------------------------------------------------- /documentation/readme_assets/mapperkit_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/mapperkit_header.png -------------------------------------------------------------------------------- /documentation/readme_assets/basic_concept_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/basic_concept_image.png -------------------------------------------------------------------------------- /documentation/readme_assets/enum_example_plist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/enum_example_plist.png -------------------------------------------------------------------------------- /documentation/readme_assets/struct_example_plist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/struct_example_plist.png -------------------------------------------------------------------------------- /documentation/readme_assets/transformer_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/transformer_example.png -------------------------------------------------------------------------------- /documentation/readme_assets/default_value_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/default_value_example.png -------------------------------------------------------------------------------- /documentation/readme_assets/nested_mapping_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/nested_mapping_example.png -------------------------------------------------------------------------------- /documentation/readme_assets/non_optional_business.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/non_optional_business.png -------------------------------------------------------------------------------- /documentation/readme_assets/ratings_array_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/ratings_array_example.png -------------------------------------------------------------------------------- /documentation/readme_assets/tuple_mapping_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/tuple_mapping_example.png -------------------------------------------------------------------------------- /documentation/readme_assets/basic data_types_business.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/basic data_types_business.png -------------------------------------------------------------------------------- /documentation/readme_assets/business_location_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/business_location_example.png -------------------------------------------------------------------------------- /documentation/readme_assets/transformer_fullname_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ustwo/US2MapperKit/HEAD/documentation/readme_assets/transformer_fullname_example.png -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectTwo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectOne.swift: -------------------------------------------------------------------------------- 1 | // 2 | // _TestObjectOne.swift 3 | // US2Mapper 4 | // 5 | // Created by Anton Doudarev on 6/25/15. 6 | // Copyright © 2015 US2Mapper. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class TestObjectOne : _TestObjectOne { 12 | 13 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | xcuserdata/ 20 | UserInterfaceState.xcuserstate 21 | # Pods - for those of you who use CocoaPods 22 | Pods -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Test Case Objects/ValueTypeDefinitions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Structs.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton on 9/2/15. 6 | // Copyright (c) 2015 ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct StructExample { 12 | var string1: String 13 | var string2: String 14 | } 15 | 16 | enum EnumExample : Int { 17 | case One = 1, Two, Three, Four, Five 18 | } -------------------------------------------------------------------------------- /documentation/default_values.md: -------------------------------------------------------------------------------- 1 | ##Example - Defining Default Values 2 | When there is need to fallback to a default value for optional or non-optional properties, define a default value by appending **default** to the property definition in the model mapping. In the example below, if the response dictionary does not have a value for the **open** property while mapping, it will default to false. 3 | 4 | **Business.plist** 5 |
6 | 7 | ![alt tag](/documentation/readme_assets/default_value_example.png?raw=true) 8 |
9 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Test Case Objects/US2ExampleEnumTransformer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // US2ExampleEnumTransformer.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton on 9/3/15. 6 | // Copyright (c) 2015 ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class US2ExampleEnumTransformer : US2TransformerProtocol { 12 | public func transformValues(inputValues : Dictionary?) -> Any? { 13 | 14 | if let enumValue = inputValues!["enumValue"] as? Int { 15 | return EnumExample(rawValue : enumValue)! 16 | } 17 | 18 | return nil 19 | } 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /US2MapperKit/US2MapperKit/US2MapperKitOSX/US2MapperKitOSX.h: -------------------------------------------------------------------------------- 1 | // 2 | // US2MapperKitOSX.h 3 | // US2MapperKitOSX 4 | // 5 | // Created by Anton Doudarev on 7/10/15. 6 | // Copyright (c) 2015 ustwo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for US2MapperKitOSX. 12 | FOUNDATION_EXPORT double US2MapperKitOSXVersionNumber; 13 | 14 | //! Project version string for US2MapperKitOSX. 15 | FOUNDATION_EXPORT const unsigned char US2MapperKitOSXVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /US2MapperKit/US2MapperKit/US2MapperKitiOS/US2MapperKitiOS.h: -------------------------------------------------------------------------------- 1 | // 2 | // US2MapperKitiOS.h 3 | // US2MapperKitiOS 4 | // 5 | // Created by Anton Doudarev on 7/10/15. 6 | // Copyright (c) 2015 ustwo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for US2MapperKitiOS. 12 | FOUNDATION_EXPORT double US2MapperKitiOSVersionNumber; 13 | 14 | //! Project version string for US2MapperKitiOS. 15 | FOUNDATION_EXPORT const unsigned char US2MapperKitiOSVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectFive.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | optionalSubType 6 | 7 | key 8 | optional_subtype 9 | type 10 | TestObjectThree 11 | 12 | non_optionalSubType 13 | 14 | nonoptional 15 | true 16 | key 17 | non_optional_subtype 18 | type 19 | TestObjectThree 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /documentation/compatibility_issues.md: -------------------------------------------------------------------------------- 1 | ##US2MapperKit - Compatibility Issues 2 | 3 | ####Carthage Issues: Module Created by Older Version of The Compiler 4 | 5 | This framework was designed to run with Swift 1.2 and 2.0. When installing using Carthage, the environment needs to be pointed to the correct instance of Xcode for the module to build correctly. 6 | 7 | If using the **Current SDK 6.0+** (Swift 1.2), run the following command in the terminal: 8 | 9 | ``` 10 | sudo xcode-select -s /Applications/Xcode.app/Contents/Developer 11 | ``` 12 | 13 | If using the **Beta SDK 7.0+** (Swift 2.0), run the following command in the terminal: 14 | 15 | ``` 16 | sudo xcode-select -s /Applications/Xcode-beta.app/Contents/Developer 17 | ``` 18 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Test Case Objects/US2ExampleTupleTransformer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // US2ExampleTupleTransformer.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton on 9/3/15. 6 | // Copyright (c) 2015 ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class US2ExampleTupleTransformer : US2TransformerProtocol { 12 | public func transformValues(inputValues : Dictionary?) -> Any? { 13 | 14 | if let valueOne = inputValues!["value_one"] as? Double { 15 | if let valueTwo = inputValues!["value_two"] as? Double { 16 | return (val1 : valueOne, val2 : valueTwo) 17 | } 18 | } 19 | 20 | return nil 21 | } 22 | } -------------------------------------------------------------------------------- /Source/US2MapperKit/Parsers/ComplexTypeParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ComplexTypeParser.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton Doudarev on 7/17/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class ComplexTypeParser { 12 | 13 | // MARK Maps a dictionary to a complex type 14 | 15 | class func complexObject(fromValue data : Dictionary, ofType objectType : String?, using instantiator : US2InstantiatorProtocol) -> AnyObject? { 16 | if let complexTypeValue: AnyObject = instantiator.newInstance(ofType: objectType!, withValue: data) { 17 | return complexTypeValue 18 | } 19 | 20 | return nil 21 | } 22 | } -------------------------------------------------------------------------------- /documentation/troubleshooting.md: -------------------------------------------------------------------------------- 1 | ##US2MapperKit - Known Compatibility Issues 2 | 3 | ####Carthage Issues: Module Created by Older Version of The Compiler 4 | 5 | This framework was designed to run with Swift 1.2 and 2.0 accordingly. When installing using Carthage, the environment needs to be pointing to the correct instance of Xcode for the module to build correctly. 6 | 7 | If using the **Current SDK 6.0+** (Swift 1.2) run the following command in the terminal: 8 | 9 | ``` 10 | sudo xcode-select -s /Applications/Xcode.app/Contents/Developer 11 | ``` 12 | 13 | If using the **Beta SDK 7.0+** (Swift 2.0) run the following command in the terminal: 14 | 15 | ``` 16 | sudo xcode-select -s /Applications/Xcode-beta.app/Contents/Developer 17 | ``` 18 | -------------------------------------------------------------------------------- /US2MapperKit.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "US2MapperKit" 3 | s.version = "0.2.0" 4 | s.summary = "JSON/Dictionary response driven object mapper with support for Swift 1.2 / 2.0" 5 | s.homepage = "https://github.com/ustwo/US2MapperKit" 6 | s.license = 'MIT' 7 | s.author = { "Anton Doudarev" => "anton@ustwo.com" } 8 | s.source = { :git => 'https://github.com/ustwo/US2MapperKit.git', :tag => s.version } 9 | s.ios.deployment_target = '8.0' 10 | s.osx.deployment_target = '10.9' 11 | s.source_files = "Source/US2MapperKit/*.*", "Source/US2MapperKit/Parsers/*.*", "Source/US2MapperKit/Transformer/*.*", "Source/US2MapperKit/Validator/*.*", "Source/ModelScript/*.*" 12 | s.requires_arc = true 13 | end 14 | -------------------------------------------------------------------------------- /Source/US2MapperKit/US2CompoundValueTransformer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // US2CompoundValueTransformer.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton Doudarev on 6/29/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | public class US2CompoundValueTransformer : US2TransformerProtocol { 10 | 11 | public func transformValues(inputValues : Dictionary?) -> Any? { 12 | var outputString : String = "" 13 | 14 | if let stringDictionary = inputValues as? Dictionary { 15 | for (key, value) in stringDictionary { 16 | outputString += value 17 | } 18 | } 19 | 20 | if outputString.isEmpty { return nil } 21 | return outputString 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectSeven.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | optionalArrayType 6 | 7 | key 8 | optional_sub_object_array 9 | type 10 | Array 11 | collection_subtype 12 | TestObjectFour 13 | 14 | non_optionalArrayType 15 | 16 | nonoptional 17 | true 18 | key 19 | non_optional_sub_object_array 20 | type 21 | Array 22 | collection_subtype 23 | TestObjectFour 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Test Case Objects/US2ExampleStructTransformer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // US2ExampleStructTransformer.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton on 9/2/15. 6 | // Copyright (c) 2015 ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class US2ExampleStructTransformer : US2TransformerProtocol { 12 | public func transformValues(inputValues : Dictionary?) -> Any? { 13 | 14 | if let stringDictionary = inputValues as? Dictionary { 15 | if let string1 = stringDictionary["string1"] { 16 | if let string2 = stringDictionary["string2"] { 17 | return StructExample(string1 : string1, string2 : string2) 18 | } 19 | } 20 | } 21 | 22 | return nil 23 | } 24 | } -------------------------------------------------------------------------------- /documentation/enable_debug_mode.md: -------------------------------------------------------------------------------- 1 | ##Example - Enable Debug Mode 2 | 3 | It is not always feasible to know why a a fail-able initializer may have failed to parse a response. USMapperKit provides the ability to use a build-time flag to print out failures to the console. 4 | 5 | To enable Debug mode, add the **-DUS2MAPPER_DEBUG** flag to the **Other Swift Flags** in your build settings. 6 | 7 |
8 | ![alt tag](/documentation/readme_assets/debug_flag.png?raw=true) 9 |
10 | 11 | The resulting output in the console will resemble the following: 12 | 13 | ``` 14 | Business instance could not be parsed, missing values for the following non-optional properties: 15 | - business_uuid 16 | 17 | Response: 18 | [response: { 19 | "business_name" : "UsTwoRestaurant"; 20 | "business_ratings" : [ 5, 4, 5, 4 ]; 21 | "business_open" : 1; 22 | }] 23 | 24 | ``` 25 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectEight.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | optionalDictionaryType 6 | 7 | key 8 | optional_sub_object_dictionary 9 | type 10 | Dictionary 11 | collection_subtype 12 | TestObjectFour 13 | 14 | non_optionalDictionaryType 15 | 16 | nonoptional 17 | true 18 | key 19 | non_optional_sub_object_dictionary 20 | type 21 | Dictionary 22 | collection_subtype 23 | TestObjectFour 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /US2MapperKit/US2MapperKit/US2MapperKitOSXTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.ustwo.US2MapperKitOSXTests 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /US2MapperKit/US2MapperKit/US2MapperKitiOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.ustwo.US2MapperKitiOSTests 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /US2MapperKit/US2MapperKit/US2MapperKitiOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.ustwo.US2MapperKit 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectSix.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | optionalCompoundString 6 | 7 | key 8 | 9 | left_hand_string 10 | right_hand_string 11 | 12 | transformer 13 | US2CompoundValueTransformer 14 | type 15 | String 16 | 17 | non_optionalCompoundString 18 | 19 | nonoptional 20 | true 21 | key 22 | 23 | non_optional_left_hand_string 24 | non_optional_right_hand_string 25 | 26 | transformer 27 | US2CompoundValueTransformer 28 | type 29 | String 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/TestObjectOne.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestObjectOne.swift 3 | // US2Mapper 4 | // 5 | // Created by Anton Doudarev on 6/25/15. 6 | // Copyright © 2015 US2Mapper. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class _TestObjectOne { 12 | var optionalString : String? 13 | 14 | required init(_optionalString: Any?) { 15 | optionalString = typeCast(_optionalString) 16 | } 17 | 18 | convenience init?(_ dictionary: Dictionary) { 19 | let dynamicTypeString = "\(self.dynamicType)" 20 | let className = dynamicTypeString.componentsSeparatedByString(".").last 21 | 22 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled: true) { 23 | self.init(_optionalString: valuesDict["optionalString"]!) 24 | } else { 25 | self.init(_optionalString : nil) 26 | return nil 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /documentation/nested_mapping.md: -------------------------------------------------------------------------------- 1 | ##Example - Nested Mapping 2 | 3 | US2MapperKit supports nested mapping for added flexibility. When mapping against a Dictionary, **dot** notation can be used to reference values in the response. Observe the following response. 4 | 5 | **Response Dictionary** 6 | 7 | ``` 8 | { 9 | "business_uuid" : 9223123456754776000, 10 | "business_name" : "UsTwoRestaurant", 11 | "business_ratings" : [ 5, 4, 5, 4 ], 12 | "business_location" : { 13 | "longitude" : 40.7053319, 14 | "latitude" : -74.0129945 15 | }, 16 | "business_open" : 1 17 | } 18 | ``` 19 | 20 | Although the location in the dictionary is formatted to be handled as custom Location object, assume the need to directly assign the longitude and latitude, as properties of a Business object. 21 | 22 | **Business.plist** 23 |
24 | 25 | ![alt tag](/documentation/readme_assets/nested_mapping_example.png?raw=true) 26 |
27 | 28 | Using the **dot** notation per the example above one can map values as needed with ease. 29 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectTwo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectTwo { 5 | 6 | 7 | 8 | required init() { 9 | 10 | } 11 | 12 | convenience init?(_ dictionary: Dictionary) { 13 | 14 | let dynamicTypeString = "\(self.dynamicType)" 15 | let className = dynamicTypeString.componentsSeparatedByString(".").last 16 | 17 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 18 | 19 | 20 | self.init() 21 | 22 | } else { 23 | self.init() 24 | 25 | return nil 26 | } 27 | } 28 | 29 | func updateWithDictionary(dictionary: Dictionary) { 30 | 31 | let dynamicTypeString = "\(self.dynamicType)" 32 | let className = dynamicTypeString.componentsSeparatedByString(".").last 33 | 34 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { } 35 | } 36 | } -------------------------------------------------------------------------------- /US2MapperKit/US2MapperKit/US2MapperKitOSX/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.ustwo.US2MapperKit 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2015 ustwo. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Test Case Objects/US2ExampleClosureTransformer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // US2ExampleClosureTransformer.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton on 9/3/15. 6 | // Copyright (c) 2015 ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | public class US2ExampleClosureTransformer : US2TransformerProtocol { 13 | public func transformValues(inputValues : Dictionary?) -> Any? { 14 | if let handlerType = inputValues!["handler_type"] as? String { 15 | if handlerType == "uppercase" { 16 | 17 | func returnCapitalizedString(value: String) -> String { 18 | return value.uppercaseString 19 | } 20 | return returnCapitalizedString 21 | 22 | } else if handlerType == "lowercase" { 23 | func returnLowercaseString(value: String) -> String { 24 | return value.lowercaseString 25 | } 26 | return returnLowercaseString 27 | } 28 | } 29 | 30 | return nil 31 | } 32 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2015 ustwo studio inc (www.ustwo.com) 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ -------------------------------------------------------------------------------- /Source/US2MapperKit/Parsers/NativeValueArrayParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NativeValueArrayParser.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton Doudarev on 7/17/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class NativeValueArrayParser { 12 | 13 | // MARK Maps Array representation of native values from a Dictionary of objects 14 | 15 | class func arrayRepresentation(collectionSubType : String?, data : Dictionary, instantiator : US2InstantiatorProtocol) -> [AnyObject] { 16 | 17 | var valueArray : [AnyObject] = [] 18 | 19 | for (_, subDictValue) in data { 20 | valueArray.append(subDictValue) 21 | } 22 | 23 | return valueArray 24 | } 25 | 26 | // MARK Maps Array representation of native values from an Array of objects 27 | 28 | class func arrayRepresentation(collectionSubType : String?, data :[AnyObject], instantiator : US2InstantiatorProtocol) -> [AnyObject] { 29 | 30 | var valueArray : [AnyObject] = [] 31 | 32 | for subDictValue in data { 33 | valueArray.append(subDictValue) 34 | } 35 | 36 | return valueArray 37 | } 38 | } -------------------------------------------------------------------------------- /documentation/changelog.md: -------------------------------------------------------------------------------- 1 | #US2MapperKit ChangeLog 2 | 3 | ###Version 0.2.0 4 | 5 | #####Important Upgrade Notes 6 | 7 | Please note the following API/project changes have been made: 8 | 9 | * New method introduced to allow the developer to update instance values with a new a dictionary. A new method is generated as part of the internal model object `func updateWithDictionary(dictionary: Dictionary)`. You can now update values on an existing instance. 10 | * Fixes [Issue #21](https://github.com/ustwo/US2MapperKit/issues/21) 11 | * The `US2TransformerProtocol` has been updated with support for returning objects of `Any` type, which includes support for _Struct_, _Enums_, _Closures_, and _Tuples_. 12 | * Fixes [Issue #23](https://github.com/ustwo/US2MapperKit/issues/23) 13 | 14 | #####Important Upgrade Notes 15 | 16 | Be sure to update your custom transformers accordingly for continued support of custom transformers. 17 | 18 | ``` 19 | Version 0.1.0 US2TransformerProtocol Definition 20 | 21 | public protocol US2TransformerProtocol { 22 | func transformValues(inputValues : Dictionary?) -> AnyObject? 23 | } 24 | 25 | 26 | Version 0.2.0 US2TransformerProtocol Definition 27 | 28 | public protocol US2TransformerProtocol { 29 | func transformValues(inputValues : Dictionary?) -> Any? 30 | } 31 | 32 | ``` 33 | 34 | ###Version 0.1.0 35 | 36 | Initial Release 37 | 38 | -------------------------------------------------------------------------------- /documentation/complex_value_types.md: -------------------------------------------------------------------------------- 1 | ##Example - Complex Value Types 2 | US2MapperKit's support for mapping complete types allows for creating object types as other objects generated. Let's assume in the example below that the business listing result returns a sub-dictionary for a location, and we would like to store it as a Location type. 3 | 4 | **Response Dictionary** 5 | 6 | ``` 7 | { 8 | 'business_uuid' : 9223123456754775807, 9 | 'business_name' : 'UsTwo Restaurant', 10 | 'business_rating' : 5, 11 | 'business_location : 12 | { 13 | 'longitude' : 40.7053319, 14 | 'latitude' : -74.0129945 15 | }, 16 | 'business_open' : 1 17 | } 18 | 19 | ``` 20 | 21 | First, create a model mapping for the Location object. 22 | 23 | **Location.plist** 24 |
25 | 26 | ![alt tag](/documentation/readme_assets/location_plist.png?raw=true) 27 |
28 | 29 | Once the model mapping for a location has generated a `Location` object, and it has been added to the project, update the Business object mapping by defining a location property typed as **Location** 30 | 31 | **Business.plist** 32 |
33 | 34 | ![alt tag](/documentation/readme_assets/business_location_example.png?raw=true) 35 |
36 | 37 | 38 | When parsing the data for a `Business` object, US2MapperKit will create a `Location` instance, and will assign the resulting value to the location property of the `Business` instance before returning it :) 39 | -------------------------------------------------------------------------------- /Source/US2MapperKit/Parsers/NativeValueDictionaryParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NativeValueDictionaryParser.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton Doudarev on 7/17/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class NativeValueDictionaryParser { 12 | 13 | // MARK Maps Dictionary representation of native values from an Array of objects 14 | 15 | class func dictionaryRepresentation(collectionSubType : String?, data : Dictionary, instantiator : US2InstantiatorProtocol) -> Dictionary { 16 | 17 | var valueDictionary = Dictionary() 18 | var intKey = 0 19 | 20 | for (key, subDictValue) in data { 21 | valueDictionary[String(key)] = subDictValue 22 | intKey++ 23 | } 24 | 25 | return valueDictionary 26 | } 27 | 28 | // MARK Maps Dictionary representation of native values from an Array of objects 29 | 30 | class func dictionaryRepresentation(collectionSubType : String?, data : [AnyObject], instantiator : US2InstantiatorProtocol) -> Dictionary { 31 | 32 | var valueDictionary = Dictionary() 33 | var intKey = 0 34 | 35 | for subDictValue in data { 36 | valueDictionary[String(intKey)] = subDictValue 37 | intKey++ 38 | } 39 | 40 | return valueDictionary 41 | } 42 | } -------------------------------------------------------------------------------- /documentation/non_optional_value_types.md: -------------------------------------------------------------------------------- 1 | ##Example - Non Optional Value Types 2 | If a property is non-optional, such as the **uuid** property for the Business model object, a **nonoptional** can be added to the property definition in the model mapping. Let's take a quick peak at the `Business.plist`. 3 | 4 | **Business.plist** 5 |
6 | 7 | ![alt tag](/documentation/readme_assets/non_optional_business.png?raw=true) 8 |
9 | 10 | Once the model mapping has been updated, perform a build **(⌘-B)**, and the changes should be reflected accordingly in the internal `_Business.swift` class. 11 | 12 | **Business.swift** 13 |
14 | 15 | ``` 16 | import Foundation 17 | import US2MapperKit 18 | 19 | class _Business { 20 | 21 | var rating : Int? 22 | var longitude : Float? 23 | var latitude : Float? 24 | var open : Bool? 25 | var name : String? 26 | 27 | var uuid : Double 28 | 29 | required init(_uuid : Double) {...} 30 | 31 | convenience init?(_ dictionary: Dictionary) {...} 32 | } 33 | ``` 34 | 35 | Once the script has updated the internal file, the uuid property should be a non-optional property, and been added to the required initializer as an input parameter. In the case that the response dictionary does not contain a value for the uuid, the fail-able initializer will return nil. 36 | 37 | ###Default Values 38 | To assign a default value definition for a non-optional property, follow the example found in the [Defining Default Values](/documentation/default_values.md) section of the documentation 39 | -------------------------------------------------------------------------------- /Source/US2MapperKit/Parsers/ComplexValueArrayParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ComplexValueArrayParser.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton Doudarev on 7/17/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class ComplexValueArrayParser { 12 | 13 | // MARK Maps array representation of complex objects from an Array of Dictionary objects 14 | 15 | class func arrayRepresentation(collectionSubType : String?, data : [Dictionary], instantiator : US2InstantiatorProtocol) -> [AnyObject] { 16 | 17 | var valueArray : [AnyObject] = [] 18 | 19 | for subArrayValue in data { 20 | if let complexTypeValue: AnyObject = instantiator.newInstance(ofType: collectionSubType!, withValue: subArrayValue) { 21 | valueArray.append(complexTypeValue) 22 | } 23 | } 24 | return valueArray 25 | } 26 | 27 | // MARK array representation of complex objects from a Dictionary of Dictionary objects 28 | 29 | class func arrayRepresentation(collectionSubType : String?, data : Dictionary>, instantiator : US2InstantiatorProtocol) -> [AnyObject] { 30 | 31 | var valueArray : [AnyObject] = [] 32 | 33 | for (_, subDictValue) in data { 34 | if let complexTypeValue: AnyObject = instantiator.newInstance(ofType: collectionSubType!, withValue: subDictValue) { 35 | valueArray.append(complexTypeValue) 36 | } 37 | } 38 | return valueArray 39 | } 40 | } -------------------------------------------------------------------------------- /documentation/collection_types.md: -------------------------------------------------------------------------------- 1 | ##Example - Collection Types 2 | US2MapperKit's support for mapping Dictionaries and Arrays when parsing a responses' collection values is quite easy. Let's assume in the example below that the business listing result returns an array of ratings, and we would like to store them as an Array type 3 | 4 | **Response Dictionary** 5 | 6 | ``` 7 | { 8 | "business_uuid" : 9223123456754776000, 9 | "business_name" : "UsTwoRestaurant", 10 | "business_ratings" : [ 5, 4, 5, 4 ], 11 | "business_location" : { 12 | "longitude" : 40.7053319, 13 | "latitude" : -74.0129945 14 | }, 15 | "business_open" : 1 16 | } 17 | ``` 18 | First, update a model mapping for the Business object by defining setting the **type** key definition to `Array`, and adding a new **collection_subtype** key to define the subtype as `Int`. 19 | 20 | **Business.plist** 21 |
22 | 23 | ![alt tag](/documentation/readme_assets/ratings_array_example.png?raw=true) 24 |
25 | 26 | When parsing the data for a `Business` object, US2MapperKit will create a parsed ratings `Array`, and will assign the resulting value to the ratings property of the `Business` instance before returning it. 27 | 28 | This also works for Dictionaries by setting the **type** key to Dictionary. When parsing a dictionary, US2MapperKit will use the assigned keys in the response when setting the values in the parsed `Dictionary`. If the response is an array, and the property to be mapped is a dictionary, US2MappkerKit will use an incremental index as the key starting with zero. 29 | 30 | Note: When parsing collections, **collection_subtype** can be any of the native value types `String`, `Int`, `Double`, `Float`, `Bool`, and/or any object generated by a US2MapperKit. 31 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectThirteen.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | optionalStruct 6 | 7 | type 8 | StructExample 9 | transformer 10 | US2ExampleStructTransformer 11 | key 12 | 13 | string1 14 | string2 15 | 16 | 17 | optionalEnum 18 | 19 | type 20 | EnumExample 21 | transformer 22 | US2ExampleEnumTransformer 23 | key 24 | 25 | enumValue 26 | 27 | 28 | optionalTuple 29 | 30 | type 31 | (val1 : Double, val2 : Double) 32 | transformer 33 | US2ExampleTupleTransformer 34 | key 35 | 36 | value_one 37 | value_two 38 | 39 | 40 | optionalUppercaseCompletionHandler 41 | 42 | type 43 | ((value : String) -> String) 44 | transformer 45 | US2ExampleClosureTransformer 46 | key 47 | 48 | handler_type 49 | 50 | 51 | optionalLowercaseCompletionHandler 52 | 53 | type 54 | ((value : String) -> String) 55 | transformer 56 | US2ExampleClosureTransformer 57 | key 58 | 59 | handler_type 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectFive.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectFive { 5 | 6 | var optionalSubType : TestObjectThree? 7 | 8 | var non_optionalSubType : TestObjectThree 9 | 10 | required init(_non_optionalSubType : TestObjectThree) { 11 | 12 | non_optionalSubType = _non_optionalSubType 13 | } 14 | 15 | convenience init?(_ dictionary: Dictionary) { 16 | 17 | let dynamicTypeString = "\(self.dynamicType)" 18 | let className = dynamicTypeString.componentsSeparatedByString(".").last 19 | 20 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 21 | 22 | let temp_non_optionalSubType : TestObjectThree = typeCast(valuesDict["non_optionalSubType"])! 23 | 24 | self.init(_non_optionalSubType : temp_non_optionalSubType) 25 | 26 | if let unwrapped_optionalSubType : Any = valuesDict["optionalSubType"] { 27 | optionalSubType = typeCast(unwrapped_optionalSubType) 28 | } 29 | 30 | } else { 31 | self.init(_non_optionalSubType : TestObjectThree(Dictionary())!) 32 | 33 | return nil 34 | } 35 | } 36 | 37 | func updateWithDictionary(dictionary: Dictionary) { 38 | 39 | let dynamicTypeString = "\(self.dynamicType)" 40 | let className = dynamicTypeString.componentsSeparatedByString(".").last 41 | 42 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { 43 | if let unwrapped_optionalSubType : Any = valuesDict["optionalSubType"] { 44 | optionalSubType = typeCast(unwrapped_optionalSubType) 45 | } 46 | 47 | if let unwrapped_non_optionalSubType : Any = valuesDict["non_optionalSubType"] { 48 | non_optionalSubType = typeCast(unwrapped_non_optionalSubType)! 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectSeven.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectSeven { 5 | 6 | var optionalArrayType : [TestObjectFour]? 7 | 8 | var non_optionalArrayType : [TestObjectFour] 9 | 10 | required init(_non_optionalArrayType : [TestObjectFour]) { 11 | 12 | non_optionalArrayType = _non_optionalArrayType 13 | } 14 | 15 | convenience init?(_ dictionary: Dictionary) { 16 | 17 | let dynamicTypeString = "\(self.dynamicType)" 18 | let className = dynamicTypeString.componentsSeparatedByString(".").last 19 | 20 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 21 | 22 | let temp_non_optionalArrayType : [TestObjectFour] = typeCast(valuesDict["non_optionalArrayType"])! 23 | 24 | self.init(_non_optionalArrayType : temp_non_optionalArrayType) 25 | 26 | if let unwrapped_optionalArrayType : Any = valuesDict["optionalArrayType"] { 27 | optionalArrayType = typeCast(unwrapped_optionalArrayType) 28 | } 29 | 30 | } else { 31 | self.init(_non_optionalArrayType : [TestObjectFour]()) 32 | 33 | return nil 34 | } 35 | } 36 | 37 | func updateWithDictionary(dictionary: Dictionary) { 38 | 39 | let dynamicTypeString = "\(self.dynamicType)" 40 | let className = dynamicTypeString.componentsSeparatedByString(".").last 41 | 42 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { 43 | if let unwrapped_optionalArrayType : Any = valuesDict["optionalArrayType"] { 44 | optionalArrayType = typeCast(unwrapped_optionalArrayType) 45 | } 46 | 47 | if let unwrapped_non_optionalArrayType : Any = valuesDict["non_optionalArrayType"] { 48 | non_optionalArrayType = typeCast(unwrapped_non_optionalArrayType)! 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectSix.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectSix { 5 | 6 | var optionalCompoundString : String? 7 | 8 | var non_optionalCompoundString : String 9 | 10 | required init(_non_optionalCompoundString : String) { 11 | 12 | non_optionalCompoundString = _non_optionalCompoundString 13 | } 14 | 15 | convenience init?(_ dictionary: Dictionary) { 16 | 17 | let dynamicTypeString = "\(self.dynamicType)" 18 | let className = dynamicTypeString.componentsSeparatedByString(".").last 19 | 20 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 21 | 22 | let temp_non_optionalCompoundString : String = typeCast(valuesDict["non_optionalCompoundString"])! 23 | 24 | self.init(_non_optionalCompoundString : temp_non_optionalCompoundString) 25 | 26 | if let unwrapped_optionalCompoundString : Any = valuesDict["optionalCompoundString"] { 27 | optionalCompoundString = typeCast(unwrapped_optionalCompoundString) 28 | } 29 | 30 | } else { 31 | self.init(_non_optionalCompoundString : String()) 32 | 33 | return nil 34 | } 35 | } 36 | 37 | func updateWithDictionary(dictionary: Dictionary) { 38 | 39 | let dynamicTypeString = "\(self.dynamicType)" 40 | let className = dynamicTypeString.componentsSeparatedByString(".").last 41 | 42 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { 43 | if let unwrapped_optionalCompoundString : Any = valuesDict["optionalCompoundString"] { 44 | optionalCompoundString = typeCast(unwrapped_optionalCompoundString) 45 | } 46 | 47 | if let unwrapped_non_optionalCompoundString : Any = valuesDict["non_optionalCompoundString"] { 48 | non_optionalCompoundString = typeCast(unwrapped_non_optionalCompoundString)! 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectEight.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectEight { 5 | 6 | var optionalDictionaryType : Dictionary? 7 | 8 | var non_optionalDictionaryType : Dictionary 9 | 10 | required init(_non_optionalDictionaryType : Dictionary) { 11 | 12 | non_optionalDictionaryType = _non_optionalDictionaryType 13 | } 14 | 15 | convenience init?(_ dictionary: Dictionary) { 16 | 17 | let dynamicTypeString = "\(self.dynamicType)" 18 | let className = dynamicTypeString.componentsSeparatedByString(".").last 19 | 20 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 21 | 22 | let temp_non_optionalDictionaryType : Dictionary = typeCast(valuesDict["non_optionalDictionaryType"])! 23 | 24 | self.init(_non_optionalDictionaryType : temp_non_optionalDictionaryType) 25 | 26 | if let unwrapped_optionalDictionaryType : Any = valuesDict["optionalDictionaryType"] { 27 | optionalDictionaryType = typeCast(unwrapped_optionalDictionaryType) 28 | } 29 | 30 | } else { 31 | self.init(_non_optionalDictionaryType : Dictionary()) 32 | 33 | return nil 34 | } 35 | } 36 | 37 | func updateWithDictionary(dictionary: Dictionary) { 38 | 39 | let dynamicTypeString = "\(self.dynamicType)" 40 | let className = dynamicTypeString.componentsSeparatedByString(".").last 41 | 42 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { 43 | if let unwrapped_non_optionalDictionaryType : Any = valuesDict["non_optionalDictionaryType"] { 44 | non_optionalDictionaryType = typeCast(unwrapped_non_optionalDictionaryType)! 45 | } 46 | 47 | if let unwrapped_optionalDictionaryType : Any = valuesDict["optionalDictionaryType"] { 48 | optionalDictionaryType = typeCast(unwrapped_optionalDictionaryType) 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /Source/US2MapperKit/Transformer/Transformer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Transformer.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton Doudarev on 7/17/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | var transformerInstances : Dictionary = Dictionary () 12 | 13 | final class Transformer : Parser { 14 | 15 | class func transformedValue(from data : Dictionary, applying propertyMapping : Dictionary, employing instantiator : US2InstantiatorProtocol) -> Any? { 16 | 17 | if let transformClass = propertyMapping[US2MapperTransformerKey] as? String { 18 | if let jsonKeys = propertyMapping[US2MapperJSONKey] as? [String] { 19 | if let transformedValue: Any = transformedValueRepresentation(transformClass, jsonKeys : jsonKeys, data: data, instantiator: instantiator) { 20 | return transformedValue 21 | } 22 | } 23 | } 24 | return nil 25 | } 26 | 27 | class func transformedValueRepresentation(mapperClass : String, jsonKeys : [String], data : Dictionary, instantiator : US2InstantiatorProtocol) -> Any? { 28 | 29 | var valueDictionary : Dictionary = Dictionary() 30 | 31 | for jsonKey in jsonKeys { 32 | if let jsonValue: AnyObject = dictionaryValueForKey(jsonKey, dictionary: data) { 33 | valueDictionary[jsonKey] = jsonValue 34 | } 35 | } 36 | 37 | if let customTransformer = customTransformer(mapperClass, instantiator: instantiator) { 38 | if let transformedValue: Any = customTransformer.transformValues(valueDictionary) { 39 | return transformedValue; 40 | } 41 | } 42 | 43 | return nil 44 | } 45 | 46 | 47 | class func customTransformer(className : String, instantiator : US2InstantiatorProtocol) -> US2TransformerProtocol? { 48 | if let transformer = transformerInstances[className] { 49 | return transformer 50 | } else { 51 | if let transformer = instantiator.transformerFromString(className) { 52 | transformerInstances[className] = transformer 53 | return transformer 54 | } else { 55 | return nil 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectFour.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | optionalInt 6 | 7 | key 8 | optional_int 9 | type 10 | Int 11 | 12 | optionalString 13 | 14 | key 15 | optional_string 16 | type 17 | String 18 | 19 | optionalDouble 20 | 21 | key 22 | optional_double 23 | type 24 | Double 25 | 26 | optionalFloat 27 | 28 | key 29 | optional_float 30 | type 31 | Float 32 | 33 | optionalBool 34 | 35 | key 36 | optional_bool 37 | type 38 | Bool 39 | 40 | non_optionalInt 41 | 42 | nonoptional 43 | true 44 | default 45 | 500 46 | key 47 | non_optional_int 48 | type 49 | Int 50 | 51 | non_optionalString 52 | 53 | nonoptional 54 | true 55 | default 56 | Non-Optional Hello 57 | key 58 | non_optional_string 59 | type 60 | String 61 | 62 | non_optionalDouble 63 | 64 | nonoptional 65 | true 66 | default 67 | 50.0 68 | key 69 | non_optional_double 70 | type 71 | Double 72 | 73 | non_optionalFloat 74 | 75 | nonoptional 76 | true 77 | default 78 | 60.0 79 | key 80 | non_optional_float 81 | type 82 | Float 83 | 84 | non_optionalBool 85 | 86 | nonoptional 87 | true 88 | default 89 | true 90 | key 91 | non_optional_bool 92 | type 93 | Bool 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectNine.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | optionalArrayStringType 6 | 7 | key 8 | optional_array_string_type 9 | type 10 | Array 11 | collection_subtype 12 | String 13 | 14 | optionalArrayDoubleType 15 | 16 | key 17 | optional_array_double_type 18 | type 19 | Array 20 | collection_subtype 21 | Double 22 | 23 | optionalArrayFloatType 24 | 25 | key 26 | optional_array_float_type 27 | type 28 | Array 29 | collection_subtype 30 | Float 31 | 32 | optionalArrayIntType 33 | 34 | key 35 | optional_array_int_type 36 | type 37 | Array 38 | collection_subtype 39 | Int 40 | 41 | non_optionalArrayStringType 42 | 43 | nonoptional 44 | true 45 | key 46 | non_optional_array_string_type 47 | type 48 | Array 49 | collection_subtype 50 | String 51 | 52 | non_optionalArrayDoubleType 53 | 54 | nonoptional 55 | true 56 | key 57 | non_optional_array_double_type 58 | type 59 | Array 60 | collection_subtype 61 | Double 62 | 63 | non_optionalArrayFloatType 64 | 65 | nonoptional 66 | true 67 | key 68 | non_optional_array_float_type 69 | type 70 | Array 71 | collection_subtype 72 | Float 73 | 74 | non_optionalArrayIntType 75 | 76 | nonoptional 77 | true 78 | key 79 | non_optional_array_int_type 80 | type 81 | Array 82 | collection_subtype 83 | Int 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Source/US2MapperKit/Parsers/NativeTypeParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NativeTypeParser.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton Doudarev on 7/17/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class NativeTypeParser { 12 | 13 | class func nativeRepresentation(fromValue data : AnyObject, asType objectType : String?) -> AnyObject? { 14 | return convertValue(data, dataType : objectType!) 15 | } 16 | 17 | class func convertValue(value : AnyObject, dataType : String) -> AnyObject? { 18 | switch dataType { 19 | case US2DataTypeString: 20 | if value is NSNumber { 21 | return numericString(value as! NSNumber) 22 | } 23 | return "\(value)" 24 | case US2DataTypeDouble: 25 | return Double(value.doubleValue) 26 | case US2DataTypeFloat: 27 | return Float(value.floatValue) 28 | case US2DataTypeInt: 29 | return Int(value.integerValue) 30 | case US2DataTypeBool: 31 | return value.boolValue 32 | default: 33 | return value 34 | } 35 | } 36 | 37 | class func numericString(value: NSNumber) -> String { 38 | switch CFNumberGetType(value){ 39 | case .SInt8Type: 40 | return String(value.charValue) 41 | case .SInt16Type: 42 | return String(value.shortValue) 43 | case .SInt32Type: 44 | return String(value.intValue) 45 | case .SInt64Type: 46 | return String(value.longLongValue) 47 | case .Float32Type: 48 | return String(stringInterpolationSegment: value.floatValue) 49 | case .Float64Type: 50 | return String(stringInterpolationSegment: value.doubleValue) 51 | case .CharType: 52 | return String(value.charValue) 53 | case .ShortType: 54 | return String(value.shortValue) 55 | case .IntType: 56 | return String(value.integerValue) 57 | case .LongType: 58 | return String(value.longValue) 59 | case .LongLongType: 60 | return String(value.longLongValue) 61 | case .FloatType: 62 | return String(stringInterpolationSegment: value.floatValue) 63 | case .DoubleType: 64 | return String(stringInterpolationSegment: value.doubleValue) 65 | default: 66 | return String(stringInterpolationSegment: value.doubleValue) 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Source/US2MapperKit/Parsers/ComplexValueDictionaryParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ComplexValueDictionaryParser.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton Doudarev on 7/17/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class ComplexValueDictionaryParser { 12 | 13 | // MARK Maps dictionary representation of complex objects from a Dictionary of Dictionary objects 14 | 15 | class func dictionaryRepresentation(collectionSubType : String?, data : Dictionary>, instantiator : US2InstantiatorProtocol) -> Dictionary { 16 | 17 | var valueDictionary : Dictionary = Dictionary() 18 | 19 | for (key, subDictValue) in data { 20 | if let complexTypeValue: AnyObject = instantiator.newInstance(ofType: collectionSubType!, withValue: subDictValue) { 21 | valueDictionary["\(key)"] = complexTypeValue 22 | } 23 | } 24 | return valueDictionary 25 | } 26 | 27 | // MARK Maps dictionary representation of complex objects from an Array of Dictionary objects 28 | 29 | class func dictionaryRepresentation(collectionSubType : String?, data : [Dictionary], instantiator : US2InstantiatorProtocol) -> Dictionary { 30 | 31 | var valueDictionary : Dictionary = Dictionary() 32 | var intKey = 0 33 | for subDictValue in data { 34 | if let complexTypeValue: AnyObject = instantiator.newInstance(ofType: collectionSubType!, withValue: subDictValue) { 35 | valueDictionary["\(intKey)"] = complexTypeValue 36 | intKey++ 37 | } 38 | } 39 | return valueDictionary 40 | } 41 | 42 | // MARK Maps dictionary representation of complex objects from a single dictionary instance returned 43 | 44 | class func dictionaryRepresentation(collectionSubType : String?, data : Dictionary, instantiator : US2InstantiatorProtocol) -> Dictionary { 45 | 46 | var valueDictionary : Dictionary = Dictionary() 47 | 48 | if let complexTypeValue: AnyObject = instantiator.newInstance(ofType: collectionSubType!, withValue: data) { 49 | valueDictionary["0"] = complexTypeValue 50 | } 51 | 52 | return valueDictionary 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectTwelve.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | optionalInt 6 | 7 | key 8 | top_level_key.optional_int 9 | type 10 | Int 11 | 12 | optionalString 13 | 14 | key 15 | top_level_key.optional_string 16 | type 17 | String 18 | 19 | optionalDouble 20 | 21 | key 22 | top_level_key,optional_double 23 | type 24 | Double 25 | 26 | optionalFloat 27 | 28 | key 29 | top_level_key.optional_float 30 | type 31 | Float 32 | 33 | optionalBool 34 | 35 | key 36 | top_level_key.optional_bool 37 | type 38 | Bool 39 | 40 | non_optionalInt 41 | 42 | nonoptional 43 | true 44 | default 45 | 500 46 | key 47 | non_optional_int 48 | type 49 | Int 50 | 51 | non_optionalString 52 | 53 | nonoptional 54 | true 55 | default 56 | Non-Optional Hello 57 | key 58 | non_optional_string 59 | type 60 | String 61 | 62 | non_optionalDouble 63 | 64 | nonoptional 65 | true 66 | default 67 | 50.0 68 | key 69 | top_level_key.non_optional_double 70 | type 71 | Double 72 | 73 | non_optionalFloat 74 | 75 | nonoptional 76 | true 77 | default 78 | 60.0 79 | key 80 | top_level_key.non_optional_float 81 | type 82 | Float 83 | 84 | non_optionalBool 85 | 86 | nonoptional 87 | true 88 | default 89 | true 90 | key 91 | top_level_key.non_optional_bool 92 | type 93 | Bool 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectTen.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | optionalDictionaryStringType 6 | 7 | key 8 | optional_dictionary_string_type 9 | type 10 | Dictionary 11 | collection_subtype 12 | String 13 | 14 | optionalDictionaryDoubleType 15 | 16 | key 17 | optional_dictionary_double_type 18 | type 19 | Dictionary 20 | collection_subtype 21 | Double 22 | 23 | optionalDictionaryFloatType 24 | 25 | key 26 | optional_dictionary_float_type 27 | type 28 | Dictionary 29 | collection_subtype 30 | Float 31 | 32 | optionalDictionaryIntType 33 | 34 | key 35 | optional_dictionary_int_type 36 | type 37 | Dictionary 38 | collection_subtype 39 | Int 40 | 41 | non_optionalDictionaryStringType 42 | 43 | nonoptional 44 | true 45 | key 46 | non_optional_dictionary_string_type 47 | type 48 | Dictionary 49 | collection_subtype 50 | String 51 | 52 | non_optionalDictionaryDoubleType 53 | 54 | nonoptional 55 | true 56 | key 57 | non_optional_dictionary_double_type 58 | type 59 | Dictionary 60 | collection_subtype 61 | Double 62 | 63 | non_optionalDictionaryFloatType 64 | 65 | nonoptional 66 | true 67 | key 68 | non_optional_dictionary_float_type 69 | type 70 | Dictionary 71 | collection_subtype 72 | Float 73 | 74 | non_optionalDictionaryIntType 75 | 76 | nonoptional 77 | true 78 | key 79 | non_optional_dictionary_int_type 80 | type 81 | Dictionary 82 | collection_subtype 83 | Int 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectEleven.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | optionalInt 6 | 7 | key 8 | top_level_key.optional_int 9 | type 10 | Int 11 | 12 | optionalString 13 | 14 | key 15 | top_level_key.optional_string 16 | type 17 | String 18 | 19 | optionalDouble 20 | 21 | key 22 | top_level_key,optional_double 23 | type 24 | Double 25 | 26 | optionalFloat 27 | 28 | key 29 | top_level_key.optional_float 30 | type 31 | Float 32 | 33 | optionalBool 34 | 35 | key 36 | top_level_key.optional_bool 37 | type 38 | Bool 39 | 40 | non_optionalInt 41 | 42 | nonoptional 43 | true 44 | default 45 | 500 46 | key 47 | top_level_key.non_optional_int 48 | type 49 | Int 50 | 51 | non_optionalString 52 | 53 | nonoptional 54 | true 55 | default 56 | Non-Optional Hello 57 | key 58 | top_level_key.non_optional_string 59 | type 60 | String 61 | 62 | non_optionalDouble 63 | 64 | nonoptional 65 | true 66 | default 67 | 50.0 68 | key 69 | top_level_key.non_optional_double 70 | type 71 | Double 72 | 73 | non_optionalFloat 74 | 75 | nonoptional 76 | true 77 | default 78 | 60.0 79 | key 80 | top_level_key.non_optional_float 81 | type 82 | Float 83 | 84 | non_optionalBool 85 | 86 | nonoptional 87 | true 88 | default 89 | true 90 | key 91 | top_level_key.non_optional_bool 92 | type 93 | Bool 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Source/US2MapperKit/Validator/Validator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Validator.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton Doudarev on 7/17/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class Validator { 12 | 13 | // MARK Validates that all the non-optional values were received or defaulted 14 | 15 | final class func validateResponse(forValues retrievedValues : Dictionary, 16 | mappedTo mappingConfiguration : Dictionary>, 17 | forType className : String, 18 | withData data : Dictionary) -> Bool { 19 | 20 | #if US2MAPPER_DEBUG 21 | var missingPropertyKeyArray = Array() 22 | #endif 23 | 24 | // Validate that all non-optional properties have a value assigned 25 | 26 | for (propertyKey, propertyMapping) in mappingConfiguration { 27 | if let isPropertyNonOptional : AnyObject = propertyMapping[US2MapperNonOptionalKey] { 28 | if isPropertyNonOptional.boolValue == true { 29 | if let _ = retrievedValues[propertyKey] { 30 | // If value was mapped, continue with validation 31 | continue 32 | } else { 33 | #if US2MAPPER_DEBUG 34 | missingPropertyKeyArray.append(propertyKey) 35 | #else 36 | return false 37 | #endif 38 | } 39 | } 40 | } 41 | } 42 | 43 | #if US2MAPPER_DEBUG 44 | if (missingPropertyKeyArray.count > 0) { 45 | printDebugStatement(className, missingPropertyKeyArray: missingPropertyKeyArray, data : data) 46 | return false 47 | } 48 | #endif 49 | 50 | return true 51 | } 52 | 53 | // MARK Debug Enabled Methods 54 | 55 | final class func printDebugStatement(className : String, missingPropertyKeyArray : Array, data : Dictionary){ 56 | if (missingPropertyKeyArray.count > 0) { 57 | print("\n\n\(className) instance could not be parsed, missing values for the following non-optional properties:") 58 | for propertyKey in missingPropertyKeyArray { 59 | print("\n- \(propertyKey)") 60 | } 61 | 62 | print("\n\nResponse:\n\(data)\n\n") 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /documentation/custom_transforms_tuples.md: -------------------------------------------------------------------------------- 1 | ##Example - Tuple Transformations 2 | 3 | As of version 0.2.0 of U2MapperKit, the ability to map tuples via the `US2TransformerProtocol` as support was added. This ensures that we can return an a value of `Any` type. Let's look at a dictionary for a business object, and see how we can map a the coordinates as a tuple. 4 | 5 | **Response Dictionary** 6 | 7 | ``` 8 | { 9 | 'business_uuid' : 9223123456754775807, 10 | 'business_name' : 'UsTwo Restaurant', 11 | 'business_longitude' : 40.7053319, 12 | 'business_latitude' : -74.0129945, 13 | } 14 | ``` 15 | 16 | For the purposes of the example, let's create a mapper that returns a tuple. First, create an enum to represent the business type for our custom Business Object: 17 | 18 | 19 | **US2TupleCoordinateExampleTransformer Implementation** 20 | 21 | ``` 22 | let longitudeKey = "business_longitude" 23 | let latitudeKey = "business_latitude" 24 | 25 | public class US2TupleCoordinateExampleTransformer : US2TransformerProtocol { 26 | 27 | public func transformValues(inputValues : Dictionary?) -> Any? { 28 | if let coordinateDictionary = inputValues as? Dictionary { 29 | if let unwrappedLongitude = coordinateDictionary[longitudeKey] as? Double { 30 | if let unwrappedLatitude = coordinateDictionary[latitudeKey] as? Double { 31 | return (longitude : unwrappedLongitude, latitude : unwrappedLatitude) 32 | } 33 | } 34 | } 35 | return nil 36 | } 37 | } 38 | ``` 39 | 40 | Now that we have created a transformer, let's create mapping for our business Object: 41 | 42 | **Business.plist** 43 |
44 | 45 | ![alt tag](/documentation/readme_assets/tuple_mapping_example.png?raw=true) 46 |
47 | 48 | After the creation of the mapping, perform a build **(⌘-B)**. The changes should be reflected accordingly in the internal `_Business.swift` class. 49 | 50 | 51 | ``` 52 | import Foundation 53 | import US2MapperKit 54 | 55 | class _Business { 56 | var uuid : Double? 57 | var name : String? 58 | var coordinates : (longitude : Double, latitude : Double)? 59 | 60 | required init() {...} 61 | 62 | convenience init?(_ dictionary: Dictionary) {...} 63 | } 64 | ``` 65 | 66 | After calling the fail-able initializer - or udpateWithDictionary method with a dictioanry representation - US2MapperKit will use the custom transformer to map the tuple accordingly. 67 | 68 | Note: The the keys defined in the property mapping correspond to the keys in the dictionary of values passed to the ` public func transformValues(inputValues : Dictionary?) -> Any?` method defined by the protocol. 69 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Mapping/TestObjectThree.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | optionalString 6 | 7 | default 8 | Hello 9 | key 10 | optional_string 11 | type 12 | String 13 | 14 | optionalInt 15 | 16 | default 17 | 10 18 | key 19 | optional_int 20 | type 21 | Int 22 | 23 | optionalDouble 24 | 25 | default 26 | 20.0 27 | key 28 | optional_double 29 | type 30 | Double 31 | 32 | optionalFloat 33 | 34 | default 35 | 30.0 36 | key 37 | optional_float 38 | type 39 | Float 40 | 41 | optionalBool 42 | 43 | default 44 | true 45 | key 46 | optional_bool 47 | type 48 | Bool 49 | 50 | non_optionalString 51 | 52 | nonoptional 53 | true 54 | default 55 | Non-Optional Hello 56 | key 57 | non_optional_string 58 | type 59 | String 60 | 61 | non_optionalInt 62 | 63 | nonoptional 64 | true 65 | default 66 | 40 67 | key 68 | non_optional_int 69 | type 70 | Int 71 | 72 | non_optionalDouble 73 | 74 | nonoptional 75 | true 76 | default 77 | 50.0 78 | key 79 | non_optional_double 80 | type 81 | Double 82 | 83 | non_optionalFloat 84 | 85 | nonoptional 86 | true 87 | default 88 | 60.0 89 | key 90 | non_optional_float 91 | type 92 | Float 93 | 94 | non_optionalBool 95 | 96 | nonoptional 97 | true 98 | default 99 | false 100 | key 101 | non_optional_bool 102 | type 103 | Bool 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectThirteen.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectThirteen { 5 | 6 | var optionalStruct : StructExample? 7 | var optionalTuple : (val1 : Double, val2 : Double)? 8 | var optionalUppercaseCompletionHandler : ((value : String) -> String)? 9 | var optionalLowercaseCompletionHandler : ((value : String) -> String)? 10 | var optionalEnum : EnumExample? 11 | 12 | 13 | required init() { 14 | 15 | } 16 | 17 | convenience init?(_ dictionary: Dictionary) { 18 | 19 | let dynamicTypeString = "\(self.dynamicType)" 20 | let className = dynamicTypeString.componentsSeparatedByString(".").last 21 | 22 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 23 | 24 | 25 | self.init() 26 | 27 | if let unwrapped_optionalStruct : Any = valuesDict["optionalStruct"] { 28 | optionalStruct = typeCast(unwrapped_optionalStruct) 29 | } 30 | 31 | if let unwrapped_optionalTuple : Any = valuesDict["optionalTuple"] { 32 | optionalTuple = typeCast(unwrapped_optionalTuple) 33 | } 34 | 35 | if let unwrapped_optionalUppercaseCompletionHandler : Any = valuesDict["optionalUppercaseCompletionHandler"] { 36 | optionalUppercaseCompletionHandler = typeCast(unwrapped_optionalUppercaseCompletionHandler) 37 | } 38 | 39 | if let unwrapped_optionalLowercaseCompletionHandler : Any = valuesDict["optionalLowercaseCompletionHandler"] { 40 | optionalLowercaseCompletionHandler = typeCast(unwrapped_optionalLowercaseCompletionHandler) 41 | } 42 | 43 | if let unwrapped_optionalEnum : Any = valuesDict["optionalEnum"] { 44 | optionalEnum = typeCast(unwrapped_optionalEnum) 45 | } 46 | 47 | } else { 48 | self.init() 49 | 50 | return nil 51 | } 52 | } 53 | 54 | func updateWithDictionary(dictionary: Dictionary) { 55 | 56 | let dynamicTypeString = "\(self.dynamicType)" 57 | let className = dynamicTypeString.componentsSeparatedByString(".").last 58 | 59 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { 60 | if let unwrapped_optionalStruct : Any = valuesDict["optionalStruct"] { 61 | optionalStruct = typeCast(unwrapped_optionalStruct) 62 | } 63 | 64 | if let unwrapped_optionalTuple : Any = valuesDict["optionalTuple"] { 65 | optionalTuple = typeCast(unwrapped_optionalTuple) 66 | } 67 | 68 | if let unwrapped_optionalUppercaseCompletionHandler : Any = valuesDict["optionalUppercaseCompletionHandler"] { 69 | optionalUppercaseCompletionHandler = typeCast(unwrapped_optionalUppercaseCompletionHandler) 70 | } 71 | 72 | if let unwrapped_optionalLowercaseCompletionHandler : Any = valuesDict["optionalLowercaseCompletionHandler"] { 73 | optionalLowercaseCompletionHandler = typeCast(unwrapped_optionalLowercaseCompletionHandler) 74 | } 75 | 76 | if let unwrapped_optionalEnum : Any = valuesDict["optionalEnum"] { 77 | optionalEnum = typeCast(unwrapped_optionalEnum) 78 | } 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /documentation/custom_transforms_struct.md: -------------------------------------------------------------------------------- 1 | ##Example - Struct Transformations 2 | 3 | As of version 0.2.0 of U2MapperKit, the ability to map structs via the `US2TransformerProtocol` as support was added. This ensures that we can return a value of `Any` type. Let's look at a dictionary for a business object and see how we can map a struct for the coordinates: 4 | 5 | **Response Dictionary** 6 | 7 | ``` 8 | { 9 | 'business_uuid' : 9223123456754775807, 10 | 'business_name' : 'UsTwo Restaurant', 11 | 'business_longitude' : 40.7053319, 12 | 'business_latitude' : -74.0129945, 13 | } 14 | ``` 15 | 16 | Unlike the model objects, US2MapperKit does not autogenerate structs, due to the lack of inheritance. Structs would be uncustomizable if it did, and would prevent the developer from using the many features Swift offers with structs. For the purposes of this example, let assume that we created a struct to represent the coordinates for our custom Business Object. 17 | 18 | **Struct Definition** 19 | 20 | ``` 21 | struct Coordinate { 22 | var longitude: Double 23 | var latitude: Double 24 | } 25 | ``` 26 | 27 | Once we have defined a Coordinate struct, let's create a mapper that parses out the values from the response and return the value of Coordinate type. 28 | 29 | **US2ExampleCoordinateTransformer Implementation** 30 | 31 | ``` 32 | let longitudeKey = "longitude" 33 | let latitudeKey = "latitude" 34 | 35 | public class US2ExampleCoordinateTransformer : US2TransformerProtocol { 36 | 37 | public func transformValues(inputValues : Dictionary?) -> Any? { 38 | 39 | if let coordinateDictionary = inputValues as? Dictionary { 40 | if let unwrappedLongitude = coordinateDictionary[longitudeKey] { 41 | if let unwrappedLatitude = coordinateDictionary[latitudeKey] { 42 | return Coordinate(longitude : unwrappedLongitude, latitude : unwrappedLatitude) 43 | } 44 | } 45 | } 46 | 47 | return nil 48 | } 49 | } 50 | ``` 51 | 52 | Now that we have created a transformeer, let's create some mapping for our business Object: 53 | 54 | **Business.plist** 55 |
56 | 57 | ![alt tag](/documentation/readme_assets/struct_example_plist.png?raw=true) 58 |
59 | 60 | After the creation of the mapping, perform a build **(⌘-B)**. The changes should be reflected accordingly in the internal `_Business.swift` class. 61 | 62 | 63 | ``` 64 | import Foundation 65 | import US2MapperKit 66 | 67 | class _Business { 68 | var uuid : Double? 69 | var name : String? 70 | var coordinates : Coordinates? 71 | 72 | required init() {...} 73 | 74 | convenience init?(_ dictionary: Dictionary) {...} 75 | } 76 | ``` 77 | 78 | After calling the fail-able initializer - or udpateWithDictionary method with a dictioanry representation - US2MapperKit will use the custom transformer to map the struct accordingly. 79 | 80 | Note: The the keys defined in the property mapping correspond to the keys in the dictionary of values passed to the ` public func transformValues(inputValues : Dictionary?) -> Any?` method defined by the protocol. 81 | -------------------------------------------------------------------------------- /Source/US2MapperKit/Parsers/CollectionParser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionParser.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton Doudarev on 7/17/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | final class CollectionParser { 12 | 13 | // MARK Determines the type of representation to be mapped to an Array 14 | 15 | class func arrayRepresentation(fromValue data : AnyObject, ofType collectionSubType : String?, using instantiator : US2InstantiatorProtocol) -> [AnyObject] { 16 | 17 | if nativeDataTypes.containsValue(collectionSubType!) { 18 | if let unwrappedData = data as? Dictionary { 19 | return NativeValueArrayParser.arrayRepresentation(collectionSubType, data : unwrappedData, instantiator : instantiator) 20 | } else if let unwrappedData = data as? [AnyObject] { 21 | return NativeValueArrayParser.arrayRepresentation(collectionSubType, data : unwrappedData, instantiator : instantiator) 22 | } 23 | } 24 | 25 | if let unwrappedData = data as? Dictionary> { 26 | return ComplexValueArrayParser.arrayRepresentation(collectionSubType, data : unwrappedData, instantiator: instantiator) 27 | } else if let unwrappedData = data as? [Dictionary] { 28 | return ComplexValueArrayParser.arrayRepresentation(collectionSubType, data : unwrappedData, instantiator: instantiator) 29 | } 30 | 31 | return [] 32 | } 33 | 34 | // MARK Determines the type of representation to be mapped to a Dictionary 35 | 36 | class func dictionaryRepresentation(fromValue data : AnyObject, ofType collectionSubType : String?, using instantiator : US2InstantiatorProtocol) -> Dictionary { 37 | 38 | if nativeDataTypes.containsValue(collectionSubType!) { 39 | if let unwrappedData = data as? Dictionary { 40 | return NativeValueDictionaryParser.dictionaryRepresentation(collectionSubType, data : unwrappedData, instantiator: instantiator) 41 | } else if let unwrappedData = data as? [AnyObject] { 42 | return NativeValueDictionaryParser.dictionaryRepresentation(collectionSubType, data : unwrappedData, instantiator: instantiator) 43 | } 44 | } 45 | 46 | if let unwrappedData = data as? Dictionary> { 47 | return ComplexValueDictionaryParser.dictionaryRepresentation(collectionSubType, data: unwrappedData, instantiator: instantiator) 48 | } else if let unwrappedData = data as? Dictionary { 49 | return ComplexValueDictionaryParser.dictionaryRepresentation(collectionSubType, data : unwrappedData, instantiator: instantiator) 50 | } else if let unwrappedData = data as? [Dictionary] { 51 | return ComplexValueDictionaryParser.dictionaryRepresentation(collectionSubType, data : unwrappedData, instantiator: instantiator) 52 | } 53 | 54 | return [:] 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /documentation/custom_transforms_enums.md: -------------------------------------------------------------------------------- 1 | ##Example - Enums Transformations 2 | 3 | As of version 0.2.0 of U2MapperKit, the ability to map enums via the `US2TransformerProtocol` as support was added. This ensures that we can return an a value of `Any` type. Let's look at a dictionary for a business object, and see how we can map an enum to represent the type business: 4 | 5 | **Response Dictionary** 6 | 7 | ``` 8 | { 9 | 'business_uuid' : 9223123456754775807, 10 | 'business_name' : 'UsTwo Restaurant', 11 | 'business_type' : 'Lounge' 12 | } 13 | ``` 14 | 15 | Unlike the model objects, US2MapperKit does not autogenerate enums, due to the fact they would be uncustomizable. This would prevent the developer from using the many features Swift offers with enums. For the purposes of the example, let's assume that a business_type key value parsed can be 'Lounge', 'Dinner', and 'Coffee Shop'. First, create an enum to represent the business type for our custom Business Object: 16 | 17 | **Enum Definition** 18 | 19 | ``` 20 | enum BusinessType : Int { 21 | case Unknown = 0, Lounge, Dinner, CoffeeShop 22 | } 23 | ``` 24 | 25 | Once we have defined a BusinessType enum, create a mapper that parses out the values from the response and return the BusinessType type enum value. 26 | 27 | **US2ExampleCoordinateTransformer Implementation** 28 | 29 | ``` 30 | let businessTypeKey = "business_type" 31 | 32 | public class US2ExampleBusinessTypeTransformer : US2TransformerProtocol { 33 | public func transformValues(inputValues : Dictionary?) -> Any? { 34 | 35 | if let typeValue = inputValues![businessTypeKey] as? String { 36 | switch typeValue { 37 | case "Lounge": 38 | return BusinessType.Lounge 39 | case "Dinner": 40 | return BusinessType.Dinner 41 | case "CoffeeShop": 42 | return BusinessType.CoffeeShop 43 | default: 44 | return BusinessType.Unknown 45 | } 46 | } 47 | return nil 48 | } 49 | } 50 | ``` 51 | 52 | Now that we have created a transformeer let's create some mapping for our business Object: 53 | 54 | **Business.plist** 55 |
56 | 57 | ![alt tag](/documentation/readme_assets/enum_example_plist.png?raw=true) 58 |
59 | 60 | After the creation of the mapping, perform a build **(⌘-B)**. The changes should be reflected accordingly in the internal `_Business.swift` class. 61 | 62 | 63 | ``` 64 | import Foundation 65 | import US2MapperKit 66 | 67 | class _Business { 68 | var uuid : Double? 69 | var name : String? 70 | var businessType : BusinessType? 71 | 72 | required init() {...} 73 | 74 | convenience init?(_ dictionary: Dictionary) {...} 75 | } 76 | 77 | ``` 78 | After calling the fail-able initializer - or udpateWithDictionary method with a dictionary representation - US2MapperKit will use the custom transformer to map the enumerator accordingly. 79 | 80 | 81 | Note: The the keys defined in the property mapping correspond to the keys in the dictionary of values passed to the ` public func transformValues(inputValues : Dictionary?) -> Any?` method defined by the protocol. 82 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/US2Instantiator.swift: -------------------------------------------------------------------------------- 1 | // US2MapperKit Generated Model 2 | // UPDATE LISCENSE HERE 3 | 4 | import Foundation 5 | 6 | enum US2MapperClassEnum: String { 7 | case _TestObjectEight = "TestObjectEight" 8 | case _TestObjectEleven = "TestObjectEleven" 9 | case _TestObjectFive = "TestObjectFive" 10 | case _TestObjectFour = "TestObjectFour" 11 | case _TestObjectNine = "TestObjectNine" 12 | case _TestObjectSeven = "TestObjectSeven" 13 | case _TestObjectSix = "TestObjectSix" 14 | case _TestObjectTen = "TestObjectTen" 15 | case _TestObjectThirteen = "TestObjectThirteen" 16 | case _TestObjectThree = "TestObjectThree" 17 | case _TestObjectTwelve = "TestObjectTwelve" 18 | case _TestObjectTwo = "TestObjectTwo" 19 | case _None = "None" 20 | 21 | func createObject(data : Dictionary) -> AnyObject? { 22 | switch self { 23 | case ._TestObjectEight: 24 | return TestObjectEight(data) 25 | case ._TestObjectEleven: 26 | return TestObjectEleven(data) 27 | case ._TestObjectFive: 28 | return TestObjectFive(data) 29 | case ._TestObjectFour: 30 | return TestObjectFour(data) 31 | case ._TestObjectNine: 32 | return TestObjectNine(data) 33 | case ._TestObjectSeven: 34 | return TestObjectSeven(data) 35 | case ._TestObjectSix: 36 | return TestObjectSix(data) 37 | case ._TestObjectTen: 38 | return TestObjectTen(data) 39 | case ._TestObjectThirteen: 40 | return TestObjectThirteen(data) 41 | case ._TestObjectThree: 42 | return TestObjectThree(data) 43 | case ._TestObjectTwelve: 44 | return TestObjectTwelve(data) 45 | case ._TestObjectTwo: 46 | return TestObjectTwo(data) 47 | case ._None: 48 | return nil 49 | } 50 | } 51 | } 52 | 53 | enum US2TransformerEnum: String { 54 | case _US2CompoundValueTransformer = "US2CompoundValueTransformer" 55 | case _US2ExampleStructTransformer = "US2ExampleStructTransformer" 56 | case _US2ExampleTupleTransformer = "US2ExampleTupleTransformer" 57 | case _US2ExampleClosureTransformer = "US2ExampleClosureTransformer" 58 | case _US2ExampleEnumTransformer = "US2ExampleEnumTransformer" 59 | case _None = "None" 60 | 61 | func transformer() -> US2TransformerProtocol? { 62 | switch self { 63 | case ._US2CompoundValueTransformer: 64 | return US2CompoundValueTransformer() 65 | 66 | case ._US2ExampleStructTransformer: 67 | return US2ExampleStructTransformer() 68 | 69 | case ._US2ExampleTupleTransformer: 70 | return US2ExampleTupleTransformer() 71 | 72 | case ._US2ExampleClosureTransformer: 73 | return US2ExampleClosureTransformer() 74 | 75 | case ._US2ExampleEnumTransformer: 76 | return US2ExampleEnumTransformer() 77 | 78 | case ._None: 79 | return nil } 80 | } 81 | } 82 | 83 | class US2Instantiator : US2InstantiatorProtocol { 84 | 85 | static let sharedInstance : US2Instantiator = US2Instantiator() 86 | 87 | func newInstance(ofType classname : String, withValue data : Dictionary) -> AnyObject? { 88 | return US2MapperClassEnum(rawValue: classname)?.createObject(data) 89 | } 90 | 91 | func transformerFromString(classString: String) -> US2TransformerProtocol? { 92 | return US2TransformerEnum(rawValue: classString)!.transformer() 93 | } 94 | } -------------------------------------------------------------------------------- /documentation/custom_transforms.md: -------------------------------------------------------------------------------- 1 | ##Example - Custom Transformations 2 | 3 | To perform transformations of a single or multiple values, US2MapperKit provides the ability to map multiple values from a dictionary response, and process them using the `US2TransformerProtocol`. Currently all transformed output properties must be optional, and the script will error out with a description in the build log. 4 | 5 | ``` 6 | public protocol US2TransformerProtocol { 7 | func transformValues(inputValues : Dictionary?) -> Any? 8 | } 9 | ``` 10 | 11 | Transformations are great approach, especially for Date transforms by reusing the NSDateFormatter - and possibly creating attributed strings by reusing NSMutableParagraphStyles. Let's observe a response with a simple user object. 12 | 13 | **Response Dictionary** 14 | 15 | ``` 16 | { 17 | "user_id" : 9223123456754776000, 18 | "first_name" : "John", 19 | "last_name" : "Doe" 20 | } 21 | ``` 22 | 23 | Assuming the need to store the user's full name as a single property, the transformer implementation below takes in a user's first name and last name as a parsed dictionary of strings keyed according to the property mapping defined and transforms them into a single full name property value before being returned and assigned. 24 | 25 | 26 | **US2TransformerProtocol Implementation** 27 | 28 | ``` 29 | let firstNameKey = "first_name" 30 | let lastNameKey = "last_name" 31 | 32 | public class US2FullNameValueTransformer : US2TransformerProtocol { 33 | 34 | public func transformValues(inputValues : Dictionary?) -> Any? { 35 | var fullNameString : String = "" 36 | 37 | if let componentDictionary = inputValues as? Dictionary { 38 | 39 | if let firstName = componentDictionary[firstNameKey] { 40 | fullNameString += firstName 41 | } 42 | 43 | if fullNameString.isEmpty == false { fullNameString += " " } 44 | 45 | if let lastName = componentDictionary[lastNameKey] { 46 | fullNameString += lastName 47 | } 48 | } 49 | 50 | if fullNameString.isEmpty { return nil } 51 | 52 | return fullNameString 53 | } 54 | } 55 | ``` 56 | 57 | To implement the transformer as part of the model mapping, observe how the **key** property in the mapping has become an array and takes in multiple values to transform into a fullName property. To use the custom transformer created above, add the **transformer** key to the property mapping defining which trasnformer class to use. 58 | 59 | **User.plist** 60 |
61 | 62 | ![alt tag](/documentation/readme_assets/transformer_fullname_example.png?raw=true) 63 |
64 | 65 | Note: The the keys defined in the property mapping correspond to the keys in the dictionary of values passed to the ` public func transformValues(inputValues : Dictionary?) -> Any?` method defined by the protocol. 66 | 67 | 68 | ###Compound Value Transformer 69 | 70 | Currently the only packaged trasnformer shipped with the framework is the `US2CompoundValueTransformer` which takes in a dictionary of values per `US2TransformerProtocol`, and creates a compound output value from the values passed into it. 71 | 72 | There is potential for more transformers to be added in future releases. 73 | -------------------------------------------------------------------------------- /documentation/custom_transforms_closures.md: -------------------------------------------------------------------------------- 1 | ##Example - Closure Transformations 2 | 3 | As of version 0.2.0 of U2MapperKit, the ability to map closures via the `US2TransformerProtocol` as support was added. This ensures that we can return an a value of `Any` type. Let's look at a dictionary for a business object, and see how we can map a function/closure. 4 | 5 | **Response Dictionary** 6 | 7 | ``` 8 | { 9 | 'business_uuid' : 9223123456754775807, 10 | 'business_name' : 'UsTwo Restaurant', 11 | 'business_facebook_id' : '123456789323123', 12 | 'business_yelp_id' : '409283409238409', 13 | } 14 | ``` 15 | Let's create a mapper that parses out the values from the response which, based on the identifier, returns the clousure: 16 | 17 | **US2ExampleSocialClosureTransformer Implementation** 18 | 19 | ``` 20 | import Foundation 21 | import UIKit 22 | 23 | let facebookIDKey = "facebook_id" 24 | let yelpIDKey = "yelp_id" 25 | 26 | public class US2ExampleSocialClosureTransformer : US2TransformerProtocol { 27 | 28 | public func transformValues(inputValues : Dictionary?) -> Any? { 29 | if let facebookdentifier = inputValues![facebookIDKey] as? String { 30 | func routeToFacebookApp() { 31 | if UIApplication.sharedApplication().openURL(NSURL(string:"fb://")!) { 32 | let facebookAppLink = "fb://profile/\(facebookdentifier)" 33 | UIApplication.sharedApplication().openURL(NSURL(string: facebookAppLink)!) 34 | } else { 35 | let itunesLink = "itms://itunes.apple.com/us/app/apple-store/id284882215?mt=8" 36 | UIApplication.sharedApplication().openURL(NSURL(string: itunesLink)!) 37 | } 38 | } 39 | return routeToFacebookApp 40 | } 41 | 42 | if let yelpIdentifier = inputValues![yelpIDKey] as? String { 43 | 44 | func routeToFacebookApp() { 45 | if UIApplication.sharedApplication().openURL(NSURL(string:"yelp://")!) { 46 | let yelpAppLink = "yelp:///biz/\(yelpIdentifier)" 47 | UIApplication.sharedApplication().openURL(NSURL(string:yelpAppLink)!) 48 | } else { 49 | let itunesLink = "itms://itunes.apple.com/us/app/apple-store/id284910350?mt=8" 50 | UIApplication.sharedApplication().openURL(NSURL(string: itunesLink)!) 51 | } 52 | } 53 | 54 | return routeToYelpApp 55 | } 56 | return nil 57 | } 58 | } 59 | 60 | ``` 61 | 62 | Now that we have created a transformer, let's create some mapping to map our closures to an isntance variable. 63 | 64 | **Business.plist** 65 |
66 | 67 | ![alt tag](/documentation/readme_assets/closure_example.png?raw=true) 68 |
69 | 70 | After the creation of the mapping, perform a build **(⌘-B)**. The changes should be reflected accordingly in the internal `_Business.swift` class. 71 | 72 | 73 | ``` 74 | import Foundation 75 | import US2MapperKit 76 | 77 | class _Business { 78 | var uuid : Double? 79 | var name : String? 80 | var routeToFacebook : (() -> Void)? 81 | var routeToYelp : (() -> Void)? 82 | 83 | required init() {...} 84 | 85 | convenience init?(_ dictionary: Dictionary) {...} 86 | } 87 | ``` 88 | 89 | After calling the fail-able initializer - or udpateWithDictionary method with a dictioanry representation - US2MapperKit will use the custom transformer to map the custom closure accordingly. Although this is a simple and abstract scenerio, the potential for this funtionality has many outcomes to be explored. 90 | 91 | Note: The the keys defined in the property mapping correspond to the keys in the dictionary of values passed to the ` public func transformValues(inputValues : Dictionary?) -> Any?` method defined by the protocol. 92 | -------------------------------------------------------------------------------- /documentation/optional_value_types.md: -------------------------------------------------------------------------------- 1 | ##Example - Optional Value Types 2 | 3 | US2MapperKit supports mapping basic data types including `String`, `Int`, `Double`, `Float` and `Bool`. Let's look at a simple example for mapping basic datatypes for a `Dictionary` response for a basic business case 4 | 5 | **Response Dictionary** 6 | 7 | ``` 8 | { 9 | 'business_uuid' : 9223123456754775807, 10 | 'business_name' : 'UsTwo Restaurant', 11 | 'business_rating' : 5, 12 | 'business_longitude' : 40.7053319, 13 | 'business_latitude' : -74.0129945, 14 | 'business_open' : 1 15 | } 16 | ``` 17 | 18 | After receiving the data dictionary, the next step is to model the response into a class and map it accordingly. Unlike other mapping frameworks, where the developer needs to model the object first prior to mapping the response, US2MapperKit takes care of generating the model by creating a plist mapping for a given model object. Let's go ahead and create a mapping for our `Business` model object, and add it to the mapping folder configured during installation. 19 | 20 | 21 | **Business.plist** 22 |
23 | 24 | ![alt tag](/documentation/readme_assets/basic data_types_business.png?raw=true) 25 |
26 | For each property that US2MapperKit will generate in the final model object, define a dictionary within the plist to represent that property. For each property, at minimum, we must define a **key** and a **type** entry. The **key** maps to the value of the response dictionary, and **type** defines the Swift datatype for that property. 27 | 28 | Now that the Model Mapping is defined and within our configured mapping folder, perform a build **(⌘-B)**. Next, navigate to the configured model output folder, and add the generated files to the project. NOTE: This only has to be done once, unless the name of the Model object changes. As a developer, one should not have to add the created files again, and they should change accordingly when the build script is run. 29 | 30 | From this example we'll find there has been created an internal `_Business.swift` file, an external `Business.swift` class that extends from the latter, and a `US2Instantiator.swift`. Lets take a take a high-level look at the output. 31 | 32 | 33 | **_Business.swift** 34 |
35 | 36 | ``` 37 | import Foundation 38 | import US2MapperKit 39 | 40 | class _Business { 41 | 42 | var rating : Int? 43 | var uuid : Double? 44 | var longitude : Float? 45 | var latitude : Float? 46 | var open : Bool? 47 | var name : String? 48 | 49 | required init() {...} 50 | 51 | convenience init?(_ dictionary: Dictionary) {...} 52 | } 53 | ``` 54 | 55 | The internal file is where all the magic happens. At a high level, it provides a required initializer, and a [Fail-able Initializer](https://developer.apple.com/swift/blog/?id=17) which takes in a `Dictionary` to be parsed. In the case that the parsing fails, the fail-able initializer will return nil. In the case where all of the properties are optional, and there are missing values in the response, the fail-able initializer will return an instance with the missing values accordingly. 56 | 57 | **Business.swift** 58 |
59 | 60 | ``` 61 | import Foundation 62 | 63 | class Business : _Business { 64 | // Add Custom Logic Here 65 | } 66 | ``` 67 | 68 | The external file is for custom logic, and is only generated once, and will go unchanged if there is an update to the mapping. As a developer, one can add properties, methods, and implement any protocol as needed. The internal class is only there to hold reference to the values from the response dictionary is is being passed. 69 | 70 | ###Default Values 71 | To assign a default value definition for an optional property, follow the example found in the [Default Value Definitions](/documentation/default_values.md) section of this documentation. 72 | -------------------------------------------------------------------------------- /Source/US2MapperKit/Parsers/Parser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Parser.swift 3 | // US2MapperKit 4 | // 5 | // Created by Anton Doudarev on 7/17/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | class Parser { 12 | 13 | final class func retrieveValue(from dictionary : Dictionary, applying propertyMapping : Dictionary, employing instantiator : US2InstantiatorProtocol, defaultsEnabled : Bool) -> Any? { 14 | 15 | if propertyMapping[US2MapperTransformerKey] != nil { 16 | return Transformer.transformedValue(from: dictionary, applying : propertyMapping, employing : instantiator) 17 | } 18 | 19 | if let jsonKey = propertyMapping[US2MapperJSONKey] as? String { 20 | if let dataType = propertyMapping[US2MapperTypeKey] as? String { 21 | 22 | let subType = propertyMapping[US2MapperCollectionSubTypeKey] as? String 23 | 24 | if let retrievedValue: AnyObject = dictionaryValueForKey(jsonKey, dictionary: dictionary) { 25 | return parsedValue(forValue : retrievedValue, dataType, subType, instantiator : instantiator) 26 | } else if let retrievedDefaultValue: AnyObject = propertyMapping[US2MapperDefaultKey] { 27 | 28 | if defaultsEnabled { 29 | return parsedValue(forValue : retrievedDefaultValue, dataType, subType, instantiator : instantiator) 30 | } else { 31 | return nil 32 | } 33 | } 34 | } 35 | } 36 | 37 | return nil 38 | } 39 | 40 | final class func parsedValue(forValue value : AnyObject, _ dataType : String, _ subType: String?, instantiator : US2InstantiatorProtocol) -> AnyObject? { 41 | 42 | if nativeDataTypes.containsValue(dataType) { 43 | 44 | return NativeTypeParser.nativeRepresentation(fromValue : value, asType : dataType) 45 | 46 | } else if collectionTypes.containsValue(dataType) { 47 | 48 | switch dataType { 49 | case US2DataTypeArray: 50 | return CollectionParser.arrayRepresentation(fromValue : value, ofType : subType, using : instantiator) 51 | case US2DataTypeDictionary: 52 | return CollectionParser.dictionaryRepresentation(fromValue : value, ofType : subType, using : instantiator) 53 | default: 54 | if let unwrappedValue = value as? Dictionary { 55 | return ComplexTypeParser.complexObject(fromValue: unwrappedValue, ofType: subType, using : instantiator) 56 | } 57 | } 58 | } else { 59 | return instantiator.newInstance(ofType: dataType, withValue: value as! Dictionary) 60 | } 61 | 62 | return nil 63 | } 64 | 65 | final class func dictionaryValueForKey(key : String, dictionary : Dictionary) -> AnyObject? { 66 | var keys = key.componentsSeparatedByString(".") 67 | var nestedDictionary = dictionary 68 | 69 | for var x = 0; x < keys.count; x++ { 70 | if x >= (keys.count - 1) { 71 | if let finalValue: AnyObject = nestedDictionary[keys[x]] { 72 | return finalValue 73 | } else { 74 | break 75 | } 76 | } else if let nextLevelDictionary = nestedDictionary[keys[x]] as? Dictionary { 77 | nestedDictionary = nextLevelDictionary 78 | } else { 79 | break 80 | } 81 | } 82 | return nil 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Source/US2MapperKit/US2Mapper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // US2Mapper.swift 3 | // US2Mapper 4 | // 5 | // Created by Anton Doudarev on 6/22/15. 6 | // Copyright © 2015 Ustwo. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public protocol US2InstantiatorProtocol { 12 | func newInstance(ofType classname : String, withValue data : Dictionary) -> AnyObject? 13 | func transformerFromString(classString: String) -> US2TransformerProtocol? 14 | } 15 | 16 | public protocol US2TransformerProtocol { 17 | func transformValues(inputValues : Dictionary?) -> Any? 18 | } 19 | 20 | public func typeCast(object: Any?) -> U? { 21 | if let typed = object as? U { 22 | return typed 23 | } 24 | return nil 25 | } 26 | 27 | extension Array { 28 | func containsValue(obj: T) -> Bool { 29 | return self.filter({$0 as? T == obj}).count > 0 30 | } 31 | } 32 | 33 | var propertyMappings : Dictionary>> = Dictionary() 34 | 35 | let US2MapperJSONKey = "key" 36 | let US2MapperTypeKey = "type" 37 | let US2MapperNonOptionalKey = "nonoptional" 38 | let US2MapperDefaultKey = "default" 39 | let US2MapperTransformerKey = "transformer" 40 | let US2MapperCollectionSubTypeKey = "collection_subtype" 41 | 42 | let US2DataTypeString = "String" 43 | let US2DataTypeInt = "Int" 44 | let US2DataTypeDouble = "Double" 45 | let US2DataTypeFloat = "Float" 46 | let US2DataTypeBool = "Bool" 47 | let US2DataTypeArray = "Array" 48 | let US2DataTypeDictionary = "Dictionary" 49 | 50 | let nativeDataTypes = [US2DataTypeString, US2DataTypeInt, US2DataTypeDouble, US2DataTypeFloat, US2DataTypeBool] 51 | let collectionTypes = [US2DataTypeArray, US2DataTypeDictionary] 52 | 53 | final public class US2Mapper { 54 | 55 | public class func mapValues(from dictionary : Dictionary, forType classType : String , employing instantiator : US2InstantiatorProtocol, defaultsEnabled : Bool) -> Dictionary? { 56 | 57 | if let mappingConfiguration = retrieveMappingConfiguration(classType) { 58 | 59 | // Dictionary to store parsed values to be returned 60 | var retrievedValueDictionary = Dictionary() 61 | 62 | for (propertyKey, propertyMapping) in mappingConfiguration { 63 | retrievedValueDictionary[propertyKey] = Parser.retrieveValue(from : dictionary, applying : propertyMapping, employing : instantiator, defaultsEnabled : defaultsEnabled) 64 | } 65 | 66 | if defaultsEnabled == false { 67 | return retrievedValueDictionary 68 | } 69 | 70 | if Validator.validateResponse(forValues: retrievedValueDictionary, mappedTo : mappingConfiguration, forType : classType, withData : dictionary) { 71 | return retrievedValueDictionary 72 | } 73 | } 74 | 75 | return nil 76 | } 77 | 78 | class func retrieveMappingConfiguration(className : String) -> Dictionary>? { 79 | if let mappingconfiguration = propertyMappings[className] { 80 | return mappingconfiguration 81 | } else { 82 | if let mappingPath = NSBundle(forClass: self).pathForResource(className, ofType: "plist") { 83 | let tempMapping = NSDictionary(contentsOfFile: mappingPath) as? Dictionary> 84 | 85 | if tempMapping!.isEmpty { return nil } 86 | 87 | propertyMappings[className] = tempMapping 88 | return tempMapping! 89 | } else { 90 | return nil 91 | } 92 | } 93 | } 94 | } 95 | 96 | -------------------------------------------------------------------------------- /documentation/installation.md: -------------------------------------------------------------------------------- 1 | ##US2MapperKit - Installation 2 | 3 | ####Manual Install 4 | 5 | 1. Clone the [US2MapperKit](git@github.com:ustwo/US2MapperKit.git) repository 6 | 2. Add the contents of the Source Directory to the project 7 | 3. In the Project's Root Folder create a new folder that will contain all the mapping plist files 8 | 4. In the application targets’ “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase”. Create a Run Script with the following content: 9 | 10 | ``` 11 | SCRIPT_LOCATION=$(find ${PODS_ROOT} -name modelgen-swift.py | head -n 1) 12 | python $SCRIPT_LOCATION -v 0.1 -i $PROJECT_DIR/$PROJECT_NAME/Mappings/ -o $PROJECT_DIR/$PROJECT_NAME/Model/ 13 | 14 | ``` 15 | 16 | 4. Move the newly created Run Script phase to the second listing right below the "Target Dependencies" task 17 | 18 | 19 | ####CocoaPods 20 | 21 | 1. Edit the project's podfile 22 | 23 | ``` 24 | pod 'US2MapperKit', :git => 'https://github.com/ustwo/US2MapperKit.git' 25 | ``` 26 | 2. Install US2MapperKit by running 27 | 28 | ``` 29 | pod install 30 | ``` 31 | 3. In the Project's Root Folder create a new folder that will contain all the mapping plist files 32 | 4. Navigate to the application targets’ “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase”. Create a Run Script with the following contents: 33 | 34 | NOTE: The script below differs for installation via Carthage 35 | 36 | ``` 37 | SCRIPT_LOCATION=$(find ${PODS_ROOT} -name modelgen-swift.py | head -n 1) 38 | python $SCRIPT_LOCATION -v 0.1 -i $PROJECT_DIR/$PROJECT_NAME/Mappings/ -o $PROJECT_DIR/$PROJECT_NAME/Model/ 39 | ``` 40 | 5. Move the newly created Run Script phase to the second listing right below the "Target Dependencies" task 41 | 42 | 43 | ####Carthage 44 | 45 | The installation instruction below are a for OSX and iOS, follow the extra steps documented when installing for iOS. 46 | 47 | #####Installation 48 | 49 | 1. Create/Update the Cartfile with with the following 50 | 51 | ``` 52 | #US2MapperKit 53 | git "https://github.com/ustwo/US2MapperKit.git" 54 | ``` 55 | 2. Run `carthage update`. This will fetch dependencies into a [Carthage/Checkouts][] folder, then build each one. 56 | 3. In the application targets’ “General” settings tab, in the “Embedded Binaries” section, drag and drop each framework for use from the Carthage/Build folder on disk. 57 | 3. In the project's root folder create a new folder that will contain all the mapping plist files 58 | 4. Navigate to the application targets’ “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase”. Create a Run Script with the following contents: 59 | 60 | NOTE: The script below differs for installation via Cocoapods 61 | 62 | ``` 63 | SCRIPT_LOCATION=$(find $SRCROOT -name modelgen-swift.py | head -n 1) 64 | python $SCRIPT_LOCATION -v 0.1 -i $PROJECT_DIR/$PROJECT_NAME/Mapping/ -o $PROJECT_DIR/$PROJECT_NAME/Model/ 65 | ``` 66 | 5. Move the newly created Run Script phase to the second listing right below the "Target Dependencies" task 67 | 68 | 69 | #####iOS Installation 70 | 71 | 1. Follow the installation instruction above. Once complete, perform the following steps 72 | (If you have setup a carthage build task for iOS already skip to Step 5) 73 | 2. Navigate to the targets’ “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase”. Create a Run Script with the following content: 74 | 75 | ``` 76 | /usr/local/bin/carthage copy-frameworks 77 | ``` 78 | 79 | 3. Add the paths to the frameworks you want to use under “Input Files” within the carthage build phase as follows e.g.: 80 | 81 | ``` 82 | $(SRCROOT)/Carthage/Build/iOS/US2MapperKit.framework 83 | 84 | ``` 85 | 86 | 87 | ####Script Reference 88 | 89 | The model-building script generates a model for part of a build task within the project. Below is a reference for the input parameters. 90 | 91 | ``` 92 | Parameter Description: 93 | -v defines the version (currently 0.1) 94 | -i defines the location where the plist mappings are stored (`$PROJECT_DIR/$PROJECT_NAME/Mappings`) 95 | -o defines the output directory for the model objects (`$PROJECT_DIR/$PROJECT_NAME/Model`) 96 | ``` 97 | -------------------------------------------------------------------------------- /US2MapperKit/US2MapperKit/US2MapperKit.xcodeproj/xcshareddata/xcschemes/US2MapperKit - OSX.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /US2MapperKit/US2MapperKit/US2MapperKit.xcodeproj/xcshareddata/xcschemes/US2MapperKit - iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 100 | 101 | 102 | 103 | 105 | 106 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectFour.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectFour { 5 | 6 | var optionalInt : Int? 7 | var optionalBool : Bool? 8 | var optionalString : String? 9 | var optionalDouble : Double? 10 | var optionalFloat : Float? 11 | 12 | var non_optionalDouble : Double 13 | var non_optionalFloat : Float 14 | var non_optionalInt : Int 15 | var non_optionalBool : Bool 16 | var non_optionalString : String 17 | 18 | required init(_non_optionalDouble : Double, 19 | _non_optionalFloat : Float, 20 | _non_optionalInt : Int, 21 | _non_optionalBool : Bool, 22 | _non_optionalString : String) { 23 | 24 | non_optionalDouble = _non_optionalDouble 25 | non_optionalFloat = _non_optionalFloat 26 | non_optionalInt = _non_optionalInt 27 | non_optionalBool = _non_optionalBool 28 | non_optionalString = _non_optionalString 29 | } 30 | 31 | convenience init?(_ dictionary: Dictionary) { 32 | 33 | let dynamicTypeString = "\(self.dynamicType)" 34 | let className = dynamicTypeString.componentsSeparatedByString(".").last 35 | 36 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 37 | 38 | let temp_non_optionalDouble : Double = typeCast(valuesDict["non_optionalDouble"])! 39 | let temp_non_optionalFloat : Float = typeCast(valuesDict["non_optionalFloat"])! 40 | let temp_non_optionalInt : Int = typeCast(valuesDict["non_optionalInt"])! 41 | let temp_non_optionalBool : Bool = typeCast(valuesDict["non_optionalBool"])! 42 | let temp_non_optionalString : String = typeCast(valuesDict["non_optionalString"])! 43 | 44 | self.init(_non_optionalDouble : temp_non_optionalDouble, 45 | _non_optionalFloat : temp_non_optionalFloat, 46 | _non_optionalInt : temp_non_optionalInt, 47 | _non_optionalBool : temp_non_optionalBool, 48 | _non_optionalString : temp_non_optionalString) 49 | 50 | if let unwrapped_optionalInt : Any = valuesDict["optionalInt"] { 51 | optionalInt = typeCast(unwrapped_optionalInt) 52 | } 53 | 54 | if let unwrapped_optionalBool : Any = valuesDict["optionalBool"] { 55 | optionalBool = typeCast(unwrapped_optionalBool) 56 | } 57 | 58 | if let unwrapped_optionalString : Any = valuesDict["optionalString"] { 59 | optionalString = typeCast(unwrapped_optionalString) 60 | } 61 | 62 | if let unwrapped_optionalDouble : Any = valuesDict["optionalDouble"] { 63 | optionalDouble = typeCast(unwrapped_optionalDouble) 64 | } 65 | 66 | if let unwrapped_optionalFloat : Any = valuesDict["optionalFloat"] { 67 | optionalFloat = typeCast(unwrapped_optionalFloat) 68 | } 69 | 70 | } else { 71 | self.init(_non_optionalDouble : Double(), 72 | _non_optionalFloat : Float(), 73 | _non_optionalInt : Int(), 74 | _non_optionalBool : Bool(), 75 | _non_optionalString : String()) 76 | 77 | return nil 78 | } 79 | } 80 | 81 | func updateWithDictionary(dictionary: Dictionary) { 82 | 83 | let dynamicTypeString = "\(self.dynamicType)" 84 | let className = dynamicTypeString.componentsSeparatedByString(".").last 85 | 86 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { 87 | if let unwrapped_non_optionalDouble : Any = valuesDict["non_optionalDouble"] { 88 | non_optionalDouble = typeCast(unwrapped_non_optionalDouble)! 89 | } 90 | 91 | if let unwrapped_optionalInt : Any = valuesDict["optionalInt"] { 92 | optionalInt = typeCast(unwrapped_optionalInt) 93 | } 94 | 95 | if let unwrapped_non_optionalFloat : Any = valuesDict["non_optionalFloat"] { 96 | non_optionalFloat = typeCast(unwrapped_non_optionalFloat)! 97 | } 98 | 99 | if let unwrapped_non_optionalInt : Any = valuesDict["non_optionalInt"] { 100 | non_optionalInt = typeCast(unwrapped_non_optionalInt)! 101 | } 102 | 103 | if let unwrapped_optionalBool : Any = valuesDict["optionalBool"] { 104 | optionalBool = typeCast(unwrapped_optionalBool) 105 | } 106 | 107 | if let unwrapped_optionalString : Any = valuesDict["optionalString"] { 108 | optionalString = typeCast(unwrapped_optionalString) 109 | } 110 | 111 | if let unwrapped_optionalDouble : Any = valuesDict["optionalDouble"] { 112 | optionalDouble = typeCast(unwrapped_optionalDouble) 113 | } 114 | 115 | if let unwrapped_optionalFloat : Any = valuesDict["optionalFloat"] { 116 | optionalFloat = typeCast(unwrapped_optionalFloat) 117 | } 118 | 119 | if let unwrapped_non_optionalBool : Any = valuesDict["non_optionalBool"] { 120 | non_optionalBool = typeCast(unwrapped_non_optionalBool)! 121 | } 122 | 123 | if let unwrapped_non_optionalString : Any = valuesDict["non_optionalString"] { 124 | non_optionalString = typeCast(unwrapped_non_optionalString)! 125 | } 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectEleven.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectEleven { 5 | 6 | var optionalInt : Int? 7 | var optionalBool : Bool? 8 | var optionalString : String? 9 | var optionalDouble : Double? 10 | var optionalFloat : Float? 11 | 12 | var non_optionalDouble : Double 13 | var non_optionalFloat : Float 14 | var non_optionalInt : Int 15 | var non_optionalBool : Bool 16 | var non_optionalString : String 17 | 18 | required init(_non_optionalDouble : Double, 19 | _non_optionalFloat : Float, 20 | _non_optionalInt : Int, 21 | _non_optionalBool : Bool, 22 | _non_optionalString : String) { 23 | 24 | non_optionalDouble = _non_optionalDouble 25 | non_optionalFloat = _non_optionalFloat 26 | non_optionalInt = _non_optionalInt 27 | non_optionalBool = _non_optionalBool 28 | non_optionalString = _non_optionalString 29 | } 30 | 31 | convenience init?(_ dictionary: Dictionary) { 32 | 33 | let dynamicTypeString = "\(self.dynamicType)" 34 | let className = dynamicTypeString.componentsSeparatedByString(".").last 35 | 36 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 37 | 38 | let temp_non_optionalDouble : Double = typeCast(valuesDict["non_optionalDouble"])! 39 | let temp_non_optionalFloat : Float = typeCast(valuesDict["non_optionalFloat"])! 40 | let temp_non_optionalInt : Int = typeCast(valuesDict["non_optionalInt"])! 41 | let temp_non_optionalBool : Bool = typeCast(valuesDict["non_optionalBool"])! 42 | let temp_non_optionalString : String = typeCast(valuesDict["non_optionalString"])! 43 | 44 | self.init(_non_optionalDouble : temp_non_optionalDouble, 45 | _non_optionalFloat : temp_non_optionalFloat, 46 | _non_optionalInt : temp_non_optionalInt, 47 | _non_optionalBool : temp_non_optionalBool, 48 | _non_optionalString : temp_non_optionalString) 49 | 50 | if let unwrapped_optionalInt : Any = valuesDict["optionalInt"] { 51 | optionalInt = typeCast(unwrapped_optionalInt) 52 | } 53 | 54 | if let unwrapped_optionalBool : Any = valuesDict["optionalBool"] { 55 | optionalBool = typeCast(unwrapped_optionalBool) 56 | } 57 | 58 | if let unwrapped_optionalString : Any = valuesDict["optionalString"] { 59 | optionalString = typeCast(unwrapped_optionalString) 60 | } 61 | 62 | if let unwrapped_optionalDouble : Any = valuesDict["optionalDouble"] { 63 | optionalDouble = typeCast(unwrapped_optionalDouble) 64 | } 65 | 66 | if let unwrapped_optionalFloat : Any = valuesDict["optionalFloat"] { 67 | optionalFloat = typeCast(unwrapped_optionalFloat) 68 | } 69 | 70 | } else { 71 | self.init(_non_optionalDouble : Double(), 72 | _non_optionalFloat : Float(), 73 | _non_optionalInt : Int(), 74 | _non_optionalBool : Bool(), 75 | _non_optionalString : String()) 76 | 77 | return nil 78 | } 79 | } 80 | 81 | func updateWithDictionary(dictionary: Dictionary) { 82 | 83 | let dynamicTypeString = "\(self.dynamicType)" 84 | let className = dynamicTypeString.componentsSeparatedByString(".").last 85 | 86 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { 87 | if let unwrapped_non_optionalDouble : Any = valuesDict["non_optionalDouble"] { 88 | non_optionalDouble = typeCast(unwrapped_non_optionalDouble)! 89 | } 90 | 91 | if let unwrapped_optionalInt : Any = valuesDict["optionalInt"] { 92 | optionalInt = typeCast(unwrapped_optionalInt) 93 | } 94 | 95 | if let unwrapped_non_optionalFloat : Any = valuesDict["non_optionalFloat"] { 96 | non_optionalFloat = typeCast(unwrapped_non_optionalFloat)! 97 | } 98 | 99 | if let unwrapped_non_optionalInt : Any = valuesDict["non_optionalInt"] { 100 | non_optionalInt = typeCast(unwrapped_non_optionalInt)! 101 | } 102 | 103 | if let unwrapped_optionalBool : Any = valuesDict["optionalBool"] { 104 | optionalBool = typeCast(unwrapped_optionalBool) 105 | } 106 | 107 | if let unwrapped_optionalString : Any = valuesDict["optionalString"] { 108 | optionalString = typeCast(unwrapped_optionalString) 109 | } 110 | 111 | if let unwrapped_optionalDouble : Any = valuesDict["optionalDouble"] { 112 | optionalDouble = typeCast(unwrapped_optionalDouble) 113 | } 114 | 115 | if let unwrapped_optionalFloat : Any = valuesDict["optionalFloat"] { 116 | optionalFloat = typeCast(unwrapped_optionalFloat) 117 | } 118 | 119 | if let unwrapped_non_optionalBool : Any = valuesDict["non_optionalBool"] { 120 | non_optionalBool = typeCast(unwrapped_non_optionalBool)! 121 | } 122 | 123 | if let unwrapped_non_optionalString : Any = valuesDict["non_optionalString"] { 124 | non_optionalString = typeCast(unwrapped_non_optionalString)! 125 | } 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectThree.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectThree { 5 | 6 | var optionalInt : Int? 7 | var optionalBool : Bool? 8 | var optionalString : String? 9 | var optionalDouble : Double? 10 | var optionalFloat : Float? 11 | 12 | var non_optionalDouble : Double 13 | var non_optionalInt : Int 14 | var non_optionalFloat : Float 15 | var non_optionalBool : Bool 16 | var non_optionalString : String 17 | 18 | required init(_non_optionalDouble : Double, 19 | _non_optionalInt : Int, 20 | _non_optionalFloat : Float, 21 | _non_optionalBool : Bool, 22 | _non_optionalString : String) { 23 | 24 | non_optionalDouble = _non_optionalDouble 25 | non_optionalInt = _non_optionalInt 26 | non_optionalFloat = _non_optionalFloat 27 | non_optionalBool = _non_optionalBool 28 | non_optionalString = _non_optionalString 29 | } 30 | 31 | convenience init?(_ dictionary: Dictionary) { 32 | 33 | let dynamicTypeString = "\(self.dynamicType)" 34 | let className = dynamicTypeString.componentsSeparatedByString(".").last 35 | 36 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 37 | 38 | let temp_non_optionalDouble : Double = typeCast(valuesDict["non_optionalDouble"])! 39 | let temp_non_optionalInt : Int = typeCast(valuesDict["non_optionalInt"])! 40 | let temp_non_optionalFloat : Float = typeCast(valuesDict["non_optionalFloat"])! 41 | let temp_non_optionalBool : Bool = typeCast(valuesDict["non_optionalBool"])! 42 | let temp_non_optionalString : String = typeCast(valuesDict["non_optionalString"])! 43 | 44 | self.init(_non_optionalDouble : temp_non_optionalDouble, 45 | _non_optionalInt : temp_non_optionalInt, 46 | _non_optionalFloat : temp_non_optionalFloat, 47 | _non_optionalBool : temp_non_optionalBool, 48 | _non_optionalString : temp_non_optionalString) 49 | 50 | if let unwrapped_optionalInt : Any = valuesDict["optionalInt"] { 51 | optionalInt = typeCast(unwrapped_optionalInt) 52 | } 53 | 54 | if let unwrapped_optionalBool : Any = valuesDict["optionalBool"] { 55 | optionalBool = typeCast(unwrapped_optionalBool) 56 | } 57 | 58 | if let unwrapped_optionalString : Any = valuesDict["optionalString"] { 59 | optionalString = typeCast(unwrapped_optionalString) 60 | } 61 | 62 | if let unwrapped_optionalDouble : Any = valuesDict["optionalDouble"] { 63 | optionalDouble = typeCast(unwrapped_optionalDouble) 64 | } 65 | 66 | if let unwrapped_optionalFloat : Any = valuesDict["optionalFloat"] { 67 | optionalFloat = typeCast(unwrapped_optionalFloat) 68 | } 69 | 70 | } else { 71 | self.init(_non_optionalDouble : Double(), 72 | _non_optionalInt : Int(), 73 | _non_optionalFloat : Float(), 74 | _non_optionalBool : Bool(), 75 | _non_optionalString : String()) 76 | 77 | return nil 78 | } 79 | } 80 | 81 | func updateWithDictionary(dictionary: Dictionary) { 82 | 83 | let dynamicTypeString = "\(self.dynamicType)" 84 | let className = dynamicTypeString.componentsSeparatedByString(".").last 85 | 86 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { 87 | if let unwrapped_non_optionalDouble : Any = valuesDict["non_optionalDouble"] { 88 | non_optionalDouble = typeCast(unwrapped_non_optionalDouble)! 89 | } 90 | 91 | if let unwrapped_non_optionalInt : Any = valuesDict["non_optionalInt"] { 92 | non_optionalInt = typeCast(unwrapped_non_optionalInt)! 93 | } 94 | 95 | if let unwrapped_non_optionalFloat : Any = valuesDict["non_optionalFloat"] { 96 | non_optionalFloat = typeCast(unwrapped_non_optionalFloat)! 97 | } 98 | 99 | if let unwrapped_optionalInt : Any = valuesDict["optionalInt"] { 100 | optionalInt = typeCast(unwrapped_optionalInt) 101 | } 102 | 103 | if let unwrapped_optionalBool : Any = valuesDict["optionalBool"] { 104 | optionalBool = typeCast(unwrapped_optionalBool) 105 | } 106 | 107 | if let unwrapped_optionalString : Any = valuesDict["optionalString"] { 108 | optionalString = typeCast(unwrapped_optionalString) 109 | } 110 | 111 | if let unwrapped_optionalDouble : Any = valuesDict["optionalDouble"] { 112 | optionalDouble = typeCast(unwrapped_optionalDouble) 113 | } 114 | 115 | if let unwrapped_optionalFloat : Any = valuesDict["optionalFloat"] { 116 | optionalFloat = typeCast(unwrapped_optionalFloat) 117 | } 118 | 119 | if let unwrapped_non_optionalBool : Any = valuesDict["non_optionalBool"] { 120 | non_optionalBool = typeCast(unwrapped_non_optionalBool)! 121 | } 122 | 123 | if let unwrapped_non_optionalString : Any = valuesDict["non_optionalString"] { 124 | non_optionalString = typeCast(unwrapped_non_optionalString)! 125 | } 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectTwelve.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectTwelve { 5 | 6 | var optionalInt : Int? 7 | var optionalBool : Bool? 8 | var optionalString : String? 9 | var optionalDouble : Double? 10 | var optionalFloat : Float? 11 | 12 | var non_optionalDouble : Double 13 | var non_optionalFloat : Float 14 | var non_optionalInt : Int 15 | var non_optionalBool : Bool 16 | var non_optionalString : String 17 | 18 | required init(_non_optionalDouble : Double, 19 | _non_optionalFloat : Float, 20 | _non_optionalInt : Int, 21 | _non_optionalBool : Bool, 22 | _non_optionalString : String) { 23 | 24 | non_optionalDouble = _non_optionalDouble 25 | non_optionalFloat = _non_optionalFloat 26 | non_optionalInt = _non_optionalInt 27 | non_optionalBool = _non_optionalBool 28 | non_optionalString = _non_optionalString 29 | } 30 | 31 | convenience init?(_ dictionary: Dictionary) { 32 | 33 | let dynamicTypeString = "\(self.dynamicType)" 34 | let className = dynamicTypeString.componentsSeparatedByString(".").last 35 | 36 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 37 | 38 | let temp_non_optionalDouble : Double = typeCast(valuesDict["non_optionalDouble"])! 39 | let temp_non_optionalFloat : Float = typeCast(valuesDict["non_optionalFloat"])! 40 | let temp_non_optionalInt : Int = typeCast(valuesDict["non_optionalInt"])! 41 | let temp_non_optionalBool : Bool = typeCast(valuesDict["non_optionalBool"])! 42 | let temp_non_optionalString : String = typeCast(valuesDict["non_optionalString"])! 43 | 44 | self.init(_non_optionalDouble : temp_non_optionalDouble, 45 | _non_optionalFloat : temp_non_optionalFloat, 46 | _non_optionalInt : temp_non_optionalInt, 47 | _non_optionalBool : temp_non_optionalBool, 48 | _non_optionalString : temp_non_optionalString) 49 | 50 | if let unwrapped_optionalInt : Any = valuesDict["optionalInt"] { 51 | optionalInt = typeCast(unwrapped_optionalInt) 52 | } 53 | 54 | if let unwrapped_optionalBool : Any = valuesDict["optionalBool"] { 55 | optionalBool = typeCast(unwrapped_optionalBool) 56 | } 57 | 58 | if let unwrapped_optionalString : Any = valuesDict["optionalString"] { 59 | optionalString = typeCast(unwrapped_optionalString) 60 | } 61 | 62 | if let unwrapped_optionalDouble : Any = valuesDict["optionalDouble"] { 63 | optionalDouble = typeCast(unwrapped_optionalDouble) 64 | } 65 | 66 | if let unwrapped_optionalFloat : Any = valuesDict["optionalFloat"] { 67 | optionalFloat = typeCast(unwrapped_optionalFloat) 68 | } 69 | 70 | } else { 71 | self.init(_non_optionalDouble : Double(), 72 | _non_optionalFloat : Float(), 73 | _non_optionalInt : Int(), 74 | _non_optionalBool : Bool(), 75 | _non_optionalString : String()) 76 | 77 | return nil 78 | } 79 | } 80 | 81 | func updateWithDictionary(dictionary: Dictionary) { 82 | 83 | let dynamicTypeString = "\(self.dynamicType)" 84 | let className = dynamicTypeString.componentsSeparatedByString(".").last 85 | 86 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { 87 | if let unwrapped_non_optionalDouble : Any = valuesDict["non_optionalDouble"] { 88 | non_optionalDouble = typeCast(unwrapped_non_optionalDouble)! 89 | } 90 | 91 | if let unwrapped_optionalInt : Any = valuesDict["optionalInt"] { 92 | optionalInt = typeCast(unwrapped_optionalInt) 93 | } 94 | 95 | if let unwrapped_non_optionalFloat : Any = valuesDict["non_optionalFloat"] { 96 | non_optionalFloat = typeCast(unwrapped_non_optionalFloat)! 97 | } 98 | 99 | if let unwrapped_non_optionalInt : Any = valuesDict["non_optionalInt"] { 100 | non_optionalInt = typeCast(unwrapped_non_optionalInt)! 101 | } 102 | 103 | if let unwrapped_optionalBool : Any = valuesDict["optionalBool"] { 104 | optionalBool = typeCast(unwrapped_optionalBool) 105 | } 106 | 107 | if let unwrapped_optionalString : Any = valuesDict["optionalString"] { 108 | optionalString = typeCast(unwrapped_optionalString) 109 | } 110 | 111 | if let unwrapped_optionalDouble : Any = valuesDict["optionalDouble"] { 112 | optionalDouble = typeCast(unwrapped_optionalDouble) 113 | } 114 | 115 | if let unwrapped_optionalFloat : Any = valuesDict["optionalFloat"] { 116 | optionalFloat = typeCast(unwrapped_optionalFloat) 117 | } 118 | 119 | if let unwrapped_non_optionalBool : Any = valuesDict["non_optionalBool"] { 120 | non_optionalBool = typeCast(unwrapped_non_optionalBool)! 121 | } 122 | 123 | if let unwrapped_non_optionalString : Any = valuesDict["non_optionalString"] { 124 | non_optionalString = typeCast(unwrapped_non_optionalString)! 125 | } 126 | } 127 | } 128 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectNine.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectNine { 5 | 6 | var optionalArrayIntType : [Int]? 7 | var optionalArrayStringType : [String]? 8 | var optionalArrayDoubleType : [Double]? 9 | var optionalArrayFloatType : [Float]? 10 | 11 | var non_optionalArrayFloatType : [Float] 12 | var non_optionalArrayDoubleType : [Double] 13 | var non_optionalArrayIntType : [Int] 14 | var non_optionalArrayStringType : [String] 15 | 16 | required init(_non_optionalArrayFloatType : [Float], 17 | _non_optionalArrayDoubleType : [Double], 18 | _non_optionalArrayIntType : [Int], 19 | _non_optionalArrayStringType : [String]) { 20 | 21 | non_optionalArrayFloatType = _non_optionalArrayFloatType 22 | non_optionalArrayDoubleType = _non_optionalArrayDoubleType 23 | non_optionalArrayIntType = _non_optionalArrayIntType 24 | non_optionalArrayStringType = _non_optionalArrayStringType 25 | } 26 | 27 | convenience init?(_ dictionary: Dictionary) { 28 | 29 | let dynamicTypeString = "\(self.dynamicType)" 30 | let className = dynamicTypeString.componentsSeparatedByString(".").last 31 | 32 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 33 | 34 | let temp_non_optionalArrayFloatType : [Float] = typeCast(valuesDict["non_optionalArrayFloatType"])! 35 | let temp_non_optionalArrayDoubleType : [Double] = typeCast(valuesDict["non_optionalArrayDoubleType"])! 36 | let temp_non_optionalArrayIntType : [Int] = typeCast(valuesDict["non_optionalArrayIntType"])! 37 | let temp_non_optionalArrayStringType : [String] = typeCast(valuesDict["non_optionalArrayStringType"])! 38 | 39 | self.init(_non_optionalArrayFloatType : temp_non_optionalArrayFloatType, 40 | _non_optionalArrayDoubleType : temp_non_optionalArrayDoubleType, 41 | _non_optionalArrayIntType : temp_non_optionalArrayIntType, 42 | _non_optionalArrayStringType : temp_non_optionalArrayStringType) 43 | 44 | if let unwrapped_optionalArrayIntType : Any = valuesDict["optionalArrayIntType"] { 45 | optionalArrayIntType = typeCast(unwrapped_optionalArrayIntType) 46 | } 47 | 48 | if let unwrapped_optionalArrayStringType : Any = valuesDict["optionalArrayStringType"] { 49 | optionalArrayStringType = typeCast(unwrapped_optionalArrayStringType) 50 | } 51 | 52 | if let unwrapped_optionalArrayDoubleType : Any = valuesDict["optionalArrayDoubleType"] { 53 | optionalArrayDoubleType = typeCast(unwrapped_optionalArrayDoubleType) 54 | } 55 | 56 | if let unwrapped_optionalArrayFloatType : Any = valuesDict["optionalArrayFloatType"] { 57 | optionalArrayFloatType = typeCast(unwrapped_optionalArrayFloatType) 58 | } 59 | 60 | } else { 61 | self.init(_non_optionalArrayFloatType : [Float](), 62 | _non_optionalArrayDoubleType : [Double](), 63 | _non_optionalArrayIntType : [Int](), 64 | _non_optionalArrayStringType : [String]()) 65 | 66 | return nil 67 | } 68 | } 69 | 70 | func updateWithDictionary(dictionary: Dictionary) { 71 | 72 | let dynamicTypeString = "\(self.dynamicType)" 73 | let className = dynamicTypeString.componentsSeparatedByString(".").last 74 | 75 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { 76 | if let unwrapped_optionalArrayIntType : Any = valuesDict["optionalArrayIntType"] { 77 | optionalArrayIntType = typeCast(unwrapped_optionalArrayIntType) 78 | } 79 | 80 | if let unwrapped_optionalArrayStringType : Any = valuesDict["optionalArrayStringType"] { 81 | optionalArrayStringType = typeCast(unwrapped_optionalArrayStringType) 82 | } 83 | 84 | if let unwrapped_non_optionalArrayFloatType : Any = valuesDict["non_optionalArrayFloatType"] { 85 | non_optionalArrayFloatType = typeCast(unwrapped_non_optionalArrayFloatType)! 86 | } 87 | 88 | if let unwrapped_non_optionalArrayDoubleType : Any = valuesDict["non_optionalArrayDoubleType"] { 89 | non_optionalArrayDoubleType = typeCast(unwrapped_non_optionalArrayDoubleType)! 90 | } 91 | 92 | if let unwrapped_non_optionalArrayIntType : Any = valuesDict["non_optionalArrayIntType"] { 93 | non_optionalArrayIntType = typeCast(unwrapped_non_optionalArrayIntType)! 94 | } 95 | 96 | if let unwrapped_non_optionalArrayStringType : Any = valuesDict["non_optionalArrayStringType"] { 97 | non_optionalArrayStringType = typeCast(unwrapped_non_optionalArrayStringType)! 98 | } 99 | 100 | if let unwrapped_optionalArrayDoubleType : Any = valuesDict["optionalArrayDoubleType"] { 101 | optionalArrayDoubleType = typeCast(unwrapped_optionalArrayDoubleType) 102 | } 103 | 104 | if let unwrapped_optionalArrayFloatType : Any = valuesDict["optionalArrayFloatType"] { 105 | optionalArrayFloatType = typeCast(unwrapped_optionalArrayFloatType) 106 | } 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /US2MapperKit/Shared Test Cases/Classes/Internal/_TestObjectTen.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | class _TestObjectTen { 5 | 6 | var optionalDictionaryFloatType : Dictionary? 7 | var optionalDictionaryStringType : Dictionary? 8 | var optionalDictionaryIntType : Dictionary? 9 | var optionalDictionaryDoubleType : Dictionary? 10 | 11 | var non_optionalDictionaryDoubleType : Dictionary 12 | var non_optionalDictionaryIntType : Dictionary 13 | var non_optionalDictionaryFloatType : Dictionary 14 | var non_optionalDictionaryStringType : Dictionary 15 | 16 | required init(_non_optionalDictionaryDoubleType : Dictionary, 17 | _non_optionalDictionaryIntType : Dictionary, 18 | _non_optionalDictionaryFloatType : Dictionary, 19 | _non_optionalDictionaryStringType : Dictionary) { 20 | 21 | non_optionalDictionaryDoubleType = _non_optionalDictionaryDoubleType 22 | non_optionalDictionaryIntType = _non_optionalDictionaryIntType 23 | non_optionalDictionaryFloatType = _non_optionalDictionaryFloatType 24 | non_optionalDictionaryStringType = _non_optionalDictionaryStringType 25 | } 26 | 27 | convenience init?(_ dictionary: Dictionary) { 28 | 29 | let dynamicTypeString = "\(self.dynamicType)" 30 | let className = dynamicTypeString.componentsSeparatedByString(".").last 31 | 32 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) { 33 | 34 | let temp_non_optionalDictionaryDoubleType : Dictionary = typeCast(valuesDict["non_optionalDictionaryDoubleType"])! 35 | let temp_non_optionalDictionaryIntType : Dictionary = typeCast(valuesDict["non_optionalDictionaryIntType"])! 36 | let temp_non_optionalDictionaryFloatType : Dictionary = typeCast(valuesDict["non_optionalDictionaryFloatType"])! 37 | let temp_non_optionalDictionaryStringType : Dictionary = typeCast(valuesDict["non_optionalDictionaryStringType"])! 38 | 39 | self.init(_non_optionalDictionaryDoubleType : temp_non_optionalDictionaryDoubleType, 40 | _non_optionalDictionaryIntType : temp_non_optionalDictionaryIntType, 41 | _non_optionalDictionaryFloatType : temp_non_optionalDictionaryFloatType, 42 | _non_optionalDictionaryStringType : temp_non_optionalDictionaryStringType) 43 | 44 | if let unwrapped_optionalDictionaryFloatType : Any = valuesDict["optionalDictionaryFloatType"] { 45 | optionalDictionaryFloatType = typeCast(unwrapped_optionalDictionaryFloatType) 46 | } 47 | 48 | if let unwrapped_optionalDictionaryStringType : Any = valuesDict["optionalDictionaryStringType"] { 49 | optionalDictionaryStringType = typeCast(unwrapped_optionalDictionaryStringType) 50 | } 51 | 52 | if let unwrapped_optionalDictionaryIntType : Any = valuesDict["optionalDictionaryIntType"] { 53 | optionalDictionaryIntType = typeCast(unwrapped_optionalDictionaryIntType) 54 | } 55 | 56 | if let unwrapped_optionalDictionaryDoubleType : Any = valuesDict["optionalDictionaryDoubleType"] { 57 | optionalDictionaryDoubleType = typeCast(unwrapped_optionalDictionaryDoubleType) 58 | } 59 | 60 | } else { 61 | self.init(_non_optionalDictionaryDoubleType : Dictionary(), 62 | _non_optionalDictionaryIntType : Dictionary(), 63 | _non_optionalDictionaryFloatType : Dictionary(), 64 | _non_optionalDictionaryStringType : Dictionary()) 65 | 66 | return nil 67 | } 68 | } 69 | 70 | func updateWithDictionary(dictionary: Dictionary) { 71 | 72 | let dynamicTypeString = "\(self.dynamicType)" 73 | let className = dynamicTypeString.componentsSeparatedByString(".").last 74 | 75 | if let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) { 76 | if let unwrapped_non_optionalDictionaryDoubleType : Any = valuesDict["non_optionalDictionaryDoubleType"] { 77 | non_optionalDictionaryDoubleType = typeCast(unwrapped_non_optionalDictionaryDoubleType)! 78 | } 79 | 80 | if let unwrapped_optionalDictionaryFloatType : Any = valuesDict["optionalDictionaryFloatType"] { 81 | optionalDictionaryFloatType = typeCast(unwrapped_optionalDictionaryFloatType) 82 | } 83 | 84 | if let unwrapped_optionalDictionaryStringType : Any = valuesDict["optionalDictionaryStringType"] { 85 | optionalDictionaryStringType = typeCast(unwrapped_optionalDictionaryStringType) 86 | } 87 | 88 | if let unwrapped_optionalDictionaryIntType : Any = valuesDict["optionalDictionaryIntType"] { 89 | optionalDictionaryIntType = typeCast(unwrapped_optionalDictionaryIntType) 90 | } 91 | 92 | if let unwrapped_non_optionalDictionaryIntType : Any = valuesDict["non_optionalDictionaryIntType"] { 93 | non_optionalDictionaryIntType = typeCast(unwrapped_non_optionalDictionaryIntType)! 94 | } 95 | 96 | if let unwrapped_non_optionalDictionaryFloatType : Any = valuesDict["non_optionalDictionaryFloatType"] { 97 | non_optionalDictionaryFloatType = typeCast(unwrapped_non_optionalDictionaryFloatType)! 98 | } 99 | 100 | if let unwrapped_non_optionalDictionaryStringType : Any = valuesDict["non_optionalDictionaryStringType"] { 101 | non_optionalDictionaryStringType = typeCast(unwrapped_non_optionalDictionaryStringType)! 102 | } 103 | 104 | if let unwrapped_optionalDictionaryDoubleType : Any = valuesDict["optionalDictionaryDoubleType"] { 105 | optionalDictionaryDoubleType = typeCast(unwrapped_optionalDictionaryDoubleType) 106 | } 107 | } 108 | } 109 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Cocoapods Compatible](https://img.shields.io/badge/pod-v0.2.0-blue.svg)](https://github.com/ustwo/US2MapperKit) 2 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 3 | [![Platform](https://img.shields.io/badge/platform-ios%20%7C%20osx-lightgrey.svg)](https://github.com/ustwo/US2MapperKit) 4 | [![License](https://img.shields.io/badge/license-MIT-343434.svg)](https://github.com/ustwo/US2MapperKit) 5 | #US2MapperKit 6 | ![alt tag](/documentation/readme_assets/mapperkit_header.png?raw=true) 7 | 8 | Inspired by [CSMapper](https://github.com/marcammann/CSMapper) and [Mogenerator](https://github.com/rentzsch/mogenerator), US2MapperKit is an an extremely lightweight mapping framework designed specifically for Swift 1.2, and Swift 2.0. 9 | 10 | Unlike previous frameworks, where an object model is manually created by the developer then retrofitted with a mapping framework at a later point, US2MapperKit takes a mapping-first approach. By mapping against dictionary data up front, US2MapperKit generates the model objects based on the mapping, and allows for the extensibility inspired by the [Protocol-Oriented Programming](https://developer.apple.com/videos/wwdc/2015/?id=408) talk at WWDC. 11 | 12 | ##Core Concept 13 | 14 | ![alt tag](/documentation/readme_assets/basic_concept_image.png?raw=true) 15 | 16 | The simple example above demonstrates the inner workings of the US2MapperKit. In this example we will attemp to map a Person object returned in the form a dictionary. The first step is to manually generate a plist representing the data that is being returned. This plist defines properties, data types, the mapping keys associated with the response dictionary, and any transformation that needs to be applied. Once defined, a build-time script will generate two model object files representing the model mapping. 17 | 18 | The first class generated in the diagram represents the internal `_Person.swift` class, which contains script-generated property definitions, along two initializers, one required, and one fail-able. The generated fail-able initializer takes in a `Dictionary` input value which is parsed to the model. The internal files purpose is to support the framework by mapping the response data and should not be modified by the developer since the script will regenerate it every time the project is built. 19 | 20 | The second class generated is the `Person.swift` which inherits from the internal `_Person.swift` class. This provides a means for developer to append any custom logic, properties, or implementations of protocols as needed during the development process. This class is only generated once, and will never be overwritten during the build task. Thus updating the model mapping will not affect any logic defined in the external class. 21 | 22 | ##Features 23 | 24 | * Auto generation of model objects via .plists files 25 | * Optional & Non-Optional support for: 26 | * String 27 | * Int 28 | * Double 29 | * Float 30 | * Bool 31 | * Collections Support for: 32 | * Array\ 33 | * Dictionary\ 34 | * Complex Type Support (stand alone, and in collections) 35 | * Default Value Definitions 36 | * Mapping Nested Values 37 | * Complex Transformations 38 | * Structs, Enums, Closures, Tuples via Transformations 39 | 40 | ##Basic Use 41 | 42 | ####Initialization with Dictionary 43 | 44 | Once configured per the [Installation](/documentation/installation.md) instructions: 45 | 46 | 1. Create a plist model mapping and place it in the mapping folder defined during installation. 47 | 2. Build the target, navigate to the output directory defined during the installation process, and add the generated files to the project. 48 | 3. Map the data to an instance, call the fail-able initializer generated by US2MapperKit with the `Dictionary` data to parse. 49 | 50 | ``` 51 | let newInstance = TestModelObject(dataDictionary) 52 | ``` 53 | 54 | ####Update with Dictionary 55 | 56 | Once an instance has been initialized, we can pass a new dictionary with values to update for the current instance by calling `updateWithDictionary(dictionary : Dictionary?)`. Note that only the values which are being passed within will be updated, defaults values are ignored unline the initialization 57 | 58 | ``` 59 | let instance = TestModelObject(dataDictionary) 60 | let newValuesDictionary = [... : ...] 61 | 62 | // Updates the current values only with the new values received, defaults in mapping are ignored 63 | instance.updateWithDictionary(newValuesDictionary) 64 | 65 | ``` 66 | 67 | ####Examples 68 | 69 | Below is a list of examples for the supported features by US2MapperKit. Each provides an overall view on how to setup the model mapping file, and short examples of the outputs generated by pre-packaged script within the framework. 70 | 71 | * [Optional Types](/documentation/optional_value_types.md) 72 | * [Non-Optional Types](/documentation/non_optional_value_types.md) 73 | * [Collection Types](/documentation/collection_types.md) 74 | * [Complex Types](/documentation/complex_value_types.md) 75 | * [Default Value Definitions](/documentation/default_values.md) 76 | * [Mapping Against Nested Values](/documentation/nested_mapping.md) 77 | * [Custom Transformations](/documentation/custom_transforms.md) 78 | * [Structs Mapping](/documentation/custom_transforms_struct.md) 79 | * [Enum Mapping](/documentation/custom_transforms_enums.md) 80 | * [Closures Mapping](/documentation/custom_transforms_closures.md) 81 | * [Tuples Mapping](/documentation/custom_transforms_tuples.md) 82 | 83 | ##Troubleshooting 84 | 85 | - [Enabling Debug Mode](/documentation/enable_debug_mode.md) 86 | - [Swift 1.2 / 2.0 Compatibility](/documentation/compatibility_issues.md) 87 | 88 | ##Updates 89 | 90 | - [Change Log](/documentation/changelog.md) 91 | 92 | ##Future Enahancements 93 | 94 | * Mapping Inheritance (Configuration to Inherit from NSManagedObject / Realm Object) 95 | * Xcode Plug-in 96 | 97 | ## License 98 | 99 | The MIT License (MIT) 100 | 101 | Copyright (c) 2015 ustwo studio inc (www.ustwo.com) 102 | 103 | Permission is hereby granted, free of charge, to any person obtaining a copy 104 | of this software and associated documentation files (the "Software"), to deal 105 | in the Software without restriction, including without limitation the rights 106 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 107 | copies of the Software, and to permit persons to whom the Software is 108 | furnished to do so, subject to the following conditions: 109 | 110 | The above copyright notice and this permission notice shall be included in all 111 | copies or substantial portions of the Software. 112 | 113 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 114 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 115 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 116 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 117 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 118 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 119 | SOFTWARE. 120 | -------------------------------------------------------------------------------- /Source/ModelScript/modelgen-swift.py: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/python 2 | import plistlib 3 | import os 4 | import sys 5 | import getopt 6 | import dircache 7 | import glob 8 | import commands 9 | 10 | FOLDER_INTERNAL_PREFIX = "Classes/Internal/_" 11 | FOLDER_EXTERNAL_PREFIX = "Classes/" 12 | 13 | PROPERTY_TYPE_STRING = "String" 14 | PROPERTY_TYPE_DOUBLE = "Double" 15 | PROPERTY_TYPE_FLOAT = "Float" 16 | PROPERTY_TYPE_INT = "Int" 17 | PROPERTY_TYPE_BOOL = "Bool" 18 | PROPERTY_TYPE_ARRAY = "Array" 19 | PROPERTY_TYPE_DICTIONARY = "Dictionary" 20 | 21 | NATIVE_PROPERTY_TYPES = [PROPERTY_TYPE_STRING, PROPERTY_TYPE_DOUBLE, PROPERTY_TYPE_FLOAT, PROPERTY_TYPE_INT, PROPERTY_TYPE_BOOL] 22 | 23 | MAPPING_KEY_TYPE = "type" 24 | MAPPING_KEY_DEFAULT = "default" 25 | MAPPING_KEY_KEY = "key" 26 | MAPPING_KEY_NONOPTIONAL = "nonoptional" 27 | MAPPING_KEY_TRANSFORMER = "transformer" 28 | MAPPING_KEY_COLLECTION_SUBTYPE = "collection_subtype" 29 | 30 | STRING_IMPORT_FOUNDATION = "import Foundation\n" 31 | STRING_REQUIRED_INIT_START = "\n\trequired init(" 32 | STRING_MAP_VALUES_DICT_START = "\n\n\tprivate func setValues(" 33 | STRING_MAP_DICT_START = '\n\n\tfunc updateWithDictionary(dictionary: Dictionary) {\n\n\t\tlet dynamicTypeString = "\(self.dynamicType)"\n\t\tlet className = dynamicTypeString.componentsSeparatedByString(".").last\n\n\t\tif let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : false) {' 34 | 35 | STRING_FAILABLE_INIT_START = '\tconvenience init?(_ dictionary: Dictionary) {\n\n\t\tlet dynamicTypeString = "\(self.dynamicType)"\n\t\tlet className = dynamicTypeString.componentsSeparatedByString(".").last\n\n\t\tif let valuesDict = US2Mapper.mapValues(from: dictionary, forType: className!, employing: US2Instantiator.sharedInstance, defaultsEnabled : true) {' 36 | STRING_FAILABLE_INIT_SUPER_START = '\t\n\t\t\tself.init(' 37 | STRING_FILE_INTRO = '// US2MapperKit Generated Model\n// UPDATE LISCENSE HERE\n\n' 38 | STRING_PROPERTY_VAR = " var" 39 | 40 | STRING_CLASS_FROM_STRING_METHOD = "\n\nstatic let sharedInstance : US2Instantiator = US2Instantiator()\n\nfunc newInstance(ofType classname : String, withValue data : Dictionary) -> AnyObject? {\n\t\tswitch classname {\n" 41 | 42 | STRING_USMAPPER_IMPORT = "\n" 43 | STRING_USMAPPER_INHERITENCE = "\nclass US2Instantiator : US2InstantiatorProtocol {\n\n" 44 | 45 | def generate_model(mappinglist, output_directory, version): 46 | 47 | for mapping in mappinglist: 48 | filename = mapping[mapping.rindex('/',0,-1)+1:-1] if mapping.endswith('/') else mapping[mapping.rindex('/')+1:] 49 | classname = filename.split('.', 1 )[0] 50 | 51 | mappingPlist = plistlib.readPlist(mapping) 52 | 53 | validate_class_mapping_configuration(classname, mappingPlist) 54 | 55 | generate_internal_file(mappingPlist, classname, output_directory) 56 | generate_external_file_if_needed(classname, output_directory) 57 | 58 | generate_internal_instantiator_file(mappinglist, output_directory) 59 | 60 | 61 | ''' 62 | External Model File Generation 63 | ''' 64 | def generate_external_file_if_needed(classname, class_directory): 65 | 66 | filename = class_directory + classname + '.swift' 67 | 68 | if os.path.exists(filename): 69 | return None 70 | 71 | if not os.path.exists(os.path.dirname(filename)): 72 | os.makedirs(os.path.dirname(filename)) 73 | 74 | outputfile = open(filename, "wba") 75 | 76 | outputfile.write(STRING_IMPORT_FOUNDATION + '\nclass ' + classname + ' : _' + classname + ' {\n\n}') 77 | outputfile.close(); 78 | 79 | 80 | ''' 81 | Internal Model File Generation 82 | ''' 83 | def generate_internal_file(mappingPlist, classname, class_directory): 84 | 85 | filename = class_directory + 'Internal/_'+ classname + '.swift' 86 | 87 | if not os.path.exists(os.path.dirname(filename)): 88 | os.makedirs(os.path.dirname(filename)) 89 | 90 | outputfile = open(filename, "wba") 91 | 92 | outputfile.write(STRING_IMPORT_FOUNDATION + STRING_USMAPPER_IMPORT + '\nclass _' + classname + ' {\n') 93 | 94 | append_optional_property_definitions(outputfile, mappingPlist) 95 | append_non_optional_property_definitions(outputfile, mappingPlist) 96 | append_required_initializer(outputfile, mappingPlist) 97 | append_failable_initializer(outputfile, mappingPlist) 98 | #append_map_values(outputfile, mappingPlist) 99 | append_map_dictionary_setter(outputfile, mappingPlist) 100 | outputfile.write('\n} ') 101 | outputfile.close(); 102 | 103 | 104 | ''' 105 | Appeand Properties 106 | ''' 107 | def append_optional_property_definitions(classfile, mappingPlist): 108 | classfile.write('\n') 109 | mappingKeys = mappingPlist.keys() 110 | 111 | for propertyName in mappingKeys: 112 | propertyType = mappingPlist[propertyName][MAPPING_KEY_TYPE] 113 | collectionSubtype = '' 114 | 115 | if MAPPING_KEY_COLLECTION_SUBTYPE in mappingPlist[propertyName].keys(): 116 | collectionSubtype = mappingPlist[propertyName][MAPPING_KEY_COLLECTION_SUBTYPE] 117 | 118 | if propertyType == PROPERTY_TYPE_ARRAY: 119 | if MAPPING_KEY_NONOPTIONAL not in mappingPlist[propertyName].keys() or mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] != 'true': 120 | append_array_instance_property(classfile, propertyName, collectionSubtype, True) 121 | 122 | elif propertyType == PROPERTY_TYPE_DICTIONARY: 123 | if MAPPING_KEY_NONOPTIONAL not in mappingPlist[propertyName].keys() or mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] != 'true': 124 | append_dictionary_instance_property(classfile, propertyName, collectionSubtype, True) 125 | else: 126 | if MAPPING_KEY_NONOPTIONAL not in mappingPlist[propertyName].keys() or mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] != 'true': 127 | append_instance_property(classfile, propertyName, propertyType, True) 128 | 129 | 130 | def append_non_optional_property_definitions(classfile, mappingPlist): 131 | classfile.write('\n') 132 | 133 | for propertyName in mappingPlist.keys(): 134 | propertyType = mappingPlist[propertyName][MAPPING_KEY_TYPE] 135 | collectionSubtype = '' 136 | 137 | if MAPPING_KEY_COLLECTION_SUBTYPE in mappingPlist[propertyName].keys(): 138 | collectionSubtype = mappingPlist[propertyName][MAPPING_KEY_COLLECTION_SUBTYPE] 139 | 140 | if propertyType == PROPERTY_TYPE_ARRAY: 141 | if MAPPING_KEY_NONOPTIONAL in mappingPlist[propertyName].keys() and mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] == 'true': 142 | append_array_instance_property(classfile, propertyName, collectionSubtype, False) 143 | 144 | elif propertyType == PROPERTY_TYPE_DICTIONARY: 145 | if MAPPING_KEY_NONOPTIONAL in mappingPlist[propertyName].keys() and mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] == 'true': 146 | append_dictionary_instance_property(classfile, propertyName, collectionSubtype, False) 147 | else: 148 | if MAPPING_KEY_NONOPTIONAL in mappingPlist[propertyName].keys() and mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] == 'true': 149 | append_instance_property(classfile, propertyName, propertyType, False) 150 | 151 | 152 | def append_instance_property(classfile, propertyname, datatype, optional): 153 | classfile.write(STRING_PROPERTY_VAR + ' ' + propertyname + ' : ' + datatype + '{}\n'.format('?' if optional else '')) 154 | 155 | def append_array_instance_property(classfile, propertyname, collectionSubtype, optional): 156 | classfile.write(STRING_PROPERTY_VAR + ' ' + propertyname + ' : [' + collectionSubtype + ']{}\n'.format('?' if optional else '')) 157 | 158 | def append_dictionary_instance_property(classfile, propertyname, collectionSubtype, optional): 159 | classfile.write(STRING_PROPERTY_VAR + ' ' + propertyname + ' : Dictionary{}\n'.format('?' if optional else '')) 160 | 161 | 162 | ''' 163 | Append Required Initializer 164 | ''' 165 | def append_required_initializer(classFile, mappingPlist): 166 | classFile.write(STRING_REQUIRED_INIT_START) 167 | firstPropertyWritten = True 168 | 169 | for propertyName in mappingPlist.keys(): 170 | propertyType = mappingPlist[propertyName][MAPPING_KEY_TYPE] 171 | 172 | if MAPPING_KEY_NONOPTIONAL in mappingPlist[propertyName].keys() and mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] == 'true': 173 | append_required_initializer_non_optional_property(classFile, mappingPlist, propertyName, propertyType, firstPropertyWritten) 174 | firstPropertyWritten = False 175 | 176 | classFile.write(') {\n ') 177 | append_required_initializer_value_assignments(classFile, mappingPlist) 178 | classFile.write('\n\t}\n\n') 179 | 180 | 181 | def append_required_initializer_value_assignments(classFile, mappingPlist): 182 | for propertyName in mappingPlist.keys(): 183 | if MAPPING_KEY_NONOPTIONAL in mappingPlist[propertyName].keys(): 184 | if mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] == 'true': 185 | classFile.write('\n ') 186 | classFile.write(propertyName + ' = _' + propertyName ) 187 | 188 | 189 | def append_required_initializer_non_optional_property(classFile, mappingPlist, propertyName, propertyType, isFirstProperty): 190 | if propertyType == PROPERTY_TYPE_ARRAY: 191 | collectionSubtype = mappingPlist[propertyName][MAPPING_KEY_COLLECTION_SUBTYPE] 192 | classFile.write('{}_'.format('' if isFirstProperty else ',\n\t\t\t\t ') + propertyName + ' : [' + collectionSubtype + ']') 193 | elif propertyType == PROPERTY_TYPE_DICTIONARY: 194 | collectionSubtype = mappingPlist[propertyName][MAPPING_KEY_COLLECTION_SUBTYPE] 195 | classFile.write('{}_'.format('' if isFirstProperty else ',\n\t\t\t\t ') + propertyName + ' : Dictionary') 196 | else: 197 | classFile.write('{}_'.format('' if isFirstProperty else ',\n\t\t\t\t ') + propertyName + ' : ' + propertyType) 198 | 199 | 200 | ''' 201 | Append Failable Initializer 202 | ''' 203 | def append_failable_initializer(classFile, mappingPlist): 204 | 205 | classFile.write(STRING_FAILABLE_INIT_START) 206 | 207 | append_failable_initializer_tempValues(classFile, mappingPlist) 208 | 209 | classFile.write(STRING_FAILABLE_INIT_SUPER_START) 210 | 211 | isFirstLine = True 212 | 213 | for propertyName in mappingPlist.keys(): 214 | if MAPPING_KEY_NONOPTIONAL in mappingPlist[propertyName].keys() and mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] == 'true': 215 | classFile.write('{}_'.format('' if isFirstLine else ',\n\t\t\t\t\t ') + propertyName + ' : temp_' + propertyName + '') 216 | isFirstLine = False 217 | 218 | classFile.write(') \n\t\t') 219 | 220 | append_failable_initializer_typecasting(classFile, mappingPlist) 221 | 222 | print xcode_version() 223 | 224 | if xcode_version() == 7.0: 225 | classFile.write(' \n\t\t} else {\n\t\t\treturn nil\n\t\t}\n\t}') 226 | else: 227 | append_swift_1_2_failable_reinitialization(classFile, mappingPlist) 228 | 229 | 230 | def append_swift_1_2_failable_reinitialization(classFile, mappingPlist): 231 | 232 | classFile.write(' \n } else {\n self.init(') 233 | isFirstLine = True 234 | 235 | for propertyName in mappingPlist.keys(): 236 | propertyType = mappingPlist[propertyName][MAPPING_KEY_TYPE] 237 | collectionSubtype = '' 238 | 239 | if MAPPING_KEY_COLLECTION_SUBTYPE in mappingPlist[propertyName].keys(): 240 | collectionSubtype = mappingPlist[propertyName][MAPPING_KEY_COLLECTION_SUBTYPE] 241 | 242 | if propertyType == PROPERTY_TYPE_ARRAY: 243 | if MAPPING_KEY_NONOPTIONAL in mappingPlist[propertyName].keys() and mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] == 'true': 244 | append_array_failed_initialiser_property(classFile, propertyName, propertyType, collectionSubtype, False, isFirstLine) 245 | isFirstLine = False 246 | 247 | elif propertyType == PROPERTY_TYPE_DICTIONARY: 248 | if MAPPING_KEY_NONOPTIONAL in mappingPlist[propertyName].keys() and mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] == 'true': 249 | append_dictionary_failed_initialiser_property(classFile, propertyName, propertyType, collectionSubtype, False, isFirstLine) 250 | isFirstLine = False 251 | else: 252 | if MAPPING_KEY_NONOPTIONAL in mappingPlist[propertyName].keys() and mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] == 'true': 253 | append_failed_initialiser_property(classFile, propertyName, propertyType, False, isFirstLine) 254 | isFirstLine = False 255 | 256 | classFile.write(')\n\n\t\t\treturn nil\n\t\t}\n\t}') 257 | 258 | 259 | def append_failable_initializer_tempValues(classFile, mappingPlist): 260 | classFile.write('\n') 261 | 262 | for propertyName in mappingPlist.keys(): 263 | if MAPPING_KEY_NONOPTIONAL in mappingPlist[propertyName].keys() and mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] == 'true': 264 | propertyType = mappingPlist[propertyName][MAPPING_KEY_TYPE] 265 | append_failable_initializer_non_optional_property_typecast(classFile, mappingPlist, propertyName, propertyType) 266 | 267 | classFile.write('\n') 268 | 269 | 270 | def append_failable_initializer_optional_temp_properties(classFile, mappingPlist, propertyName, propertyType): 271 | if propertyType == PROPERTY_TYPE_ARRAY: 272 | collectionSubtype = mappingPlist[propertyName][MAPPING_KEY_COLLECTION_SUBTYPE] 273 | classFile.write('\t\t\tvar temp_' + propertyName + ' : [' + collectionSubtype + ']?') 274 | elif propertyType == PROPERTY_TYPE_DICTIONARY: 275 | collectionSubtype = mappingPlist[propertyName][MAPPING_KEY_COLLECTION_SUBTYPE] 276 | classFile.write('\t\t\tvar temp_' + propertyName + ' : Dictionary?') 277 | else: 278 | classFile.write('\t\t\tvar temp_' + propertyName + ' : ' + propertyType + '?' ) 279 | 280 | 281 | def append_failable_initializer_non_optional_property_typecast(classFile, mappingPlist, propertyName, propertyType): 282 | if propertyType == PROPERTY_TYPE_ARRAY: 283 | collectionSubtype = mappingPlist[propertyName][MAPPING_KEY_COLLECTION_SUBTYPE] 284 | classFile.write('\n\t\t\tlet temp_' + propertyName + ' : [' + collectionSubtype + ']' + ' = typeCast(valuesDict["' + propertyName + '"])!') 285 | elif propertyType == PROPERTY_TYPE_DICTIONARY: 286 | collectionSubtype = mappingPlist[propertyName][MAPPING_KEY_COLLECTION_SUBTYPE] 287 | classFile.write('\n\t\t\tlet temp_' + propertyName + ' : Dictionary' + ' = typeCast(valuesDict["' + propertyName + '"])!') 288 | else: 289 | classFile.write('\n\t\t\tlet temp_' + propertyName + ' : ' + propertyType + ' = typeCast(valuesDict["' + propertyName + '"])!') 290 | 291 | 292 | def append_failable_initializer_typecasting(classFile, mappingPlist): 293 | for propertyName in mappingPlist.keys(): 294 | if MAPPING_KEY_NONOPTIONAL not in mappingPlist[propertyName].keys(): 295 | append_failable_typecast_unwrap_statement(classFile, propertyName) 296 | else: 297 | if mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] != 'true': 298 | append_failable_typecast_unwrap_statement(classFile, propertyName) 299 | 300 | 301 | def append_failable_typecast_unwrap_statement(classFile, propertyName): 302 | classFile.write('\n\t\t\tif let unwrapped_' + propertyName + ' : Any = valuesDict["' + propertyName + '"] {\n\t\t\t\t' + propertyName + ' = typeCast(unwrapped_' + propertyName + ')\n\t\t\t}\n') 303 | 304 | def append_failed_initialiser_property(classfile, propertyname, datatype, optional, isFirstLine): 305 | if datatype not in NATIVE_PROPERTY_TYPES: 306 | classfile.write('{}_'.format('' if isFirstLine else ',\n\t\t\t\t ') + propertyname + ' : ' + datatype + '(Dictionary())!{}'.format('?' if optional else '')) 307 | else: 308 | classfile.write('{}_'.format('' if isFirstLine else ',\n\t\t\t\t ') + propertyname + ' : ' + datatype + '(){}'.format('?' if optional else '')) 309 | 310 | def append_array_failed_initialiser_property(classfile, propertyname, datatype, collectionSubtype, optional, isFirstLine): 311 | classfile.write('{}_'.format('' if isFirstLine else ',\n\t\t\t\t ') + propertyname + ' : [' + collectionSubtype + '](){}'.format('?' if optional else '')) 312 | 313 | def append_dictionary_failed_initialiser_property(classfile, propertyname, datatype, collectionSubtype, optional, isFirstLine): 314 | classfile.write( '{}_'.format('' if isFirstLine else ',\n\t\t\t\t ') + propertyname + ' : Dictionary(){}'.format('?' if optional else '')) 315 | 316 | 317 | ''' 318 | Create External US2Mapper Inherited File 319 | ''' 320 | def generate_internal_instantiator_file(mappingPlist, output_directory): 321 | filename = output_directory + 'Internal/US2Instantiator.swift' 322 | 323 | if not os.path.exists(os.path.dirname(filename)): 324 | os.makedirs(os.path.dirname(filename)) 325 | 326 | outputfile = open(filename, "wba") 327 | 328 | outputfile.write(STRING_FILE_INTRO + STRING_IMPORT_FOUNDATION + STRING_USMAPPER_IMPORT) 329 | 330 | classnames = [] 331 | 332 | for mapping in mappingPlist: 333 | filename = mapping[mapping.rindex('/',0,-1)+1:-1] if mapping.endswith('/') else mapping[mapping.rindex('/')+1:] 334 | classname = filename.split('.', 1 )[0] 335 | classnames.append(classname) 336 | 337 | outputfile.write('enum US2MapperClassEnum: String {') 338 | 339 | for classname in classnames: 340 | outputfile.write('\n\tcase _' + classname + ' \t= "'+ classname + '"' ) 341 | 342 | outputfile.write('\n\tcase _None\t\t\t\t= "None"') 343 | outputfile.write('\n\n\tfunc createObject(data : Dictionary) -> AnyObject? {\n\t\tswitch self {') 344 | 345 | for classname in classnames: 346 | outputfile.write('\n\t\tcase ._' + classname + ':\n\t\t\treturn '+ classname + '(data)' ) 347 | 348 | outputfile.write('\n\t\tcase ._None:\n\t\t\treturn nil' ) 349 | 350 | outputfile.write('\n\t\t}\n\t}\n}\n\n') 351 | 352 | append_mapper_method_definitions(outputfile, mappingPlist) 353 | 354 | outputfile.write('\n\nclass US2Instantiator : US2InstantiatorProtocol {\n\n\tstatic let sharedInstance : US2Instantiator = US2Instantiator()\n\n\tfunc newInstance(ofType classname : String, withValue data : Dictionary) -> AnyObject? {\n\t\treturn US2MapperClassEnum(rawValue: classname)?.createObject(data)\n\t}\n\n' ) 355 | 356 | outputfile.write('\tfunc transformerFromString(classString: String) -> US2TransformerProtocol? {\n\t\treturn US2TransformerEnum(rawValue: classString)!.transformer()\n\t}\n}') 357 | outputfile.close(); 358 | 359 | 360 | def append_mapper_method_definitions(classfile, mappinglist): 361 | distinctMapperClassDefinitions = [] 362 | 363 | for mappingPath in mappinglist: 364 | mappingPlist = plistlib.readPlist(mappingPath) 365 | mappingKeys = mappingPlist.keys() 366 | 367 | for propertyName in mappingKeys: 368 | if MAPPING_KEY_TRANSFORMER in mappingPlist[propertyName].keys(): 369 | mapperClass = mappingPlist[propertyName][MAPPING_KEY_TRANSFORMER] 370 | if mapperClass not in distinctMapperClassDefinitions: 371 | distinctMapperClassDefinitions.append(mapperClass) 372 | 373 | classfile.write('enum US2TransformerEnum: String {') 374 | for mapperClass in distinctMapperClassDefinitions: 375 | classfile.write('\n\tcase _' + mapperClass + ' = "'+ mapperClass + '"' ) 376 | 377 | classfile.write('\n\tcase _None = "None"') 378 | classfile.write('\n\n\tfunc transformer() -> US2TransformerProtocol? {\n\t\tswitch self {') 379 | 380 | for mapperClass in distinctMapperClassDefinitions: 381 | classfile.write('\n\t\tcase ._' + mapperClass + ':\n\t\t\treturn ' + mapperClass + '()\n' ) 382 | 383 | classfile.write('\n\t\tcase ._None:\n\t\t\treturn nil' ) 384 | 385 | classfile.write('\t\t}\n\t} \n}') 386 | 387 | 388 | ''' 389 | Create Mapping for Instantiated Class 390 | ''' 391 | 392 | ''' 393 | Append MapDictionary Setter 394 | ''' 395 | def append_map_dictionary_setter(classFile, mappingPlist): 396 | classFile.write(STRING_MAP_DICT_START) 397 | append_map_dictionary_non_optional_typecasting(classFile, mappingPlist) 398 | 399 | classFile.write(' \t\t} \n\t}') 400 | 401 | def append_map_dictionary_non_optional_typecasting(classFile, mappingPlist): 402 | for propertyName in mappingPlist.keys(): 403 | if MAPPING_KEY_NONOPTIONAL not in mappingPlist[propertyName].keys(): 404 | append_failable_typecast_unwrap_statement(classFile, propertyName) 405 | else: 406 | if mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] != 'true': 407 | append_failable_typecast_unwrap_statement(classFile, propertyName) 408 | else: 409 | append_optional_typecast_unwrap_statement(classFile, propertyName) 410 | 411 | def append_optional_typecast_unwrap_statement(classFile, propertyName): 412 | classFile.write('\n\t\t\tif let unwrapped_' + propertyName + ' : Any = valuesDict["' + propertyName + '"] {\n\t\t\t\t' + propertyName + ' = typeCast(unwrapped_' + propertyName + ')!\n\t\t\t}\n') 413 | 414 | 415 | ''' 416 | Validation and System Checks 417 | ''' 418 | def validate_class_mapping_configuration(classname, mappingPlist): 419 | for propertyName in mappingPlist.keys(): 420 | if MAPPING_KEY_TYPE not in mappingPlist[propertyName].keys(): 421 | if MAPPING_KEY_TRANSFORMER not in mappingPlist[propertyName].keys(): 422 | throw_missing_type_error(classname, MAPPING_KEY_TYPE, mappingPlist[propertyName]) 423 | 424 | if MAPPING_KEY_KEY not in mappingPlist[propertyName].keys(): 425 | if MAPPING_KEY_TRANSFORMER not in mappingPlist[propertyName].keys(): 426 | throw_missing_json_key_error(classname, MAPPING_KEY_KEY, mappingPlist[propertyName]) 427 | 428 | if MAPPING_KEY_KEY in mappingPlist[propertyName].keys(): 429 | if MAPPING_KEY_TRANSFORMER in mappingPlist[propertyName].keys(): 430 | propertyType = mappingPlist[propertyName][MAPPING_KEY_TYPE] 431 | if xcode_version() == 6.0 and propertyType not in NATIVE_PROPERTY_TYPES: 432 | if MAPPING_KEY_NONOPTIONAL in mappingPlist[propertyName].keys(): 433 | if mappingPlist[propertyName][MAPPING_KEY_NONOPTIONAL] == 'true': 434 | throw_missing_nonoptional_error(classname, MAPPING_KEY_KEY, mappingPlist[propertyName]) 435 | 436 | 437 | def print_default_error_header(classname, mapping): 438 | print "\n\nUS2Mapper Error: Invalid Configuration (" + classname + ".plist)\n\n" 439 | print mapping 440 | print "\n" 441 | 442 | def throw_missing_type_error(classname, propertykey, mapping): 443 | print_default_error_header(classname, mapping) 444 | print "The mapping configuration for the " + propertykey + " property is missing the type configuration.\nAll properties must specify a 'type' value.\n\n\n\n" 445 | raise Exception('Invalid Configuration') 446 | 447 | def throw_missing_nonoptional_error(classname, propertykey, mapping): 448 | print_default_error_header(classname, mapping) 449 | print "The mapping configuration for the " + propertykey + " cannot be performed. Transformed properties have to be optional when not defined as a native datatype (String, Int, Float, Double, Bool, Array, Dictionary).\n\n\n" 450 | raise Exception('Invalid Configuration') 451 | 452 | def throw_missing_json_key_error(classname, propertykey, mapping): 453 | print_default_error_header(classname, mapping) 454 | print "The mapping configuration for the " + propertykey + " property is missing the key configuration.\nAll properties must specify a 'key' value to map against value in a dictionary.\n\n" 455 | raise Exception('Invalid Configuration') 456 | 457 | 458 | def xcode_version(): 459 | status, xcodeVersionString = commands.getstatusoutput("xcodebuild -version") 460 | if xcodeVersionString.find("Xcode 7.") != -1: 461 | return 7.0 462 | else: 463 | return 6.0 464 | 465 | 466 | def main(argv): 467 | 468 | try: 469 | opts, args = getopt.getopt(argv,"hv:i:o:",["version=", "mapdir=", "classdir="]) 470 | except getopt.GetoptError: 471 | print 'test.py -v -i -o ' 472 | sys.exit(2) 473 | for opt, arg in opts: 474 | if opt == '-h': 475 | print 'test.py -v -i -o ' 476 | sys.exit() 477 | elif opt in ("-v", "--version"): 478 | version = arg 479 | elif opt in ("-i", "--mapdir"): 480 | mapdir = arg 481 | elif opt in ("-o", "--classdir"): 482 | classdir = arg 483 | 484 | mappinglist = glob.glob(mapdir + "*.plist") 485 | generate_model(mappinglist, classdir, version) 486 | 487 | if __name__ == "__main__": 488 | main(sys.argv[1:]) --------------------------------------------------------------------------------