From 04f0c99f0449a554bcc50d267510f0ca242daa2e Mon Sep 17 00:00:00 2001 From: Amber Star Date: Thu, 28 Jul 2016 17:50:14 -0400 Subject: [PATCH] [MIGRATE] Swift 3 --- Docs/About.md | 37 - Docs/CreatingEnumModels.md | 159 ---- Docs/Enums.md | 52 -- Docs/GetStarted.md | 109 --- Docs/KVStore.md | 27 - Docs/Protocols.md | 50 - Docs/Readme.md | 16 - Docs/Reference.md | 72 -- Docs/Resources/diag1.png | Bin 38969 -> 0 bytes Docs/Resources/diag2.png | Bin 34274 -> 0 bytes Docs/Resources/diag3.png | Bin 17033 -> 0 bytes Docs/Resources/diag4.png | Bin 51187 -> 0 bytes Docs/Resources/diag5.png | Bin 21008 -> 0 bytes Docs/Resources/protocol_2.png | Bin 53817 -> 0 bytes Docs/Setup.md | 30 - Docs/UsingProtocols.md | 105 --- Docs/Versioning.md | 18 - LICENSE | 25 - README.md | 327 +++++-- {Docs/Resources => Resources}/protocol_1.png | Bin Sources/Coding.swift | 233 ----- Sources/Conversion.swift | 252 ----- Sources/Format.swift | 210 +++++ Sources/KVStore.swift | 474 ---------- Sources/Migration.swift | 117 --- Sources/Model.swift | 353 ++++++- Sources/NSURL+Coding.swift | 36 - Sources/NSUserDefaults+Coding.swift | 52 -- Sources/Store.swift | 248 +++++ Sources/UIColor+Coding.swift | 63 -- State.xcodeproj/project.pbxproj | 372 ++++---- .../xcshareddata/State.xcscmblueprint | 30 + .../xcshareddata/xcschemes/State-iOS.xcscheme | 5 +- Templates/machine.swift.motemplate | 476 +++------- Tests/BaseTest.swift | 106 +++ ...ConverterTests.swift => FormatTests.swift} | 128 ++- Tests/ModelTests.swift | 862 ++++++++++++++++++ Tests/Models/BasicModels.swift | 160 ++-- Tests/Models/ObjectModels.swift | 72 +- Tests/Models/RecursiveModel.swift | 61 +- .../TestModels.xcdatamodel/contents | 106 +-- .../TestImmutableOptionalTypes.swift | 10 +- .../TestModels/TestImmutableTypes.swift | 10 +- Tests/Models/TestModels/TestMigrationV1.swift | 6 +- Tests/Models/TestModels/TestMigrationV2.swift | 2 +- .../Models/TestModels/TestOptionalTypes.swift | 10 +- Tests/Models/TestModels/TestTypes.swift | 10 +- Tests/Models/TestModels/_Company.swift | 131 +-- Tests/Models/TestModels/_Employee.swift | 123 +-- Tests/Models/TestModels/_Gender.swift | 121 +-- Tests/Models/TestModels/_Grandchild.swift | 127 +-- .../TestModels/_TestAssociatedEnum.swift | 308 +++---- .../_TestAssociatedOptionalEnum.swift | 268 ++---- Tests/Models/TestModels/_TestChild.swift | 131 +-- .../Models/TestModels/_TestCollections.swift | 127 +-- Tests/Models/TestModels/_TestDefaults.swift | 161 +--- .../TestModels/_TestDefaultsChild.swift | 119 +-- .../_TestDictionaryComposition.swift | 119 +-- .../_TestImmutableOptionalTypes.swift | 149 +-- .../TestModels/_TestImmutableTypes.swift | 149 +-- .../Models/TestModels/_TestMigrationV1.swift | 60 -- .../Models/TestModels/_TestMigrationV2.swift | 123 +-- .../TestModels/_TestOptionalTypes.swift | 149 +-- .../Models/TestModels/_TestOverrideType.swift | 123 +-- .../TestModels/_TestParentProtocol.swift | 223 +---- Tests/Models/TestModels/_TestProtocol.swift | 223 +---- .../TestModels/_TestProtocolConformer.swift | 138 +-- .../TestModels/_TestProtocolConformer2.swift | 126 +-- .../TestModels/_TestProtocolContainter.swift | 127 +-- Tests/Models/TestModels/_TestRawEnum.swift | 123 +-- Tests/Models/TestModels/_TestRegEnum.swift | 134 +-- .../TestModels/_TestRelationships.swift | 127 +-- .../TestModels/_TestTransformable.swift | 131 +-- Tests/Models/TestModels/_TestTransient.swift | 121 +-- Tests/Models/TestModels/_TestTransient2.swift | 119 +-- Tests/Models/TestModels/_TestTransient3.swift | 123 +-- Tests/Models/TestModels/_TestTypes.swift | 149 +-- Tests/PerformanceTests.swift | 85 ++ Tests/StoreTests.swift | 64 ++ Tests/Tests/BaseTest.swift | 75 -- Tests/Tests/DecodableTests.swift | 50 - Tests/Tests/DecodingTests.swift | 148 --- Tests/Tests/DefaultTests.swift | 17 - Tests/Tests/EncodableTests.swift | 33 - Tests/Tests/EncodingTests.swift | 160 ---- Tests/Tests/EnumTests.swift | 189 ---- Tests/Tests/KVStoreTests.swift | 296 ------ Tests/Tests/MigrationTests.swift | 41 - Tests/Tests/PerfTests.swift | 82 -- Tests/Tests/ProtocolTests.swift | 23 - Tests/Tests/RecursiveTests.swift | 28 - Tests/Tests/RelationshipTests.swift | 63 -- Tests/Tests/TemplateTests.swift | 117 --- 93 files changed, 3500 insertions(+), 7814 deletions(-) delete mode 100644 Docs/About.md delete mode 100644 Docs/CreatingEnumModels.md delete mode 100644 Docs/Enums.md delete mode 100644 Docs/GetStarted.md delete mode 100644 Docs/KVStore.md delete mode 100644 Docs/Protocols.md delete mode 100644 Docs/Readme.md delete mode 100644 Docs/Reference.md delete mode 100644 Docs/Resources/diag1.png delete mode 100644 Docs/Resources/diag2.png delete mode 100644 Docs/Resources/diag3.png delete mode 100644 Docs/Resources/diag4.png delete mode 100644 Docs/Resources/diag5.png delete mode 100644 Docs/Resources/protocol_2.png delete mode 100644 Docs/Setup.md delete mode 100644 Docs/UsingProtocols.md delete mode 100644 Docs/Versioning.md delete mode 100644 LICENSE rename {Docs/Resources => Resources}/protocol_1.png (100%) delete mode 100644 Sources/Coding.swift delete mode 100644 Sources/Conversion.swift create mode 100644 Sources/Format.swift delete mode 100644 Sources/KVStore.swift delete mode 100644 Sources/Migration.swift delete mode 100644 Sources/NSURL+Coding.swift delete mode 100644 Sources/NSUserDefaults+Coding.swift create mode 100644 Sources/Store.swift delete mode 100644 Sources/UIColor+Coding.swift create mode 100644 State.xcodeproj/project.xcworkspace/xcshareddata/State.xcscmblueprint create mode 100644 Tests/BaseTest.swift rename Tests/{Tests/ConverterTests.swift => FormatTests.swift} (53%) create mode 100644 Tests/ModelTests.swift delete mode 100644 Tests/Models/TestModels/_TestMigrationV1.swift create mode 100644 Tests/PerformanceTests.swift create mode 100644 Tests/StoreTests.swift delete mode 100644 Tests/Tests/BaseTest.swift delete mode 100644 Tests/Tests/DecodableTests.swift delete mode 100644 Tests/Tests/DecodingTests.swift delete mode 100644 Tests/Tests/DefaultTests.swift delete mode 100644 Tests/Tests/EncodableTests.swift delete mode 100644 Tests/Tests/EncodingTests.swift delete mode 100644 Tests/Tests/EnumTests.swift delete mode 100644 Tests/Tests/KVStoreTests.swift delete mode 100644 Tests/Tests/MigrationTests.swift delete mode 100644 Tests/Tests/PerfTests.swift delete mode 100644 Tests/Tests/ProtocolTests.swift delete mode 100644 Tests/Tests/RecursiveTests.swift delete mode 100644 Tests/Tests/RelationshipTests.swift delete mode 100644 Tests/Tests/TemplateTests.swift diff --git a/Docs/About.md b/Docs/About.md deleted file mode 100644 index 0f1cd89..0000000 --- a/Docs/About.md +++ /dev/null @@ -1,37 +0,0 @@ -#About State -[State](https://github.com/STLabs/State) is a Swift model framework. State is for using `structs`, `enums`, and `protocols` as models and has serialization with API for plists, JSON, and Binary formats. - -**Q.** What is a model? - -**A.** A model is an item type in your application that represents a distinct part of your applications data. Usually a model item is something you want to persist between launches of the application. - -**Q.** What is a model framework? - -**A.** A model framework is a framework focused on providing the API to convert your applications model items to and from a universal data formats, and reading and writing that data, typically using a database or files. - -**Q.** What is a model layer? - -**A.** Typically an application has a user interface, a logic or controller, and a model layer. A model layer is the entire set of model items in your application that represent all of the data items of your application. - -**Q.** What is State? - -**A.** State is a light weight model framework written in Swift. It provides the API to save and load struct, enum, and protocol models to binary, plist, and JSON files. It allows you define one model, or an entire model layer. Models can be composed together in a one-to-one or one-to-many relationship. - -State is **not** a database. Any add/delete/update functionality you need for your models themselves is up to you. State is focused on model composition and persistence. - -**Q.** What are the benefits of State vs. say a JSON parsing library? - -**A.** JSON parsing libraries are more general in nature therefore the API is not as tightly focused on models themselves. State is focused on models specifically. To that end it provides easy API for reading and writing JSON, Plists, and Binary files. State also has versioning and migration API built in to every model. In general State is designed for any application that has one, or hundreds of model items where you want to use lightweight plist, or JSON formats to store models, and you want to take advantage of Swift's structs, enums, and protocols. - - -Other Benefits Include: - -* extremely light weight code base -* low dependency surface area -* support for struct, enum, and protocol model items -* models can have optional, non-optional, constant and transient properties. -* models can be composed together -* optional migration/version management if and when you need it - - -There is one more huge benefit if you want it. Automatic code generation. State comes with a set of custom Mogenerator templates that allow you to design your model layer in the Xcode Designer. With a little bit of set-up you can get up and running, and be able to define models graphically and have all the code generated for you. This allows you to define, and modify, and grow your model layer very quickly. diff --git a/Docs/CreatingEnumModels.md b/Docs/CreatingEnumModels.md deleted file mode 100644 index 5da9b60..0000000 --- a/Docs/CreatingEnumModels.md +++ /dev/null @@ -1,159 +0,0 @@ -# Creating Enum Models - - -Enumerations are first-class types in Swift. Without good support for enumerations in a model framework, you wouldn't be able to take advantage of this powerful aspect of Swift. - -Let's define an enum. - -```swift -public enum Temperature { - case Cold - case Hot -} -``` - -######Creating a model -To create a model we have to implement the `Model` protocol. The `Model` protocol has no requirements, but inherits from `Decodable`, `Encodable`, and `Migratable`. - -```swift -public protocol Model : Decodable, Encodable, Migratable {} -``` - -Let's declare Temperature as a model: -```swift -public enum Temperature : Model { - case Cold - case Hot -} -``` - -`Encodable` has one requirement `func encode(encoder: Encoder)` here we will encode the case name as the value and the string "type" as the key.: - -```swift -extension Temperature : Encodable { - public func encode(encoder: Encoder) { - switch self { - case .Cold: - encoder.encode("Cold", "type") - case .Hot: - encoder.encode("Hot", "type") - } - } -} -``` - -`Decodable` has one requirement `init?(decoder: Decoder)` a failable initializer. Here we will decode the string we encoded earlier and match the value in a switch statement: - -```swift -extension Temperature : Decodable { - public init?(decoder: Decoder) { - guard let type: String = decoder.decode("type") else { return nil } - switch type { - case "Cold": - self = .Cold - case "Hot": - self = .Hot - default: - return nil - } - } -} -``` - - -`Migratable` is a protocol that provides migration and version management. It gives models the ability to check it's version before decoding to see if it's the current version, and migrate if needed. If we don't want to support migration and versioning of our model we do not have to do anything at this point, because the `Migratable` protocol provides a default implementation that disables migration. For the purposes of this article we will skip migration, and I will cover it in another article. Just remember, this model is complete without migration because migration is opt-in only. - -#####Serializing the model -Instances of Temperature can now be saved to a file and re-initialized from the file: - -```swift -// create an instance of Temperature. -let myTemperature = Temperature.Hot -// save to JSON file -myTemperature.save(.JSON, "myTemperatureFile.json") -// init from file -let myFileTemperature = Temperature(.JSON, "myTemperatureFile.json") -``` - -###### Associated Values -Enumerations can have associated values too. Let's add a temperature value to our enum. - -```swift -
 public enum Temperature : Model {
-    case Cold (Double)
-    case Hot (Double)
-}
-```
-
-We have to update our `Encodable` extension. First we update the switch case statements to match on the associated value, and to encode the value in the case:
-
-```swift
-extension Temperature : Encodable {
-    public func encode(encoder: Encoder) {
-        switch self {
-            case let .Cold(value):
-                encoder.encode("Cold", "type")
-                encoder.encode(value, "value")
-            case .Hot(value):
-                encoder.encode("Hot", "type")
-                encoder.encode(value, "value")
-        }
-    }
-}
-```
-
-The `Decodable` extension is updated. We added a guard statement to decode the associated value, and we then use the value when we assign to self.
-
-```swift
-extension Temperature : Decodable {
-    public init?(decoder: Decoder) {
-        guard let type: String = decoder.decode("type"), let value: Double = decoder.decode("value") else { return nil }
-        switch type {
-            case "Cold":
-                self = .Cold(value)
-            case "Hot":
-                self = .Hot(value)
-            default:
-                return nil
-        }
-    }
-}
-```
-
-###### Raw Values
-As an alternative to associated values, enumerations can have raw values. The enum is declared with a type and each case has a default value.  Let's change our Temperature enum to a raw value enum.
-
-```swift 
-public enum Temperature : Double, Model {
-    case Freeze = 32.0
-    case Boil = 212.0
-}
-```
-
-The code to encode and decode raw value enums becomes even simpler because all we have to be concerned with is the raw value itself.
-
-```swift
-extension Temperature : Encodable {
-    public func encode(encoder: Encoder) {
-        encoder.encode(self.rawValue, "value")
-    }
-}
-```
-
-```swift
-extension Temperature : Decodable {
-    public init?(decoder: Decoder) {
-        guard let value: Double = decoder.decode("value") else { return nil }
-        self.init(rawValue: value)
-    }
-}
-```
-
-As you can see implementing enumeration models using State is very straightforward. 
-
-A few things to note:
-
-* Model types can compose(have as properties) enum models
-* Enums can have associated and raw values and those values can be other model types.
-* If you are designing your model layer using State's Xcode data model design support, you can model enums right in the data model design tool. (for more information see: [Enum Design Guide](https://github.com/STLabs/State/blob/master/Docs/Enums.md))
-
diff --git a/Docs/Enums.md b/Docs/Enums.md
deleted file mode 100644
index c35c3c0..0000000
--- a/Docs/Enums.md
+++ /dev/null
@@ -1,52 +0,0 @@
-#Enum Design Guide
-You can design the following types of enums in the Xcode data modeler:
-* enums
-* raw value enums
-* enums with cases that have associated values
-
-
-## Enums:
-To create an enum in the modeler:
-
-1. Add the key `State.Enum` and the value `YES` to an entity in the user info area of the inspector to specify an entity as an enum.
- 
-2. Add attributes to create cases for the enum. The name of the attribute becomes the name of the case.(but will be capitalized)
-
-
-
-## Associated values for enum cases:
-Enum cases can have an associated type. To specify the associated value type of an enum case:
-
-* Add the key `State.Type` to the user info section of the inspector for the attribute and specify the 
-type in the value field.
-
-*-or-*
-
-*  Create a relationship to another model entity to specify the destination entity type as the associated value type.
-
-#### Transformable values
-If a value type you are specifying is a transformable value type:
-
-1. Specify the type with the `State.Type` key in the user info area of the inspector
-
-2. select Transformable in the Attribute Type selection in the inspector
-
-3. enter a value transformer name in the inspector. The value transformer name entered must be of a type that implements the ValueTransform protocol. Your model will automatically use the transform type to transform the associated vale when encoding and decoding the enum.
-
-## Raw value enums:
-Raw value enums are enums that have a type, and each case has a value called the raw value. To create raw value enums in the modeler:
-
-1. Specify an entity as an enum as described in the enum section
-
-2. Add the `State.Type` key  to **Entity** in the user-info part of the inspector 
-
-3. Specify a type in the value field of the `State.Type`. 
-
-4. Add attributes to create cases for the enum. The name of the attribute becomes the name of the case. 
-
-5. Add the `State.Value` key and a value to each **Attribute** in  the user info inspector to specify the raw value of each enum case.
-
-Notes:
-* Raw values enum types can be any type including other model entities
-* Optionals and transforms are not supported for raw value types
-* Raw value enums cannot have associated value types in the cases
diff --git a/Docs/GetStarted.md b/Docs/GetStarted.md
deleted file mode 100644
index ff684f8..0000000
--- a/Docs/GetStarted.md
+++ /dev/null
@@ -1,109 +0,0 @@
-
-##Getting Started With Designing Models Using the Xcode data model designer
-If you want to take advantage of automatic code generation, the process of creating models is:
-
-1.  Design the models in Xcode's data model tool
-2.  Run the model design file through mogenerator using the state templates
-3.  Add the State framework and the model files to the project
-
-![diagram1](https://cloud.githubusercontent.com/assets/84623/7788560/f75d1d42-020d-11e5-9243-1be48e959cee.png)
-  
-## Designing the model in the Xcode model design tool
-
-####Create the model design file
-1. In the project select file new, and select Core Data.
-2. Select Data Model and click next.
-3. Give the model a name and click the create button.
-4. In the project navigator select the model design file.
-5. In the Xcode menu select View > Utilities > Show File Inspector
-6. In the file inspector uncheck any target membership
-7. Open the model design file and add the entities, attributes, and relationships you want in the model layer.
-
-In the modeler elements correspond to the model as follows:
-* Entity == Struct || Enum
-* Entity.Attribute == property || if Enum == case
-* One-One Relationship == composition
-* One-Many Relationship == \[composition\] (array)
-* Enum Relationship == Enum Type property
-
-See the [Data Model Design Reference](Reference.md) for more information.
-
-## Generating model code with Mogenerator
-
-####Install Mogenerator
-
-Mogenerator is used to generate the model code with the State templates. You can download Mogenerator [here](http://rentzsch.github.io/mogenerator/), or to install using [homebrew](http://mxcl.github.com/homebrew)  type `$ brew install mogenerator ` into the terminal.
-
-####Get the State template files
-If you downloaded the State project the templates are located in the [Templates](https://github.com/STLabs/State/tree/master/Templates) directory.
-
-####Run Mogenerator on the model design using the templates
-Type the following in to terminal to generate the model code files.
-
-```
-mogenerator --model <$path to the .xcdatamodeld file> --swift --template-path <$path to the state templates directory> <$path to the output directory>
-```
-
-## About the model code files
-
-Two files for each entity in the model design are generated when you run Mogenerator.
-- _Model.swift
-- Model.swift  
-
-The file with the underscore prefix is the automatic file, and the other is the manual file. The automatic file is updated every time you regenerate the code after modifying the model design file. The manual file is only generated once the first time you generate code. Therefore the manual file is not overwritten and is safe for you to use for extending the models via. a swift extension.
-
-The manual file serves the following purposes:
-
-- extend the model code via a swift extension in this file
-- hook in to the encoding and decoding process, so you can read and write additional data during decoding and encoding if needed.
-- manage the versioning and migration of the models if and when needed.
-
-##Adding the code files and State framework to your project.
-
-####Adding the State  framework to your project
-
-####Using Carthage
-
-[Carthage]: https://github.com/Carthage/Carthage
-
-Add the following to your project's Cartfile:
-
-```
-github "STLabs/State" ~> 0.1
-```
-
-Then run `carthage update`.
-
-Follow the current instructions in [Carthage's README][carthage-installation]
-for up to date installation instructions.
-
-####As a Submodule
-1. Add State as a submodule by going to your project directory and enter the following:
-	`git submodule add https://github.com/STLabs/State.git`
-2. Open the State folder and drag and drop the State.xcodeproj into the file navigator of your workspace.
-
-3. In Xcode, select the project icon to open the target window and select your host target that will use State.
-
-4. Select the "Build Phases" tab in the target configuration window.
-
-5. Add State as a target dependency to the host target
-
-6. Click on the + button at the top left and select "New Copy Files Phase". Rename this new phase to "Copy Frameworks", set the "Destination" to "Frameworks", and add State.framework.
-
-[carthage-installation]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application
-
-####Adding the code files
-Drag the model code files in to your project to add them.
-
-
-####Set up a target to automatically generate model code every time you build
-
-If you would like to make changes to your model as you are working and automate updating the code
-see [How to set up a target to automatically generate model code every time you build.] (Setup.md)
-
-```
-
-Have a question? Please [open an issue](https://github.com/STLabs/State/issues/new)
-
-
-
diff --git a/Docs/KVStore.md b/Docs/KVStore.md
deleted file mode 100644
index 695c69b..0000000
--- a/Docs/KVStore.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# KVStore [WIP]
-
-A KVStore is a hierarchical in-memory key-value store. It is a repository to store a collection of models, and values.
-It is divided up into keys and values. A key is like a category, or a
-sub-folder, which contains values, and possibly more child keys.
-
-A KVStore can:
-- store and retrieve basic types (String, Int, etc.)
-- store type safe models (decodable, encodable)
-
-
-
-```
-KVStore
-   |
-   |- KEY
-   |   |
-   |   |- VALUE
-   |   |- VALUE
-   |
-   |- KEY
-   |   |
-   |   |- VALUE
-   |   |- VALUE
-```
-
-
diff --git a/Docs/Protocols.md b/Docs/Protocols.md
deleted file mode 100644
index c12a318..0000000
--- a/Docs/Protocols.md
+++ /dev/null
@@ -1,50 +0,0 @@
-#Protocols
-
-## Creating protocols
-You can create protocols in the data model designer.
-You  create protocols by specifying the `State.Protocol` key or checking the abstract checkbox in the inspector for the entity to be a protocol. 
-
-### Function requirements
-You can specify function requirements on protocols using the `State.ProtocolRequirementType` and the `State.Func` key on the protocol entities attributes. 
-**Note:** an empty implementation is added to the **manual** file only the first time it is generated. If you already generated code before adding this requirement
-you may have to manually add it to the manual file.
-
-On the protocol requiment attribute:
-- Set State.ProtocolRequirementType to Func
-- Set State.Func to the exact function signature of the requirement
-
-### Get only variable requirements
-You can specify a variable requirement as get only using the `State.ProtocolRequirementType` with a value of `get` on protocol attributes and relationships.
-**Note:** an empty implementation is added to the **manual** file only the first time it is generated. If you already generated code before adding this requirement
-you may have to manually add it to the manual file.
-
-###Protocol inheritance  
-There are two ways you can specify a protocol inherits from other protocols. 
-
-1. Set one protocol entity as the parent of another protocol entity
-2. Use the `State.Type` key on a protocol entity to specify additional protocols. These are entered as a comma separated list. For example if you want your protocol
-to also inherit from `CustomStringConvertible` and `CustomDebugStringConvertible` you would enter `CustomStringConvertible, CustomStringConvertible` as the value for 
-`State.Type` on the protocol entity.
-
-**Note:** you can use these two methods in combination if needed
-##Conforming to protocol
-To specify a model item has conformance to a protocol, set the protocol as the parent entity of a model item. 
-
-**Note:** Only structs can conform at this time. You do not need to re-specify the protocols requirements in your conforming entity, they will be inherited and implemented automatically.
-
-## Using protocols
-
-You can use protocols as types just like struct and enum types. A protocol extension is started for you in the manual file so you can extend your protocol if needed.
-
-You can compose with protocols. For example, one model item can have a one to many composition to a protocol type. This allows you to add any conforming type into the composition collection of the containing model type. 
-
-### Example:
-The following shows a valid model design for an AssetLibrary. AssetGroup has assets which is a one-to-many relationship to the `Asset protocol type`. `FileAsset` is protocol that inherits from `Asset`. ColorAsset, ImageAsset, and SoundAsset are all conforming model types.
-
-You can add any of the conforming types to the assets of `AssetGroup`. When AssetGroup is serialized and de-serialized, each type contained in the assets composition will be restored.
-
-![](Resources/protocol_1.png)
-
-Notes:
-* Protocol requirements can include other model items
-* Model items can have relationships to protocol types.
diff --git a/Docs/Readme.md b/Docs/Readme.md
deleted file mode 100644
index d279ddb..0000000
--- a/Docs/Readme.md
+++ /dev/null
@@ -1,16 +0,0 @@
-#State Model Framework Documentation:
-
-###Topics:
-- [About State] (About.md)
-- [Getting Started With Xcode data model designer] (GetStarted.md)
-- [Model Design Reference](Reference.md)
-- [Enum Design Guide](Enums.md)
-- [Protocols](Protocols.md)
-- [How to Setup a target in your project to automatically generate your models](Setup.md)
-- [Version and Migration Management](Versioning.md)
-
-###Articles:
-- [Creating Enum Models](CreatingEnumModels.md)
-- [Using Protocols](UsingProtocols.md)
-
-Have a question? Please [open an issue](https://github.com/STLabs/State/issues/new)
\ No newline at end of file
diff --git a/Docs/Reference.md b/Docs/Reference.md
deleted file mode 100644
index 4ef47af..0000000
--- a/Docs/Reference.md
+++ /dev/null
@@ -1,72 +0,0 @@
-#Data Model Design Reference
-## Entity Key-Value Reference
-**Note:** You enter the keys and values below into the user-info section of the data modeler inspector window when you want to use the options.
-
-| Key                              | Description                | Values            |
-| -------------------------------- | -------------------------- | :----------------:|
-| `State.Enum` | Specify entity is an enum. All attributes are considered cases of the enum. Specify raw value type with `State.Type` . *required for enums. | `YES`, `NO` |
-| `State.Protocol` | Specify entity is a protocol. (**note:** you can also check the abstract checkbox) | `YES`, `NO` |
-| `State.Type`       | When used on `Enum` entities, declares the enum as a raw value enum, and specifies it's raw value type. When used on `Protocol` entities specifies protocol inheritance.  |**For Enums:** The exact type for `Enum` **-or**  **For Protocols:** comma seperated list of protocols to inherit  |
-| `State.Model`       | Used for raw value enums, and specifies it's raw value type as a model type.  |`Model`, `ModelArray`, `ModelDictionary`  |
-| `State.Transformable`       | Used for raw value enums, and specifies it's raw value type as transformable.  |The exact name of the transform type to use. |
-
-## Attribute Key-Value Reference
-**Note:** You enter the keys and values below into the user-info section of the data modeler inspector window when you want to use the options.
-
-| Key                              | Description                | Values            |
-| -------------------------------- | -------------------------- | :----------------:|
-| `State.Immutable`    | Specify an attribute is immutable (code will use `let` instead of `var` for the property) | `YES`, `NO` |
-| `State.Type`       | Specify a type for the attribute. For example, `[String : Int]` would specify to use a Dictionary of String, Ints for this property **-or-** Specifies the associated value type for enum cases.| The exact type  |
-| `State.Func`       | Used on `State.Protocol` entities with a requirement type of `func` specifies the function signature for the requirement| The exact signature of the function requirement  |
-| `State.Mutating`       | Used on `State.Protocol` entities with a requirement type of `func`  specifies the function is `mutating` | `YES`, `NO`  |
-| `State.ProtocolRequirementType`       | Used on State.Protocol entities. Specifies attribute requirment type for the protocol. **note: if not specified `var` is assumed, use `get` to generate a get only variable requirement| `func`, `var`, `get`  |
-| `State.Value`	| Specify a default value for a property. (only supported for non-optional properties) **-or-** The raw value of an enum case. | The exact value
-| `State.Import`	| Useful when you need to import a module in the generated source for the particular attribute type  | The exact module name 
-| `State.CompositionType`       | Used with one-to-many relationships. Type of collection to use for a one to many compositions.|Dictionary, Array  |
-| `State.Transformable`       | Used on relationships, Specify a relationship to a model item uses a transform  |The exact name of the transform type to use. |
-
-
-## Compose models with relationships between model items
-Model one-to-one, and one-to-many single direction relationships to compose models and enums together.
-
-## Enums
-See the [Enum Design Guide](Enums.md)
-
-## Protocols 
-[Protocol Design Guide](Protocols.md)
-
-## Transients (experimental)
-There is preliminary support for transient properties. Mark the attribute as transient in the inspector. Transients MUST be optional OR have a default value.
-
-## Transforms:
-
-### For attributes: 
-Set the attribute type as transformable in the data modeler attribute type selector in the inspector window and enter a value transformer name in the name field. The value transformer name entered must be of a type that implements the [ValueTransform] (https://github.com/amberstar/State/blob/master/State/Transforms/ValueTransform.swift) protocol. Your model will automatically use the transform type to transform the attribute when encoding and decoding the element. Add a State.Type to indicate the non-transformed type. For example: for an URLTransform, enter State.Type and NSURL to indicate the type.
-
-### For relashionships to other model items:
-Mostly useful for using transforms that modify model items during encoding. To specify a model item relationship as Transformable use the State.Transformable key 
-in the user info section on the relationship. 
-
-
-To learn more about Transforms see [Transforms](Transformables.md)
-
-## Optionals:
-Select the optional check box for an attribute in the data modeler inspector window and the property will be implemented as an optional type.
-
-## Default Values:
-You can specify a default value in the inspector window, or use `State.Value` in the user info section to give a property a default value. **Note:** because of swift 1.2 bugs, default values are not fully supported. Current limitations are:
-1. Not supported for optional types
-2. Some type inference problems can occur but will be caught at compile time if so.
-
-
-## Versioning:
-You can add a versionHashModifier to each entity in your model design. This value along with the versionHash are imported in to the code generated and used in the migration scheme of state. For more information see [Versioning and Migration](Versioning.md)
-
-## Data Modeler Notes / Gotchas:
-
-- You must enter a class name for entities or no code will be generated 
-- Int16, Int32 or Int64 are all implemented as Int.
-- If you enter a custom type using `State.Type` key, it will override the type in the attribute type option list.
-- Do not link the .xcdatamodel file to your target.
-- Recursive type references are not supported  with swift structs without boxing, therefore be sure not to generate circular dependancies in the modeler.
-- Even if you specify a type with `State.Type` you have to still choose a type in the type section box. (it will be ignored) If you don't, the project will not build.
diff --git a/Docs/Resources/diag1.png b/Docs/Resources/diag1.png
deleted file mode 100644
index 05eb64e26e3792fc88a330f2d5a2e443c72fa430..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 38969
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

diff --git a/Docs/Resources/diag2.png b/Docs/Resources/diag2.png
deleted file mode 100644
index 92bdd10dd454fde6bd4449d54f3de2948a0c7541..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 34274
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
kW$*z&-T&J*ZZY}NX9jK?3L=X^|b_)>^1t}2`
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

diff --git a/Docs/Resources/diag4.png b/Docs/Resources/diag4.png
deleted file mode 100644
index ade6662c59c8dead5fcb39b568e32dcdf07c6260..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 51187
zcmeFXWmsI#@-7O5Uf-}P~cgSz=
z{onW8=egg`r*rtinqJ*qUDefZy;Z#;loTW}F$ggb5D+k>rNmVb5S~>cARu0%p}<>4
zIw6h-2pAmzF)<}+F)?x_CwmKkjX45>R77$rs?saK>w&J*oY9v6qYv!cAGB+?c>=zg
z;UpWQguZ{-i>xLW9?sB=A}-ESv5yh{)f&M}8CUt`M^L+t%C3?>W9Nb-X
zHE+uduB#0@{Ge;|>zdd02!p+HLc#9DoD;f6_yYDCcWIql--Bug-7y
zmVewMV^XWkBcU~t!rP;_tXfs`@ySV0Y)94M^CB1MtdeL^3o#!6E6VaSCGp$4DkT0c7!)*h-4k6NG{&t
zcyr;!Vdrvt)dUW_(iE-yUXghFFG)vi-meb#OrZoEu=7HOgeNS<2*uk3$wt1QbiXIV
zblNqQBSB#5L=FH0go-aoSDD%nn`egbUa(o3PA|VULPQ@#c%Ju?BLIs9xwso+0f}Y<
zr9Ds>O_U}Ag#qzJHVtOB8K)LDSCD`bf?JSp-Ya6n0TC)5%(1Ut6UbFxi8iqIk+Hk+
zCs0v-TC-pX1xllRJ;!8bs!KPYiFGnRtvE=BA@l?YAeJj0JrV^~{HLofN=a7%W&5a6v
z5FcCFkT$;cM)F4VCV?REheLyVH^1;a%OV-WeiI|xU)g)oP0};_JHt`G8FA$;X`E(%
z=0^6PPaf0;!Q;JT-MKx6Ki#)b|KKCjeWm^xxgi$*{v3@r*rZ3g$6S=#IGjZ~iRuuS
zB;u1emm{O&n?F1?@gAu>Qdu8{;$KRQ6|$(X0oY4})x=sAykx-SR8&QbJLC;=kqpU<
z>J+XLhsA1LGnTaii)qKwu~bn*{6hrW78jHks2CyN6&(wHDTya#C(#dc4m%GAbEq%L
zWxNNatbNd@)~8uzgldG+7SL=l)u~X+7HjQhjq0a!*NSWVYAb3NA4@E?~fiTnubi4`D0emSN2%4u7}HCj}Y+vFJBmy?pf+
zV+i9p29SX7l?1^K!5caW+A8Ibs_lgfl44)L94L&*jZtnXb7GKM5#K<_*Wl;NZ)QI3
z8?aOrmTea&hgZ}jC1O^U?+%R#$RWF)!UM
z&r$cSKq-G$9#T@N%3nNJ#Z_FDe_B4KDV*mg4~;>Q@0F+2E|A))?GL9`pZ=U!u3hN)
z`I10C{!~G+D0M>jpg_k;$4|$kvOtGKCvgd7X>*BpsbOi{MT+l+FM{tgA0uBuYeuWA
z%lwhXksOvlIw)KApLp9
zPTFi{2j@Iz9P7I2n#JR4Pd~-%@8&*ySx;I25#kYvkz0*^jgRGQ<&e2o)?`QWbC`2y
zuhT!uXt{VyiV>B8@G@<=7`fJMPHdhxayC-BwYoXFp`Li15F7`cxG$``bn|)e*f@Q0
zx;y@IMC&AQbeEb~sv0>h4czQQiNb$PW+<>xaWd*6bhxr7>K@^IKU6fXK9YQ(a|-T}
zABZ_|>#-eN9TZ%ICP8$uUtk9gJdbl!lpM#*0U3m+R%>=@hBdXjH@lbKI+NLw#VR(8
zmsH1`@vU13R~QDYlXe+|@&)ykm_&n@@9od+G09PbQIb&F(KxVPA#*VWrrt3xwrwA%
zbQHB0U4J4E$F1ky*Z%RzLE^l6#9`!XYBHnuJCk>{LWPV;gst>fX8S;vxF7n)ianUU
zeVdH9Y`8VJ>bP6+2Js>BzRJ7GMBh)v%f+1wh)m8|aan0h`cu4_*PDD;=BT-t8!bbA
zMshOPRjO&Hw_Z%qr>l>u@BRMa81G24)yWo=wliAeA@T6@PC13fTKI@_IY$2%skDOv
zt=wA~7ln^<#JfDsH%<}>dWn&VYYu`fMJw(@enXN81FBzD=v9hUC{?Ye(EyHsH=Y;m
zuMDhPCBPY1Or7Y$aqFp@X*JBIYB=OP?}LLGf-xzct3A|5VfN|vLDQMi&C~JADK&C+
zDVsu@ihV2pES*?~)%w)>8H8yM=*-s|SVMQOp+qa(#H(nw(d!Gf(w3^H#XoJZjJTISrTE6Vyikam&4R
zrXRGlOn0q84O=&HDZ(iaJPquQmIF-7`eE){ZkKMi$BwJ2+O(Q!>O4Q(ht^styp;VW
z2YkzKR_P7Ye9VLaT^|01(niv~h^x=quzeWi>3x-Ul{LJTPBw0Ww!#*|TCv+ms(8Qq
z6>bcs<~9op3LJXZSLt=N-@QH6+O0_)pp0#T+Q6J=(Ub9?({!qz(}U^7=yl7F%gPkW
zvRBkGHKWQU75Z`x1x{RB^ZV;}zc5xdZoK576uLZ2Z8r28L&>t`we+vrZC|?&dQx*Tl(~_EkJI38_IN&$y0W-dHZs)>j(cMr0ZJ_aODL
z*}xQaM#ZYn`fcm26%AWn-Pf7iK6ZN6&h~9i)AttBj03uF?3dT8x=g)+Rjb9&9(%4X
z{rw*&C2iL3P5IOLbv4$G^E-C)r{%Zpr>o85&Hj5or%?3;HwCf1O}!zcwPaYrGQL-*
zj=Nh!G>eKgikG=VLJWRYH|-DZ1?$!j8wk_2_jOYjn(rU80M2tT_9mGjs`CU?wTv`eSXqt!Vl?0P%1U3lkF;BM~x_^gZtWV0CfkOfb5O0
z&AS(*-j8%A)7u`8!588?mXL8P$KFr5p~zV6m-z?mX&s<`-04$)ZxgS@0S
zA_Aek8X*8L#tKzUGqKQ;^D_EV9iM+__xhiTsvK5b1o{;Ov~d)2oLSm1<@u4E*}3Ti
zx>3yTxj8%-5FNj=(!x4kc_$(}Ed!i~h0uu`VE?tWbVy89bv?EKB!ra5YpPMMNQ4Cq
zqT|SWzg^4kX1ll{d`zZxi?K~w$;t+2wb=kQEf+0$IX+W+TP9;OdlPde4_gN~(M3QI
z@Zf_#+M2rFbpklJ0PO9^pXN0-v3GS5q@Z{b^q;?f)@kkm_#a7j&i_&i
zt|0T%8)jA}7UuuV4Ie7-)XJv>@G!U05(n6t+d0E!2=Q{T3jFQ=|9SI268~$Y_Wz9J
z;N|`Ak^lAPUn2#WpA`5nh5oVD-&VM}gfIk{|6_U~49~*)WCR2e1ZnY4Y95Hk9oRPN
z^Vu6P(DCRm>B8UNf+sj!qt)IfhAb%?TVcdVzmq5aLXr1r;|uK%V_nIJNcQ8$fFDJ{
zT!@8K3px}61eMZSed5xA^0E#VpINoFR?u;a^U_3Hn@>L=P9ZO-TS>Mh`0shI@sFQX
zLmyZ7Zcm}aLw;wg-eb2}m%Qr`!CUX~T<_jIbkP6=WO4*VG!X3Z?u?|49GBfKhylFY_|5Du?G_>4IMcsm+S&+_t6yeP
zxH=CETc=1(Un~W4==9(uTG#rRCeHjaFSYfmDp%#hI!=B@vRW2eJglx_XlOqyWM~yu
zS|>sE585E0zr_2CSmYweVASO!vk4dX8+%7@#mLrMY*HPrSJjn3VQK@IBn?Vxh`E;b
z>}*iKedHiPDXGm_3t?t4Q1H;lWhMV?)_MtbOQkPqKAHbdo!5C1<8LMC?-63vv?Srs
zDVkkYHHAt;+OD5Jb8h-Jy=F0U!Wn&d-q6%BCG?xG*ZIr8#NWCbcwF=O!jjT1y$G8$
z(p6jjqWyciGQxiTG3RIB?UpfbEGQjWXEa#0x@y|!gP>)wd|9t;Lsv%g;_xkQ^qEw<|pzengX3`Aw_pV
zo9pwfMUPSJ;)agP_~6t#?{rJDgW#5_4Zt+@mVRMLv=;dSOtBZX3LU+kCW)R<=(1yz2!Z49OUR4
z)Y?)`pKR7dEyfQ@<`u$IrPMpJOCEaBxYWFiot^Ob_^J1YZnP%-8^s3MY+h%tRk7Nd
z%Y+zwu)Dm@Q5P-4#|L$%!o9MH>SKAn-YYeT1(B_Fuh}AAqJpUB{7F(&aRQq@SW+4Bw
z%z4C#*J^CmR)}J?EpnP6BEIkK-1|WyUER&!)KSaQ$vrrnJ&N
zsVXW=H1?@M|y19Nbm-SIOvewdxr~JXd_FDr<2f%Eaf#}S;r=Ptb
zc}mTYQVh!=T`i-ui3I4jbg4_WK%wxvXiURXbW_tlHEI=9GaZIGok3;2a~N^Lwc3h0
zN6nWMy6M60%F_dq8>uSGW(MiMF^`eIuD6jcf8eUUzfF)cSdL#&c31An-E*rZIQq_P
zms;)(s^3g2-6$SwkS#n?%Z%wb4eS^qEB-aK{V#V4LQt?~SxVOtg$MX>N)}y0ke3){
z8~=D;_B3bOQM6{O{!LS5q@a7HESH_2Z7gHTZt-Hx-gm!Qt`jWYPt|tuRUZl}m6a(C
zN9d2tZxvkK`l9h}mc~`UO%{6=M=nhQ^#TWI&Mx{Wt^7rwu|Ha;_P>gX9Esj)_1{xi
z^ezYD|4R|@u_6`qPVOqvt(PM
z0&c8gIo57UM}GVy(2_&umZclTt4*|^!qwXR=FUTUvTMYAD21`s=g~p$`_?7NUpDqt
z1Odp2Rw+mF!ni@o-Z~_v(+;Win1e_wO?gb-o^lL9=
zaTycN{&J@cb|g9M8|@$!k|&Oyj?1DN+!R)f=1wH621Gfk9g?VvWz(i5G9>UL7zrGV
zZ5;ZY{-#xG?{yu^T=3E`GB$@Np7YgIi=8*qqRzOuJ55nqd)6RT7hxT4vhRKLqI`49
zR#tiyk#6B|nV0v*)Q>S(0I`+rPRMN=tPX1~#*^-lpr8^DwJfC^XyPer=
zuT(fYBBj~f4{)*3Gm2xf9<{^&z%RcbHQ_$8HjiVtNv~Zc2JUAxm|7_{MEi%?2G*l*
z)ECD@hCls$kj|?po3kUGnK}>PNXu_Dx3(OJN&GzDrk6stV2@q@F^yaoD@)cP#|zXZ
zZtuGRAhO&m?Kd{V93p9+VFX=U=ogZ*o&Cu&OwJtP`QUlgxd`al)V%wU^u1j}r&lZz
zJ3S0#)sdeJQ;(lUcURa*vZK7II;P@e23PM0((v&cxB(T9OO9~=B#EjibZYiwMexCE
z$sr#F#cLCB{N;{XTPN#(h^W@8&-|--}%|O>$
zyPsy-njKnPne$uG%+NfzD=!?mRiiDh1
z*@Oy9AN7=(oTy)su*r&x@&)PC
z55JJnJM=kqIv0_xrOWFZI_Vi=?UEsOtMslTbAx#7jNaYtSbKoBD%Gv(_zsJ0XIi!4
zlqktU=bmRyE=Nc$uGS3|OKY^8JLXP9(RS6&=P_IU7fyzNH5@$@og_<1W@
zD;$N2O$Y1lAVQed^KFisE*7Ue%k=F!sy`X{f)Ot*4W75#B+q1`zDjLvE8Lm=@jGoW
zs>yz|l-QB?68|qu%4BzwBmM)J;(7k(6B&n}wqC!yxx!X&>jJJ4Cw^id=6&nx@dN0a
zF4ze(xtdgJeT)L4G*y?qD4MR{>}oa7M2)-BBf%qmd_6=-Z$~SCZM6DZJ&6A{_pMxl
z)x=9F39~kV1mDI*jC6426c{s+x+=Ej`N=p-*H1LcEslXmnUdSux4Ze%&>)(nChR$?
zq$V#1`Q`Wz0$CGLL6D|unF`C*+MhR+f~>Y*RIhGdGRY27{u(?^5NP(?d;A#{agM5=
z$!K?mZYhvq
zIt0xvxSS&YQ&|vkLmuVls!kWiG&kSbW#(u7q{!)TqGKjwqusKZ_8RBXPnEr4VTyZW
zME2#QQuavUX!L8K=3ad_4*Fm7`G_L`XC-5#)&G|Q#$5~o5$k>B=ThvyjQW2n5M;RB
zfNNz_6@vezvf)P=Fn!qcx=84s-U`Oc)NJ^!oEf7A$AhsP)I|5gRM4Z)S7i*rCAP*MnT
z%zocX_DD|V|4;*sN+}wEJ?sffl12J-?d5oH?`GOJb}=w8oVW|RjW9Mzef}H*jTYa1
z@z=Jm2m)=6yOw+!E+;o*`A>16&Nu!S+e4GUd#t~zQpt!w(D%qngeR7liAtsE$pZZ-
zzS1%q+P&p?&zvA59?n-><^cv`q{>WQXp;czZ`Zu5JJKhK-no83|GODVJV*rq*mYp>
zlHala=2B+Xlab710{kdcO+up1yn&oL_iNr~f=7kay^tbi-=WxVeme|?HCQ{V?&~D@
zpzJu_w~v3SVc_bi^>urH=&5^GU9Ojnk&(#b-GK1Y_?=7Bx?fufKELe}2jq=^&iY@e
z--r;IPr8Hvu#F&W6O0l!!%H6+^!8*l>+X`NHuhH;bRfc2{4N;2%Pf4zGZtNt)3)zI
zUmu|divBV>-y-m7WVE%@d0-p%kGu91e^l<#uJCciJ@0?(09H`6qmX@RLVRK
zv&wpkRO;_IS{@#^6BUm^@`i@F9qH1$gM53})`k$mf*&p2)Qs><&;zN@0wxT-Qk_K2
zI2<)-c6gufn+5HHJwouu9G^H10`i4yH*eX&9lGg2Z1S>Q8)Mh=@Wf(2B&axX(g$JR
zoqE2V>GAz*;G{yCA9HA);`a6K&aVi3bj73V{?D*0X@P$*NrGBQ=El(0pN&Q%HGv0J
zL-?P4_$G|Rm#{QB8PAee^h}H0Vie~ZcSXwT(Fvr02NkE_Hsq-Ut3j{l4ddQTxntbT
zR{PCf(tL=}V(0&^sHMi+*4DN&n$8~oi!bDEQj&~7!jMwx4hilep%$1r<;$Z{}h
z+SnsIm~eXK;VJk1hKtBurgI2if3VaLUu9V^xPE&gUo2i(oumf_p6{~DP4N&+%AF)g
z{AA{8)cWh_PnaPy&-ZwNf+}LxFdnH?HYNqbz#`aik?DjEC4Z;JSOrXfb
zF|67jdNg=}d+bm5h1MLt`x2Q5&|rVm7MWqdEWn7l>%qy)Og($n^Ky5QcfY_l-Xpz>
zuM!oTG}_Ui3$l8)%KUx~-NOM1%bb%|}uq?5bXE
z=S9^RdY?25X3*%LwK{By&b6Uv)0OZe`$!-_a@#-6K6YJA$;Jy}|9}ngI=(`}ITsGR
z^Ao*ooP3woYQ{47vl=Qs$yW)U*$#PQ5H9yTN6@=bU0i=&3}@u?JpX}&8lekNn#6U7
zllKcMe7%S8_4YR9bxz5rM!UGVErl;JKW+&>Qr`G`*kr-&>?2O@=b}!w;R{(_zfs0?
zE{`OGM0|JA@&6NL82$*Dc>hQ~DmkvfdF@-x=L!zO7WzSP^BxpFRHd8vg@X^1n=fit>l$c+Oy6Oy_TvRGB;9RjbCzZJ^)xk}M69
z-T6uNCbwiD^+EZ5wcmC5;PVRSh3irXW7A4PCxXdemh%~D0d~A;3ahh}ltB~8b3ywe
z{3kK@LENSK8Ri}OK~pvv+|Z6X1;C(#CH3sXvVw}>EA;*8q?6^Ql{o^pi9dI04+w_$iIc$>D7m%vVB_-6lun
zj3%-NAn0{f@-Qt7P5fLPdwAP)^~s;Zd$-;qCs&2Czp38=1%%ny`@;1$BWBuIp^yUz8{k4{bLXT1+CbS5rV
ztNIJJQ;u-JTaG{4zw`-vg1II5#;w(hTyd}*cX3C@V<4iv3Kek?&d;o6(y1?Dc?S_l
zRXL`41WDjal!hr|K?{lcoR8N75pp&VPaxlzybI*ttHG-H4^%(gr~Cg8+cC`)H~9Q+$KUX26vDyiio#Hi>Z@T=%i*M=ImK5#
zUJh4dh6=cg#e79VJ3Hc6DDt-}&T$Vw*j4U=HV?BIE*!_q;O99Pz4GB#-{W2wr3(B&
z_u%B^(!Si=*OMvArQMfeheBRM&gMz*~)K%~k64F=Z~VP!a&Vxzd2+6`??t=uWP
znm?42n|lP6%*V(uqz(=~#8e5yPdhybw=5<51s}@Ix^>SWd>ftKiwMWR=y)h(yz%?Z
ze4z@8FWT3bZGHbu0lnXtBt7*F>(y!{7z5e%ne7Yx4TUEd-rz($?wSvlOo@Y%rQ@=~
z6`Q0K5oYx|)*tIzQ+#CxH_oYHYnqOG164E@qPi5fx)!&kiRR`c0M#i(L
z+O&wsK9UF!Lm&A_D03%QzW5Wefg^rfLrqR-1hPqeuJ)A|o9uIKWBU6gUaP)|H#qDK
zg5%mE9)Re8TK+G~yr&3&j=vdt82S0QmrIBD9wBfPeL~S}tU`${vL^T3hLT#J{eFuK
zrsbl1HdQ2B)Y#allr=>23`t*K|N9Y|3tu<3|D9OdCsmXoUwn0-bQkny*{!nL4kZs<
z-YOd)LXQLn({|Vu%V%0x((l`gK6x4k$NRw>vP?rlKAn$6YP!{2k14u#HMzIz{#`4M
z10;Pa?Fk=Iq2d4zUDj*-9G*(A=`OofzWeFi#}EFHCV!%LlMFGt=mvC#UI$e7ss8tG
ztiywDu;$_1XxvV!s8uFFgb8`Zb5^(`9o?z>F;(LT74&F&DJv@+)l&b&X7)e!c%OAN
zrA28cnHS{J4qHfTmzW&T2srAjezh{NO{|4R9g1JQp7-jllvp_Xlv`V#b8~gIP<9CE
z?z~8@9`wCkrQu$6NtDatnLI-)F^olK(rYG%LZMEFGjx#CEjU;)D3fTe7U|{=qOuyn
zWXorROkg$lMMbH7T1#qNPYm#;Ga`QeN;k%j!dIgYr%nqT(Qf~1dlz_Qtv+*a4BRkL
zYT6t**Yv;EWHatTZmUw~wwMBjB_}8M($H_#@ll!ghGJg8nZhDw&+d3GGwgI7%3oSq
z8qa^$j-SoA*~n-%Ionv;S+eGHnYo_CYT7>t0~^9*!C>$q5u4dHY;_r8VlJzyO37P%_>d+cATG>G@%?+0
z(nqMcLAJ)p+s6_Ad*%y&*cmJtj$2uiW#3iXW}Z)F_jKO%F%P$$by`c3S&pV{j>J=}
zIvmmn-$%?&mZ}0HJHG;^3Z+YbI-no{a2!zdvo*8*Jnk>dkD3qneU)-LO<~hYNfa@^
zEg@vKm#!!v|A#mjZl+?#9?s=~{+1QlO{hs)FX>p(unyS8oxgHfnP=Q`LcRxZ3T%l%gXL+0$QYrmh51RMJ>{@=X
zSqkx^AhPO9wcvn6w8M{tu03ZdB)M
z*;MpD5kJ%UH#_r%^
z@Lnpa$REZ4XdI2oQWw++w)OAn$=7zvN%2IH_h}xA&wp`CP<8nFX`ufWM0D;FdY4
zXLD>P&*NHW#QakL8V`L373Z3X6b5~{!sq3$?1KB<$Hg#GuW-$fS6#71`l72#zBk8<
zT%Fci_4seJ#c!E3d{G$?kwU1?W9)r;ElT;FA&flB0nl5`k(5^Gz%E3VOtzBi)S&mk
zxHMUKeWxgQkbCm?H*P|xxPn5tkl}whgZb<
zswI5GGuQ2-xRylX8T7G3XA|tKgJAn7DCLzR8?5OZyV3X>TTs8p}pHpB^RJ@qo
z?qigcoLFUWka4V^b$#2k=4I^|RP548oj3mtMPK(M3~mQ8hFHBYm3r91L;P~`Tljpp
z#0q2`<283q@Q~ff_2;{I$T3Z=n~tZ~@6Xe3az{mlKM!#u&KvKqcq1W8M0LY6OWV5B
zlM|9kifvBAV}Aq3*Ofp1&i7p%C_*s0>dfQ&Qf;R7U>EXz!@xRHK?I~
z0cO<5-w-Oo1)l+a#=roKNky~c`WykzsRY-{R9P~1PN~!YYiHoIgJMcjIIF-$I$d&a
z>?UjY{`vsN!S>XJJe%VeylV1QvU?HDlKrbBc{8WmQ}g->
zbH#TJAlJwrD8Ls#3q)exu2(bsQV)$j>k
zH7?t|K=HIn7ZF+ZJ6@>Kc=LE3Cj235?}>&9BQ5yD8US3JJ&%@RF&sE(C~ziZRDUVe
za0U0TLBQYeQR?c|i&%>7$B;o+y
z59FqkE$dVGsFZ2&p8>LE&S-OU^9sut`*eiIx%VXW*AlN=T=K?(+g_
zrBDxdSnx<%=xaaDLD@0^Z+tGPI|KEcHc3
zM*3_=yd=YEhI2w&#*2I8K2)s|q`#c?tc@DfBDw&}!lgh!>V&i2&GOw*S@ZV&CnfX`
z>{}10ZD}YTIKoG)ei0)jXet7U)8;>UIcF7IL!0h2=mwqsmRyBC~xGI>Q%(2?{~>W`qX@B~e@jcp-oAb+ttmUxiZ|4V|a3mn@)VH;K*KEy}8;<5F%
z#d%6Roy#^uEjj{ZmUos`-$=^!Ib8M?<0jZOz4?dqt~{q>&ow^-ei5s5dO>2$jr(i_
zJU^T1yxE198{eM%zTo2
z8>^8&$jylK*%H<;L%Ag740_w<*L>FMBXnwSzLvH=^s{c>Tt_VNqZ&~rg`TjpQpR%J
z$gh@|i-ihDx~ev!7$_Mf0X~q>TUh<~s4vD)DYoHh+ecIS)1(ChO4kPyz98thq4i6>
zv&1b_?BUK{`{DE#UgK;M#bfCVn3!=x6(4RX?nheA6Hu6LhxSbAojTnx44s_hKIhRw
zBGf`a=N@H{$MCn#Fau+7bjb8sy^!ctN9-ERe$`8Bw*vjNL$MPQftx)yE(95EjJZss
z#N@OxMA>$bjXK8O6Lvk-)8?VmPF<&IORY-LAhHkq$bq$?^!A&(fi@$y&@3r0hk4}N
zf$L_d_3BlU9AJg2%g4_+8lS~s=SO{ga~7qvX=lZftD0ZE!{J0tAVY0wgZaLDnf=!5
zVW28!cKJFIAe_#*EV#g3&lL$c>;0&?#4SDYC;lRx;)UjDV(Ac5NPL2qk3n_j+#Hn6
z{GKq*S=6T!{Z%e>o)F8D5_Nln-Je-jcRa)6#db^%C)-ZX+4d$d8naVCefQDE7z1^3
z(8hq?YORUW=Eqyf&eP(-s)8=!Io!st36E_|keqaK2HmEiu-qys!h!{C6WHan=pMEZ
zLxXJCDQ&YTbstTUq7i>yGHTK
zQs_4HVVa6s3tg-Yw13^>cly|Kz1uG}_5zx@ih
zzyHeiXJl;B{PT;E>n#rYISC2=3QVV~-%%#08Uty#42vI5Aj{jMFJ72?RRFNwcloJg
z#Prf%WI2keg98*MSl>Uk5`81Q}1O>um)p2Fi?jUI;mEOjT(P3c7f
zfyG_nC;p>1+46IC^W*iOiRbnV_~{ue6q4D>SMt5%X+Rx=f8?Xgj_OJ8Co9yPhZCfk
z`c0oX{TvOLu%^FhW$dp-X_NEo+-0+0RI%6CAT02WGpi?wV9=#r_S8m^q7N{U%kR4VO0B1yGvK&aR17cRNYk{6%n^Z
zRyr1YlEif1Lx@*dbJpEE#SM66`67tyLBtPUXIuab{n>*)cxR=X7`(3LR_;p7971gI
zxv$mZQq}sc#)dN6-R7^~x$Cl>zUZP*_$ht-&MglL2FWyR&9L-n0a
zEatylEF7IGl%{d$YY4!`FP7-15!2P;(hdxV)ZDxGVde$%^N9xDo4{0yCI6|tv|SU2
z`HAazrk9L`aY56Ig5EcGqr105bFH(DJ2~D*-vw9)cq_bUU6?PHCT(wgMkpDjPn~=C
z*uD!kQi$FNV)7G33a|9y{JL7L
znZj?iOQrhPZ)w{6$=CrYAG5d_jOk2N(%-E>KFE_z1i{aYT@|>pX-!8j+ya!y8G~6Y
z$LPeiRzu9ge3CgfJc`+7CTVI@Gk&~mh5d1%MqWjznV4PH;3a<^$UY~UfMv8gl2^V~
z{wzi=J+{xgvbT_7R@K~C60#L1%=Cre@d_xc4RoC?Q?G?rOgtecO`mgL!n3cjGjF~A
zSYJJ?E@vfDGVfHm906@=#WZsFbk0HBKintt+Y66LS3t_oQbB#9(Qa7mzll~h0YXnT|
zW~xGz&U>4e%8oIV7k65eTiO8c8{^E|V08DPL`VWZsWSRK-^)O`s@(4lFxKlAycG<(
z*BkT);Pd-nzy{f
z7MsSQj-9bX1C}04r!0<38qSRQA$Mcvu12THIUJ5~!%|Puk@A>=u^YM|6!UWH{E%(q
z6V&?ZAJA_7i@UL2R%pP;?P4RB=facktZ?3VU$|4R%J63zcg?)hg`G2qH42fm0=#=Q^8c8EbGu;;R@wP
zZzC<`t(#Y?)@fBO8S8~zA{|_s{WhET83!X
z+}hBf{s_NPyS?an!8|yWcpz-%;3Tud?u$891A^A>|17HY|4F}iy<}Z$+KZ$MnvHu1
zB979-_q{j{=F?vH(y|A*^{Tve_AE|+(CC6Jdyb)Ly{wBFjSw=K9z%*+gbo`ZYv|kDF^CZSKQt=I${4!
z-@e^^%L;v-xh#3$7ISrUL6pose%3L7n
z8hg(n@!To4|A(PQ9@_FW0m
z1L@_B=|_J`+W%y1&g8Cw)Y
z$9pnp47QiNGd@@{9WcA5j2k?JzAzi8ny*+p_yav6i`O_o8~qr(T!V>&rzSIF`hGTF3-bE0umZTJD7l+4K{J3M8!Tz)0p1mxB$
zc5$3T@?M|ofctpiz5J&9g`M4`>Rq}ZD=T_b7CrZ6wQ2^N9kQzX7EhaU_hQ|^sOl8~y5ec?l#1V#ek{lXrn)->RxSO`
z%rd>`m*PlTT1arwOjw_jL&|@l9qz-)jG1wU$-QDEeBI=y8Kw@qnw4u!ycEM0ECl-C
zT^-c>%4OFJvAeqrF_T4+P-RSg;X3yaY7ZR9;@t%|lgFjKL(|{}H3EGt<^m7k*D+-F
zFDqAbg!Ehc^-^>$rP}X7mlt&{xg&?kV6?%CleW9M!KIFaI;P>70gwb6L^G4-{soB8
zF8*fr{quFlD>2WH?UXZD*ucT&HY;19s*Pv9_QRBn{jzB-@=T9TpFQ|?T_&3e2;FzA
z02!AfZ&ANHDy9kukI$T0G83{=>a{TyP&|CxZb+yAKeqZUneTjOH@O*qfm$cTQDhYz
z&ns_nAL@y4G5qI}&2n?1!Kwe4t=d?3YjkF)m-hpVhvB`mF!?}}U9Iws3rub|guk#<
z)p96_^_dD}=25A=79;(3LC^EDRNl$$H!(o#?Gmw!WQomT==^r7a0dRERoN)pkrB$M
zYt1?j!BTl)g~>&ar&m4BjW9{J@BL1y?8I)Ej?CYWn2()p1SBYl=^nWX)l`
z&fDLI?0P6ON1r8)Ocl1h8fPa8tmGauf=Fw#&K_h>?pU0VxZDIv8%dbyf?k=Qpsuk&
z1Bl+{@Il4WJ%DyTjVenZ3uOiqw>{F~+s_5fe5^+ooxnoqv3NRU!PKO>`{T9(V8s;N
z;JM3pr!5^_8`}tqEBS))r5g*z>y)f{o&*n
zY>Y$MHd_}9ndboKQP5EF1R*_1KA*En_9WfKL*zcFUz{4`YtY*2_rYBwn!Rna1CV2z
zshhf&L4jo*zWz47%_7xvv{U6KTYy>KBCN!e>v!zA1efvfuJj`Y`)sFq{Mvc2=z2}i
z&B#{*b`axq_k@myGkcfAG7><$!*J{^v(f&e<)@i?&<6t7uTc-vs~c|)b)-Xk^(jyF
zN)3fA<1)j@EVu$ES?Vs&s7pO9%6#@oXPRX~g&8cEIGR>0_U@DIhcEj94a-Yuk0xC$
z#`AzaXQwr?mz3QY?wCYQuPj+<^nzV|IC>CYveI`}5xdxR)55Z%{^C
zfegO>F2Ye4)7FqP?rixlzliW-3k6sv+}{g&3s`%J_kSh9WUa&QPt!JI2W{cHbE{~u
zN;alXKFnHVK+-XtMX|?0{bmf;wO_u}yLoIp3{CW>yx5KC43xZPdo^sP5pFv1THowa~P8PX85J
zXW2^x>?2jUW`KI=oab7)oMDSPcqAV-mautY%ji>1c14pje!%mV?^qr}xftHph
z2JuIS4aG%ov^%4i6>h#3+g{X_03ky!G&3a2%gVOlAJZ^OZLY&Vso`}$%>v0{mZP|D
zod`WuEFd$!Rh}eM@GBTf$jwRJ9~sCx5pWN+T1-DuO5>vuD%oz
z6Y
zZ6-a#=&m$Gmuu+HK@;KZBEpVWy|yo^joBjTff!PtSMCVUe5V^L!`#*)beCgAx2bjf$ksDBMm=_o)mA
zOIyY7ft<=yF>}TwI^AZZkJW%z?0QzDA{o~k7Ikr#7N%^Nd&EdS~jn=ipr#|zivyL_%GLbAMob;x#_VoD!Fh#A#c
zeI$JI;)Lg_{Z*NSS@oIH8ic_!KE>))Ns91Vs+?a
zL$$B`;o)ILZ&?>-$@F2W()l7H%1RomA=Z}ab5cUYVbtl+J+~n}=k#Vx$f4d
zt<$U2-a`+93mr#K34ibrn018SfCH;sV}hp;b{&K1wq!c;-T#~RD(s^(Js$rf08`!~
zw>^3Hz2&|-V8G4VpY^lG{>)``F9C0zA%6NhoXz$%fH%(rA19^jr=SWQ9?((&t8e9n
z)QtDfL>XXH|vIc{4+8H7FNya
zWfYpDr>&(yo-xyj7GT@;kDgn7m=-hBMBaL=z@O2b8Jaf@*&Nk#=~Q7S3Ew2rxj9z*
zUMt@UX_-df?A1u{yI{u3`WU6R8q`>}ClF^~6NX6DLQLcKudy**JJpW1JS-VDHt
zFvG(#ne$KI7wj^O3yiQTq7#X!2FH{V!}
zsVy{=w}#H1o!MXa$Fvz0GiAJcF?oAyF}z)8u~jtwrYat0Z}I=I_m)vrHf8?(XirzuDZ+^FHtWuJwJtzaP(9d$E9P
zUo&&fb)M&(GjklrY>MhH#LyYeneIw=2`;GBF2#IuVEMpGb!y$QD?=#Yw{$}1HYA;8
z+p~K>v#uV`!N;v3Ahsiz3ZaJhS4d-t<}s=e1VoI`o9bSDFE
ztW4q}OByvT%ixz`_ahi|9^%B02Rz{RQ`U6QL@$CEZM^>51d5Yu+2~@<&d&
zMsZS&wjV2Rnt$>61XHX#%-2@x5MVh;q*AUDwV+}}_ips*aOj4~ef}c-AvvNy`
z6~}Nw4RCRS(v0^-#|7T_;z4L_b^FZT$g)T~=1#ql)lYSTxx~zJhGg=w(=eAL8Y&cL
ziYi2obF3Zu59DhlRWmrBzgL|OS7Wx)p6$gy>0e^OE9j}xH&gjg{&Kxh#m2WQOu+=_
z<3%jpIfQKQi3`!YJr|O~r}CUvSNqgZ-SpHQT{AQxvzMY0pDs_p1f&)NM>$sO_>@>*
zB3GTR`lZ)NO6UqwC)D!(T$R;;})x%IRn0-%bj;SRSu+#SUtA
zJgil2<3@}ndToVlm$3bz)Ja@YGQfPQq%FAMdhSafLEVpJ=9mgOChyW?shQ%=Pj|x?
z>y{?(O0f!l{th`l3>up{8|W;K)>0|#X~=)=w(xnL$+$u|!s)5vtf>OD>TBT9*_2bI+hW3`$Io4|BZBw(=zC+8rp{>hA5~LVSfsD^E-|Xl!d&7iswgbby
zc>&grZTmO#3CxaBGNua@1NaD}%49U#qpavTzU^p|eW{5d~pSl^a@ydzlRP
z#nULH5h~XXeBiXyxqaTfIW$rtmpGEyzW>7+`ni@NOY`jk4RNL_gg?TsKk}LHyOF;B
zAyZb77YxqqOWOK>>Y&+IB*ewF#j@{Qo@|DhZEOY`|77uzqhcXAO(-(lxD->K<|Rnm
zPXpt_R0gTh#6(w9v?Ei@TrGz*yPI`B?}=dpTA=LH8oG=H-)M~
za=dD5_{(-qhZ!8(>O@&W=cQ0*PJhh0FL60Fe96(|(sR()vhqzz|Fp3mOORo)PSrR*
zYbU^b1v$y_BIz0hiU@s1%Kiz8Z*9d^oBC%->J1HR8N$wfN<|7-&XC(u$5NkDCDx{D
zR(DhNm16|ID6jaqr$uehL0symK80)I&Q4g_lwQt)>(lMaw;f4vp@92WD0tIc=~>OeHXsz5rYoGtFzuH)DaRuFFrQq21E
zR7wIq^qScxnlt{wT_2N5ijy9W?X#S;wBL^5x91T`GpImc=gSWu=6{1mkQl|aVs5IY
zb&)=MIsN2!)sgKM&n&%c%mm+*^?CYcX}qyJr%9-r!yprPT%H;ggX?>Tvc0IR-hy#^
z9QDAJDv1~U@oyd&YMoxc;JKKkU@2tKz#^Vw9a$VH@8~)v*jJ62;!-8KEHh1~S?4<+
zDsAhvFK;)`p0H#e)lhed%9}3km^VsbJ&>By514u*Fbw?r^WF5_@oFj^bJiEHymu^5
zj>#O;UAdC55CwE>@jW|jS5FVzj^m4ewqCWEu+h;Pva>~}j60aTohg`MlX(|pXSDl{
zg?9Ax+?TndZhJ8%V`s0Ou)t-IVV+}GU2pz~Te4T4^vuT?faIia|eps
zJa%;-Ag5m{rDjjldB7a%XVEy1jK(c`DXdk
zT=gB3jl~vYI9{#xFC(e=@iEC34uM?#fr76kc5Bz!LvKzNH?J_(@=Y|>nj#pEM~B78
zmUn@{6GmrPI-s@V!P(wDj2X>FGR
zD|!mO4J_*xIqwumf8hi+?q|Mq5itAWMX$;!o2epv!H!#!d4pE1E7~#5k^d|x_*E#2
z%3fH3&)1UjbF3*V2SewfI^qqFf+L<5o|dh6O0v~D%$oMHN%iyed#t~)w^u|`+ED~nZO$!9Lq^zT=|QSQA8wQFQk
zN@P7SwQw>uS!FY1A*k%CU|WAJsmTu}>>!nxo^j}U?v|`?cpT4G_*o%~O`#f9m%Myg
zvH|7tCblP7KHeFFj$+>Nr9|9T{Xo$a^6@H~;p6ea7kM-}g|$EKR;dNB+}`ij*zd@<
z((bi9m?-qs39?O_`eyjCUZPfcJ_>TO-j`~YaCVaDvVX+iLT@vO_R#L)vzyK3o|QY#
zQ`Dx9%x^yzAQDy73~4@Sr};?yXtic;jHB#}e77-Gac!n0>jCs5W#9UjOm%GxtL>Dy
zw`kNXPB9WIZ~!YE7XZp6jB87?e6mL=@BYtE_=NzLB8J#vem-WvjkAwuW~65|S2
z#3E?vBs;#)OWvf&OizSYe-+=Oa8Xoi&6FlZITx^ai7(tM4AZlkm8PP!k^T&0k^8}#
zmYL51P*3NaeY+!phVjxT)&lRXMx^r1WKxrco>BHF?T1h_;6{RN%NKQ$t^G!yN~0;j
zkS;p=L)>=aLfiBb4yvbyfoU)dPG*BFXJ}-3=3=zJI;Rf{b?$q1a_3a0i?z^vfFlO+5@mF%nG*OjbFK{
zAZefCm~iD=vi6~!3=?8n*Zdj%Y=?*hr2;q;#~VWho?UnL(T@*6#mPyBRx^egEKJva
zW%0@!vFB4pNd_7Y!&iYGBM&bij7dsAx4{Y#1rkvjUt^jBI7pKvOuzgh
zHR)rIiG2(7pb-WsvH42xfgI1sIfp`ul=BS053DDuYS$lpGNI+7zu(pN3F?KT4la=6
z8LTUsE^sryli%-N>$M`A2*V4Km77hSW?jW@+d!^+d49pgob%W-i~{TkcNw0P4Nkht
z9+43uQHps$QdeVpPmo;h_n^0HMCS0N@PMS2^L)QZlIOOdyL;mps!_Io!{BpF09o}1
z?WQwtkoLa2uo#hlhoTSm@5#*U8l*PwcmH#Q=Uk!zm~c_@k0PxblFZ|Hne?PE0EQN%
z!M2{LsXdo0Mi1u_K#oV}Oz8Znm=5|QLk8f0jL0SG`NIWV?(fiNqG2~^m)SXhT-2(f
z-aa8j%zAL8-2TTiy&3Zj7Sg`D;{?R-d7Q4Z;GZpz5mby4K?;B={*D|kZOxvFoGTc5
zA`HLa$Lkjnn4nx)#IEyDP-Y9unmfeGfSwOK{3TKo>0*JsZjr)z~V(3odn-sv}-0BIAgKMin!XYPCXZMPRJ@Si?a_Z-A4Xj8~O?G4gC~h
zLKNg*z)s)J@HLEUpW~SDnqU
zrazEYA)mr=F_my!jD?FSx~Cm*kaWrJq@%ifT#QxqTI7$?WgquDzXWwk^2KS*ps;Nu
z@VF@G01IP1&8-GN2wmCM&j8z;N>Bhxn*7_s--sGq*y+}Y1zpwB!Xlfvwb|{C4s2R^
zeoN3=T+SBsjYsV{sM5@R*Zpuh{*@3Z0Wkb2xf8Kha2!v<_-2ZG0<8oIfJzlI$%!J2)fpc6tf
z?bGA0h@Cf65JsbE0Ttjkz%?s`9&LP`Q+;rAFi?@9jClya6W%KN0ScBW*M52N<2?IS
zLJe1aR_Zp?GVyO@zK7FVA=4&eljMj
zzg9-uUTwRf9-EMma14jL+jYth2cj6yK;a}7li6RTfyjY2`WyN?3Z!sAnui8VM@@}O
zU8K{jVG>riOt1bW!x#VwMRH|4X`^d5tgl~Ycl**w3Sb2)GwBP2mXA0O@LhBQxO_%q
zqfWdpQQ$hN@;ySaJYRC?vW8iw-kD7mP0S*||IeR49t;BjJff+%)?M*-5@y~NpR|wBNBo?>EczHpyB*fgb=BR*Wr9Peb3N
zxEHiolWS2b+WBvjBjGV>7L|X!-t^7kih~35%&5jw6!#iy+l#LJEV@IRvEWd@Vrwou
z6`50#=oJ2;{e~x!94AJxY*=cDmecJXOP`KEpK`}<7HV(c6N5rnKct1W1F+w
z`Y`3`ot4G%7n+58rcvXTA-?=mEPJt{H?4D2o9WomQ-R|xkNvSe`ej^6wlK&|TAo~1*$
zRn#&fD1t#u#|B;0B&VRYW@vE-O!f2;)0b20Mk9|3k~r-)F(Dt=5dv8Ij4x3El9Su0
zzM)~B%nhu`1UzSG>kjuYleEyVSdmA+j!lfStm$f~Xp$bGU%Qq&AAX&Dohdt~1iQVg
zd9&-jwW&)*$zXr;vu_~1+%HZR2~v4ARg{|4>7#y>g%2>-Mp;V5+wu1GG$R4!xw*NQ
z;tI`QP>l&pHB94b&QMyY-W>np*6QVY<{Y|3=!%3~N0scn9$2%z0LU)O_K|61BsT)I
zlYBj+80R{LY~~F{wBHw>BY)RDQBZWBY&pegS*EG}1qZvfnT(+~qrq05hsW=?J?EU>
zyr1zmH38(aaYn7(&R{)U~BuW$8X
zXR#w@vW4%>A=;x4UXx>@`1g?@3Js5(;)oZAuQm{KPexr+7Yr>|PqqaukTbxphsPfAV5ul>xkadl!rRd52!@n6CmbzFdIb9#Q>ZBaQ#
z1vUyD8-&TT5RmPvU|@d`X329^ZZ>gk7(SLl$HWu`M@Xi|QMev9J$86<3c%P(SGkSX
zba;QsqO1xF>bzMP9wy`C<2&abeoP4{CcWZ@zbV?GQ4*4rOj#s*@D@Smoi>PEbW(e?
zi>|t6lG3KI20vxt>A1ctaeN4MQ1s=2GuwBELD@ir>>sjtLIR;GSxRau%F5jlbSkTW!Bp>7
zas}2JgF^Gjls_=U&RfI4E`B-3%);$D#~Oh6GaO@YDD%1%9Rs+s5FGN@2^K3U4(cxw
z3At>98MSICIA*QAZVzC0jeAm_vo^2GlTbI=(pV(yTA=`G5LQvao-5|ek~cAk0Xcl2
zQ~!%?uA&v1C7JVW`C$_@w+~j^c*Ela=uDu+SQFpk3S}ObTKbDI1r$@{aDdIp=i>E_
za&ZDq$NE!cCJLkgDZU2=0krZVX$AVbRx~fFRf0C7BsVGn=+V!N!a~^w=vko{yGger
ze`gN{V&w}Vj{M6d4EN1ilcttW!!lw!g@02tP7xCdrjAC`56!=QhLxtUJDYqr1W`FH
z%M8+^b`WESBj4CBby5N#dUfe>?o(~UvfqHAGZM88Q_BLfMTy;({O^3g0T7{BmlE8_
z+QAXxD9;#O=!#_s`6&QZl}Y3^fhqbFh*JoD=0v)-)AHi}4Jan=$;9W+Iz$El?}1E_
zaKp
zvuc>y&&f1HoQ$T4?canfFrDuNL=i?9N!=sS>%gFWTMWYrtgfdpkr9=B^dLX`m}`ub<_WZUX`_Nr%VJNI-T
zZ2(Vo5n;Ejo`m(rgd%}d01W)z7l9*vDbY86jUOwqtJ@VeKH?SUmZlTHHqX1fo3Z8A
zYuZ(31Rc5CzA(_c+jt4e0gju-Nkwx(X_jNo-ZmS#hcI9sX+%|R|2UsWrf=H>d@;#SPcT#uZM6^g+a!i
zN!ZX3ayblq0cHeBU!+z6*@-mLC928yV^VdRQ=EtP>SN-u@AQ1^HOJzNf^r|LM+xhn
z%DH1Mw8bK$`hrrBz{|pW`HhnY+;4qRMXvDO9>dFi
zXZ&4Dd(#roGpfx@y||SBO`3D@s5MeL+g9#
z#z(-_{6heyRaR9wqZ|va3S}6BaymLpbSed93s-Q~XmU7;FoyNkkL3PWqbf$&Hq>%}
zZ3uUK?Xy`5LO$nFnJ@A**A1BmZU-(lAoOieu_phv_x((yHD=QEDw0u)7K86pPS8Zo
z0+clgtm9#(c3LtT{jwzPug43cUbuiRFk@R!cFrH5NvTgCZrt>$@S
zcpNPa8L$T@xqICY7vF2RxRLA&048q9lDwe3r>Ri#bMO?UR&2ZO=er+)0feK2cLBLw
zA(=soEgStGuB(kYk+W7nsnr7ije?j4iQDO?7dkwgUz50NYK#Vmhh))eAX{*XkS09@
zxI5+>G|>Lj8Jc-0lV;W6dDMS+xrbof224O-hAO}^k>?cE`c;{h1jw{@>bSKscxDzB
z5dwf*Ux7>fZ4r@YyIXxCM1DKo&dt;YOo3b$&u6Tn00l79>#svFd||!;b7G3
zuTB?yI5aDeov<&>fCDc-Q)DxOiIoZ{ca3d7yDTWy4zavI!=C4XilX9=2A7Dw
z$oR}d(8oZw;#^=f_2^vZf^jf|bke=ig!c?M0y8D1z_x!9rnA=%K;#ayR!=zI&cy-*
zzzbFr6o2{lg}hD0#RI@}uIv6o^C$^0-Veab6XJNyz49?ZN!wt>B_iuPm}2`Nmn98`
zs#KP}&4zr}x$z6LQCD)D3xAiuz8kO7DD!yGlc!9d`3_MI>g1Q^1TzO_T(%aT^fYU1tC+EMoZzLB42S(BO=j?)?OBIAI-leN
zX?ZcFr0iP9yc!!fz&HOqn0jrY+n(9@C#4%%
zFeHKHE-TckA(cHkpA(!>oxu!WZCOgcC4RxH=^0PT|yuKdQ^rD>u6Wl;AQD)Hh%opTKEaP&+m-@
z-u;-Lk$&=>N9W(s71m*Yelo9k$5e+Ep!h%6|NT|LeV_tkYxLt^syO#A?*2=MKM-Vc
z#Xe&_{ZE;H-&2kA$D}Xe_1`j>z<%Mi!LR%w2Rbvvo+9-BXa~5mDg%V%9DP3i`-}f`
z&rcvU`zajP?W6OUByMHGN_g3=%&k@^wD^&CEoZwG3=D*d=
z^&!&w(CKn{jl??A2OH>}?QyK`QF^)vBo4XX`H6E->N@bIPSa%Q!X3USlrsxgoZt*+zr87mvUSE~CUfING;o@;gI9oaT?pn+e&yccis*NzJj
zC8znh{$N7?s=f8vG%j&xJ3RP-%bK8AWlqX(n~2egiMW!1sOc};d7u7PT0`(eM)LYQ
z7d*uBgf^XXU%&v{S~-650uTNxc`^3`Sjn)=5KZ`?aY>E${UTWzuLJ_-e}hwzAaGqx?5t;
zH6s|taqJ!65T<{u@~%VANYm}{y|lSP@MQ_pyc1b*zsy@ODFqs8(SkxkEy+-tgpGpDCXOQmCU
zzcU=@a@ic^gbIZBXJEKFNJJ1&1?K1k#@o45^c|2_PuhNPC@9GY_qkc#dC~296B;l~
zqEtD_tR2z*@pYe|qhqd=cF|a*=}n3P)m-wINrra1h=8o=jQ)78`u*2alTI`_s}t$v
z(14QWW*tf~=YrVF?)h|h*2{C-@4~g!BclX`mE|=
zUTM+=^=a7{OLu;C`>ZGSVXnL5Cmzonmk5_{e3kapw*{Pv&oi=`5t-Moe)UI`O40U>
z&IBv)?0M#6m;>zpZ^?xGWAEm|c}Be2IK35@BkG((VKeTvUq!p3q=_73+1exY6Mu9XI^%f5P)`Kik2~77t
z&Oleq41Q%Tzq!x3krRL%`XHOfHBkBBr?i%CpXjX!HfVnSg@vu^igG2AecOk>c#NdV
zu0Ob>yM$6`6@dpD+yyE&FD*b~oKM5)s&ySc|S)mkxF-B2pRCFF+
zwS4sp9&r5I+C5NY=+y7$xlzc0z9|Y$9Mm#c4Ws1~+?hQ)L8Yvi2i89E8Ewv%$c)^3
zDlMMR2&v-)VU&TG4YU_?c3!jALdT6$H9cROT1@;d)Kq}~bu-Vu<#EojgUg^Bh-Os$
zelgKg#Gf0gYM6Ov%ITcU({xoyEr0toB1feFZN;M|{XzSCrd)MKv0Xcp5&jlw9Eaof
z+R;x*qQTw%umJz2f4SwKBIIvteMR3m!K$8MvN!5Wu@5>1WIM`}G|gv{IZ_6_ql?O=
z$Aft>qiVTP@=62$-&*L$w7T~835t{qt6bHJztTg*(SuYg!h^!-4cPI$IV>co7`uw6
z2rjxy@_(&SCQ#M2<_$={o8t;+E#}=gAMaVkt&!v49_{)Kl@a%$=YH|G&Nc#)1VR=r
zAAAbGsE5Q&si=})5l!Tx5j3I>$=9fe&hQPG+1aaU5r(~4%}=a-E`SvGN`CEQ%lED@
zD$cBcJ{PHr;J1`qF{D;M+iE|XT{v`xWfOf@*dSh>9Gau+$<2`$3*gaH(0VGJ5In%c
zm~*G5WybC!;h;OIhoAX&BqOfRc`~ZEU7lOI3Sxcm*2!lZP_oq4u+=JZMB8T)vYicf
zl(lYRrK{62j{hZwFAPSF_of!xKzk55#3P2Rj*nHOYUVP9n@u%JnmyJ&yz9f%WzJ!)
zD!Q;kne>Z+x%dGvp@&dICI>qcWU!$xGO`x7gMeV_?D#^nO0rgXmO!H3clbTcn<37oFK
z)@2{Zws*2FQEG5Y?Zkb#&X)U^+__lux>AH8(aHY0;gs%piRDy@#`IqEbat!jy^1y>
zN+6K{giu5tCkx4Yf3rmO3=#xW4pl~
zkUYPI?ImECYmP<0WNT*HDX@LKDU_g`#oi-mWPZB4Hq)zMP;pv0->r#(7cW)StW
z&aP~HKJ255f@y+Q%#MN=Q$vY6PusMgNkO4i-DF-O9)N`?R#o0Y6&)6aU{X)lnXJ{-
zXuIE=;KY(BU}ZQT=j7fXTVk|ce{*3A&?AXA2YzRgvco~|e6&8ux+0AJ{BXcfPaa$x
zv3{%5Y+T}Iy{_Z_+}XZ|2!G(#AB(y}5skmoUqL|&33gt!AP|yXk
ztcv#CC=bKDX6wOcoix6+!9G*&*5s2z^fg-^H%AsB@(3yOVJu}H4ZUSXiH=BVxd&Jydu
zz;k?$fGi0AxTwE=aR1B?kV=HBVjVW8sx_i0`fQuRcs5U$sDEE(`fjGw7@Q8WEu>Rl
zopI_gd`?@*!WbTSmU}01
zyG3i$HTXSp935KYDM%SNQa8RbczB96U@4HkRJsJ~dE=gf2^snr(dbT#O=#2|!eBTV
zakN{E{7RE*R)piXRiiQc_ip+@mQK=JUHK$TiXLc~Ns#5~0G4ER-OS#22B_q{7LAkE@_NVIo4c$aM=vO2BE;-CW_&wY;E3Qlx8bI%tA*S>7@7F`MR3a^`{qV$
z*S1xK4F80?IdgEKcw)#i-~5#y7gK4>tyg9dx0FXXzdAO(wWVH?Bt7Guy4D|9Egn%&
z_{~Kb6g6_%ml(Ra8GT+nZ$y=wm3|T1#lYvgaya-_R`y(AgqtmC%u)87nAne2Xl-S=
zb9GK(8HIUSA%;51wZNTOrh>{o#;ueiZ2#LuDs$V{Bl98&0t^aazAzFz7%%e_Y&NpX
zEHfRnuQujDm1dXmHY
z)SA%qY-b{uwH^ox2TR7y;CQRdSJfkjLf{vR;yj)PQPzg)V>dVnjlHa?4XW=wHt!W^
z@B%Le{=q`m{r>#^w|}+g@83Bi5dxJvUZ7z=y7&ISW5B_PsFCYHjme8QmYu7~sNh<7`Uq;K1RL+qIFw=lw!J6iXS-QMSIrfTL)xom?vdE}{znevMu94#r$iKFWVt
ztfFNfaUFi}R=@AWOY+{6z6l%sj`CK#$wAbBb*f?V76b|FS&msHKE=iD0W>;b-i7f3sSRfhs
z%KdW5HwTA&i`#x%aW*(`zfKc~o4@?4GWRVeBd~}KR8Dc&Q*->*aCX6pVS!_Wg?7Ue4E%M;i1qQQ%^?c74;
zith@$$YnSRPiN0WbBUD}Y8|b@5x~OO(D7PNM2hK#)V5;!)&f=&ufuNi_8(1fJ^-Ny
z{p;L<0%f9?yPi+$f!01+ZoSSco4l5cZqcG)*&wt
zO{iPtA_P{3b*NwE_%Zu9kbP_~7tKXU>CI`l-p<`F)9DIESp=fAS)vm0mf2L;z26??
z^)?h}*S~5vBQvhT0C^W3lJ*#E_+2PsZ;LO6uganz>_(z2R1LJ@De8|PINC#O3RNcV
zlQc&y#FARmsH}Y_ud`$UZ1bK)SuXKR-5srTn82WS=|(z3PG4LUS-AS?__c+1(ln|Hetz+XH|?et7Wo_A
zZ!12uv1n%;cQvSJ!e7JUV}L;&QM&Vg^-j4>
zCd7|{Ne5y=t@)+QAJf6!{;!L?>o(P({LjVhxpfEjK%IS7roKr
zp#;{1^;I7kS&&o`$>vYkBr1eOS+CfsKEb+dh*q)*NEDAYDABwulsV{lqLs4%irRI|
zFD&fHwUPI1u?5dGf$0JLsiQbd;{?WvmKo7x*otkl7PxSL6XKwIu|KyRLfMsHH(rvG
z(saU-`&(i>ch6fdXnboGDC
zKRLo(Qr(}myM+?{O8{h1Ko@~kmY0Y2HvFCY2w;Z%@-T2vNZAcRm=T|WJy7qwr;bWra1`fl9ZE)i&9g$
zD^S^lt=1hr2i`@1yvmn5to-8(Rqoq^+5`ScR8;?Q$vyA1K;@Wq_uHe6mNcs4;2MB^
zrg{Hvv4V;;LYbTKn#i4b8aj6XiCXWCNlRG7fx8HyG{UvO$@05`8mv1Q5bi>l5n=8?
zg*zBJC1x#QRbHNyw0YOoc2yY8;Rl|jmuX6w7bGsb@7PSq%!Wx^58nsIQbaY<$ga&n
z$ikU-XmKy$()^JD(kb2qpb!~&AG!IxRGAZm84cjTM^VlI55kI55c6{V7E949;Y2Yz(jbE;E7}^CvB>gfGU2_le0lwg&yH}BT&Tx{mPtpsh4
zGU4@n*9&U^Cm0;QCOYO<;Yvrn&&@df5KbHUG7#^qFjTysfLQ8+WK6yLWxw5Fxe(GC
z#m5=uOS?1dxHl~Vu)hjoiX80h!|+oLW^oc@sSYcFfse|9q3itF2x^n`
zp0G@iavEv3O9Z>cv^UQ8k&
zT|WGGJJN~#dKln^j1%!V3ASBKtAE&1UkI8v}8JiU>f8Z30uNTU0XWj57$?kScsZsbk(Tt6~i
zOaxDJl;ng?pF}=L!nDk!X&E{?`Y;?)E}}T!;yk9LG9`qUk|`~STvAjdN7PM0{X_@k
zO=bFBVP!3zkKxAhLk##OF|N_97t~Rdixii1(Gm1bJRPEpIW=^eQ4^5Y`1j`PH6Av8
zX?bLi5~B6>^=vOnXOonTI9FHF%lufCO;sclRHa_uwQZ!i=8LWZ1|CJh0O2Tz8F`=J-fAUK@}i({@a!p(W0(Ey}bL#q@2Zb5auvk&Trnh<-X~@#3E96Jv}|Uqh%3iFhv+;z7Zr%{(!r3)^M|bGPd{=
zi~6)N)aRt}Mg%6b!K3pcA+cGQTgUKo#)9`4`?@6Np0|^-jP+KyL-R3TehGg)fUFbM
zQAB(LBH=QNL97(757(I7WBdaG#)eh7K27f2Xc&lh1I6}DaD>ROun_=z@`5grKs_Uw
zbYuWS)vK2(6qnZ@6LXI0n9Rnu1&t${Zy9!`0~1+US+U!le8+YTnKFnH;k{fWIBmRn
zGKFzX!oA>Tv(@^Xz#a+$O)8bX@P_;8kk~dF{)DD2+LiQ%k-UsCHFHX&j)05_H9ebp
z#+OU@IS1DZusfaRCdn(@B0D_}%c{t!4qQ6rZ#J19&-3^Ja7#k8r@MO-X!oaQNJeD_
zJl%g!>hGbvsaw~5++w@YPt&4gcyPyjjebW$iCu8LWN>FSdSxR4g`bqN>8c{0Ws5`S
zb(eZF5YLrn2L;TgX+t)5sOtt5_W+F$Pv{0xCz&&K8BXM@eBGk%-H2Vi`n`&o62S+B
zSENPYWSsI!h37?YB7tOzD@98MC#5WiR%OhpBBF6|apHk!nxvm`5kslBT04nNev1u%
zIq%uzIc-#u4^OhL%ZBOMH{?OT_YeGZbz)NvrRK^LwQDdhb_QTcx3m)$8ig{P7&+VE
zB-ctDosuViNnP|j(|Z3Nk&TsA6_>ub>m4Eu4~-CwB#lC$X317#TAG)>7C-vq6N%s4
z93(cE@trZ9al3O^S0~30?+${7&%&U-{TDt`HI#Uw2~2Kig*&%Wz$=8QM&mcAllHtR
zMROHp?wkp_0_z?jMe(41oD#?HrZm{bZMy-{KPOaNTCD>6T%_r5F)}OW8S>+e
zv8UGyJd`_>@J_9fK9LcBO)W!_Y~RpZp26Q-KL
zWRHc1GAT`}yb(aS`~+K&XNf_)Q-vqAe2BIbWtvpA(lVh^qOGHP$biOx&R}<4Qk3_s
zVYwX08JMNpev)xa1128cY3M+lSecBMSF@+LL
zqn_l=t}>JC36G2J1TZyZzXYiKSbZ->Mk~yalDeaI0wqH`{8~1nYpuLvbY)G_5Hq9+
z9rt?wV*ncLwI8kM$g+QM+PIf(`^t0XOu!Bz)Alg54Rg>9jluWbPqz!4J#UTxUQoQU
zXl~u~d)f@bSz7=hcPUkLjnAE)o>r=gSw=wMc`GjbUhyzRN`Bn3PTwgw@YpX<+wE-3
zvKMK1*9M8qk<6XUS6iL&(cOVflT@f{S`Uj8+r~Ra|t2<;1X8iI3
zmFpLdGUF_pmn8Q?-;K~j+~Lbt*ld-s?@hf%FApsOh-cq)l&(W^L=J0Siu
zg|CnDRw==DxHETVN8^{!Q6^;tdy*o>ZuIO7pMemr#;BY@JFzF+E=ngVn@4M7#iRjP`TJoaskoyr76
zH`+WLnw<=E#r$oiWc1C;wjICehR>m6S<6H-`=`o!^II=^*kT(pQ`R&^gY%@sNx&%@
z<2ZvicffP?+!mcsu&xC#22U_E2;dz~jQsGE%)O`^jM$DigZ3oX3v+AH;@c@OmXt>VaIJY`>RXj{?hc1a925Nf
zB)4<5O9Uz>CuT->tU&`t1sK`WDv*QU3L#uC2pAACWeviPvKNU#J3?1_2jdJuu(SncwJNSi?kYJrEkjowN
zBjyv76&yl>Lt9jlYIe)%Tlojp9o0p5Iy-;(=ccDq#BnZ7v?1F~nWGj};m3*)G|(XdD8_Ti_J4^qk-fwNPg`iv)SVv3uD;+7b1SD;lnH4Y
z{!AC}N9&9D)Q*C;2o*e&`<4VUIKQ|I2TBjL31_BcqQT8>7g`Yo
z00zv=?smDyf~5YaOzM*UrjrrnGT5VFr)K{K9f6sUD%n7=NB9!40n9cofnA}hi(S6*
z8DJ>{|Mphm9A;N2B!{yj!gmwUCh-UZ;0Ysn;r)!lsiZ@6;6B
z(8RA4``#C{w3J6?2Bt$Mn1kH!cYd(eHUI8Ff!FXw>0AmwUp31T*V4+Hd}r+GlP9CZ
zM!RNbqA_H6q#^M9n2Z@(hjDi>U?W!Wo)jPSN7v@%L5$X(H%;0Ze0{5x601s35QSd7
z?4##k2_h}1W*%4t=V>EH563Uf_b{UmXb{0awZJaERhqN(#Sq=!3KBKiK4(3POneW4
z1I)paWP=tSE+H9Uj)BN_L=*P&m(LdN#07i4N20mQ3l;!xWJSz>T4p(TakQm_r2eAJ
zT=ji(_)w0R99Taz5s61>d4OC-Z#;D<7#Z>q*ahc(Dg41Wv&Z;|3{TbBT_fG}@j$NZ
z<1zkFouievU6uscI
zU*i`e2T+XF21}MocgbtPW4=Q!V;rn`z5Whz9pVxBkbyv%^sPbJc8de>XoG*ZNR{jR
zG9rB^63Vw=U|bvitUJ#@mjq!VdU#}k9Q{!7t9lqd&orun=*~uxdjYeD7biW9m@INC
zuve_-vL5fL1pnxP`30YH@(caP*9%BLP>_&$g%S3=eV>e^=1mUC+}h`qZQ->rsuqz(
zjLh<41dd4ZIB&Xsc`Yr6Rc>C8<%FtBJhvcJFNAYz$H-=(CM)uA2>roI%jm?2h}MI8
zyJLNth{zYi-PfWy8VZuQl26l!P7066nLZ8taazt!E7%%&YBE2JP0PfTmD;@d5otv%
zJJ-zP7v@UW%jQ<(h*7J|X=VqU?geq$lt@k!cITc8$51~Ef!h#$Z;PYlwkw%n>J?cE
z0W#aaPW-b24GQw!_?dHg`iE^XzM@kX(uh@-w?q5-0V&i+7@05&MwvomukR6Dq)qZN
zDVb>Uo|NpM2cjr^v+3-o*B@P({
z`S$CEK;2Qd?;$t~{2Y+rCjsl#B{G6AYQ_n>BxI`gtxf3ND2KI&Pe=NIJUE8lEW7wC
zUw+^So;Zgqbu~sjK^D`KfRX|pneJZ;Bg>r*&8Z*6M-MO_58PdlS+Z=?t>fA^?sS6J{gH8U>91>{-)}TZeYT_8
zcOLy5k>x1+6lJ3#c4m$sT7Xc0BoE}|e{;CzmW5AR^W{Kmra3;DNOIh5`(0jI@iciLG7U1+3#rk{CL+78Y2C`sRH!w
zeuvJzRI6EK5e8?W#%lI2UW9HjZWq!Tq>ZW32$}X`4cgDeo7HMjj)Wpk!wxx&g(k#h
zgo*YDraoloxhKzX6r=O2h?;3<%YG)ciRR%5$-W3~x1fEn;WG34#JHp`T>fIQFzi*c
zpPQ`QLQC7|?AUuFrm9kT;}{R9tY)`iV&J}eI4y_pHA==T{*YVfe1E=TjRnS?v#m5z
zH5-nX?d-D)KB=)jG2_GC9sNy8E^5z@;>yTnGM%)TzE12T2h{tG0Yk4|9;}Je5?`9@
zlPeuJ-BtF_%g~z4Ef;C7F><(X1TF<|s-o%gosvwm`U)V}Qe$|9mMCErI>UA
ztXMAB0i{BE-xu6FH@ggleFtTUgv*Z!zu5vj3m<
z&MGXbHhlNe-6GP6gp`B=64D{vT`FA?Qql^7v~+iOcL_*$OScT&HN@<9{7&}%AMN9P
z?YY+3%v!V7+v|OP_x&VE4^P*tQ8-g$znX*n;+tp3Q8)O&rIqH1ni&3g@3+0upZ7~`
z=09(VK~XcixL37)b)n!RIoX`ILm=BA#{XU1m$g@F{mMkHQ$^UOBS|u&m@Q>+@B^)P&C0R)*ZS}JxHj{x9=vale<7WNR~E$&!Q}lI
zzXwKJvS^D6EVGQ#{}8>_*U?1#_+9ZEHZo+f@$((;GoxsIgrrr|m+LOHLCqpGkiQho
z3hSX8T>i0Qbx1@}LgBnRznR$y%}(8-O~$w*l(o2+iXM&XkKheg)E&!@R6jPv(65Nm
ztqYM7mc5r=uYJ;TAzt^RBBbXqsbHErDyp%iHk&4A4-0EsWqbnD%6)ydCZF4)p=@i*
z=ww$+WI7*1qdZRtCiabCeXBRqu44r%tTlsCNJ7ygaT;9g^#)4BMOp6FV=3*N>|Sv{
zX4%x97kW!PZ&1NrWnLk^1kqn0%}*zaihRtk7x?Bw5#?A}w3lNGGpi*_o~%oZ(lqW<
zr#dopS(-EbkfDI$UCp9PTIOdX4_~2c`=^mp-IuprUapqpV#M|KJF-RP27IP09~T!L
zmN;j5L-rQxdDX~D-9I~vN+k0m%?#+yPta~`r@nq{t&J*GSbtBaVY`=Sz&74bdAN}I
zY3g8iRplCDzGn2DWoPauLetqV>ug~Zu^a)PlLZg$Hehe
ztgVZo;eN>_Y@6S*$lQ5eI0<&y?f)Dkyq30{xx1;cnd5q3$-6l-AODP$twzYv1mn}?
zwiY5LAz`WS-v6}m8L7p5(Ow}`b+ku=LTYT7%SFIvrnN@cWjFYW{L-f7?Y`po3kdEm
zH*#(}YR^hWpk2D;SqQz?;G2h=*L%y`7E|~R?`tA9k(;DF+#xQ+^}la9x;4L0=IIHi
z>S|FG!?H2?Eh>0i`-e68y)Q8)qI2hUWNa&*L3a5Gdw->5+zUvG6+_aJa_8lOM-i9v
z&r8S_bIRhgP?@CBa)g5Poqln0IB*
zKXcjL`SM!3KBx6hgK$b6I;E@Und-g0w7`dU{m@HW_50Wgp$PKan>HQ&Bcb-h35&O%
z|Ava?tkiEjH6)rWv@va!Roo|B3#!a6ie9YAOTomUd_Tv|KSQ#ZquyNg!csGM!1~)O
zZ7*XL98pyzK`Eo@oF`f1f6xT|shqnhl_DJ1>ZsunKiR5f|ME%U*RLhO?#k{bn;|*$^#@fUKEv{bbXpAY5
z7ljlu+B8(1j8&v8IZzfa&T+<
z#4hDyj7weZiJ%VgbS05h2^VjaC8xQ-H*yLJCnp1kk_WBt&n8t{NG?7cVh3W+5SdeF
zx=B+!eq4%;`+{moLfTkU7ghU7eUatNaO9lMtM3NNVhXeoucfF{@N{Fg!}oIrPz#lu
zr#c3IqoQ3!P9Zer9QIqG%M2bGEU4eoUQ}l{3p_sJoA1A{VVSKi(kwLhtFcq!N_40%Tv4iuK5D
zMWnm_N`9xjrqn>r_TIUs*droJASlykPj@%U`Je@Jjj9$iGX%BMT`(cwv-IuMFIi)?
zM%k6?NNLL(w&9XMKilrrOs~i4b2#drcE2m8`F_mI74M8MHGiubdZ-8Shh%ZNXG4K3
z7xyn}Yn@N8Ra57CrW*px^PT-)-Z(XZZH(;dg&=vy$Gs8s25x6w)o+;Ww@M`rB=QnD
zz3|oY2>$$KKSoj5?(q?juF!}>Uoq-2$3QDz6Vh><6w{E~o>1P0I9a5tS{B_qPi`0a
zAp(nx&TNQ+n$)4V3jN(vVG>FQ7z35gN=)AuN_KOPX9sTxzsE(~eoPoBDSBGsKBX{`
z88&S>nOAsp%E!ee22bd%7{%nU^Lmr6(^HD;F~tjvQ0k1@)J3fF-Hge0D@-=ml8oT$
zT=m!OQT)jZ7N3X93v8e-4lGu2AGy+AhTZ8Nz@j&`?x1f{ja~0;1uSb$P@q}$3OI-w
zw!#waP3^P^UBQ_A2AX2s)5!&;O@TA|f8KkVMB$I%kRnScWGNiTXo^G_`1jK*r$C|?)lTi
z#$*?+g~B7P+RJ1CL8GHs27-FA${d)5X0PySC=PPs!^2e-yiBB=6O%tW1zW+48ye4AT;CjUUzhym4U9j0y
zZJE`*w5jeJ)Tlgt9lJD$=5bN4G8*YVUqW4wPp~ATE}qZVv|f84=<68H^LbBMbI>nM
zZ|>M|uZFEmM`@SKrv_0(2Zb5m%O
zpa|01u^BmRY*U!>sPdmFF;Xf*HN*d8Irs^BK~$@cXNZn7A*(;qwwQDF>eDy{(L38~}!>$FZZ+_dJ9EoJUHa057j}WuPJN(%8
ztYnsd8Bfizkk3I5tg_qIKC4I-b1r9$@SuBHoYQlpc{i|KN$k4HmttnwkHJhX#G`g{
zA0nd{Fyth@DP6=#va8JYM+bO8RFu{qI2L$W1}_b)9E`7e6ynKCCFG_F*SzQXKG}+nTeSv`Td)i3PJ=
zR(~OIdw^h1_X|^s;vo~*x`viPZ1fOxKm_+n>|5vT%24&I;S0HXEam
z(X?eDvNscQAJvlEF$>;9zmP%p)~=j!mF?OS7z3=WxVZ&~MzyNBY~@pzxDKdNsb8<7
zDuz$GgJkg;>z=~GJUNFmF$%FW-?CJlWnI|YRi0JweXLQ$F>B(|e!iQ42CJ{ZSBkId
z7`*McsfbV!N{}x*VC%TDI?K9z&#{>Cn9)L=VMGaeDd%FP%zjeV-!^=B29I&)PX7Iy
zw$wg4HBN6AXIRo+;mkQF-tYrRy;;6n&@QU8VCL0)MX@Nw3>c
zL}-#0(;6lZW~3uihNQLIS?_qZ(|cg4(zEx+pJLCea!Q+!Dl*hR8lvYb^c3?Dse~!a
zQvG9e)C=_ZWuq21&Ltn%J@ZA?zRIO-%gx{9-TD_M*=x+Gd%zafF>12av~q-WkVy^(@V7M
zl-X;yO(RZ_6bZgHQ>F7e%hJDbnNjDrJY~$^2tr`-FzD^gPf>uB4e@i=wzN1%TeMr)
zezC})t68jzF>S4*ZQ7uE!#g1N1*<^f(kU?5#3sR`i?jHV)Gbx+-!yhe&>>9v%w)W?
zAE~AO)_Z-{kgV)c>LUB|(-y6`_-gs>S^j=*Ayd*W3QHtywEZfj{8{4sJ)ezVQfmWG=4a>gFF*6L9%T`=jPjd7e#Wn!a=FGu
zUX~)gZcF<%IJL*4_67AG<{%W5=9*P8tUD-oaHDp)&E!`bi5upm{5`WOG|)v!LWBCm
zxNS$c?JCUE(l%)ET}))g!j{X-|gQt{Lzgu2@6
zl^*S=QbrI6fvKJ4s#AeA4%=C3|tE&a9l{e`sAUyUE!!<=wy=kjk
zu6hoAY#4WNX&S3;(3paIY?+TDH+a*)RVOXrI!3V3@nP}i!SXXBwS5<5WanUkNv?LX
zbYbiE4`lK-hJahKa*l$0u0uKESX8`|KTRj}RF^^e8-h_exC!I+n>1uPFFhSu4*pQ{
z^=nf_9NFa$?8+`DKZPyD^P`u0@z<6$h{B{zGJQ2q+k|qLb=KQjU+Eh99sV6p`eZmU
zGD_`r{h>D2#6!*`LZ7aLZlz&^v&DyzO{-evcQH!VmA#q<@oeC?caQYb-Nioj8pkV>
znJbAK4h&`~Nl-kpIMBYki%`rP%_;yo(86Ewyd_?z)RmuQB=b@r$+J
zH`z6{28oX-K&Igb{qz>H)BuIy6?7_D{3fp`UgN;>xKHjpW;3#B7j{;8m1Pyh3G9qJ
zCZy>NP#ef&nTwkAq;}3H8{s~V`ld_08$F!Ul|V0(_)3}$BhIvg3n_%y
z1!1ZvN{rg~J7nA(lVj5|v1fr6v!8@=N>&9gga#M|gZ+AzT5Po4`y{72kDec{6Zy}+
zyhUw4{Yzlz%|qa#)y>YQ>B8Y^Mz-+h&EHwN68^?iDofVvph~2v#V3y;27a0DooN00
zmUF+0aq1?jG^mxYh^&8XO01P;@)M^qts_}e&2`0QeQn}VpRnJ1Io~OFF^X5YpnShD
zoS!d?X&ewkcahevtffj)85i=y5btJ9{C6GYQC^wsp<8`Qv$yAKWX|e5gM#yXL^qHGEY-~WuKJ%v@$Nl6_^{Q1
z0;8Ec!LqcxpR6g)PvZO5!;%0O{qsXn^L8VuyM=jesxGLZ_mK%j8
zI`dMGcxvu5Bji`taL$u28V6i_V?x|-Q9K>(u~rVFq;v16JT|O2%e3?wN+DZyAH}yk
zt(I!_E~*2rQwtB66WPvx>`TfxGd0(x^YEnPC-vCYeAjxcP57zEjq-uwqH7JsMCEko
zYM3>6%&)_(%VG;9KqL9fc?$8D=hV$Y&bhNK5D&r0>YIyd^{#S$w}cfHCbZ9xzoMy8
z^R3^LW=eAW(cB!$yT|N4po}sim6v2fo7@i{(W@?wr=~JhsS`G33kco4n&$|*?lYm_
zUKfC^nD`TDH6ef8%8xP9sE;x)-z#XVqt$IQeg8M8+Nr=3ZK?BBUNTP!j`Yk#WnkTF
zNwc_ME2>PQTUm>Zd4-zV#%KGV^sZ=XrvmB11XxGY-YRMw*wzH$OrX9k>pDtU9KJ1~
zy-lNAo~$t+@0zNp4bc)RIK->9M>8M)g&MWw2aO_P8BKd5A;7cTS$&-BCSwkf(ZD*`
z`NL(pTG$u%);V>KRY*l^{TJ3=-_uqqN9O!v+(WVqt7Y-|w#yGiL0+laANXw7;tA|l
z4ZRJf2>aeRoRn(6)gOR*n|eK;o}N{eoGLVytl9c4#6MaMh@0Uxp4_6^V=H;EbgIfHRT(ErM7#y3OG%YMOla9y_Sb#xVp`?
z={-H^xm7lJNI~htDNEnw$yG=uphhRw#@ENCmw!v0YT~y<_q3>VEtf8kZ4F1g2>jx6
zFGeSV8a33MTsAJ3JUc!1U9c`+WczT&FD5}}+G!1w45bb3tnxIeUcc^PTGr5WC=#S9q|S^a>si((WG%z
zDw*iiw)|{cwy$&zJk(^WW_5(NG7uOI9YuUw!p(v4tSJs)S#WnNG`m!d!J@K5oC
zhW7N;kFHkiMJ*0~OZ1M!t4*|%dXCpp>%ZKBUq7~EcBN2ncu2HQrqKy+zXyyAFOnfU7|Xi
zko}ydx2!r(ydr1cco7ILr8>LB>?Z|3J166b`{FlMJ!;d%P5fnqqETbp91;CM0(Gj>
z-LOfmA8JPGe?Y^oSx>}du6yxJVC3x&rrQaocM~$BLQY2k8K#|usKu`R`H`;=LaMAVT6nL1Bn3-f?T}3Wt)sL;A2jh2aN6As%`IV!IE@0#a0KnOmH>u98A
zv4CcH$L6du*}1=mp`LggHD9NFJ^a4sBE`00CkNqEDIFjrkdj`GpOJ2|4unh}NDTNT
z&|SjCC-mze1wfcAw)b^Bh|f}#Y#Nb@jNFR?+JSm2Me$`OuyaSLr&;v^m_&B@(zp-=!1}N
z0st#&U;uM18N%yy
z8L)f3%RWAII$BUo1f)L8^~I?mN{;DxPnB0$$>|gK$dU4Y2PWL2{(%%8T+w|oO#c9j
zgi~Z`5N%Im%y9lTLy$Jg!Ic2Q?Fei{7?gQ8G=Pc0^SKsJQu)<53y_8i-KVWR7&iz&
zPcY_eFzZ#miFNZX{ol`b0v}O>>lgyo4P3`?==rHh_`fgydgi*s){PhO&g9{ey=;*c
z8T6g*glHJ{k)SuE{=1vzx5Dpy{vy|4TO{@g(p`hnJSIdaC8`NOR$cxXfBp}ph)g^B
zU8X=@s$HJ;G%G!=kKcK2fz>1B|B@`BSDF7fV;yTu6uh#`cnnDV0(mPPI0yqrw*i0v
zARC`81n5e;X+(;jFDa;vA?4FLa)E`Qn$VfkQ%6bY@mkk1L--;+o&DXl!-f2ym{_12
zTpz)N*fb&z^C;4u9Kb&J(QR0LitH&3+R{<5r)?H@={cM1c!49-ckAKT59(k5_}h+|=#yK%0ICPK^wJwJj_u=71LP5FCuDf$0vN
z^^sg(p@0EPe3ismu2myK&|0peeamhE1I6M4@qxwi0n#WDUqm1hgWK-95+F$n7Tk*W
zgQ_a}4>UBUrAjzYNPhv@0^ptCr+n_`gcC`Wji_Jc;S{ug((V0b7W^dQl6ec#r%&yL
zO*el%MlhI}o}SKI>>>cX6E7eZJ*xGiw=ki?q?CeyH2(qkG1|BvS3cWWseOGG27pq`
zf&mLuTr{pPMz|WJayo;x?iW_nn@@G%o$J3|Znqro#|=8JPF)`{`X5Q~yapzzq@T*>
z0l_xI_xbM_NC=zJ2N3n4MC3^3L39ZBuIgXa%YP7-9O!aJrhv35Kb86<`U?|OaY+Uw
zjpIN146}#Zdget^dFv&a7f>D?J`0J-lN1>MCYkr8r`ggY6PPrk;kA)$*&+=hG)Bnh
z4={SUxJ?#}xE`!~J0`_m)W1^qc&SI)4yPKOPU+%<+2vf+1FZ8HJ~8fazAkL0JA`Di
z%5)F{WMMgMHa?Fd+8yCICadXz)K>8%a9xDW8KDF&@&}91;4AMW0^8#3iCD{z8L(IM
z+b?}SO#z1cFp9H0PxFeeM$nx*z5n#P3oR+-k>H@IKxE}ObHh=~nW7|Rb?GvJkg=l4
zxx|3xOM{u+z>tR>RPj-##uq#9iUQF?!@>#|Exw$K&D1FRK3s`eDh~VUU9^`OkKL#Z
zK6Z7KhNFzVi{1Mr31f(5!_w)Sw{m!dq?
z#HIrxw1WR0^AWqL)*dPVCu6OSTT4F8z?#ZLw>{)uE=7^E!x>(YdZO|+DD%F*{3HG;
zC82%)k}yr3YHvV^Gv|0*9Xh|zrDHKbY+}u|$qild?6-D**|_?
zvZ)}oB>B(+(g;9&uKGUmGdVW{R#+*&W^G0m(Qx)Au|f>qU$$@irT?L}+NQ%zP6Ihr
zRKnhiH#w1=ImkKKxvaVJ7vBCkR1^=&aUqs|qRfdU9la<(pM}piDQmE42ZTB<(uwiM
znXt2OOLgyBGhn&kITjdb(cd5-v_tNY=ak&Z4@Gvo3s#A%r~t`QKQfIo=ddR0{}4sN`EioYWA>mwqq5v_TZZik$oa1e(mjFEPu
z?ACAsmUWhUC`0K#;u=rU#98Y-d6O7J00(gSMwNsXg4&@3Mw-tek?c^>(00K4;A@Xd
z8{G!`ObyZJDHQlWcOHCTS3X){cfcCoYjmi}$|>H!g_KRZ!guqhKj5E~*}lSMb~}Sc
z4^=MTlt4}$-xlSz>gs4IDJk{0QD39Lr=-&<#2n&NAESQf8HtBp^^n^Ycn8^d
zd>x4}dT2-{MM!jZ2RVki%t@|gw#~(`|MA%yj4KEJxl+ZUHnPu8{wCWo`-%9UO~|o3
zC;g$H7q$3(z{6-{#T>5EkMgA^mwXd8SI
zWKvptu<4z9mdpO^6?CD_)=xk8CvFW9(<8p?N}_oTxiHNSttS11{5}tYtyjw)Rwifj
z*5%#uaem*GqZlX;0q}FVlb86R8uB%|O!~u<_
z9sMt4vY+3O=yanX&f)(=;Ge7B$ZcIsJobGU_1As4yH)@U^|sPX%aiK!#7%tF@-q4A
z>XtFZKQgn>iqwCq6U>*1-BFSGU_CVvfJ0tTRW;!rjLvC|SS4g2g?%ycq`p0xTaAX=
z=Z+Hx2d7XNL;RBNpSZ@v$>1fYDhNhw6?deW=x>sq`!I`*xE-3q$9-&4CpG3!exvg?
z*0;T}e1PIitRBo&Vyq>qBP~T#$2EnXMEI2a>9ilt{gD_Vhn3aPcGPw|#Tv<%ZvRgZ
z*bgR1#_i}MfC%5bMEDJ)p#ZO*<65oxCr**NtNP>xe4TgIx#zHa{Srf+PHzo()CYrH
z9s7O1?O%2LyM`uM6V?akT&#(}^hO^)1Jrd6Tmc3ha@^_)I`A)*D)x;ff}R5nQ4t6B
ztbUN*x|;;P>)~P{F8)t(V={7bB7q(vxHzfrC*V>8R&CBv@9m!JBjW&l8V`6R%jeZg
zergLC3t^hi^i)(3x~5$SUXgr#A~9#pidx*_N%>D@2c~7{%FC*qK&<<8p;y;%VO%<(
zoo`8#!#es8e#Z})(dxN=r08dG;f&i{rREbN)%t{i{&~)r)s%)Ywe$Tjo6m1lL~nW^
zEQCeDfQ}Fhjz-w;;BqoVFlQ6`_OIFI*Aww2T28lY)zsFncqa>8uOjg~ZlcFwT66GS
z$3#X0Ylog&T(W)jmvgTtqrfEYkcf{K=o_7W*G+}D@-kv1Z6m$)sw0|0dwGbaF
zRWL48Sa^|u1>7AJPG*k|VN!pxgkJzto9(C1&7ctkbWOE@J$Sa0Bwo8T;za@}Yy`eq
z9Yu^84{d5-)83-Q6+qw(YHJg&jQ#XxPa7!vQjeqF^L4F)H{4E4avU_cU^AR9VOH%)2QGgMoB=K@+gXAks=u8onYf$T_JE5751AT!&U*IPrneB+xn7uD+J&3#TqO
zH>bYv?fxqu5|43@->b2loMLf2|Lkd|`2J|Q_1q42X~+C1g)oIr8op+)2!!h^_35XO
z&~Sg&AUG}oRo2wvVoBQuHN4;(f_xpm$(bRWPG_|669MA|po^4G-ekEgF(>I$!JsJaqXBE~|e%qG+`$U6S(+)@5KNVj!%MB0I$ohD|dU6tU7d*K-1U*vxFLjp(OSu>*jXMr{JY>ngg+r#Fm@$pP475Gda)uV|_
z6#oUWCv2+I9t^BCZYLkl5Ps3aZ*%i2sD;Zh(+t)23HkH(6#NL%p#4T#WY96p@!ddn
zl)~0lgE@?9vtd;i#5&?UEuK$yj1%aEZ1;5
zSU1Ibe4##cZND|3XxLQK5vddX6$aixU$JvTU_)~qz*xoC1O1)A$sgm0LZl?R=?bEu
z_*9a43~AC*vey0XoxMFZVbeP2r6%V;o~3KQJqPx8foM@iXe;Vo4y3Np3T3$iRRDAf
zKoiYtq*w`UZ)-EGjsGj|`_Jsap86}8ts{ZPv4HSpb!inbZgtto;5g6}KM&LFcsbY&
z(gs1mwuwrv{iFgg8blU0n
zpfrM}1mN)&C7Qa_UnSN~i5``y_9f%Y5K~fLo3@$iG7xFW%=}sg^qr8XlezL0U_5^g
zc2dT^W09zjm^vBY>Lu}g&KrG414q6MLAR%FH<5%L%~eYu>=BXx#RT6P+>qc30~8LB
z!v~rhn3nH>R2irO9oaw;9j0lpWO7!^iZbS5VA@|1T5x@k!7wMncB^^O|4UL*lJ3Z`
z`-7aW>M;g*f#C+7wu3Ni8s_No)duD3!&TDn=fdD`cL;x^I)6{a_w@TQ3-s_$OLg70
zrqO|1&Le5_G(@?_Mbm`oIMsDINQ=~>;}^WHwm}0#6L?m&{w`FbWuWJbHUb+y-pYu~
zV
z6#ZofU1`7pn-N5`q4J;={*k9K6nGZ+ddc%_I8Bd-qS;_<@4$aARFiE__l1$q{l)Q*
z;HTwqm0*9S0vHr#6b&wJcJkAs(AVs|&yp)t4xOJlX&^kS1W)&cano85@+#my7no$$=
z+^VXmvNotyFL}ksg0`~}f!F-}MMBQYCZk18ngfG_<2vKY@B)5>h>B=94(pAe#%phq
zuL`uK2@vbi`fp0{eOfLqF0L{dK>vbw9>d#?QSd{J6<=J~pNX#oYg2N8weJV8OG<3x
zg&Flvm+3gwO(hK4jWzQ3K*AE`+t{+EU1l#V_%H|#8FaWY1Ru&NNiob+BMe)0z*_?X
zqx&8P-^ZZ&i2#flO#WWLz3NZdP)jD^eh?~>Io@sq7Tjh^*jk+LjZxGVf2=iu#6jEx
zRqs0x7tBAJGF)`w39I)M4&?>Ykg@L+yhD@ZXGzfDj_PoQKLFU|NIq}hJOnE&jesJE
z&p&g7M~Ih%W7Xvonsn7fzYTwu2D-4*E1EK*18J2+8nMGKPK_%oOcGlptfzoC5$uZsWk
zAV>G?58xo6gOA<+FAE`tgNi8%FN2Q;OQ_~X%ToB92gJ~5O^_BL3t1m&=%l_015(F^5#C}1p)%oWhNjX
zD<&X7Bx`SDY-VW$0wNj~p9raldW!N=sR06sdsGKd0Z`s#sT|ML~-A$qh{}x&dL7{#4E2zu%+lRK>3--q`n~P?L
z!ws8`%d}4rK7y^#{^Kef5NzUP65^>4WX#O2u6Kkg5X2%rSW|~4d3q`?F0{9DuQtf6
z>r<=LYjvN@N1dpVU5RE8zHKP7>%29%K$&kF-RKgAAXzuRo30s>UDHaD7k&}J6MH(R
zeT`dVpAd_C8x)jQ3v{QaphMQkJmFPd*Su2vFjLxvo^&_VevbM(5C=DQZpJ;L|CVT#x+
zs6F%GGBqc4AR(o5_`xa8F8eb
zBiM|2v+Z{5vzM{?f?uT`kqXa31|M%#285779j=w(1;+3yS{i5fr=5K=6%7|1>q$EmnRawU;|kuVEC|KenRR<-a$vn
zCK4LZ{Z<${sTY4&{2&bynK?Wx^O3=0w?Om~b*!ok3sMmzDocmIi}l6!fE}bR
zW|n@}WypCMqN`cDLNk^d8+Wq-{Ang2AKxCo0f1c8rv3NVFzMC^!v
z;!nWWK1Fng@B)^r%TNY-+HHJgnFL+Cg~SG<4F|hL%?3FU(%5BWOX`Vc?F;B(-EOS{
z^ZtsM3lbiflM5%uLjGd}6Fpd*k2II0h`H#eB1H*`Qi!>5eYSNjTG3+Bq$zbuuyK~v
z)Ws2zBU4Jm#Lr588{x#<(rNgk(WBKP?K`9w&S3xPepQ1tI!j4BVPCaiimpHU2nNyy
z6}lJtFZ6`fs?_)v(N5hEdb`!dOYuwNOYKYUmaq-5t0DLU+qNrg7HN>QaD&~$wqKjp
zn{u0Ao2)f?FHkcAS-Uv5zFa}OBJ&{Xg!B6I##|0`cEzB~K^1_r{>1VVQRQC}XA?C2
zu||A{DjcSm!#*8=B_v5&@jU_gG*l%tChSs-Bo=u%zRs6~WIuL9bWm(jv^{Uq(5VJ}
zIk7F2n#|^#%5RM!#Gy+Hv~cYH)L6dXat*TP}^Km7OiaMppb7OO!^K9l8bCh!vMfXMU3TBEP=2*-DEy?bI?&%y^
z(F&{zk1B`7hoyvyop~D~0@IOZ9Za-V+~-K=Fy%U5O7$wb7ewdDXV?m+v+47SE7(OC
zg&mrWgAUlGzTyk9=GGn`-<98?-g(>s81Ia$jIT^AQ{-54JqAJ-Bx!7DI+U}O+ZVLT
z0V{A;KIcs5=POYwGLBOm${etc3CCx%%{jO31p|_g$!p0$j51@MMX;yp$HGSybKFI%
z6`W;-m6%0j3#;WWVwd$iTALcYN}YnAZ68^n<6X0Srn36B-CLvraozfPj3Zcy*aE>V
z!TiDYy9j~aM!l$(qZVK5ZaKt4oobn?o~o_UVpU|7VU>HHy8NRS)z~I;o#nMP
zJx;4-{adTZ!^uPUgWJRS!zErBUK0X3f(sr+G-$L1ek$JPM0G}QX06SH7g@?IS7DTN
zx%6h5RvPJq(?kI6585zV4^8(ZoH5%2;{#@u$kLco^~KtX%=NT&Lu<0N5Bo+t83*1S
z9=b(OTAz#TW-kI^0=$?n1TZqeCOL;P8883=K(tE!BBPCgO~#|%B__3mGUX}xX;e&l
zOy6PMWN2mTrTHcX?;o8kootKtui1dVKW*HHg=y2ZiQ}fd-VUF#`cbs#jb+Jo-w48YDFKW_!PfV&r(_G;#@qGz3R;H4GFDF#6~EBKuzYF$O7j
zj0el3Td^xq0g*Q1U8H>^c+yzfN1e8ZJs(2S5il6*8kQZd&pW3QjtO}H_C`e~3X|hu
zK}mhfo!@`)0CTwBpb!29tr=#orUj4TR@mCPf1aJBu5r#2)JA0shA-W;Dbp2HM
zO#AgyDyp=esW^XHc%4XSsLLs>sJU6%dA?-+PO=luqZLQhnwXo^%vdIEz`zVeSF={*
ztPLjl7TYT?+M>EbGRxN|)4KMvgMTCSJX!1ayP4WpP26blsL<%DifZ{%-Hwnn-^3)<
zG*vT|h6;9tdSi(Tv&Fq1^HfS6bGb#-;z8y4B>Y&pwuok8!$l)kYuip6;;F$R>*4AC
z;lZO7)S9eDmOK%~(ehD;-6!G^VIZ%grTto+$L!-z?d>Sy)|{D~%GBmmn>W)>gXI_l
zjo3y!4|#S!k`i9LcZcb0%VHUNoWD
z@2|}JmL{&KT47eWX>xk3pT8vIj^ReJrrWU8an@&kj2}17;!ohiH)>ilJGD5oxQw53
zY@W}1T{mo=m%1#uSZ}2JG@feTwZC#lxT8I~Jwg)X@w&d!y>1`nt_>y)2Fc82{Nb7R
zQh#pUzr2Sr>2KEV+;}kgJxOqH_p1H=?S0q6=fh#-b_NpyU=D!?F@XR9=iH(BRP!1C
zG=FsJ&s*$s;bw4sFsHNOQ;*mWf8QD3hVRk%-2U)dg6P0ghY*6u`<`@d=a_dD_fU8;
zIW}pfqu<$vrS*XRSbvtf-*|BOZIdv@C^9OH9c3aAjqe)*8QGVs3K$S^t{i+MEh)w1
zxiM4-sgpNoFrUG=7WbYs(4rd%A`VPnS;5>hfi)%4=z1FIR2qmkV3urzDqImdepAcUm
z^#QPf&um4Pz=dtPnWCzrs+1&$fsGZdo}rDt5v{A0EpV+10>b6W0sLuYIIH0QBta>;O6j00RRJum+8To3*2!D~+|o_kSDtzuOTs
zaxkzrvvoAHu_pT4uAaV)lOs1V@n1#%{rb0`My_W6qsiLgzlH@IAmA?tKu=2t`0uuX
zqFjGVIb_XTjVx6K&8&>99e_G`n3x#2{;B`};QWuq|BzJsA4vu_mj9Ie56*u{asmDh
z;6DcRueJUu1)7Toh70iDrsshnS2J1x0pSA?6XaKP1wBvqkW^C3xb%_cxL&%2Okm8_
zHVN*@GpYmo5}%F2F-7na>nLZ$A4u`VafRqNFI|f7xfI{IDrs{<3a+|nNzX7m`rSfb
zZgnrc@^g`xY5terVUm4*aNrz%1+ArX$#T!Rg9<+BuNoGelgo#ohu!QRJ}zLd_1c}2
z>Yeu*lU^)=Pegb`AYgyrTe4t22eQpX7*M_-f8U~DbdKau|1zV0fCwBOodwzcO9B~R
z{=de!YF89{Y~6g1{y|2jfR5J#>KBPhPDPc=y6MTddtJcz^T>$fnD|T*Ni;~?8tVGD
zrG5}YI+q*6vhEfk_(FQu^X(zN!C6+~sdm~gUo>P
zr&z*04SJ|oJM`PJjE^`aGzD(UoP4##BJE2zqIcH%4jh=8%vNLPI}HsrwV@YBoEXs^
z1Gf8BD*?ECaUun)W6zM+RX5~m_g6drt`sQG`+1dUR>!GPW^{O0brG=QxzRsxS{2`6
z1>yhkCj?D5B2L5T=&SH8}hgJU!5R+NkCG6r(5D*N|OvkAn}wv^e*6^nCl|}5x_)6)b{^}
z+T-y1^C>yG;tOtOw9mPII?%>-bL8@X*&UBA?`fIW*5+Dq-aE8Vm|_`bJEV;Li`E1M
z3PSBNaL3B9{gzGQawgHh{2jvhSOAY~uk2|0>tTr5;Y9jN=H;~bnISK3Hh#v
z;8D^gzGce}%2*sQr=9oUKMY`)czG<{JL6eWF4An1FTuYN1?)mm$GnoIw6BCNqkmC@i9QN74;wwtrVi7k!Qa!r8qne0b{<+6mxYp~g}ym-Kx
zxRFc!mp9EjG{jkq`S)lVjiQGm5Gh_p52%@?F1eLf7r=cKwMZXbGlcsyBzWwEe!7#;U$T_??Mfo=^EH_{OEC+^%!_1GvJ$tMa
z-I0AUv<|GGu5G=ZRUC;sgLD^M8lb=6mD=DIp^4DSka;mPHVzi1hLF8SeTyD=)*>oP
zZe3x*rszV4G6V%>A?TP5=Sk;O9EQG;bxNEWgTuRxlUv6%(~8Of&y*2QpYe==1Y_di
zDW90Ho<3WZ$iJ-lrbq@wrMRwg=Ku*GM5B#LiGNg_%bl-%0-Y4%GjQDJXV1|eY*F|~
zl&T0k&d6=KsS2{9GEi)-OkJqoQerJ8U=LbVFEg`r@Ik?CdSNgsx6wYSEKnKZpUGrKm7|jJ{0XHPqqkS
z6!!y7P+}$HQlQd+(EwE@8B^3=Zd^h;5qCUv2vIx}cviTo7d((QC3u%twe8?u%{DTw
zVmCK?w8L5!kf}hA__cxyC#Qv=ABpL4L*D6y^=^CzJY8Y6ifrS(IiG%HV=gztT9R7a
z%UjR>(x6ue{m}I1z^y+9S%)mnV%yw+2~II~t7;*22gQl(%v~zrcyzNZ%f?uwSis68
zv!g6>qc4_UBI=o1S>IiTJfSsXU;U3${4Wbd{Nj{s1pxzNK$G;}XyLf1@VF_enfHFO
z*E19icQ0s;T>Znfi2md0rl;;EuPCwQ0sYkABj>C7+LTacNjUO_jB5$oBeU0Bm$xF#
zu+L%P-92`HFJtS5hU(h1b)1+&9o;n^ID?39$fH-Gk)x0af?T$-5LauFf}8?Jdbkip
z+n^+@`>ybL`0j<=PC>NBotj1d#Xy{jsED=Xuh>A4=L>UKla7Ndnc7i6OkElm&WcFfl~ELK|v;ANJ9()gJQ;1Bo&Y+OFB_ehp0wx?@ad)qKX6v^)~jbES&86cH7?eFki^x3PQoR
zL7@y&x<*Luzy1;BZ2o47M^IvVsbu}diYeno%BgI3v}FRpewStE3QgXlat86PR;h+X
zciz2c&&)!u-d<&MBzW}BAHZr2yLj(;@+ObHZicQU;byy=!mCKn`yP6+hAo#_etwsp
zva~TV6rYr_qfDTN(!L@?t`p&IHQkjcP9)J0iIPC*W@P_#v*hZlqVo|8vpKxWejs*&
zIkDnH8N$>fUXKg{pu}!vl>AujWg5SA9LWl~=2(eW63b~;-@RonFpH}0#)Zm@?0SQm
z6f4cHe?J3(PloRcpSC~4%_uneZY+>gLt@K!Uq>Y#mD#AIHO%&|wS&wfvvxf4h6Vrn
z&cww)bGV86h}}zydnHzXUG>|;?{|m@p<1|S2${vVU+KZouLkkw=WU{WBKr6HzgGrm{q8^yBfK=RPk?MrKQ$p5|Sijq%U;4M6L9KcU4ps+psf6crWL1bZna
zu!=$UZuCP>+;HII>q>w(RU-|_3k>!q#$VoEkybjRlmc3vr_%|h-S>vCv<`mc3t^-X
zaAe~&!{EHNByIpE4ikPaJnCedn3P{Acs+XRF%S>kODhQaUx9$5kRYWI%3=6a|L~@_
z3n*~|O{(9l`z?ZbIYm&JWOEbea|7q4h;2}rgj1QGAt({cFoTknd}t|X|Eb}=Uw5^
zMJ!7FuNYzG?z3hI5~gO?4sjsoor?3
zw(KEsuE*gN-YHGO15%E&^8kPtw(gtLOjK3C`OJd{xYYgT*Eh@@TE6
zbx98fB{}OLrI$OT%f?c16P|h;;k@5bSfM!L^rsW5)bM*u<~|Xs?Dp!H^&q6j9
z?bJv?u&9jxLzgE@=bExqL~cNf{%9pz)oRWIzxtao@lLIwg;*TRs9y9!8lGkVpF1?T
z*^PN;WKO6G`{22fYk0BJx&z1Tt_sh3y*RgCoUm4IW(jVi&>UkOk%;6?(YC{NH>6Uf
z8)?I2VFfsic|rFy#fxF4md!*FCb8-<{B$U50k_0zQ5>sHrrc?!Z)J#d<^|bxcD!?S
zcdCz3-`T2$VbcpEo=%ry&VFk!HPKbZ$19O}O5=k%!&Bdhv^!8(?^tD?i2DG|aHf
z3f6m3CyT{-t-0bvbgAfg3AtQu#7pDg;2iZL@<#4+nQRzEXjdr9xSp1BMFtt-*vBDU
zhmbPd2aGbj6U%AFgtCu3!OLE6KbSI@)+9}yeotioy6kGTFsk#mgL${0VN=eYtk!yB
zKaL_6qeL%|8$uVsFb|L+Ytog>1yYUtO0Hda|kzS#m|fA>_NNVZI%SR5iIfWR;RkU$3Z
z|1$oMm_!7tWov|irV^YnR&Lbbi=u~f;0&t9uYs57neE(=VjI^D<&5L)T15?yKf(#S
zg+xtUKSdB7Tti+>HzwR{Qzi&1@^ih!hEO#NI#zleIsNXS{7|+VxmW}}8ZEO|zIi}2
z=w8w7f-5H+nvtegL#UW~v#Y~Rq5BcE#Hxahc?n>q73OkEH0MZ3ZW(HQ&6JsWGGyA9
zU~$Yjob`rz`Z71`9Fidf-YEIe;EhB0ILpY{i++(o1>@t}3wt+}E|xka{5D63MfNGm
za06~;$i)}d!012fV(Ll4K;u5c&O5n~p4Ar3|B}a{;}aQiMvSCMP>`O#|3~-L7(NVf
z=E^T!kwBn2n`$av5LS5syG57oHx8G4TU*rc$)CjH@Gg^h5$%
zM5*9;;_hd$o8s$}iJn>H{f@&4L#zlQDTLB&tNPo%vz>0#4K9M3`-w`+<&nTa>34^R
z)#YWr{^#oTup_%NR8Tb*$|33Vg#_Z)9%aMQC386UYu^e!75&5(YI;Y0_dWr84c8{~
z!DxKXgX}7^`owAmDUp7<1T$9}Hg4*W1_U(pxjg&?D@WuB1uN+GZQqcKO8=NKzJ
zdgr>GA+OfB0@P~;Z1s<5QBpC(w((Eq$0y%&fz3<`czZ1KzM}io7gn6mEbebB)a@Tx
zt(%sO#n`zXGzCX(D1+Gv8OBUKzBro$h;O2(RkdYaUPDtji~KWTO!Q6V;jZB|21uJj
zoSXsk2wXGo4Vh*KU7mHi6%xunifLp8@z3#6s;F1G%?LP@M(r6}@u@KpJ)~1xW4cY4
zJRhni4iqL;
zUuJVaCs{o1rnQ|tC^8ncuY8hCGw0&5LZVBY2y`>KQBbxA(-o?FV#uDmP2|kk4%#}K
zh~reNLUGq^`0-ddBh!Y1Z!iJ$E~^Y#n-$Y6muUItt<}ks`>&-RvV&VRCna0i74af>
zaWgK(J{Eu|>G7GlBTPYVNV7vd0kw?rr=kfB5h1+IxjyprQo=%m%MAI0>ZY7ew`Wjw
z>kfW}+K6zUO?t|6>^QD~zOQo3Jv~!r)Ro_L>;O`>ny9$}cWs4H4|q)_xC=>kLZjbg
zu$f)zXP?554W8t&vOchJEGvIl@lD1}Ua&>7eC8peu)djv5
z-wYw)j!V0DO47}y(ax$_v!z|_&z6T#q@=&3OiH+%Bx7yP)V!g>d*Q^`q053%!~Ze+d_FC;G51i_(X8}xFw%=81r&*
z)f2V#n|M*((O@mgZj$ZzG`vngmH~4!V{7PqiN?f0MhwmoFqtHCkTE#&BZ~@cIOrOmeB5R~vR@{f1e-#j<>vrS6`rF__OTSc~gH9K(TD|kBE
zHmOr;+ak*3Rmmt1-Rk4cELqkKB&->EJj+pTz_)^Ar*)Ry^bW>3*(^M984H$vf}80{
z$EM_XOy1~4k>PF~S)vPV96@HJotNr6es-y&uZ-l`$FL$q)M2T^n9a+K&vE&wOc~tP
z2XT$mSh~62|D!XnXC#WretOajC*EvkhEEe4t#fnKIW7diyDHMpW$EVc6@_8*y~UvK
z!;*jPP9B?g0r8+Z1{dE8Pu12fg{pw~1pT8fz+-I%guX$O8s#zz2Kl5
z`n%8f^lh;pP<^vs+HI3j6=Z}onERP{8#}#u#>KU#&69U&ET2Mo;wG%Vhr*GII0eOr
zVcJ!*?V224)t1&sqcG3h`WBT^=JE8KpYf{@NBk@!JGDNl>zj9=s;Z}s=};IfQ`cy1
zVo$VzQ}cXG6V%Ybi-R4VlP#*piZ@yKyq{ZH5qDG9#nlKC$bAdMV0A6puEkVbzYc}n
zVS`UU$`0rtp!LX{*-7NB7yf>MvUn=mNuTLjR8yNAT^}_qek+V~Q|*_D!Vp5!Y$7n*
zAN-uYw0J>g{LqvEn$oLUjn>2T#&(5Z769jye2%Jpo`2W#?}xDrU6
zx`=MD4$=>KZ$v&
zT2y#RthJ{%%2*y>K=)^qE8})|*{9|#V@f^atS?Sy%#B&#yD=nJ+OfedC1pq74Fj?I
zJO4*VjA_E5!Ru)qJO4X6ErTQxJ@*z*XpSqrya`Q}y`oUdgRC5Lj8~+L#+}J?gX);Q
zvd!E8qD~mcqGJ%(YLUF6XPLr5O9{12P(k8uBS;n%eR$eEM&Gz7
zz`LuIuHXAIa)Xurt8{uoww|ZKT!4F8gv*oSfYOWGyM(apz&Ydn_u%a>{p#W43_J77
z@QaGFB-auwR%SEwZk?HWY#BL
z5n^$_jUAlG0aAJHMTr2+h0_ym&m&0HUNPTN09-Q6eoyX1aH_r+a531Wk-aF}%jD|*
zgQljDtO*Wk*tl#&_o}B=hlydxvEJsp=<}1VfC$xnw}-6Eqp{Z)$F8SyP9_$@Qkz`i
z6pNOg6-^q-jt>qF=C{ztY>4CKJ1dSYZqY(F9Sh=p!WI0mWUNj$|IsmXShhX
z8P>KztKTZTACW4?H8hIRInFK2PQuBLdhcik+s+|%1{wM>b9gzN@*Ts)yQ0W2SkeMd$3BP
z;NmqkWq`#*$5V$6`1@qnY_W_FK
zwd|@YUBZ(P@X0qR6tt$NM@x65i%|L|B>I0-@XRMZ?=7p7G|D7}{2afuOaBIDcjw#m
z2v8P!sGFaLnk?QxYLBBEAK6^w4;VL?Q&ySSMe(fj5f3nNbrfC_<>@<-5>i2&B2e<7
zbdBG)eC53HlH*KV2;f%4OezSo;bDzedrq;}P-$XR@d_4(Y>aI@*YfhQL}pCk$UUD8
zsvu`ifBOV(qGRC?R61YK;Smu>b%8r*?w73q#08AJj^mU?g%fl;fBvxbaSWM(V3U}A
zH~;PHtYRp6yzBSMfpQe%lFyj*m7h*jI#aA|ONRAFXEQlg579qbT>+7D+Dr`=;}Y7<
zYOT3ZJkJNL_6XCoR>j^A^C~*i>#Z(ERq*ieciSO^1svf{&;Vw4>{iPNd!+J6)1QMh
zRP;_!yN4+0;SA;ZWFAhWzgvXk{3lPds0x;5z0Lk}qdh@=G@U#%5r2>Z>nIr13SnR-
z4ui>Fx?a}?+o=|{YTG%y4!9k73+O$!gMpLp)NFGxaetrk{nVK=f&NfKO92A0s9R`H3K-s@|ujJL6~
zRhj$6id)g=0;5vU$yaV`dsfD^`}e0R{&{oDFSWGL@ow-eDuju(rW_-c7+P!l?JjY?
zv9R_mn~6~6+IuP5O>|bzp8%YRp>L&{317@6e}GNJTaH9Y7JlV!kwldd@RVk-hsc2lib=BD_ia9nZHGC`#V5lJ2#%$fwG-O-?eQ{@2oNI;>9QR6v`
zh?>}k8|EW=gyI7@049IwYk)259kH2dSjB~e06lRk2IAhFafj?u0%aJIeS39fg#6pb
zm|e;K8y--hAv7N#juh%s?I#f@9KM^WjtwBHF@AR2kG`y9EVjqbuqhqnZswe{i{i#4
zEPMC4xs7X>>B^%_)J}ZcAFo*k#69`d4GKDR!OO!h7MdT&+9Ee+L+(Y&g8t?!I3E!e
zuv4|fxW7X4pbbT0Xq(1v9R$zOTVpYxK!L!Hyikxk1|cHkF?ZA<1c5=csuqj(2(TSU
zKT)8;M1Q!(di*_7+%_O@RarTz$OKP3FOv7;r>Dt_=skKNCO5bylcOIzyyYW
zfT#pvyYCGD0uLnr0ved?`XK)WDaZk*4R(Lj&|g6ia0V$LGGew5necy={vR=~Cm^@_
z8v~Lks$WphSL_?Yk1I&`_m}#%jLgg!oK>IqMW5*iOh8V@AS`h1>_HnwX!lH!W+p;?
z8wY2~&7&B<^!fBK8w=z|4W@|~;pgY43=mKy+EN8eo*Om%2COQ9^r0Zmhs8KOi!vaI
zML*t@&xC?-2Kc-I99MpvR8n_$JRhVgDk~ei1>*w4Bi6ks!~Gd}d`lV+Pvot-QR22yP$mt8kAJ
zOsgVch)|$$H_?}w#3@l%_`_YhCp3&#Z>}dw4MCqTmY=8;ilj7AJwTp`u3p$!8G0zp
zFMG5B&ra6859_1zeYNvASW1HgMXHb6<3Tjw#~&dq7Ae1+=0OLb8Rk)KbAe_k??~$s
zK?BoY+WiX~l9G}-Hh7UsllS)SU^47Ug3e7Sr|C9521*Q}gH1`?9ogrX89Q+ZRZ3y8
z+C?u|pbGrT8TD|06V~p1e~}60ok>O{)H^yeM=vmZ=;=}UrZX8)yw?v+}mpggP)mkeOgaURDO)rLJ&3Dad!ZueJF#cK_gbi+`(oI?Y1Zq6k8H7
z@4hF)3M6_DoDv973!#*f^3>UOl-ot@F2OD%D96M1;R84_gU#XYD%
zk}bJJT-D(gxU?<;9K4qsfyz0J#mIf`Lds8us8A6Ah8K?dgLQV|gQoql
z*$7;^n(1^b9zK4Q#ho{>dovYUtz+6+E;Iwrmz$k3sHmuDAK6CdiQs+SxOhars6mg6
zcEGa}!)iyqCYsSZ8h3vJyQ#(MzKz~&TX=u>adG((?R^zMIHmK}uanfyd81DL`^is1
zZ>`6}=BMu4RPpy(?$SViZDC``JBHXWg^axQsbu~zy>XEkg5ive^l4Px`K
z2s%$`wJ{W#u)wn&fziv(Po8#Q4%@+igfa{S28w&Gf+6thdp}+IZ^OB%WKuD~=D^p^
z=hV*M!If22bcb*{!~-@9s2sT-F)xvBJ$sIfWDa*m73l&TH(-5cJ(lSUxo~!+u~kET$3`cQvo*TNptm+v@o`
z>|^4Dhu&Ntajd^Tn49-$dE*Q=eh-9S+21+XLe1~52*z%9l(Vm0fCev2qmHn}4kZX&
zrU)~1$Bm)b{>hFAk(R9Z1VT7x(t|cn0g{+GAqDU*;RLwK!YNx@DB$vZM4E`bm*+W1
zys9PdrWC?5XHeV8$-bq)fU?#67wXs)(3RONASwDUN^(mXxB#&pcN_X=Nl*KCNgo>-
zob=C<{(o8juUq4)eQp>#Po>h|-8N%9bvSo(SqEIFowz?FgvBQMkV6|wkN|NIn=DE9
z*REn*vMA2ELDVCYD8DhXA(%zHL|@jmm=4G8u->P(foWnzp@Ra`<6Zm^+)9TR>pAU`
zB_ULXF%4+>S{S&oWT7gBj#+r}uZ^S=Tw06NU5XDJvq8$!FbHhJ<~|)_YE*be(hJ1{
z=VKV2^xWd+LUa6vbmv5jzVb*AZ3yu3
zvk`}*9smF{{tnObpT%v?(89}!e%nNL}(MEdPtzj*uL3uu<+B50*%8hE@A9ZZ?U@>y2aEzp+J~ua4Q=O
zdvawTWh0)>kZ<{U@~BI}_TmS#j$EwTj#YL=v@l1f4=Z>3vY1Vqmds*C3Z6+JlW4qn
zR+l6(5UWH#_!3wlMV+jG?2MlWnfMxI(pv5mb4~nAHEB&6nWw*05tyA3E29`LFf}l5
zSk=w`(xhf^nqN_YV9u^1keX;cQ^2}W@O?3(fbC%nJh3Nxvck*bc-yiQPUZEXREcii}gbL5733fnyiwTi&|nEfNXiQr0_4aw5YqM
zduGaeax>ToEsadU0`dj4hoc?^$Dj+T;&`2<(yf^<93LcSdg0c9wbXEw85Au}9-Mux
zJp(IEZmj2#hp?RuSM#)%#))nH6^!_3aY;!Uj3O!0Wab37tWGLHiOe3w
zh(Rr?rU{v!;_+NbUh73J`8*^IcavC{GGPiWNr`dFYu{|iSZBUMjDn5;`HUNkxLQo9
zE5W+##MTU+S$*F1oS;GLF-HjPtnQJz>6Uzipe@(PRX&U5^8TYj2sTFJ974RZoYL_(
zcU_C`0gmOh;o{5V_3RE0iBr#hw~9S_-0arCXijtI%MrNXzAVf}*q*t7n(3?ODOsuV
zW3gJvd%Jcr*_5gwbc1#2^b=2gF*QGq-^hiIA$>9r_oVKHpz-9fDLRQCh9Pz(47bbfA=&?lRSP&R1GD>>l*v@tPW(On%QEMT_>nP-kTX1goH2+#
zwxm9Fgk8|s5nRa*29?OK%$BiKi=-A8g!LYObl&+qt>s0VXm?IYOPy7`9>_Z)U;T)H
zBFR;#Ji7UoJ*c#o3I&h~4^>Y-`C~MK)S9=?rDcx%!j5C~6dOYGn)f4)myXD3Wbax$WomI&oK_Ti-Bj;8k3Qco1r#^(csjlLPh1op+e!AB$T+?%7N>xD
za-XV@g>e3iF}VzBD!TEK7^>0c7k;ohYV%yga(_FwED~r}UTcTblE>s=dMQWE3s;)`+B;Km
z5I`YG^}UvwH2ZZkV+@zXR}HlkIA$!cJmn!F|>r~|gx
z&q9I>mAfdMca{juNFlv1^1lVL)qEo6WX!Kaj4yTME6(3K6i+d{8`*GW*WAYK+7Q+k
zca%pn7fTC-+6kdFj!`T*?=f$YT;yjb49~g
zvwaS7>htgooEIEz8CnPq$4@O~Aq4KWJnE-w1nvZ})O#vBiem|*O_
z$CVz&Rlg{TDyhf-p03f5Fd}vHn}XY
z+Lzn@*Do&)5!th|T|otQL`<*p3PFq6Ap#|_4r`zZ0t7!E4;)XR8MTs@Hy7V-Ul$`D
z@9P?$F!K?|w^&Ppw0M~MNnx6W`0K)hIM{T8EClSvkKMVlC{2fbV{J;XVwC!=@MQl;
z421YBOLQq>ylEyZlqj@hI0RgKClTXP)wS-K^MDGlI!5_TStq4$^n(|F>?hX<7c<@d{Ni3E|X(?vj$*(?XsVv}6
zt3!YY66^>UFtC-
zNM0U(TXScDJ?hO=03bZkfT)9$Ys10Lw}GXj%7@~kdNL&cbyaGl9i~ZXg~ru>l>(!h
zIL_eO`^z*auvZo~1Eqj6&3y*u*YcE?hYC%SB^^fj#D2Q5FE}8qha@#a8rNs%cLq=E
z0RNVJ(dk?Mlve$InF_e}JW=v{?avUZp&hOIpdzX$cwXT4iMNnPzR1&3Fi{oA~$8MzR&-$Nw^>m?qW@pH-Y8c?sajHZr=Lj*FLkA-*A$PYCse9p$ga$
zEe#D3dTtupU3Sl7a(WK+Txsr9%;^36nphy3tY^Mw_wIkSxVPM%*%U$<6INV^w~QiH
z#Mt1hcTr(RHs4IJur|lN-;x{7a{Kf_wLx9^dHrroz?mpghwaKuk_u~;*%!Ba2Qi7N
z+2k3=>Ongkb=~^tG81$mZ9LHSyfn7^vSz+VfuxQ8Dz1q{BenkLu)+^?f4$#>3zi6h
z9+KifAe2@}k4z`!lb!%?f{2LOG>W62H0r@;?2D(TX7g27(&Ik6)~1jVg_z0sMNw7>
z0!0e7vd&4$o1=d;RON=Xd?{k7&%&rjiS`R(yvAl2=LXdjJCOvhR&vsgZNFzy$#Z&J
zAkSEci3@zSUOnDU0My8|P=0EEfm0ko1fsDet?VY%OW_8Ivp)9*tyc6*%;r`-C?@S}
zKrwssZ|ymLFR%4EMTHVcTzhUeQDuhQGhsPHxfm_I&y5OD4nTj~5TT9i(YO>jhqk>L
zFFHvAj)w|+$>uS=BiQtT{mCC}J1rg4>`Q}Fwmg7FRNnCDA}3&YFn178icUKXE|V7C
z%Q=PiJ-0z2O8wVs-F)KDYD2AcAtkv6{2^bXElnt{m-Kyok7D~*#rKzp*v%+K^FzPR
zDS6%NaS7)_wEcn)cXxwX+`9qX0^SZEjnzPwmOR?adT^xM0fnke*CSacMsYHY)8lh)
zPB;2-2=kLO10lM2Y2}A^nx5hUBFiz)pUdraoyEZ=dHS$lw?)P-3a0Q_e3VME(OlTp
z1a;3jlw{}gn4U85vLPkJgI>d_G|kjqamC})FN#cA6Bo(7rAh(yLYDaJ`{G7~%(yr-
zRM6uSEH)~V&{7n~(3E7>u9!*b#fxwK@#_nNl^N#27sTiEr&Vnmf}guqR`i2-VTj=6
z7vxzngosDlFER~4`)~B#_y5q|TM%0$NWyG!Eo#%EWY9V|+)3Cz?YR59!^=?Cq|K5lUbFDa)XZR^r%VJc}$KlvpJIXChMeM;r
zSS#ychP1^~o*u1Q-H$kQ9r)*~&z72(n%cAm2N`kY-9&wCQH4FTPU`IF3LF;VlHj2J
z$CG%nl~TIIh1Hn{i@TbF)Qj~t;f`I*d(xi8*O<7c-RXx6wKs!6Fg+3inGlkj?I95^fQq!(gTlYB4|Dlm
zC$(xrkZ4!G7%I-Ql8v!24XqBdqH@wk^?#Ld=J8DUe;ilx6(Ltqg=lOg!
zc}cY|sPqBhc_!(Z_UO$~Z2_UfQ8dD%s4{=>1*=`e)VgF>d9v48Lppqh>L@!n*~YxG
z>Ygi8Bx9b2B6S)}L7QyOR1F%p1ZH|LJ4PmI%8o`yGv&xq+1-_b?}4>mq;1;tFz=;_OSU(vad`ChKE*4`-lKO@$42H_
zWT41g1pZlJ+QdQ@4i8G&jWSd^kR9ljDJn2eqcp#iEaaiM1T7_g_n~#GrKL#YSxw@|
zPC3IBwbsAFbwu?yScSnRodr=s6|!dY+nn&o!1-CC`?{FN`aoyK6m82&0*>Vk1uiDF
zZO(g%!e`1{J$-yS5G;D;;NhFYQl)K^!<_={3wtT8Ng}^@3Ho_!cN*d`z&~jBnNTUs
zz%_y5`?BGnNY-kUc7xnuK<+O4%%{Y+0ua*rF8$JlLozqU!Qf{ShN3OtI*U!?+^vUV+S2lLD9zCKr>tl_hef^PHu
z{ECB64q9M<*|v7FORdVbd&aj>QcJBC#rcEO5LmF$w%6D1(bGf|b8Dsk%dR3VjZH26
zpOceiP=1a1lRAafX8p|t#7Gg8vLh^=dr_*Vcx*{><(WbH{`TJno6QSTy#(?o{s2bW
zIqB7)t0j`VGyS{lraE5HqCLg!bxIi8D;`77B#k{lXTovaivSk05QBU~aDvUfPL={|
z4qKY%VWdfuO8Rgpua3flJLfjzVPEoPe2gm{t6J2crre#$G*~ZZ_+0l-nR1CCWoV8e
zO`3Z7w|D!u;w!IX|9GfR-2ys_ulM+l(k%{opF7J{f7~mx*U-i_8U&q9+7@fiTl*y{
z%>oJT5@4y*&`MA(Gja}I0ule(Ha8tzMw*?ls_b^ADAH_SEu9Vwx=q`QHdrH{VduwQ
z^;RV**P4FoC4
zOJKbcYL`nkB~{sqV0a(-D)6;P{X>D$E2N{(d3YAJKE?rq)V~1u7GbY9|OoKjW8p$Oj^VF}*Xqd%xWLQ7^t<%NMsXkjCw2
zOeJwHe|O-XLdkIIxE9G%(r3R_+2;`Ny>4hA`U{F=szXC>iwr))sDN_)fn`N!#^59F
zr@GAz%ve?qoikf+$#_LBj+Z{z04UmYympIxQwYl5rqU=Ob0l6C@>prTRgt$(mw
z)l!B5HUp^7W;M0jz8{{!)72y3&=Wn>SqKSCE)w}O6~ULdj3xc3niaf3{?N|
z6)kbT;0Xc#>rCUp*!}7K+_Mh2(>I1V$TN@LU!BB_rBKvSAa{T}ikLfauYM-Yw8{3N
zpvg{Z0cGY+oYBm0I0zo+6_Hhhh}aEf7fOJH418YX71mPB5es|Sw~nm=49O<6i#pHq
zv!QL@rEz)R5uipZw=~8BzO9^#NX>E|0PwGn2aF&QnYfnxw00;d^pE8|F}-R&%B|=@
zX&*iIUnYkac~|2R)HjxkT0ig)TXqnh{xIlN&HHth5jtf-Ve)J;p%XLroC|j8t^`p0
z&zx3Y?E*L;xQismkNLv7j-_AH8wVx(&KlDlIfDy(rAA#ZLaIv8kIfu|_&z(SXWy4~
z8@o|$D6bR_YBlFwp{ZAnWE?D+U3Qb-1;pWg#y0H{O5dNpP)S$76XhOFumWB{7SNCP
z2`o6mh4gh0t7YJ{7^x#QEu)j9HbK}@Gqhp_hVAEznHJ2m**OWFz?(52GQpu
zY<~=3JYaNg&&e79=2hXDxbyOwT?ihP%PZk84)X@Z@j4ei&MP=+h4Q`zec+s8wz+xW
zFm2satl>Xkla`|C!7yZAnVm`!v3{GOzKCS0bKU<)x%#GDI!-q_hwZ&@Kr^f>LUe<^
zOB1GI>a+z))n~=@(3arnNti_oE{e_LfrH+4O}(mdAZ&$PP**7i8rXGU4x$q;-0A0K
z_KS2!RWWsl4mE{-q#&LCB7EQy
zqbQzfXL&IxvxLM)9oI{3*u*cm)0E8p`bVEk*IBm`_q-qJxg<``fXQr*S=q!V_PYNg
z77TfGx575x*oU+oHz_E;V&cePzI6_8%t8n<$Ow+}RVR<#Au)z1!|E)pc^u_VHw|34
zesqIJIFSb9TY{?>%D_mEq8&pyx@9rL{vTh_6v8+~IHiD_?Kp}t-E$!@9QC92kY~&c
zPUCMmQ*qwoc!w$Mi(QD!f9S;tRz`V*w_V=dE64FUW3=Xz=En#J7oz}TsY(B(?s5E!
zG1_yMl4B}ESeJ21NGf~WapYi(#`vH<-st}p{H<;vsJW_NBHVFQesf>TP_yK&UFg61
Ck~|*(

diff --git a/Docs/Resources/protocol_2.png b/Docs/Resources/protocol_2.png
deleted file mode 100644
index 0d98d5d92a4716818bd2176bc602ded3098f13dd..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 53817
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 new > target`, and under OS X select other. Choose "External Build System" and click next.
-
-2. give your target a name such as "GenerateModels" and hit finish.
-
-3. select your project in the project navigator and select the new target you just added
-
-4. under the info tab for the target set up the "External Build Tool Configuration" as follows:
-
-	#####Build Tool: `/usr/local/bin/mogenerator`  
-	(or where ever mogenerator is installed. (type `which mogenerator` in terminal to 	find the location)
-	
-
-	#####Arguments:
-	--model `` --swift --template-path `` --output-dir ``
-
-	#####example: 
-If state is installed in a subdirectory of your project, and you had a models folder for your models, it would look something like this: --model $(SRCROOT)/ProjectName/Models/Model.xcdatamodeld --swift --template-path $(SRCROOT)/../State/Templates --output-dir $(SRCROOT)/ProjectName/Models/
-
-5. Select the target that you want to use the model entities in, and select `Build Phases` and twist open the `Target Dependencies` section at the top. 
-
-6. Click the plus to add a dependency and select the GenerateModels target you just created earlier. 
-	This will tell Xcode to build your GenerateModels target before building the host target.
-	
-7. The first time you generate the code files you will have to manually add them to the project.
-
-You should now be able to add entities to the data modeler, and the code files should generate each time you build. If not, check the issue or report navigator to investigate the cause.
diff --git a/Docs/UsingProtocols.md b/Docs/UsingProtocols.md
deleted file mode 100644
index c3309f6..0000000
--- a/Docs/UsingProtocols.md
+++ /dev/null
@@ -1,105 +0,0 @@
-# Using Protocols
-
-
-State is built with a protocol oriented design. This allows you to extend models by extending each model type, and now also extend all of them by extending the `Model` protocol itself.
-
-State has native support for protocols in the model layer itself. What does native protocol support mean in a model framework? Protocol support allows you to model protocols just like any other model type, compose them, and serialize them.
-
-Here are a few of the highlights to using protocols with State:
-
-* Protocols can inherit from other protocols
-* Protocol requirements can be other model items
-* Model items can compose with protocols and vice versa
-* ==Protocol compositions can be serialized and de-serialized  ==
-
-The last item on that list is a bit tricky. How can we serialize and deserialize some unknown type that is a conformer to a protocol? Let's go through a few examples to see how State handles this.
-
-Let's say we have a model item, `Company`. `Company` has `Employees`. So the model item `Company` has a collection of `Employee` types.`Employee` is a protocol. So we say, "The model type Company composes the protocol Employee".  `Managers`, `Engineers`, and `SalesPeople` are all conforming model types of `Employee`.
-
-`Company` has a collection of `Employee` types because it has a one-to-many relationship to them. What happens when you serialize out `Company` that contains `Employees`? What happens when you try to de-serialize them back in? How will the decoder know what each conforming model type is, and how will it be able to instantiate the correct conforming model type, and compose it into the collection of `Companies`  `Employee` types?
-
-It turns out this is a common situation. So common that I decided to build this capability in to State. The answer is State handles all of this automatically, but let's take a closer look.
-
-Let's look at another example. Here is an example model design of an Asset Library. `Asset` is a protocol.  `FileAsset` is a protocol that inherits from `Asset`. AssetGroup has a one-to-many relationship to the `Asset` protocol. `ColorAsset`, `ImageAsset`, and `SoundAsset` are all conforming to the `Asset` protocol.
-
-![](Resources/protocol_2.png)
-
-Any one of the conforming types can be added to the `AssetGroup`'s assets collection. When you serialize the model out, and back, each type is restored.
-```swift
-// create two assets
-let colorAsset = ColorAsset(red: 0, alpha: 1, name: "BlackColor", blue: 0, green: 0, type:.Color)
-let soundAsset = SoundAsset(name: "test Asset", path:"this is a test", type:.Sound)
-
-// add the assets
-assetLibrary.addAsset("Test.Domain", group: "TestGroup", asset: colorAsset)
-assetLibrary.addAsset("Test.Domain", group: "TestGroup", asset: soundAsset)
-
-// save the asset library to a plist file
-assetLibrary.save(.Plist, path: "testAsset.plist")
-
-// Read the model back in
-let inAssetLibrary = AssetLibrary(.Plist, path: "testAsset.plist")
-
-// fetch the color asset
-let inColorAsset = assetLibrary.fetchAsset("asset://Test.Domain/TestGroup/BlackColor")
-```
-
-How does this work? How does the decoder know what type to create from the data being deserialized? When a conforming type is encoded to a file a model type key is added to the encoded data:
-```swift
-// Note: All of this code is generated automatically by the State Framework code generator.
-extension ColorAsset : Encodable {
-    public func encode(encoder: Encoder) {
-        encoder.encode(red, "red")
-        encoder.encode(alpha, "alpha")
-        encoder.encode(name, "name")
-        encoder.encode(blue, "blue")
-        encoder.encode(green, "green")
-        encoder.encode(type, "type")
-
-        // encode model type
-        encoder.encode("ColorAsset", model_type_key)
-
-        ColorAsset.encodeVersionIfNeeded(encoder)
-        self.willFinishEncodingWithEncoder(encoder)
-    }
-}
-```
-When State generates the code for the protocol, it searches for conforming types and generates a type lookup function that returns a type:
-
-```swift
-private func AssetTypeForKey(key: String) -> Asset.Type? {
-    switch key {
-    case "ColorAsset":
-        return ColorAsset.self
-    case "SoundAsset":
-        return SoundAsset.self
-    case "ImageAsset":
-        return ImageAsset.self
-    default:
-        return nil
-    }
-}
-```
-An extension on the decoder is generated for decoding conforming types to the protocol:
-
-```swift
-public func decodeAsset(key: String) -> Asset? {
-    let data = self.extractData()
-    let d = data[key] as? [String : AnyObject]
-    return d.flatMap(_decodeAsset)
-}
-
-private func _decodeAsset(data: [String : AnyObject]) -> Asset? {
-    guard let dataTypeKey = data[model_type_key] as? String else { return nil }
-
-    // call the type lookup function with the model type key
-    if let t = AssetTypeForKey(dataTypeKey) {
-        return t.init(decoder: Decoder(data: data))
-    }
-    return nil
-}
-```
-
-The protocol plays the role of a type `stub`, looking up the type and initiating the decoding on the conforming type.
-
-Protocol support in State now means being able to generate model code quickly and still take advantage of Swift's protocols.
diff --git a/Docs/Versioning.md b/Docs/Versioning.md
deleted file mode 100644
index ca193e2..0000000
--- a/Docs/Versioning.md
+++ /dev/null
@@ -1,18 +0,0 @@
-#Version and Migration Management
-
-
-Versioning and migration management is opt-in. It allows you to fully control the version and migration of your models.
-
-Migration is implemented as a protocol `Migratable`
-
-The migration layer of the model code passes delegation to the model extension. It's in the model  that you specify and control all of the following:
-
-* if models should be versioned when encoded
-* a versionKey to use for the version encoding
-* the current version of the model
-* if version checking and migration is done at all
-* does a model need migration
-* directly migrate raw key-value data to the current version before attempting to read a model
-
-
-When designing the models in the model designer, you can specify a version hash modifier signifying a new model version. This version modifier get's carried over to the model code so you can determine if a model version about to be decoded is a different version than the current version of the model code.
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index a3089df..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,25 +0,0 @@
-
-State
-Copyright (c) 2016 SimpleTouch LLC 
-
-The MIT License (MIT)
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
-
----
\ No newline at end of file
diff --git a/README.md b/README.md
index 90f44ee..bc1e806 100644
--- a/README.md
+++ b/README.md
@@ -1,85 +1,302 @@
-#State Model Framework
+# State Model Framework
 
-State is a model framework using structs, enums, and protocols as models and provides plist, binary, or JSON formats to store models.
+- [Designing Models in the Xcode Data Modeler] (#Designing-Models-in-the-Xcode-data-modeler)
+- [Struct Models](#Structs)
+- [Enum Models](#Enums)
+- [Protocol Models](#Protocols)
+- [Generating code](#Generating-Code)
+- [Reading and Writing Models](#Reading-and-Writing-Models)
+- [Version and Migration](#Versioning-and-Migration )
 
-- model versioning, and migration
-- design model layer in Xcode model designer and generate model code
-- models can be implemented as `struct`, `enum`, and `protocol` types.
-- immutable, optional, non-optional, and transient properties
-- custom transforms
 
-#### Creating a model
+**Requirements**
+- Swift 3.0
+- Xcode 8.0
+- iOS 8.0
+- Mogenerator 1.28
 
-To create a model you conform to the Model protocol.
+---
 
-```swift
-    public struct Person : Model {
-        public let name : String
-        public let age: Int
-    }
-
-   extension Person : Decodable {
-        public init?(decoder: Decoder) {
-            gaurd
-                let name: String = decoder.decode("name"),
-                let age: Int = decoder.decode("age")
-            else { return nil }
-
-            self.name = name
-            self.age = age
-        }
-   }
-
-   extension Person : Encodable {
-        public func encode(encoder: Endcoder) {
-            encoder.encode("name" : name)
-            encoder.encode("age" : age)
-        }
-   }
+# Designing Models in the Xcode Data Modeler
+Add a new data model file to the project, but do not link it to any targets. In the modeler elements correspond to the model as follows:
+
+|    Data Model Type    |          Swift Generated Type          |
+|-------------------|----------------------------------|
+| Entity              | struct \| enum                      |
+| Attribute    | property \| enum: case |
+| Relationship | property \| enum associated value 
  • if source == enum -> target == associated value 
  • if target == enum -> enum property
  • if one-to-many -> property is collection
| + +The following tables show the keys and values you can enter into the user-info section of the data modeler inspector window to use the options described. You only need to add these settings when you require them to be other than the default. + + +### Entity Settings +| Key | Description | Values
**bold = default when no key-value setting is present.** | +| -------------------------------- | -------------------------- | :----------------:| +| `State.Enum` | set entity is enum | `YES`, **`NO`** | +| `State.Protocol` | set entity is protocol | `YES`, **`NO`** | +| `State.Type` | enum: set enum is raw value enum, and raw value type.
protocol: set protocol inheritance. |enum: The exact type
**-or**
protocol: comma separated list of inherited protocols | +| `State.Model` | set raw value model type for a raw value enum. |`Model`, `ModelArray`, `ModelDictionary` | + + +### Attribute Settings + +| Key | Description | Values
**bold = default when no key-value setting is present.** | +| -------------------------------- | -------------------------- | :----------------:| +| `State.Immutable` | set is read-only, (use `let` instead of `var` for property) | `YES`, **`NO`** | +| `State.Type` | set type for property or associated value | The exact type | +| `State.Func` | set the function signature for a protocol function requirement| The exact signature of the function requirement | +| `State.Mutating` | set a protocol function requirement is `mutating` | `YES`, **`NO`** | +| `State.ProtocolRequirementType` | set protocol requirement type (get = readonly property) | `func`, **`var`**, `get` | +| `State.Value` | set default value for a property (only supported for non-optional properties)
**-or-**
raw value enum: sets the raw value of a case. | The exact value +| `State.Import` | import a module in the generated source associated with the particular attribute | The exact module name + +### Relationship Settings +| Key | Description | Values
**bold = default when no key-value setting is present.** | +| -------------------------------- | -------------------------- | :----------------:| +| `State.CompositionType` | set the collection type for a one-to-many relationship|Dictionary, **Array** | + + +## Structs +Entities are structs by default. + +1. Create an entity, give it a name, and set a class name in the property inspector. +2. Create attributes, and relationships as required. + +## Enums +1. Add the key `State.Enum` and the value `YES` to an entity in the user info area of the inspector to specify an entity as an enum. +2. Add attributes to create cases for the enum. The name of the attribute becomes the name of the case. + +### Associated values + +* Add the key `State.Type` to the user info section of the inspector for the attribute and specify the +type in the value field. + +*-or-* + +* Create a relationship to another model entity to specify the destination entity type as the associated value type. + +### Raw value enums + +1. Specify an entity as an enum as described above + +2. Add the `State.Type` key to the **Entity** in the user-info part of the inspector + +3. Specify a type in the value field of the `State.Type`. + +4. Add attributes to create cases for the enum. The name of the attribute becomes the name of the case. + +5. Add the `State.Value` key and a value to each **Attribute** in the user info inspector to specify the raw value of each enum case. + +Notes: +* Raw values enum types can be any type including other model entities +* Optionals are not supported for raw value types +* Raw value enums cannot have associated value types in the cases + +## Protocols + +To create a protocol: + +1. create an entity, give it name and a class name in the property inspector. +2. Add the `State.Protocol` key to the user info section, or check the abstract checkbox in the inspector. + +### Function requirements +Use the `State.ProtocolRequirementType` and the `State.Func` key on the protocol entities attributes. + +**Note:** an empty implementation is added to the **manual** file only the first time it is generated. If you already generated code before adding this requirement +you may have to manually add it to the manual file. + +On the protocol requirement attribute: +- Set State.ProtocolRequirementType to Func +- Set State.Func to the exact function signature of the requirement + +### Read-only property requirements + +Use the `State.ProtocolRequirementType` with a value of `get` on protocol attributes and relationships. + +**Note:** an empty implementation is added to the **manual** file only the first time it is generated. If you already generated code before adding this requirement +you may have to manually add it to the manual file. + +### Protocol inheritance +There are two ways you can specify a protocol inherits from other protocols. + +1. Set one protocol entity as the parent of another protocol entity +2. Use the `State.Type` key on a protocol entity to specify additional protocols. These are entered as a comma separated list. For example if you want your protocol +to also inherit from `CustomStringConvertible` and `CustomDebugStringConvertible` you would enter `CustomStringConvertible, CustomStringConvertible` as the value for +`State.Type` on the protocol entity. + +**Note:** you can use these two methods in combination if needed + +### Protocol conformance +To specify a model item has conformance to a protocol, set the protocol as the parent entity of a model item. + +**Note:** Only structs can conform at this time. You do not need to re-specify the protocols requirements in your conforming entity, they will be inherited and implemented automatically. + +### Using protocols + +You can use protocols as types just like struct and enum types. A protocol extension is started for you in the manual file so you can extend your protocol if needed. + +You can compose with protocols. For example, one model item can have a one to many composition to a protocol type. This allows you to add any conforming type into the composition collection of the containing model type. + +#### Example +The following shows a valid model design for an AssetLibrary. AssetGroup has assets which is a one-to-many relationship to the `Asset protocol type`. `FileAsset` is protocol that inherits from `Asset`. ColorAsset, ImageAsset, and SoundAsset are all conforming model types. + +You can add any of the conforming types to the assets of `AssetGroup`. When AssetGroup is serialized and de-serialized, each type contained in the assets composition will be restored. + +![](Resources/protocol_1.png) + +Notes +* Protocol requirements can include other model items +* Model items can have relationships to protocol types. + +## Optionals +Select the optional check box for an attribute in the data modeler inspector window and the property will be implemented as an optional type. + +## Default Values +You can specify a default value in the inspector window, or use `State.Value` in the user info section to give a property a default value. + +Current limitations are: +1. not supported for optional types + +## Transients +There is preliminary support for transient properties. Mark the attribute as transient in the inspector. Transients MUST be optional OR have a default value. + +## Data Modeler Notes / Gotchas + +- You must always enter a class name in the entities property inspector or no code will be generated +- Int16, Int32 or Int64 are all currently implemented as Int. +- If you enter a custom type using `State.Type` key, it will override the type in the inspector attribute type option list. Even when using `State.Type` you have to still choose an arbitrary type (which will be ignored) in the type selection box or the build will have errors. +- Do not link the .xcdatamodel file to your target. +- Do not to generate circular dependencies in the modeler. + +# Generating Code +You must have mogenerator installed and it must be the version specified +in the requirements. (newer versions of mogenerator are not supported). + +To generate the model code files: +``` +mogenerator --model <$path to the .xcdatamodeld file> --swift --template-path <$path to the state templates directory> <$path to the output directory> ``` -#### Saving and loading models to a file -```swift +## Generated files + +Two files for each entity in the model design are generated when you run Mogenerator. +- _Model.swift +- Model.swift + +The file with the underscore prefix is the automatic file, and the other is the manual file. The automatic file is updated every time you regenerate the code after modifying the model design file. The manual file is only generated once the first time you generate code. Therefore the manual file is not overwritten and is safe for you to use for extending the models via. a swift extension. + +The manual file serves the following purposes: + +- extend the model code via a swift extension in this file +- hook in to the encoding and decoding process, so you can read and write additional data during decoding and encoding if needed. +- manage the versioning and migration of the models if and when needed. + +To add the files to your project drag the model code files in to your project to add them. + +# Adding State framework to your project. + +## Carthage + +[Carthage]: https://github.com/Carthage/Carthage + +Add the following to your project's Cartfile: + +``` +github "STLabs/State" ~> 0.1 +``` +Then run `carthage update`. + +Follow the current instructions in [Carthage's README][carthage-installation] +for up to date installation instructions. + +## Submodule +1. Add State as a submodule by going to your project directory and enter the following: + `git submodule add https://github.com/STLabs/State.git` +2. Open the State folder and drag and drop the State.xcodeproj into the file navigator of your workspace. + +3. In Xcode, select the project icon to open the target window and select your host target that will use State. + +4. Select the "Build Phases" tab in the target configuration window. + +5. Add State as a target dependency to the host target + +6. Click on the + button at the top left and select "New Copy Files Phase". Rename this new phase to "Copy Frameworks", set the "Destination" to "Frameworks", and add State.framework. + +[carthage-installation]: https://github.com/Carthage/Carthage#adding-frameworks-to-an-application + + +# Reading and Writing Models + +Models, and collections of models can be + written to and read from files, `Strings`, or `Data`. + +```swift // save person to JSON -person.save(.JSON, path: "person.json") +person.write(to: fileURL, format: .JSON) + +// make a string +var jsonPerson = person.makeString(format: .JSON)) + +// make data +var dataPerson = person.makeData(format: .Plist) // load person from JSON -let person = Person(.JSON, path: "person.json") +let person = Person(file: fileURL, format: .JSON) +// create person from json string +let person = Person(content: jsonPerson) + +// create person from plist data +let person = Person(content: dataPerson) ``` +# Versioning and Migration +Versioning and migration is opt-in. Models do not version or migrate by default. -State is built on three protocols, `Encodeable`, `Decodable` and `Migratable`. Together these protocols define the `Model` protocol. +To support versioning and migration implement the following methods in your model extension: -![](Docs/Resources/diag2.png) + * `static func writeVersion(with: inout Store)` + This method is called before writing a model is finished to give the model an + opportunity to write version information to the output. + * `static func migrate(from: Store) -> Store` - The coding process is decoupled from the data conversion format. All models are encoded and decoded to intermediate key-value data. The KV data is then converted to a target format (bin, plist, json). + This method is called before reading a model to give the model + an opportunity to migrate the store. In this method: -![](Docs/Resources/diag4.png) + - read the version information from the store + - compare the version information with the "current version" + - add, remove, and update keys, and values to the store + - return the updated store +## Automatic code generation setup. -#### Xcode Data Model Designer, and Automatic Code Generation -State comes with mogenerator templates so you can design models in the Xcode data model designer. Writing model code that reads and writes models to JSON or Plists, is a tedious unnecessary task. Being able to make changes quickly to your model layer and have your models generated automatically, with consistent clean code, when you build your project is a powerful way to save you hours of writing tedious code. This is especially useful now, because as the Swift language changes, you can easily update all of your model code by just updating to the latest version of State. +If you want to automaticly update the model code each time you build your project do the following. -**Q.** If I use code generation, can I still add code manually to my models? +1. In your Xcode project, select `file > new > target`, and under OS X select other. Choose "External Build System" and click next. -**A.** Yes. When you use code generation, two files are created for each model. An automatic file and a manual file. The manual files is only created the first time you generate the code, so it is never overwritten again. The automatic file is regenerated every time you generate code. The manual file has an extension where you can extend your model. +2. give your target a name such as "GenerateModels" and hit finish. -## Documentation -- [ State docs](Docs/) +3. select your project in the project navigator and select the new target you just added -##System Requirements -- Swift 2.0 -- Xcode 7.0 -- iOS 8.0 -- Mogenerator 1.28 +4. under the info tab for the target set up the "External Build Tool Configuration" as follows: + +Build Tool: `/usr/local/bin/mogenerator` + (or where ever mogenerator is installed. (type `which mogenerator` in terminal to find the location) + + +Arguments: + --model `` --swift --template-path `` --output-dir `` + +5. Select the target that you want to use the model entities in, and select `Build Phases` and twist open the `Target Dependencies` section at the top. + +6. Click plus to add a dependency, select the GenerateModels target. + This will tell Xcode to build your GenerateModels target before building the host target. -## License +7. The first time you generate the code files you will have to manually add them to the project. -State is released under the MIT license. See -[LICENSE.md](https://github.com/STLabs/State/blob/master/LICENSE). +You should now be able to add entities to the data modeler, and the code files should generate each time you build. If not, check the issue or report navigator to investigate the cause. diff --git a/Docs/Resources/protocol_1.png b/Resources/protocol_1.png similarity index 100% rename from Docs/Resources/protocol_1.png rename to Resources/protocol_1.png diff --git a/Sources/Coding.swift b/Sources/Coding.swift deleted file mode 100644 index 4eba8c1..0000000 --- a/Sources/Coding.swift +++ /dev/null @@ -1,233 +0,0 @@ -import Foundation - -public enum DecodingError : ErrorType { - case KeyNotFound(String) - - public init(key: String) { - self = .KeyNotFound(errorMessage("Decoding Error, Key Not Found: \(key)")) - } -} - -func errorMessage(reason: String, function: String = #function ,file: String = #file, line: Int = #line) -> String { - return "reason: \(reason) function: \(function) file: \((file as NSString).lastPathComponent) line: \(line)" -} - -//****************************************************************************// -// Encodable -//****************************************************************************// - -public protocol Encodable { - func encode(encoder: Encoder) - func willFinishEncodingWithEncoder(encoder: Encoder) -} - -public extension Encodable { - - public func encode() -> [String : AnyObject] { - let coder = Encoder() - self.encode(coder) - return coder.data - } - - func encodeToFile(converter: Converter.Type, path: String) { - converter.write(self.encode(), path: path) - } - - /// Called when encoding will finish on the receiver - /// - /// - parameter encoder: the encoder used for encoding - /// - note: This method is called right before encoding finishes. - /// It provides a chance to encode any further data with the encoder. - func willFinishEncodingWithEncoder(encoder: Encoder) { } - - - /// Save a model to a specified format - public func save(format: Format, path: String) -> Bool { - return format.converter.write(self.encode(), path: path) - } - - /// Print the models JSON representation to the standard output - func printJSON() { - print(JSON.inspect(self.encode())) - } - - var JSONDescription : String? { - return JSON.write(self.encode()) - } -} - -//****************************************************************************// -// Encoder -//****************************************************************************// - - -public protocol EncoderType : class { - var data : [String : AnyObject] { get set } -} - -extension EncoderType { - public func encode(value: T?, _ key: String) { - guard let value = value else { return } - data[key] = value.encode() - } - - public func encode(value: [T]?, _ key: String) { - guard let value = value else { return } - data[key] = value.map { $0.encode() } - } - - public func encode(value: [String : T]?, _ key: String) { - guard let value = value else { return } - data[key] = value.map { $0.encode() } - } - - public func encode(value: V?, _ key: String) { - guard let value = value else { return } - self.data[key] = value as? AnyObject - } -} - -public final class Encoder : EncoderType { - public var data = [String : AnyObject]() -} - -//****************************************************************************// -// Decodable -//****************************************************************************// - -public protocol Decodable { - static func decode(decoder: Decoder) -> Self? - func didFinishDecodingWithDecoder(decoder: Decoder) -} - -public extension Decodable { - - public static func decode(data: [String : AnyObject]) -> Self? { - let decoder = Decoder(data: data) - return Self.decode(decoder) - } - - static func decode(data: AnyObject?) -> Self? { - - if let data = data as? [String : AnyObject] { - return Self.decode(data) - } - return nil - } - - static func decodeFromFile( - converter: Converter.Type, - path: String) -> Self? { - return decode(converter.read(path)) - } - - /// Initialize a model with a specified format from a file - /// note this is a failable init - public init?(_ format: Format, path: String) { - if let i = Self.decodeFromFile(format.converter, path: path) { - self = i - } else { return nil } - } - - /// decoding is finished on the receiver - /// - parameter decoder: the decoder used for decoding - /// - /// - note: This method is called after decoding takes place. - /// It provides a way to decode any further data with the decoder - /// or to do any initialization needed after decoding. - func didFinishDecodingWithDecoder(decoder: Decoder) { - - } -} - -//****************************************************************************// -// Decoder -//****************************************************************************// - -public protocol DecoderType { - var data :[String : AnyObject] { get set } -} - -extension DecoderType { - - /// decode a decodable element - /// - parameter key: a dictionary to use for decoding - /// - returns: return element of type T or nil if decoding failed - public func decode(key: String) -> T? { - let d = data[key] as? [String : AnyObject] - return d.flatMap(_decodeDecodable) - } - - /// decode a decodable array of element T - /// - parameter key: a dictionary to use for decoding - /// - returns: return an optional array of T or nil - /// if decoding failed - public func decode(key: String) -> [T]? { - let d = data[key] as? [[String : AnyObject]] - return d.flatMap { sequence($0.map( _decodeDecodable)) } - } - - /// decode a dictionary of string,decodable element T - /// - parameter key: a dictionary to use for decoding - /// - returns: return a dictionary of string, element T - /// or nil if decoding failed - public func decode(key: String) -> [String : T]? { - let d = data[key] as? [String : [String : AnyObject]] - return d.flatMap { sequence($0.map(_decodeDecodable)) } - } - - /// decode a value element V - /// - parameter key: a dictionary to use for decoding - /// - returns: return an element V or nil if decoding failed - public func decode(key: String) -> V? { - return data[key] as? V - } - - private func _decodeDecodable( - data: [String : AnyObject]) -> T? { - return T.decode(Decoder(data: data)) - } -} - -public final class Decoder : DecoderType { - public var data = [String : AnyObject]() - - /// initialize a new decoder with data - /// - parameter data: a dictionary to use for decoding - /// - returns: returns a decoder - public init(data: [String : AnyObject]) { - self.data = data - } -} - -//****************************************************************************// -// functions -//****************************************************************************// - -public func sequence(array: [T?]) -> [T]? { - return array.reduce(.Some([])) { accum, elem in - guard let accum = accum, elem = elem else { return nil } - return accum + [elem] - } -} - -public func sequence(dictionary: [String: T?]) -> [String: T]? { - return dictionary.reduce(.Some([:])) { accum, elem in - guard let accum = accum, value = elem.1 else { return nil } - var result = accum - result[elem.0] = value - return result - } -} - -extension Dictionary { - - public func map
(transform: Value -> A) -> [Key: A] { - return self.reduce([:]) { accum, elem in - var result = accum - result[elem.0] = transform(elem.1) - return result - } - - } -} \ No newline at end of file diff --git a/Sources/Conversion.swift b/Sources/Conversion.swift deleted file mode 100644 index 3afc5e8..0000000 --- a/Sources/Conversion.swift +++ /dev/null @@ -1,252 +0,0 @@ -import Foundation - -public enum Format { - case JSON - case Plist - case Binary - - public var converter: Converter.Type { - switch self { - case JSON: - return State.JSON.self - case Plist: - return State.Plist.self - case Binary: - return State.Binary.self - } - } -} - -//****************************************************************************// -// Converter -//****************************************************************************// - -/// Serialization format -public protocol Converter { - static func write(data: [String : AnyObject]?, path: String) -> Bool - static func write(data: [String : AnyObject]) -> NSData? - static func write(data: [String : AnyObject]) -> String? - static func read(path: String) -> [String : AnyObject]? - static func read(data: NSData) -> [String : AnyObject]? - static func read(contentsOfURL aURL: NSURL) -> [String : AnyObject]? - static func readString(string: String) -> [String : AnyObject]? -} - -extension Converter { - /// print data to standard output - static func inspect(data: [String : AnyObject]) { - if let string: String = write(data) { - print(string) - } else { debugPrint("Data: could not print") } - } -} - -//****************************************************************************// -// Binary -//****************************************************************************// - -/// binary Plist data format -/// base class for all data services. (see JSON, and Plist) -public class Binary: Converter { - - /// write data to a file - /// - returns: true if succeeded, false if failed - public class func write(data: [String : AnyObject]?, path: String) -> Bool { - if let input = data { - return fileFromObject(input, path: path) - } else { - return false - } - } - - /// write data to NSData - /// - returns: NSData or nil if failed - public class func write(data: [String : AnyObject]) -> NSData? { - return dataFromObject(data, prettyPrint: false) - } - - /// write data to String - /// - returns: a string or nil if failed - public class func write(data: [String : AnyObject]) -> String? { - return stringFromObject(data) - } - - /// Read data from a file - /// - returns: a data object or nil - public class func read(path: String) -> [String : AnyObject]? { - return objectFromFile(path) - } - - /// Read data from NSData - /// - returns: a data object or nil - public class func read(data: NSData) -> [String : AnyObject]? { - return objectFromData(data) - } - - /// Read data from a URL - /// - returns: a data object or nil - public class func read(contentsOfURL aURL: NSURL) -> [String : AnyObject]? { - if let data = NSData(contentsOfURL: aURL) { - return objectFromData(data) - } - return nil - } - - /// Read data from a string - /// - returns: a data object or nil - public class func readString(string: String) -> [String : AnyObject]? { - return objectFromString(string) - } - - // MARK: - INTERNAL METHODS - - class func fileFromObject(object: [String : AnyObject], path: String) -> Bool { - if let data = dataFromObject(object, prettyPrint: true) { - return data.writeToFile(path, atomically: true ) - } - else { - return false - } - } - - class func objectFromFile(path: String) -> [String : AnyObject]? { - if let data = dataFromFile(path) { - return objectFromData(data) - } else { - return nil - } - } - - class func stringFromObject(object: [String : AnyObject]) -> String? { - if let data = dataFromObject(object, prettyPrint: true) { - return stringFromData(data) - } else { - return nil - } - } - - class func objectFromString(string: String) -> [String : AnyObject]? { - if let data = dataFromString(string) { - return objectFromData(data) - } else { - return nil - } - } - - class func dataFromFile(path: String) -> NSData? { - return NSData(contentsOfFile: path) - } - - class func stringFromData(data: NSData) -> String? { - return NSString(data: data, encoding: NSUTF8StringEncoding) as? String - } - - class func dataFromString(string : String) -> NSData? { - return string.dataUsingEncoding(NSUTF8StringEncoding, - allowLossyConversion: true) - } - - class func objectFromData(data: NSData) -> [String : AnyObject]? { - return NSKeyedUnarchiver.unarchiveObjectWithData(data) as? [String : AnyObject] - } - - class func dataFromObject(object: [String : AnyObject], - prettyPrint: Bool) -> NSData? { - return NSKeyedArchiver.archivedDataWithRootObject(object) - } -} - -//****************************************************************************// -// Json -//****************************************************************************// - - -/// JSON serialization format -public final class JSON: Binary { - - override class func objectFromData(data: NSData) -> [String : AnyObject]? { - do { - let o: AnyObject = try NSJSONSerialization.JSONObjectWithData( - data, options: NSJSONReadingOptions.AllowFragments) - return o as? [String : AnyObject] - } catch let error as NSError { - Swift.print(error) - return nil - } - } - - override class func dataFromObject(object: [String : AnyObject], - prettyPrint: Bool) -> NSData? { - - guard NSJSONSerialization.isValidJSONObject(object) else { - return nil - } - - let options: NSJSONWritingOptions = prettyPrint ? .PrettyPrinted : [] - let data: NSData? - - do { - - data = try NSJSONSerialization.dataWithJSONObject(object, options: options) - } - catch let error as NSError { - - Swift.print(error) - data = nil - } - return data - } -} - -//****************************************************************************// -// Plist -//****************************************************************************// - - -/// XML Plist serialization format -public final class Plist: Binary { - - override class func objectFromData(data: NSData) -> [String : AnyObject]? { - - do { - - let o: AnyObject = - try NSPropertyListSerialization.propertyListWithData( - data, options:[.MutableContainersAndLeaves], format:nil - ) - - return o as? [String : AnyObject] - } catch let error as NSError { - - Swift.print(error) - return nil - } - } - - override class func dataFromObject(object: [String : AnyObject], - prettyPrint: Bool) -> NSData? { - - guard NSPropertyListSerialization.propertyList( - object, isValidForFormat: NSPropertyListFormat.XMLFormat_v1_0) else { - return nil - } - - do { - - let data: NSData? = try NSPropertyListSerialization.dataWithPropertyList( - object, format: NSPropertyListFormat.XMLFormat_v1_0, options: .allZeros - ) - - return data - } catch let error as NSError { - - Swift.print(error) - } - return nil - } - - override class func objectFromString(string: String) -> [String : AnyObject]? { - let s = string as NSString - return s.propertyList() as? [String : AnyObject] - } -} \ No newline at end of file diff --git a/Sources/Format.swift b/Sources/Format.swift new file mode 100644 index 0000000..ec4df02 --- /dev/null +++ b/Sources/Format.swift @@ -0,0 +1,210 @@ + +/* +Copyright (c) 2016 SIMPLETOUCH LLC + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +--- +*/ + +/// Format - File formats for Storage +/// +/// This file implements the formats available +/// for saving and loading stores and models. + +import Foundation + +/// data formats for storage. +public enum Format { + /// binary plist format + case binary + /// xml plist format + case plist + /// json format + case json + + /// returns a formatter that can + /// read and write to the current format. + var formatter : Formatter { + + switch self { + case .binary: + return Formatter() + case .plist: + return PlistFormatter() + case .json: + return JSONFormatter() + } + } +} + +// MARK: - Formatter + +/// A base formatter that provides the binary format. +class Formatter { + + /// write data to a file + /// - returns: true if succeeded, false if failed + func write(_ object: AnyObject, to url: URL) -> Bool { + + if let data = makeData(from: object, prettyPrint: true) { + return ((try? data.write(to: url, options: [.atomic] )) != nil) + } + else { + return false + } + } + + /// write data to NSData + /// - returns: NSData or nil if failed + func makeData(from object: AnyObject, + prettyPrint: Bool) -> Data? { + return NSKeyedArchiver.archivedData(withRootObject: object) + } + + /// write data to String + /// - returns: a string or nil if failed + func makeString(from object: AnyObject) -> String? { + + if let data = makeData(from: object, prettyPrint: true) { + return NSString(data: data, encoding: String.Encoding.utf8.rawValue) as? String + } else { + return nil + } + } + + /// Read data from NSData + /// - returns: a data object or nil + func read(_ data: Data) -> AnyObject? { + return NSKeyedUnarchiver.unarchiveObject(with: data) as? [String : AnyObject] + } + + /// Read file from a URL + /// - returns: a data object or nil + func read(_ url: URL) -> AnyObject? { + + if let data = try? Data(contentsOf: url) { + return read(data) + } + return nil + } + + /// Read data from a string + /// - returns: a data object or nil + func read(_ content: String) -> AnyObject? { + + guard let data = makeData(from: content) + else { + return nil + } + + return read(data) + } + + func makeData(from string : String) -> Data? { + return string.data(using: String.Encoding.utf8, + allowLossyConversion: true) + } +} + +/// JSON serialization format +final class JSONFormatter: Formatter { + + override func read(_ data: Data) -> AnyObject? { + do { + let o: AnyObject = try JSONSerialization.jsonObject( + with: data, options: JSONSerialization.ReadingOptions.allowFragments) + return o + } catch let error as NSError { + Swift.print(error) + return nil + } + } + + override func makeData(from object: AnyObject, + prettyPrint: Bool) -> Data? { + + guard JSONSerialization.isValidJSONObject(object) + else { + return nil + } + + let options: JSONSerialization.WritingOptions = prettyPrint ? .prettyPrinted : [] + let data: Data? + + do { + data = try JSONSerialization.data(withJSONObject: object, options: options) + } + catch let error as NSError { + + Swift.print(error) + data = nil + } + return data + } +} + +/// XML Plist serialization format +final class PlistFormatter: Formatter { + + override func read(_ data: Data) -> AnyObject? { + + do { + let o: AnyObject = + try PropertyListSerialization.propertyList( + from: data, options:[.mutableContainersAndLeaves], format:nil + ) + + return o + } catch let error as NSError { + + Swift.print(error) + return nil + } + } + + override func read(_ content: String) -> AnyObject? { + let s = content as NSString + return s.propertyList() + } + + + override func makeData(from object: AnyObject, + prettyPrint: Bool) -> Data? { + + guard PropertyListSerialization.propertyList( + object, isValidFor: PropertyListSerialization.PropertyListFormat.xml) + else { + return nil + } + + do { + let data: Data? = try PropertyListSerialization.data( + fromPropertyList: object, format: PropertyListSerialization.PropertyListFormat.xml, options: .allZeros + ) + + return data + } catch let error as NSError { + + Swift.print(error) + } + return nil + } +} diff --git a/Sources/KVStore.swift b/Sources/KVStore.swift deleted file mode 100644 index 28f4e91..0000000 --- a/Sources/KVStore.swift +++ /dev/null @@ -1,474 +0,0 @@ -import Foundation - -let KeypathSeperator : Character = "." -let StoreKey = "KEYS" -let DataKey = "VALUES" -let KVStoreVersionKey = "VERSION" -let KVStoreVersion = 1 - -public enum KVStoreError : ErrorType { - case KeyNotFound(String) - case NoResult -} - -/// A KVStore is a general purpose key-value store for arbitrary values. -public final class KVStore: Encodable, Decodable, EncoderType, DecoderType { - - public private(set) var keys : [String : KVStore] = [:] - public var data = [String : AnyObject]() - - /// Initialize a new Store with the specified value and key dictionaries - public init(values: [String : AnyObject] = [:], keys: [String : KVStore] = [:]) { - data = values - self.keys = keys - } - - public func save(path: String) { - save(.Plist, path: path) - } - - public static func load(path: String) -> KVStore? { - return KVStore.decodeFromFile(Format.Plist.converter, path: path) - } - - public static func load(data: NSData) -> KVStore? { - return decode(Format.Plist.converter.read(data)) - } - - //****************************************************************************// - // MARK: Coding - //****************************************************************************// - - public func encode(encoder: Encoder) { - - if data.count > 0 { - encoder.encode(data, DataKey) - } - - if keys.count > 0 { - encoder.encode(keys, StoreKey) - } - } - - public static func decode(decoder: Decoder) -> KVStore? { - let stores : [String : KVStore]? = decoder.decode(StoreKey) - let data : [String : AnyObject]? = decoder.decode(DataKey) - - let result = self.init(values: data ?? [:], keys: stores ?? [:]) - - return result - } - //****************************************************************************// - // MARK: Keys - Creating, Getting, Updating - //****************************************************************************// - - /// Return the key at the keypath - /// or nil if not found - public func getKey(keypath: String) -> KVStore? { - let editor: KVStore -> KVStore = { store in - return store - } - let onMissingKey : (KVStore, String) throws -> KVStore? = { store, key in - return nil - } - - do { - return try edit(splitKeypath(keypath), editor: editor, onMissingKey: onMissingKey) - } - catch { - return nil - } - } - - /// Adds or returns an existing key with the specified path to the reciever - /// - /// - note: any intermediate keys are created - /// - returns: key created or found - public func addKey(keypath: String) -> KVStore { - var keyNames: [String] = splitKeypath(keypath) - let keyName: String = keyNames.removeLast() - - func addNewKeyToKey(key: KVStore, name: String) -> KVStore { - let newStore = KVStore() - key.keys[name] = newStore - return newStore - } - - // if key already exsists return it - if let key = getKey(keypath) { - return key - } - else { - let editor: KVStore throws -> KVStore = { key in - return addNewKeyToKey(key, name: keyName) - } - let onMissingKey: (KVStore, String) -> KVStore? = { key, keyName in - return addNewKeyToKey(key, name: keyName) - } - - do { - return try edit(keyNames, editor: editor, onMissingKey: onMissingKey) - } - catch { - fatalError("Could not create key \(keypath)") - } - } - } - - /// Updates the key at with the specified name, or adds it - /// if it doesn't already exsist. - /// - /// - returns : the key that was replaced or nil if the newKey was added - public func updateKey(keypath: String, newKey key: KVStore) -> KVStore? { - let keys = seperateKeypath(keypath) - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - - return targetKey.keys.updateValue(key, forKey: keys.valueName) - } - - /// Removes the key at `keypath` and returns it or - /// returns nil if not found. - public func removeKey(keypath: String) -> KVStore? { - var keyNames = splitKeypath(keypath) - let keyName = keyNames.removeLast() - let editor : KVStore -> KVStore? = { key in - return key.keys.removeValueForKey(keyName) - } - let onMissingKey : (KVStore, String) throws -> KVStore? = { store, key in - print("Key not found, Invalid Key: \(keypath) Key: \(key)") - return nil - } - - do { - let result : KVStore? = try edit(keyNames, editor: editor, onMissingKey: onMissingKey) - return result - - } - catch { - return nil - } - } - - //****************************************************************************// - // MARK: Merging Stores - //****************************************************************************// - - /// Merges the sourceKey with the key specified at keypath - /// - returns : the mergedKey - public func merge(source: KVStore, intoKeypath: String ) -> KVStore { - let targetKey = addKey(intoKeypath) - return targetKey.merge(source) - } - - /// Deep merges the sourceKey into the reciever - public func merge(source: KVStore) -> KVStore { - data.merge(source.data) - - for entry in source.keys { - // if we already have this key, merge them - if let targetKey = keys[entry.0] { - targetKey.merge(entry.1) - } - // else add the key - else { - keys[entry.0] = entry.1 - } - } - return self - } - - //****************************************************************************// - // MARK: Setters - //****************************************************************************// - - public func setValue(value: V, forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - - } - - public func setValue(value: [T], forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - - public func setValue(value: [String : T], forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - - public func setValue(value: V, forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - - //****************************************************************************// - // MARK: Getters - //****************************************************************************// - - public func getValue(key: String) -> T? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decode(keys.valueName) - } - else { - return nil - } - } - - public func getValue(key: String) -> T? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decode(keys.valueName) - } - else { - return nil - } - } - - public func getValue(key: String) -> [T]? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decode(keys.valueName) - } - else { - return nil - } - } - - public func getValue(key: String) -> [String : T]? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decode(keys.valueName) - } - else { - return nil - } - } - - //****************************************************************************// - // MARK: Basic Getters - //****************************************************************************// - - /// Returns a Bool at key or nil - public func getBool(key: String) -> Bool? { - return getValue(key) - } - - /// Returns a Int at key or nil - public func getInt(key: String) -> Int? { - return getValue(key) - } - - /// Returns a double at key or nil - public func getDouble(key: String) -> Double? { - return getValue(key) - } - - /// Returns a Float at key or nil - public func getFloat(key: String) -> Float? { - return getValue(key) - } - - /// Returns a String at key or nil - public func getString(key: String) -> String? { - return getValue(key) - } - - //****************************************************************************// - // MARK: Getters with default values - //****************************************************************************// - - public func getBool(key: String , defaultValue: Bool) -> Bool { - return getValue(key) ?? defaultValue - } - - public func getInt(key: String, defaultValue: Int) -> Int { - return getValue(key) ?? defaultValue - } - - public func getDouble(key: String, defaultValue: Double) -> Double { - return getValue(key) ?? defaultValue - } - - public func getFloat(key: String, defaultValue: Float) -> Float { - return getValue(key) ?? defaultValue - } - - public func getString(key: String, defaultValue: String) -> String { - return getValue(key) ?? defaultValue - } - - public func getValue(key: String, defaultValue: T) -> T { - return getValue(key) ?? defaultValue - } - - public func getValue(key: String, defaultValue: T) -> T { - return getValue(key) ?? defaultValue - } - - public func getValue(key: String, defaultValue: [T]) -> [T] { - return getValue(key) ?? defaultValue - } - - public func getValue(key: String, defaultValue: [String : T] - ) -> [String : T] { - return getValue(key) ?? defaultValue - } - -//****************************************************************************// -// MARK: Removal -//****************************************************************************// - - /// Removes a value at key and returns it, - /// or returns nil if not found - public func removeValue(key: String) -> T? { - return removeValue(key) { store, valueName in - return store.decode(valueName) - } - } - - /// Removes a value at key and returns it, - /// or returns nil if not found - public func removeValue(key: String) -> T? { - return removeValue(key) { store, valueName in - return store.decode(valueName) - } - } - - /// Removes a value at key and returns it, - /// or returns nil if not found - public func removeValue(key: String) -> [T]? { - return removeValue(key) { store, valueName in - return store.decode(valueName) - } - } - - /// Removes a value at key and returns it, - /// or returns nil if not found - public func removeValue(key: String) -> [String : T]? { - return removeValue(key) { store, valueName in - return store.decode(valueName) - } - } - - /// Removes a value at key and returns it, - /// or returns nil if not found - func removeValue(key: String, decode: (KVStore, String) -> T? ) -> T? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - let value : T? = decode(targetKey, keys.valueName) - targetKey.data.removeValueForKey(keys.valueName) - return value - } - else { - return nil - } - } - - /// Simillar to remove but does not return - /// the value removed. - public func deleteValue(key: String) { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - targetKey.data.removeValueForKey(keys.valueName) - } - } -} - -//****************************************************************************// -// MARK: Implementations -//****************************************************************************// - -extension KVStore { - - func walk(@noescape descend descend: KVStore throws -> KVStore?, - @noescape ascend: (KVStore, KVStore) throws -> Void) rethrows -> Void { - - guard let child = try descend(self) else { - return - } - try child.walk(descend: descend, ascend: ascend) - try ascend(self, child) - } - - func edit(keys: [String], editor: KVStore throws -> V, - onMissingKey: (KVStore, String) throws -> KVStore? ) throws -> V { - var keyGen = keys.generate() - var result : V? = nil - - try walk( - descend: { store in - guard let nextKey = keyGen.next() else { - // bottom - result = try editor(store) - return nil - } - guard let next = store.keys[nextKey] else { - // we have an unrecognized key - return try onMissingKey(store, nextKey) - } - return next - }, - ascend: { _, _ in } - ) - - if let result = result { - return result - } else { - throw KVStoreError.NoResult - } - } -} - -extension Dictionary { - /// Merges the dictionary with dictionaries passed. The latter dictionaries will override - /// values of the keys that are already set - /// - /// :param dictionaries A comma seperated list of dictionaries - mutating func merge(dictionaries: Dictionary...) { - for dict in dictionaries { - for (key, value) in dict { - self.updateValue(value as! Value, forKey: key as! Key) - } - } - } -} - -/// Split keys into an array of strings -func splitKeypath(path: String) -> [String] { - return path.characters.split(".").map(String.init) -} - -/// Join keys with `KeypathSeperator` -func joinKeypath(keys: [String]) -> String { - return keys.joinWithSeparator(String(KeypathSeperator)) -} - -public func seperateKeypath(path: String) -> (keypath: String?, valueName: String) { - var keys = splitKeypath(path) - let key = keys.removeLast() - let joinResult = joinKeypath(keys) - let keypath : String? = joinResult.characters.count > 0 ? joinResult : nil - return (keypath, key) -} \ No newline at end of file diff --git a/Sources/Migration.swift b/Sources/Migration.swift deleted file mode 100644 index 6b757ba..0000000 --- a/Sources/Migration.swift +++ /dev/null @@ -1,117 +0,0 @@ -let default_version_key = "model_version" -let blank_version_hash = "" - -// All implemented as func because: http://openradar.appspot.com/21550415 -/// Provides migration and version managment for models -public protocol Migratable { - static func version(modelVersionHash: String, modelVersionHashModifier: String?) -> AnyObject? - static func needsMigration(dataVersion: AnyObject) -> Bool - static func shouldEncodeVersion() -> Bool - static func shouldMigrateIfNeeded() -> Bool - static func versionKey() -> String - static func modelVersionHash() -> String - static func modelVersionHashModifier() -> String? - static func migrateDataForDecoding(data: [String : AnyObject], dataVersion: AnyObject) -> [String : AnyObject] -} - -/// Default Migration Implementations. -/// To support migration for your models override these methods in your model. -public extension Migratable { - - /// true if the encoder should include a model version - /// when encoding the model. Set to false if you do not want a version - /// encoded with your model. - /// -note: this value must be yes to support migration - static func shouldEncodeVersion() -> Bool { - return false - } - - /// the key to use for encoding/decoding the model version - /// only used if shouldEncodeVersion is set to true - static func versionKey() -> String { - return default_version_key - } - - /// true if the decoder should perform a migration attempt - /// during decoding of the model - /// If set to false no migration attempt will be made - static func shouldMigrateIfNeeded() -> Bool { - return false - } - - /// calculate the current model version based on modelVersionHash information - /// - parameter modelVersionHash: a unique hash from the model design that generated the model - /// - parameter modelVersionHashModifier: a hash modifier if any from the model design that generated the model - /// - returns: an object the represents the model version used to denote the model "version" - /// - note: This method is called during encoding and decoding when the version is needed. - /// The modelVersionHash and modelVersionHashModifier are provided from the model designer to help denote - /// a unique version. What type, and how to make that denotation is unspecified, and ultimatly up to the impementation - /// of this method. - static func version(modelVersionHash: String, modelVersionHashModifier: String?) -> AnyObject? { - return modelVersionHash - } - - /// determines if the model data being decoded needs migration - /// - parameter dataVersion: the version of the data to be decoded - /// - returns: true if a migration is needed - /// - note: This method is called during decoding if - /// * shouldMigrateIfNeeded returns true - /// * a version was found in the data using the versionKey - - /// given the dataVersion parameter, this method should determine if the data being decoded is a different version - /// than the current version, and needs to be migrated. - static func needsMigration(dataVersion: AnyObject) -> Bool { - if let dataVersion = dataVersion as? String, - currentVersion = version( modelVersionHash(), modelVersionHashModifier: modelVersionHashModifier()) as? String { - return dataVersion != currentVersion - } else { - return false - } - } - - /// migrate model data before decoding - /// - parameter data: model data that needs migration - /// - parameter dataVersion: the version of the data to be migrated - /// - returns: migrated data - /// - note: This method is called during decoding if the following are true: - /// * shouldMigrateIfNeeded returns true - /// * a version was found in the data using the versionKey - /// * needsMigration returns true - - /// This method should perform the migration needed to prepare the data for decoding. - /// Here you can add keys and values, remove keys and values, rename properties, etc. - /// migrated data returned will then be used for decoding the model. - static func migrateDataForDecoding(data: [String : AnyObject], dataVersion: AnyObject) -> [String : AnyObject] { - return data - } - - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - static func modelVersionHash() -> String { - return blank_version_hash - } - - static func modelVersionHashModifier()-> String? { - return nil - } -} - -public extension Migratable where Self: Decodable { - static func performMigrationIfNeeded(decoder: Decoder) -> Decoder { - guard Self.shouldMigrateIfNeeded() else { return decoder } - - if let dataVersion: AnyObject = decoder.decode(Self.versionKey()) where Self.needsMigration(dataVersion) { - let migratedData = Self.migrateDataForDecoding(decoder.data, dataVersion: dataVersion) - return Decoder(data: migratedData) - } - return decoder - } -} - -public extension Migratable where Self: Encodable { - static func encodeVersionIfNeeded(encoder: Encoder) { - guard Self.shouldEncodeVersion() else { return } - encoder.encode(Self.version(Self.modelVersionHash(), modelVersionHashModifier: Self.modelVersionHashModifier()), Self.versionKey()) - } -} \ No newline at end of file diff --git a/Sources/Model.swift b/Sources/Model.swift index 1748e6b..473fd92 100644 --- a/Sources/Model.swift +++ b/Sources/Model.swift @@ -1,4 +1,353 @@ -/// A Model type is decodable, encodable and migratable -public protocol Model : Decodable, Encodable, Migratable {} +/* +Copyright (c) 2016 SIMPLETOUCH LLC +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +*/ + +import Foundation +import UIKit + +/* + + `Models`, and collections of them can be + written and read to json and plist files, + `Strings`, or `Data`. They have methods + to support migration and versioning. + + Migration is opt-in. To support migration: + + * implement `static func writeVersion(with: Store)` + + this method should be called in the `write(to:)` method + before writing to a store is finished to give the model an + opertunity to write version information to the store. + + * implement `static func migrate(from: Store) -> Store` + + this method should be called in the `read(from:)` method + before reading any values from the store to give the model + an opertunity to migrate the store. Here the model should: + + - read the version information from the store + - compare the version information with the "current version" + - add, remove, and update keys, and values to the store + - return the updated store. + + in the `read(from:)` method use the migrated store to read + and instantiate the model instance. +*/ + +public protocol Model { + + /// creates a `Model` instance from + /// a store. + static func read(from: Store) -> Self? + + /// called after reading is finished + /// to give a model an opertunity + /// to prepare or to read extra values + /// from the store before instantiation + func finishReading(from: Store) + + /// Writes the`Model` to a `Store` + func write(to: inout Store) + + /// called before writing is finished + /// to give the model an opertunity + /// to write extra values to the store + func finishWriting(to: inout Store) + + /// writes the model version to the store. + /// + /// This is called before writing a model to + /// a store is complete to give the model + /// an opertunity to write version information + /// to the store for migration purporses. + static func writeVersion(to: inout Store) + + /// migrates a store to the current version if needed. + /// + /// the default implementation returns the origional store + /// models can update the store to the current version + /// by adding, removing, and changing keys ans values in the + /// store, and return the updated store. + static func migrate(source: Store) -> Store +} + +extension Model { + + /// Create a model from a file in the specified format. + public init?(file: URL, format: Format) { + guard let data = format.formatter.read(file) + else { + return nil + } + + guard let instance = Self.read(from: Store(data: data as! [String : AnyObject])) + else { + return nil + } + + self = instance + } + + /// Create a model from a string in the specified format. + public init?(content: String, format: Format) { + + guard let data = format.formatter.read(content) + else { + return nil + } + + guard let instance = Self.read(from: Store(data: data as! [String : AnyObject])) + else { + return nil + } + + self = instance + } + + /// Create a model from data in the specified format. + public init?(content: Data, format: Format) { + guard let data = format.formatter.read(content) + else { + return nil + } + + guard let instance = Self.read(from: Store(data: data as! [String : AnyObject])) + else { + return nil + } + + self = instance + } + + /// Write the store content to a file in the specified format. + /// + /// - Returns: `true` if succeeded otherwise `false` + public func write(to location: URL, format: Format) -> Bool { + var vstore = Store() + self.write(to: &vstore) + return format.formatter.write(vstore.data, to: location) + } + + /// Convert and return the content as a string in the specified format. + public func makeString(format: Format) -> String? { + var vstore = Store() + self.write(to: &vstore) + return format.formatter.makeString(from: vstore.data) + } + + /// Convert and return the content as data in the specified format. + public func makeData(format: Format) -> Data? { + var vstore = Store() + self.write(to: &vstore) + return format.formatter.makeData(from: vstore.data, prettyPrint: true) + } + + // These default implementations do nothing to provide them as optional. + + public static func migrate(source: Store) -> Store { + return source + } + + // default implementation does nothing + public static func writeVersion(to: inout Store) { } + + // default implementation does nothing + public func finishReading(from: Store) { } + + // default implementation does nothing + public func finishWriting(to: inout Store) { } +} + +// TODO: Refactor these collections to reduce repeat code + +extension Array where Element: Model { + /// Create an array of models from a file in the specified format. + public init?(file: URL, format: Format) { + + guard let data = format.formatter.read(file) as? [[String : AnyObject]] + else { + return nil + } + + guard let instance = sequence(data.map { Element.read(from: Store(data: $0)) }) + else { + return nil + } + + self = instance + } + + /// Create an array of models from a string in the specified format. + public init?(content: String, format: Format) { + + guard let data = format.formatter.read(content) as? [[String : AnyObject]] + else { + return nil + } + + guard let instance = sequence(data.map { Element.read(from: Store(data: $0)) }) + else { + return nil + } + + self = instance + } + + /// Create an array of models from data in the specified format. + public init?(content: Data, format: Format) { + + guard let data = format.formatter.read(content) as? [[String : AnyObject]] + else { + return nil + } + + guard let instance = sequence(data.map { Element.read(from: Store(data: $0)) }) + else { + return nil + } + + self = instance + } + + /// Writes the model array to a file in the specified format. + /// + /// - Returns: `true` if succeeded otherwise `false` + public func write(to location: URL, format: Format) -> Bool { + return format.formatter.write(encodeToData(), to: location) + } + + /// Return the model array content as a string in the specified format. + public func makeString(format: Format) -> String? { + return format.formatter.makeString(from: encodeToData()) + } + + /// Return the model array content as data in the specified format. + public func makeData(format: Format) -> Data? { + return format.formatter.makeData(from: encodeToData(), prettyPrint: true) + } + + func encodeToData() -> AnyObject { + + return self.reduce([[String : AnyObject]]()) { (accum, elem) -> [[String : AnyObject]] in + var vaccum = accum + var vstore = Store() + elem.write(to: &vstore) + vaccum.append(vstore.data) + return vaccum + } + } +} + + +extension Store { + + /// Return a value at key or nil if not found. + public func value(forKey key: String) -> Value? { + + guard let data = data[key] as? [String : AnyObject] + else { + return nil + } + + return Value.read(from: Store(data: data)) + } + + /// Return a value at key or nil if not found. + public func value(forKey key: String) -> [Value]? { + + guard let data = data[key] as? [[String : AnyObject]] + else { + return nil + } + + return sequence(data.map { Value.read(from: Store(data: $0)) }) + } + + /// Return a value at key or nil if not found. + public func value(forKey key: String) -> [String : Value]? { + + guard let data = data[key] as? [String : [String : AnyObject]] + else { + return nil + } + + return sequence(data.map { Value.read(from: Store(data: $0))}) + } + + /// Add or update the value at key. + public mutating func set(_ value: Value?, forKey key: String ) { + + guard let value = value + else { + return + } + + var vstore = Store() + value.write(to: &vstore) + data[key] = vstore.data + } + + /// Add or update the value at key. + public mutating func set(_ value: [Value]?, forKey key: String) { + + guard let value = value + else { + return + } + + let data = value.reduce([[String : AnyObject]](), combine: + { (data, value) -> [[String: AnyObject]] in + var vstore = Store() + var vdata = data + value.write(to: &vstore ) + vdata.append(vstore.data) + return vdata + }) + + self.data[key] = data + } + + /// Add or update the value at key. + public mutating func set(_ value: [String : Value]?, forKey key: String) { + + guard let value = value + else { + return + } + + let data = value.reduce([String : [String : AnyObject]](), combine: { (data, element) -> [String : [String : AnyObject]] in + var vstore = Store() + var vdata = data + element.value.write(to: &vstore) + vdata[element.key] = vstore.data + return vdata + }) + + self.data[key] = data + } +} diff --git a/Sources/NSURL+Coding.swift b/Sources/NSURL+Coding.swift deleted file mode 100644 index 077b446..0000000 --- a/Sources/NSURL+Coding.swift +++ /dev/null @@ -1,36 +0,0 @@ -import Foundation - -extension NSURL : Encodable, Decodable { - - public static func decode(decoder: Decoder) -> Self? { - if let value : String = decoder.decode("URL") { - return self.init(string: value) - } - else { - return nil - } - } - - public func encode(encoder: Encoder) { - encoder.encode(self.absoluteString, "URL") - } -} - -extension KVStore { - - public func getURL(key: String) -> NSURL? { - return getValue(key) - } - - public func getURL(key: String, defaultValue: NSURL) -> NSURL { - return getValue(key) ?? defaultValue - } - - public func getURLS(key: String) -> [NSURL]? { - return getValue(key) - } - - public func getURLS(key: String, defaultValue: [NSURL]) -> [NSURL] { - return getValue(key) ?? defaultValue - } -} \ No newline at end of file diff --git a/Sources/NSUserDefaults+Coding.swift b/Sources/NSUserDefaults+Coding.swift deleted file mode 100644 index bfb7503..0000000 --- a/Sources/NSUserDefaults+Coding.swift +++ /dev/null @@ -1,52 +0,0 @@ -import Foundation - -extension NSUserDefaults { - - //****************************************************************************// - // MARK: Getters - //****************************************************************************// - - public func getDecodable(key: String) -> T? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return T.decode(dictionary) - } - - public func getDecodable(key: String) -> [T]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(T.decode)) - } - - public func getDecodable(key: String) -> [String : T]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { T.decode($0) }) - } - - public func getDecodable(key: String, defaultValue: T) -> T { - return getDecodable(key) ?? defaultValue - } - - public func getDecodable(key: String, defaultValue: [T]) -> [T] { - return getDecodable(key) ?? defaultValue - } - - public func getDecodable(key: String, defaultValue: [String : T] - ) -> [String : T] { - return getDecodable(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: Setters - //****************************************************************************// - - public func setEncodeable(value: V, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setValue(value: [T], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setValue(value: [String : T], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} \ No newline at end of file diff --git a/Sources/Store.swift b/Sources/Store.swift new file mode 100644 index 0000000..1e6281e --- /dev/null +++ b/Sources/Store.swift @@ -0,0 +1,248 @@ + +/* +Copyright (c) 2016 SIMPLETOUCH LLC + +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- +*/ + +import Foundation +import UIKit + +/* +1. A `Store` is an abstract key-value property store for + reading a writing values. + +2. A`Formatter` is used internally by a Store to read and write it's + data to files, strings, data. +*/ + +public struct Store { + + /// The contents of the store. + public var data : [String : AnyObject] + + /// Create an instance with initial data. + public init(data: [String : AnyObject] = [:]) { + self.data = data + } + +// MARK: - Values + + /// Returns the value associated with the specified key. + public func value(forKey key: String) -> V? { + return data[key] as? V + } + + /// Returns the object associated with the specified key. + public func object(forKey key: String) -> AnyObject? { + return data[key] + } + + /// Returns the array associated with the specified key. + public func array(forKey key: String) -> [AnyObject]? { + return data[key] as? [AnyObject] + } + + /// Returns the dictionary associated with the specified key. + public func dictionary(forKey key: String) -> [String : AnyObject]? { + return data[key] as? [String : AnyObject] + } + + /// Sets the value of the specified key to the specified value. + public mutating func set(_ value: V?, forKey key: String) { + guard let value = value else { return } + data[key] = value as? AnyObject + } + +// MARK: - URL + + /// Returns the url associated with the specified key. + public func value(forKey key: String) -> URL? { + + guard let urlString : String = value(forKey: key) + else { + return nil + } + return URL(string: urlString) + } + + /// Sets the value of the specified key to the specified url value. + public mutating func set(_ value: URL?, forKey key: String) { + + guard let urlString : String = value?.absoluteString + else { + return + } + data[key] = urlString + } + +// MARK: - UIColor + + /// Returns the color associated with the specified key. + public func value(forKey key: String) -> UIColor? { + + guard + let cStore = store(forKey: key), + let red: Float = cStore.value(forKey: "red"), + let green: Float = cStore.value(forKey: "green"), + let blue: Float = cStore.value(forKey: "blue"), + let alpha: Float = cStore.value(forKey: "alpha") + else { + return nil + } + + return UIColor(colorLiteralRed: red, green: green, blue: blue, alpha: alpha) + } + + /// Sets the value of the specified key to the specified color value. + public mutating func set(_ value: UIColor?, forKey key: String) { + guard let value = value + else { + return + } + var red, green, blue, alpha : CGFloat + red = 0; green = 0; blue = 0; alpha = 0 + value.getRed(&red, green: &green, blue: &blue, alpha: &alpha) + + var cStore = Store() + cStore.set(red, forKey: "red") + cStore.set(green, forKey: "green") + cStore.set(blue, forKey: "blue") + cStore.set(alpha, forKey: "alpha") + + set(cStore, forKey: key) + } + +// MARK: - Sub Stores + + /// Returns the sub store associated with the specified key. + public func store(forKey key: String) -> Store? { + + guard let data = data[key] as? [String : AnyObject] + else { + return nil + } + return Store(data: data) + } + + /// Sets the value of the specified key to the specified sub store. + public mutating func set(_ store: Store, forKey key: String) { + data[key] = store.data + } + +// MARK: File + + /// Create a store with file content in the specified format. + public init?(file: URL, format: Format) { + guard let data = format.formatter.read(file) as? [String : AnyObject] + else { + return nil + } + self.data = data + } + + /// Writes the store content to a file in the specified format. + /// + /// - Returns: `true` if succeeded otherwise `false` + public func write(to file: URL, format: Format) -> Bool { + return format.formatter.write(data, to: file) + } + +// MARK: String + + /// Returns the stores content as a string in the + /// specified format. + public func makeString(format: Format) -> String? { + return format.formatter.makeString(from: data) + } + + /// Create a store with a string in the specified format. + public init?(content: String, format: Format) { + guard let data = format.formatter.read(content) as? [String : AnyObject] + else { + return nil + } + self.data = data + } + +// MARK: Data + + /// Create a store with data in the specified format. + public init?(content: Data, format: Format) { + + guard let data = format.formatter.read(content) as? [String : AnyObject] + else { + return nil + } + self.data = data + } + + public func makeData(format: Format) -> Data? { + return format.formatter.makeData(from: data, prettyPrint: true) + } + +// MARK: Removal + + /// Removes and returns the value at the specified key + /// or .none if not found. + public mutating func remove(key: String) -> AnyObject? { + return data.removeValue(forKey: key) + } +} + +// MARK: - Utility + +public func sequence(_ array: [T?]) -> [T]? { + return array.reduce(.some([])) { accum, elem in + + guard let accum = accum, let elem = elem + else { + return nil + } + return accum + [elem] + } +} + +public func sequence(_ dictionary: [String: T?]) -> [String: T]? { + return dictionary.reduce(.some([:])) { accum, elem in + + guard let accum = accum, let value = elem.1 + else { + return nil + } + var result = accum + result[elem.0] = value + return result + } +} + +extension Dictionary { + + public func map(_ transform: (Value) -> A) -> [Key: A] { + return self.reduce([:]) { accum, elem in + var result = accum + result[elem.0] = transform(elem.1) + return result + } + } +} diff --git a/Sources/UIColor+Coding.swift b/Sources/UIColor+Coding.swift deleted file mode 100644 index ce3ff51..0000000 --- a/Sources/UIColor+Coding.swift +++ /dev/null @@ -1,63 +0,0 @@ -import UIKit - -extension UIColor : Encodable, Decodable { - - public static func decode(decoder: Decoder) -> Self? { - - if let - red : CGFloat = decoder.decode("red"), - green: CGFloat = decoder.decode("green"), - blue: CGFloat = decoder.decode("blue"), - alpha: CGFloat = decoder.decode("alpha") { - - return self.init(red: red, green: green, blue: blue, alpha: alpha) - } - else { - return nil - } - } - - public convenience init?(decoder: Decoder) { - if let - red : CGFloat = decoder.decode("red"), - green: CGFloat = decoder.decode("green"), - blue: CGFloat = decoder.decode("blue"), - alpha: CGFloat = decoder.decode("alpha") { - - self.init(red: red, green: green, blue: blue, alpha: alpha) - } - else { - return nil - } - } - - public func encode(encoder: Encoder) { - var red, green, blue, alpha : CGFloat - red = 0; green = 0; blue = 0; alpha = 0 - self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) - - encoder.encode(red, "red") - encoder.encode(green, "green") - encoder.encode(blue, "blue") - encoder.encode(alpha, "alpha") - } -} - -extension KVStore { - - public func getColor(key: String) -> UIColor? { - return getValue(key) - } - - public func getColor(key: String, defaultValue: UIColor) -> UIColor { - return getValue(key) ?? defaultValue - } - - public func getColors(key: String) -> [UIColor]? { - return getValue(key) - } - - public func getColors(key: String, defaultValue: [UIColor]) -> [UIColor] { - return getValue(key) ?? defaultValue - } -} \ No newline at end of file diff --git a/State.xcodeproj/project.pbxproj b/State.xcodeproj/project.pbxproj index 1764bc4..7263cfe 100644 --- a/State.xcodeproj/project.pbxproj +++ b/State.xcodeproj/project.pbxproj @@ -7,14 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - 041817871B124AB4002CA532 /* BaseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041817781B124AB4002CA532 /* BaseTest.swift */; }; - 041817891B124AB4002CA532 /* ConverterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041817791B124AB4002CA532 /* ConverterTests.swift */; }; - 0418178B1B124AB4002CA532 /* DecodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0418177A1B124AB4002CA532 /* DecodableTests.swift */; }; - 0418178F1B124AB4002CA532 /* DefaultTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0418177C1B124AB4002CA532 /* DefaultTests.swift */; }; - 041817911B124AB4002CA532 /* EncodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0418177D1B124AB4002CA532 /* EncodableTests.swift */; }; - 041817951B124AB4002CA532 /* EnumTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0418177F1B124AB4002CA532 /* EnumTests.swift */; }; - 0418179B1B124AB4002CA532 /* RecursiveTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041817821B124AB4002CA532 /* RecursiveTests.swift */; }; - 0418179F1B124AB4002CA532 /* TemplateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041817841B124AB4002CA532 /* TemplateTests.swift */; }; 044F88121AE5D02900FAB475 /* ObjectModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04012AC61AE132AE006DAC19 /* ObjectModels.swift */; }; 044F88131AE5D02900FAB475 /* RecursiveModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04012AC71AE132AE006DAC19 /* RecursiveModel.swift */; }; 044F88961AE69BD900FAB475 /* Company.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044F88881AE69BD900FAB475 /* Company.swift */; }; @@ -30,75 +22,67 @@ 044F88A11AE69BD900FAB475 /* TestRelationships.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044F88931AE69BD900FAB475 /* TestRelationships.swift */; }; 044F88A21AE69BD900FAB475 /* TestTransformable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044F88941AE69BD900FAB475 /* TestTransformable.swift */; }; 044F88A31AE69BD900FAB475 /* TestTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 044F88951AE69BD900FAB475 /* TestTypes.swift */; }; - 0485AA1A1AFE9B83008E89D6 /* _TestMigrationV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485AA171AFE9B83008E89D6 /* _TestMigrationV1.swift */; }; - 0485AA1C1AFE9B83008E89D6 /* TestMigrationV1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485AA181AFE9B83008E89D6 /* TestMigrationV1.swift */; }; 0485AA221AFE9BDE008E89D6 /* TestMigrationV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485AA1E1AFE9BDE008E89D6 /* TestMigrationV2.swift */; }; - 0485AA251AFE9C43008E89D6 /* _TestMigrationV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0485AA231AFE9C43008E89D6 /* _TestMigrationV2.swift */; }; 04925EC01AE9967500BF1D88 /* TestDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04925EBF1AE9967500BF1D88 /* TestDefaults.swift */; }; - 04925EC21AE9967B00BF1D88 /* _TestDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04925EC11AE9967B00BF1D88 /* _TestDefaults.swift */; }; 04B46BE21B2EF44F00ED20BF /* BasicModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04012AC51AE132AE006DAC19 /* BasicModels.swift */; }; - 04B46BE41B2EF89400ED20BF /* RelationshipTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041817831B124AB4002CA532 /* RelationshipTests.swift */; }; - 04B46BE51B2EFAE000ED20BF /* EncodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0418177E1B124AB4002CA532 /* EncodingTests.swift */; }; - 04B46BE71B2EFAE800ED20BF /* DecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0418177B1B124AB4002CA532 /* DecodingTests.swift */; }; - 04BD1ACF1AE9A6E4008F576C /* _TestDefaultsChild.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BD1ACD1AE9A6E4008F576C /* _TestDefaultsChild.swift */; }; 04BD1AD01AE9A6E4008F576C /* TestDefaultsChild.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BD1ACE1AE9A6E4008F576C /* TestDefaultsChild.swift */; }; - 04BD1AEF1AEACF75008F576C /* _TestRegEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BD1AED1AEACF75008F576C /* _TestRegEnum.swift */; }; 04BD1AF01AEACF75008F576C /* TestRegEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BD1AEE1AEACF75008F576C /* TestRegEnum.swift */; }; - 04BD1AF31AEACF86008F576C /* _TestRawEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BD1AF11AEACF86008F576C /* _TestRawEnum.swift */; }; 04BD1AF41AEACF86008F576C /* TestRawEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BD1AF21AEACF86008F576C /* TestRawEnum.swift */; }; - 04BD1AF61AEAD2A0008F576C /* _TestAssociatedEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BD1AF51AEAD2A0008F576C /* _TestAssociatedEnum.swift */; }; 04BD1AF81AEAD2B9008F576C /* TestAssociatedEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BD1AF71AEAD2B9008F576C /* TestAssociatedEnum.swift */; }; - 04BD1AFF1AEBA549008F576C /* _TestAssociatedOptionalEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BD1AFD1AEBA549008F576C /* _TestAssociatedOptionalEnum.swift */; }; 04BD1B001AEBA549008F576C /* TestAssociatedOptionalEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04BD1AFE1AEBA549008F576C /* TestAssociatedOptionalEnum.swift */; }; - 04C1B92F1AE9219900A85730 /* _Company.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B9211AE9219900A85730 /* _Company.swift */; }; - 04C1B9301AE9219900A85730 /* _Employee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B9221AE9219900A85730 /* _Employee.swift */; }; - 04C1B9311AE9219900A85730 /* _Gender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B9231AE9219900A85730 /* _Gender.swift */; }; - 04C1B9321AE9219900A85730 /* _Grandchild.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B9241AE9219900A85730 /* _Grandchild.swift */; }; - 04C1B9331AE9219900A85730 /* _TestChild.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B9251AE9219900A85730 /* _TestChild.swift */; }; - 04C1B9341AE9219900A85730 /* _TestCollections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B9261AE9219900A85730 /* _TestCollections.swift */; }; - 04C1B9361AE9219900A85730 /* _TestImmutableOptionalTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B9281AE9219900A85730 /* _TestImmutableOptionalTypes.swift */; }; - 04C1B9371AE9219900A85730 /* _TestImmutableTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B9291AE9219900A85730 /* _TestImmutableTypes.swift */; }; - 04C1B9381AE9219900A85730 /* _TestOptionalTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B92A1AE9219900A85730 /* _TestOptionalTypes.swift */; }; - 04C1B9391AE9219900A85730 /* _TestOverrideType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B92B1AE9219900A85730 /* _TestOverrideType.swift */; }; - 04C1B93A1AE9219900A85730 /* _TestRelationships.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B92C1AE9219900A85730 /* _TestRelationships.swift */; }; - 04C1B93B1AE9219900A85730 /* _TestTransformable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B92D1AE9219900A85730 /* _TestTransformable.swift */; }; - 04C1B93C1AE9219900A85730 /* _TestTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C1B92E1AE9219900A85730 /* _TestTypes.swift */; }; - 04C3C6DA1AFA73E600C95039 /* _TestTransient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C3C6D71AFA73E600C95039 /* _TestTransient.swift */; }; 04C3C6DC1AFA73E600C95039 /* TestTransient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C3C6D81AFA73E600C95039 /* TestTransient.swift */; }; - 04C3C6E01AFA77E300C95039 /* _TestTransient2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C3C6DD1AFA77E300C95039 /* _TestTransient2.swift */; }; 04C3C6E21AFA77E300C95039 /* TestTransient2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C3C6DE1AFA77E300C95039 /* TestTransient2.swift */; }; - 04C3C6E61AFA7E2400C95039 /* _TestTransient3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C3C6E31AFA7E2400C95039 /* _TestTransient3.swift */; }; 04C3C6E81AFA7E2400C95039 /* TestTransient3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04C3C6E41AFA7E2400C95039 /* TestTransient3.swift */; }; 960072DC1BA8590E00AFD3C5 /* TestParentProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A860291B4B2D5E006A5ABE /* TestParentProtocol.swift */; }; - 960072DF1BA8591700AFD3C5 /* _TestParentProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A85FD41B4AD38E006A5ABE /* _TestParentProtocol.swift */; }; - 960072E11BA8593800AFD3C5 /* _TestProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A85FD51B4AD38E006A5ABE /* _TestProtocol.swift */; }; 960072E31BA8594300AFD3C5 /* TestProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A860321B4B35A8006A5ABE /* TestProtocol.swift */; }; - 960072E61BA8595000AFD3C5 /* _TestProtocolConformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A85FE31B4ADCF8006A5ABE /* _TestProtocolConformer.swift */; }; 961D13F01C11AE5A00F0EE1F /* Big_data-bin.plist in Resources */ = {isa = PBXBuildFile; fileRef = 961D13EB1C11AE5A00F0EE1F /* Big_data-bin.plist */; }; 961D13F21C11AE5A00F0EE1F /* Big_data.json in Resources */ = {isa = PBXBuildFile; fileRef = 961D13EC1C11AE5A00F0EE1F /* Big_data.json */; }; 961D13F41C11AE5A00F0EE1F /* Big_data.plist in Resources */ = {isa = PBXBuildFile; fileRef = 961D13ED1C11AE5A00F0EE1F /* Big_data.plist */; }; 961D13F61C11AE5A00F0EE1F /* Data.json in Resources */ = {isa = PBXBuildFile; fileRef = 961D13EE1C11AE5A00F0EE1F /* Data.json */; }; 961D13F81C11AE5A00F0EE1F /* Data.plist in Resources */ = {isa = PBXBuildFile; fileRef = 961D13EF1C11AE5A00F0EE1F /* Data.plist */; }; - 9622DF981C9C8EC5009C1E6B /* NSURL+Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96B8A90C1C9B6CA60086619F /* NSURL+Coding.swift */; }; - 9622DFA11C9EE637009C1E6B /* KVStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9622DF921C9C8A61009C1E6B /* KVStore.swift */; }; - 9622DFA21C9EE63A009C1E6B /* UIColor+Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96B8A90D1C9B6CA60086619F /* UIColor+Coding.swift */; }; - 9690A0641C942C9100924F4C /* _TestProtocolConformer2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9690A0621C942C9100924F4C /* _TestProtocolConformer2.swift */; }; + 96239BD01D1DA94700C27329 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9622DF921C9C8A61009C1E6B /* Store.swift */; }; + 96712B821D2DA0B100C7E1C5 /* _Company.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B651D2DA0B100C7E1C5 /* _Company.swift */; }; + 96712B831D2DA0B100C7E1C5 /* _Employee.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B661D2DA0B100C7E1C5 /* _Employee.swift */; }; + 96712B841D2DA0B100C7E1C5 /* _Gender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B671D2DA0B100C7E1C5 /* _Gender.swift */; }; + 96712B851D2DA0B100C7E1C5 /* _Grandchild.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B681D2DA0B100C7E1C5 /* _Grandchild.swift */; }; + 96712B861D2DA0B100C7E1C5 /* _TestAssociatedEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B691D2DA0B100C7E1C5 /* _TestAssociatedEnum.swift */; }; + 96712B871D2DA0B100C7E1C5 /* _TestAssociatedOptionalEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B6A1D2DA0B100C7E1C5 /* _TestAssociatedOptionalEnum.swift */; }; + 96712B881D2DA0B100C7E1C5 /* _TestChild.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B6B1D2DA0B100C7E1C5 /* _TestChild.swift */; }; + 96712B891D2DA0B100C7E1C5 /* _TestCollections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B6C1D2DA0B100C7E1C5 /* _TestCollections.swift */; }; + 96712B8A1D2DA0B100C7E1C5 /* _TestDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B6D1D2DA0B100C7E1C5 /* _TestDefaults.swift */; }; + 96712B8B1D2DA0B100C7E1C5 /* _TestDefaultsChild.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B6E1D2DA0B100C7E1C5 /* _TestDefaultsChild.swift */; }; + 96712B8C1D2DA0B100C7E1C5 /* _TestDictionaryComposition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B6F1D2DA0B100C7E1C5 /* _TestDictionaryComposition.swift */; }; + 96712B8D1D2DA0B100C7E1C5 /* _TestImmutableOptionalTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B701D2DA0B100C7E1C5 /* _TestImmutableOptionalTypes.swift */; }; + 96712B8E1D2DA0B100C7E1C5 /* _TestImmutableTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B711D2DA0B100C7E1C5 /* _TestImmutableTypes.swift */; }; + 96712B8F1D2DA0B100C7E1C5 /* _TestMigrationV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B721D2DA0B100C7E1C5 /* _TestMigrationV2.swift */; }; + 96712B901D2DA0B100C7E1C5 /* _TestOptionalTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B731D2DA0B100C7E1C5 /* _TestOptionalTypes.swift */; }; + 96712B911D2DA0B100C7E1C5 /* _TestOverrideType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B741D2DA0B100C7E1C5 /* _TestOverrideType.swift */; }; + 96712B921D2DA0B100C7E1C5 /* _TestParentProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B751D2DA0B100C7E1C5 /* _TestParentProtocol.swift */; }; + 96712B931D2DA0B100C7E1C5 /* _TestProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B761D2DA0B100C7E1C5 /* _TestProtocol.swift */; }; + 96712B941D2DA0B100C7E1C5 /* _TestProtocolConformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B771D2DA0B100C7E1C5 /* _TestProtocolConformer.swift */; }; + 96712B951D2DA0B100C7E1C5 /* _TestProtocolConformer2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B781D2DA0B100C7E1C5 /* _TestProtocolConformer2.swift */; }; + 96712B961D2DA0B100C7E1C5 /* _TestProtocolContainter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B791D2DA0B100C7E1C5 /* _TestProtocolContainter.swift */; }; + 96712B971D2DA0B100C7E1C5 /* _TestRawEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B7A1D2DA0B100C7E1C5 /* _TestRawEnum.swift */; }; + 96712B981D2DA0B100C7E1C5 /* _TestRegEnum.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B7B1D2DA0B100C7E1C5 /* _TestRegEnum.swift */; }; + 96712B991D2DA0B100C7E1C5 /* _TestRelationships.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B7C1D2DA0B100C7E1C5 /* _TestRelationships.swift */; }; + 96712B9A1D2DA0B100C7E1C5 /* _TestTransformable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B7D1D2DA0B100C7E1C5 /* _TestTransformable.swift */; }; + 96712B9B1D2DA0B100C7E1C5 /* _TestTransient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B7E1D2DA0B100C7E1C5 /* _TestTransient.swift */; }; + 96712B9C1D2DA0B100C7E1C5 /* _TestTransient2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B7F1D2DA0B100C7E1C5 /* _TestTransient2.swift */; }; + 96712B9D1D2DA0B100C7E1C5 /* _TestTransient3.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B801D2DA0B100C7E1C5 /* _TestTransient3.swift */; }; + 96712B9E1D2DA0B100C7E1C5 /* _TestTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96712B811D2DA0B100C7E1C5 /* _TestTypes.swift */; }; 9690A0651C942C9100924F4C /* TestProtocolConformer2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9690A0631C942C9100924F4C /* TestProtocolConformer2.swift */; }; - 96960A5C1C90F00B00D4E6D0 /* Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96960A4C1C90F00B00D4E6D0 /* Migration.swift */; }; + 96930D991D3BCFD5001F9565 /* Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96930D981D3BCFD5001F9565 /* Format.swift */; }; 96960A5D1C90F00B00D4E6D0 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96960A4D1C90F00B00D4E6D0 /* Model.swift */; }; 96960A681C90F07700D4E6D0 /* State.h in Headers */ = {isa = PBXBuildFile; fileRef = 96960A651C90F07700D4E6D0 /* State.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 96A5435F1B63C6C8009A2B2D /* _TestDictionaryComposition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A5435D1B63C6C8009A2B2D /* _TestDictionaryComposition.swift */; }; + 969C00FB1D40083B0039CBEB /* BaseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C00F61D40083B0039CBEB /* BaseTest.swift */; }; + 969C00FC1D40083B0039CBEB /* FormatTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C00F71D40083B0039CBEB /* FormatTests.swift */; }; + 969C00FD1D40083B0039CBEB /* ModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C00F81D40083B0039CBEB /* ModelTests.swift */; }; + 969C00FE1D40083B0039CBEB /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C00F91D40083B0039CBEB /* PerformanceTests.swift */; }; + 969C00FF1D40083B0039CBEB /* StoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969C00FA1D40083B0039CBEB /* StoreTests.swift */; }; 96A543611B63C6C8009A2B2D /* TestDictionaryComposition.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A5435E1B63C6C8009A2B2D /* TestDictionaryComposition.swift */; }; - 96B8A8F91C9AD3CC0086619F /* Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96B8A8F81C9AD3CC0086619F /* Coding.swift */; }; - 96B8A8FC1C9ADFCF0086619F /* ProtocolTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9690A0601C9429A300924F4C /* ProtocolTests.swift */; }; - 96B8A8FD1C9ADFDB0086619F /* _TestProtocolContainter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A8602C1B4B3040006A5ABE /* _TestProtocolContainter.swift */; }; 96B8A8FE1C9ADFDB0086619F /* TestProtocolContainter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96A8602F1B4B304A006A5ABE /* TestProtocolContainter.swift */; }; 96B8A9091C9AFA390086619F /* (null) in Sources */ = {isa = PBXBuildFile; }; - 96B8A9491C9BEB870086619F /* Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96B8A9101C9B6FD10086619F /* Conversion.swift */; }; - 96C5C3891B3C6988009121A1 /* MigrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041817801B124AB4002CA532 /* MigrationTests.swift */; }; 96C86BFD1BC2E81800D6F0F3 /* TestProtocolConformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96C86BFB1BC2E7F500D6F0F3 /* TestProtocolConformer.swift */; }; - 96FDF3361CAAABCB0099074C /* NSUserDefaults+Coding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96FDF3351CAAABCB0099074C /* NSUserDefaults+Coding.swift */; }; - 96FDF3371CAAC5420099074C /* KVStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9622DF941C9C8A85009C1E6B /* KVStoreTests.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -139,21 +123,8 @@ 04012AC61AE132AE006DAC19 /* ObjectModels.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ObjectModels.swift; path = Tests/Models/ObjectModels.swift; sourceTree = ""; }; 04012AC71AE132AE006DAC19 /* RecursiveModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RecursiveModel.swift; path = Tests/Models/RecursiveModel.swift; sourceTree = ""; }; 041817621B1239C4002CA532 /* TestModels.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = TestModels.xcdatamodel; sourceTree = ""; }; - 041817781B124AB4002CA532 /* BaseTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BaseTest.swift; path = Tests/Tests/BaseTest.swift; sourceTree = SOURCE_ROOT; }; - 041817791B124AB4002CA532 /* ConverterTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ConverterTests.swift; path = Tests/Tests/ConverterTests.swift; sourceTree = SOURCE_ROOT; }; - 0418177A1B124AB4002CA532 /* DecodableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DecodableTests.swift; path = Tests/Tests/DecodableTests.swift; sourceTree = SOURCE_ROOT; }; - 0418177B1B124AB4002CA532 /* DecodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DecodingTests.swift; path = Tests/Tests/DecodingTests.swift; sourceTree = SOURCE_ROOT; }; - 0418177C1B124AB4002CA532 /* DefaultTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DefaultTests.swift; path = Tests/Tests/DefaultTests.swift; sourceTree = SOURCE_ROOT; }; - 0418177D1B124AB4002CA532 /* EncodableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EncodableTests.swift; path = Tests/Tests/EncodableTests.swift; sourceTree = SOURCE_ROOT; }; - 0418177E1B124AB4002CA532 /* EncodingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EncodingTests.swift; path = Tests/Tests/EncodingTests.swift; sourceTree = SOURCE_ROOT; }; - 0418177F1B124AB4002CA532 /* EnumTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EnumTests.swift; path = Tests/Tests/EnumTests.swift; sourceTree = SOURCE_ROOT; }; - 041817801B124AB4002CA532 /* MigrationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MigrationTests.swift; path = Tests/Tests/MigrationTests.swift; sourceTree = SOURCE_ROOT; }; - 041817811B124AB4002CA532 /* PerfTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PerfTests.swift; path = Tests/Tests/PerfTests.swift; sourceTree = SOURCE_ROOT; }; - 041817821B124AB4002CA532 /* RecursiveTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RecursiveTests.swift; path = Tests/Tests/RecursiveTests.swift; sourceTree = SOURCE_ROOT; }; - 041817831B124AB4002CA532 /* RelationshipTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RelationshipTests.swift; path = Tests/Tests/RelationshipTests.swift; sourceTree = SOURCE_ROOT; }; - 041817841B124AB4002CA532 /* TemplateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TemplateTests.swift; path = Tests/Tests/TemplateTests.swift; sourceTree = SOURCE_ROOT; }; 0443C9D01AE7F0F1008299E5 /* human.swift.motemplate */ = {isa = PBXFileReference; lastKnownFileType = text; name = human.swift.motemplate; path = Templates/human.swift.motemplate; sourceTree = SOURCE_ROOT; }; - 0443C9D11AE7F0F1008299E5 /* machine.swift.motemplate */ = {isa = PBXFileReference; lastKnownFileType = text; name = machine.swift.motemplate; path = Templates/machine.swift.motemplate; sourceTree = SOURCE_ROOT; }; + 0443C9D11AE7F0F1008299E5 /* machine.swift.motemplate */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; name = machine.swift.motemplate; path = Templates/machine.swift.motemplate; sourceTree = SOURCE_ROOT; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 044F88881AE69BD900FAB475 /* Company.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Company.swift; path = Tests/Models/TestModels/Company.swift; sourceTree = ""; }; 044F88891AE69BD900FAB475 /* Employee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Employee.swift; path = Tests/Models/TestModels/Employee.swift; sourceTree = ""; }; 044F888A1AE69BD900FAB475 /* Gender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Gender.swift; path = Tests/Models/TestModels/Gender.swift; sourceTree = ""; }; @@ -167,75 +138,70 @@ 044F88931AE69BD900FAB475 /* TestRelationships.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestRelationships.swift; path = Tests/Models/TestModels/TestRelationships.swift; sourceTree = ""; }; 044F88941AE69BD900FAB475 /* TestTransformable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestTransformable.swift; path = Tests/Models/TestModels/TestTransformable.swift; sourceTree = ""; }; 044F88951AE69BD900FAB475 /* TestTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestTypes.swift; path = Tests/Models/TestModels/TestTypes.swift; sourceTree = ""; }; - 0485AA171AFE9B83008E89D6 /* _TestMigrationV1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestMigrationV1.swift; path = Tests/Models/TestModels/_TestMigrationV1.swift; sourceTree = ""; }; 0485AA181AFE9B83008E89D6 /* TestMigrationV1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestMigrationV1.swift; path = Tests/Models/TestModels/TestMigrationV1.swift; sourceTree = ""; }; 0485AA1E1AFE9BDE008E89D6 /* TestMigrationV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestMigrationV2.swift; path = Tests/Models/TestModels/TestMigrationV2.swift; sourceTree = ""; }; - 0485AA231AFE9C43008E89D6 /* _TestMigrationV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestMigrationV2.swift; path = Tests/Models/TestModels/_TestMigrationV2.swift; sourceTree = ""; }; 04925EBF1AE9967500BF1D88 /* TestDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestDefaults.swift; path = Tests/Models/TestModels/TestDefaults.swift; sourceTree = ""; }; - 04925EC11AE9967B00BF1D88 /* _TestDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestDefaults.swift; path = Tests/Models/TestModels/_TestDefaults.swift; sourceTree = ""; }; 0493E73B1B12330B00CD93E2 /* TestModels */ = {isa = PBXFileReference; lastKnownFileType = folder; name = TestModels; path = Tests/Models/TestModels; sourceTree = SOURCE_ROOT; }; - 04BD1ACD1AE9A6E4008F576C /* _TestDefaultsChild.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestDefaultsChild.swift; path = Tests/Models/TestModels/_TestDefaultsChild.swift; sourceTree = ""; }; 04BD1ACE1AE9A6E4008F576C /* TestDefaultsChild.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestDefaultsChild.swift; path = Tests/Models/TestModels/TestDefaultsChild.swift; sourceTree = ""; }; - 04BD1AED1AEACF75008F576C /* _TestRegEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestRegEnum.swift; path = Tests/Models/TestModels/_TestRegEnum.swift; sourceTree = ""; }; 04BD1AEE1AEACF75008F576C /* TestRegEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestRegEnum.swift; path = Tests/Models/TestModels/TestRegEnum.swift; sourceTree = ""; }; - 04BD1AF11AEACF86008F576C /* _TestRawEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestRawEnum.swift; path = Tests/Models/TestModels/_TestRawEnum.swift; sourceTree = ""; }; 04BD1AF21AEACF86008F576C /* TestRawEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestRawEnum.swift; path = Tests/Models/TestModels/TestRawEnum.swift; sourceTree = ""; }; - 04BD1AF51AEAD2A0008F576C /* _TestAssociatedEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestAssociatedEnum.swift; path = Tests/Models/TestModels/_TestAssociatedEnum.swift; sourceTree = ""; }; 04BD1AF71AEAD2B9008F576C /* TestAssociatedEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestAssociatedEnum.swift; path = Tests/Models/TestModels/TestAssociatedEnum.swift; sourceTree = ""; }; - 04BD1AFD1AEBA549008F576C /* _TestAssociatedOptionalEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestAssociatedOptionalEnum.swift; path = Tests/Models/TestModels/_TestAssociatedOptionalEnum.swift; sourceTree = ""; }; 04BD1AFE1AEBA549008F576C /* TestAssociatedOptionalEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestAssociatedOptionalEnum.swift; path = Tests/Models/TestModels/TestAssociatedOptionalEnum.swift; sourceTree = ""; }; - 04C1B9211AE9219900A85730 /* _Company.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _Company.swift; path = Tests/Models/TestModels/_Company.swift; sourceTree = ""; }; - 04C1B9221AE9219900A85730 /* _Employee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _Employee.swift; path = Tests/Models/TestModels/_Employee.swift; sourceTree = ""; }; - 04C1B9231AE9219900A85730 /* _Gender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _Gender.swift; path = Tests/Models/TestModels/_Gender.swift; sourceTree = ""; }; - 04C1B9241AE9219900A85730 /* _Grandchild.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _Grandchild.swift; path = Tests/Models/TestModels/_Grandchild.swift; sourceTree = ""; }; - 04C1B9251AE9219900A85730 /* _TestChild.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestChild.swift; path = Tests/Models/TestModels/_TestChild.swift; sourceTree = ""; }; - 04C1B9261AE9219900A85730 /* _TestCollections.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestCollections.swift; path = Tests/Models/TestModels/_TestCollections.swift; sourceTree = ""; }; - 04C1B9281AE9219900A85730 /* _TestImmutableOptionalTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestImmutableOptionalTypes.swift; path = Tests/Models/TestModels/_TestImmutableOptionalTypes.swift; sourceTree = ""; }; - 04C1B9291AE9219900A85730 /* _TestImmutableTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestImmutableTypes.swift; path = Tests/Models/TestModels/_TestImmutableTypes.swift; sourceTree = ""; }; - 04C1B92A1AE9219900A85730 /* _TestOptionalTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestOptionalTypes.swift; path = Tests/Models/TestModels/_TestOptionalTypes.swift; sourceTree = ""; }; - 04C1B92B1AE9219900A85730 /* _TestOverrideType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestOverrideType.swift; path = Tests/Models/TestModels/_TestOverrideType.swift; sourceTree = ""; }; - 04C1B92C1AE9219900A85730 /* _TestRelationships.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestRelationships.swift; path = Tests/Models/TestModels/_TestRelationships.swift; sourceTree = ""; }; - 04C1B92D1AE9219900A85730 /* _TestTransformable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestTransformable.swift; path = Tests/Models/TestModels/_TestTransformable.swift; sourceTree = ""; }; - 04C1B92E1AE9219900A85730 /* _TestTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestTypes.swift; path = Tests/Models/TestModels/_TestTypes.swift; sourceTree = ""; }; 04C1B93D1AE93D9800A85730 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - 04C1B93E1AE93DA100A85730 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; sourceTree = ""; }; - 04C3C6D71AFA73E600C95039 /* _TestTransient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestTransient.swift; path = Tests/Models/TestModels/_TestTransient.swift; sourceTree = ""; }; 04C3C6D81AFA73E600C95039 /* TestTransient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestTransient.swift; path = Tests/Models/TestModels/TestTransient.swift; sourceTree = ""; }; - 04C3C6DD1AFA77E300C95039 /* _TestTransient2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestTransient2.swift; path = Tests/Models/TestModels/_TestTransient2.swift; sourceTree = ""; }; 04C3C6DE1AFA77E300C95039 /* TestTransient2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestTransient2.swift; path = Tests/Models/TestModels/TestTransient2.swift; sourceTree = ""; }; - 04C3C6E31AFA7E2400C95039 /* _TestTransient3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestTransient3.swift; path = Tests/Models/TestModels/_TestTransient3.swift; sourceTree = ""; }; 04C3C6E41AFA7E2400C95039 /* TestTransient3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestTransient3.swift; path = Tests/Models/TestModels/TestTransient3.swift; sourceTree = ""; }; 961D13EB1C11AE5A00F0EE1F /* Big_data-bin.plist */ = {isa = PBXFileReference; lastKnownFileType = file.bplist; name = "Big_data-bin.plist"; path = "Tests/Inputs/Big_data-bin.plist"; sourceTree = SOURCE_ROOT; }; 961D13EC1C11AE5A00F0EE1F /* Big_data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = Big_data.json; path = Tests/Inputs/Big_data.json; sourceTree = SOURCE_ROOT; }; 961D13ED1C11AE5A00F0EE1F /* Big_data.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Big_data.plist; path = Tests/Inputs/Big_data.plist; sourceTree = SOURCE_ROOT; }; 961D13EE1C11AE5A00F0EE1F /* Data.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = Data.json; path = Tests/Inputs/Data.json; sourceTree = SOURCE_ROOT; }; 961D13EF1C11AE5A00F0EE1F /* Data.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Data.plist; path = Tests/Inputs/Data.plist; sourceTree = SOURCE_ROOT; }; - 9622DF921C9C8A61009C1E6B /* KVStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KVStore.swift; sourceTree = ""; }; - 9622DF941C9C8A85009C1E6B /* KVStoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = KVStoreTests.swift; path = Tests/Tests/KVStoreTests.swift; sourceTree = ""; }; - 9690A0601C9429A300924F4C /* ProtocolTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProtocolTests.swift; path = Tests/Tests/ProtocolTests.swift; sourceTree = ""; }; - 9690A0621C942C9100924F4C /* _TestProtocolConformer2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestProtocolConformer2.swift; path = Tests/Models/TestModels/_TestProtocolConformer2.swift; sourceTree = ""; }; + 9622DF921C9C8A61009C1E6B /* Store.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = ""; }; + 96712B651D2DA0B100C7E1C5 /* _Company.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _Company.swift; path = Tests/Models/TestModels/_Company.swift; sourceTree = ""; }; + 96712B661D2DA0B100C7E1C5 /* _Employee.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _Employee.swift; path = Tests/Models/TestModels/_Employee.swift; sourceTree = ""; }; + 96712B671D2DA0B100C7E1C5 /* _Gender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _Gender.swift; path = Tests/Models/TestModels/_Gender.swift; sourceTree = ""; }; + 96712B681D2DA0B100C7E1C5 /* _Grandchild.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _Grandchild.swift; path = Tests/Models/TestModels/_Grandchild.swift; sourceTree = ""; }; + 96712B691D2DA0B100C7E1C5 /* _TestAssociatedEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestAssociatedEnum.swift; path = Tests/Models/TestModels/_TestAssociatedEnum.swift; sourceTree = ""; }; + 96712B6A1D2DA0B100C7E1C5 /* _TestAssociatedOptionalEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestAssociatedOptionalEnum.swift; path = Tests/Models/TestModels/_TestAssociatedOptionalEnum.swift; sourceTree = ""; }; + 96712B6B1D2DA0B100C7E1C5 /* _TestChild.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestChild.swift; path = Tests/Models/TestModels/_TestChild.swift; sourceTree = ""; }; + 96712B6C1D2DA0B100C7E1C5 /* _TestCollections.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestCollections.swift; path = Tests/Models/TestModels/_TestCollections.swift; sourceTree = ""; }; + 96712B6D1D2DA0B100C7E1C5 /* _TestDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestDefaults.swift; path = Tests/Models/TestModels/_TestDefaults.swift; sourceTree = ""; }; + 96712B6E1D2DA0B100C7E1C5 /* _TestDefaultsChild.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestDefaultsChild.swift; path = Tests/Models/TestModels/_TestDefaultsChild.swift; sourceTree = ""; }; + 96712B6F1D2DA0B100C7E1C5 /* _TestDictionaryComposition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestDictionaryComposition.swift; path = Tests/Models/TestModels/_TestDictionaryComposition.swift; sourceTree = ""; }; + 96712B701D2DA0B100C7E1C5 /* _TestImmutableOptionalTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestImmutableOptionalTypes.swift; path = Tests/Models/TestModels/_TestImmutableOptionalTypes.swift; sourceTree = ""; }; + 96712B711D2DA0B100C7E1C5 /* _TestImmutableTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestImmutableTypes.swift; path = Tests/Models/TestModels/_TestImmutableTypes.swift; sourceTree = ""; }; + 96712B721D2DA0B100C7E1C5 /* _TestMigrationV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestMigrationV2.swift; path = Tests/Models/TestModels/_TestMigrationV2.swift; sourceTree = ""; }; + 96712B731D2DA0B100C7E1C5 /* _TestOptionalTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestOptionalTypes.swift; path = Tests/Models/TestModels/_TestOptionalTypes.swift; sourceTree = ""; }; + 96712B741D2DA0B100C7E1C5 /* _TestOverrideType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestOverrideType.swift; path = Tests/Models/TestModels/_TestOverrideType.swift; sourceTree = ""; }; + 96712B751D2DA0B100C7E1C5 /* _TestParentProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestParentProtocol.swift; path = Tests/Models/TestModels/_TestParentProtocol.swift; sourceTree = ""; }; + 96712B761D2DA0B100C7E1C5 /* _TestProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestProtocol.swift; path = Tests/Models/TestModels/_TestProtocol.swift; sourceTree = ""; }; + 96712B771D2DA0B100C7E1C5 /* _TestProtocolConformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestProtocolConformer.swift; path = Tests/Models/TestModels/_TestProtocolConformer.swift; sourceTree = ""; }; + 96712B781D2DA0B100C7E1C5 /* _TestProtocolConformer2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestProtocolConformer2.swift; path = Tests/Models/TestModels/_TestProtocolConformer2.swift; sourceTree = ""; }; + 96712B791D2DA0B100C7E1C5 /* _TestProtocolContainter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestProtocolContainter.swift; path = Tests/Models/TestModels/_TestProtocolContainter.swift; sourceTree = ""; }; + 96712B7A1D2DA0B100C7E1C5 /* _TestRawEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestRawEnum.swift; path = Tests/Models/TestModels/_TestRawEnum.swift; sourceTree = ""; }; + 96712B7B1D2DA0B100C7E1C5 /* _TestRegEnum.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestRegEnum.swift; path = Tests/Models/TestModels/_TestRegEnum.swift; sourceTree = ""; }; + 96712B7C1D2DA0B100C7E1C5 /* _TestRelationships.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestRelationships.swift; path = Tests/Models/TestModels/_TestRelationships.swift; sourceTree = ""; }; + 96712B7D1D2DA0B100C7E1C5 /* _TestTransformable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestTransformable.swift; path = Tests/Models/TestModels/_TestTransformable.swift; sourceTree = ""; }; + 96712B7E1D2DA0B100C7E1C5 /* _TestTransient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestTransient.swift; path = Tests/Models/TestModels/_TestTransient.swift; sourceTree = ""; }; + 96712B7F1D2DA0B100C7E1C5 /* _TestTransient2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestTransient2.swift; path = Tests/Models/TestModels/_TestTransient2.swift; sourceTree = ""; }; + 96712B801D2DA0B100C7E1C5 /* _TestTransient3.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestTransient3.swift; path = Tests/Models/TestModels/_TestTransient3.swift; sourceTree = ""; }; + 96712B811D2DA0B100C7E1C5 /* _TestTypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestTypes.swift; path = Tests/Models/TestModels/_TestTypes.swift; sourceTree = ""; }; 9690A0631C942C9100924F4C /* TestProtocolConformer2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestProtocolConformer2.swift; path = Tests/Models/TestModels/TestProtocolConformer2.swift; sourceTree = ""; }; - 96960A4C1C90F00B00D4E6D0 /* Migration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Migration.swift; sourceTree = ""; }; + 96930D981D3BCFD5001F9565 /* Format.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Format.swift; sourceTree = ""; }; 96960A4D1C90F00B00D4E6D0 /* Model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; 96960A651C90F07700D4E6D0 /* State.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = State.h; sourceTree = ""; }; 96960A661C90F07700D4E6D0 /* StateInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = StateInfo.plist; sourceTree = ""; }; 96960A671C90F07700D4E6D0 /* StateTestsInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = StateTestsInfo.plist; sourceTree = ""; }; - 96A5435D1B63C6C8009A2B2D /* _TestDictionaryComposition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestDictionaryComposition.swift; path = Tests/Models/TestModels/_TestDictionaryComposition.swift; sourceTree = ""; }; + 969C00F61D40083B0039CBEB /* BaseTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BaseTest.swift; path = Tests/BaseTest.swift; sourceTree = ""; }; + 969C00F71D40083B0039CBEB /* FormatTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FormatTests.swift; path = Tests/FormatTests.swift; sourceTree = ""; }; + 969C00F81D40083B0039CBEB /* ModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModelTests.swift; path = Tests/ModelTests.swift; sourceTree = ""; }; + 969C00F91D40083B0039CBEB /* PerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PerformanceTests.swift; path = Tests/PerformanceTests.swift; sourceTree = ""; }; + 969C00FA1D40083B0039CBEB /* StoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = StoreTests.swift; path = Tests/StoreTests.swift; sourceTree = ""; }; 96A5435E1B63C6C8009A2B2D /* TestDictionaryComposition.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestDictionaryComposition.swift; path = Tests/Models/TestModels/TestDictionaryComposition.swift; sourceTree = ""; }; - 96A85FD41B4AD38E006A5ABE /* _TestParentProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestParentProtocol.swift; path = Tests/Models/TestModels/_TestParentProtocol.swift; sourceTree = ""; }; - 96A85FD51B4AD38E006A5ABE /* _TestProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestProtocol.swift; path = Tests/Models/TestModels/_TestProtocol.swift; sourceTree = ""; }; - 96A85FE31B4ADCF8006A5ABE /* _TestProtocolConformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestProtocolConformer.swift; path = Tests/Models/TestModels/_TestProtocolConformer.swift; sourceTree = ""; }; 96A860291B4B2D5E006A5ABE /* TestParentProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestParentProtocol.swift; path = Tests/Models/TestModels/TestParentProtocol.swift; sourceTree = ""; }; - 96A8602C1B4B3040006A5ABE /* _TestProtocolContainter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = _TestProtocolContainter.swift; path = Tests/Models/TestModels/_TestProtocolContainter.swift; sourceTree = ""; }; 96A8602F1B4B304A006A5ABE /* TestProtocolContainter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestProtocolContainter.swift; path = Tests/Models/TestModels/TestProtocolContainter.swift; sourceTree = ""; }; 96A860321B4B35A8006A5ABE /* TestProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestProtocol.swift; path = Tests/Models/TestModels/TestProtocol.swift; sourceTree = ""; }; - 96B8A8F81C9AD3CC0086619F /* Coding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Coding.swift; path = Sources/Coding.swift; sourceTree = SOURCE_ROOT; }; - 96B8A90C1C9B6CA60086619F /* NSURL+Coding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSURL+Coding.swift"; sourceTree = ""; }; - 96B8A90D1C9B6CA60086619F /* UIColor+Coding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Coding.swift"; sourceTree = ""; }; - 96B8A9101C9B6FD10086619F /* Conversion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Conversion.swift; sourceTree = ""; }; 96C86BFB1BC2E7F500D6F0F3 /* TestProtocolConformer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestProtocolConformer.swift; path = Tests/Models/TestModels/TestProtocolConformer.swift; sourceTree = ""; }; - 96CE6B7B1B3BFDEC00D632BF /* Docs */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Docs; sourceTree = ""; }; - 96FDF3351CAAABCB0099074C /* NSUserDefaults+Coding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSUserDefaults+Coding.swift"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -260,7 +226,6 @@ isa = PBXGroup; children = ( 04C1B93D1AE93D9800A85730 /* README.md */, - 96CE6B7B1B3BFDEC00D632BF /* Docs */, 96960A431C90F00B00D4E6D0 /* Sources */, 04012A841AE12FA6006DAC19 /* Tests */, 04012AAF1AE130B7006DAC19 /* Templates */, @@ -281,22 +246,12 @@ 04012A841AE12FA6006DAC19 /* Tests */ = { isa = PBXGroup; children = ( - 9622DF941C9C8A85009C1E6B /* KVStoreTests.swift */, + 969C00F61D40083B0039CBEB /* BaseTest.swift */, + 969C00F71D40083B0039CBEB /* FormatTests.swift */, + 969C00FA1D40083B0039CBEB /* StoreTests.swift */, + 969C00F81D40083B0039CBEB /* ModelTests.swift */, + 969C00F91D40083B0039CBEB /* PerformanceTests.swift */, 04012AB91AE13274006DAC19 /* Inputs */, - 041817781B124AB4002CA532 /* BaseTest.swift */, - 041817791B124AB4002CA532 /* ConverterTests.swift */, - 0418177A1B124AB4002CA532 /* DecodableTests.swift */, - 0418177B1B124AB4002CA532 /* DecodingTests.swift */, - 0418177C1B124AB4002CA532 /* DefaultTests.swift */, - 0418177D1B124AB4002CA532 /* EncodableTests.swift */, - 0418177E1B124AB4002CA532 /* EncodingTests.swift */, - 0418177F1B124AB4002CA532 /* EnumTests.swift */, - 041817801B124AB4002CA532 /* MigrationTests.swift */, - 041817811B124AB4002CA532 /* PerfTests.swift */, - 041817821B124AB4002CA532 /* RecursiveTests.swift */, - 041817831B124AB4002CA532 /* RelationshipTests.swift */, - 041817841B124AB4002CA532 /* TemplateTests.swift */, - 9690A0601C9429A300924F4C /* ProtocolTests.swift */, 04012AC41AE13290006DAC19 /* Models */, 04012A851AE12FA6006DAC19 /* Supporting Files */, ); @@ -337,41 +292,46 @@ 04012AC41AE13290006DAC19 /* Models */ = { isa = PBXGroup; children = ( + 96712B651D2DA0B100C7E1C5 /* _Company.swift */, + 96712B661D2DA0B100C7E1C5 /* _Employee.swift */, + 96712B671D2DA0B100C7E1C5 /* _Gender.swift */, + 96712B681D2DA0B100C7E1C5 /* _Grandchild.swift */, + 96712B691D2DA0B100C7E1C5 /* _TestAssociatedEnum.swift */, + 96712B6A1D2DA0B100C7E1C5 /* _TestAssociatedOptionalEnum.swift */, + 96712B6B1D2DA0B100C7E1C5 /* _TestChild.swift */, + 96712B6C1D2DA0B100C7E1C5 /* _TestCollections.swift */, + 96712B6D1D2DA0B100C7E1C5 /* _TestDefaults.swift */, + 96712B6E1D2DA0B100C7E1C5 /* _TestDefaultsChild.swift */, + 96712B6F1D2DA0B100C7E1C5 /* _TestDictionaryComposition.swift */, + 96712B701D2DA0B100C7E1C5 /* _TestImmutableOptionalTypes.swift */, + 96712B711D2DA0B100C7E1C5 /* _TestImmutableTypes.swift */, + 96712B721D2DA0B100C7E1C5 /* _TestMigrationV2.swift */, + 96712B731D2DA0B100C7E1C5 /* _TestOptionalTypes.swift */, + 96712B741D2DA0B100C7E1C5 /* _TestOverrideType.swift */, + 96712B751D2DA0B100C7E1C5 /* _TestParentProtocol.swift */, + 96712B761D2DA0B100C7E1C5 /* _TestProtocol.swift */, + 96712B771D2DA0B100C7E1C5 /* _TestProtocolConformer.swift */, + 96712B781D2DA0B100C7E1C5 /* _TestProtocolConformer2.swift */, + 96712B791D2DA0B100C7E1C5 /* _TestProtocolContainter.swift */, + 96712B7A1D2DA0B100C7E1C5 /* _TestRawEnum.swift */, + 96712B7B1D2DA0B100C7E1C5 /* _TestRegEnum.swift */, + 96712B7C1D2DA0B100C7E1C5 /* _TestRelationships.swift */, + 96712B7D1D2DA0B100C7E1C5 /* _TestTransformable.swift */, + 96712B7E1D2DA0B100C7E1C5 /* _TestTransient.swift */, + 96712B7F1D2DA0B100C7E1C5 /* _TestTransient2.swift */, + 96712B801D2DA0B100C7E1C5 /* _TestTransient3.swift */, + 96712B811D2DA0B100C7E1C5 /* _TestTypes.swift */, 0485AA1E1AFE9BDE008E89D6 /* TestMigrationV2.swift */, - 0485AA231AFE9C43008E89D6 /* _TestMigrationV2.swift */, - 0485AA171AFE9B83008E89D6 /* _TestMigrationV1.swift */, 0485AA181AFE9B83008E89D6 /* TestMigrationV1.swift */, - 04C3C6E31AFA7E2400C95039 /* _TestTransient3.swift */, 04C3C6E41AFA7E2400C95039 /* TestTransient3.swift */, - 04C3C6DD1AFA77E300C95039 /* _TestTransient2.swift */, 04C3C6DE1AFA77E300C95039 /* TestTransient2.swift */, - 04C3C6D71AFA73E600C95039 /* _TestTransient.swift */, 04C3C6D81AFA73E600C95039 /* TestTransient.swift */, - 04BD1AFD1AEBA549008F576C /* _TestAssociatedOptionalEnum.swift */, 04BD1AFE1AEBA549008F576C /* TestAssociatedOptionalEnum.swift */, 04BD1AF71AEAD2B9008F576C /* TestAssociatedEnum.swift */, - 04BD1AF51AEAD2A0008F576C /* _TestAssociatedEnum.swift */, - 04BD1AF11AEACF86008F576C /* _TestRawEnum.swift */, 04BD1AF21AEACF86008F576C /* TestRawEnum.swift */, - 04BD1AED1AEACF75008F576C /* _TestRegEnum.swift */, 04BD1AEE1AEACF75008F576C /* TestRegEnum.swift */, - 04BD1ACD1AE9A6E4008F576C /* _TestDefaultsChild.swift */, 04BD1ACE1AE9A6E4008F576C /* TestDefaultsChild.swift */, 04925EBF1AE9967500BF1D88 /* TestDefaults.swift */, - 04925EC11AE9967B00BF1D88 /* _TestDefaults.swift */, - 04C1B9211AE9219900A85730 /* _Company.swift */, - 04C1B9221AE9219900A85730 /* _Employee.swift */, - 04C1B9231AE9219900A85730 /* _Gender.swift */, - 04C1B9241AE9219900A85730 /* _Grandchild.swift */, - 04C1B9251AE9219900A85730 /* _TestChild.swift */, - 04C1B9261AE9219900A85730 /* _TestCollections.swift */, - 04C1B9281AE9219900A85730 /* _TestImmutableOptionalTypes.swift */, - 04C1B9291AE9219900A85730 /* _TestImmutableTypes.swift */, - 04C1B92A1AE9219900A85730 /* _TestOptionalTypes.swift */, - 04C1B92B1AE9219900A85730 /* _TestOverrideType.swift */, - 04C1B92C1AE9219900A85730 /* _TestRelationships.swift */, - 04C1B92D1AE9219900A85730 /* _TestTransformable.swift */, - 04C1B92E1AE9219900A85730 /* _TestTypes.swift */, 044F88881AE69BD900FAB475 /* Company.swift */, 044F88891AE69BD900FAB475 /* Employee.swift */, 044F888A1AE69BD900FAB475 /* Gender.swift */, @@ -385,16 +345,10 @@ 044F88931AE69BD900FAB475 /* TestRelationships.swift */, 044F88941AE69BD900FAB475 /* TestTransformable.swift */, 044F88951AE69BD900FAB475 /* TestTypes.swift */, - 96A85FD41B4AD38E006A5ABE /* _TestParentProtocol.swift */, - 96A85FD51B4AD38E006A5ABE /* _TestProtocol.swift */, 96C86BFB1BC2E7F500D6F0F3 /* TestProtocolConformer.swift */, - 96A85FE31B4ADCF8006A5ABE /* _TestProtocolConformer.swift */, - 9690A0621C942C9100924F4C /* _TestProtocolConformer2.swift */, 9690A0631C942C9100924F4C /* TestProtocolConformer2.swift */, 96A860291B4B2D5E006A5ABE /* TestParentProtocol.swift */, - 96A8602C1B4B3040006A5ABE /* _TestProtocolContainter.swift */, 96A8602F1B4B304A006A5ABE /* TestProtocolContainter.swift */, - 96A5435D1B63C6C8009A2B2D /* _TestDictionaryComposition.swift */, 96A5435E1B63C6C8009A2B2D /* TestDictionaryComposition.swift */, 041817611B1239C4002CA532 /* TestModels.xcdatamodeld */, 96A860321B4B35A8006A5ABE /* TestProtocol.swift */, @@ -409,14 +363,9 @@ 96960A431C90F00B00D4E6D0 /* Sources */ = { isa = PBXGroup; children = ( - 96FDF3351CAAABCB0099074C /* NSUserDefaults+Coding.swift */, - 9622DF921C9C8A61009C1E6B /* KVStore.swift */, - 96B8A8F81C9AD3CC0086619F /* Coding.swift */, - 96B8A9101C9B6FD10086619F /* Conversion.swift */, - 96960A4C1C90F00B00D4E6D0 /* Migration.swift */, + 96930D981D3BCFD5001F9565 /* Format.swift */, + 9622DF921C9C8A61009C1E6B /* Store.swift */, 96960A4D1C90F00B00D4E6D0 /* Model.swift */, - 96B8A90C1C9B6CA60086619F /* NSURL+Coding.swift */, - 96B8A90D1C9B6CA60086619F /* UIColor+Coding.swift */, ); path = Sources; sourceTree = ""; @@ -424,7 +373,6 @@ 96960A641C90F07700D4E6D0 /* Support */ = { isa = PBXGroup; children = ( - 04C1B93E1AE93DA100A85730 /* LICENSE */, 96960A651C90F07700D4E6D0 /* State.h */, 96960A661C90F07700D4E6D0 /* StateInfo.plist */, 96960A671C90F07700D4E6D0 /* StateTestsInfo.plist */, @@ -508,14 +456,20 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0700; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = "Amber Star"; TargetAttributes = { 04012A741AE12FA6006DAC19 = { CreatedOnToolsVersion = 6.3; + DevelopmentTeam = FG43PMZ33H; + DevelopmentTeamName = "Amber Star (Personal Team)"; + LastSwiftMigration = 0800; }; 04012A7F1AE12FA6006DAC19 = { CreatedOnToolsVersion = 6.3; + DevelopmentTeam = FG43PMZ33H; + DevelopmentTeamName = "Amber Star (Personal Team)"; + LastSwiftMigration = 0800; }; 04012AE31AE13A90006DAC19 = { CreatedOnToolsVersion = 6.3; @@ -568,13 +522,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 9622DFA21C9EE63A009C1E6B /* UIColor+Coding.swift in Sources */, - 96B8A8F91C9AD3CC0086619F /* Coding.swift in Sources */, - 96B8A9491C9BEB870086619F /* Conversion.swift in Sources */, - 96960A5C1C90F00B00D4E6D0 /* Migration.swift in Sources */, - 9622DFA11C9EE637009C1E6B /* KVStore.swift in Sources */, - 96FDF3361CAAABCB0099074C /* NSUserDefaults+Coding.swift in Sources */, - 9622DF981C9C8EC5009C1E6B /* NSURL+Coding.swift in Sources */, + 96239BD01D1DA94700C27329 /* Store.swift in Sources */, + 96930D991D3BCFD5001F9565 /* Format.swift in Sources */, 96960A5D1C90F00B00D4E6D0 /* Model.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -584,83 +533,72 @@ buildActionMask = 2147483647; files = ( 96B8A8FE1C9ADFDB0086619F /* TestProtocolContainter.swift in Sources */, - 041817871B124AB4002CA532 /* BaseTest.swift in Sources */, + 96712B9D1D2DA0B100C7E1C5 /* _TestTransient3.swift in Sources */, + 96712B9C1D2DA0B100C7E1C5 /* _TestTransient2.swift in Sources */, + 96712B901D2DA0B100C7E1C5 /* _TestOptionalTypes.swift in Sources */, + 96712B871D2DA0B100C7E1C5 /* _TestAssociatedOptionalEnum.swift in Sources */, 044F88971AE69BD900FAB475 /* Employee.swift in Sources */, - 04B46BE41B2EF89400ED20BF /* RelationshipTests.swift in Sources */, + 969C00FC1D40083B0039CBEB /* FormatTests.swift in Sources */, + 96712B941D2DA0B100C7E1C5 /* _TestProtocolConformer.swift in Sources */, + 96712B891D2DA0B100C7E1C5 /* _TestCollections.swift in Sources */, + 96712B861D2DA0B100C7E1C5 /* _TestAssociatedEnum.swift in Sources */, 04C3C6E21AFA77E300C95039 /* TestTransient2.swift in Sources */, 04925EC01AE9967500BF1D88 /* TestDefaults.swift in Sources */, - 041817891B124AB4002CA532 /* ConverterTests.swift in Sources */, - 0418178F1B124AB4002CA532 /* DefaultTests.swift in Sources */, - 04BD1AFF1AEBA549008F576C /* _TestAssociatedOptionalEnum.swift in Sources */, - 04C1B93C1AE9219900A85730 /* _TestTypes.swift in Sources */, - 96A5435F1B63C6C8009A2B2D /* _TestDictionaryComposition.swift in Sources */, - 0418178B1B124AB4002CA532 /* DecodableTests.swift in Sources */, - 04BD1AF61AEAD2A0008F576C /* _TestAssociatedEnum.swift in Sources */, + 96712B8C1D2DA0B100C7E1C5 /* _TestDictionaryComposition.swift in Sources */, 96C86BFD1BC2E81800D6F0F3 /* TestProtocolConformer.swift in Sources */, - 0418179B1B124AB4002CA532 /* RecursiveTests.swift in Sources */, + 96712B971D2DA0B100C7E1C5 /* _TestRawEnum.swift in Sources */, 04C3C6DC1AFA73E600C95039 /* TestTransient.swift in Sources */, - 04C1B9361AE9219900A85730 /* _TestImmutableOptionalTypes.swift in Sources */, 044F889B1AE69BD900FAB475 /* TestCollections.swift in Sources */, - 04C1B9301AE9219900A85730 /* _Employee.swift in Sources */, 044F88A31AE69BD900FAB475 /* TestTypes.swift in Sources */, - 96FDF3371CAAC5420099074C /* KVStoreTests.swift in Sources */, + 96712B9B1D2DA0B100C7E1C5 /* _TestTransient.swift in Sources */, 96B8A9091C9AFA390086619F /* (null) in Sources */, + 96712B911D2DA0B100C7E1C5 /* _TestOverrideType.swift in Sources */, + 96712B821D2DA0B100C7E1C5 /* _Company.swift in Sources */, 96A543611B63C6C8009A2B2D /* TestDictionaryComposition.swift in Sources */, 044F88A11AE69BD900FAB475 /* TestRelationships.swift in Sources */, + 96712B841D2DA0B100C7E1C5 /* _Gender.swift in Sources */, 044F88981AE69BD900FAB475 /* Gender.swift in Sources */, + 969C00FE1D40083B0039CBEB /* PerformanceTests.swift in Sources */, 0485AA221AFE9BDE008E89D6 /* TestMigrationV2.swift in Sources */, - 0485AA251AFE9C43008E89D6 /* _TestMigrationV2.swift in Sources */, - 9690A0641C942C9100924F4C /* _TestProtocolConformer2.swift in Sources */, 044F88121AE5D02900FAB475 /* ObjectModels.swift in Sources */, - 04925EC21AE9967B00BF1D88 /* _TestDefaults.swift in Sources */, - 04C3C6DA1AFA73E600C95039 /* _TestTransient.swift in Sources */, - 041817951B124AB4002CA532 /* EnumTests.swift in Sources */, + 969C00FD1D40083B0039CBEB /* ModelTests.swift in Sources */, 044F88961AE69BD900FAB475 /* Company.swift in Sources */, 04B46BE21B2EF44F00ED20BF /* BasicModels.swift in Sources */, - 04C1B93A1AE9219900A85730 /* _TestRelationships.swift in Sources */, - 960072DF1BA8591700AFD3C5 /* _TestParentProtocol.swift in Sources */, + 96712B831D2DA0B100C7E1C5 /* _Employee.swift in Sources */, + 969C00FF1D40083B0039CBEB /* StoreTests.swift in Sources */, 04BD1AF01AEACF75008F576C /* TestRegEnum.swift in Sources */, - 04C1B9311AE9219900A85730 /* _Gender.swift in Sources */, 04BD1AF41AEACF86008F576C /* TestRawEnum.swift in Sources */, 044F889A1AE69BD900FAB475 /* TestChild.swift in Sources */, - 04C1B93B1AE9219900A85730 /* _TestTransformable.swift in Sources */, - 0485AA1A1AFE9B83008E89D6 /* _TestMigrationV1.swift in Sources */, - 04B46BE71B2EFAE800ED20BF /* DecodingTests.swift in Sources */, - 04BD1AF31AEACF86008F576C /* _TestRawEnum.swift in Sources */, + 96712B881D2DA0B100C7E1C5 /* _TestChild.swift in Sources */, 960072DC1BA8590E00AFD3C5 /* TestParentProtocol.swift in Sources */, 044F88A21AE69BD900FAB475 /* TestTransformable.swift in Sources */, - 04C1B9371AE9219900A85730 /* _TestImmutableTypes.swift in Sources */, - 04C1B92F1AE9219900A85730 /* _Company.swift in Sources */, - 04B46BE51B2EFAE000ED20BF /* EncodingTests.swift in Sources */, - 04C1B9381AE9219900A85730 /* _TestOptionalTypes.swift in Sources */, - 04C3C6E01AFA77E300C95039 /* _TestTransient2.swift in Sources */, - 96B8A8FD1C9ADFDB0086619F /* _TestProtocolContainter.swift in Sources */, - 0485AA1C1AFE9B83008E89D6 /* TestMigrationV1.swift in Sources */, - 041817911B124AB4002CA532 /* EncodableTests.swift in Sources */, + 96712B961D2DA0B100C7E1C5 /* _TestProtocolContainter.swift in Sources */, + 96712B951D2DA0B100C7E1C5 /* _TestProtocolConformer2.swift in Sources */, + 96712B8D1D2DA0B100C7E1C5 /* _TestImmutableOptionalTypes.swift in Sources */, + 96712B8F1D2DA0B100C7E1C5 /* _TestMigrationV2.swift in Sources */, + 96712B931D2DA0B100C7E1C5 /* _TestProtocol.swift in Sources */, 04BD1AD01AE9A6E4008F576C /* TestDefaultsChild.swift in Sources */, + 96712B9A1D2DA0B100C7E1C5 /* _TestTransformable.swift in Sources */, 9690A0651C942C9100924F4C /* TestProtocolConformer2.swift in Sources */, - 04C3C6E61AFA7E2400C95039 /* _TestTransient3.swift in Sources */, - 96B8A8FC1C9ADFCF0086619F /* ProtocolTests.swift in Sources */, - 96C5C3891B3C6988009121A1 /* MigrationTests.swift in Sources */, + 96712B851D2DA0B100C7E1C5 /* _Grandchild.swift in Sources */, + 96712B921D2DA0B100C7E1C5 /* _TestParentProtocol.swift in Sources */, + 96712B9E1D2DA0B100C7E1C5 /* _TestTypes.swift in Sources */, 044F88131AE5D02900FAB475 /* RecursiveModel.swift in Sources */, + 96712B8A1D2DA0B100C7E1C5 /* _TestDefaults.swift in Sources */, 044F889F1AE69BD900FAB475 /* TestOptionalTypes.swift in Sources */, + 96712B8B1D2DA0B100C7E1C5 /* _TestDefaultsChild.swift in Sources */, 044F88A01AE69BD900FAB475 /* TestOverrideType.swift in Sources */, + 96712B991D2DA0B100C7E1C5 /* _TestRelationships.swift in Sources */, 044F889E1AE69BD900FAB475 /* TestImmutableTypes.swift in Sources */, - 04C1B9391AE9219900A85730 /* _TestOverrideType.swift in Sources */, + 96712B8E1D2DA0B100C7E1C5 /* _TestImmutableTypes.swift in Sources */, 960072E31BA8594300AFD3C5 /* TestProtocol.swift in Sources */, - 960072E61BA8595000AFD3C5 /* _TestProtocolConformer.swift in Sources */, + 96712B981D2DA0B100C7E1C5 /* _TestRegEnum.swift in Sources */, 04BD1B001AEBA549008F576C /* TestAssociatedOptionalEnum.swift in Sources */, 044F88991AE69BD900FAB475 /* Grandchild.swift in Sources */, + 969C00FB1D40083B0039CBEB /* BaseTest.swift in Sources */, 04BD1AF81AEAD2B9008F576C /* TestAssociatedEnum.swift in Sources */, 044F889D1AE69BD900FAB475 /* TestImmutableOptionalTypes.swift in Sources */, - 04C1B9321AE9219900A85730 /* _Grandchild.swift in Sources */, - 04C1B9331AE9219900A85730 /* _TestChild.swift in Sources */, - 04C1B9341AE9219900A85730 /* _TestCollections.swift in Sources */, - 04BD1ACF1AE9A6E4008F576C /* _TestDefaultsChild.swift in Sources */, - 0418179F1B124AB4002CA532 /* TemplateTests.swift in Sources */, 04C3C6E81AFA7E2400C95039 /* TestTransient3.swift in Sources */, - 04BD1AEF1AEACF75008F576C /* _TestRegEnum.swift in Sources */, - 960072E11BA8593800AFD3C5 /* _TestProtocol.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -784,6 +722,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.amberstar.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(PROJECT_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -801,6 +740,8 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.amberstar.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(PROJECT_NAME)"; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -818,6 +759,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.amberstar.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(PROJECT_NAME)Tests"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -830,6 +772,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.amberstar.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(PROJECT_NAME)Tests"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/State.xcodeproj/project.xcworkspace/xcshareddata/State.xcscmblueprint b/State.xcodeproj/project.xcworkspace/xcshareddata/State.xcscmblueprint new file mode 100644 index 0000000..4f4ebdc --- /dev/null +++ b/State.xcodeproj/project.xcworkspace/xcshareddata/State.xcscmblueprint @@ -0,0 +1,30 @@ +{ + "DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "FB04C9513992D7FF4BC3F299B83FA8CCB6EBBFDA", + "DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { + + }, + "DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { + "C3529E4D2E88136AC210054090DB230D3D838E87" : 0, + "FB04C9513992D7FF4BC3F299B83FA8CCB6EBBFDA" : 0 + }, + "DVTSourceControlWorkspaceBlueprintIdentifierKey" : "7B9BBE27-0D84-4055-83DC-0993B84F2974", + "DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { + "C3529E4D2E88136AC210054090DB230D3D838E87" : "Library\/", + "FB04C9513992D7FF4BC3F299B83FA8CCB6EBBFDA" : "State" + }, + "DVTSourceControlWorkspaceBlueprintNameKey" : "State", + "DVTSourceControlWorkspaceBlueprintVersion" : 204, + "DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "State.xcodeproj", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/SimpleTouch\/Library.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "C3529E4D2E88136AC210054090DB230D3D838E87" + }, + { + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/amberstar\/Spot.git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", + "DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "FB04C9513992D7FF4BC3F299B83FA8CCB6EBBFDA" + } + ] +} \ No newline at end of file diff --git a/State.xcodeproj/xcshareddata/xcschemes/State-iOS.xcscheme b/State.xcodeproj/xcshareddata/xcschemes/State-iOS.xcscheme index 1b01e43..3447c41 100644 --- a/State.xcodeproj/xcshareddata/xcschemes/State-iOS.xcscheme +++ b/State.xcodeproj/xcshareddata/xcschemes/State-iOS.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> diff --git a/Templates/machine.swift.motemplate b/Templates/machine.swift.motemplate index becf4de..a1b1761 100644 --- a/Templates/machine.swift.motemplate +++ b/Templates/machine.swift.motemplate @@ -14,7 +14,6 @@ import State <$if hasSuperentity$><$call setSuperentityType superentity$><$endif$> - <$set transientAttributeCount = 0$><$foreach Attribute noninheritedAttributes do$><$if Attribute.isTransient$><$set transientAttributeCount = transientAttributeCount + 1$><$endif$><$endforeach do$> <$set functionRequirementCount = 0$><$foreach Attribute attributesByName do$><$if Attribute.userInfo.State.ProtocolRequirementType == func$><$set functionRequirementCount = functionRequirementCount + 1$><$endif$><$endforeach do$> @@ -37,237 +36,6 @@ import State <$procedure getPropertyDeclarationForRelationship Relationship$><$if Relationship.userInfo.State.Immutable == YES$>public let<$else$>public var<$endif$> <$Relationship.name$><$if !Relationship.isOptional && Relationship.userInfo.State.Value$> <$call getDefaultExpressionForRelationship Relationship$><$else$>: <$if Relationship.isToMany$>[<$if Relationship.userInfo.State.CompositionType == Dictionary$>String : <$endif$><$endif$><$Relationship.destinationEntity.managedObjectClassName$><$if Relationship.isToMany$>]<$endif$><$if Relationship.isOptional$>?<$endif$><$endif$><$endProcedure$> -<$procedure writeVersionHashExtension$> -extension <$typeName$> { - - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<$versionHash$>" - } - - public static func modelVersionHashModifier() -> String? { - return <$if versionHashModifier$>"<$versionHashModifier$>"<$else$>nil<$endif$> - } -}<$endprocedure$> - - -<$procedure writeNSUserDefaultsSupportBlock$> -//****************************************************************************// -// MARK: NSUserDefaults support -//****************************************************************************// -extension NSUserDefaults { - - public func get<$typeName$>(key: String) -> <$typeName$>? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return <$typeName$>.decode(dictionary) - } - - public func get<$typeName$>(key: String) -> [<$typeName$>]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(<$typeName$>.decode)) - } - - public func get<$typeName$>(key: String) -> [String : <$typeName$>]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { <$typeName$>.decode($0) }) - } - - public func get<$typeName$>(key: String, defaultValue: <$typeName$>) -> <$typeName$> { - return get<$typeName$>(key) ?? defaultValue - } - - public func get<$typeName$>(key: String, defaultValue: [<$typeName$>]) -> [<$typeName$>] { - return getDecodable(key) ?? defaultValue - } - - public func get<$typeName$>(key: String, defaultValue: [String : <$typeName$>] - ) -> [String : <$typeName$>] { - return get<$typeName$>(key) ?? defaultValue - } - - public func set<$typeName$>(value: <$typeName$>, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func set<$typeName$>(value: [<$typeName$>], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func set<$typeName$>(value: [String : <$typeName$>], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} -<$endprocedure$> - -<$procedure writeKVStoreSupportBlock$> - -//****************************************************************************// -// MARK: KVStore support -//****************************************************************************// -extension KVStore { - - public func get<$typeName$>(key: String) -> <$typeName$>? { - return getValue(key) - } - - public func get<$typeName$>(key: String, defaultValue: <$typeName$>) -> <$typeName$> { - return get<$typeName$>(key) ?? defaultValue - } - - public func get<$typeName$>s(key: String) -> [<$typeName$>]? { - return getValue(key) - } - - public func get<$typeName$>s(key: String, defaultValue: [<$typeName$>]) -> [<$typeName$>] { - return get<$typeName$>s(key) ?? defaultValue - } - - public func get<$typeName$>Dictionary(key: String) -> [String : <$typeName$>]? { - return getValue(key) - } - - public func get<$typeName$>Dictionary(key: String, defaultValue: [String : <$typeName$>]) -> [String : <$typeName$>] { - return get<$typeName$>Dictionary(key) ?? defaultValue - } -} -<$endprocedure$> - -<$procedure writeNSUserDefaultsProtocolSupportBlock$> - -//****************************************************************************// -// MARK: NSUserDefault Support -//****************************************************************************// - -extension NSUserDefaults { - - public func get<$typeName$>(key: String) -> <$typeName$>? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return decode<$typeName$>(dictionary) - } - - public func get<$typeName$>(key: String) -> [<$typeName$>]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(decode<$typeName$>)) - } - - public func get<$typeName$>(key: String) -> [String : <$typeName$>]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { decode<$typeName$>($0) }) - } - - public func get<$typeName$>(key: String, defaultValue: <$typeName$>) -> <$typeName$> { - return get<$typeName$>(key) ?? defaultValue - } - - public func get<$typeName$>(key: String, defaultValue: [<$typeName$>]) -> [<$typeName$>] { - return get<$typeName$>(key) ?? defaultValue - } - - public func get<$typeName$>(key: String, defaultValue: [String : <$typeName$>] - ) -> [String : <$typeName$>] { - return get<$typeName$>(key) ?? defaultValue - } - - public func set<$typeName$>(value: <$typeName$>, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func set<$typeName$>(value: [<$typeName$>], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func set<$typeName$>(value: [String : <$typeName$>], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} -<$endprocedure$> - - -<$procedure writeKVStoreProtocolSupportBlock$> -//****************************************************************************// -// MARK: KVStore support -//****************************************************************************// -extension KVStore { - public func get<$typeName$>(key: String) -> <$typeName$>? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decode<$typeName$>(keys.valueName) - } - else { - return nil - } - } - - public func get<$typeName$>(key: String, defaultValue: <$typeName$>) -> <$typeName$> { - return get<$typeName$>(key) ?? defaultValue - } - - public func get<$typeName$>s(key: String) -> [<$typeName$>]? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decode<$typeName$>(keys.valueName) - } - else { - return nil - } - } - - public func get<$typeName$>s(key: String, defaultValue: [<$typeName$>]) -> [<$typeName$>] { - return get<$typeName$>s(key) ?? defaultValue - } - - public func get<$typeName$>Dictionary(key: String) -> [String : <$typeName$>]? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decode<$typeName$>(keys.valueName) - } - else { - return nil - } - } - - public func get<$typeName$>Dictionary(key: String, defaultValue: [String : <$typeName$>]) -> [String : <$typeName$>] { - return get<$typeName$>Dictionary(key) ?? defaultValue - } - - public func setValue(value: <$typeName$>, forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - - public func setValue(value: [<$typeName$>], forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - - public func setValue(value: [String : <$typeName$>], forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - -} -<$endprocedure$> - -<$procedure writeEncodingVersioningBlock$> - <$typeName$>.encodeVersionIfNeeded(encoder) - <$endprocedure$> - -<$procedure writeDecodingMigrationBlock$>decoder = <$typeName$>.performMigrationIfNeeded(decoder)<$endprocedure$> - <$procedure Struct$> <$setmerge typeName = <$managedObjectClassName$>$> @@ -279,15 +47,14 @@ public struct <$typeName$> : <$superTypeName$> { <$endforeach do$> } -extension <$typeName$> : Decodable { +extension <$typeName$> { - public static func decode(decoder: Decoder) -> <$typeName$>? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> <$typeName$>? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - <$call writeDecodingMigrationBlock$> + public init?(with inStore: Store) { + let store = <$typeName$>.migrate(source: inStore) <$setlocal hasNonOptionals = 0 $> <$foreach Attribute attributesByName do$><$if !Attribute.isTransient && Attribute.userInfo.State.ProtocolRequirementType != func && Attribute.userInfo.State.ProtocolRequirementType != get$><$if !Attribute.isOptional$><$setlocal hasNonOptionals = 1$><$endif$><$endif$><$endforeach do$> @@ -296,36 +63,30 @@ extension <$typeName$> : Decodable { <$if hasNonOptionals == 1$> guard <$setlocal prop = 0$><$foreach Attribute attributesByName do$><$if !Attribute.isTransient && Attribute.userInfo.State.ProtocolRequirementType != func && Attribute.userInfo.State.ProtocolRequirementType != get$><$if !Attribute.isOptional$><$if prop > 0$>, - <$endif$><$setlocal prop = prop + 1$>let <$Attribute.name$>: <$call getTypeForAttribute Attribute$> = decoder.decode("<$Attribute.name$>")<$endif$><$endif$><$endforeach do$><$foreach Relationship relationshipsByName do$><$if !Relationship.isTransient && Relationship.userInfo.State.ProtocolRequirementType != get$><$if !Relationship.isOptional$><$if prop > 0$>, - <$endif$><$setlocal prop = prop + 1$>let <$Relationship.name$>: <$if Relationship.isToMany$>[<$endif$><$if Relationship.userInfo.State.CompositionType == Dictionary$>String : <$endif$><$Relationship.destinationEntity.managedObjectClassName$><$if Relationship.isToMany$>]<$endif$><$if Relationship.isOptional$>?<$endif$> = decoder.decode<$if Relationship.destinationEntity.isAbstract || Relationship.destinationEntity.userInfo.State.Protocol == YES$><$Relationship.destinationEntity.managedObjectClassName$><$endif$>("<$Relationship.name$>")<$endif$><$endif$><$endforeach do$> + <$endif$><$setlocal prop = prop + 1$>let <$Attribute.name$>: <$call getTypeForAttribute Attribute$> = store.value(forKey: "<$Attribute.name$>")<$endif$><$endif$><$endforeach do$><$foreach Relationship relationshipsByName do$><$if !Relationship.isTransient && Relationship.userInfo.State.ProtocolRequirementType != get$><$if !Relationship.isOptional$><$if prop > 0$>, + <$endif$><$setlocal prop = prop + 1$>let <$Relationship.name$>: <$if Relationship.isToMany$>[<$endif$><$if Relationship.userInfo.State.CompositionType == Dictionary$>String : <$endif$><$Relationship.destinationEntity.managedObjectClassName$><$if Relationship.isToMany$>]<$endif$><$if Relationship.isOptional$>?<$endif$> = store.value<$if Relationship.destinationEntity.isAbstract || Relationship.destinationEntity.userInfo.State.Protocol == YES$><$endif$>(forKey: "<$Relationship.name$>")<$endif$><$endif$><$endforeach do$> else { return nil } <$endif$> - <$foreach Attribute attributesByName do$><$if !Attribute.isTransient && Attribute.userInfo.State.ProtocolRequirementType != func && Attribute.userInfo.State.ProtocolRequirementType != get$><$if Attribute.isOptional$>let <$Attribute.name$>: <$call getTypeForAttribute Attribute$> = decoder.decode("<$Attribute.name$>")<$endif$> - <$endif$><$endforeach do$><$foreach Relationship relationshipsByName do$><$if !Relationship.isTransient && Relationship.userInfo.State.ProtocolRequirementType != get$><$if Relationship.isOptional$>let <$Relationship.name$>: <$if Relationship.isToMany$>[<$endif$><$if Relationship.userInfo.State.CompositionType == Dictionary$>String : <$endif$><$Relationship.destinationEntity.managedObjectClassName$><$if Relationship.isToMany$>]<$endif$><$if Relationship.isOptional$>?<$endif$> = decoder.decode<$if Relationship.destinationEntity.isAbstract || Relationship.destinationEntity.userInfo.State.Protocol == YES$><$Relationship.destinationEntity.managedObjectClassName$><$endif$>("<$Relationship.name$>")<$endif$> + <$foreach Attribute attributesByName do$><$if !Attribute.isTransient && Attribute.userInfo.State.ProtocolRequirementType != func && Attribute.userInfo.State.ProtocolRequirementType != get$><$if Attribute.isOptional$>let <$Attribute.name$>: <$call getTypeForAttribute Attribute$> = store.value(forKey: "<$Attribute.name$>")<$endif$> + <$endif$><$endforeach do$><$foreach Relationship relationshipsByName do$><$if !Relationship.isTransient && Relationship.userInfo.State.ProtocolRequirementType != get$><$if Relationship.isOptional$>let <$Relationship.name$>: <$if Relationship.isToMany$>[<$endif$><$if Relationship.userInfo.State.CompositionType == Dictionary$>String : <$endif$><$Relationship.destinationEntity.managedObjectClassName$><$if Relationship.isToMany$>]<$endif$><$if Relationship.isOptional$>?<$endif$> = store.value<$if Relationship.destinationEntity.isAbstract || Relationship.destinationEntity.userInfo.State.Protocol == YES$><$endif$>(forKey: "<$Relationship.name$>")<$endif$> <$endif$><$endforeach do$> <$foreach Attribute attributesByName do$><$if !Attribute.isTransient && Attribute.userInfo.State.ProtocolRequirementType != func && Attribute.userInfo.State.ProtocolRequirementType != get$>self.<$Attribute.name$> = <$Attribute.name$> <$endif$><$endforeach do$><$foreach Relationship relationshipsByName do$><$if !Relationship.isTransient && Relationship.userInfo.State.ProtocolRequirementType != get$>self.<$Relationship.name$> = <$Relationship.name$> - <$endif$><$endforeach do$>didFinishDecodingWithDecoder(decoder) + <$endif$><$endforeach do$>finishReading(from: store) } -} -extension <$typeName$> : Encodable { - - public func encode(encoder: Encoder) { - <$foreach Attribute attributesByName do$><$if !Attribute.isTransient && Attribute.userInfo.State.ProtocolRequirementType != func && Attribute.userInfo.State.ProtocolRequirementType != get$>encoder.encode(<$Attribute.name$>, "<$Attribute.name$>") - <$endif$><$endforeach do$><$foreach Relationship relationshipsByName do$><$if !Relationship.isTransient && Relationship.userInfo.State.ProtocolRequirementType != get$>encoder.encode(<$Relationship.name$>, "<$Relationship.name$>") + public func write(to store: inout Store) { + <$foreach Attribute attributesByName do$><$if !Attribute.isTransient && Attribute.userInfo.State.ProtocolRequirementType != func && Attribute.userInfo.State.ProtocolRequirementType != get$>store.set(<$Attribute.name$>, forKey: "<$Attribute.name$>") + <$endif$><$endforeach do$><$foreach Relationship relationshipsByName do$><$if !Relationship.isTransient && Relationship.userInfo.State.ProtocolRequirementType != get$>store.set(<$Relationship.name$>, forKey: "<$Relationship.name$>") <$endif$><$endforeach do$> - <$if hasSuperentity$>encoder.encode("<$typeName$>", "<$rootTypeName$>")<$endif$> - <$call writeEncodingVersioningBlock$> - self.willFinishEncodingWithEncoder(encoder) + <$if hasSuperentity$>store.set("<$typeName$>", forKey: "<$rootTypeName$>")<$endif$> + <$typeName$>.writeVersion(to: &store) + finishWriting(to: &store) } } -<$call writeVersionHashExtension $> -<$call writeNSUserDefaultsSupportBlock$> -<$call writeKVStoreSupportBlock$> <$endprocedure$> @@ -333,7 +94,7 @@ extension <$typeName$> : Encodable { <$procedure writeAssociatedValueCaseForAttribute Attribute$><$if Attribute.userInfo.State.Type$>(<$Attribute.userInfo.State.Type$><$if Attribute.isOptional$>?<$endif$>)<$endif$><$endprocedure$> -<$procedure writeEnumCaseForAttribute Attribute$>case <$Attribute.name.initialCapitalString$> <$if userInfo.State.Type$><$call writeRawValueCaseForAttribute Attribute$><$else$><$call writeAssociatedValueCaseForAttribute Attribute$><$endif$><$endprocedure$> +<$procedure writeEnumCaseForAttribute Attribute$>case <$Attribute.name$> <$if userInfo.State.Type$><$call writeRawValueCaseForAttribute Attribute$><$else$><$call writeAssociatedValueCaseForAttribute Attribute$><$endif$><$endprocedure$> <$procedure writeRawValueCaseForRelationship Relationship$><$if Relationship.userInfo.State.Value$> = <$if userInfo.State.Type == String$>"<$endif$><$ Relationship.userInfo.State.Value$><$if userInfo.State.Type == String$>"<$endif$><$endif$><$endprocedure$> @@ -341,67 +102,67 @@ extension <$typeName$> : Encodable { <$procedure writeAssociatedValueCaseForRelationship Relationship$><$if Relationship.destinationEntity.managedObjectClassName$>(<$if Relationship.isToMany$>[<$endif$><$Relationship.destinationEntity.managedObjectClassName$><$if Relationship.isToMany$>]<$endif$><$if Relationship.isOptional$>?<$endif$>)<$endif$><$endprocedure$> -<$procedure writeEnumCaseForRelationship Relationship$>case <$Relationship.name.initialCapitalString$> <$if userInfo.State.Type$><$call writeRawValueCaseForRelationship Relationship$><$else$><$call writeAssociatedValueCaseForRelationship Relationship$><$endif$><$endprocedure$> +<$procedure writeEnumCaseForRelationship Relationship$>case <$Relationship.name$> <$if userInfo.State.Type$><$call writeRawValueCaseForRelationship Relationship$><$else$><$call writeAssociatedValueCaseForRelationship Relationship$><$endif$><$endprocedure$> -<$procedure writeAttributeDecodeAssociatedSwitchCaseForEnumOptional Attribute$>let value: <$Attribute.userInfo.State.Type$>? = decoder.decode("value") -self = <$typeName$>.<$Attribute.name.initialCapitalString$>(value) +<$procedure writeAttributeDecodeAssociatedSwitchCaseForEnumOptional Attribute$>let value: <$Attribute.userInfo.State.Type$>? = store.value(forKey: "value") + self = <$typeName$>.<$Attribute.name$>(value) <$endprocedure$> -<$procedure writeAttributeDecodeAssociatedSwitchCaseForEnumNonOptional Attribute$>if let value: <$Attribute.userInfo.State.Type$> = decoder.decode("value") { -self = <$typeName$>.<$Attribute.name.initialCapitalString$>(value) -} else { return nil }<$endprocedure$> +<$procedure writeAttributeDecodeAssociatedSwitchCaseForEnumNonOptional Attribute$>if let value: <$Attribute.userInfo.State.Type$> = store.value(forKey: "value") { + self = <$typeName$>.<$Attribute.name$>(value) + } else { return nil }<$endprocedure$> <$procedure writeAttributeDecodeAssociatedSwitchCaseForEnum Attribute$><$if Attribute.isOptional$><$call writeAttributeDecodeAssociatedSwitchCaseForEnumOptional Attribute$><$else$><$call writeAttributeDecodeAssociatedSwitchCaseForEnumNonOptional Attribute$><$endif$> <$endprocedure$> -<$procedure writeAttributeDecodeBasicSwitchCaseForEnum Attribute$>self = <$typeName$>.<$Attribute.name.initialCapitalString$><$endprocedure$> +<$procedure writeAttributeDecodeBasicSwitchCaseForEnum Attribute$>self = <$typeName$>.<$Attribute.name$><$endprocedure$> -<$procedure writeAttributeDecodeSwitchCaseForEnumCase Attribute$>case "<$Attribute.name.initialCapitalString$>": +<$procedure writeAttributeDecodeSwitchCaseForEnumCase Attribute$>case "<$Attribute.name$>": <$if Attribute.userInfo.State.Type$><$call writeAttributeDecodeAssociatedSwitchCaseForEnum Attribute$><$else$><$call writeAttributeDecodeBasicSwitchCaseForEnum Attribute$><$endif$><$endprocedure$> -<$procedure writeRelationshipDecodeAssociatedSwitchCaseForEnumOptional Relationship$>let value: <$if Relationship.isToMany$>[<$endif$><$Relationship.destinationEntity.managedObjectClassName$><$if Relationship.isToMany$>]<$endif$>? = decoder.decode("value") -self = <$typeName$>.<$Relationship.name.initialCapitalString$>(value) +<$procedure writeRelationshipDecodeAssociatedSwitchCaseForEnumOptional Relationship$>let value: <$if Relationship.isToMany$>[<$endif$><$Relationship.destinationEntity.managedObjectClassName$><$if Relationship.isToMany$>]<$endif$>? = store.value(forKey: "value") + self = <$typeName$>.<$Relationship.name$>(value) <$endprocedure$> -<$procedure writeRelationshipDecodeAssociatedSwitchCaseForEnumNonOptional Relationship$>if let value: <$if Relationship.isToMany$>[<$endif$><$Relationship.destinationEntity.managedObjectClassName$><$if Relationship.isToMany$>]<$endif$> = decoder.decode("value") { -self = <$typeName$>.<$Relationship.name.initialCapitalString$>(value) -} else { return nil }<$endprocedure$> +<$procedure writeRelationshipDecodeAssociatedSwitchCaseForEnumNonOptional Relationship$>if let value: <$if Relationship.isToMany$>[<$endif$><$Relationship.destinationEntity.managedObjectClassName$><$if Relationship.isToMany$>]<$endif$> = store.value(forKey: "value") { + self = <$typeName$>.<$Relationship.name$>(value) + } else { return nil }<$endprocedure$> <$procedure writeRelationshipDecodeAssociatedSwitchCaseForEnum Relationship$><$if Relationship.isOptional$><$call writeRelationshipDecodeAssociatedSwitchCaseForEnumOptional Relationship$><$else$><$call writeRelationshipDecodeAssociatedSwitchCaseForEnumNonOptional Relationship$> <$endif$><$endprocedure$> -<$procedure writeRelationshipDecodeBasicSwitchCaseForEnum Relationship$>self = <$typeName$>.<$Relationship.name.initialCapitalString$><$endprocedure$> +<$procedure writeRelationshipDecodeBasicSwitchCaseForEnum Relationship$>self = <$typeName$>.<$Relationship.name$><$endprocedure$> -<$procedure writeRelationshipDecodeRawSwitchCaseForEnum Relationship$>if let value: <$userInfo.State.Type$> = decoder.decode("value"), +<$procedure writeRelationshipDecodeRawSwitchCaseForEnum Relationship$>if let value: <$userInfo.State.Type$> = store.value(forKey: "value"), instance = <$typeName$>(rawValue: value) { - instance.didFinishDecodingWithDecoder(decoder) + instance.finishReading(from: store) self = instance } else { return nil }<$endprocedure$> -<$procedure writeRelationshipDecodeSwitchCaseForEnumCase Relationship$>case "<$Relationship.name.initialCapitalString$>": +<$procedure writeRelationshipDecodeSwitchCaseForEnumCase Relationship$>case "<$Relationship.name$>": <$if userInfo.State.Type$><$call writeRelationshipDecodeRawSwitchCaseForEnum Relationship$><$elseif Relationship.destinationEntity.managedObjectClassName$><$call writeRelationshipDecodeAssociatedSwitchCaseForEnum Relationship$><$else$><$call writeRelationshipDecodeBasicSwitchCaseForEnum Relationship$><$endif$><$endprocedure$> -<$procedure writeAttributeEncodeBasicSwitchCaseForEnum Attribute$>case .<$Attribute.name.initialCapitalString$>: - encoder.encode("<$Attribute.name.initialCapitalString$>", "<$typeName$>")<$endprocedure$> +<$procedure writeAttributeEncodeBasicSwitchCaseForEnum Attribute$>case .<$Attribute.name$>: + store.set("<$Attribute.name$>", forKey: "<$typeName$>")<$endprocedure$> -<$procedure writeAttributeEncodeAssociatedSwitchCaseForEnum Attribute$>case let .<$Attribute.name.initialCapitalString$>(value): - encoder.encode("<$Attribute.name.initialCapitalString$>", "<$typeName$>") - encoder.encode(value, "value")<$endprocedure$> +<$procedure writeAttributeEncodeAssociatedSwitchCaseForEnum Attribute$>case let .<$Attribute.name$>(value): + store.set("<$Attribute.name$>", forKey: "<$typeName$>") + store.set(value, forKey: "value")<$endprocedure$> <$procedure writeAttributeEncodeSwitchCaseForEnumCase Attribute$><$if Attribute.userInfo.State.Type$><$call writeAttributeEncodeAssociatedSwitchCaseForEnum Attribute$><$else$><$call writeAttributeEncodeBasicSwitchCaseForEnum Attribute$><$endif$><$endprocedure$> -<$procedure writeRelationshipEncodeBasicSwitchCaseForEnum Relationship$>case .<$Relationship.name.initialCapitalString$>: - encoder.encode("<$Relationship.name.initialCapitalString$>", "<$typeName$>")<$endprocedure$> +<$procedure writeRelationshipEncodeBasicSwitchCaseForEnum Relationship$>case .<$Relationship.name$>: + store.set("<$Relationship.name$>", forKey: "<$typeName$>")<$endprocedure$> -<$procedure writeRelationshipEncodeRawSwitchCaseForEnum Relationship$>case let .<$Relationship.name.initialCapitalString$>: - encoder.encode("<$Relationship.name.initialCapitalString$>", "<$typeName$>") - encoder.encode(self.rawValue, "value")<$endprocedure$> +<$procedure writeRelationshipEncodeRawSwitchCaseForEnum Relationship$>case let .<$Relationship.name$>: + store.set("<$Relationship.name$>", forKey: "<$typeName$>") + store.set(self.rawValue, forKey: "value")<$endprocedure$> -<$procedure writeRelationshipEncodeAssociatedSwitchCaseForEnum Relationship$>case let .<$Relationship.name.initialCapitalString$>(value): - encoder.encode("<$Relationship.name.initialCapitalString$>", "<$typeName$>") - encoder.encode(value, "value")<$endprocedure$> +<$procedure writeRelationshipEncodeAssociatedSwitchCaseForEnum Relationship$>case let .<$Relationship.name$>(value): + store.set("<$Relationship.name$>", forKey: "<$typeName$>") + store.set(value, forKey: "value")<$endprocedure$> <$procedure writeRelationshipEncodeSwitchCaseForEnumCase Relationship$><$if userInfo.State.Type$><$call writeRelationshipEncodeRawSwitchCaseForEnum Relationship$><$elseif Relationship.destinationEntity.managedObjectClassName$><$call writeRelationshipEncodeAssociatedSwitchCaseForEnum Relationship$><$else$><$call writeRelationshipEncodeBasicSwitchCaseForEnum Relationship$><$endif$><$endprocedure$> @@ -415,17 +176,17 @@ public enum <$typeName$> <$if userInfo.State.Type$> : <$userInfo.State.Type$>, M <$endforeach do$> } -extension <$typeName$>: Decodable { +extension <$typeName$> { - public static func decode(decoder: Decoder) -> <$typeName$>? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> <$typeName$>? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - <$call writeDecodingMigrationBlock$> + public init?(with inStore: Store) { + let store = <$typeName$>.migrate(source: inStore) + <$if ! userInfo.State.Type$> - guard let type: String = decoder.decode("<$typeName$>") else { return nil } + guard let type: String = store.value(forKey: "<$typeName$>") else { return nil } switch type { <$foreach Attribute noninheritedAttributes do$><$call writeAttributeDecodeSwitchCaseForEnumCase Attribute$> <$endforeach do$><$foreach Relationship noninheritedRelationships do$><$call writeRelationshipDecodeSwitchCaseForEnumCase Relationship$> @@ -433,27 +194,23 @@ extension <$typeName$>: Decodable { default: return nil } -<$else$> guard let value: <$userInfo.State.Type$> = decoder.decode<$if userInfo.State.Model$><$userInfo.State.Model$><$endif$>("value") else { return nil } + <$else$> guard let value: <$userInfo.State.Type$> = store.value(forKey: "value") else { return nil } self.init(rawValue: value)<$endif$> } -} - -extension <$typeName$>: Encodable { - public func encode(encoder: Encoder) { + public func write(to store: inout Store) { <$if ! userInfo.State.Type$> switch self { <$foreach Attribute noninheritedAttributes do$><$call writeAttributeEncodeSwitchCaseForEnumCase Attribute$> <$endforeach do$><$foreach Relationship noninheritedRelationships do$><$call writeRelationshipEncodeSwitchCaseForEnumCase Relationship$> <$endforeach do$> } -<$else$> encoder.encode(self.rawValue, "value")<$endif$><$call writeEncodingVersioningBlock$>self.willFinishEncodingWithEncoder(encoder) +<$else$> store.set(self.rawValue, forKey: "value")<$endif$> + <$typeName$>.writeVersion(to: &store) + finishWriting(to: &store) } } -<$call writeVersionHashExtension $> -<$call writeNSUserDefaultsSupportBlock$> -<$call writeKVStoreSupportBlock$> <$endprocedure$> <$procedure writeAttributeProtocolFunctionRequirement Attribute$> <$if Attribute.userInfo.State.Mutating == YES$>mutating <$endif$>func <$Attribute.userInfo.State.Func$><$endprocedure$> @@ -482,55 +239,71 @@ public protocol <$typeName$><$if hasSuperentity$> : <$superentity.managedObjectC <$foreach Attribute noninheritedAttributes do$><$if Attribute.userInfo.State.ProtocolRequirementType == func$><$call writeAttributeProtocolFunctionRequirement Attribute$> <$endif$><$endforeach do$> - -} - -func decode<$typeName$>(data: AnyObject?) -> <$typeName$>? { - - if let data = data as? [String : AnyObject] { - let decoder = Decoder(data: data) - guard let dataTypeKey = data["<$typeName$>"] as? String else { return nil } - if let t = decoder.<$typeName$>TypeForKey(dataTypeKey) { - return t.decode(decoder) - } - return nil - } - return nil } - -// Mark: Decoding - -public extension DecoderType { - - - public func decode<$typeName$>(key: String) -> <$typeName$>? { - let data = self.data - let d = data[key] as? [String : AnyObject] - return d.flatMap(_decode<$typeName$>) +extension Store { + + public func value(forKey key: String) -> <$typeName$>? { + guard let data : [String : AnyObject] = value(forKey: key) else { return nil } + return _decode<$typeName$>(data: data) } - - public func decode<$typeName$>(key: String) -> [<$typeName$>]? { - let data = self.data - let d = data[key] as? [[String : AnyObject]] - return d.flatMap { sequence($0.map(_decode<$typeName$>)) } + + public func value(forKey key: String) -> [<$typeName$>]? { + guard let arrayv : [[String : AnyObject]] = value(forKey: key) else { return nil } + return sequence(arrayv.map { _decode<$typeName$>(data:$0) }) + } + + public func value(forKey key: String) -> [String : <$typeName$>]? { + guard let data : [String : [String : AnyObject]] = value(forKey: key) else { return nil } + return sequence(data.map { self._decode<$typeName$>(data:$0) }) + } + + public mutating func set(_ value: <$typeName$>?, forKey key: String) { + guard let value = value else { return } + var vstore = Store() + value.write(to: &vstore) + set(vstore.data, forKey: key) + } + + /// Add or update the value at key. + public mutating func set(_ value: [<$typeName$>]?, forKey key: String) { + guard let value = value else { return } + + let data = value.reduce([[String : AnyObject]](), combine: { (data, value) -> [[String: AnyObject]] in + var vstore = Store() + var vdata = data + value.write(to: &vstore ) + vdata.append(vstore.data) + return vdata + }) + + set(data , forKey: key) } - public func decode<$typeName$>(key: String) -> [String : <$typeName$>]? { - let data = self.data - let d = data[key] as? [String : [String : AnyObject]] - return d.flatMap { sequence($0.map(_decode<$typeName$>)) } + /// Add or update the value at key. + public mutating func set(_ value: [String : <$typeName$>]?, forKey key: String) { + + guard let value = value else { return } + let data = value.reduce([String : [String : AnyObject]](), combine: { (data, element) -> [String : [String : AnyObject]] in + var vstore = Store() + var vdata = data + element.value.write(to: &vstore) + vdata[element.key] = vstore.data + return vdata + }) + + set(data, forKey: key) } private func _decode<$typeName$>(data: [String : AnyObject]) -> <$typeName$>? { - guard let dataTypeKey = data["<$rootTypeName$>"] as? String else { return nil } - if let t = <$typeName$>TypeForKey(dataTypeKey) { - return t.decode(Decoder(data: data)) + guard let typeKey = data["<$rootTypeName$>"] as? String else { return nil } + if let t = <$typeName$>Type(forKey: typeKey) { + return t.read(from: Store(data: data)) } return nil } - - private func <$typeName$>TypeForKey(key: String) -> <$typeName$>.Type? { + + private func <$typeName$>Type(forKey key: String) -> <$typeName$>.Type? { switch key { <$call writeCasesForTypes subentities$> default: @@ -538,29 +311,6 @@ public extension DecoderType { } } } - -// Mark: Encoding - -public extension EncoderType { - - public func encode(element: <$typeName$>?, _ key: String) { - guard let element = element else { return } - self.data[key] = element.encode() - } - - public func encode(element: [<$typeName$>]?, _ key: String) { - guard let element = element else { return } - self.data[key] = element.map { $0.encode() } - } - - public func encode(element: [String : <$typeName$>]?, _ key: String) { - guard let element = element else { return } - self.data[key] = element.map { $0.encode() } - } -} - -<$call writeNSUserDefaultsProtocolSupportBlock$> -<$call writeKVStoreProtocolSupportBlock$> <$endprocedure$> <$if userInfo.State.Enum == YES$><$call Enum$><$elseif isAbstract || userInfo.State.Protocol == YES$><$call Protocol$><$else$><$call Struct$> diff --git a/Tests/BaseTest.swift b/Tests/BaseTest.swift new file mode 100644 index 0000000..433f8d6 --- /dev/null +++ b/Tests/BaseTest.swift @@ -0,0 +1,106 @@ +import Foundation +import XCTest +@testable import State + +infix operator >>- { associativity left precedence 100 } +infix operator -<< { associativity right precedence 100 } + +/** + flatMap a function over an optional value (left associative) + + - If the value is .None, the function will not be evaluated and this will return .None + - If the value is .Some, the function will be applied to the unwrapped value + + - parameter f: A transformation function from type T to type Optional + - parameter a: A value of type Optional + + - returns: A value of type Optional + */ +public func >>-(a: T?, f: @noescape (T) -> U?) -> U? { + return a.flatMap(f) +} + +public extension Optional { + + public func apply(_ f: ((Wrapped) -> U)?) -> U? { + return f.flatMap { self.map($0) } + } +} + +// MARK: - BASE TEST + +class Test : XCTestCase { + let plistFile: AnyObject? = Test.plist(fromFile: "Data") + var plistData : [String : AnyObject] = [:] + let jsonFile: AnyObject? = Test.JSON(fromFile: "Data") + var jsonData : [String : AnyObject] = [:] + + class func plist(fromFile file: String) -> AnyObject? { + let path = Bundle(for: self).pathForResource(file, ofType: "plist") + + if let p = path { + if let dict = NSDictionary(contentsOfFile: p) { + return dict + } + if let arr = NSArray(contentsOfFile: p) { + return arr + } + } + return .none + } + + class func JSON(fromFile file: String) -> AnyObject? { + let path = Bundle(for: self).pathForResource(file, ofType: "json") + + if path != nil { + if let data = try? Data(contentsOf: URL(fileURLWithPath: path!)) { + do { + return try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions(rawValue: 0)) + } catch _ { + return nil + } + } + } + return .none + } + + func bundlePathFor(_ file: String, ofType type: String) -> String? { + return Bundle(for: Test.self ).pathForResource(file , ofType:type) + } + + func bundleURLFor(_ file: String, ofType type: String) -> URL? { + guard let path = bundlePathFor(file, ofType: type) else { return nil } + return URL(fileURLWithPath: path) + } + + func tempPathFor(_ file: String) -> String { + return NSString.path(withComponents: [NSTemporaryDirectory(), file]) + } + + func tempURLFor(_ file: String) -> URL { + return URL(fileURLWithPath: tempPathFor(file)) + } + + func clearTempData() { + let fileManager = FileManager.default + let enumerator = fileManager.enumerator(atPath: NSTemporaryDirectory()) + while let file = enumerator?.nextObject() as? String { + do { + try fileManager.removeItem(at: try! URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(file)) + } catch _ { + } + } + } + + override func setUp() { + super.setUp() + clearTempData() + if let d = plistFile as? [String : AnyObject] { + plistData = d + } + + if let j = jsonFile as? [String : AnyObject] { + jsonData = j + } + } +} diff --git a/Tests/Tests/ConverterTests.swift b/Tests/FormatTests.swift similarity index 53% rename from Tests/Tests/ConverterTests.swift rename to Tests/FormatTests.swift index 36e0d36..317b015 100644 --- a/Tests/Tests/ConverterTests.swift +++ b/Tests/FormatTests.swift @@ -1,45 +1,27 @@ -import XCTest -import State import Foundation +import XCTest +@testable import State -infix operator >>- { associativity left precedence 100 } -infix operator -<< { associativity right precedence 100 } - -/** - flatMap a function over an optional value (left associative) - - - If the value is .None, the function will not be evaluated and this will return .None - - If the value is .Some, the function will be applied to the unwrapped value - - - parameter f: A transformation function from type T to type Optional - - parameter a: A value of type Optional - - - returns: A value of type Optional - */ -func >>-(a: T?, @noescape f: T -> U?) -> U? { - return a.flatMap(f) -} - - - -class ConverterTests: Test { +class FormatTests: Test { var testPlist : [String : AnyObject]? var testJSON : [String : AnyObject]? var testData : [String : AnyObject]? override func setUp() { super.setUp() - - bundlePathFor("Data", ofType: "plist").apply{ self.testPlist = Plist.read($0) } - bundlePathFor("Data", ofType: "plist").apply { self.testData = Plist.read($0) } - bundlePathFor("Data", ofType: "json").apply{ self.testJSON = JSON.read($0) } + + let plist = PlistFormatter() + let json = JSONFormatter() + self.testPlist = plist.read(bundleURLFor("Data", ofType: "plist")!) as? [String : AnyObject] + self.testData = plist.read(bundleURLFor("Data", ofType: "plist")!) as? [String : AnyObject] + self.testJSON = json.read(bundleURLFor("Data", ofType: "json")!) as? [String : AnyObject] } func testPlistWasReadCorrectly() { XCTAssert(testPlist?.count == 9, "Plist Count should be 9 , is \(testPlist?.count)") if let floatData = testPlist?["Float"] as? [String : AnyObject], let v = floatData["t"] as? Float { - XCTAssert(v == -0.345) + XCTAssert(v == -0.345) } else { XCTFail("Plist was not read correctly") } @@ -49,19 +31,19 @@ class ConverterTests: Test { XCTAssert(testData?.count == 9) if let floatData = testData?["Float"] as? [String : AnyObject], let v = floatData["t"] as? Float { - XCTAssert(v == -0.345) + XCTAssert(v == -0.345) } else { XCTFail("Data was not read correctly") } } func testJSONWasReadCorrectly() { - XCTAssert(testJSON?.count == 9) + XCTAssert(testJSON?.count == 9) if let tArr = testJSON?["t_arr"] as? [AnyObject], let u = tArr[1] as? [String : AnyObject], let name = u["name"] as? String { - XCTAssert(u.count == 3) - XCTAssert(name == "John Doe") + XCTAssert(u.count == 3) + XCTAssert(name == "John Doe") } else { XCTFail("JSON was not read correctly") } @@ -108,64 +90,70 @@ class ConverterTests: Test { func testParsingJSONFromString() { testJSONWasReadCorrectly() - let testString : String? = bundlePathFor("Data", ofType: "json") >>- JSON.read >>- JSON.write + let json = JSONFormatter() + let testString : String? = bundleURLFor("Data", ofType: "json") >>- json.read >>- json.makeString testJSON = nil - testJSON = JSON.readString(testString!) + testJSON = json.read(testString!) as? [String : AnyObject] testJSONWasReadCorrectly() } func testParsingPlistFromString() { testPlistWasReadCorrectly() - let testString : String? = bundlePathFor("Data", ofType: "plist") >>- Plist.read >>- Plist.write + let plist = PlistFormatter() + let testString : String? = bundleURLFor("Data", ofType: "plist") >>- plist.read >>- plist.makeString testPlist = nil - testPlist = Plist.readString(testString!) + testPlist = plist.read(testString!) as? [String : AnyObject] testPlistWasReadCorrectly() } func testWritingPlistString() { testPlistWasReadCorrectly() - let baseString : String? = bundlePathFor("Data", ofType: "plist") >>- Plist.read >>- Plist.write + let plist = PlistFormatter() + let baseString : String? = bundleURLFor("Data", ofType: "plist") >>- plist.read >>- plist.makeString var testString: String = "" - testPlist >>- Plist.write >>- { testString = $0 } + _ = testPlist >>- plist.makeString >>- { testString = $0 } XCTAssert(testString == baseString!) } func testWritingJSONString() { testJSONWasReadCorrectly() - let baseString : String? = bundlePathFor("Data", ofType: "json") >>- JSON.read >>- JSON.write - var testString: String = "" - testJSON >>- JSON.write >>- { testString = $0 } - XCTAssert(testString == baseString) + let json = JSONFormatter() + let baseString : String? = bundleURLFor("Data", ofType: "json") >>- json.read >>- { json.makeString(from: $0 as![String : AnyObject]) } + let testString: String? = (testJSON >>- json.makeString) + XCTAssert(testString! == baseString!, "testString:\(testString), baseString:\(baseString)") } func testReadingAndWritingPlistData() { testPlistWasReadCorrectly() - let testData: NSData? = Plist.write(testPlist!) + let plist = PlistFormatter() + let testData: Data? = plist.makeData(from: testPlist!, prettyPrint: true) testPlist = nil - testData >>- Plist.read >>- { self.testPlist = $0 } + _ = testData >>- plist.read >>- { self.testPlist = $0 as? [String : AnyObject] } testPlistWasReadCorrectly() } func testReadingAndWritingJSONData() { testJSONWasReadCorrectly() - let testData: NSData? = JSON.write(testJSON!) + let json = JSONFormatter() + let testData: Data? = json.makeData(from: testJSON!, prettyPrint: true) testJSON = nil - testData >>- JSON.read >>- { self.testJSON = $0 } + _ = testData >>- json.read >>- { self.testJSON = $0 as? [String : AnyObject] } testJSONWasReadCorrectly() } func testReadingAndWritingData() { testDataWasReadCorrectly() - let testNSData: NSData? = Binary.write(testData!) + let binary = State.Formatter() + let testNSData: Data? = binary.makeData(from: testData!, prettyPrint: true) testData = nil - testNSData >>- Binary.read >>- { self.testData = $0 } + _ = testNSData >>- binary.read >>- { self.testData = $0 as? [String : AnyObject] } testDataWasReadCorrectly() } func testReadingJSONAndWritingPlist() { - let users_out = UserTypes.decode(jsonData) - users_out!.save(.Plist, path: tempPathFor("users.plist")) - let users = UserTypes(.Plist, path: tempPathFor("users.plist")) + let users_out = UserTypes.read(from: Store(data: jsonData)) + _ = users_out!.write(to: tempURLFor("users.plist"), format: .plist) + let users = UserTypes(file: tempURLFor("users.plist"), format:.plist) XCTAssert(users != nil) XCTAssert(users?.tArr.count == 3) XCTAssert(users?.tImp.name == "John Doe") @@ -173,35 +161,41 @@ class ConverterTests: Test { XCTAssert(users?.tDicOpt?["item1"]?.email == "john@unit-testing.com") XCTAssert(users?.tArrImp.count == 3) } - -///MARK: - PRIVATE + + ///MARK: - PRIVATE private func writePlistDataOutToTempFile() { - let path = tempPathFor("test.plist") - testPlist >>- { Plist.write($0, path: path) } + let path = tempURLFor("test.plist") + let plist = PlistFormatter() + _ = testPlist >>- { plist.write($0, to: path) } } private func readPlistDataFromTempFile() { - let path = tempPathFor("test.plist") - path >>- { self.testPlist = Plist.read($0) } + let path = tempURLFor("test.plist") + let plist = PlistFormatter() + _ = path >>- { self.testPlist = plist.read($0) as? [String : AnyObject] } } private func writeJSONDataOutToTempFile() { - let path = tempPathFor("temp.json") - testJSON >>- { JSON.write($0, path: path) } + let path = tempURLFor("temp.json") + let json = JSONFormatter() + _ = testJSON >>- { json.write($0, to: path) } } - + private func readJSONDataFromTempFile() { - let path = tempPathFor("temp.json") - path >>- { self.testJSON = JSON.read($0) } + let path = tempURLFor("temp.json") + let json = JSONFormatter() + _ = path >>- { self.testJSON = json.read($0) as? [String : AnyObject] } } - + private func writeDataOutToTempFile() { - let path = tempPathFor("temp.data") - testData >>- { Binary.write($0, path: path) } + let path = tempURLFor("temp.data") + let binary = State.Formatter() + _ = testData >>- { binary.write($0, to: path) } } private func readDataFromTempFile() { - let path = tempPathFor("temp.data") - path >>- { self.testData = Binary.read($0) } + let binary = State.Formatter() + let path = tempURLFor("temp.data") + _ = path >>- { self.testData = binary.read($0) as? [String : AnyObject] } } } diff --git a/Tests/ModelTests.swift b/Tests/ModelTests.swift new file mode 100644 index 0000000..fd0bb09 --- /dev/null +++ b/Tests/ModelTests.swift @@ -0,0 +1,862 @@ +import UIKit +import XCTest +@testable import State + +class ModelReadingTests: Test { + + func testDecodingDecodableFromJSON() { + let user = User.read(from: Store(data: jsonData["t"] as! [String : AnyObject])) + let userNoEmail = User.read(from: Store(data: jsonData["u"] as! [String : AnyObject])) + let users = UserTypes.read(from: Store(data: jsonData)) + XCTAssert(user != nil) + XCTAssert(user?.id == 10) + XCTAssert(user?.name == "John Doe") + XCTAssert(user?.email == "john@unit-testing.com") + XCTAssert(userNoEmail != nil) + XCTAssert(userNoEmail?.id == 10) + XCTAssert(userNoEmail?.name == "John Doe") + XCTAssert(userNoEmail?.email == nil) + XCTAssert(users != nil) + XCTAssert(users?.tArr.count == 3) + XCTAssert(users?.tImp.name == "John Doe") + XCTAssert(users?.tDicOpt?.count == 3) + XCTAssert(users?.tDicOpt?["item1"]?.email == "john@unit-testing.com") + XCTAssert(users?.tArrImp.count == 3) + } + + func testDecodingDecodableFromPlist() { + let user = User.read(from: Store(data: plistData["User1"] as! [String : AnyObject])) + let userNoEmail = User.read(from: Store(data: plistData["User2"] as! [String : AnyObject])) + let users = UserTypes.read(from: Store(data: plistData["Users"] as! [String : AnyObject])) + XCTAssert(user != nil) + XCTAssert(user?.id == 10) + XCTAssert(user?.name == "John Doe") + XCTAssert(user?.email == "john@unit-testing.com") + XCTAssert(userNoEmail != nil) + XCTAssert(userNoEmail?.id == 10) + XCTAssert(userNoEmail?.name == "John Doe") + XCTAssert(userNoEmail?.email == nil) + XCTAssert(users != nil) + XCTAssert(users?.tArr.count == 3) + XCTAssert(users?.tImp.name == "John Doe") + XCTAssert(users?.tDicOpt?.count == 3) + XCTAssert(users?.tDicOpt?["item1"]?.email == "john@unit-testing.com") + XCTAssert(users?.tArrImp.count == 3) + } + + func testDecodingInvalidDecodableShouldFail() { + let user = User.read(from: Store(data: jsonData["x"] as! [String : AnyObject])) + XCTAssert(user == nil) + } +} + +class DecodingTests: Test { + + func testDecodingBools() { + let bools = BasicTypes.read(from: Store(data: plistData["Bool"] as! [String : AnyObject])) + /// Bools + XCTAssert(bools != nil) + XCTAssert(bools?.t == true) + XCTAssert(bools?.tOpt == nil) + XCTAssert(bools?.tImp == false) + + /// Bool Arrays + XCTAssert(bools?.tArr.count == 3) + XCTAssert(bools?.tArr[1] == true) + XCTAssert(bools?.tArrOpt == nil) + XCTAssert(bools?.tArrImp != nil) + XCTAssert(bools?.tArrImp[1] == true) + + /// Bool Dictionaries + XCTAssert(bools?.tDic.count == 2) + XCTAssert(bools?.tDic["key1"] == true) + XCTAssert(bools?.tDic["key0"] == false) + XCTAssert(bools?.tDicOpt != nil) + XCTAssert(bools?.tDictImp["key0"] == true) + } + + func testDecodingIntTypes() { + let ints = BasicTypes.read(from: Store(data: plistData["Int"] as! [String : AnyObject])) + + /// Ints + XCTAssert(ints != nil) + XCTAssert(ints?.t == 10) + XCTAssert(ints?.tOpt == nil) + XCTAssert(ints?.tImp == 40) + + /// Int Arrays + XCTAssert(ints?.tArr.count == 3) + XCTAssert(ints?.tArr[1] == 10) + XCTAssert(ints?.tArrOpt == nil) + XCTAssert(ints?.tArrImp != nil) + XCTAssert(ints?.tArrImp[1] == 64) + + /// Int Dictionaries + XCTAssert(ints?.tDic.count == 2) + XCTAssert(ints?.tDic["key1"] == 123) + XCTAssert(ints?.tDic["key0"] == 67) + XCTAssert(ints?.tDicOpt != nil) + XCTAssert(ints?.tDictImp["key1"] == 79) + } + + func testDecodingDoubles() { + let doubles = BasicTypes.read(from: Store(data: plistData["Double"] as! [String : AnyObject])) + + /// Doubles + XCTAssert(doubles != nil) + XCTAssert(doubles?.t == -0.456) + XCTAssert(doubles?.tOpt == nil) + XCTAssert(doubles?.tImp == 0.6565) + + /// Double Arrays + XCTAssert(doubles?.tArr.count == 3) + XCTAssert(doubles?.tArr[1] == 0.45) + XCTAssert(doubles?.tArrOpt == nil) + XCTAssert(doubles?.tArrImp != nil) + XCTAssert(doubles?.tArrImp[1] == 0) + + /// Double Dictionaries + XCTAssert(doubles?.tDic.count == 2) + XCTAssert(doubles?.tDic["key1"] == -1.0005) + XCTAssert(doubles?.tDic["key0"] == 67.6756) + XCTAssert(doubles?.tDicOpt != nil) + XCTAssert(doubles?.tDictImp["key1"] == -5.78) + } + + func testDecodingFloats() { + let floats = BasicTypes.read(from: Store(data: plistData["Float"] as! [String : AnyObject])) + + /// Floats + XCTAssert(floats != nil) + XCTAssert(floats?.t == -0.345) + XCTAssert(floats?.tOpt == nil) + XCTAssert(floats?.tImp == 0.78796) + + /// Float Arrays + XCTAssert(floats?.tArr.count == 3) + XCTAssert(floats?.tArr[1] == 0.54) + XCTAssert(floats?.tArrOpt == nil) + XCTAssert(floats?.tArrImp != nil) + XCTAssert(floats?.tArrImp[1] == -0.45) + + /// Float Dictionaries + XCTAssert(floats?.tDic.count == 2) + XCTAssert(floats?.tDic["key1"] == 0.45) + XCTAssert(floats?.tDic["key0"] == 65.0909) + XCTAssert(floats?.tDicOpt != nil) + XCTAssert(floats?.tDictImp["key1"] == -222.222) + } + + func testDecodingStrings() { + let strings = StringTypes.read(from: Store(data: plistData["String"] as! [String : AnyObject])) + + /// Strings + XCTAssert(strings != nil) + XCTAssert(strings?.t == "Hello") + XCTAssert(strings?.tOpt == nil) + XCTAssert(strings?.tImp == "Unwrapped") + + /// String Arrays + XCTAssert(strings?.tArr.count == 3) + XCTAssert(strings?.tArr[1] == "item1") + XCTAssert(strings?.tArrOpt == nil) + XCTAssert(strings?.tArrImp != nil) + XCTAssert(strings?.tArrImp[1] == "Ray") + + /// String Dictionaries + XCTAssert(strings?.tDic.count == 2) + XCTAssert(strings?.tDic["key1"] == "Dic_String_1") + XCTAssert(strings?.tDic["key0"] == "Dic_String_0") + XCTAssert(strings?.tDicOpt != nil) + XCTAssert(strings?.tDictImp["key1"] == "") + } + + func testDecodingAnyObjects() { + let objects = AnyObjectTypes.read(from: Store(data: plistData["Object"] as! [String : AnyObject])) + + /// AnyObjects + XCTAssert(objects != nil) + XCTAssert(objects?.t as? Int == 400) + XCTAssert(objects?.tOpt == nil) + XCTAssert(objects?.tImp as? Bool == true) + + /// AnyObject Arrays + XCTAssert(objects?.tArr.count == 3) + XCTAssert(objects?.tArr[1] as? Double == 20.6 ) + XCTAssert(objects?.tArrOpt == nil) + XCTAssert(objects?.tArrImp != nil) + XCTAssert(objects?.tArrImp[1] as? String == "Ray") + + /// AnyObject Dictionaries + XCTAssert(objects?.tDic.count == 2) + XCTAssert(objects?.tDic["key1"] as? Bool == true ) + XCTAssert(objects?.tDic["key0"] as? Int == 0) + XCTAssert(objects?.tDicOpt != nil) + XCTAssert(objects?.tDictImp["key1"] as? Date != nil) + } +} + +class DefaultTests: Test { + + func testDefaults() { + let test = TestDefaults() + + XCTAssert(test.defaultArray.count == 3 ) + XCTAssert(test.defaultString == "defaultString") + XCTAssertNotNil(test.defaultEmptyArray) + XCTAssert(test.defaultChild.name == "New Child") + XCTAssert(test.defaultChildren.count == 0) + } + +} + +class ModelWritingTests: Test { + + func testEcodingToAndFromJSON() { + let inUsers = UserTypes.read(from: Store(data: jsonData)) + if let inUsers = inUsers { + _ = inUsers.write(to: tempURLFor("temp.json"), format: .json) + } + let users = UserTypes(file: tempURLFor("temp.json"), format: .json) + XCTAssert(users != nil) + XCTAssert(users?.tArr.count == 3) + XCTAssert(users?.tImp.name == "John Doe") + XCTAssert(users?.tDicOpt?.count == 3) + XCTAssert(users?.tDicOpt?["item1"]?.email == "john@unit-testing.com") + XCTAssert(users?.tArrImp.count == 3) + } + + func testEcodingToAndFromPlist() { + let inUsers = UserTypes.read(from: Store(data: plistData["Users"] as! [String : AnyObject])) + if let inUsers = inUsers { + _ = inUsers.write(to: tempURLFor("temp.plist"), format: .plist) + } + let users = UserTypes(file: tempURLFor("temp.plist"), format: .plist) + XCTAssert(users != nil) + XCTAssert(users?.tArr.count == 3) + XCTAssert(users?.tImp.name == "John Doe") + XCTAssert(users?.tDicOpt?.count == 3) + XCTAssert(users?.tDicOpt?["item1"]?.email == "john@unit-testing.com") + XCTAssert(users?.tArrImp.count == 3) + } +} + +class EncodingTests: Test { + func testEncodingBools() { + let bools_in = BasicTypes.read(from: Store(data: plistData["Bool"] as! [String : AnyObject])) + var store: Store = Store() + bools_in!.write(to: &store) + let bools = BasicTypes.read(from: store) + + /// Bools + XCTAssert(bools != nil) + XCTAssert(bools?.t == true) + XCTAssert(bools?.tOpt == nil) + XCTAssert(bools?.tImp == false) + + /// Bool Arrays + XCTAssert(bools?.tArr.count == 3) + XCTAssert(bools?.tArr[1] == true) + XCTAssert(bools?.tArrOpt == nil) + XCTAssert(bools?.tArrImp != nil) + XCTAssert(bools?.tArrImp[1] == true) + + /// Bool Dictionaries + XCTAssert(bools?.tDic.count == 2) + XCTAssert(bools?.tDic["key1"] == true) + XCTAssert(bools?.tDic["key0"] == false) + XCTAssert(bools?.tDicOpt != nil) + XCTAssert(bools?.tDictImp["key0"] == true) + } + + func testEncodingInts() { + let ints_in = BasicTypes.read(from: Store(data: plistData["Int"] as! [String : AnyObject])) + var store : Store = Store() + ints_in!.write(to: &store) + let ints = BasicTypes(with: store) + + /// Ints + XCTAssert(ints != nil) + XCTAssert(ints?.t == 10) + XCTAssert(ints?.tOpt == nil) + XCTAssert(ints?.tImp == 40) + + /// Int Arrays + XCTAssert(ints?.tArr.count == 3) + XCTAssert(ints?.tArr[1] == 10) + XCTAssert(ints?.tArrOpt == nil) + XCTAssert(ints?.tArrImp != nil) + XCTAssert(ints?.tArrImp[1] == 64) + + /// Int Dictionaries + XCTAssert(ints?.tDic.count == 2) + XCTAssert(ints?.tDic["key1"] == 123) + XCTAssert(ints?.tDic["key0"] == 67) + XCTAssert(ints?.tDicOpt != nil) + XCTAssert(ints?.tDictImp["key1"] == 79) + } + + func testEncodingDoubles() { + let doubles_in = BasicTypes.read(from: Store(data: plistData["Double"] as! [String : AnyObject])) + var store: Store = Store() + doubles_in!.write(to: &store) + let doubles = BasicTypes(with: store) + + /// Doubles + XCTAssert(doubles != nil) + XCTAssert(doubles?.t == -0.456) + XCTAssert(doubles?.tOpt == nil) + XCTAssert(doubles?.tImp == 0.6565) + + /// Double Arrays + XCTAssert(doubles?.tArr.count == 3) + XCTAssert(doubles?.tArr[1] == 0.45) + XCTAssert(doubles?.tArrOpt == nil) + XCTAssert(doubles?.tArrImp != nil) + XCTAssert(doubles?.tArrImp[1] == 0) + + /// Double Dictionaries + XCTAssert(doubles?.tDic.count == 2) + XCTAssert(doubles?.tDic["key1"] == -1.0005) + XCTAssert(doubles?.tDic["key0"] == 67.6756) + XCTAssert(doubles?.tDicOpt != nil) + XCTAssert(doubles?.tDictImp["key1"] == -5.78) + } + + func testEncodingFloats() { + let floats_in = BasicTypes.read(from: Store(data: plistData["Float"] as! [String : AnyObject])) + var store: Store = Store() + floats_in!.write(to: &store) + let floats = BasicTypes(with: store) + + /// Floats + XCTAssert(floats != nil) + XCTAssert(floats?.t == -0.345) + XCTAssert(floats?.tOpt == nil) + XCTAssert(floats?.tImp == 0.78796) + + /// Float Arrays + XCTAssert(floats?.tArr.count == 3) + XCTAssert(floats?.tArr[1] == 0.54) + XCTAssert(floats?.tArrOpt == nil) + XCTAssert(floats?.tArrImp != nil) + XCTAssert(floats?.tArrImp[1] == -0.45) + + /// Float Dictionaries + XCTAssert(floats?.tDic.count == 2) + XCTAssert(floats?.tDic["key1"] == 0.45) + XCTAssert(floats?.tDic["key0"] == 65.0909) + XCTAssert(floats?.tDicOpt != nil) + XCTAssert(floats?.tDictImp["key1"] == -222.222) + } + + func testEncodingStringTypes() { + let strings_in = StringTypes.read(from: Store(data: plistData["String"] as! [String : AnyObject])) + var store: Store = Store() + strings_in!.write(to: &store) + let strings = StringTypes(with: store) + + /// Strings + XCTAssert(strings != nil) + XCTAssert(strings?.t == "Hello") + XCTAssert(strings?.tOpt == nil) + XCTAssert(strings?.tImp == "Unwrapped") + + /// String Arrays + XCTAssert(strings?.tArr.count == 3) + XCTAssert(strings?.tArr[1] == "item1") + XCTAssert(strings?.tArrOpt == nil) + XCTAssert(strings?.tArrImp != nil) + XCTAssert(strings?.tArrImp[1] == "Ray") + + /// String Dictionaries + XCTAssert(strings?.tDic.count == 2) + XCTAssert(strings?.tDic["key1"] == "Dic_String_1") + XCTAssert(strings?.tDic["key0"] == "Dic_String_0") + XCTAssert(strings?.tDicOpt != nil) + XCTAssert(strings?.tDictImp["key1"] == "") + } + + func testEncodingAnyObjectTypes() { + let objects_in = AnyObjectTypes.read(from: Store(data: plistData["Object"] as! [String : AnyObject])) + var store: Store = Store() + objects_in?.write(to: &store) + let objects = AnyObjectTypes(with: store) + + /// AnyObjects + XCTAssert(objects != nil) + XCTAssert(objects?.t as? Int == 400) + XCTAssert(objects?.tOpt == nil) + XCTAssert(objects?.tImp as? Bool == true) + + /// AnyObject Arrays + XCTAssert(objects?.tArr.count == 3) + XCTAssert(objects?.tArr[1] as? Double == 20.6 ) + XCTAssert(objects?.tArrOpt == nil) + XCTAssert(objects?.tArrImp != nil) + XCTAssert(objects?.tArrImp[1] as? String == "Ray") + + /// AnyObject Dictionaries + XCTAssert(objects?.tDic.count == 2) + XCTAssert(objects?.tDic["key1"] as? Bool == true ) + XCTAssert(objects?.tDic["key0"] as? Int == 0) + XCTAssert(objects?.tDicOpt != nil) + XCTAssert(objects?.tDictImp["key1"] as? Date != nil) + } +} + +class EnumTests: Test { + + func testRawEnum() { + let test_out = TestRawEnum.ready + _ = test_out.write(to: tempURLFor("test_raw_enum.plist"), format: .plist) + let sut = TestRawEnum(file: tempURLFor("test_raw_enum.plist"), format: .plist) + XCTAssert(sut != nil) + XCTAssert(sut == TestRawEnum.ready) + } + + func testRegEnum() { + let test_out = TestRegEnum.cold + _ = test_out.write(to: tempURLFor("test_reg_enum.plist"), format: .plist) + let sut = TestRegEnum(file: tempURLFor("test_reg_enum.plist"), format: .plist) + XCTAssert(sut != nil) + XCTAssert(sut == TestRegEnum.cold) + } + + func testAssociatedEnum() { + + func createBinary() -> Data? { + if let path = Bundle(for: Test.self).pathForResource("Data", ofType: "plist") { + return (try? Data(contentsOf: URL(fileURLWithPath: path))) + } + return nil + } + + func performTestFor(_ testEnum: TestAssociatedEnum, message: String) { + _ = testEnum.write(to: tempURLFor("test_associated_enum.plist"), format: .binary) + let sut = TestAssociatedEnum(file: tempURLFor("test_associated_enum.plist"), format: .binary) + XCTAssert(sut != nil) + if let sut = sut { + switch sut { + case let .stringType(s): + XCTAssert(s == "Hello World", message) + case let .intType(i): + XCTAssert(i == 10, message) + case let .floatType(f): + XCTAssert(f == 0.1235, message) + case let .doubleType(d): + XCTAssert(d == -12.34, message) + case let .booleanType(b): + XCTAssert(b == true, message) + case let .binaryType(b): + XCTAssertNotNil(b, message) + case let .decimalType(d): + XCTAssert(d == NSDecimalNumber(value:0.8976), message) + case let .dateType(d): + XCTAssert(d == Date(timeIntervalSince1970: 10000), message) + case let .transformableColorType(t): + XCTAssert(t == UIColor.blue(), message) + default: + XCTFail() + } + } + + } + + performTestFor(TestAssociatedEnum.stringType("Hello World"), message: "StringType should be Hello World") + performTestFor(TestAssociatedEnum.intType(10), message: "IntType should be 10") + performTestFor(TestAssociatedEnum.floatType(0.1235), message: "FloatType should be .1235") + performTestFor(TestAssociatedEnum.doubleType(-12.34), message: "DoubleType should be -12.34") + performTestFor(TestAssociatedEnum.booleanType(true), message: "BooleanType should be true") + performTestFor(TestAssociatedEnum.binaryType(createBinary()!), message: "Binary should not be nil") + performTestFor(TestAssociatedEnum.decimalType(NSDecimalNumber(value: 0.8976)), message: "DecimalType should equal 0.8976") + performTestFor(TestAssociatedEnum.dateType(Date(timeIntervalSince1970: 10000)), message: "DateType should equal 10000 since 1970") + performTestFor(TestAssociatedEnum.transformableColorType(UIColor.blue()), message: "Color should be blue") + } + + func testAssociatedDecodeableToManyEnum() { + let employee = Employee(name: "Joe", title: "Manager") + let employees = [employee, employee, employee] + let test_out = TestAssociatedEnum.decodableToManyType(employees) + _ = test_out.write(to: tempURLFor("test_associated_tomany_enum.plist"), format: .plist) + let sut = TestAssociatedEnum(file: tempURLFor("test_associated_tomany_enum.plist"), format: .plist) + XCTAssert(sut != nil) + + switch sut! { + case let .decodableToManyType(e): + XCTAssert(e.count == 3) + XCTAssert(e[1].name == "Joe") + default: + XCTFail() + } + } + + func testAssociatedDecodeableToOneEnum() { + let employee = Employee(name: "Joe", title: "Manager") + let test_out = TestAssociatedEnum.decodableToOneType(employee) + _ = test_out.write(to: tempURLFor("test_associated_toone_enum.plist"), format: .plist) + let sut = TestAssociatedEnum(file: tempURLFor("test_associated_toone_enum.plist"), format: .plist) + XCTAssert(sut != nil) + + switch sut! { + case let .decodableToOneType(e): + XCTAssert(e.name == "Joe") + default: + XCTFail() + } + } + + func testAssociatedOptionalEnum() { + + func createBinary() -> Data? { + if let path = Bundle(for: Test.self).pathForResource("Data", ofType: "plist") { + return (try? Data(contentsOf: URL(fileURLWithPath: path))) + } + return nil + } + + func performTestFor(_ testEnum: TestAssociatedOptionalEnum, message: String) { + _ = testEnum.write(to: tempURLFor("test_associated_optional_enum.plist"), format: .binary) + let sut = TestAssociatedOptionalEnum(file: tempURLFor("test_associated_optional_enum.plist"), format: .binary) + XCTAssert(sut != nil, "system under test is nil") + if let sut = sut { + switch sut { + case let .stringType(s): + XCTAssert(s == "Hello World", message) + case let .intType(i): + XCTAssert(i == 10, message) + case let .floatType(f): + XCTAssert(f == 0.1235, message) + case let .doubleType(d): + XCTAssert(d == -12.34, message) + case let .booleanType(b): + XCTAssert(b == true, message) + case let .binaryType(b): + XCTAssertNotNil(b, message) + case let .decimalType(d): + XCTAssert(d == NSDecimalNumber(value:0.8976), message) + case let .dateType(d): + XCTAssert(d == Date(timeIntervalSince1970: 10000), message) + case let .transformableColorType(t): + XCTAssert(t == UIColor.blue(), message) + default: + XCTFail("no case found") + } + } + } + + performTestFor(TestAssociatedOptionalEnum.stringType("Hello World"), message: "StringType should be Hello World") + performTestFor(TestAssociatedOptionalEnum.intType(10), message: "IntType should be 10") + performTestFor(TestAssociatedOptionalEnum.floatType(0.1235), message: "FloatType should be .1235") + performTestFor(TestAssociatedOptionalEnum.doubleType(-12.34), message: "DoubleType should be -12.34") + performTestFor(TestAssociatedOptionalEnum.booleanType(true), message: "BooleanType should be true") + performTestFor(TestAssociatedOptionalEnum.binaryType(createBinary()!), message: "Binary should not be nil") + performTestFor(TestAssociatedOptionalEnum.decimalType(NSDecimalNumber(value: 0.8976)), message: "DecimalType should equal 0.8976") + performTestFor(TestAssociatedOptionalEnum.dateType(Date(timeIntervalSince1970: 10000)), message: "DateType should equal 10000 since 1970") + performTestFor(TestAssociatedOptionalEnum.transformableColorType(UIColor.blue()), message: "Color should be blue") + } + + func testAssociatedDecodeableOptionalToManyEnum() { + let employee = Employee(name: "Joe", title: "Manager") + let employees = [employee, employee, employee] + let test_out = TestAssociatedOptionalEnum.decodableToManyType(employees) + _ = test_out.write(to: tempURLFor("test_associated_optional_tomany_enum.plist"), format: .plist) + let sut = TestAssociatedOptionalEnum(file: tempURLFor("test_associated_optional_tomany_enum.plist"), format: .plist) + XCTAssert(sut != nil) + + switch sut! { + case let .decodableToManyType(e): + XCTAssert(e?.count == 3) + XCTAssert(e?[1].name == "Joe") + default: + XCTFail() + } + } + + func testAssociatedDecodeableOptionalToOneEnum() { + let employee = Employee(name: "Joe", title: "Manager") + let test_out = TestAssociatedOptionalEnum.decodableToOneType(employee) + _ = test_out.write(to: tempURLFor("test_associated_optional_toone_enum.plist"), format: .plist) + let sut = TestAssociatedOptionalEnum(file: tempURLFor("test_associated_optional_toone_enum.plist"), format: .plist) + XCTAssert(sut != nil) + + switch sut! { + case let .decodableToOneType(e): + XCTAssert(e?.name == "Joe") + default: + XCTFail() + } + } +} + +class RecursiveTests: Test { + + func testEncodingAndDecodingRecursiveModel() { + var player = Player(id: 100, name: "player", age: 23) + var players = [Player]() + var innerPlayers = [Player]() + for index in 1...10 { + players.append(Player(id:index, name: "player\(index)", age:23 )) + } + for index in 1...5 { + innerPlayers.append(Player(id:index, name: "player\(index)", age:23 )) + } + + player.teamates = players + player.teamates[3].fillins = innerPlayers + + _ = player.write(to: tempURLFor("player.plist"), format: .plist) + let resultPlayer = Player(file: tempURLFor("player.plist"), format: .plist) + + XCTAssert(resultPlayer != nil) + XCTAssert(resultPlayer?.teamates.count == 10) + XCTAssert(resultPlayer?.teamates[1].name != nil) + XCTAssert(resultPlayer?.teamates[3].fillins?.count == 5) + } +} + +class RelationshipTests: Test { + + func makeChildren() -> [TestChild] { + var children = [TestChild]() + for index in 0...9 { + var grandChildren = [Grandchild]() + + for index in 0...4 { + let grandChild = Grandchild(age: index, name: "GrandChild\(index)", gender: Gender.female) + grandChildren.append(grandChild) + } + let child = TestChild(age: index, name: "Child\(index)", myChildren: grandChildren, gender: Gender.male) + children.append(child) + } + return children + } + + func makeGrandChildren(_ children: [TestChild]) -> [Grandchild] { + var grandChildren = [Grandchild]() + + for child in children { + if let grandkids = child.myChildren { + grandChildren.append(contentsOf: grandkids) + } + } + return grandChildren + } + + func testCodingModelWithOneToMany() { + let children = makeChildren() + let grandChildren = makeGrandChildren(children) + let sampleData = TestRelationships(myChildren: children, myGrandChildren: grandChildren, myOneChild: TestChild(age: 22, name: "Mark", myChildren: nil, gender: Gender.male )) + _ = sampleData.write(to: tempURLFor("relationship.json"), format: .json) + + let testData = TestRelationships(file: tempURLFor("relationship.json"), format: .json) + + XCTAssert(testData != nil) + XCTAssert(testData?.myChildren?.count == sampleData.myChildren?.count) + XCTAssert(testData?.myGrandChildren?.count == sampleData.myGrandChildren?.count) + XCTAssert(testData?.myGrandChildren?[0].name == sampleData.myGrandChildren?[0].name) + XCTAssert(testData?.myOneChild?.name == sampleData.myOneChild?.name) + XCTAssert(testData?.myGrandChildren?[0].gender == sampleData.myGrandChildren?[0].gender) + XCTAssert(testData?.myChildren?[3].age == sampleData.myGrandChildren?[3].age) + } + + + func testCodingModelWithDictionaryComposition() { + var testComposition = TestDictionaryComposition(employees: [String : Employee]()) + let employee1 = Employee(name: "Jane", title: "Manager") + let employee2 = Employee(name: "John", title: nil) + testComposition.employees["Jane"] = employee1 + testComposition.employees["John"] = employee2 + _ = testComposition.write(to: tempURLFor("test_composition.plist"), format: .plist) + + let inTestComposition = TestDictionaryComposition(file: tempURLFor("test_composition.plist"), format: .plist) + XCTAssert(inTestComposition != nil) + XCTAssert(inTestComposition?.employees["Jane"]?.title == "Manager") + } +} + +class TemplateTests: Test { + + func testEncodingAndDecodingAutoGeneratedModel() { + var company = Company(name: "State llc",yearFounded: 2015, phoneNumber: "888-888-8888", employees: [Employee]()) + let employee = Employee(name:"Joe", title: "CEO") + company.employees?.append(employee) + _ = company.write(to: tempURLFor("company.plist"), format: .plist) + let testCompany = Company(file: tempURLFor("company.plist"), format: .plist) + + XCTAssert(testCompany != nil) + XCTAssert(testCompany?.name == "State llc") + XCTAssert(testCompany?.phoneNumber == "888-888-8888") + XCTAssert(testCompany?.yearFounded == 2015) + XCTAssert(testCompany?.employees?.count == 1) + XCTAssert(testCompany?.employees?[0].name == "Joe") + } + + func testTypes() { + let test_out = TestTypes() + _ = test_out.write(to: tempURLFor("test_types.plist"), format: .binary) + let sut = TestTypes(file: tempURLFor("test_types.plist"), format: .binary) + XCTAssert(sut != nil) + XCTAssert(sut?.myBinary != nil) + XCTAssert(sut?.myDate != nil) + XCTAssert(sut?.myFloat == 4.567) + XCTAssert(sut?.myDouble == -0.02) + XCTAssert(sut?.myInt == 5) + XCTAssert(sut?.myString == "Hello World") + XCTAssert(sut?.myDecimal == 3.14) + } + + func testImmutableTypes() { + let test_out = TestImmutableTypes() + _ = test_out.write(to: tempURLFor("test_immutable_types.plist"), format: .binary) + let sut = TestImmutableTypes(file: tempURLFor("test_immutable_types.plist"), format: .binary) + XCTAssert(sut != nil) + XCTAssert(sut?.myBinary != nil) + XCTAssert(sut?.myDate != nil) + XCTAssert(sut?.myFloat == 4.567) + XCTAssert(sut?.myDouble == -0.02) + XCTAssert(sut?.myInt == 5) + XCTAssert(sut?.myString == "Hello World") + XCTAssert(sut?.myDecimal == 3.14) + } + + func testOptionalTypes() { + let test_out = TestOptionalTypes.CreateTestInstance() + _ = test_out.write(to: tempURLFor("test_optional_types.plist"), format: .binary) + let sut = TestOptionalTypes(file: tempURLFor("test_optional_types.plist"), format: .binary) + XCTAssert(sut != nil) + XCTAssert(sut?.myBinary != nil) + XCTAssert(sut?.myDate != nil) + XCTAssert(sut?.myFloat == 4.567) + XCTAssert(sut?.myDouble == -0.02) + XCTAssert(sut?.myInt == 5) + XCTAssert(sut?.myString == "Hello World") + XCTAssert(sut?.myDecimal == 3.14) + } + + func testImmutableOptionalTypes() { + let test_out = TestImmutableOptionalTypes() + _ = test_out.write(to: tempURLFor("test_immutable_optional_types.plist"), format: .binary) + let sut = TestImmutableOptionalTypes(file: tempURLFor("test_immutable_optional_types.plist"), format: .binary) + XCTAssert(sut != nil) + XCTAssert(sut?.myBinary != nil) + XCTAssert(sut?.myDate != nil) + XCTAssert(sut?.myFloat == 4.567) + XCTAssert(sut?.myDouble == -0.02) + XCTAssert(sut?.myInt == 5) + XCTAssert(sut?.myString == "Hello World") + XCTAssert(sut?.myDecimal == 3.14) + } + + func testCollections() { + var test_out = TestCollections() + test_out.arrayOfStrings = ["string1", "string2", "string3"] + test_out.dicOfInts["int1"] = 1 + test_out.dicOfInts["int2"] = 2 + test_out.dicOfInts["int3"] = 3 + test_out.setOfStrings = ["do", "ray", "me"] + _ = test_out.write(to: tempURLFor("test_collections.plist"), format: .binary) + let sut = TestCollections(file: tempURLFor("test_collections.plist"), format: .binary) + + XCTAssert(sut != nil) + XCTAssert(sut?.arrayOfStrings.count == 3) + XCTAssert(sut?.dicOfInts.count == 3) + XCTAssert(sut?.setOfStrings.count == 3) + } + + func testRawEnum() { + let test_out = TestRawEnum.ready + _ = test_out.write(to: tempURLFor("test_enum.plist"), format: .plist) + let sut = TestRawEnum(file: tempURLFor("test_enum.plist"), format: .plist) + XCTAssert(sut != nil) + XCTAssert(sut == TestRawEnum.ready) + } + + func testTransformable() { + let test_out = TestTransformable( myTransformable: URL(string: "http://facebook.com")!, myTransformableImmutable: URL(string: "http://yahoo.com")!, myTransformableImmutableOptional: nil, myTransformableOptional:URL(string: "http://twitter.com")!) + _ = test_out.write(to: tempURLFor("test_transformable.plist"), format: .binary) + let sut = TestTransformable(file: tempURLFor("test_transformable.plist"), format: .binary) + XCTAssert(sut != nil) + XCTAssert(sut?.myTransformable == test_out.myTransformable) + XCTAssert(sut?.myTransformableImmutable == test_out.myTransformableImmutable) + XCTAssert(sut?.myTransformableImmutableOptional == test_out.myTransformableImmutableOptional) + XCTAssert(sut?.myTransformableOptional == test_out.myTransformableOptional) + } + + func testOverrideType() { + let test_out: TestOverrideType? = TestOverrideType(myURL: URL(string: "http://simpletouchsoftware.com"), myArrayOfString: ["string1", "string2"]) + XCTAssert(test_out != nil) + } +} + +class ProtocolTests : Test { + + func testCodingProtocols() { + let testEmployee = Employee(name: "Test Employee", title: "Manager") + let testGrandChild = Grandchild(age: 10, name: "Test Grandchild", gender: .male) + let testChild = TestChild(age: 10, name: "Test Child", myChildren: [testGrandChild, testGrandChild], gender: .male) + let testConformer1 = TestProtocolConformer(age: 19, ss_number: "12345", isReady: true, employee: testEmployee, children: [testChild, testChild]) + let testConformer2 = TestProtocolConformer2(name: "Test Conformer", ss_number: "1111111") + let testProtocolContainer = TestProtocolContainter(testProtocol: testConformer1, testProtocols: [testConformer1, testConformer2], testProtocolsDict: ["Conformer 1" : testConformer1, "Conformer 2" : testConformer2]) + + _ = testProtocolContainer.write(to: tempURLFor("testProtocol.plist"), format: .plist) + print(tempPathFor("testProtocol.plist")) + let inTestProtocolContainer = TestProtocolContainter(file: tempURLFor("testProtocol.plist"), format: .plist) + + XCTAssertNotNil(inTestProtocolContainer) + } +} + +class ModelTests : Test { + + func testMakeDataInitWithData() { + let testedSource = Store(data: plistData["Users"] as! [String : AnyObject]) + let testedStore = testedSource.store(forKey: "t") + let testedUser = User.read(from: testedStore!) + let testData = testedUser?.makeData(format: .json) + XCTAssertNotNil(testData) + let testUserIn = User(content: testData!, format: .json) + XCTAssert(testUserIn?.name == testedUser?.name) + } + + func testMakeStringInitWithString() { + let testedSource = Store(data: plistData["Users"] as! [String : AnyObject]) + let testedStore = testedSource.store(forKey: "t") + let testedUser = User.read(from: testedStore!) + let testString = testedUser?.makeString(format: .json) + XCTAssertNotNil(testString) + let testUserIn = User(content: testString!, format: .json) + XCTAssert(testUserIn?.name == testedUser?.name) + } + + func testWriteToFileInitModelArray() { + let arraySource : [String : AnyObject] = plistData["Users"] as! [String : AnyObject] + let testedStore = Store(data: arraySource) + let users : [User]? = testedStore.value(forKey: "t_arr") + XCTAssertNotNil(users) + _ = users?.write(to: tempURLFor("testModelArray.json"), format: .json) + let usersIn : [User]? = Array(file: tempURLFor("testModelArray.json"), format: .json) + XCTAssertNotNil(usersIn) + XCTAssert(usersIn?.count == users?.count) + } + + func testMakeFromAndInitWithStringArray() { + let arraySource : [String : AnyObject] = plistData["Users"] as! [String : AnyObject] + let testedStore = Store(data: arraySource) + let users : [User]? = testedStore.value(forKey: "t_arr") + let stringUserArray = users?.makeString(format: .json) + let usersIn : [User]? = Array(content: stringUserArray!, format: .json) + XCTAssertNotNil(usersIn) + XCTAssert(usersIn?.count == users?.count) + } + + func testMakeFromAndInitWithDataArray() { + let arraySource : [String : AnyObject] = plistData["Users"] as! [String : AnyObject] + let testedStore = Store(data: arraySource) + let users : [User]? = testedStore.value(forKey: "t_arr") + let stringUserArray = users?.makeData(format: .json) + let usersIn : [User]? = Array(content: stringUserArray!, format: .json) + XCTAssertNotNil(usersIn) + XCTAssert(usersIn?.count == users?.count) + } +} diff --git a/Tests/Models/BasicModels.swift b/Tests/Models/BasicModels.swift index 4f40bc9..b13ba37 100644 --- a/Tests/Models/BasicModels.swift +++ b/Tests/Models/BasicModels.swift @@ -21,23 +21,27 @@ struct BasicTypes { } -extension BasicTypes : Decodable { +extension BasicTypes : Model { - static func decode(decoder: Decoder) -> BasicTypes? { - return self.init(decoder: decoder) + static func read(from store: Store) -> BasicTypes? { + return self.init(with: store) } - init?(decoder: Decoder) { - guard let t: T = decoder.decode("t"), - tArr : [T] = decoder.decode("t_arr"), - tDic : [String : T] = decoder.decode("t_dic") else { return nil } + init?(with store: Store) { + guard + let t: T = store.value(forKey: "t"), + let tArr : [T] = store.value(forKey: "t_arr"), + let tDic : [String : T] = store.value(forKey: "t_dic") + else { + return nil + } - let tOpt: T? = decoder.decode("t_opt") - let tImp : T! = decoder.decode("t_imp") - let tArrOpt : [T]? = decoder.decode("t_arr_opt") - let tArrImp : [T]! = decoder.decode("t_arr_imp") - let tDicOpt : [String : T]? = decoder.decode("t_dic_opt") - let tDictImp : [String : T]! = decoder.decode("t_dic_imp") + let tOpt: T? = store.value(forKey: "t_opt") + let tImp : T! = store.value(forKey: "t_imp") + let tArrOpt : [T]? = store.value(forKey: "t_arr_opt") + let tArrImp : [T]! = store.value(forKey: "t_arr_imp") + let tDicOpt : [String : T]? = store.value(forKey: "t_dic_opt") + let tDictImp : [String : T]! = store.value(forKey: "t_dic_imp") self.t = t self.tOpt = tOpt @@ -49,20 +53,17 @@ extension BasicTypes : Decodable { self.tDicOpt = tDicOpt self.tDictImp = tDictImp } -} - -extension BasicTypes : Encodable { - func encode(encoder: Encoder){ - encoder.encode(t, "t") - encoder.encode(tOpt, "t_opt") - encoder.encode(tImp, "t_imp") - encoder.encode(tArr, "t_arr") - encoder.encode(tArrOpt, "t_arr_opt") - encoder.encode(tArrImp, "t_arr_imp") - encoder.encode(tDic, "t_dic") - encoder.encode(tDicOpt, "t_dic_opt") - encoder.encode(tDictImp, "t_dic_imp") + func write(to store: inout Store){ + store.set(t, forKey: "t") + store.set(tOpt, forKey: "t_opt") + store.set(tImp, forKey: "t_imp") + store.set(tArr, forKey: "t_arr") + store.set(tArrOpt, forKey: "t_arr_opt") + store.set(tArrImp, forKey: "t_arr_imp") + store.set(tDic, forKey: "t_dic") + store.set(tDicOpt, forKey: "t_dic_opt") + store.set(tDictImp, forKey: "t_dic_imp") } } @@ -87,23 +88,27 @@ struct StringTypes { } -extension StringTypes : Decodable { +extension StringTypes : Model { - static func decode(decoder: Decoder) -> StringTypes? { - return self.init(decoder: decoder) + static func read(from store: Store) -> StringTypes? { + return self.init(with: store) } - init?(decoder: Decoder) { - guard let t: String = decoder.decode("t"), - tArr : [String] = decoder.decode("t_arr"), - tDic : [String : String] = decoder.decode("t_dic") else { return nil } + init?(with store: Store) { + guard + let t: String = store.value(forKey: "t"), + let tArr : [String] = store.value(forKey: "t_arr"), + let tDic : [String : String] = store.value(forKey: "t_dic") + else { + return nil + } - let tOpt: String? = decoder.decode("t_opt") - let tImp : String! = decoder.decode("t_imp") - let tArrOpt : [String]? = decoder.decode("t_arr_opt") - let tArrImp : [String]! = decoder.decode("t_arr_imp") - let tDicOpt : [String : String]? = decoder.decode("t_dic_opt") - let tDictImp : [String : String]! = decoder.decode("t_dic_imp") + let tOpt: String? = store.value(forKey: "t_opt") + let tImp : String! = store.value(forKey: "t_imp") + let tArrOpt : [String]? = store.value(forKey: "t_arr_opt") + let tArrImp : [String]! = store.value(forKey: "t_arr_imp") + let tDicOpt : [String : String]? = store.value(forKey: "t_dic_opt") + let tDictImp : [String : String]! = store.value(forKey: "t_dic_imp") self.t = t self.tOpt = tOpt @@ -115,20 +120,17 @@ extension StringTypes : Decodable { self.tDicOpt = tDicOpt self.tDictImp = tDictImp } -} - -extension StringTypes : Encodable { - func encode(encoder: Encoder){ - encoder.encode(t, "t") - encoder.encode(tOpt, "t_opt") - encoder.encode(tImp, "t_imp") - encoder.encode(tArr, "t_arr") - encoder.encode(tArrOpt, "t_arr_opt") - encoder.encode(tArrImp, "t_arr_imp") - encoder.encode(tDic, "t_dic") - encoder.encode(tDicOpt, "t_dic_opt") - encoder.encode(tDictImp, "t_dic_imp") + func write(to store: inout Store){ + store.set(t, forKey: "t") + store.set(tOpt, forKey: "t_opt") + store.set(tImp, forKey: "t_imp") + store.set(tArr, forKey: "t_arr") + store.set(tArrOpt, forKey: "t_arr_opt") + store.set(tArrImp, forKey: "t_arr_imp") + store.set(tDic, forKey: "t_dic") + store.set(tDicOpt, forKey: "t_dic_opt") + store.set(tDictImp, forKey: "t_dic_imp") } } @@ -153,23 +155,28 @@ struct AnyObjectTypes { } -extension AnyObjectTypes : Decodable { +extension AnyObjectTypes : Model { - static func decode(decoder: Decoder) -> AnyObjectTypes? { - return self.init(decoder: decoder) + static func read(from store: Store) -> AnyObjectTypes? { + return self.init(with: store) } - init?(decoder: Decoder) { - guard let t: AnyObject = decoder.decode("t"), - tArr : [AnyObject] = decoder.decode("t_arr"), - tDic : [String : AnyObject] = decoder.decode("t_dic") else { return nil } + init?(with store: Store) { + + guard + let t: AnyObject = store.object(forKey: "t"), + let tArr : [AnyObject] = store.array(forKey: "t_arr"), + let tDic : [String : AnyObject] = store.dictionary(forKey: "t_dic") + else { + return nil + } - let tOpt: AnyObject? = decoder.decode("t_opt") - let tImp : AnyObject! = decoder.decode("t_imp") - let tArrOpt : [AnyObject]? = decoder.decode("t_arr_opt") - let tArrImp : [AnyObject]! = decoder.decode("t_arr_imp") - let tDicOpt : [String : AnyObject]? = decoder.decode("t_dic_opt") - let tDictImp : [String : AnyObject]! = decoder.decode("t_dic_imp") + let tOpt: AnyObject? = store.object(forKey: "t_opt") + let tImp : AnyObject! = store.object(forKey: "t_imp") + let tArrOpt : [AnyObject]? = store.array(forKey: "t_arr_opt") + let tArrImp : [AnyObject]! = store.array(forKey: "t_arr_imp") + let tDicOpt : [String : AnyObject]? = store.dictionary(forKey: "t_dic_opt") + let tDictImp : [String : AnyObject]! = store.dictionary(forKey: "t_dic_imp") self.t = t self.tOpt = tOpt @@ -181,19 +188,16 @@ extension AnyObjectTypes : Decodable { self.tDicOpt = tDicOpt self.tDictImp = tDictImp } -} - -extension AnyObjectTypes : Encodable { - func encode(encoder: Encoder){ - encoder.encode(t, "t") - encoder.encode(tOpt, "t_opt") - encoder.encode(tImp, "t_imp") - encoder.encode(tArr, "t_arr") - encoder.encode(tArrOpt, "t_arr_opt") - encoder.encode(tArrImp, "t_arr_imp") - encoder.encode(tDic, "t_dic") - encoder.encode(tDicOpt,"t_dic_opt") - encoder.encode(tDictImp, "t_dic_imp") + func write(to store: inout Store){ + store.set(t, forKey: "t") + store.set(tOpt, forKey: "t_opt") + store.set(tImp, forKey: "t_imp") + store.set(tArr, forKey: "t_arr") + store.set(tArrOpt, forKey: "t_arr_opt") + store.set(tArrImp, forKey: "t_arr_imp") + store.set(tDic, forKey: "t_dic") + store.set(tDicOpt,forKey: "t_dic_opt") + store.set(tDictImp, forKey: "t_dic_imp") } } diff --git a/Tests/Models/ObjectModels.swift b/Tests/Models/ObjectModels.swift index 4573197..6582ed9 100644 --- a/Tests/Models/ObjectModels.swift +++ b/Tests/Models/ObjectModels.swift @@ -20,23 +20,23 @@ struct UserTypes: Model { let tDictImp: [String : User]! } -extension UserTypes : Decodable { +extension UserTypes { - static func decode(decoder: Decoder) -> UserTypes? { - return self.init(decoder: decoder) + static func read(from store: Store) -> UserTypes? { + return self.init(with: store) } - init?(decoder: Decoder) { + init?(with store: Store) { - guard let t : User = decoder.decode("t") else { return nil } - guard let tArr : [User] = decoder.decode("t_arr") else { return nil } - guard let tDic : [String : User] = decoder.decode("t_dic") else { return nil } - let tOpt : User? = decoder.decode("t_opt") - let tImp : User! = decoder.decode("t_imp") - let tArrOpt : [User]? = decoder.decode("t_arr_opt") - let tArrImp : [User]! = decoder.decode("t_arr_imp") - let tDicOpt : [String : User]? = decoder.decode("t_dic_opt") - let tDictImp : [String : User]! = decoder.decode("t_dic_imp") + guard let t : User = store.value(forKey: "t") else { return nil } + guard let tArr : [User] = store.value(forKey: "t_arr") else { return nil } + guard let tDic : [String : User] = store.value(forKey: "t_dic") else { return nil } + let tOpt : User? = store.value(forKey: "t_opt") + let tImp : User! = store.value(forKey: "t_imp") + let tArrOpt : [User]? = store.value(forKey: "t_arr_opt") + let tArrImp : [User]! = store.value(forKey: "t_arr_imp") + let tDicOpt : [String : User]? = store.value(forKey: "t_dic_opt") + let tDictImp : [String : User]! = store.value(forKey: "t_dic_imp") self.t = t self.tOpt = tOpt @@ -48,20 +48,17 @@ extension UserTypes : Decodable { self.tDicOpt = tDicOpt self.tDictImp = tDictImp } -} - -extension UserTypes : Encodable { - func encode(encoder: Encoder){ - encoder.encode(t, "t") - encoder.encode(tOpt, "t_opt") - encoder.encode(tImp, "t_imp") - encoder.encode(tArr, "t_arr") - encoder.encode(tArrOpt, "t_arr_opt") - encoder.encode(tArrImp, "t_arr_imp") - encoder.encode(tDic, "t_dic") - encoder.encode(tDicOpt, "t_dic_opt") - encoder.encode(tDictImp, "t_dic_imp") + func write(to store: inout Store){ + store.set(t, forKey: "t") + store.set(tOpt, forKey: "t_opt") + store.set(tImp, forKey: "t_imp") + store.set(tArr, forKey: "t_arr") + store.set(tArrOpt, forKey: "t_arr_opt") + store.set(tArrImp, forKey: "t_arr_imp") + store.set(tDic, forKey: "t_dic") + store.set(tDicOpt, forKey: "t_dic_opt") + store.set(tDictImp, forKey: "t_dic_imp") } } @@ -79,26 +76,25 @@ struct User { let email: String? } -extension User: Decodable, Encodable{ +extension User: Model { - - static func decode(decoder: Decoder) -> User? { - return self.init(decoder: decoder) + static func read(from store: Store) -> User? { + return self.init(with: store) } - init? (decoder: Decoder) { - guard let id : Int = decoder.decode("id") else { return nil } - guard let name : String = decoder.decode("name") else { return nil } - let email : String? = decoder.decode("email") + init? (with store: Store) { + guard let id : Int = store.value(forKey: "id") else { return nil } + guard let name : String = store.value(forKey: "name") else { return nil } + let email : String? = store.value(forKey: "email") self.id = id self.name = name self.email = email } - func encode(encoder: Encoder) { - encoder.encode(id, "id") - encoder.encode(name, "name") - encoder.encode(email, "email") + func write(to store: inout Store) { + store.set(id, forKey: "id") + store.set(name, forKey: "name") + store.set(email, forKey: "email") } } diff --git a/Tests/Models/RecursiveModel.swift b/Tests/Models/RecursiveModel.swift index 81505b8..65bced1 100644 --- a/Tests/Models/RecursiveModel.swift +++ b/Tests/Models/RecursiveModel.swift @@ -30,25 +30,28 @@ struct Player: Model { self.age = age } - static func decode(decoder: Decoder) -> Player? { - return self.init(decoder: decoder) + static func read(from store: Store) -> Player? { + return self.init(with: store) } - init?(decoder: Decoder) { + init?(with store: Store) { - guard let id: Int = decoder.decode("id"), - name: String = decoder.decode("name"), - age: Int = decoder.decode("age"), - MVP: Bool = decoder.decode("mvp"), - teamates: [Player] = decoder.decode("teamates") - else { return nil } + guard + let id: Int = store.value(forKey: "id"), + let name: String = store.value(forKey: "name"), + let age: Int = store.value(forKey: "age"), + let MVP: Bool = store.value(forKey: "mvp"), + let teamates: [Player] = store.value(forKey: "teamates") + else { + return nil + } - let email : String? = decoder.decode("email") - let height : Float? = decoder.decode("height") - let weight: Double? = decoder.decode("weight") - let fillins: [Player]? = decoder.decode("fillins") - let teamatesByName: [String : Player]? = decoder.decode("teamatesByName") - let awards: [AnyObject]? = decoder.decode("awards") + let email : String? = store.value(forKey: "email") + let height : Float? = store.value(forKey: "height") + let weight: Double? = store.value(forKey: "weight") + let fillins: [Player]? = store.value(forKey: "fillins") + let teamatesByName: [String : Player]? = store.value(forKey: "teamatesByName") + let awards: [AnyObject]? = store.value(forKey: "awards") self.id = id self.name = name @@ -61,23 +64,19 @@ struct Player: Model { self.fillins = fillins self.teamatesByName = teamatesByName self.awards = awards - } -} - -extension Player: Encodable { - func encode(encoder: Encoder) { - encoder.encode(id, "id") - encoder.encode(name, "name") - encoder.encode(email, "email") - encoder.encode(age, "age") - encoder.encode(height, "height") - encoder.encode(weight, "weight") - encoder.encode(MVP, "mvp") - encoder.encode(teamates, "teamates") - encoder.encode(fillins, "fillins") - encoder.encode(teamatesByName, "teamatesByName") - encoder.encode(awards, "awards") + func write(to store: inout Store) { + store.set(id, forKey: "id") + store.set(name, forKey: "name") + store.set(email, forKey: "email") + store.set(age, forKey: "age") + store.set(height, forKey: "height") + store.set(weight, forKey: "weight") + store.set(MVP, forKey: "mvp") + store.set(teamates, forKey: "teamates") + store.set(fillins, forKey: "fillins") + store.set(teamatesByName, forKey: "teamatesByName") + store.set(awards, forKey: "awards") } } diff --git a/Tests/Models/TestModels.xcdatamodeld/TestModels.xcdatamodel/contents b/Tests/Models/TestModels.xcdatamodeld/TestModels.xcdatamodel/contents index a62a23a..a3d7a78 100644 --- a/Tests/Models/TestModels.xcdatamodeld/TestModels.xcdatamodel/contents +++ b/Tests/Models/TestModels.xcdatamodeld/TestModels.xcdatamodel/contents @@ -1,9 +1,9 @@ - + - + @@ -17,12 +17,12 @@ - + - + @@ -31,7 +31,7 @@ - + @@ -41,12 +41,12 @@ - + - + @@ -56,17 +56,17 @@ - + - + - + @@ -94,12 +94,12 @@ - + - + @@ -109,17 +109,17 @@ - + - + - + @@ -142,7 +142,7 @@ - + @@ -153,7 +153,7 @@ - + @@ -177,15 +177,15 @@ - - + + - + @@ -216,12 +216,12 @@ - + - + @@ -231,17 +231,17 @@ - + - + - + @@ -258,12 +258,12 @@ - + - + @@ -273,17 +273,17 @@ - + - + - + @@ -295,21 +295,21 @@ - + - - + + - - - + + + - + @@ -327,8 +327,8 @@ - - + + @@ -356,7 +356,7 @@ - + @@ -393,8 +393,8 @@ - - + + @@ -433,31 +433,31 @@ - + - + - + - + - - + + - - - + + + @@ -480,15 +480,15 @@ + - + - \ No newline at end of file diff --git a/Tests/Models/TestModels/TestImmutableOptionalTypes.swift b/Tests/Models/TestModels/TestImmutableOptionalTypes.swift index 452e791..b04a18e 100644 --- a/Tests/Models/TestModels/TestImmutableOptionalTypes.swift +++ b/Tests/Models/TestModels/TestImmutableOptionalTypes.swift @@ -11,17 +11,17 @@ extension TestImmutableOptionalTypes { init() { self.myBinary = TestImmutableOptionalTypes.createBinary()! self.myBoolean = true - self.myDate = NSDate() - self.myDecimal = NSDecimalNumber(double: 3.14) + self.myDate = Date() + self.myDecimal = NSDecimalNumber(value: 3.14) self.myFloat = 4.567 self.myDouble = -0.02 self.myInt = 5 self.myString = "Hello World" } - private static func createBinary() -> NSData? { - if let path = NSBundle(forClass: Test.self).pathForResource("Data", ofType: "plist") { - return NSData(contentsOfFile:path) + private static func createBinary() -> Data? { + if let path = Bundle(for: Test.self).pathForResource("Data", ofType: "plist") { + return (try? Data(contentsOf: URL(fileURLWithPath: path))) } return nil } diff --git a/Tests/Models/TestModels/TestImmutableTypes.swift b/Tests/Models/TestModels/TestImmutableTypes.swift index c95856f..ab9b45a 100644 --- a/Tests/Models/TestModels/TestImmutableTypes.swift +++ b/Tests/Models/TestModels/TestImmutableTypes.swift @@ -11,17 +11,17 @@ extension TestImmutableTypes { init() { self.myBinary = TestImmutableTypes.createBinary()! self.myBoolean = true - self.myDate = NSDate() - self.myDecimal = NSDecimalNumber(double: 3.14) + self.myDate = Date() + self.myDecimal = NSDecimalNumber(value: 3.14) self.myFloat = 4.567 self.myDouble = -0.02 self.myInt = 5 self.myString = "Hello World" } - private static func createBinary() -> NSData? { - if let path = NSBundle(forClass: Test.self).pathForResource("Data", ofType: "plist") { - return NSData(contentsOfFile:path) + private static func createBinary() -> Data? { + if let path = Bundle(for: Test.self).pathForResource("Data", ofType: "plist") { + return (try? Data(contentsOf: URL(fileURLWithPath: path))) } return nil } diff --git a/Tests/Models/TestModels/TestMigrationV1.swift b/Tests/Models/TestModels/TestMigrationV1.swift index 0c96eb4..2e78164 100644 --- a/Tests/Models/TestModels/TestMigrationV1.swift +++ b/Tests/Models/TestModels/TestMigrationV1.swift @@ -17,7 +17,7 @@ extension TestMigrationV1 { :Discussion: This method is called right before encoding finishes. It provides a chance to encode any further data with the encoder. */ - public func willFinishEncodingWithEncoder(encoder: Encoder) { + public func willFinishEncodingWithEncoder(_ encoder: Encoder) { encoder.encode("Hello World", "migration_test") } @@ -55,7 +55,7 @@ extension TestMigrationV1 { given the dataVersion parameter, this method should determine if the data being decoded is a different version than the current version, and needs to be migrated. */ - public static func needsMigration(dataVersion: AnyObject) -> Bool { + public static func needsMigration(_ dataVersion: AnyObject) -> Bool { if let dataVersion = dataVersion as? String, currentVersion = version( modelVersionHash, modelVersionHashModifier: modelVersionHashModifier) as? String { return dataVersion != currentVersion @@ -81,7 +81,7 @@ extension TestMigrationV1 { Note: the data version will automatically be updated the next time the model is encoded. */ - public static func migrateDataForDecoding(data: [String : AnyObject], dataVersion: AnyObject) -> [String : AnyObject] { + public static func migrateDataForDecoding(_ data: [String : AnyObject], dataVersion: AnyObject) -> [String : AnyObject] { return data } } diff --git a/Tests/Models/TestModels/TestMigrationV2.swift b/Tests/Models/TestModels/TestMigrationV2.swift index 08de5b0..7e1f1ef 100644 --- a/Tests/Models/TestModels/TestMigrationV2.swift +++ b/Tests/Models/TestModels/TestMigrationV2.swift @@ -48,7 +48,7 @@ extension TestMigrationV2 { Note: the data version will automatically be updated the next time the model is encoded. */ - public static func migrateDataForDecoding(data: [String : AnyObject], dataVersion: AnyObject) -> [String : AnyObject] { + public static func migrateDataForDecoding(_ data: [String : AnyObject], dataVersion: AnyObject) -> [String : AnyObject] { var newData = data newData.updateValue(10, forKey: "age") return newData diff --git a/Tests/Models/TestModels/TestOptionalTypes.swift b/Tests/Models/TestModels/TestOptionalTypes.swift index 50cb099..33356cb 100644 --- a/Tests/Models/TestModels/TestOptionalTypes.swift +++ b/Tests/Models/TestModels/TestOptionalTypes.swift @@ -12,8 +12,8 @@ extension TestOptionalTypes { var instance = TestOptionalTypes() instance.myBinary = TestOptionalTypes.createBinary() instance.myBoolean = true - instance.myDate = NSDate() - instance.myDecimal = NSDecimalNumber(double: 3.14) + instance.myDate = Date() + instance.myDecimal = NSDecimalNumber(value: 3.14) instance.myFloat = 4.567 instance.myDouble = -0.02 instance.myInt = 5 @@ -21,9 +21,9 @@ extension TestOptionalTypes { return instance } - private static func createBinary() -> NSData? { - if let path = NSBundle(forClass: Test.self).pathForResource("Data", ofType: "plist") { - return NSData(contentsOfFile:path) + private static func createBinary() -> Data? { + if let path = Bundle(for: Test.self).pathForResource("Data", ofType: "plist") { + return (try? Data(contentsOf: URL(fileURLWithPath: path))) } return nil } diff --git a/Tests/Models/TestModels/TestTypes.swift b/Tests/Models/TestModels/TestTypes.swift index 15337bd..cfe8274 100644 --- a/Tests/Models/TestModels/TestTypes.swift +++ b/Tests/Models/TestModels/TestTypes.swift @@ -10,17 +10,17 @@ extension TestTypes { init() { self.myBinary = TestTypes.createBinary()! self.myBoolean = true - self.myDate = NSDate() - self.myDecimal = NSDecimalNumber(double: 3.14) + self.myDate = Date() + self.myDecimal = NSDecimalNumber(value: 3.14) self.myFloat = 4.567 self.myDouble = -0.02 self.myInt = 5 self.myString = "Hello World" } - private static func createBinary() -> NSData? { - if let path = NSBundle(forClass: Test.self).pathForResource("Data", ofType: "plist") { - return NSData(contentsOfFile:path) + private static func createBinary() -> Data? { + if let path = Bundle(for: Test.self).pathForResource("Data", ofType: "plist") { + return (try? Data(contentsOf: URL(fileURLWithPath: path))) } return nil } diff --git a/Tests/Models/TestModels/_Company.swift b/Tests/Models/TestModels/_Company.swift index b64e74e..2a44928 100644 --- a/Tests/Models/TestModels/_Company.swift +++ b/Tests/Models/TestModels/_Company.swift @@ -14,135 +14,38 @@ public struct Company : Model { } -extension Company : Decodable { +extension Company { - public static func decode(decoder: Decoder) -> Company? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> Company? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = Company.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = Company.migrate(source: inStore) guard - let name: String = decoder.decode("name"), - let yearFounded: Double = decoder.decode("yearFounded") + let name: String = store.value(forKey: "name"), + let yearFounded: Double = store.value(forKey: "yearFounded") else { return nil } - let phoneNumber: String? = decoder.decode("phoneNumber") - let employees: [Employee]? = decoder.decode("employees") + let phoneNumber: String? = store.value(forKey: "phoneNumber") + let employees: [Employee]? = store.value(forKey: "employees") self.name = name self.yearFounded = yearFounded self.phoneNumber = phoneNumber self.employees = employees - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension Company : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(name, "name") - encoder.encode(yearFounded, "yearFounded") - encoder.encode(phoneNumber, "phoneNumber") - encoder.encode(employees, "employees") - - Company.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension Company { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<96a6f843 e4004fa9 5be7cca8 25260494 31324f8c 67a0643f 53096004 e1f9e4f0>" - } + public func write(to store: inout Store) { + store.set(name, forKey: "name") + store.set(yearFounded, forKey: "yearFounded") + store.set(phoneNumber, forKey: "phoneNumber") + store.set(employees, forKey: "employees") - public static func modelVersionHashModifier() -> String? { - return nil + Company.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getCompany(key: String) -> Company? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return Company.decode(dictionary) - } - - public func getCompany(key: String) -> [Company]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(Company.decode)) - } - - public func getCompany(key: String) -> [String : Company]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { Company.decode($0) }) - } - - public func getCompany(key: String, defaultValue: Company) -> Company { - return getCompany(key) ?? defaultValue - } - - public func getCompany(key: String, defaultValue: [Company]) -> [Company] { - return getDecodable(key) ?? defaultValue - } - - public func getCompany(key: String, defaultValue: [String : Company] - ) -> [String : Company] { - return getCompany(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setCompany(value: Company, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setCompany(value: [Company], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setCompany(value: [String : Company], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getCompany(key: String) -> Company? { - return getValue(key) - } - - public func getCompany(key: String, defaultValue: Company) -> Company { - return getCompany(key) ?? defaultValue - } - - public func getCompanys(key: String) -> [Company]? { - return getValue(key) - } - - public func getCompanys(key: String, defaultValue: [Company]) -> [Company] { - return getCompanys(key) ?? defaultValue - } - - public func getCompanyDictionary(key: String) -> [String : Company]? { - return getValue(key) - } - - public func getCompanyDictionary(key: String, defaultValue: [String : Company]) -> [String : Company] { - return getCompanyDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_Employee.swift b/Tests/Models/TestModels/_Employee.swift index 773417e..db9ca49 100644 --- a/Tests/Models/TestModels/_Employee.swift +++ b/Tests/Models/TestModels/_Employee.swift @@ -12,129 +12,32 @@ public struct Employee : Model { } -extension Employee : Decodable { +extension Employee { - public static func decode(decoder: Decoder) -> Employee? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> Employee? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = Employee.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = Employee.migrate(source: inStore) guard - let name: String = decoder.decode("name") + let name: String = store.value(forKey: "name") else { return nil } - let title: String? = decoder.decode("title") + let title: String? = store.value(forKey: "title") self.name = name self.title = title - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension Employee : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(name, "name") - encoder.encode(title, "title") - - Employee.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension Employee { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "" - } + public func write(to store: inout Store) { + store.set(name, forKey: "name") + store.set(title, forKey: "title") - public static func modelVersionHashModifier() -> String? { - return nil + Employee.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getEmployee(key: String) -> Employee? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return Employee.decode(dictionary) - } - - public func getEmployee(key: String) -> [Employee]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(Employee.decode)) - } - - public func getEmployee(key: String) -> [String : Employee]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { Employee.decode($0) }) - } - - public func getEmployee(key: String, defaultValue: Employee) -> Employee { - return getEmployee(key) ?? defaultValue - } - - public func getEmployee(key: String, defaultValue: [Employee]) -> [Employee] { - return getDecodable(key) ?? defaultValue - } - - public func getEmployee(key: String, defaultValue: [String : Employee] - ) -> [String : Employee] { - return getEmployee(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setEmployee(value: Employee, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setEmployee(value: [Employee], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setEmployee(value: [String : Employee], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getEmployee(key: String) -> Employee? { - return getValue(key) - } - - public func getEmployee(key: String, defaultValue: Employee) -> Employee { - return getEmployee(key) ?? defaultValue - } - - public func getEmployees(key: String) -> [Employee]? { - return getValue(key) - } - - public func getEmployees(key: String, defaultValue: [Employee]) -> [Employee] { - return getEmployees(key) ?? defaultValue - } - - public func getEmployeeDictionary(key: String) -> [String : Employee]? { - return getValue(key) - } - - public func getEmployeeDictionary(key: String, defaultValue: [String : Employee]) -> [String : Employee] { - return getEmployeeDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_Gender.swift b/Tests/Models/TestModels/_Gender.swift index 7ee6810..2ccd5bc 100644 --- a/Tests/Models/TestModels/_Gender.swift +++ b/Tests/Models/TestModels/_Gender.swift @@ -8,123 +8,28 @@ import State public enum Gender : String, Model { - case Female = "Female" - case Male = "Male" + case female = "female" + case male = "male" } -extension Gender: Decodable { +extension Gender { - public static func decode(decoder: Decoder) -> Gender? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> Gender? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = Gender.performMigrationIfNeeded(decoder) - guard let value: String = decoder.decode("value") else { return nil } - self.init(rawValue: value) - } -} - -extension Gender: Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(self.rawValue, "value") - Gender.encodeVersionIfNeeded(encoder) - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension Gender { + public init?(with inStore: Store) { + let store = Gender.migrate(source: inStore) - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "" + guard let value: String = store.value(forKey: "value") else { return nil } + self.init(rawValue: value) } - public static func modelVersionHashModifier() -> String? { - return nil + public func write(to store: inout Store) { + store.set(self.rawValue, forKey: "value") + Gender.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getGender(key: String) -> Gender? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return Gender.decode(dictionary) - } - - public func getGender(key: String) -> [Gender]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(Gender.decode)) - } - - public func getGender(key: String) -> [String : Gender]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { Gender.decode($0) }) - } - - public func getGender(key: String, defaultValue: Gender) -> Gender { - return getGender(key) ?? defaultValue - } - - public func getGender(key: String, defaultValue: [Gender]) -> [Gender] { - return getDecodable(key) ?? defaultValue - } - - public func getGender(key: String, defaultValue: [String : Gender] - ) -> [String : Gender] { - return getGender(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setGender(value: Gender, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setGender(value: [Gender], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setGender(value: [String : Gender], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getGender(key: String) -> Gender? { - return getValue(key) - } - - public func getGender(key: String, defaultValue: Gender) -> Gender { - return getGender(key) ?? defaultValue - } - - public func getGenders(key: String) -> [Gender]? { - return getValue(key) - } - - public func getGenders(key: String, defaultValue: [Gender]) -> [Gender] { - return getGenders(key) ?? defaultValue - } - - public func getGenderDictionary(key: String) -> [String : Gender]? { - return getValue(key) - } - - public func getGenderDictionary(key: String, defaultValue: [String : Gender]) -> [String : Gender] { - return getGenderDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_Grandchild.swift b/Tests/Models/TestModels/_Grandchild.swift index 01f8ecb..0478938 100644 --- a/Tests/Models/TestModels/_Grandchild.swift +++ b/Tests/Models/TestModels/_Grandchild.swift @@ -13,129 +13,32 @@ public struct Grandchild : Model { } -extension Grandchild : Decodable { +extension Grandchild { - public static func decode(decoder: Decoder) -> Grandchild? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> Grandchild? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = Grandchild.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = Grandchild.migrate(source: inStore) - let age: Int? = decoder.decode("age") - let name: String? = decoder.decode("name") - let gender: Gender? = decoder.decode("gender") + let age: Int? = store.value(forKey: "age") + let name: String? = store.value(forKey: "name") + let gender: Gender? = store.value(forKey: "gender") self.age = age self.name = name self.gender = gender - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension Grandchild : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(age, "age") - encoder.encode(name, "name") - encoder.encode(gender, "gender") - - Grandchild.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension Grandchild { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<10d8adcc 35a3ab52 8d11fa17 fbbdb083 23527533 29812594 823e8a17 8e1cb50d>" - } + public func write(to store: inout Store) { + store.set(age, forKey: "age") + store.set(name, forKey: "name") + store.set(gender, forKey: "gender") - public static func modelVersionHashModifier() -> String? { - return nil + Grandchild.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getGrandchild(key: String) -> Grandchild? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return Grandchild.decode(dictionary) - } - - public func getGrandchild(key: String) -> [Grandchild]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(Grandchild.decode)) - } - - public func getGrandchild(key: String) -> [String : Grandchild]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { Grandchild.decode($0) }) - } - - public func getGrandchild(key: String, defaultValue: Grandchild) -> Grandchild { - return getGrandchild(key) ?? defaultValue - } - - public func getGrandchild(key: String, defaultValue: [Grandchild]) -> [Grandchild] { - return getDecodable(key) ?? defaultValue - } - - public func getGrandchild(key: String, defaultValue: [String : Grandchild] - ) -> [String : Grandchild] { - return getGrandchild(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setGrandchild(value: Grandchild, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setGrandchild(value: [Grandchild], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setGrandchild(value: [String : Grandchild], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getGrandchild(key: String) -> Grandchild? { - return getValue(key) - } - - public func getGrandchild(key: String, defaultValue: Grandchild) -> Grandchild { - return getGrandchild(key) ?? defaultValue - } - - public func getGrandchilds(key: String) -> [Grandchild]? { - return getValue(key) - } - - public func getGrandchilds(key: String, defaultValue: [Grandchild]) -> [Grandchild] { - return getGrandchilds(key) ?? defaultValue - } - - public func getGrandchildDictionary(key: String) -> [String : Grandchild]? { - return getValue(key) - } - - public func getGrandchildDictionary(key: String, defaultValue: [String : Grandchild]) -> [String : Grandchild] { - return getGrandchildDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestAssociatedEnum.swift b/Tests/Models/TestModels/_TestAssociatedEnum.swift index 80b601a..71b8393 100644 --- a/Tests/Models/TestModels/_TestAssociatedEnum.swift +++ b/Tests/Models/TestModels/_TestAssociatedEnum.swift @@ -9,228 +9,132 @@ import UIKit public enum TestAssociatedEnum : Model { - case BinaryType (NSData) - case BooleanType (Bool) - case DateType (NSDate) - case DecimalType (NSDecimalNumber) - case DoubleType (Double) - case FloatType (Float) - case IntType (Int) - case StringType (String) - case TransformableColorType (UIColor) - case DecodableToManyType ([Employee]) - case DecodableToOneType (Employee) + case binaryType (NSData) + case booleanType (Bool) + case dateType (NSDate) + case decimalType (NSDecimalNumber) + case doubleType (Double) + case floatType (Float) + case intType (Int) + case stringType (String) + case transformableColorType (UIColor) + case decodableToManyType ([Employee]) + case decodableToOneType (Employee) } -extension TestAssociatedEnum: Decodable { +extension TestAssociatedEnum { - public static func decode(decoder: Decoder) -> TestAssociatedEnum? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestAssociatedEnum? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestAssociatedEnum.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestAssociatedEnum.migrate(source: inStore) - guard let type: String = decoder.decode("TestAssociatedEnum") else { return nil } + guard let type: String = store.value(forKey: "TestAssociatedEnum") else { return nil } switch type { - case "BinaryType": - if let value: NSData = decoder.decode("value") { -self = TestAssociatedEnum.BinaryType(value) -} else { return nil } - - case "BooleanType": - if let value: Bool = decoder.decode("value") { -self = TestAssociatedEnum.BooleanType(value) -} else { return nil } - - case "DateType": - if let value: NSDate = decoder.decode("value") { -self = TestAssociatedEnum.DateType(value) -} else { return nil } - - case "DecimalType": - if let value: NSDecimalNumber = decoder.decode("value") { -self = TestAssociatedEnum.DecimalType(value) -} else { return nil } - - case "DoubleType": - if let value: Double = decoder.decode("value") { -self = TestAssociatedEnum.DoubleType(value) -} else { return nil } - - case "FloatType": - if let value: Float = decoder.decode("value") { -self = TestAssociatedEnum.FloatType(value) -} else { return nil } - - case "IntType": - if let value: Int = decoder.decode("value") { -self = TestAssociatedEnum.IntType(value) -} else { return nil } - - case "StringType": - if let value: String = decoder.decode("value") { -self = TestAssociatedEnum.StringType(value) -} else { return nil } - - case "TransformableColorType": - if let value: UIColor = decoder.decode("value") { -self = TestAssociatedEnum.TransformableColorType(value) -} else { return nil } - - case "DecodableToManyType": - if let value: [Employee] = decoder.decode("value") { -self = TestAssociatedEnum.DecodableToManyType(value) -} else { return nil } - case "DecodableToOneType": - if let value: Employee = decoder.decode("value") { -self = TestAssociatedEnum.DecodableToOneType(value) -} else { return nil } + case "binaryType": + if let value: NSData = store.value(forKey: "value") { + self = TestAssociatedEnum.binaryType(value) + } else { return nil } + + case "booleanType": + if let value: Bool = store.value(forKey: "value") { + self = TestAssociatedEnum.booleanType(value) + } else { return nil } + + case "dateType": + if let value: NSDate = store.value(forKey: "value") { + self = TestAssociatedEnum.dateType(value) + } else { return nil } + + case "decimalType": + if let value: NSDecimalNumber = store.value(forKey: "value") { + self = TestAssociatedEnum.decimalType(value) + } else { return nil } + + case "doubleType": + if let value: Double = store.value(forKey: "value") { + self = TestAssociatedEnum.doubleType(value) + } else { return nil } + + case "floatType": + if let value: Float = store.value(forKey: "value") { + self = TestAssociatedEnum.floatType(value) + } else { return nil } + + case "intType": + if let value: Int = store.value(forKey: "value") { + self = TestAssociatedEnum.intType(value) + } else { return nil } + + case "stringType": + if let value: String = store.value(forKey: "value") { + self = TestAssociatedEnum.stringType(value) + } else { return nil } + + case "transformableColorType": + if let value: UIColor = store.value(forKey: "value") { + self = TestAssociatedEnum.transformableColorType(value) + } else { return nil } + + case "decodableToManyType": + if let value: [Employee] = store.value(forKey: "value") { + self = TestAssociatedEnum.decodableToManyType(value) + } else { return nil } + case "decodableToOneType": + if let value: Employee = store.value(forKey: "value") { + self = TestAssociatedEnum.decodableToOneType(value) + } else { return nil } default: return nil } } -} - -extension TestAssociatedEnum: Encodable { - public func encode(encoder: Encoder) { + public func write(to store: inout Store) { switch self { - case let .BinaryType(value): - encoder.encode("BinaryType", "TestAssociatedEnum") - encoder.encode(value, "value") - case let .BooleanType(value): - encoder.encode("BooleanType", "TestAssociatedEnum") - encoder.encode(value, "value") - case let .DateType(value): - encoder.encode("DateType", "TestAssociatedEnum") - encoder.encode(value, "value") - case let .DecimalType(value): - encoder.encode("DecimalType", "TestAssociatedEnum") - encoder.encode(value, "value") - case let .DoubleType(value): - encoder.encode("DoubleType", "TestAssociatedEnum") - encoder.encode(value, "value") - case let .FloatType(value): - encoder.encode("FloatType", "TestAssociatedEnum") - encoder.encode(value, "value") - case let .IntType(value): - encoder.encode("IntType", "TestAssociatedEnum") - encoder.encode(value, "value") - case let .StringType(value): - encoder.encode("StringType", "TestAssociatedEnum") - encoder.encode(value, "value") - case let .TransformableColorType(value): - encoder.encode("TransformableColorType", "TestAssociatedEnum") - encoder.encode(value, "value") - case let .DecodableToManyType(value): - encoder.encode("DecodableToManyType", "TestAssociatedEnum") - encoder.encode(value, "value") - case let .DecodableToOneType(value): - encoder.encode("DecodableToOneType", "TestAssociatedEnum") - encoder.encode(value, "value") + case let .binaryType(value): + store.set("binaryType", forKey: "TestAssociatedEnum") + store.set(value, forKey: "value") + case let .booleanType(value): + store.set("booleanType", forKey: "TestAssociatedEnum") + store.set(value, forKey: "value") + case let .dateType(value): + store.set("dateType", forKey: "TestAssociatedEnum") + store.set(value, forKey: "value") + case let .decimalType(value): + store.set("decimalType", forKey: "TestAssociatedEnum") + store.set(value, forKey: "value") + case let .doubleType(value): + store.set("doubleType", forKey: "TestAssociatedEnum") + store.set(value, forKey: "value") + case let .floatType(value): + store.set("floatType", forKey: "TestAssociatedEnum") + store.set(value, forKey: "value") + case let .intType(value): + store.set("intType", forKey: "TestAssociatedEnum") + store.set(value, forKey: "value") + case let .stringType(value): + store.set("stringType", forKey: "TestAssociatedEnum") + store.set(value, forKey: "value") + case let .transformableColorType(value): + store.set("transformableColorType", forKey: "TestAssociatedEnum") + store.set(value, forKey: "value") + case let .decodableToManyType(value): + store.set("decodableToManyType", forKey: "TestAssociatedEnum") + store.set(value, forKey: "value") + case let .decodableToOneType(value): + store.set("decodableToOneType", forKey: "TestAssociatedEnum") + store.set(value, forKey: "value") } - TestAssociatedEnum.encodeVersionIfNeeded(encoder) - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestAssociatedEnum { - - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<6da9f98e 37df6363 56b14e25 3100b317 ea72bc42 9578573b 17427080 0a824a73>" - } - - public static func modelVersionHashModifier() -> String? { - return nil + TestAssociatedEnum.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestAssociatedEnum(key: String) -> TestAssociatedEnum? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestAssociatedEnum.decode(dictionary) - } - - public func getTestAssociatedEnum(key: String) -> [TestAssociatedEnum]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestAssociatedEnum.decode)) - } - - public func getTestAssociatedEnum(key: String) -> [String : TestAssociatedEnum]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestAssociatedEnum.decode($0) }) - } - - public func getTestAssociatedEnum(key: String, defaultValue: TestAssociatedEnum) -> TestAssociatedEnum { - return getTestAssociatedEnum(key) ?? defaultValue - } - - public func getTestAssociatedEnum(key: String, defaultValue: [TestAssociatedEnum]) -> [TestAssociatedEnum] { - return getDecodable(key) ?? defaultValue - } - - public func getTestAssociatedEnum(key: String, defaultValue: [String : TestAssociatedEnum] - ) -> [String : TestAssociatedEnum] { - return getTestAssociatedEnum(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestAssociatedEnum(value: TestAssociatedEnum, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestAssociatedEnum(value: [TestAssociatedEnum], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestAssociatedEnum(value: [String : TestAssociatedEnum], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestAssociatedEnum(key: String) -> TestAssociatedEnum? { - return getValue(key) - } - - public func getTestAssociatedEnum(key: String, defaultValue: TestAssociatedEnum) -> TestAssociatedEnum { - return getTestAssociatedEnum(key) ?? defaultValue - } - - public func getTestAssociatedEnums(key: String) -> [TestAssociatedEnum]? { - return getValue(key) - } - - public func getTestAssociatedEnums(key: String, defaultValue: [TestAssociatedEnum]) -> [TestAssociatedEnum] { - return getTestAssociatedEnums(key) ?? defaultValue - } - - public func getTestAssociatedEnumDictionary(key: String) -> [String : TestAssociatedEnum]? { - return getValue(key) - } - - public func getTestAssociatedEnumDictionary(key: String, defaultValue: [String : TestAssociatedEnum]) -> [String : TestAssociatedEnum] { - return getTestAssociatedEnumDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestAssociatedOptionalEnum.swift b/Tests/Models/TestModels/_TestAssociatedOptionalEnum.swift index b7ae770..fc0db2a 100644 --- a/Tests/Models/TestModels/_TestAssociatedOptionalEnum.swift +++ b/Tests/Models/TestModels/_TestAssociatedOptionalEnum.swift @@ -9,218 +9,122 @@ import UIKit public enum TestAssociatedOptionalEnum : Model { - case BinaryType (NSData?) - case BooleanType (Bool?) - case DateType (NSDate?) - case DecimalType (NSDecimalNumber?) - case DoubleType (Double?) - case FloatType (Float?) - case IntType (Int?) - case StringType (String?) - case TransformableColorType (UIColor?) - case DecodableToManyType ([Employee]?) - case DecodableToOneType (Employee?) + case binaryType (NSData?) + case booleanType (Bool?) + case dateType (NSDate?) + case decimalType (NSDecimalNumber?) + case doubleType (Double?) + case floatType (Float?) + case intType (Int?) + case stringType (String?) + case transformableColorType (UIColor?) + case decodableToManyType ([Employee]?) + case decodableToOneType (Employee?) } -extension TestAssociatedOptionalEnum: Decodable { +extension TestAssociatedOptionalEnum { - public static func decode(decoder: Decoder) -> TestAssociatedOptionalEnum? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestAssociatedOptionalEnum? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestAssociatedOptionalEnum.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestAssociatedOptionalEnum.migrate(source: inStore) - guard let type: String = decoder.decode("TestAssociatedOptionalEnum") else { return nil } + guard let type: String = store.value(forKey: "TestAssociatedOptionalEnum") else { return nil } switch type { - case "BinaryType": - let value: NSData? = decoder.decode("value") -self = TestAssociatedOptionalEnum.BinaryType(value) + case "binaryType": + let value: NSData? = store.value(forKey: "value") + self = TestAssociatedOptionalEnum.binaryType(value) - case "BooleanType": - let value: Bool? = decoder.decode("value") -self = TestAssociatedOptionalEnum.BooleanType(value) + case "booleanType": + let value: Bool? = store.value(forKey: "value") + self = TestAssociatedOptionalEnum.booleanType(value) - case "DateType": - let value: NSDate? = decoder.decode("value") -self = TestAssociatedOptionalEnum.DateType(value) + case "dateType": + let value: NSDate? = store.value(forKey: "value") + self = TestAssociatedOptionalEnum.dateType(value) - case "DecimalType": - let value: NSDecimalNumber? = decoder.decode("value") -self = TestAssociatedOptionalEnum.DecimalType(value) + case "decimalType": + let value: NSDecimalNumber? = store.value(forKey: "value") + self = TestAssociatedOptionalEnum.decimalType(value) - case "DoubleType": - let value: Double? = decoder.decode("value") -self = TestAssociatedOptionalEnum.DoubleType(value) + case "doubleType": + let value: Double? = store.value(forKey: "value") + self = TestAssociatedOptionalEnum.doubleType(value) - case "FloatType": - let value: Float? = decoder.decode("value") -self = TestAssociatedOptionalEnum.FloatType(value) + case "floatType": + let value: Float? = store.value(forKey: "value") + self = TestAssociatedOptionalEnum.floatType(value) - case "IntType": - let value: Int? = decoder.decode("value") -self = TestAssociatedOptionalEnum.IntType(value) + case "intType": + let value: Int? = store.value(forKey: "value") + self = TestAssociatedOptionalEnum.intType(value) - case "StringType": - let value: String? = decoder.decode("value") -self = TestAssociatedOptionalEnum.StringType(value) + case "stringType": + let value: String? = store.value(forKey: "value") + self = TestAssociatedOptionalEnum.stringType(value) - case "TransformableColorType": - let value: UIColor? = decoder.decode("value") -self = TestAssociatedOptionalEnum.TransformableColorType(value) + case "transformableColorType": + let value: UIColor? = store.value(forKey: "value") + self = TestAssociatedOptionalEnum.transformableColorType(value) - case "DecodableToManyType": - let value: [Employee]? = decoder.decode("value") -self = TestAssociatedOptionalEnum.DecodableToManyType(value) + case "decodableToManyType": + let value: [Employee]? = store.value(forKey: "value") + self = TestAssociatedOptionalEnum.decodableToManyType(value) - case "DecodableToOneType": - let value: Employee? = decoder.decode("value") -self = TestAssociatedOptionalEnum.DecodableToOneType(value) + case "decodableToOneType": + let value: Employee? = store.value(forKey: "value") + self = TestAssociatedOptionalEnum.decodableToOneType(value) default: return nil } } -} - -extension TestAssociatedOptionalEnum: Encodable { - public func encode(encoder: Encoder) { + public func write(to store: inout Store) { switch self { - case let .BinaryType(value): - encoder.encode("BinaryType", "TestAssociatedOptionalEnum") - encoder.encode(value, "value") - case let .BooleanType(value): - encoder.encode("BooleanType", "TestAssociatedOptionalEnum") - encoder.encode(value, "value") - case let .DateType(value): - encoder.encode("DateType", "TestAssociatedOptionalEnum") - encoder.encode(value, "value") - case let .DecimalType(value): - encoder.encode("DecimalType", "TestAssociatedOptionalEnum") - encoder.encode(value, "value") - case let .DoubleType(value): - encoder.encode("DoubleType", "TestAssociatedOptionalEnum") - encoder.encode(value, "value") - case let .FloatType(value): - encoder.encode("FloatType", "TestAssociatedOptionalEnum") - encoder.encode(value, "value") - case let .IntType(value): - encoder.encode("IntType", "TestAssociatedOptionalEnum") - encoder.encode(value, "value") - case let .StringType(value): - encoder.encode("StringType", "TestAssociatedOptionalEnum") - encoder.encode(value, "value") - case let .TransformableColorType(value): - encoder.encode("TransformableColorType", "TestAssociatedOptionalEnum") - encoder.encode(value, "value") - case let .DecodableToManyType(value): - encoder.encode("DecodableToManyType", "TestAssociatedOptionalEnum") - encoder.encode(value, "value") - case let .DecodableToOneType(value): - encoder.encode("DecodableToOneType", "TestAssociatedOptionalEnum") - encoder.encode(value, "value") + case let .binaryType(value): + store.set("binaryType", forKey: "TestAssociatedOptionalEnum") + store.set(value, forKey: "value") + case let .booleanType(value): + store.set("booleanType", forKey: "TestAssociatedOptionalEnum") + store.set(value, forKey: "value") + case let .dateType(value): + store.set("dateType", forKey: "TestAssociatedOptionalEnum") + store.set(value, forKey: "value") + case let .decimalType(value): + store.set("decimalType", forKey: "TestAssociatedOptionalEnum") + store.set(value, forKey: "value") + case let .doubleType(value): + store.set("doubleType", forKey: "TestAssociatedOptionalEnum") + store.set(value, forKey: "value") + case let .floatType(value): + store.set("floatType", forKey: "TestAssociatedOptionalEnum") + store.set(value, forKey: "value") + case let .intType(value): + store.set("intType", forKey: "TestAssociatedOptionalEnum") + store.set(value, forKey: "value") + case let .stringType(value): + store.set("stringType", forKey: "TestAssociatedOptionalEnum") + store.set(value, forKey: "value") + case let .transformableColorType(value): + store.set("transformableColorType", forKey: "TestAssociatedOptionalEnum") + store.set(value, forKey: "value") + case let .decodableToManyType(value): + store.set("decodableToManyType", forKey: "TestAssociatedOptionalEnum") + store.set(value, forKey: "value") + case let .decodableToOneType(value): + store.set("decodableToOneType", forKey: "TestAssociatedOptionalEnum") + store.set(value, forKey: "value") } - TestAssociatedOptionalEnum.encodeVersionIfNeeded(encoder) - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestAssociatedOptionalEnum { - - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<91a6ba56 f3ff3271 c6a947d9 d59ab16f 03cfe13e 869a8894 de84a78a dcfe623f>" - } - - public static func modelVersionHashModifier() -> String? { - return nil + TestAssociatedOptionalEnum.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestAssociatedOptionalEnum(key: String) -> TestAssociatedOptionalEnum? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestAssociatedOptionalEnum.decode(dictionary) - } - - public func getTestAssociatedOptionalEnum(key: String) -> [TestAssociatedOptionalEnum]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestAssociatedOptionalEnum.decode)) - } - - public func getTestAssociatedOptionalEnum(key: String) -> [String : TestAssociatedOptionalEnum]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestAssociatedOptionalEnum.decode($0) }) - } - - public func getTestAssociatedOptionalEnum(key: String, defaultValue: TestAssociatedOptionalEnum) -> TestAssociatedOptionalEnum { - return getTestAssociatedOptionalEnum(key) ?? defaultValue - } - - public func getTestAssociatedOptionalEnum(key: String, defaultValue: [TestAssociatedOptionalEnum]) -> [TestAssociatedOptionalEnum] { - return getDecodable(key) ?? defaultValue - } - - public func getTestAssociatedOptionalEnum(key: String, defaultValue: [String : TestAssociatedOptionalEnum] - ) -> [String : TestAssociatedOptionalEnum] { - return getTestAssociatedOptionalEnum(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestAssociatedOptionalEnum(value: TestAssociatedOptionalEnum, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestAssociatedOptionalEnum(value: [TestAssociatedOptionalEnum], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestAssociatedOptionalEnum(value: [String : TestAssociatedOptionalEnum], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestAssociatedOptionalEnum(key: String) -> TestAssociatedOptionalEnum? { - return getValue(key) - } - - public func getTestAssociatedOptionalEnum(key: String, defaultValue: TestAssociatedOptionalEnum) -> TestAssociatedOptionalEnum { - return getTestAssociatedOptionalEnum(key) ?? defaultValue - } - - public func getTestAssociatedOptionalEnums(key: String) -> [TestAssociatedOptionalEnum]? { - return getValue(key) - } - - public func getTestAssociatedOptionalEnums(key: String, defaultValue: [TestAssociatedOptionalEnum]) -> [TestAssociatedOptionalEnum] { - return getTestAssociatedOptionalEnums(key) ?? defaultValue - } - - public func getTestAssociatedOptionalEnumDictionary(key: String) -> [String : TestAssociatedOptionalEnum]? { - return getValue(key) - } - - public func getTestAssociatedOptionalEnumDictionary(key: String, defaultValue: [String : TestAssociatedOptionalEnum]) -> [String : TestAssociatedOptionalEnum] { - return getTestAssociatedOptionalEnumDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestChild.swift b/Tests/Models/TestModels/_TestChild.swift index 21a6d8d..c8f581e 100644 --- a/Tests/Models/TestModels/_TestChild.swift +++ b/Tests/Models/TestModels/_TestChild.swift @@ -14,132 +14,35 @@ public struct TestChild : Model { } -extension TestChild : Decodable { +extension TestChild { - public static func decode(decoder: Decoder) -> TestChild? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestChild? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestChild.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestChild.migrate(source: inStore) - let age: Int? = decoder.decode("age") - let name: String? = decoder.decode("name") - let myChildren: [Grandchild]? = decoder.decode("myChildren") - let gender: Gender? = decoder.decode("gender") + let age: Int? = store.value(forKey: "age") + let name: String? = store.value(forKey: "name") + let myChildren: [Grandchild]? = store.value(forKey: "myChildren") + let gender: Gender? = store.value(forKey: "gender") self.age = age self.name = name self.myChildren = myChildren self.gender = gender - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestChild : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(age, "age") - encoder.encode(name, "name") - encoder.encode(myChildren, "myChildren") - encoder.encode(gender, "gender") - - TestChild.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestChild { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<4b2e27e5 53e329ff 69cfb4ba 1573537c 35d26944 7199acfc 729b6b5c c6e0ac88>" - } + public func write(to store: inout Store) { + store.set(age, forKey: "age") + store.set(name, forKey: "name") + store.set(myChildren, forKey: "myChildren") + store.set(gender, forKey: "gender") - public static func modelVersionHashModifier() -> String? { - return nil + TestChild.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestChild(key: String) -> TestChild? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestChild.decode(dictionary) - } - - public func getTestChild(key: String) -> [TestChild]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestChild.decode)) - } - - public func getTestChild(key: String) -> [String : TestChild]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestChild.decode($0) }) - } - - public func getTestChild(key: String, defaultValue: TestChild) -> TestChild { - return getTestChild(key) ?? defaultValue - } - - public func getTestChild(key: String, defaultValue: [TestChild]) -> [TestChild] { - return getDecodable(key) ?? defaultValue - } - - public func getTestChild(key: String, defaultValue: [String : TestChild] - ) -> [String : TestChild] { - return getTestChild(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestChild(value: TestChild, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestChild(value: [TestChild], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestChild(value: [String : TestChild], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestChild(key: String) -> TestChild? { - return getValue(key) - } - - public func getTestChild(key: String, defaultValue: TestChild) -> TestChild { - return getTestChild(key) ?? defaultValue - } - - public func getTestChilds(key: String) -> [TestChild]? { - return getValue(key) - } - - public func getTestChilds(key: String, defaultValue: [TestChild]) -> [TestChild] { - return getTestChilds(key) ?? defaultValue - } - - public func getTestChildDictionary(key: String) -> [String : TestChild]? { - return getValue(key) - } - - public func getTestChildDictionary(key: String, defaultValue: [String : TestChild]) -> [String : TestChild] { - return getTestChildDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestCollections.swift b/Tests/Models/TestModels/_TestCollections.swift index 9dc4c56..5740a04 100644 --- a/Tests/Models/TestModels/_TestCollections.swift +++ b/Tests/Models/TestModels/_TestCollections.swift @@ -13,131 +13,34 @@ public struct TestCollections : Model { } -extension TestCollections : Decodable { +extension TestCollections { - public static func decode(decoder: Decoder) -> TestCollections? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestCollections? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestCollections.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestCollections.migrate(source: inStore) guard - let arrayOfStrings: [String] = decoder.decode("arrayOfStrings"), - let dicOfInts: [String : Int] = decoder.decode("dicOfInts"), - let setOfStrings: Set = decoder.decode("setOfStrings") + let arrayOfStrings: [String] = store.value(forKey: "arrayOfStrings"), + let dicOfInts: [String : Int] = store.value(forKey: "dicOfInts"), + let setOfStrings: Set = store.value(forKey: "setOfStrings") else { return nil } self.arrayOfStrings = arrayOfStrings self.dicOfInts = dicOfInts self.setOfStrings = setOfStrings - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestCollections : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(arrayOfStrings, "arrayOfStrings") - encoder.encode(dicOfInts, "dicOfInts") - encoder.encode(setOfStrings, "setOfStrings") - - TestCollections.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestCollections { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<313ca880 7b444092 cef097e8 0b29feb7 e70ab4b5 3b7298dc 4debc39c 90801887>" - } + public func write(to store: inout Store) { + store.set(arrayOfStrings, forKey: "arrayOfStrings") + store.set(dicOfInts, forKey: "dicOfInts") + store.set(setOfStrings, forKey: "setOfStrings") - public static func modelVersionHashModifier() -> String? { - return nil + TestCollections.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestCollections(key: String) -> TestCollections? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestCollections.decode(dictionary) - } - - public func getTestCollections(key: String) -> [TestCollections]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestCollections.decode)) - } - - public func getTestCollections(key: String) -> [String : TestCollections]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestCollections.decode($0) }) - } - - public func getTestCollections(key: String, defaultValue: TestCollections) -> TestCollections { - return getTestCollections(key) ?? defaultValue - } - - public func getTestCollections(key: String, defaultValue: [TestCollections]) -> [TestCollections] { - return getDecodable(key) ?? defaultValue - } - - public func getTestCollections(key: String, defaultValue: [String : TestCollections] - ) -> [String : TestCollections] { - return getTestCollections(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestCollections(value: TestCollections, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestCollections(value: [TestCollections], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestCollections(value: [String : TestCollections], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestCollections(key: String) -> TestCollections? { - return getValue(key) - } - - public func getTestCollections(key: String, defaultValue: TestCollections) -> TestCollections { - return getTestCollections(key) ?? defaultValue - } - - public func getTestCollectionss(key: String) -> [TestCollections]? { - return getValue(key) - } - - public func getTestCollectionss(key: String, defaultValue: [TestCollections]) -> [TestCollections] { - return getTestCollectionss(key) ?? defaultValue - } - - public func getTestCollectionsDictionary(key: String) -> [String : TestCollections]? { - return getValue(key) - } - - public func getTestCollectionsDictionary(key: String, defaultValue: [String : TestCollections]) -> [String : TestCollections] { - return getTestCollectionsDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestDefaults.swift b/Tests/Models/TestModels/_TestDefaults.swift index a9cb6f3..756469f 100644 --- a/Tests/Models/TestModels/_TestDefaults.swift +++ b/Tests/Models/TestModels/_TestDefaults.swift @@ -21,32 +21,31 @@ public struct TestDefaults : Model { } -extension TestDefaults : Decodable { +extension TestDefaults { - public static func decode(decoder: Decoder) -> TestDefaults? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestDefaults? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestDefaults.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestDefaults.migrate(source: inStore) guard - let defaultManualString: String = decoder.decode("defaultManualString"), - let defaultArray: [String] = decoder.decode("defaultArray"), - let defaultString: String = decoder.decode("defaultString"), - let defaultInt: Int = decoder.decode("defaultInt"), - let defaultEmptyArray: [String] = decoder.decode("defaultEmptyArray"), - let defaultChildren: [TestDefaultsChild] = decoder.decode("defaultChildren"), - let defaultChild: TestDefaultsChild = decoder.decode("defaultChild") + let defaultManualString: String = store.value(forKey: "defaultManualString"), + let defaultArray: [String] = store.value(forKey: "defaultArray"), + let defaultString: String = store.value(forKey: "defaultString"), + let defaultInt: Int = store.value(forKey: "defaultInt"), + let defaultEmptyArray: [String] = store.value(forKey: "defaultEmptyArray"), + let defaultChildren: [TestDefaultsChild] = store.value(forKey: "defaultChildren"), + let defaultChild: TestDefaultsChild = store.value(forKey: "defaultChild") else { return nil } - let noDefaultInt: Int? = decoder.decode("noDefaultInt") + let noDefaultInt: Int? = store.value(forKey: "noDefaultInt") - let noDefaultString: String? = decoder.decode("noDefaultString") + let noDefaultString: String? = store.value(forKey: "noDefaultString") - let noDefaultChild: TestDefaultsChild? = decoder.decode("noDefaultChild") - let noDefaultChildren: TestDefaultsChild? = decoder.decode("noDefaultChildren") + let noDefaultChild: TestDefaultsChild? = store.value(forKey: "noDefaultChild") + let noDefaultChildren: TestDefaultsChild? = store.value(forKey: "noDefaultChildren") self.defaultManualString = defaultManualString self.defaultArray = defaultArray @@ -59,120 +58,24 @@ extension TestDefaults : Decodable { self.defaultChild = defaultChild self.noDefaultChild = noDefaultChild self.noDefaultChildren = noDefaultChildren - didFinishDecodingWithDecoder(decoder) - } -} - -extension TestDefaults : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(defaultManualString, "defaultManualString") - encoder.encode(defaultArray, "defaultArray") - encoder.encode(defaultString, "defaultString") - encoder.encode(noDefaultInt, "noDefaultInt") - encoder.encode(defaultInt, "defaultInt") - encoder.encode(noDefaultString, "noDefaultString") - encoder.encode(defaultEmptyArray, "defaultEmptyArray") - encoder.encode(defaultChildren, "defaultChildren") - encoder.encode(defaultChild, "defaultChild") - encoder.encode(noDefaultChild, "noDefaultChild") - encoder.encode(noDefaultChildren, "noDefaultChildren") - - TestDefaults.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestDefaults { - - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<0e8e50ed 18d24253 6a725634 c5478e08 df6549ca 70f50d04 adec849b 3e79bdfc>" + finishReading(from: store) } - public static func modelVersionHashModifier() -> String? { - return nil + public func write(to store: inout Store) { + store.set(defaultManualString, forKey: "defaultManualString") + store.set(defaultArray, forKey: "defaultArray") + store.set(defaultString, forKey: "defaultString") + store.set(noDefaultInt, forKey: "noDefaultInt") + store.set(defaultInt, forKey: "defaultInt") + store.set(noDefaultString, forKey: "noDefaultString") + store.set(defaultEmptyArray, forKey: "defaultEmptyArray") + store.set(defaultChildren, forKey: "defaultChildren") + store.set(defaultChild, forKey: "defaultChild") + store.set(noDefaultChild, forKey: "noDefaultChild") + store.set(noDefaultChildren, forKey: "noDefaultChildren") + + TestDefaults.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestDefaults(key: String) -> TestDefaults? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestDefaults.decode(dictionary) - } - - public func getTestDefaults(key: String) -> [TestDefaults]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestDefaults.decode)) - } - - public func getTestDefaults(key: String) -> [String : TestDefaults]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestDefaults.decode($0) }) - } - - public func getTestDefaults(key: String, defaultValue: TestDefaults) -> TestDefaults { - return getTestDefaults(key) ?? defaultValue - } - - public func getTestDefaults(key: String, defaultValue: [TestDefaults]) -> [TestDefaults] { - return getDecodable(key) ?? defaultValue - } - - public func getTestDefaults(key: String, defaultValue: [String : TestDefaults] - ) -> [String : TestDefaults] { - return getTestDefaults(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestDefaults(value: TestDefaults, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestDefaults(value: [TestDefaults], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestDefaults(value: [String : TestDefaults], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestDefaults(key: String) -> TestDefaults? { - return getValue(key) - } - - public func getTestDefaults(key: String, defaultValue: TestDefaults) -> TestDefaults { - return getTestDefaults(key) ?? defaultValue - } - - public func getTestDefaultss(key: String) -> [TestDefaults]? { - return getValue(key) - } - - public func getTestDefaultss(key: String, defaultValue: [TestDefaults]) -> [TestDefaults] { - return getTestDefaultss(key) ?? defaultValue - } - - public func getTestDefaultsDictionary(key: String) -> [String : TestDefaults]? { - return getValue(key) - } - - public func getTestDefaultsDictionary(key: String, defaultValue: [String : TestDefaults]) -> [String : TestDefaults] { - return getTestDefaultsDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestDefaultsChild.swift b/Tests/Models/TestModels/_TestDefaultsChild.swift index 257e204..33d4bd0 100644 --- a/Tests/Models/TestModels/_TestDefaultsChild.swift +++ b/Tests/Models/TestModels/_TestDefaultsChild.swift @@ -11,125 +11,28 @@ public struct TestDefaultsChild : Model { } -extension TestDefaultsChild : Decodable { +extension TestDefaultsChild { - public static func decode(decoder: Decoder) -> TestDefaultsChild? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestDefaultsChild? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestDefaultsChild.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestDefaultsChild.migrate(source: inStore) guard - let name: String = decoder.decode("name") + let name: String = store.value(forKey: "name") else { return nil } self.name = name - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestDefaultsChild : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(name, "name") - - TestDefaultsChild.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestDefaultsChild { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<6b3afe9f ee54b7fc e944c82f 03ec6569 96cbe98a c3f4b991 13e91cf9 2abea4f9>" - } + public func write(to store: inout Store) { + store.set(name, forKey: "name") - public static func modelVersionHashModifier() -> String? { - return nil + TestDefaultsChild.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestDefaultsChild(key: String) -> TestDefaultsChild? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestDefaultsChild.decode(dictionary) - } - - public func getTestDefaultsChild(key: String) -> [TestDefaultsChild]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestDefaultsChild.decode)) - } - - public func getTestDefaultsChild(key: String) -> [String : TestDefaultsChild]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestDefaultsChild.decode($0) }) - } - - public func getTestDefaultsChild(key: String, defaultValue: TestDefaultsChild) -> TestDefaultsChild { - return getTestDefaultsChild(key) ?? defaultValue - } - - public func getTestDefaultsChild(key: String, defaultValue: [TestDefaultsChild]) -> [TestDefaultsChild] { - return getDecodable(key) ?? defaultValue - } - - public func getTestDefaultsChild(key: String, defaultValue: [String : TestDefaultsChild] - ) -> [String : TestDefaultsChild] { - return getTestDefaultsChild(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestDefaultsChild(value: TestDefaultsChild, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestDefaultsChild(value: [TestDefaultsChild], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestDefaultsChild(value: [String : TestDefaultsChild], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestDefaultsChild(key: String) -> TestDefaultsChild? { - return getValue(key) - } - - public func getTestDefaultsChild(key: String, defaultValue: TestDefaultsChild) -> TestDefaultsChild { - return getTestDefaultsChild(key) ?? defaultValue - } - - public func getTestDefaultsChilds(key: String) -> [TestDefaultsChild]? { - return getValue(key) - } - - public func getTestDefaultsChilds(key: String, defaultValue: [TestDefaultsChild]) -> [TestDefaultsChild] { - return getTestDefaultsChilds(key) ?? defaultValue - } - - public func getTestDefaultsChildDictionary(key: String) -> [String : TestDefaultsChild]? { - return getValue(key) - } - - public func getTestDefaultsChildDictionary(key: String, defaultValue: [String : TestDefaultsChild]) -> [String : TestDefaultsChild] { - return getTestDefaultsChildDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestDictionaryComposition.swift b/Tests/Models/TestModels/_TestDictionaryComposition.swift index 2a423de..ec1f607 100644 --- a/Tests/Models/TestModels/_TestDictionaryComposition.swift +++ b/Tests/Models/TestModels/_TestDictionaryComposition.swift @@ -11,125 +11,28 @@ public struct TestDictionaryComposition : Model { } -extension TestDictionaryComposition : Decodable { +extension TestDictionaryComposition { - public static func decode(decoder: Decoder) -> TestDictionaryComposition? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestDictionaryComposition? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestDictionaryComposition.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestDictionaryComposition.migrate(source: inStore) guard - let employees: [String : Employee] = decoder.decode("employees") + let employees: [String : Employee] = store.value(forKey: "employees") else { return nil } self.employees = employees - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestDictionaryComposition : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(employees, "employees") - - TestDictionaryComposition.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestDictionaryComposition { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<80c11a40 d9a760e9 bfcbb271 8b75d132 c3ac7b52 8d23b6f1 222b79ae b0e4c5f9>" - } + public func write(to store: inout Store) { + store.set(employees, forKey: "employees") - public static func modelVersionHashModifier() -> String? { - return nil + TestDictionaryComposition.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestDictionaryComposition(key: String) -> TestDictionaryComposition? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestDictionaryComposition.decode(dictionary) - } - - public func getTestDictionaryComposition(key: String) -> [TestDictionaryComposition]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestDictionaryComposition.decode)) - } - - public func getTestDictionaryComposition(key: String) -> [String : TestDictionaryComposition]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestDictionaryComposition.decode($0) }) - } - - public func getTestDictionaryComposition(key: String, defaultValue: TestDictionaryComposition) -> TestDictionaryComposition { - return getTestDictionaryComposition(key) ?? defaultValue - } - - public func getTestDictionaryComposition(key: String, defaultValue: [TestDictionaryComposition]) -> [TestDictionaryComposition] { - return getDecodable(key) ?? defaultValue - } - - public func getTestDictionaryComposition(key: String, defaultValue: [String : TestDictionaryComposition] - ) -> [String : TestDictionaryComposition] { - return getTestDictionaryComposition(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestDictionaryComposition(value: TestDictionaryComposition, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestDictionaryComposition(value: [TestDictionaryComposition], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestDictionaryComposition(value: [String : TestDictionaryComposition], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestDictionaryComposition(key: String) -> TestDictionaryComposition? { - return getValue(key) - } - - public func getTestDictionaryComposition(key: String, defaultValue: TestDictionaryComposition) -> TestDictionaryComposition { - return getTestDictionaryComposition(key) ?? defaultValue - } - - public func getTestDictionaryCompositions(key: String) -> [TestDictionaryComposition]? { - return getValue(key) - } - - public func getTestDictionaryCompositions(key: String, defaultValue: [TestDictionaryComposition]) -> [TestDictionaryComposition] { - return getTestDictionaryCompositions(key) ?? defaultValue - } - - public func getTestDictionaryCompositionDictionary(key: String) -> [String : TestDictionaryComposition]? { - return getValue(key) - } - - public func getTestDictionaryCompositionDictionary(key: String, defaultValue: [String : TestDictionaryComposition]) -> [String : TestDictionaryComposition] { - return getTestDictionaryCompositionDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestImmutableOptionalTypes.swift b/Tests/Models/TestModels/_TestImmutableOptionalTypes.swift index dfaa1f6..60a3e7e 100644 --- a/Tests/Models/TestModels/_TestImmutableOptionalTypes.swift +++ b/Tests/Models/TestModels/_TestImmutableOptionalTypes.swift @@ -18,24 +18,23 @@ public struct TestImmutableOptionalTypes : Model { } -extension TestImmutableOptionalTypes : Decodable { +extension TestImmutableOptionalTypes { - public static func decode(decoder: Decoder) -> TestImmutableOptionalTypes? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestImmutableOptionalTypes? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestImmutableOptionalTypes.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestImmutableOptionalTypes.migrate(source: inStore) - let myDate: NSDate? = decoder.decode("myDate") - let myFloat: Float? = decoder.decode("myFloat") - let myBinary: NSData? = decoder.decode("myBinary") - let myDouble: Double? = decoder.decode("myDouble") - let myString: String? = decoder.decode("myString") - let myBoolean: Bool? = decoder.decode("myBoolean") - let myDecimal: NSDecimalNumber? = decoder.decode("myDecimal") - let myInt: Int? = decoder.decode("myInt") + let myDate: NSDate? = store.value(forKey: "myDate") + let myFloat: Float? = store.value(forKey: "myFloat") + let myBinary: NSData? = store.value(forKey: "myBinary") + let myDouble: Double? = store.value(forKey: "myDouble") + let myString: String? = store.value(forKey: "myString") + let myBoolean: Bool? = store.value(forKey: "myBoolean") + let myDecimal: NSDecimalNumber? = store.value(forKey: "myDecimal") + let myInt: Int? = store.value(forKey: "myInt") self.myDate = myDate self.myFloat = myFloat @@ -45,117 +44,21 @@ extension TestImmutableOptionalTypes : Decodable { self.myBoolean = myBoolean self.myDecimal = myDecimal self.myInt = myInt - didFinishDecodingWithDecoder(decoder) - } -} - -extension TestImmutableOptionalTypes : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(myDate, "myDate") - encoder.encode(myFloat, "myFloat") - encoder.encode(myBinary, "myBinary") - encoder.encode(myDouble, "myDouble") - encoder.encode(myString, "myString") - encoder.encode(myBoolean, "myBoolean") - encoder.encode(myDecimal, "myDecimal") - encoder.encode(myInt, "myInt") - - TestImmutableOptionalTypes.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestImmutableOptionalTypes { - - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<8954c691 e621c6bd bad84d7f 4fb9addd 53ed8e45 053f272c fafd2d9b 63de0acc>" + finishReading(from: store) } - public static func modelVersionHashModifier() -> String? { - return nil + public func write(to store: inout Store) { + store.set(myDate, forKey: "myDate") + store.set(myFloat, forKey: "myFloat") + store.set(myBinary, forKey: "myBinary") + store.set(myDouble, forKey: "myDouble") + store.set(myString, forKey: "myString") + store.set(myBoolean, forKey: "myBoolean") + store.set(myDecimal, forKey: "myDecimal") + store.set(myInt, forKey: "myInt") + + TestImmutableOptionalTypes.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestImmutableOptionalTypes(key: String) -> TestImmutableOptionalTypes? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestImmutableOptionalTypes.decode(dictionary) - } - - public func getTestImmutableOptionalTypes(key: String) -> [TestImmutableOptionalTypes]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestImmutableOptionalTypes.decode)) - } - - public func getTestImmutableOptionalTypes(key: String) -> [String : TestImmutableOptionalTypes]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestImmutableOptionalTypes.decode($0) }) - } - - public func getTestImmutableOptionalTypes(key: String, defaultValue: TestImmutableOptionalTypes) -> TestImmutableOptionalTypes { - return getTestImmutableOptionalTypes(key) ?? defaultValue - } - - public func getTestImmutableOptionalTypes(key: String, defaultValue: [TestImmutableOptionalTypes]) -> [TestImmutableOptionalTypes] { - return getDecodable(key) ?? defaultValue - } - - public func getTestImmutableOptionalTypes(key: String, defaultValue: [String : TestImmutableOptionalTypes] - ) -> [String : TestImmutableOptionalTypes] { - return getTestImmutableOptionalTypes(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestImmutableOptionalTypes(value: TestImmutableOptionalTypes, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestImmutableOptionalTypes(value: [TestImmutableOptionalTypes], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestImmutableOptionalTypes(value: [String : TestImmutableOptionalTypes], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestImmutableOptionalTypes(key: String) -> TestImmutableOptionalTypes? { - return getValue(key) - } - - public func getTestImmutableOptionalTypes(key: String, defaultValue: TestImmutableOptionalTypes) -> TestImmutableOptionalTypes { - return getTestImmutableOptionalTypes(key) ?? defaultValue - } - - public func getTestImmutableOptionalTypess(key: String) -> [TestImmutableOptionalTypes]? { - return getValue(key) - } - - public func getTestImmutableOptionalTypess(key: String, defaultValue: [TestImmutableOptionalTypes]) -> [TestImmutableOptionalTypes] { - return getTestImmutableOptionalTypess(key) ?? defaultValue - } - - public func getTestImmutableOptionalTypesDictionary(key: String) -> [String : TestImmutableOptionalTypes]? { - return getValue(key) - } - - public func getTestImmutableOptionalTypesDictionary(key: String, defaultValue: [String : TestImmutableOptionalTypes]) -> [String : TestImmutableOptionalTypes] { - return getTestImmutableOptionalTypesDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestImmutableTypes.swift b/Tests/Models/TestModels/_TestImmutableTypes.swift index e3279e1..a773fc3 100644 --- a/Tests/Models/TestModels/_TestImmutableTypes.swift +++ b/Tests/Models/TestModels/_TestImmutableTypes.swift @@ -18,25 +18,24 @@ public struct TestImmutableTypes : Model { } -extension TestImmutableTypes : Decodable { +extension TestImmutableTypes { - public static func decode(decoder: Decoder) -> TestImmutableTypes? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestImmutableTypes? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestImmutableTypes.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestImmutableTypes.migrate(source: inStore) guard - let myDate: NSDate = decoder.decode("myDate"), - let myFloat: Float = decoder.decode("myFloat"), - let myBinary: NSData = decoder.decode("myBinary"), - let myDouble: Double = decoder.decode("myDouble"), - let myString: String = decoder.decode("myString"), - let myBoolean: Bool = decoder.decode("myBoolean"), - let myDecimal: NSDecimalNumber = decoder.decode("myDecimal"), - let myInt: Int = decoder.decode("myInt") + let myDate: NSDate = store.value(forKey: "myDate"), + let myFloat: Float = store.value(forKey: "myFloat"), + let myBinary: NSData = store.value(forKey: "myBinary"), + let myDouble: Double = store.value(forKey: "myDouble"), + let myString: String = store.value(forKey: "myString"), + let myBoolean: Bool = store.value(forKey: "myBoolean"), + let myDecimal: NSDecimalNumber = store.value(forKey: "myDecimal"), + let myInt: Int = store.value(forKey: "myInt") else { return nil } self.myDate = myDate @@ -47,117 +46,21 @@ extension TestImmutableTypes : Decodable { self.myBoolean = myBoolean self.myDecimal = myDecimal self.myInt = myInt - didFinishDecodingWithDecoder(decoder) - } -} - -extension TestImmutableTypes : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(myDate, "myDate") - encoder.encode(myFloat, "myFloat") - encoder.encode(myBinary, "myBinary") - encoder.encode(myDouble, "myDouble") - encoder.encode(myString, "myString") - encoder.encode(myBoolean, "myBoolean") - encoder.encode(myDecimal, "myDecimal") - encoder.encode(myInt, "myInt") - - TestImmutableTypes.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestImmutableTypes { - - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<053f29fe 14df09a6 b7d222ee 5b611256 e3e3f8d5 0ab9d644 c9a1466a f9293bea>" + finishReading(from: store) } - public static func modelVersionHashModifier() -> String? { - return nil + public func write(to store: inout Store) { + store.set(myDate, forKey: "myDate") + store.set(myFloat, forKey: "myFloat") + store.set(myBinary, forKey: "myBinary") + store.set(myDouble, forKey: "myDouble") + store.set(myString, forKey: "myString") + store.set(myBoolean, forKey: "myBoolean") + store.set(myDecimal, forKey: "myDecimal") + store.set(myInt, forKey: "myInt") + + TestImmutableTypes.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestImmutableTypes(key: String) -> TestImmutableTypes? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestImmutableTypes.decode(dictionary) - } - - public func getTestImmutableTypes(key: String) -> [TestImmutableTypes]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestImmutableTypes.decode)) - } - - public func getTestImmutableTypes(key: String) -> [String : TestImmutableTypes]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestImmutableTypes.decode($0) }) - } - - public func getTestImmutableTypes(key: String, defaultValue: TestImmutableTypes) -> TestImmutableTypes { - return getTestImmutableTypes(key) ?? defaultValue - } - - public func getTestImmutableTypes(key: String, defaultValue: [TestImmutableTypes]) -> [TestImmutableTypes] { - return getDecodable(key) ?? defaultValue - } - - public func getTestImmutableTypes(key: String, defaultValue: [String : TestImmutableTypes] - ) -> [String : TestImmutableTypes] { - return getTestImmutableTypes(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestImmutableTypes(value: TestImmutableTypes, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestImmutableTypes(value: [TestImmutableTypes], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestImmutableTypes(value: [String : TestImmutableTypes], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestImmutableTypes(key: String) -> TestImmutableTypes? { - return getValue(key) - } - - public func getTestImmutableTypes(key: String, defaultValue: TestImmutableTypes) -> TestImmutableTypes { - return getTestImmutableTypes(key) ?? defaultValue - } - - public func getTestImmutableTypess(key: String) -> [TestImmutableTypes]? { - return getValue(key) - } - - public func getTestImmutableTypess(key: String, defaultValue: [TestImmutableTypes]) -> [TestImmutableTypes] { - return getTestImmutableTypess(key) ?? defaultValue - } - - public func getTestImmutableTypesDictionary(key: String) -> [String : TestImmutableTypes]? { - return getValue(key) - } - - public func getTestImmutableTypesDictionary(key: String, defaultValue: [String : TestImmutableTypes]) -> [String : TestImmutableTypes] { - return getTestImmutableTypesDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestMigrationV1.swift b/Tests/Models/TestModels/_TestMigrationV1.swift deleted file mode 100644 index cce72fb..0000000 --- a/Tests/Models/TestModels/_TestMigrationV1.swift +++ /dev/null @@ -1,60 +0,0 @@ -/************************************************ - - WARNING: MACHINE GENERATED FILE - - ************************************************/ -import Foundation -import State - -public struct TestMigrationV1: Model, Migratable { - public var name: String - - public init(name: String) { - - self.name = name - - } -} - -extension TestMigrationV1 : Decodable { - - public static func decode(decoder: Decoder) -> TestMigrationV1? { - return self.init(decoder: decoder) - } - - public init?(decoder d: Decoder) { - let decoder = TestMigrationV1.performMigrationIfNeeded(d) - - guard let name : String = decoder.decode("name") else { return nil } - self.name = name - didFinishDecodingWithDecoder(decoder) - - } -} - -extension TestMigrationV1 : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(name, "name") - - TestMigrationV1.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestMigrationV1 { - /** - These are provided from the data model designer - and can be used to determine if the model is - a different version. - */ - public static var modelVersionHash: String { - return "" - } - - public static var modelVersionHashModifier: String? { - return "1.0" - } -} - diff --git a/Tests/Models/TestModels/_TestMigrationV2.swift b/Tests/Models/TestModels/_TestMigrationV2.swift index 8319958..9ecbbb1 100644 --- a/Tests/Models/TestModels/_TestMigrationV2.swift +++ b/Tests/Models/TestModels/_TestMigrationV2.swift @@ -12,129 +12,32 @@ public struct TestMigrationV2 : Model { } -extension TestMigrationV2 : Decodable { +extension TestMigrationV2 { - public static func decode(decoder: Decoder) -> TestMigrationV2? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestMigrationV2? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestMigrationV2.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestMigrationV2.migrate(source: inStore) guard - let name: String = decoder.decode("name") + let name: String = store.value(forKey: "name") else { return nil } - let age: Int? = decoder.decode("age") + let age: Int? = store.value(forKey: "age") self.age = age self.name = name - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestMigrationV2 : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(age, "age") - encoder.encode(name, "name") - - TestMigrationV2.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestMigrationV2 { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "" - } + public func write(to store: inout Store) { + store.set(age, forKey: "age") + store.set(name, forKey: "name") - public static func modelVersionHashModifier() -> String? { - return "2.0" + TestMigrationV2.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestMigrationV2(key: String) -> TestMigrationV2? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestMigrationV2.decode(dictionary) - } - - public func getTestMigrationV2(key: String) -> [TestMigrationV2]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestMigrationV2.decode)) - } - - public func getTestMigrationV2(key: String) -> [String : TestMigrationV2]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestMigrationV2.decode($0) }) - } - - public func getTestMigrationV2(key: String, defaultValue: TestMigrationV2) -> TestMigrationV2 { - return getTestMigrationV2(key) ?? defaultValue - } - - public func getTestMigrationV2(key: String, defaultValue: [TestMigrationV2]) -> [TestMigrationV2] { - return getDecodable(key) ?? defaultValue - } - - public func getTestMigrationV2(key: String, defaultValue: [String : TestMigrationV2] - ) -> [String : TestMigrationV2] { - return getTestMigrationV2(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestMigrationV2(value: TestMigrationV2, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestMigrationV2(value: [TestMigrationV2], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestMigrationV2(value: [String : TestMigrationV2], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestMigrationV2(key: String) -> TestMigrationV2? { - return getValue(key) - } - - public func getTestMigrationV2(key: String, defaultValue: TestMigrationV2) -> TestMigrationV2 { - return getTestMigrationV2(key) ?? defaultValue - } - - public func getTestMigrationV2s(key: String) -> [TestMigrationV2]? { - return getValue(key) - } - - public func getTestMigrationV2s(key: String, defaultValue: [TestMigrationV2]) -> [TestMigrationV2] { - return getTestMigrationV2s(key) ?? defaultValue - } - - public func getTestMigrationV2Dictionary(key: String) -> [String : TestMigrationV2]? { - return getValue(key) - } - - public func getTestMigrationV2Dictionary(key: String, defaultValue: [String : TestMigrationV2]) -> [String : TestMigrationV2] { - return getTestMigrationV2Dictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestOptionalTypes.swift b/Tests/Models/TestModels/_TestOptionalTypes.swift index fdf591e..14a8542 100644 --- a/Tests/Models/TestModels/_TestOptionalTypes.swift +++ b/Tests/Models/TestModels/_TestOptionalTypes.swift @@ -18,24 +18,23 @@ public struct TestOptionalTypes : Model { } -extension TestOptionalTypes : Decodable { +extension TestOptionalTypes { - public static func decode(decoder: Decoder) -> TestOptionalTypes? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestOptionalTypes? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestOptionalTypes.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestOptionalTypes.migrate(source: inStore) - let myDate: NSDate? = decoder.decode("myDate") - let myFloat: Float? = decoder.decode("myFloat") - let myBinary: NSData? = decoder.decode("myBinary") - let myDouble: Double? = decoder.decode("myDouble") - let myString: String? = decoder.decode("myString") - let myBoolean: Bool? = decoder.decode("myBoolean") - let myDecimal: NSDecimalNumber? = decoder.decode("myDecimal") - let myInt: Int? = decoder.decode("myInt") + let myDate: NSDate? = store.value(forKey: "myDate") + let myFloat: Float? = store.value(forKey: "myFloat") + let myBinary: NSData? = store.value(forKey: "myBinary") + let myDouble: Double? = store.value(forKey: "myDouble") + let myString: String? = store.value(forKey: "myString") + let myBoolean: Bool? = store.value(forKey: "myBoolean") + let myDecimal: NSDecimalNumber? = store.value(forKey: "myDecimal") + let myInt: Int? = store.value(forKey: "myInt") self.myDate = myDate self.myFloat = myFloat @@ -45,117 +44,21 @@ extension TestOptionalTypes : Decodable { self.myBoolean = myBoolean self.myDecimal = myDecimal self.myInt = myInt - didFinishDecodingWithDecoder(decoder) - } -} - -extension TestOptionalTypes : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(myDate, "myDate") - encoder.encode(myFloat, "myFloat") - encoder.encode(myBinary, "myBinary") - encoder.encode(myDouble, "myDouble") - encoder.encode(myString, "myString") - encoder.encode(myBoolean, "myBoolean") - encoder.encode(myDecimal, "myDecimal") - encoder.encode(myInt, "myInt") - - TestOptionalTypes.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestOptionalTypes { - - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<9f253c6d 6eee6daf 0cb47189 ec638d50 fa91dd34 ba49773b 92c39ed1 0d3546a3>" + finishReading(from: store) } - public static func modelVersionHashModifier() -> String? { - return nil + public func write(to store: inout Store) { + store.set(myDate, forKey: "myDate") + store.set(myFloat, forKey: "myFloat") + store.set(myBinary, forKey: "myBinary") + store.set(myDouble, forKey: "myDouble") + store.set(myString, forKey: "myString") + store.set(myBoolean, forKey: "myBoolean") + store.set(myDecimal, forKey: "myDecimal") + store.set(myInt, forKey: "myInt") + + TestOptionalTypes.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestOptionalTypes(key: String) -> TestOptionalTypes? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestOptionalTypes.decode(dictionary) - } - - public func getTestOptionalTypes(key: String) -> [TestOptionalTypes]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestOptionalTypes.decode)) - } - - public func getTestOptionalTypes(key: String) -> [String : TestOptionalTypes]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestOptionalTypes.decode($0) }) - } - - public func getTestOptionalTypes(key: String, defaultValue: TestOptionalTypes) -> TestOptionalTypes { - return getTestOptionalTypes(key) ?? defaultValue - } - - public func getTestOptionalTypes(key: String, defaultValue: [TestOptionalTypes]) -> [TestOptionalTypes] { - return getDecodable(key) ?? defaultValue - } - - public func getTestOptionalTypes(key: String, defaultValue: [String : TestOptionalTypes] - ) -> [String : TestOptionalTypes] { - return getTestOptionalTypes(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestOptionalTypes(value: TestOptionalTypes, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestOptionalTypes(value: [TestOptionalTypes], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestOptionalTypes(value: [String : TestOptionalTypes], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestOptionalTypes(key: String) -> TestOptionalTypes? { - return getValue(key) - } - - public func getTestOptionalTypes(key: String, defaultValue: TestOptionalTypes) -> TestOptionalTypes { - return getTestOptionalTypes(key) ?? defaultValue - } - - public func getTestOptionalTypess(key: String) -> [TestOptionalTypes]? { - return getValue(key) - } - - public func getTestOptionalTypess(key: String, defaultValue: [TestOptionalTypes]) -> [TestOptionalTypes] { - return getTestOptionalTypess(key) ?? defaultValue - } - - public func getTestOptionalTypesDictionary(key: String) -> [String : TestOptionalTypes]? { - return getValue(key) - } - - public func getTestOptionalTypesDictionary(key: String, defaultValue: [String : TestOptionalTypes]) -> [String : TestOptionalTypes] { - return getTestOptionalTypesDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestOverrideType.swift b/Tests/Models/TestModels/_TestOverrideType.swift index 3091bb3..46e2004 100644 --- a/Tests/Models/TestModels/_TestOverrideType.swift +++ b/Tests/Models/TestModels/_TestOverrideType.swift @@ -12,126 +12,29 @@ public struct TestOverrideType : Model { } -extension TestOverrideType : Decodable { +extension TestOverrideType { - public static func decode(decoder: Decoder) -> TestOverrideType? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestOverrideType? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestOverrideType.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestOverrideType.migrate(source: inStore) - let myURL: NSURL? = decoder.decode("myURL") - let myArrayOfString: [String]? = decoder.decode("myArrayOfString") + let myURL: NSURL? = store.value(forKey: "myURL") + let myArrayOfString: [String]? = store.value(forKey: "myArrayOfString") self.myURL = myURL self.myArrayOfString = myArrayOfString - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestOverrideType : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(myURL, "myURL") - encoder.encode(myArrayOfString, "myArrayOfString") - - TestOverrideType.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestOverrideType { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<1b2022d4 1d237610 f72665c6 67dea8a1 a68750de df8625c3 d9495017 916e62c6>" - } + public func write(to store: inout Store) { + store.set(myURL, forKey: "myURL") + store.set(myArrayOfString, forKey: "myArrayOfString") - public static func modelVersionHashModifier() -> String? { - return nil + TestOverrideType.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestOverrideType(key: String) -> TestOverrideType? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestOverrideType.decode(dictionary) - } - - public func getTestOverrideType(key: String) -> [TestOverrideType]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestOverrideType.decode)) - } - - public func getTestOverrideType(key: String) -> [String : TestOverrideType]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestOverrideType.decode($0) }) - } - - public func getTestOverrideType(key: String, defaultValue: TestOverrideType) -> TestOverrideType { - return getTestOverrideType(key) ?? defaultValue - } - - public func getTestOverrideType(key: String, defaultValue: [TestOverrideType]) -> [TestOverrideType] { - return getDecodable(key) ?? defaultValue - } - - public func getTestOverrideType(key: String, defaultValue: [String : TestOverrideType] - ) -> [String : TestOverrideType] { - return getTestOverrideType(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestOverrideType(value: TestOverrideType, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestOverrideType(value: [TestOverrideType], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestOverrideType(value: [String : TestOverrideType], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestOverrideType(key: String) -> TestOverrideType? { - return getValue(key) - } - - public func getTestOverrideType(key: String, defaultValue: TestOverrideType) -> TestOverrideType { - return getTestOverrideType(key) ?? defaultValue - } - - public func getTestOverrideTypes(key: String) -> [TestOverrideType]? { - return getValue(key) - } - - public func getTestOverrideTypes(key: String, defaultValue: [TestOverrideType]) -> [TestOverrideType] { - return getTestOverrideTypes(key) ?? defaultValue - } - - public func getTestOverrideTypeDictionary(key: String) -> [String : TestOverrideType]? { - return getValue(key) - } - - public func getTestOverrideTypeDictionary(key: String, defaultValue: [String : TestOverrideType]) -> [String : TestOverrideType] { - return getTestOverrideTypeDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestParentProtocol.swift b/Tests/Models/TestModels/_TestParentProtocol.swift index d1f5e15..a7cb1c8 100644 --- a/Tests/Models/TestModels/_TestParentProtocol.swift +++ b/Tests/Models/TestModels/_TestParentProtocol.swift @@ -12,50 +12,69 @@ public protocol TestParentProtocol : Model { } -func decodeTestParentProtocol(data: AnyObject?) -> TestParentProtocol? { - - if let data = data as? [String : AnyObject] { - let decoder = Decoder(data: data) - guard let dataTypeKey = data["TestParentProtocol"] as? String else { return nil } - if let t = decoder.TestParentProtocolTypeForKey(dataTypeKey) { - return t.decode(decoder) - } - return nil - } - return nil -} +extension Store { -// Mark: Decoding + public func value(forKey key: String) -> TestParentProtocol? { + guard let data : [String : AnyObject] = value(forKey: key) else { return nil } + return _decodeTestParentProtocol(data: data) + } -public extension DecoderType { + public func value(forKey key: String) -> [TestParentProtocol]? { + guard let arrayv : [[String : AnyObject]] = value(forKey: key) else { return nil } + return sequence(arrayv.map { _decodeTestParentProtocol(data:$0) }) + } - public func decodeTestParentProtocol(key: String) -> TestParentProtocol? { - let data = self.data - let d = data[key] as? [String : AnyObject] - return d.flatMap(_decodeTestParentProtocol) + public func value(forKey key: String) -> [String : TestParentProtocol]? { + guard let data : [String : [String : AnyObject]] = value(forKey: key) else { return nil } + return sequence(data.map { self._decodeTestParentProtocol(data:$0) }) } - public func decodeTestParentProtocol(key: String) -> [TestParentProtocol]? { - let data = self.data - let d = data[key] as? [[String : AnyObject]] - return d.flatMap { sequence($0.map(_decodeTestParentProtocol)) } + public mutating func set(_ value: TestParentProtocol?, forKey key: String) { + guard let value = value else { return } + var vstore = Store() + value.write(to: &vstore) + set(vstore.data, forKey: key) } - public func decodeTestParentProtocol(key: String) -> [String : TestParentProtocol]? { - let data = self.data - let d = data[key] as? [String : [String : AnyObject]] - return d.flatMap { sequence($0.map(_decodeTestParentProtocol)) } + /// Add or update the value at key. + public mutating func set(_ value: [TestParentProtocol]?, forKey key: String) { + guard let value = value else { return } + + let data = value.reduce([[String : AnyObject]](), combine: { (data, value) -> [[String: AnyObject]] in + var vstore = Store() + var vdata = data + value.write(to: &vstore ) + vdata.append(vstore.data) + return vdata + }) + + set(data , forKey: key) + } + + /// Add or update the value at key. + public mutating func set(_ value: [String : TestParentProtocol]?, forKey key: String) { + + guard let value = value else { return } + let data = value.reduce([String : [String : AnyObject]](), combine: { (data, element) -> [String : [String : AnyObject]] in + var vstore = Store() + var vdata = data + element.value.write(to: &vstore) + vdata[element.key] = vstore.data + return vdata + }) + + set(data, forKey: key) } private func _decodeTestParentProtocol(data: [String : AnyObject]) -> TestParentProtocol? { - guard let dataTypeKey = data["TestParentProtocol"] as? String else { return nil } - if let t = TestParentProtocolTypeForKey(dataTypeKey) { - return t.decode(Decoder(data: data)) + guard let typeKey = data["TestParentProtocol"] as? String else { return nil } + if let t = TestParentProtocolType(forKey: typeKey) { + return t.read(from: Store(data: data)) } return nil } - private func TestParentProtocolTypeForKey(key: String) -> TestParentProtocol.Type? { + private func TestParentProtocolType(forKey key: String) -> TestParentProtocol.Type? { switch key { case "TestProtocolConformer2": @@ -69,147 +88,3 @@ public extension DecoderType { } } } - -// Mark: Encoding - -public extension EncoderType { - - public func encode(element: TestParentProtocol?, _ key: String) { - guard let element = element else { return } - self.data[key] = element.encode() - } - - public func encode(element: [TestParentProtocol]?, _ key: String) { - guard let element = element else { return } - self.data[key] = element.map { $0.encode() } - } - - public func encode(element: [String : TestParentProtocol]?, _ key: String) { - guard let element = element else { return } - self.data[key] = element.map { $0.encode() } - } -} - -extension NSUserDefaults { - -//****************************************************************************// -// MARK: NSUserDefault Getters -//****************************************************************************// - - public func getTestParentProtocol(key: String) -> TestParentProtocol? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return decodeTestParentProtocol(dictionary) - } - - public func getTestParentProtocol(key: String) -> [TestParentProtocol]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(decodeTestParentProtocol)) - } - - public func getTestParentProtocol(key: String) -> [String : TestParentProtocol]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { decodeTestParentProtocol($0) }) - } - - public func getTestParentProtocol(key: String, defaultValue: TestParentProtocol) -> TestParentProtocol { - return getTestParentProtocol(key) ?? defaultValue - } - - public func getTestParentProtocol(key: String, defaultValue: [TestParentProtocol]) -> [TestParentProtocol] { - return getTestParentProtocol(key) ?? defaultValue - } - - public func getTestParentProtocol(key: String, defaultValue: [String : TestParentProtocol] - ) -> [String : TestParentProtocol] { - return getTestParentProtocol(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestParentProtocol(value: TestParentProtocol, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestParentProtocol(value: [TestParentProtocol], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestParentProtocol(value: [String : TestParentProtocol], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - public func getTestParentProtocol(key: String) -> TestParentProtocol? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decodeTestParentProtocol(keys.valueName) - } - else { - return nil - } - } - - public func getTestParentProtocol(key: String, defaultValue: TestParentProtocol) -> TestParentProtocol { - return getTestParentProtocol(key) ?? defaultValue - } - - public func getTestParentProtocols(key: String) -> [TestParentProtocol]? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decodeTestParentProtocol(keys.valueName) - } - else { - return nil - } - } - - public func getTestParentProtocols(key: String, defaultValue: [TestParentProtocol]) -> [TestParentProtocol] { - return getTestParentProtocols(key) ?? defaultValue - } - - public func getTestParentProtocolDictionary(key: String) -> [String : TestParentProtocol]? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decodeTestParentProtocol(keys.valueName) - } - else { - return nil - } - } - - public func getTestParentProtocolDictionary(key: String, defaultValue: [String : TestParentProtocol]) -> [String : TestParentProtocol] { - return getTestParentProtocolDictionary(key) ?? defaultValue - } - - public func setValue(value: TestParentProtocol, forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - - public func setValue(value: [TestParentProtocol], forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - - public func setValue(value: [String : TestParentProtocol], forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - -} - diff --git a/Tests/Models/TestModels/_TestProtocol.swift b/Tests/Models/TestModels/_TestProtocol.swift index ae20778..22a387f 100644 --- a/Tests/Models/TestModels/_TestProtocol.swift +++ b/Tests/Models/TestModels/_TestProtocol.swift @@ -18,50 +18,69 @@ public protocol TestProtocol : TestParentProtocol { } -func decodeTestProtocol(data: AnyObject?) -> TestProtocol? { - - if let data = data as? [String : AnyObject] { - let decoder = Decoder(data: data) - guard let dataTypeKey = data["TestProtocol"] as? String else { return nil } - if let t = decoder.TestProtocolTypeForKey(dataTypeKey) { - return t.decode(decoder) - } - return nil - } - return nil -} +extension Store { -// Mark: Decoding + public func value(forKey key: String) -> TestProtocol? { + guard let data : [String : AnyObject] = value(forKey: key) else { return nil } + return _decodeTestProtocol(data: data) + } -public extension DecoderType { + public func value(forKey key: String) -> [TestProtocol]? { + guard let arrayv : [[String : AnyObject]] = value(forKey: key) else { return nil } + return sequence(arrayv.map { _decodeTestProtocol(data:$0) }) + } - public func decodeTestProtocol(key: String) -> TestProtocol? { - let data = self.data - let d = data[key] as? [String : AnyObject] - return d.flatMap(_decodeTestProtocol) + public func value(forKey key: String) -> [String : TestProtocol]? { + guard let data : [String : [String : AnyObject]] = value(forKey: key) else { return nil } + return sequence(data.map { self._decodeTestProtocol(data:$0) }) } - public func decodeTestProtocol(key: String) -> [TestProtocol]? { - let data = self.data - let d = data[key] as? [[String : AnyObject]] - return d.flatMap { sequence($0.map(_decodeTestProtocol)) } + public mutating func set(_ value: TestProtocol?, forKey key: String) { + guard let value = value else { return } + var vstore = Store() + value.write(to: &vstore) + set(vstore.data, forKey: key) } - public func decodeTestProtocol(key: String) -> [String : TestProtocol]? { - let data = self.data - let d = data[key] as? [String : [String : AnyObject]] - return d.flatMap { sequence($0.map(_decodeTestProtocol)) } + /// Add or update the value at key. + public mutating func set(_ value: [TestProtocol]?, forKey key: String) { + guard let value = value else { return } + + let data = value.reduce([[String : AnyObject]](), combine: { (data, value) -> [[String: AnyObject]] in + var vstore = Store() + var vdata = data + value.write(to: &vstore ) + vdata.append(vstore.data) + return vdata + }) + + set(data , forKey: key) + } + + /// Add or update the value at key. + public mutating func set(_ value: [String : TestProtocol]?, forKey key: String) { + + guard let value = value else { return } + let data = value.reduce([String : [String : AnyObject]](), combine: { (data, element) -> [String : [String : AnyObject]] in + var vstore = Store() + var vdata = data + element.value.write(to: &vstore) + vdata[element.key] = vstore.data + return vdata + }) + + set(data, forKey: key) } private func _decodeTestProtocol(data: [String : AnyObject]) -> TestProtocol? { - guard let dataTypeKey = data["TestParentProtocol"] as? String else { return nil } - if let t = TestProtocolTypeForKey(dataTypeKey) { - return t.decode(Decoder(data: data)) + guard let typeKey = data["TestParentProtocol"] as? String else { return nil } + if let t = TestProtocolType(forKey: typeKey) { + return t.read(from: Store(data: data)) } return nil } - private func TestProtocolTypeForKey(key: String) -> TestProtocol.Type? { + private func TestProtocolType(forKey key: String) -> TestProtocol.Type? { switch key { case "TestProtocolConformer": @@ -72,147 +91,3 @@ public extension DecoderType { } } } - -// Mark: Encoding - -public extension EncoderType { - - public func encode(element: TestProtocol?, _ key: String) { - guard let element = element else { return } - self.data[key] = element.encode() - } - - public func encode(element: [TestProtocol]?, _ key: String) { - guard let element = element else { return } - self.data[key] = element.map { $0.encode() } - } - - public func encode(element: [String : TestProtocol]?, _ key: String) { - guard let element = element else { return } - self.data[key] = element.map { $0.encode() } - } -} - -extension NSUserDefaults { - -//****************************************************************************// -// MARK: NSUserDefault Getters -//****************************************************************************// - - public func getTestProtocol(key: String) -> TestProtocol? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return decodeTestProtocol(dictionary) - } - - public func getTestProtocol(key: String) -> [TestProtocol]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(decodeTestProtocol)) - } - - public func getTestProtocol(key: String) -> [String : TestProtocol]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { decodeTestProtocol($0) }) - } - - public func getTestProtocol(key: String, defaultValue: TestProtocol) -> TestProtocol { - return getTestProtocol(key) ?? defaultValue - } - - public func getTestProtocol(key: String, defaultValue: [TestProtocol]) -> [TestProtocol] { - return getTestProtocol(key) ?? defaultValue - } - - public func getTestProtocol(key: String, defaultValue: [String : TestProtocol] - ) -> [String : TestProtocol] { - return getTestProtocol(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestProtocol(value: TestProtocol, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestProtocol(value: [TestProtocol], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestProtocol(value: [String : TestProtocol], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - public func getTestProtocol(key: String) -> TestProtocol? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decodeTestProtocol(keys.valueName) - } - else { - return nil - } - } - - public func getTestProtocol(key: String, defaultValue: TestProtocol) -> TestProtocol { - return getTestProtocol(key) ?? defaultValue - } - - public func getTestProtocols(key: String) -> [TestProtocol]? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decodeTestProtocol(keys.valueName) - } - else { - return nil - } - } - - public func getTestProtocols(key: String, defaultValue: [TestProtocol]) -> [TestProtocol] { - return getTestProtocols(key) ?? defaultValue - } - - public func getTestProtocolDictionary(key: String) -> [String : TestProtocol]? { - let keys = seperateKeypath(key) - let targetKey = keys.keypath == nil ? self : getKey(keys.keypath!) - - if let targetKey = targetKey { - return targetKey.decodeTestProtocol(keys.valueName) - } - else { - return nil - } - } - - public func getTestProtocolDictionary(key: String, defaultValue: [String : TestProtocol]) -> [String : TestProtocol] { - return getTestProtocolDictionary(key) ?? defaultValue - } - - public func setValue(value: TestProtocol, forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - - public func setValue(value: [TestProtocol], forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - - public func setValue(value: [String : TestProtocol], forKey: String) { - let keys = seperateKeypath(forKey) - - let targetKey = keys.keypath == nil ? self : addKey(keys.keypath!) - targetKey.encode(value, keys.valueName) - } - -} - diff --git a/Tests/Models/TestModels/_TestProtocolConformer.swift b/Tests/Models/TestModels/_TestProtocolConformer.swift index 9f15cf4..3d72906 100644 --- a/Tests/Models/TestModels/_TestProtocolConformer.swift +++ b/Tests/Models/TestModels/_TestProtocolConformer.swift @@ -16,141 +16,43 @@ public struct TestProtocolConformer : TestProtocol { } -extension TestProtocolConformer : Decodable { +extension TestProtocolConformer { - public static func decode(decoder: Decoder) -> TestProtocolConformer? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestProtocolConformer? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestProtocolConformer.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestProtocolConformer.migrate(source: inStore) guard - let ss_number: String = decoder.decode("ss_number"), - let employee: Employee = decoder.decode("employee"), - let children: [TestChild] = decoder.decode("children") + let ss_number: String = store.value(forKey: "ss_number"), + let employee: Employee = store.value(forKey: "employee"), + let children: [TestChild] = store.value(forKey: "children") else { return nil } - let age: Int? = decoder.decode("age") + let age: Int? = store.value(forKey: "age") - let isReady: Bool? = decoder.decode("isReady") + let isReady: Bool? = store.value(forKey: "isReady") self.age = age self.ss_number = ss_number self.isReady = isReady self.employee = employee self.children = children - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestProtocolConformer : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(age, "age") - encoder.encode(ss_number, "ss_number") - encoder.encode(isReady, "isReady") - encoder.encode(employee, "employee") - encoder.encode(children, "children") - - encoder.encode("TestProtocolConformer", "TestParentProtocol") - - TestProtocolConformer.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestProtocolConformer { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "" - } + public func write(to store: inout Store) { + store.set(age, forKey: "age") + store.set(ss_number, forKey: "ss_number") + store.set(isReady, forKey: "isReady") + store.set(employee, forKey: "employee") + store.set(children, forKey: "children") - public static func modelVersionHashModifier() -> String? { - return nil + store.set("TestProtocolConformer", forKey: "TestParentProtocol") + TestProtocolConformer.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestProtocolConformer(key: String) -> TestProtocolConformer? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestProtocolConformer.decode(dictionary) - } - - public func getTestProtocolConformer(key: String) -> [TestProtocolConformer]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestProtocolConformer.decode)) - } - - public func getTestProtocolConformer(key: String) -> [String : TestProtocolConformer]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestProtocolConformer.decode($0) }) - } - - public func getTestProtocolConformer(key: String, defaultValue: TestProtocolConformer) -> TestProtocolConformer { - return getTestProtocolConformer(key) ?? defaultValue - } - - public func getTestProtocolConformer(key: String, defaultValue: [TestProtocolConformer]) -> [TestProtocolConformer] { - return getDecodable(key) ?? defaultValue - } - - public func getTestProtocolConformer(key: String, defaultValue: [String : TestProtocolConformer] - ) -> [String : TestProtocolConformer] { - return getTestProtocolConformer(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestProtocolConformer(value: TestProtocolConformer, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestProtocolConformer(value: [TestProtocolConformer], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestProtocolConformer(value: [String : TestProtocolConformer], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestProtocolConformer(key: String) -> TestProtocolConformer? { - return getValue(key) - } - - public func getTestProtocolConformer(key: String, defaultValue: TestProtocolConformer) -> TestProtocolConformer { - return getTestProtocolConformer(key) ?? defaultValue - } - - public func getTestProtocolConformers(key: String) -> [TestProtocolConformer]? { - return getValue(key) - } - - public func getTestProtocolConformers(key: String, defaultValue: [TestProtocolConformer]) -> [TestProtocolConformer] { - return getTestProtocolConformers(key) ?? defaultValue - } - - public func getTestProtocolConformerDictionary(key: String) -> [String : TestProtocolConformer]? { - return getValue(key) - } - - public func getTestProtocolConformerDictionary(key: String, defaultValue: [String : TestProtocolConformer]) -> [String : TestProtocolConformer] { - return getTestProtocolConformerDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestProtocolConformer2.swift b/Tests/Models/TestModels/_TestProtocolConformer2.swift index 7821e16..b029157 100644 --- a/Tests/Models/TestModels/_TestProtocolConformer2.swift +++ b/Tests/Models/TestModels/_TestProtocolConformer2.swift @@ -12,130 +12,32 @@ public struct TestProtocolConformer2 : TestParentProtocol { } -extension TestProtocolConformer2 : Decodable { +extension TestProtocolConformer2 { - public static func decode(decoder: Decoder) -> TestProtocolConformer2? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestProtocolConformer2? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestProtocolConformer2.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestProtocolConformer2.migrate(source: inStore) guard - let name: String = decoder.decode("name"), - let ss_number: String = decoder.decode("ss_number") + let name: String = store.value(forKey: "name"), + let ss_number: String = store.value(forKey: "ss_number") else { return nil } self.name = name self.ss_number = ss_number - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestProtocolConformer2 : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(name, "name") - encoder.encode(ss_number, "ss_number") - - encoder.encode("TestProtocolConformer2", "TestParentProtocol") - - TestProtocolConformer2.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestProtocolConformer2 { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "" - } + public func write(to store: inout Store) { + store.set(name, forKey: "name") + store.set(ss_number, forKey: "ss_number") - public static func modelVersionHashModifier() -> String? { - return nil + store.set("TestProtocolConformer2", forKey: "TestParentProtocol") + TestProtocolConformer2.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestProtocolConformer2(key: String) -> TestProtocolConformer2? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestProtocolConformer2.decode(dictionary) - } - - public func getTestProtocolConformer2(key: String) -> [TestProtocolConformer2]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestProtocolConformer2.decode)) - } - - public func getTestProtocolConformer2(key: String) -> [String : TestProtocolConformer2]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestProtocolConformer2.decode($0) }) - } - - public func getTestProtocolConformer2(key: String, defaultValue: TestProtocolConformer2) -> TestProtocolConformer2 { - return getTestProtocolConformer2(key) ?? defaultValue - } - - public func getTestProtocolConformer2(key: String, defaultValue: [TestProtocolConformer2]) -> [TestProtocolConformer2] { - return getDecodable(key) ?? defaultValue - } - - public func getTestProtocolConformer2(key: String, defaultValue: [String : TestProtocolConformer2] - ) -> [String : TestProtocolConformer2] { - return getTestProtocolConformer2(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestProtocolConformer2(value: TestProtocolConformer2, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestProtocolConformer2(value: [TestProtocolConformer2], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestProtocolConformer2(value: [String : TestProtocolConformer2], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestProtocolConformer2(key: String) -> TestProtocolConformer2? { - return getValue(key) - } - - public func getTestProtocolConformer2(key: String, defaultValue: TestProtocolConformer2) -> TestProtocolConformer2 { - return getTestProtocolConformer2(key) ?? defaultValue - } - - public func getTestProtocolConformer2s(key: String) -> [TestProtocolConformer2]? { - return getValue(key) - } - - public func getTestProtocolConformer2s(key: String, defaultValue: [TestProtocolConformer2]) -> [TestProtocolConformer2] { - return getTestProtocolConformer2s(key) ?? defaultValue - } - - public func getTestProtocolConformer2Dictionary(key: String) -> [String : TestProtocolConformer2]? { - return getValue(key) - } - - public func getTestProtocolConformer2Dictionary(key: String, defaultValue: [String : TestProtocolConformer2]) -> [String : TestProtocolConformer2] { - return getTestProtocolConformer2Dictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestProtocolContainter.swift b/Tests/Models/TestModels/_TestProtocolContainter.swift index 2ae66b2..2c235c4 100644 --- a/Tests/Models/TestModels/_TestProtocolContainter.swift +++ b/Tests/Models/TestModels/_TestProtocolContainter.swift @@ -13,131 +13,34 @@ public struct TestProtocolContainter : Model { } -extension TestProtocolContainter : Decodable { +extension TestProtocolContainter { - public static func decode(decoder: Decoder) -> TestProtocolContainter? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestProtocolContainter? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestProtocolContainter.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestProtocolContainter.migrate(source: inStore) guard - let testProtocol: TestProtocol = decoder.decodeTestProtocol("testProtocol"), - let testProtocols: [TestParentProtocol] = decoder.decodeTestParentProtocol("testProtocols"), - let testProtocolsDict: [String : TestParentProtocol] = decoder.decodeTestParentProtocol("testProtocolsDict") + let testProtocol: TestProtocol = store.value(forKey: "testProtocol"), + let testProtocols: [TestParentProtocol] = store.value(forKey: "testProtocols"), + let testProtocolsDict: [String : TestParentProtocol] = store.value(forKey: "testProtocolsDict") else { return nil } self.testProtocol = testProtocol self.testProtocols = testProtocols self.testProtocolsDict = testProtocolsDict - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestProtocolContainter : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(testProtocol, "testProtocol") - encoder.encode(testProtocols, "testProtocols") - encoder.encode(testProtocolsDict, "testProtocolsDict") - - TestProtocolContainter.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestProtocolContainter { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "" - } + public func write(to store: inout Store) { + store.set(testProtocol, forKey: "testProtocol") + store.set(testProtocols, forKey: "testProtocols") + store.set(testProtocolsDict, forKey: "testProtocolsDict") - public static func modelVersionHashModifier() -> String? { - return nil + TestProtocolContainter.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestProtocolContainter(key: String) -> TestProtocolContainter? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestProtocolContainter.decode(dictionary) - } - - public func getTestProtocolContainter(key: String) -> [TestProtocolContainter]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestProtocolContainter.decode)) - } - - public func getTestProtocolContainter(key: String) -> [String : TestProtocolContainter]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestProtocolContainter.decode($0) }) - } - - public func getTestProtocolContainter(key: String, defaultValue: TestProtocolContainter) -> TestProtocolContainter { - return getTestProtocolContainter(key) ?? defaultValue - } - - public func getTestProtocolContainter(key: String, defaultValue: [TestProtocolContainter]) -> [TestProtocolContainter] { - return getDecodable(key) ?? defaultValue - } - - public func getTestProtocolContainter(key: String, defaultValue: [String : TestProtocolContainter] - ) -> [String : TestProtocolContainter] { - return getTestProtocolContainter(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestProtocolContainter(value: TestProtocolContainter, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestProtocolContainter(value: [TestProtocolContainter], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestProtocolContainter(value: [String : TestProtocolContainter], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestProtocolContainter(key: String) -> TestProtocolContainter? { - return getValue(key) - } - - public func getTestProtocolContainter(key: String, defaultValue: TestProtocolContainter) -> TestProtocolContainter { - return getTestProtocolContainter(key) ?? defaultValue - } - - public func getTestProtocolContainters(key: String) -> [TestProtocolContainter]? { - return getValue(key) - } - - public func getTestProtocolContainters(key: String, defaultValue: [TestProtocolContainter]) -> [TestProtocolContainter] { - return getTestProtocolContainters(key) ?? defaultValue - } - - public func getTestProtocolContainterDictionary(key: String) -> [String : TestProtocolContainter]? { - return getValue(key) - } - - public func getTestProtocolContainterDictionary(key: String, defaultValue: [String : TestProtocolContainter]) -> [String : TestProtocolContainter] { - return getTestProtocolContainterDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestRawEnum.swift b/Tests/Models/TestModels/_TestRawEnum.swift index 9d9b27e..d31b721 100644 --- a/Tests/Models/TestModels/_TestRawEnum.swift +++ b/Tests/Models/TestModels/_TestRawEnum.swift @@ -8,124 +8,29 @@ import State public enum TestRawEnum : String, Model { - case Aim = "Aim" - case Fire = "Fire" - case Ready = "Ready" + case aim = "Aim" + case fire = "Fire" + case ready = "Ready" } -extension TestRawEnum: Decodable { +extension TestRawEnum { - public static func decode(decoder: Decoder) -> TestRawEnum? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestRawEnum? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestRawEnum.performMigrationIfNeeded(decoder) - guard let value: String = decoder.decode("value") else { return nil } - self.init(rawValue: value) - } -} - -extension TestRawEnum: Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(self.rawValue, "value") - TestRawEnum.encodeVersionIfNeeded(encoder) - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestRawEnum { + public init?(with inStore: Store) { + let store = TestRawEnum.migrate(source: inStore) - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<4a42ad80 0164503c a7c17d8c 2a24bcf5 f44a5730 0fab6252 969f7b23 e3ff6822>" + guard let value: String = store.value(forKey: "value") else { return nil } + self.init(rawValue: value) } - public static func modelVersionHashModifier() -> String? { - return nil + public func write(to store: inout Store) { + store.set(self.rawValue, forKey: "value") + TestRawEnum.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestRawEnum(key: String) -> TestRawEnum? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestRawEnum.decode(dictionary) - } - - public func getTestRawEnum(key: String) -> [TestRawEnum]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestRawEnum.decode)) - } - - public func getTestRawEnum(key: String) -> [String : TestRawEnum]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestRawEnum.decode($0) }) - } - - public func getTestRawEnum(key: String, defaultValue: TestRawEnum) -> TestRawEnum { - return getTestRawEnum(key) ?? defaultValue - } - - public func getTestRawEnum(key: String, defaultValue: [TestRawEnum]) -> [TestRawEnum] { - return getDecodable(key) ?? defaultValue - } - - public func getTestRawEnum(key: String, defaultValue: [String : TestRawEnum] - ) -> [String : TestRawEnum] { - return getTestRawEnum(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestRawEnum(value: TestRawEnum, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestRawEnum(value: [TestRawEnum], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestRawEnum(value: [String : TestRawEnum], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestRawEnum(key: String) -> TestRawEnum? { - return getValue(key) - } - - public func getTestRawEnum(key: String, defaultValue: TestRawEnum) -> TestRawEnum { - return getTestRawEnum(key) ?? defaultValue - } - - public func getTestRawEnums(key: String) -> [TestRawEnum]? { - return getValue(key) - } - - public func getTestRawEnums(key: String, defaultValue: [TestRawEnum]) -> [TestRawEnum] { - return getTestRawEnums(key) ?? defaultValue - } - - public func getTestRawEnumDictionary(key: String) -> [String : TestRawEnum]? { - return getValue(key) - } - - public func getTestRawEnumDictionary(key: String, defaultValue: [String : TestRawEnum]) -> [String : TestRawEnum] { - return getTestRawEnumDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestRegEnum.swift b/Tests/Models/TestModels/_TestRegEnum.swift index fbb71a8..35498be 100644 --- a/Tests/Models/TestModels/_TestRegEnum.swift +++ b/Tests/Models/TestModels/_TestRegEnum.swift @@ -8,141 +8,45 @@ import State public enum TestRegEnum : Model { - case Cold - case Hot + case cold + case hot } -extension TestRegEnum: Decodable { +extension TestRegEnum { - public static func decode(decoder: Decoder) -> TestRegEnum? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestRegEnum? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestRegEnum.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestRegEnum.migrate(source: inStore) - guard let type: String = decoder.decode("TestRegEnum") else { return nil } + guard let type: String = store.value(forKey: "TestRegEnum") else { return nil } switch type { - case "Cold": - self = TestRegEnum.Cold - case "Hot": - self = TestRegEnum.Hot + case "cold": + self = TestRegEnum.cold + case "hot": + self = TestRegEnum.hot default: return nil } } -} - -extension TestRegEnum: Encodable { - public func encode(encoder: Encoder) { + public func write(to store: inout Store) { switch self { - case .Cold: - encoder.encode("Cold", "TestRegEnum") - case .Hot: - encoder.encode("Hot", "TestRegEnum") + case .cold: + store.set("cold", forKey: "TestRegEnum") + case .hot: + store.set("hot", forKey: "TestRegEnum") } - TestRegEnum.encodeVersionIfNeeded(encoder) - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestRegEnum { - - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "" - } - - public static func modelVersionHashModifier() -> String? { - return nil + TestRegEnum.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestRegEnum(key: String) -> TestRegEnum? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestRegEnum.decode(dictionary) - } - - public func getTestRegEnum(key: String) -> [TestRegEnum]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestRegEnum.decode)) - } - - public func getTestRegEnum(key: String) -> [String : TestRegEnum]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestRegEnum.decode($0) }) - } - - public func getTestRegEnum(key: String, defaultValue: TestRegEnum) -> TestRegEnum { - return getTestRegEnum(key) ?? defaultValue - } - - public func getTestRegEnum(key: String, defaultValue: [TestRegEnum]) -> [TestRegEnum] { - return getDecodable(key) ?? defaultValue - } - - public func getTestRegEnum(key: String, defaultValue: [String : TestRegEnum] - ) -> [String : TestRegEnum] { - return getTestRegEnum(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestRegEnum(value: TestRegEnum, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestRegEnum(value: [TestRegEnum], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestRegEnum(value: [String : TestRegEnum], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestRegEnum(key: String) -> TestRegEnum? { - return getValue(key) - } - - public func getTestRegEnum(key: String, defaultValue: TestRegEnum) -> TestRegEnum { - return getTestRegEnum(key) ?? defaultValue - } - - public func getTestRegEnums(key: String) -> [TestRegEnum]? { - return getValue(key) - } - - public func getTestRegEnums(key: String, defaultValue: [TestRegEnum]) -> [TestRegEnum] { - return getTestRegEnums(key) ?? defaultValue - } - - public func getTestRegEnumDictionary(key: String) -> [String : TestRegEnum]? { - return getValue(key) - } - - public func getTestRegEnumDictionary(key: String, defaultValue: [String : TestRegEnum]) -> [String : TestRegEnum] { - return getTestRegEnumDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestRelationships.swift b/Tests/Models/TestModels/_TestRelationships.swift index 5e94b89..7262912 100644 --- a/Tests/Models/TestModels/_TestRelationships.swift +++ b/Tests/Models/TestModels/_TestRelationships.swift @@ -13,129 +13,32 @@ public struct TestRelationships : Model { } -extension TestRelationships : Decodable { +extension TestRelationships { - public static func decode(decoder: Decoder) -> TestRelationships? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestRelationships? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestRelationships.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestRelationships.migrate(source: inStore) - let myChildren: [TestChild]? = decoder.decode("myChildren") - let myGrandChildren: [Grandchild]? = decoder.decode("myGrandChildren") - let myOneChild: TestChild? = decoder.decode("myOneChild") + let myChildren: [TestChild]? = store.value(forKey: "myChildren") + let myGrandChildren: [Grandchild]? = store.value(forKey: "myGrandChildren") + let myOneChild: TestChild? = store.value(forKey: "myOneChild") self.myChildren = myChildren self.myGrandChildren = myGrandChildren self.myOneChild = myOneChild - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestRelationships : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(myChildren, "myChildren") - encoder.encode(myGrandChildren, "myGrandChildren") - encoder.encode(myOneChild, "myOneChild") - - TestRelationships.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestRelationships { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<4086c709 08537ea3 c28164b3 9e9cbdbf e9d83f02 72d9cd8f cd10f5c7 101fbcbb>" - } + public func write(to store: inout Store) { + store.set(myChildren, forKey: "myChildren") + store.set(myGrandChildren, forKey: "myGrandChildren") + store.set(myOneChild, forKey: "myOneChild") - public static func modelVersionHashModifier() -> String? { - return nil + TestRelationships.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestRelationships(key: String) -> TestRelationships? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestRelationships.decode(dictionary) - } - - public func getTestRelationships(key: String) -> [TestRelationships]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestRelationships.decode)) - } - - public func getTestRelationships(key: String) -> [String : TestRelationships]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestRelationships.decode($0) }) - } - - public func getTestRelationships(key: String, defaultValue: TestRelationships) -> TestRelationships { - return getTestRelationships(key) ?? defaultValue - } - - public func getTestRelationships(key: String, defaultValue: [TestRelationships]) -> [TestRelationships] { - return getDecodable(key) ?? defaultValue - } - - public func getTestRelationships(key: String, defaultValue: [String : TestRelationships] - ) -> [String : TestRelationships] { - return getTestRelationships(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestRelationships(value: TestRelationships, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestRelationships(value: [TestRelationships], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestRelationships(value: [String : TestRelationships], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestRelationships(key: String) -> TestRelationships? { - return getValue(key) - } - - public func getTestRelationships(key: String, defaultValue: TestRelationships) -> TestRelationships { - return getTestRelationships(key) ?? defaultValue - } - - public func getTestRelationshipss(key: String) -> [TestRelationships]? { - return getValue(key) - } - - public func getTestRelationshipss(key: String, defaultValue: [TestRelationships]) -> [TestRelationships] { - return getTestRelationshipss(key) ?? defaultValue - } - - public func getTestRelationshipsDictionary(key: String) -> [String : TestRelationships]? { - return getValue(key) - } - - public func getTestRelationshipsDictionary(key: String, defaultValue: [String : TestRelationships]) -> [String : TestRelationships] { - return getTestRelationshipsDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestTransformable.swift b/Tests/Models/TestModels/_TestTransformable.swift index 2138513..72af9fa 100644 --- a/Tests/Models/TestModels/_TestTransformable.swift +++ b/Tests/Models/TestModels/_TestTransformable.swift @@ -14,135 +14,38 @@ public struct TestTransformable : Model { } -extension TestTransformable : Decodable { +extension TestTransformable { - public static func decode(decoder: Decoder) -> TestTransformable? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestTransformable? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestTransformable.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestTransformable.migrate(source: inStore) guard - let myTransformable: NSURL = decoder.decode("myTransformable"), - let myTransformableImmutable: NSURL = decoder.decode("myTransformableImmutable") + let myTransformable: NSURL = store.value(forKey: "myTransformable"), + let myTransformableImmutable: NSURL = store.value(forKey: "myTransformableImmutable") else { return nil } - let myTransformableImmutableOptional: NSURL? = decoder.decode("myTransformableImmutableOptional") - let myTransformableOptional: NSURL? = decoder.decode("myTransformableOptional") + let myTransformableImmutableOptional: NSURL? = store.value(forKey: "myTransformableImmutableOptional") + let myTransformableOptional: NSURL? = store.value(forKey: "myTransformableOptional") self.myTransformable = myTransformable self.myTransformableImmutable = myTransformableImmutable self.myTransformableImmutableOptional = myTransformableImmutableOptional self.myTransformableOptional = myTransformableOptional - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestTransformable : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(myTransformable, "myTransformable") - encoder.encode(myTransformableImmutable, "myTransformableImmutable") - encoder.encode(myTransformableImmutableOptional, "myTransformableImmutableOptional") - encoder.encode(myTransformableOptional, "myTransformableOptional") - - TestTransformable.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestTransformable { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "" - } + public func write(to store: inout Store) { + store.set(myTransformable, forKey: "myTransformable") + store.set(myTransformableImmutable, forKey: "myTransformableImmutable") + store.set(myTransformableImmutableOptional, forKey: "myTransformableImmutableOptional") + store.set(myTransformableOptional, forKey: "myTransformableOptional") - public static func modelVersionHashModifier() -> String? { - return nil + TestTransformable.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestTransformable(key: String) -> TestTransformable? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestTransformable.decode(dictionary) - } - - public func getTestTransformable(key: String) -> [TestTransformable]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestTransformable.decode)) - } - - public func getTestTransformable(key: String) -> [String : TestTransformable]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestTransformable.decode($0) }) - } - - public func getTestTransformable(key: String, defaultValue: TestTransformable) -> TestTransformable { - return getTestTransformable(key) ?? defaultValue - } - - public func getTestTransformable(key: String, defaultValue: [TestTransformable]) -> [TestTransformable] { - return getDecodable(key) ?? defaultValue - } - - public func getTestTransformable(key: String, defaultValue: [String : TestTransformable] - ) -> [String : TestTransformable] { - return getTestTransformable(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestTransformable(value: TestTransformable, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestTransformable(value: [TestTransformable], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestTransformable(value: [String : TestTransformable], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestTransformable(key: String) -> TestTransformable? { - return getValue(key) - } - - public func getTestTransformable(key: String, defaultValue: TestTransformable) -> TestTransformable { - return getTestTransformable(key) ?? defaultValue - } - - public func getTestTransformables(key: String) -> [TestTransformable]? { - return getValue(key) - } - - public func getTestTransformables(key: String, defaultValue: [TestTransformable]) -> [TestTransformable] { - return getTestTransformables(key) ?? defaultValue - } - - public func getTestTransformableDictionary(key: String) -> [String : TestTransformable]? { - return getValue(key) - } - - public func getTestTransformableDictionary(key: String, defaultValue: [String : TestTransformable]) -> [String : TestTransformable] { - return getTestTransformableDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestTransient.swift b/Tests/Models/TestModels/_TestTransient.swift index d23b8bb..32d5a9c 100644 --- a/Tests/Models/TestModels/_TestTransient.swift +++ b/Tests/Models/TestModels/_TestTransient.swift @@ -9,129 +9,32 @@ import State public struct TestTransient : Model { public var myNonTransient: String public var myTransientOptional: Double? - public var myTransientRelationship = Gender.Female + public var myTransientRelationship = Gender.female } -extension TestTransient : Decodable { +extension TestTransient { - public static func decode(decoder: Decoder) -> TestTransient? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestTransient? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestTransient.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestTransient.migrate(source: inStore) guard - let myNonTransient: String = decoder.decode("myNonTransient") + let myNonTransient: String = store.value(forKey: "myNonTransient") else { return nil } self.myNonTransient = myNonTransient - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestTransient : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(myNonTransient, "myNonTransient") - - TestTransient.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestTransient { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "" - } + public func write(to store: inout Store) { + store.set(myNonTransient, forKey: "myNonTransient") - public static func modelVersionHashModifier() -> String? { - return nil + TestTransient.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestTransient(key: String) -> TestTransient? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestTransient.decode(dictionary) - } - - public func getTestTransient(key: String) -> [TestTransient]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestTransient.decode)) - } - - public func getTestTransient(key: String) -> [String : TestTransient]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestTransient.decode($0) }) - } - - public func getTestTransient(key: String, defaultValue: TestTransient) -> TestTransient { - return getTestTransient(key) ?? defaultValue - } - - public func getTestTransient(key: String, defaultValue: [TestTransient]) -> [TestTransient] { - return getDecodable(key) ?? defaultValue - } - - public func getTestTransient(key: String, defaultValue: [String : TestTransient] - ) -> [String : TestTransient] { - return getTestTransient(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestTransient(value: TestTransient, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestTransient(value: [TestTransient], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestTransient(value: [String : TestTransient], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestTransient(key: String) -> TestTransient? { - return getValue(key) - } - - public func getTestTransient(key: String, defaultValue: TestTransient) -> TestTransient { - return getTestTransient(key) ?? defaultValue - } - - public func getTestTransients(key: String) -> [TestTransient]? { - return getValue(key) - } - - public func getTestTransients(key: String, defaultValue: [TestTransient]) -> [TestTransient] { - return getTestTransients(key) ?? defaultValue - } - - public func getTestTransientDictionary(key: String) -> [String : TestTransient]? { - return getValue(key) - } - - public func getTestTransientDictionary(key: String, defaultValue: [String : TestTransient]) -> [String : TestTransient] { - return getTestTransientDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestTransient2.swift b/Tests/Models/TestModels/_TestTransient2.swift index a317638..2f22d46 100644 --- a/Tests/Models/TestModels/_TestTransient2.swift +++ b/Tests/Models/TestModels/_TestTransient2.swift @@ -13,123 +13,26 @@ public struct TestTransient2 : Model { } -extension TestTransient2 : Decodable { +extension TestTransient2 { - public static func decode(decoder: Decoder) -> TestTransient2? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestTransient2? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestTransient2.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestTransient2.migrate(source: inStore) - let myNonTransient: Gender? = decoder.decode("myNonTransient") + let myNonTransient: Gender? = store.value(forKey: "myNonTransient") self.myNonTransient = myNonTransient - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestTransient2 : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(myNonTransient, "myNonTransient") - - TestTransient2.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestTransient2 { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<3bdb5dca 2d9104fe d8d34881 3d5e8518 763ba9eb 44d3c0b4 c57a65ec 1c4e4924>" - } + public func write(to store: inout Store) { + store.set(myNonTransient, forKey: "myNonTransient") - public static func modelVersionHashModifier() -> String? { - return nil + TestTransient2.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestTransient2(key: String) -> TestTransient2? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestTransient2.decode(dictionary) - } - - public func getTestTransient2(key: String) -> [TestTransient2]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestTransient2.decode)) - } - - public func getTestTransient2(key: String) -> [String : TestTransient2]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestTransient2.decode($0) }) - } - - public func getTestTransient2(key: String, defaultValue: TestTransient2) -> TestTransient2 { - return getTestTransient2(key) ?? defaultValue - } - - public func getTestTransient2(key: String, defaultValue: [TestTransient2]) -> [TestTransient2] { - return getDecodable(key) ?? defaultValue - } - - public func getTestTransient2(key: String, defaultValue: [String : TestTransient2] - ) -> [String : TestTransient2] { - return getTestTransient2(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestTransient2(value: TestTransient2, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestTransient2(value: [TestTransient2], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestTransient2(value: [String : TestTransient2], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestTransient2(key: String) -> TestTransient2? { - return getValue(key) - } - - public func getTestTransient2(key: String, defaultValue: TestTransient2) -> TestTransient2 { - return getTestTransient2(key) ?? defaultValue - } - - public func getTestTransient2s(key: String) -> [TestTransient2]? { - return getValue(key) - } - - public func getTestTransient2s(key: String, defaultValue: [TestTransient2]) -> [TestTransient2] { - return getTestTransient2s(key) ?? defaultValue - } - - public func getTestTransient2Dictionary(key: String) -> [String : TestTransient2]? { - return getValue(key) - } - - public func getTestTransient2Dictionary(key: String, defaultValue: [String : TestTransient2]) -> [String : TestTransient2] { - return getTestTransient2Dictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestTransient3.swift b/Tests/Models/TestModels/_TestTransient3.swift index 084908d..35d45f8 100644 --- a/Tests/Models/TestModels/_TestTransient3.swift +++ b/Tests/Models/TestModels/_TestTransient3.swift @@ -13,126 +13,29 @@ public struct TestTransient3 : Model { } -extension TestTransient3 : Decodable { +extension TestTransient3 { - public static func decode(decoder: Decoder) -> TestTransient3? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestTransient3? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestTransient3.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestTransient3.migrate(source: inStore) - let myNonTransient1: Double? = decoder.decode("myNonTransient1") - let myNonTransient2: String? = decoder.decode("myNonTransient2") + let myNonTransient1: Double? = store.value(forKey: "myNonTransient1") + let myNonTransient2: String? = store.value(forKey: "myNonTransient2") self.myNonTransient1 = myNonTransient1 self.myNonTransient2 = myNonTransient2 - didFinishDecodingWithDecoder(decoder) + finishReading(from: store) } -} - -extension TestTransient3 : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(myNonTransient1, "myNonTransient1") - encoder.encode(myNonTransient2, "myNonTransient2") - - TestTransient3.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestTransient3 { - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "<05b69b5d 1e7b7b56 3e25a035 1e39a111 32b6a4e5 35fd06b5 f81d5fe0 9fbcf182>" - } + public func write(to store: inout Store) { + store.set(myNonTransient1, forKey: "myNonTransient1") + store.set(myNonTransient2, forKey: "myNonTransient2") - public static func modelVersionHashModifier() -> String? { - return nil + TestTransient3.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestTransient3(key: String) -> TestTransient3? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestTransient3.decode(dictionary) - } - - public func getTestTransient3(key: String) -> [TestTransient3]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestTransient3.decode)) - } - - public func getTestTransient3(key: String) -> [String : TestTransient3]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestTransient3.decode($0) }) - } - - public func getTestTransient3(key: String, defaultValue: TestTransient3) -> TestTransient3 { - return getTestTransient3(key) ?? defaultValue - } - - public func getTestTransient3(key: String, defaultValue: [TestTransient3]) -> [TestTransient3] { - return getDecodable(key) ?? defaultValue - } - - public func getTestTransient3(key: String, defaultValue: [String : TestTransient3] - ) -> [String : TestTransient3] { - return getTestTransient3(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestTransient3(value: TestTransient3, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestTransient3(value: [TestTransient3], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestTransient3(value: [String : TestTransient3], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestTransient3(key: String) -> TestTransient3? { - return getValue(key) - } - - public func getTestTransient3(key: String, defaultValue: TestTransient3) -> TestTransient3 { - return getTestTransient3(key) ?? defaultValue - } - - public func getTestTransient3s(key: String) -> [TestTransient3]? { - return getValue(key) - } - - public func getTestTransient3s(key: String, defaultValue: [TestTransient3]) -> [TestTransient3] { - return getTestTransient3s(key) ?? defaultValue - } - - public func getTestTransient3Dictionary(key: String) -> [String : TestTransient3]? { - return getValue(key) - } - - public func getTestTransient3Dictionary(key: String, defaultValue: [String : TestTransient3]) -> [String : TestTransient3] { - return getTestTransient3Dictionary(key) ?? defaultValue - } -} - diff --git a/Tests/Models/TestModels/_TestTypes.swift b/Tests/Models/TestModels/_TestTypes.swift index 304dde3..f4c5aeb 100644 --- a/Tests/Models/TestModels/_TestTypes.swift +++ b/Tests/Models/TestModels/_TestTypes.swift @@ -18,25 +18,24 @@ public struct TestTypes : Model { } -extension TestTypes : Decodable { +extension TestTypes { - public static func decode(decoder: Decoder) -> TestTypes? { - return self.init(decoder: decoder) + public static func read(from store: Store) -> TestTypes? { + return self.init(with: store) } - public init?(decoder d: Decoder) { - var decoder = d - decoder = TestTypes.performMigrationIfNeeded(decoder) + public init?(with inStore: Store) { + let store = TestTypes.migrate(source: inStore) guard - let myDate: NSDate = decoder.decode("myDate"), - let myFloat: Float = decoder.decode("myFloat"), - let myBinary: NSData = decoder.decode("myBinary"), - let myDouble: Double = decoder.decode("myDouble"), - let myString: String = decoder.decode("myString"), - let myBoolean: Bool = decoder.decode("myBoolean"), - let myDecimal: NSDecimalNumber = decoder.decode("myDecimal"), - let myInt: Int = decoder.decode("myInt") + let myDate: NSDate = store.value(forKey: "myDate"), + let myFloat: Float = store.value(forKey: "myFloat"), + let myBinary: NSData = store.value(forKey: "myBinary"), + let myDouble: Double = store.value(forKey: "myDouble"), + let myString: String = store.value(forKey: "myString"), + let myBoolean: Bool = store.value(forKey: "myBoolean"), + let myDecimal: NSDecimalNumber = store.value(forKey: "myDecimal"), + let myInt: Int = store.value(forKey: "myInt") else { return nil } self.myDate = myDate @@ -47,117 +46,21 @@ extension TestTypes : Decodable { self.myBoolean = myBoolean self.myDecimal = myDecimal self.myInt = myInt - didFinishDecodingWithDecoder(decoder) - } -} - -extension TestTypes : Encodable { - - public func encode(encoder: Encoder) { - encoder.encode(myDate, "myDate") - encoder.encode(myFloat, "myFloat") - encoder.encode(myBinary, "myBinary") - encoder.encode(myDouble, "myDouble") - encoder.encode(myString, "myString") - encoder.encode(myBoolean, "myBoolean") - encoder.encode(myDecimal, "myDecimal") - encoder.encode(myInt, "myInt") - - TestTypes.encodeVersionIfNeeded(encoder) - - self.willFinishEncodingWithEncoder(encoder) - } -} - -extension TestTypes { - - /// These are provided from the data model designer - /// and can be used to determine if the model is - /// a different version. - public static func modelVersionHash() -> String { - return "" + finishReading(from: store) } - public static func modelVersionHashModifier() -> String? { - return nil + public func write(to store: inout Store) { + store.set(myDate, forKey: "myDate") + store.set(myFloat, forKey: "myFloat") + store.set(myBinary, forKey: "myBinary") + store.set(myDouble, forKey: "myDouble") + store.set(myString, forKey: "myString") + store.set(myBoolean, forKey: "myBoolean") + store.set(myDecimal, forKey: "myDecimal") + store.set(myInt, forKey: "myInt") + + TestTypes.writeVersion(to: &store) + finishWriting(to: &store) } } -extension NSUserDefaults { - - //****************************************************************************// - // MARK: NSUserDefault Getters - //****************************************************************************// - - public func getTestTypes(key: String) -> TestTypes? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return TestTypes.decode(dictionary) - } - - public func getTestTypes(key: String) -> [TestTypes]? { - guard let array = arrayForKey(key) else { return nil } - return sequence(array.map(TestTypes.decode)) - } - - public func getTestTypes(key: String) -> [String : TestTypes]? { - guard let dictionary = dictionaryForKey(key) else { return nil } - return sequence(dictionary.map { TestTypes.decode($0) }) - } - - public func getTestTypes(key: String, defaultValue: TestTypes) -> TestTypes { - return getTestTypes(key) ?? defaultValue - } - - public func getTestTypes(key: String, defaultValue: [TestTypes]) -> [TestTypes] { - return getDecodable(key) ?? defaultValue - } - - public func getTestTypes(key: String, defaultValue: [String : TestTypes] - ) -> [String : TestTypes] { - return getTestTypes(key) ?? defaultValue - } - - //****************************************************************************// - // MARK: NSUserDefault Setters - //****************************************************************************// - - public func setTestTypes(value: TestTypes, forKey key: String) { - setObject(value.encode(), forKey: key) - } - - public func setTestTypes(value: [TestTypes], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } - - public func setTestTypes(value: [String : TestTypes], forKey key: String) { - setObject(value.map { $0.encode() }, forKey: key) - } -} - -extension KVStore { - - public func getTestTypes(key: String) -> TestTypes? { - return getValue(key) - } - - public func getTestTypes(key: String, defaultValue: TestTypes) -> TestTypes { - return getTestTypes(key) ?? defaultValue - } - - public func getTestTypess(key: String) -> [TestTypes]? { - return getValue(key) - } - - public func getTestTypess(key: String, defaultValue: [TestTypes]) -> [TestTypes] { - return getTestTypess(key) ?? defaultValue - } - - public func getTestTypesDictionary(key: String) -> [String : TestTypes]? { - return getValue(key) - } - - public func getTestTypesDictionary(key: String, defaultValue: [String : TestTypes]) -> [String : TestTypes] { - return getTestTypesDictionary(key) ?? defaultValue - } -} - diff --git a/Tests/PerformanceTests.swift b/Tests/PerformanceTests.swift new file mode 100644 index 0000000..de3ffe0 --- /dev/null +++ b/Tests/PerformanceTests.swift @@ -0,0 +1,85 @@ +import XCTest +@testable import State + +class PerfTests: Test { + + override func setUp() { + super.setUp() + } + + func generateModelOfSize(x: Int, y: Int) -> Player { + var player = Player(id: 100, name: "player", age: 23) + var players = [Player]() + var innerPlayers = [Player]() + for index in 1...y { + innerPlayers.append(Player(id:index, name: "player\(index)", age:23 )) + } + for index in 1...x { + var newPlayer = Player(id:index, name: "player\(index)", age:23 ) + newPlayer.teamates = innerPlayers + players.append(newPlayer) + } + + player.teamates = players + return player + } + + func testTimeEncodingLargeDataSet() { + let player = self.generateModelOfSize(x: 500, y:10 ) + var store = Store() + + measure() { + player.write(to: &store) + } + } + + func testTimeDecodingLargeDataSet() { + let p = self.generateModelOfSize(x: 500, y:10 ) + var store = Store() + p.write(to: &store) + + measure { + var _ = Player.read(from: store) + } + } + + func testTimeParsingJSON() { + + measure { + var _ : AnyObject? = Format.json.formatter.read(self.bundleURLFor("Big_data", ofType: "json")!) + } + } + + func testTimeParsingPlist() { + measure { + var _ = Format.plist.formatter.read(self.bundlePathFor("Big_data", ofType: "plist")!) + } + } + + func testTimeParsingBinaryPlist() { + measure { + var _ = Format.binary.formatter.read(self.bundlePathFor("Big_data-bin", ofType: "plist")!) + } + } + + func testTimeWritingJSON() { + let data = Format.json.formatter.read(self.bundleURLFor("Big_data", ofType: "json")!) + measure { + _ = Format.json.formatter.write(data!, to: self.tempURLFor("Big_data.json")) + } + } + + func testTimeWritingPlist() { + let data = Format.plist.formatter.read(self.bundleURLFor("Big_data", ofType: "plist")!) + measure { + _ = Format.plist.formatter.write(data!, to: self.tempURLFor("Big_data.plist")) + } + } + + func testTimeWritingBinaryPlist() { + let data = Format.binary.formatter.read(self.bundleURLFor("Big_data-bin", ofType: "plist")!) + measure { + _ = Format.binary.formatter.write(data!, to: self.tempURLFor("Big_data-bin.plist")) + } + } +} diff --git a/Tests/StoreTests.swift b/Tests/StoreTests.swift new file mode 100644 index 0000000..2da72ff --- /dev/null +++ b/Tests/StoreTests.swift @@ -0,0 +1,64 @@ +import Foundation +import XCTest +@testable import State + + +class StoreTests: Test { + + var testPlist : [String : AnyObject]? + var testJSON : [String : AnyObject]? + var testData : [String : AnyObject]? + + override func setUp() { + super.setUp() + + let plist = PlistFormatter() + let json = JSONFormatter() + self.testPlist = plist.read(bundleURLFor("Data", ofType: "plist")!) as? [String : AnyObject] + self.testData = plist.read(bundleURLFor("Data", ofType: "plist")!) as? [String : AnyObject] + self.testJSON = json.read(bundleURLFor("Data", ofType: "json")!) as? [String : AnyObject] + } + + func testRemoveKey() { + var tested = Store(data: testPlist!) + let removed = tested.remove(key: "Float") as! [String : AnyObject] + XCTAssert(removed.count == 7) + XCTAssert(!tested.data.keys.contains("Float")) + } + + func testMakeDataWillInitWithData() { + let source = Store(data: testPlist!) + let tested = source.store(forKey: "Float") + let data = tested?.makeData(format: .binary) + XCTAssertNotNil(data) + let testedIn = Store(content: data!, format: .binary) + XCTAssert(testedIn?.data.keys.count == 7) + } + + func testMakeStringWillInitWithString() { + let tested = Store(data: testJSON!) + let str = tested.makeString(format: .json) + XCTAssertNotNil(str) + let testedIn = Store(content: str!, format: .json) + XCTAssert(testedIn?.data.keys.count == 9) + } + + func testWriteToFileInitWithFile() { + let testFileURL = tempURLFor("temp_store_write_to_file.plist") + let tested = Store(data: testPlist!) + let result = tested.write(to: testFileURL , format: .plist) + XCTAssertTrue(result) + let testedIn = Store(file: testFileURL, format: .plist) + XCTAssert(tested.data.count == testedIn?.data.count) + } + + func testURLStorage() { + var tested = Store() + let testURL = tempURLFor("Some_Test_URL.json") + tested.set(testURL, forKey: "tested") + _ = tested.write(to: testURL, format: .json) + let testedIn = Store(file: tested.value(forKey: "tested")!, format: .json) + let testURLIn : URL? = testedIn?.value(forKey: "tested") + XCTAssert(testURLIn! == testURL) + } +} diff --git a/Tests/Tests/BaseTest.swift b/Tests/Tests/BaseTest.swift deleted file mode 100644 index e22e4bb..0000000 --- a/Tests/Tests/BaseTest.swift +++ /dev/null @@ -1,75 +0,0 @@ -import XCTest - -public extension Optional { - - public func apply(f: (Wrapped -> U)?) -> U? { - return f.flatMap { self.map($0) } - } -} - -class Test : XCTestCase { - let plistFile: AnyObject? = Test.plist(fromFile: "Data") - var plistData : [String : AnyObject] = [:] - let jsonFile: AnyObject? = Test.JSON(fromFile: "Data") - var jsonData : [String : AnyObject] = [:] - - class func plist(fromFile file: String) -> AnyObject? { - let path = NSBundle(forClass: self).pathForResource(file, ofType: "plist") - - if let p = path { - if let dict = NSDictionary(contentsOfFile: p) { - return dict - } - if let arr = NSArray(contentsOfFile: p) { - return arr - } - } - return .None - } - - class func JSON(fromFile file: String) -> AnyObject? { - let path = NSBundle(forClass: self).pathForResource(file, ofType: "json") - - if path != nil { - if let data = NSData(contentsOfFile: path!) { - do { - return try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0)) - } catch _ { - return nil - } - } - } - return .None - } - - func bundlePathFor(file: String, ofType type: String) -> String? { - return NSBundle(forClass: Test.self ).pathForResource(file , ofType:type) - } - - func tempPathFor(file: String) -> String { - return NSString.pathWithComponents([NSTemporaryDirectory(), file]) - } - - func clearTempData() { - let fileManager = NSFileManager.defaultManager() - let enumerator = fileManager.enumeratorAtPath(NSTemporaryDirectory()) - while let file = enumerator?.nextObject() as? String { - do { - try fileManager.removeItemAtURL(NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(file)) - } catch _ { - } - } - } - - override func setUp() { - super.setUp() - clearTempData() - if let d = plistFile as? [String : AnyObject] { - plistData = d - } - - if let j = jsonFile as? [String : AnyObject] { - jsonData = j - } - } -} \ No newline at end of file diff --git a/Tests/Tests/DecodableTests.swift b/Tests/Tests/DecodableTests.swift deleted file mode 100644 index 8b06b3b..0000000 --- a/Tests/Tests/DecodableTests.swift +++ /dev/null @@ -1,50 +0,0 @@ -import XCTest -import State - -class DecodableTests: Test { - - func testDecodingDecodableFromJSON() { - let user = User.decode(jsonData["t"]) - let userNoEmail = User.decode(jsonData["u"]) - let users = UserTypes.decode(jsonData) - XCTAssert(user != nil) - XCTAssert(user?.id == 10) - XCTAssert(user?.name == "John Doe") - XCTAssert(user?.email == "john@unit-testing.com") - XCTAssert(userNoEmail != nil) - XCTAssert(userNoEmail?.id == 10) - XCTAssert(userNoEmail?.name == "John Doe") - XCTAssert(userNoEmail?.email == nil) - XCTAssert(users != nil) - XCTAssert(users?.tArr.count == 3) - XCTAssert(users?.tImp.name == "John Doe") - XCTAssert(users?.tDicOpt?.count == 3) - XCTAssert(users?.tDicOpt?["item1"]?.email == "john@unit-testing.com") - XCTAssert(users?.tArrImp.count == 3) - } - - func testDecodingDecodableFromPlist() { - let user = User.decode(plistData["User1"]) - let userNoEmail = User.decode(plistData["User2"]) - let users = UserTypes.decode(plistData["Users"]) - XCTAssert(user != nil) - XCTAssert(user?.id == 10) - XCTAssert(user?.name == "John Doe") - XCTAssert(user?.email == "john@unit-testing.com") - XCTAssert(userNoEmail != nil) - XCTAssert(userNoEmail?.id == 10) - XCTAssert(userNoEmail?.name == "John Doe") - XCTAssert(userNoEmail?.email == nil) - XCTAssert(users != nil) - XCTAssert(users?.tArr.count == 3) - XCTAssert(users?.tImp.name == "John Doe") - XCTAssert(users?.tDicOpt?.count == 3) - XCTAssert(users?.tDicOpt?["item1"]?.email == "john@unit-testing.com") - XCTAssert(users?.tArrImp.count == 3) - } - - func testDecodingInvalidDecodableShouldFail() { - let user = User.decode(jsonData["x"]) - XCTAssert(user == nil) - } -} diff --git a/Tests/Tests/DecodingTests.swift b/Tests/Tests/DecodingTests.swift deleted file mode 100644 index d3f579a..0000000 --- a/Tests/Tests/DecodingTests.swift +++ /dev/null @@ -1,148 +0,0 @@ -import XCTest -import State - -class DecodingTests: Test { - - func testDecodingBools() { - let bools = BasicTypes.decode(plistData["Bool"]) - /// Bools - XCTAssert(bools != nil) - XCTAssert(bools?.t == true) - XCTAssert(bools?.tOpt == nil) - XCTAssert(bools?.tImp == false) - - /// Bool Arrays - XCTAssert(bools?.tArr.count == 3) - XCTAssert(bools?.tArr[1] == true) - XCTAssert(bools?.tArrOpt == nil) - XCTAssert(bools?.tArrImp != nil) - XCTAssert(bools?.tArrImp[1] == true) - - /// Bool Dictionaries - XCTAssert(bools?.tDic.count == 2) - XCTAssert(bools?.tDic["key1"] == true) - XCTAssert(bools?.tDic["key0"] == false) - XCTAssert(bools?.tDicOpt != nil) - XCTAssert(bools?.tDictImp["key0"] == true) - } - - func testDecodingIntTypes() { - let ints = BasicTypes.decode(plistData["Int"]) - - /// Ints - XCTAssert(ints != nil) - XCTAssert(ints?.t == 10) - XCTAssert(ints?.tOpt == nil) - XCTAssert(ints?.tImp == 40) - - /// Int Arrays - XCTAssert(ints?.tArr.count == 3) - XCTAssert(ints?.tArr[1] == 10) - XCTAssert(ints?.tArrOpt == nil) - XCTAssert(ints?.tArrImp != nil) - XCTAssert(ints?.tArrImp[1] == 64) - - /// Int Dictionaries - XCTAssert(ints?.tDic.count == 2) - XCTAssert(ints?.tDic["key1"] == 123) - XCTAssert(ints?.tDic["key0"] == 67) - XCTAssert(ints?.tDicOpt != nil) - XCTAssert(ints?.tDictImp["key1"] == 79) - } - - func testDecodingDoubles() { - let doubles = BasicTypes.decode(plistData["Double"]) - - /// Doubles - XCTAssert(doubles != nil) - XCTAssert(doubles?.t == -0.456) - XCTAssert(doubles?.tOpt == nil) - XCTAssert(doubles?.tImp == 0.6565) - - /// Double Arrays - XCTAssert(doubles?.tArr.count == 3) - XCTAssert(doubles?.tArr[1] == 0.45) - XCTAssert(doubles?.tArrOpt == nil) - XCTAssert(doubles?.tArrImp != nil) - XCTAssert(doubles?.tArrImp[1] == 0) - - /// Double Dictionaries - XCTAssert(doubles?.tDic.count == 2) - XCTAssert(doubles?.tDic["key1"] == -1.0005) - XCTAssert(doubles?.tDic["key0"] == 67.6756) - XCTAssert(doubles?.tDicOpt != nil) - XCTAssert(doubles?.tDictImp["key1"] == -5.78) - } - - func testDecodingFloats() { - let floats = BasicTypes.decode(plistData["Float"]) - - /// Floats - XCTAssert(floats != nil) - XCTAssert(floats?.t == -0.345) - XCTAssert(floats?.tOpt == nil) - XCTAssert(floats?.tImp == 0.78796) - - /// Float Arrays - XCTAssert(floats?.tArr.count == 3) - XCTAssert(floats?.tArr[1] == 0.54) - XCTAssert(floats?.tArrOpt == nil) - XCTAssert(floats?.tArrImp != nil) - XCTAssert(floats?.tArrImp[1] == -0.45) - - /// Float Dictionaries - XCTAssert(floats?.tDic.count == 2) - XCTAssert(floats?.tDic["key1"] == 0.45) - XCTAssert(floats?.tDic["key0"] == 65.0909) - XCTAssert(floats?.tDicOpt != nil) - XCTAssert(floats?.tDictImp["key1"] == -222.222) - } - - func testDecodingStrings() { - let strings = StringTypes.decode(plistData["String"]) - - /// Strings - XCTAssert(strings != nil) - XCTAssert(strings?.t == "Hello") - XCTAssert(strings?.tOpt == nil) - XCTAssert(strings?.tImp == "Unwrapped") - - /// String Arrays - XCTAssert(strings?.tArr.count == 3) - XCTAssert(strings?.tArr[1] == "item1") - XCTAssert(strings?.tArrOpt == nil) - XCTAssert(strings?.tArrImp != nil) - XCTAssert(strings?.tArrImp[1] == "Ray") - - /// String Dictionaries - XCTAssert(strings?.tDic.count == 2) - XCTAssert(strings?.tDic["key1"] == "Dic_String_1") - XCTAssert(strings?.tDic["key0"] == "Dic_String_0") - XCTAssert(strings?.tDicOpt != nil) - XCTAssert(strings?.tDictImp["key1"] == "") - } - - func testDecodingAnyObjects() { - let objects = AnyObjectTypes.decode(plistData["Object"]) - - /// AnyObjects - XCTAssert(objects != nil) - XCTAssert(objects?.t as? Int == 400) - XCTAssert(objects?.tOpt == nil) - XCTAssert(objects?.tImp as? Bool == true) - - /// AnyObject Arrays - XCTAssert(objects?.tArr.count == 3) - XCTAssert(objects?.tArr[1] as? Double == 20.6 ) - XCTAssert(objects?.tArrOpt == nil) - XCTAssert(objects?.tArrImp != nil) - XCTAssert(objects?.tArrImp[1] as? String == "Ray") - - /// AnyObject Dictionaries - XCTAssert(objects?.tDic.count == 2) - XCTAssert(objects?.tDic["key1"] as? Bool == true ) - XCTAssert(objects?.tDic["key0"] as? Int == 0) - XCTAssert(objects?.tDicOpt != nil) - XCTAssert(objects?.tDictImp["key1"] as? NSDate != nil) - } -} diff --git a/Tests/Tests/DefaultTests.swift b/Tests/Tests/DefaultTests.swift deleted file mode 100644 index d6ab9dd..0000000 --- a/Tests/Tests/DefaultTests.swift +++ /dev/null @@ -1,17 +0,0 @@ -import XCTest -import State - - -class DefaultTests: Test { - - func testDefaults() { - let test = TestDefaults() - - XCTAssert(test.defaultArray.count == 3 ) - XCTAssert(test.defaultString == "defaultString") - XCTAssertNotNil(test.defaultEmptyArray) - XCTAssert(test.defaultChild.name == "New Child") - XCTAssert(test.defaultChildren.count == 0) - } - -} diff --git a/Tests/Tests/EncodableTests.swift b/Tests/Tests/EncodableTests.swift deleted file mode 100644 index aba69d3..0000000 --- a/Tests/Tests/EncodableTests.swift +++ /dev/null @@ -1,33 +0,0 @@ -import XCTest -import State - -class EncodableTests: Test { - - func testEcodingToAndFromJSON() { - let inUsers = UserTypes.decode(jsonData) - if let inUsers = inUsers { - inUsers.save(.JSON, path: tempPathFor("temp.json")) - } - let users = UserTypes(.JSON, path: tempPathFor("temp.json")) - XCTAssert(users != nil) - XCTAssert(users?.tArr.count == 3) - XCTAssert(users?.tImp.name == "John Doe") - XCTAssert(users?.tDicOpt?.count == 3) - XCTAssert(users?.tDicOpt?["item1"]?.email == "john@unit-testing.com") - XCTAssert(users?.tArrImp.count == 3) - } - - func testEcodingToAndFromPlist() { - let inUsers = UserTypes.decode(plistData["Users"]) - if let inUsers = inUsers { - inUsers.save(.Plist, path: tempPathFor("temp.plist")) - } - let users = UserTypes(.Plist, path: tempPathFor("temp.plist")) - XCTAssert(users != nil) - XCTAssert(users?.tArr.count == 3) - XCTAssert(users?.tImp.name == "John Doe") - XCTAssert(users?.tDicOpt?.count == 3) - XCTAssert(users?.tDicOpt?["item1"]?.email == "john@unit-testing.com") - XCTAssert(users?.tArrImp.count == 3) - } -} diff --git a/Tests/Tests/EncodingTests.swift b/Tests/Tests/EncodingTests.swift deleted file mode 100644 index 1407385..0000000 --- a/Tests/Tests/EncodingTests.swift +++ /dev/null @@ -1,160 +0,0 @@ -import XCTest -import State - -class EncodingTests: Test { - func testEncodingBools() { - let bools_in = BasicTypes.decode(plistData["Bool"]) - let bools_data = bools_in!.encode() - let bools = BasicTypes.decode(bools_data) - - /// Bools - XCTAssert(bools != nil) - XCTAssert(bools?.t == true) - XCTAssert(bools?.tOpt == nil) - XCTAssert(bools?.tImp == false) - - /// Bool Arrays - XCTAssert(bools?.tArr.count == 3) - XCTAssert(bools?.tArr[1] == true) - XCTAssert(bools?.tArrOpt == nil) - XCTAssert(bools?.tArrImp != nil) - XCTAssert(bools?.tArrImp[1] == true) - - /// Bool Dictionaries - XCTAssert(bools?.tDic.count == 2) - XCTAssert(bools?.tDic["key1"] == true) - XCTAssert(bools?.tDic["key0"] == false) - XCTAssert(bools?.tDicOpt != nil) - XCTAssert(bools?.tDictImp["key0"] == true) - } - - func testEncodingInts() { - let ints_in = BasicTypes.decode(plistData["Int"]) - let ints_data = ints_in!.encode() - let ints = BasicTypes.decode(ints_data) - - /// Ints - XCTAssert(ints != nil) - XCTAssert(ints?.t == 10) - XCTAssert(ints?.tOpt == nil) - XCTAssert(ints?.tImp == 40) - - /// Int Arrays - XCTAssert(ints?.tArr.count == 3) - XCTAssert(ints?.tArr[1] == 10) - XCTAssert(ints?.tArrOpt == nil) - XCTAssert(ints?.tArrImp != nil) - XCTAssert(ints?.tArrImp[1] == 64) - - /// Int Dictionaries - XCTAssert(ints?.tDic.count == 2) - XCTAssert(ints?.tDic["key1"] == 123) - XCTAssert(ints?.tDic["key0"] == 67) - XCTAssert(ints?.tDicOpt != nil) - XCTAssert(ints?.tDictImp["key1"] == 79) - } - - func testEncodingDoubles() { - let doubles_in = BasicTypes.decode(plistData["Double"]) - let doubles_data = doubles_in!.encode() - let doubles = BasicTypes.decode(doubles_data) - - /// Doubles - XCTAssert(doubles != nil) - XCTAssert(doubles?.t == -0.456) - XCTAssert(doubles?.tOpt == nil) - XCTAssert(doubles?.tImp == 0.6565) - - /// Double Arrays - XCTAssert(doubles?.tArr.count == 3) - XCTAssert(doubles?.tArr[1] == 0.45) - XCTAssert(doubles?.tArrOpt == nil) - XCTAssert(doubles?.tArrImp != nil) - XCTAssert(doubles?.tArrImp[1] == 0) - - /// Double Dictionaries - XCTAssert(doubles?.tDic.count == 2) - XCTAssert(doubles?.tDic["key1"] == -1.0005) - XCTAssert(doubles?.tDic["key0"] == 67.6756) - XCTAssert(doubles?.tDicOpt != nil) - XCTAssert(doubles?.tDictImp["key1"] == -5.78) - } - - func testEncodingFloats() { - let floats_in = BasicTypes.decode(plistData["Float"]) - let floats_data = floats_in!.encode() - let floats = BasicTypes.decode(floats_data) - - /// Floats - XCTAssert(floats != nil) - XCTAssert(floats?.t == -0.345) - XCTAssert(floats?.tOpt == nil) - XCTAssert(floats?.tImp == 0.78796) - - /// Float Arrays - XCTAssert(floats?.tArr.count == 3) - XCTAssert(floats?.tArr[1] == 0.54) - XCTAssert(floats?.tArrOpt == nil) - XCTAssert(floats?.tArrImp != nil) - XCTAssert(floats?.tArrImp[1] == -0.45) - - /// Float Dictionaries - XCTAssert(floats?.tDic.count == 2) - XCTAssert(floats?.tDic["key1"] == 0.45) - XCTAssert(floats?.tDic["key0"] == 65.0909) - XCTAssert(floats?.tDicOpt != nil) - XCTAssert(floats?.tDictImp["key1"] == -222.222) - } - - func testEncodingStringTypes() { - let strings_in = StringTypes.decode(plistData["String"]) - let strings_data = strings_in!.encode() - let strings = StringTypes.decode(strings_data) - - /// Strings - XCTAssert(strings != nil) - XCTAssert(strings?.t == "Hello") - XCTAssert(strings?.tOpt == nil) - XCTAssert(strings?.tImp == "Unwrapped") - - /// String Arrays - XCTAssert(strings?.tArr.count == 3) - XCTAssert(strings?.tArr[1] == "item1") - XCTAssert(strings?.tArrOpt == nil) - XCTAssert(strings?.tArrImp != nil) - XCTAssert(strings?.tArrImp[1] == "Ray") - - /// String Dictionaries - XCTAssert(strings?.tDic.count == 2) - XCTAssert(strings?.tDic["key1"] == "Dic_String_1") - XCTAssert(strings?.tDic["key0"] == "Dic_String_0") - XCTAssert(strings?.tDicOpt != nil) - XCTAssert(strings?.tDictImp["key1"] == "") - } - - func testEncodingAnyObjectTypes() { - let objects_in = AnyObjectTypes.decode(plistData["Object"]) - let objects_data = objects_in!.encode() - let objects = AnyObjectTypes.decode(objects_data) - - /// AnyObjects - XCTAssert(objects != nil) - XCTAssert(objects?.t as? Int == 400) - XCTAssert(objects?.tOpt == nil) - XCTAssert(objects?.tImp as? Bool == true) - - /// AnyObject Arrays - XCTAssert(objects?.tArr.count == 3) - XCTAssert(objects?.tArr[1] as? Double == 20.6 ) - XCTAssert(objects?.tArrOpt == nil) - XCTAssert(objects?.tArrImp != nil) - XCTAssert(objects?.tArrImp[1] as? String == "Ray") - - /// AnyObject Dictionaries - XCTAssert(objects?.tDic.count == 2) - XCTAssert(objects?.tDic["key1"] as? Bool == true ) - XCTAssert(objects?.tDic["key0"] as? Int == 0) - XCTAssert(objects?.tDicOpt != nil) - XCTAssert(objects?.tDictImp["key1"] as? NSDate != nil) - } -} diff --git a/Tests/Tests/EnumTests.swift b/Tests/Tests/EnumTests.swift deleted file mode 100644 index 5137522..0000000 --- a/Tests/Tests/EnumTests.swift +++ /dev/null @@ -1,189 +0,0 @@ -import XCTest -import State -import UIKit - -class EnumTests: Test { - - func testRawEnum() { - let test_out = TestRawEnum.Ready - test_out.save(.Plist, path: tempPathFor("test_raw_enum.plist")) - let sut = TestRawEnum(.Plist, path: tempPathFor("test_raw_enum.plist")) - XCTAssert(sut != nil) - XCTAssert(sut == TestRawEnum.Ready) - } - - func testRegEnum() { - let test_out = TestRegEnum.Cold - test_out.save(.Plist, path: tempPathFor("test_reg_enum.plist")) - let sut = TestRegEnum(.Plist, path: tempPathFor("test_reg_enum.plist")) - XCTAssert(sut != nil) - XCTAssert(sut == TestRegEnum.Cold) - } - - func testAssociatedEnum() { - - func createBinary() -> NSData? { - if let path = NSBundle(forClass: Test.self).pathForResource("Data", ofType: "plist") { - return NSData(contentsOfFile:path) - } - return nil - } - - func performTestFor(testEnum: TestAssociatedEnum, message: String) { - testEnum.save(.Binary, path: tempPathFor("test_associated_enum.plist")) - let sut = TestAssociatedEnum(.Binary, path: tempPathFor("test_associated_enum.plist")) - XCTAssert(sut != nil) - if let sut = sut { - switch sut { - case let .StringType(s): - XCTAssert(s == "Hello World", message) - case let .IntType(i): - XCTAssert(i == 10, message) - case let .FloatType(f): - XCTAssert(f == 0.1235, message) - case let .DoubleType(d): - XCTAssert(d == -12.34, message) - case let .BooleanType(b): - XCTAssert(b == true, message) - case let .BinaryType(b): - XCTAssertNotNil(b, message) - case let .DecimalType(d): - XCTAssert(d == NSDecimalNumber(double:0.8976), message) - case let .DateType(d): - XCTAssert(d == NSDate(timeIntervalSince1970: 10000), message) - case let .TransformableColorType(t): - XCTAssert(t == UIColor.blueColor(), message) - default: - XCTFail() - } - } - - } - - performTestFor(TestAssociatedEnum.StringType("Hello World"), message: "StringType should be Hello World") - performTestFor(TestAssociatedEnum.IntType(10), message: "IntType should be 10") - performTestFor(TestAssociatedEnum.FloatType(0.1235), message: "FloatType should be .1235") - performTestFor(TestAssociatedEnum.DoubleType(-12.34), message: "DoubleType should be -12.34") - performTestFor(TestAssociatedEnum.BooleanType(true), message: "BooleanType should be true") - performTestFor(TestAssociatedEnum.BinaryType(createBinary()!), message: "Binary should not be nil") - performTestFor(TestAssociatedEnum.DecimalType(NSDecimalNumber(double: 0.8976)), message: "DecimalType should equal 0.8976") - performTestFor(TestAssociatedEnum.DateType(NSDate(timeIntervalSince1970: 10000)), message: "DateType should equal 10000 since 1970") - performTestFor(TestAssociatedEnum.TransformableColorType(UIColor.blueColor()), message: "Color should be blue") - } - - - func testAssociatedDecodeableToManyEnum() { - let employee = Employee(name: "Joe", title: "Manager") - let employees = [employee, employee, employee] - let test_out = TestAssociatedEnum.DecodableToManyType(employees) - test_out.save(.Plist, path: tempPathFor("test_associated_tomany_enum.plist")) - print(tempPathFor("test_associated_tomany_enum.plist")) - let sut = TestAssociatedEnum(.Plist, path: tempPathFor("test_associated_tomany_enum.plist")) - XCTAssert(sut != nil) - - switch sut! { - case let .DecodableToManyType(e): - XCTAssert(e.count == 3) - XCTAssert(e[1].name == "Joe") - default: - XCTFail() - } - } - - func testAssociatedDecodeableToOneEnum() { - let employee = Employee(name: "Joe", title: "Manager") - let test_out = TestAssociatedEnum.DecodableToOneType(employee) - test_out.save(.Plist, path: tempPathFor("test_associated_toone_enum.plist")) - let sut = TestAssociatedEnum(.Plist, path: tempPathFor("test_associated_toone_enum.plist")) - XCTAssert(sut != nil) - - switch sut! { - case let .DecodableToOneType(e): - XCTAssert(e.name == "Joe") - default: - XCTFail() - } - } - - func testAssociatedOptionalEnum() { - - func createBinary() -> NSData? { - if let path = NSBundle(forClass: Test.self).pathForResource("Data", ofType: "plist") { - return NSData(contentsOfFile:path) - } - return nil - } - - func performTestFor(testEnum: TestAssociatedOptionalEnum, message: String) { - testEnum.save(.Binary, path: tempPathFor("test_associated_optional_enum.plist")) - let sut = TestAssociatedOptionalEnum(.Binary, path: tempPathFor("test_associated_optional_enum.plist")) - XCTAssert(sut != nil, "system under test is nil") - if let sut = sut { - switch sut { - case let .StringType(s): - XCTAssert(s == "Hello World", message) - case let .IntType(i): - XCTAssert(i == 10, message) - case let .FloatType(f): - XCTAssert(f == 0.1235, message) - case let .DoubleType(d): - XCTAssert(d == -12.34, message) - case let .BooleanType(b): - XCTAssert(b == true, message) - case let .BinaryType(b): - XCTAssertNotNil(b, message) - case let .DecimalType(d): - XCTAssert(d == NSDecimalNumber(double:0.8976), message) - case let .DateType(d): - XCTAssert(d == NSDate(timeIntervalSince1970: 10000), message) - case let .TransformableColorType(t): - XCTAssert(t == UIColor.blueColor(), message) - default: - XCTFail("no case found") - } - } - } - - performTestFor(TestAssociatedOptionalEnum.StringType("Hello World"), message: "StringType should be Hello World") - performTestFor(TestAssociatedOptionalEnum.IntType(10), message: "IntType should be 10") - performTestFor(TestAssociatedOptionalEnum.FloatType(0.1235), message: "FloatType should be .1235") - performTestFor(TestAssociatedOptionalEnum.DoubleType(-12.34), message: "DoubleType should be -12.34") - performTestFor(TestAssociatedOptionalEnum.BooleanType(true), message: "BooleanType should be true") - performTestFor(TestAssociatedOptionalEnum.BinaryType(createBinary()!), message: "Binary should not be nil") - performTestFor(TestAssociatedOptionalEnum.DecimalType(NSDecimalNumber(double: 0.8976)), message: "DecimalType should equal 0.8976") - performTestFor(TestAssociatedOptionalEnum.DateType(NSDate(timeIntervalSince1970: 10000)), message: "DateType should equal 10000 since 1970") - performTestFor(TestAssociatedOptionalEnum.TransformableColorType(UIColor.blueColor()), message: "Color should be blue") - } - - func testAssociatedDecodeableOptionalToManyEnum() { - let employee = Employee(name: "Joe", title: "Manager") - let employees = [employee, employee, employee] - let test_out = TestAssociatedOptionalEnum.DecodableToManyType(employees) - test_out.save(.Plist, path: tempPathFor("test_associated_optional_tomany_enum.plist")) - let sut = TestAssociatedOptionalEnum(.Plist, path: tempPathFor("test_associated_optional_tomany_enum.plist")) - XCTAssert(sut != nil) - - switch sut! { - case let .DecodableToManyType(e): - XCTAssert(e?.count == 3) - XCTAssert(e?[1].name == "Joe") - default: - XCTFail() - } - } - - func testAssociatedDecodeableOptionalToOneEnum() { - let employee = Employee(name: "Joe", title: "Manager") - let test_out = TestAssociatedOptionalEnum.DecodableToOneType(employee) - test_out.save(.Plist, path: tempPathFor("test_associated_optional_toone_enum.plist")) - let sut = TestAssociatedOptionalEnum(.Plist, path: tempPathFor("test_associated_optional_toone_enum.plist")) - XCTAssert(sut != nil) - - switch sut! { - case let .DecodableToOneType(e): - XCTAssert(e?.name == "Joe") - default: - XCTFail() - } - } -} diff --git a/Tests/Tests/KVStoreTests.swift b/Tests/Tests/KVStoreTests.swift deleted file mode 100644 index 561b713..0000000 --- a/Tests/Tests/KVStoreTests.swift +++ /dev/null @@ -1,296 +0,0 @@ -import XCTest -import State - -class KVStoreTests: Test { - override func setUp() { - super.setUp() - } - - func testGetKeyThatDoesNotExsistShouldReturnNil() { - let store = KVStore() - let result = store.getKey("InvalidKey") - XCTAssert(result == nil) - } - - func testGetKeyReturnsKey() { - let store = KVStore() - store.addKey("A.B.C.D") - XCTAssertNotNil(store.getKey("A.B.C")) - } - - func testCreateKeyOneLevelDeepShouldCreateKey() { - let store = KVStore() - store.addKey("Level1") - let resultKey = store.getKey("Level1") - XCTAssertNotNil(resultKey) - } - - func testCreateKeyMultiLevelsDeepShouldCreateKeys() { - let store = KVStore() - store.addKey("Level1.Level2.Level3") - - let resultKey1 = store.getKey("Level1") - XCTAssertNotNil(resultKey1) - - let resultKey2 = store.getKey("Level1.Level2") - XCTAssertNotNil(resultKey2) - - let resultKey3 = store.getKey("Level1.Level2.Level3") - XCTAssertNotNil(resultKey3) - } - - func testCreatingKeyThatExsistsReturnsExsitingKey() { - let store = KVStore() - store.addKey("A.B.C.D") - let cKey = store.getKey("A.B.C") - let createdKey = store.addKey("A.B.C") - XCTAssert(cKey === createdKey) - } - - func testUpdatingKeyWithNewKeyReplacesAndReturnsOldKey() { - let store = KVStore() - store.addKey("A.B.C.D") - let oldKey = store.getKey("A.B.C") - let newKey = KVStore() - let returnedKey = store.updateKey("A.B.C", newKey: newKey) - XCTAssert(store.getKey("A.B.C") === newKey) - XCTAssert(returnedKey === oldKey) - } - - - func testRemovingKeyThatDoesNotExsistReturnsNil() { - let store = KVStore() - XCTAssertNil(store.removeKey("A.B.C")) - } - - func testRemovingKeyReturnsRemovedKeyAndIsRemoved() { - let store = KVStore() - store.addKey("A.B.C.D") - let lastKey = store.getKey("A.B.C.D") - let removedKey = store.removeKey("A.B.C.D") - XCTAssert(lastKey === removedKey) - let firstKey = store.getKey("A") - store.removeKey("C") - store.removeKey("B") - let removedFirstKey = store.removeKey("A") - XCTAssert(removedFirstKey === firstKey) - } - - func testSettingAValueOneLevelYieldsValue() { - let store = KVStore() - store.setValue(10, forKey: "TestValue") - - let value = store.data["TestValue"] as! Int - debugPrint(value) - - XCTAssert(value == 10) - } - - func testSettingAValueMultiLevelsYieldsValue() { - let store = KVStore() - store.setValue(20, forKey:"A.B.C.TestValue") - - if let key = store.getKey("A.B.C") { - let value = key.data["TestValue"] as! Int - XCTAssert(value == 20) - } - else { - XCTFail() - } - } - - func testGettingAValueOneLevelYieldsValue() { - let store = KVStore() - store.setValue(10, forKey: "TestValue") - let result : Int? = store.getValue("TestValue") - - XCTAssert(result == 10) - } - - func testGettingAValueMultiLevelYieldsValue() { - let store = KVStore() - store.setValue(10, forKey: "A.B.C.TestValue") - let targetKey = store.getKey("A.B.C") - let result : Int? = targetKey?.getValue("TestValue") - - XCTAssert(result == 10) - } - - func testGettingADefaultValueYieldsCorrectValue() { - let store = KVStore() - let result = store.getValue("InvalidKey", defaultValue: 44) - XCTAssert(result == 44) - - store.setValue(42, forKey: "ValidKey") - let result2 = store.getValue("ValidKey", defaultValue: 44) - XCTAssert(result2 == 42) - } - - func testDecodables() { - let employee = Employee(name: "Fred", title: "President") - let employee2 = Employee(name: "Alice", title: nil) - let company = Company(name: "TestCompany", yearFounded: 2014, phoneNumber: "860-222-1234", employees: [employee, employee2]) - - let employeeArray = [employee, employee2] - let employeeDict = ["Fred" : employee, "Alice" : employee2] - - let store = KVStore() - - store.setValue(employee, forKey: "employees.instance") - store.setValue(employeeArray, forKey: "employees.array") - store.setValue(employeeDict, forKey: "employees.dict") - store.setValue(company, forKey: "company") - - store.save(tempPathFor("Test.plist")) - - let inputStore = KVStore.load(tempPathFor("Test.plist")) - - XCTAssertNotNil(inputStore) - - let inEmployee : Employee? = inputStore?.getValue("employees.instance") - XCTAssertNotNil(inEmployee) - XCTAssert(inEmployee?.name == "Fred") - - let inEmployeeArray : [Employee]? = inputStore?.getValue("employees.array") - XCTAssertNotNil(inEmployeeArray) - XCTAssert(inEmployeeArray?.count == 2) - - let inEmployeeDict : [String : Employee]? = inputStore?.getValue("employees.dict") - XCTAssertNotNil(inEmployeeDict) - XCTAssert(inEmployeeDict?.count == 2) - XCTAssert(inEmployeeDict?["Alice"]?.name == "Alice") - - let inCompany : Company? = inputStore?.getValue("company") - XCTAssertNotNil(inCompany) - XCTAssert(inCompany?.employees?.count == 2) - } - - func testBasicGetters() { - let testBool: Bool = true - let testInt : Int = 42 - let testDouble: Double = 3.14 - let testFloat: Float = 0.001 - let testString: String = "Hello" - - let store = KVStore() - - store.setValue(testBool, forKey: "testBool") - store.setValue(testInt, forKey: "testInt") - store.setValue(testDouble, forKey: "testDouble") - store.setValue(testFloat, forKey: "testFloat") - store.setValue(testString, forKey: "testString") - - let notFound = store.getBool("Invalid") - XCTAssertNil(notFound) - - let inValidType = store.getString("testInt") - XCTAssertNil(inValidType) - - XCTAssert(store.getBool("testBool") == testBool) - XCTAssert(store.getInt("testInt") == testInt) - XCTAssert(store.getDouble("testDouble") == testDouble) - XCTAssert(store.getFloat("testFloat") == testFloat) - XCTAssert(store.getString("testString") == testString) - } - - func testGettersWithDefaultValues() { - - let store = KVStore() - - let notFound = store.getBool("Invalid") - XCTAssertNil(notFound) - - let inValidType = store.getString("testInt") - XCTAssertNil(inValidType) - - XCTAssert(store.getBool("testBool", defaultValue: true) == true) - XCTAssert(store.getInt("testInt", defaultValue: 42) == 42) - XCTAssert(store.getDouble("testDouble", defaultValue: 3.14) == 3.14) - XCTAssert(store.getFloat("testFloat", defaultValue: 0.001) == 0.001) - XCTAssert(store.getString("testString", defaultValue: "Hello") == "Hello") - - store.setValue(10, forKey: "testInt") - XCTAssert(store.getInt("testInt", defaultValue: 42) == 10) - - let employee = Employee(name: "Fred", title: "President") - - let resultEmployee : Employee = store.getValue("Fred", defaultValue: employee) - XCTAssert(resultEmployee.name == "Fred") - } - - func testRemovalFromStore() { - let store = KVStore() - - let employee = Employee(name: "Fred", title: "President") - let employee2 = Employee(name: "Alice", title: nil) - let company = Company(name: "TestCompany", yearFounded: 2014, phoneNumber: "860-222-1234", employees: [employee, employee2]) - - let employeeArray = [employee, employee2] - let employeeDict = ["Fred" : employee, "Alice" : employee2] - - store.setValue("HELLO", forKey: "some.string.value") - store.setValue(employee, forKey: "employees.instance") - store.setValue(employeeArray, forKey: "employees.array") - store.setValue(employeeDict, forKey: "employees.dict") - store.setValue(company, forKey: "company") - - let removedString: String? = store.removeValue("some.string.value") - XCTAssert(removedString == "HELLO") - - let getRemovedString: String? = store.getValue("some.string.value") - XCTAssertNil(getRemovedString) - - let removedEmployee : Employee? = store.removeValue("employees.instance") - XCTAssertNotNil(removedEmployee) - - let getRemovedEmployee : Employee? = store.getValue("employees.instance") - XCTAssertNil(getRemovedEmployee) - - let removedEmployeeArray : [Employee]? = store.removeValue("employees.array") - XCTAssertNotNil(removedEmployeeArray) - - store.setValue(employee, forKey: "employees.instance") - store.deleteValue("employees.instance") - - let getDeletedEmployee : Employee? = store.getValue("employees.instance") - XCTAssertNil(getDeletedEmployee) - } - - func testMergingStores() { - let store = KVStore() - store.setValue("HELLO", forKey: "some.string.value") - let store2 = KVStore() - - store2.setValue(12, forKey: "some.integer.value") - store2.setValue("SOME STRING", forKey: "some.string.other") - - store.merge(store2) - - let i: Int? = store.getInt("some.integer.value") - XCTAssertNotNil(i) - XCTAssert(i == 12) - - let s: String? = store.getString("some.string.other") - XCTAssertNotNil(s) - XCTAssert(s == "SOME STRING") - } - - func testMergingStoreIntoKeypath() { - let store = KVStore() - store.setValue("HELLO", forKey: "some.string.value") - let store2 = KVStore() - - store2.setValue(12, forKey: "branch.integer.value") - store2.setValue("SOME STRING", forKey: "some.string.other") - store.merge(store2, intoKeypath: "other.key") - - let i : Int? = store.getValue("other.key.branch.integer.value") - XCTAssertNotNil(i) - XCTAssert(i == 12) - - let s: String? = store.getString("other.key.some.string.other") - XCTAssertNotNil(s) - XCTAssert(s == "SOME STRING") - } - -} diff --git a/Tests/Tests/MigrationTests.swift b/Tests/Tests/MigrationTests.swift deleted file mode 100644 index 142944a..0000000 --- a/Tests/Tests/MigrationTests.swift +++ /dev/null @@ -1,41 +0,0 @@ -import XCTest -import State -import UIKit - -class MigrationTests: Test { - - func testEmployeeEncodesVersion() { - let testItem = Employee(name: "John", title: "Manager") - let versionString = Employee.modelVersionHash() - - testItem.save(.JSON, path: tempPathFor("employee.json")) - let data = JSON.read(tempPathFor("employee.json")) - - if let data = data, testVersionString = data[Employee.versionKey()] as? String { - XCTAssert(testVersionString == versionString) - } else { XCTFail() } - } - - func testMigration() { - // create version 1, and write out to file - let testVersion1 = TestMigrationV1(name: "John") - testVersion1.save(.JSON, path: tempPathFor("version1.json")) - - // read in version 1, and migrate to version 2 - let testVersion2 = TestMigrationV2(.JSON, path: tempPathFor("version1.json")) - - // should now have a version 2 type (should have an age property that defaults to 10) - - XCTAssert(testVersion2?.age == 10) - - } - - func testWillFinishEncodingWithEncoderIsCalled() { - let testVersion1 = TestMigrationV1(name: "John") - testVersion1.save(.JSON, path: tempPathFor("migration.json")) - let data = JSON.read(tempPathFor("migration.json")) - if let data = data, extraKey = data["migration_test"] as? String { - XCTAssert(extraKey == "Hello World") - } else { XCTFail() } - } -} diff --git a/Tests/Tests/PerfTests.swift b/Tests/Tests/PerfTests.swift deleted file mode 100644 index 0087f2f..0000000 --- a/Tests/Tests/PerfTests.swift +++ /dev/null @@ -1,82 +0,0 @@ -import XCTest -import State - -class PerfTests: Test { - - override func setUp() { - super.setUp() - } - - func generateModelOfSize(x: Int, y: Int) -> Player { - var player = Player(id: 100, name: "player", age: 23) - var players = [Player]() - var innerPlayers = [Player]() - for index in 1...y { - innerPlayers.append(Player(id:index, name: "player\(index)", age:23 )) - } - for index in 1...x { - var newPlayer = Player(id:index, name: "player\(index)", age:23 ) - newPlayer.teamates = innerPlayers - players.append(newPlayer) - } - - player.teamates = players - return player - } - - func testTimeEncodingLargeDataSet() { - let player = self.generateModelOfSize(500, y:10 ) - - measureBlock() { - player.encode() - } - } - - func testTimeDecodingLargeDataSet() { - _ = self.generateModelOfSize(500, y:10 ) - let data = [String : AnyObject]() - - measureBlock { - var _ = Player.decode(data) - } - } - - func testTimeParsingJSON() { - measureBlock { - var _ = JSON.read(self.bundlePathFor("Big_data", ofType: "json")!) - } - } - - func testTimeParsingPlist() { - measureBlock { - var _ = Plist.read(self.bundlePathFor("Big_data", ofType: "plist")!) - } - } - - func testTimeParsingBinaryPlist() { - measureBlock { - var _ = Binary.read(self.bundlePathFor("Big_data-bin", ofType: "plist")!) - } - } - - func testTimeWritingJSON() { - let data = JSON.read(self.bundlePathFor("Big_data", ofType: "json")!) - measureBlock { - JSON.write(data, path: self.tempPathFor("Big_data.json")) - } - } - - func testTimeWritingPlist() { - let data = Plist.read(self.bundlePathFor("Big_data", ofType: "plist")!) - measureBlock { - Plist.write(data, path: self.tempPathFor("Big_data.plist")) - } - } - - func testTimeWritingBinaryPlist() { - let data = Binary.read(self.bundlePathFor("Big_data-bin", ofType: "plist")!) - measureBlock { - Binary.write(data, path: self.tempPathFor("Big_data-bin.plist")) - } - } -} diff --git a/Tests/Tests/ProtocolTests.swift b/Tests/Tests/ProtocolTests.swift deleted file mode 100644 index 1827ae6..0000000 --- a/Tests/Tests/ProtocolTests.swift +++ /dev/null @@ -1,23 +0,0 @@ -import XCTest - - -class TestProtocols : Test { - - func testCodingProtocols() { - let testEmployee = Employee(name: "Test Employee", title: "Manager") - let testGrandChild = Grandchild(age: 10, name: "Test Grandchild", gender: .Male) - let testChild = TestChild(age: 10, name: "Test Child", myChildren: [testGrandChild, testGrandChild], gender: .Male) - let testConformer1 = TestProtocolConformer(age: 19, ss_number: "12345", isReady: true, employee: testEmployee, children: [testChild, testChild]) - let testConformer2 = TestProtocolConformer2(name: "Test Conformer", ss_number: "1111111") - let testProtocolContainer = TestProtocolContainter(testProtocol: testConformer1, testProtocols: [testConformer1, testConformer2], testProtocolsDict: ["Conformer 1" : testConformer1, "Conformer 2" : testConformer2]) - - testProtocolContainer.save(.Plist, path: tempPathFor("testProtocol.plist")) - print(tempPathFor("testProtocol.plist")) - let inTestProtocolContainer = TestProtocolContainter(.Plist, path: tempPathFor("testProtocol.plist")) - - XCTAssertNotNil(inTestProtocolContainer) - - } - - -} \ No newline at end of file diff --git a/Tests/Tests/RecursiveTests.swift b/Tests/Tests/RecursiveTests.swift deleted file mode 100644 index 2287288..0000000 --- a/Tests/Tests/RecursiveTests.swift +++ /dev/null @@ -1,28 +0,0 @@ -import XCTest -import State - -class RecursiveTests: Test { - - func testEncodingAndDecodingRecursiveModel() { - var player = Player(id: 100, name: "player", age: 23) - var players = [Player]() - var innerPlayers = [Player]() - for index in 1...10 { - players.append(Player(id:index, name: "player\(index)", age:23 )) - } - for index in 1...5 { - innerPlayers.append(Player(id:index, name: "player\(index)", age:23 )) - } - - player.teamates = players - player.teamates[3].fillins = innerPlayers - - player.save(.Plist, path: tempPathFor("player.plist")) - let resultPlayer = Player(.Plist, path: tempPathFor("player.plist")) - - XCTAssert(resultPlayer != nil) - XCTAssert(resultPlayer?.teamates.count == 10) - XCTAssert(resultPlayer?.teamates[1].name != nil) - XCTAssert(resultPlayer?.teamates[3].fillins?.count == 5) - } -} diff --git a/Tests/Tests/RelationshipTests.swift b/Tests/Tests/RelationshipTests.swift deleted file mode 100644 index 9866da1..0000000 --- a/Tests/Tests/RelationshipTests.swift +++ /dev/null @@ -1,63 +0,0 @@ -import XCTest -import State - -class RelationshipTests: Test { - - func makeChildren() -> [TestChild] { - var children = [TestChild]() - for index in 0...9 { - var grandChildren = [Grandchild]() - - for index in 0...4 { - let grandChild = Grandchild(age: index, name: "GrandChild\(index)", gender: Gender.Female) - grandChildren.append(grandChild) - } - let child = TestChild(age: index, name: "Child\(index)", myChildren: grandChildren, gender: Gender.Male) - children.append(child) - } - return children - } - - func makeGrandChildren(children: [TestChild]) -> [Grandchild] { - var grandChildren = [Grandchild]() - - for child in children { - if let grandkids = child.myChildren { - grandChildren.appendContentsOf(grandkids) - } - } - return grandChildren - } - - func testCodingModelWithOneToMany() { - let children = makeChildren() - let grandChildren = makeGrandChildren(children) - let sampleData = TestRelationships(myChildren: children, myGrandChildren: grandChildren, myOneChild: TestChild(age: 22, name: "Mark", myChildren: nil, gender: Gender.Male )) - sampleData.save(.JSON, path: tempPathFor("relationship.json")) - - let testData = TestRelationships(.JSON, path:tempPathFor("relationship.json")) - - XCTAssert(testData != nil) - XCTAssert(testData?.myChildren?.count == sampleData.myChildren?.count) - XCTAssert(testData?.myGrandChildren?.count == sampleData.myGrandChildren?.count) - XCTAssert(testData?.myGrandChildren?[0].name == sampleData.myGrandChildren?[0].name) - XCTAssert(testData?.myOneChild?.name == sampleData.myOneChild?.name) - XCTAssert(testData?.myGrandChildren?[0].gender == sampleData.myGrandChildren?[0].gender) - XCTAssert(testData?.myChildren?[3].age == sampleData.myGrandChildren?[3].age) - } - - - func testCodingModelWithDictionaryComposition() { - var testComposition = TestDictionaryComposition(employees: [String : Employee]()) - let employee1 = Employee(name: "Jane", title: "Manager") - let employee2 = Employee(name: "John", title: nil) - testComposition.employees["Jane"] = employee1 - testComposition.employees["John"] = employee2 - testComposition.save(.Plist, path: tempPathFor("test_composition.plist")) - - let inTestComposition = TestDictionaryComposition(.Plist, path: tempPathFor("test_composition.plist")) - - XCTAssert(inTestComposition != nil) - XCTAssert(inTestComposition?.employees["Jane"]?.title == "Manager") - } -} diff --git a/Tests/Tests/TemplateTests.swift b/Tests/Tests/TemplateTests.swift deleted file mode 100644 index f3e735a..0000000 --- a/Tests/Tests/TemplateTests.swift +++ /dev/null @@ -1,117 +0,0 @@ -import XCTest -import State - -class TemplateTests: Test { - - func testEncodingAndDecodingAutoGeneratedModel() { - var company = Company(name: "State llc",yearFounded: 2015, phoneNumber: "888-888-8888", employees: [Employee]()) - let employee = Employee(name:"Joe", title: "CEO") - company.employees?.append(employee) - let data = company.encode() - Plist.write(data, path: tempPathFor("company.plist")) - let testCompany = Company(.Plist, path: tempPathFor("company.plist")) - - XCTAssert(testCompany != nil) - XCTAssert(testCompany?.name == "State llc") - XCTAssert(testCompany?.phoneNumber == "888-888-8888") - XCTAssert(testCompany?.yearFounded == 2015) - XCTAssert(testCompany?.employees?.count == 1) - XCTAssert(testCompany?.employees?[0].name == "Joe") - } - - func testTypes() { - let test_out = TestTypes() - test_out.save(.Binary, path: tempPathFor("test_types.plist")) - let sut = TestTypes(.Binary, path: tempPathFor("test_types.plist")) - XCTAssert(sut != nil) - XCTAssert(sut?.myBinary != nil) - XCTAssert(sut?.myDate != nil) - XCTAssert(sut?.myFloat == 4.567) - XCTAssert(sut?.myDouble == -0.02) - XCTAssert(sut?.myInt == 5) - XCTAssert(sut?.myString == "Hello World") - XCTAssert(sut?.myDecimal == 3.14) - } - - func testImmutableTypes() { - let test_out = TestImmutableTypes() - test_out.save(.Binary, path: tempPathFor("test_immutable_types.plist")) - let sut = TestImmutableTypes(.Binary, path: tempPathFor("test_immutable_types.plist")) - XCTAssert(sut != nil) - XCTAssert(sut?.myBinary != nil) - XCTAssert(sut?.myDate != nil) - XCTAssert(sut?.myFloat == 4.567) - XCTAssert(sut?.myDouble == -0.02) - XCTAssert(sut?.myInt == 5) - XCTAssert(sut?.myString == "Hello World") - XCTAssert(sut?.myDecimal == 3.14) - } - - func testOptionalTypes() { - let test_out = TestOptionalTypes.CreateTestInstance() - test_out.save(.Binary, path: tempPathFor("test_optional_types.plist")) - let sut = TestOptionalTypes(.Binary, path: tempPathFor("test_optional_types.plist")) - XCTAssert(sut != nil) - XCTAssert(sut?.myBinary != nil) - XCTAssert(sut?.myDate != nil) - XCTAssert(sut?.myFloat == 4.567) - XCTAssert(sut?.myDouble == -0.02) - XCTAssert(sut?.myInt == 5) - XCTAssert(sut?.myString == "Hello World") - XCTAssert(sut?.myDecimal == 3.14) - } - - func testImmutableOptionalTypes() { - let test_out = TestImmutableOptionalTypes() - test_out.save(.Binary, path: tempPathFor("test_immutable_optional_types.plist")) - let sut = TestImmutableOptionalTypes(.Binary, path: tempPathFor("test_immutable_optional_types.plist")) - XCTAssert(sut != nil) - XCTAssert(sut?.myBinary != nil) - XCTAssert(sut?.myDate != nil) - XCTAssert(sut?.myFloat == 4.567) - XCTAssert(sut?.myDouble == -0.02) - XCTAssert(sut?.myInt == 5) - XCTAssert(sut?.myString == "Hello World") - XCTAssert(sut?.myDecimal == 3.14) - } - - func testCollections() { - var test_out = TestCollections() - test_out.arrayOfStrings = ["string1", "string2", "string3"] - test_out.dicOfInts["int1"] = 1 - test_out.dicOfInts["int2"] = 2 - test_out.dicOfInts["int3"] = 3 - test_out.setOfStrings = ["do", "ray", "me"] - test_out.save(.Binary, path: tempPathFor("test_collections.plist")) - let sut = TestCollections(.Binary, path: tempPathFor("test_collections.plist")) - - XCTAssert(sut != nil) - XCTAssert(sut?.arrayOfStrings.count == 3) - XCTAssert(sut?.dicOfInts.count == 3) - XCTAssert(sut?.setOfStrings.count == 3) - } - - func testRawEnum() { - let test_out = TestRawEnum.Ready - test_out.save(.Plist, path: tempPathFor("test_enum.plist")) - let sut = TestRawEnum(.Plist, path: tempPathFor("test_enum.plist")) - XCTAssert(sut != nil) - XCTAssert(sut == TestRawEnum.Ready) - } - - func testTransformable() { - let test_out = TestTransformable( myTransformable: NSURL(string: "http://facebook.com")!, myTransformableImmutable: NSURL(string: "http://yahoo.com")!, myTransformableImmutableOptional: nil, myTransformableOptional:NSURL(string: "http://twitter.com")!) - test_out.save(.Binary, path: tempPathFor("test_transformable.plist")) - let sut = TestTransformable(.Binary, path: tempPathFor("test_transformable.plist")) - XCTAssert(sut != nil) - XCTAssert(sut?.myTransformable == test_out.myTransformable) - XCTAssert(sut?.myTransformableImmutable == test_out.myTransformableImmutable) - XCTAssert(sut?.myTransformableImmutableOptional == test_out.myTransformableImmutableOptional) - XCTAssert(sut?.myTransformableOptional == test_out.myTransformableOptional) - } - - func testOverrideType() { - let test_out: TestOverrideType? = TestOverrideType(myURL: NSURL(string: "http://simpletouchsoftware.com"), myArrayOfString: ["string1", "string2"]) - XCTAssert(test_out != nil) - } -}