From 9d6e527b42481ddcb5ae03430069a994651fec0b Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Tue, 27 Dec 2016 16:27:06 +0100 Subject: [PATCH 01/14] some progress --- Spine/Query.swift | 2 +- Spine/Resource.swift | 89 +++++++++++++++++++++++----------- Spine/ResourceCollection.swift | 4 +- Spine/ResourceFactory.swift | 8 +-- 4 files changed, 68 insertions(+), 35 deletions(-) diff --git a/Spine/Query.swift b/Spine/Query.swift index 36afc5d4..8142a339 100644 --- a/Spine/Query.swift +++ b/Spine/Query.swift @@ -62,7 +62,7 @@ public struct Query { /// - returns: Query public init(resource: T) { assert(resource.id != nil, "Cannot instantiate query for resource, id is nil.") - self.resourceType = resource.resourceType + self.resourceType = resource.resourceType self.url = resource.url self.resourceIDs = [resource.id!] } diff --git a/Spine/Resource.swift b/Spine/Resource.swift index 3213ff7c..9b37995c 100644 --- a/Spine/Resource.swift +++ b/Spine/Resource.swift @@ -42,7 +42,7 @@ public func ==(lhs: ResourceIdentifier, rhs: ResourceIdentifier) -> Bool { } /// A RelationshipData struct holds data about a relationship. -struct RelationshipData { +public struct RelationshipData { var selfURL: URL? var relatedURL: URL? var data: [ResourceIdentifier]? @@ -79,36 +79,69 @@ struct RelationshipData { /// A base recource class that provides some defaults for resources. /// You can create custom resource classes by subclassing from Resource. -open class Resource: NSObject, NSCoding { +public protocol Resource: NSCoding, NSObjectProtocol, Equatable { /// The resource type in plural form. - open class var resourceType: ResourceType { - fatalError("Override resourceType in a subclass.") - } + static var resourceType: ResourceType { get } +// open class var resourceType: ResourceType { +// fatalError("Override resourceType in a subclass.") +// } /// All fields that must be persisted in the API. - open class var fields: [Field] { return [] } + static var fields: [Field] { get } /// The ID of this resource. - public var id: String? + var id: String? { get set } // and set? /// The canonical URL of the resource. - public var url: URL? + var url: URL? { get set } /// Whether the fields of the resource are loaded. - public var isLoaded: Bool = false + var isLoaded: Bool { get set } /// The metadata for this resource. - public var meta: [String: Any]? + var meta: [String: Any]? { get set } /// Raw relationship data keyed by relationship name. - var relationships: [String: RelationshipData] = [:] - - public required override init() { - super.init() - } - - public required init(coder: NSCoder) { - super.init() + var relationships: [String: RelationshipData] { get set } + + var description: String { get } + var debugDescription: String { get } + + + /// Returns the value for the field named `field`. + func value(forField field: String) -> Any? + + /// Sets the value for the field named `field` to `value`. + func setValue(_ value: Any?, forField field: String) + + /// Set the values for all fields to nil and sets `isLoaded` to false. + func unload() + + /// Returns the field named `name`, or nil if no such field exists. + static func field(named name: String) -> Field? +} + +extension Resource where Self: NSObject { +// static var fields: [Field] { +// return [] +// } + + var isLoaded: Bool { + return false + } + + var relationships: [String: RelationshipData] { + return [:] + } + + public init() { + // XXX: check this for recursion + self.init() + } + + public init(coder: NSCoder) { +// super.init() + self.init() self.id = coder.decodeObject(forKey: "id") as? String self.url = coder.decodeObject(forKey: "url") as? URL self.isLoaded = coder.decodeBool(forKey: "isLoaded") @@ -121,8 +154,8 @@ open class Resource: NSObject, NSCoding { } } } - - open func encode(with coder: NSCoder) { + + public func encode(with coder: NSCoder) { coder.encode(id, forKey: "id") coder.encode(url, forKey: "url") coder.encode(isLoaded, forKey: "isLoaded") @@ -135,7 +168,7 @@ open class Resource: NSObject, NSCoding { coder.encode(relationshipsData, forKey: "relationships") } - /// Returns the value for the field named `field`. + /// Returns the value for the field named `field`. func value(forField field: String) -> Any? { return value(forKey: field) as AnyObject? } @@ -147,7 +180,7 @@ open class Resource: NSObject, NSCoding { /// Set the values for all fields to nil and sets `isLoaded` to false. public func unload() { - for field in fields { + for field in Self.fields { setValue(nil, forField: field.name) } @@ -155,27 +188,27 @@ open class Resource: NSObject, NSCoding { } /// Returns the field named `name`, or nil if no such field exists. - class func field(named name: String) -> Field? { + static func field(named name: String) -> Field? { return fields.filter { $0.name == name }.first } } extension Resource { - override open var description: String { - return "\(resourceType)(\(id), \(url))" + var description: String { + return "\(Self.resourceType)(\(id), \(url))" } - override open var debugDescription: String { + var debugDescription: String { return description } } -/// Instance counterparts of class functions +// Instance counterparts of class functions extension Resource { final var resourceType: ResourceType { return type(of: self).resourceType } final var fields: [Field] { return type(of: self).fields } } public func == (left: T, right: T) -> Bool { - return (left.id == right.id) && (left.resourceType == right.resourceType) + return (left.id == right.id) && (left.resourceType == right.resourceType) } diff --git a/Spine/ResourceCollection.swift b/Spine/ResourceCollection.swift index b675f023..13d02b6e 100644 --- a/Spine/ResourceCollection.swift +++ b/Spine/ResourceCollection.swift @@ -170,7 +170,7 @@ public class LinkedResourceCollection: ResourceCollection { /// Link `resource` to the parent resource by appending it to the collection. /// This marks the resource as newly linked. The relationship will be persisted when /// the parent resource is saved. - public func linkResource(_ resource: Resource) { + public func linkResource(_ resource: Resource) { assert(resource.id != nil, "Cannot link resource that hasn't been persisted yet.") resources.append(resource) @@ -200,7 +200,7 @@ public class LinkedResourceCollection: ResourceCollection { /// Link `resources` to the parent resource by appending them to the collection. /// This marks the resources as newly linked. The relationship will be persisted when /// the parent resource is saved. - public func linkResources(_ resources: [Resource]) { + public func linkResources(_ resources: [Resource]) { for resource in resources { linkResource(resource) } diff --git a/Spine/ResourceFactory.swift b/Spine/ResourceFactory.swift index 7683cd47..111fe1b8 100644 --- a/Spine/ResourceFactory.swift +++ b/Spine/ResourceFactory.swift @@ -29,11 +29,11 @@ struct ResourceFactory { /// - throws: A SerializerError.resourceTypeUnregistered erro when the type is not registered. /// /// - returns: An instantiated resource. - func instantiate(_ type: ResourceType) throws -> Resource { - if resourceTypes[type] == nil { + func instantiate(_ type: ResourceType) throws -> Resource { + guard let resourceType = resourceTypes[type] else { throw SerializerError.resourceTypeUnregistered(type) } - return resourceTypes[type]!.init() + return resourceType.init() } @@ -52,7 +52,7 @@ struct ResourceFactory { /// /// - returns: A resource with the given type and id. func dispense(_ type: ResourceType, id: String, pool: inout [Resource], index: Int? = nil) throws -> Resource { - var resource: Resource! = pool.filter { $0.resourceType == type && $0.id == id }.first + var resource: Resource! = pool.filter { $0.resourceType == type && $0.id == id }.first if resource == nil && index != nil && !pool.isEmpty { let applicableResources = pool.filter { $0.resourceType == type } From cee30d5143e7ecba452af90a23733dd0c43de15e Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Wed, 18 Jan 2017 11:43:48 +0100 Subject: [PATCH 02/14] make resource a protocol + convert resource fields --- Cartfile.resolved | 6 +- Spine/DeserializeOperation.swift | 214 +++++++------- Spine/Operation.swift | 41 +-- Spine/Query.swift | 6 +- Spine/Resource.swift | 24 +- Spine/ResourceCollection.swift | 60 ++-- Spine/ResourceField.swift | 482 +++++++++++++++++++++++++++---- Spine/Routing.swift | 26 +- Spine/Serializing.swift | 4 +- Spine/Spine.swift | 28 +- Spine/ValueFormatter.swift | 4 +- SpineTests/Fixtures.swift | 8 +- 12 files changed, 652 insertions(+), 251 deletions(-) diff --git a/Cartfile.resolved b/Cartfile.resolved index 3907670c..62613afa 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,3 +1,3 @@ -github "antitypical/Result" "3.0.0" -github "SwiftyJSON/SwiftyJSON" "3.1.0" -github "Thomvis/BrightFutures" "v5.0.1" +github "antitypical/Result" "3.1.0" +github "SwiftyJSON/SwiftyJSON" "3.1.3" +github "Thomvis/BrightFutures" "v5.1.0" diff --git a/Spine/DeserializeOperation.swift b/Spine/DeserializeOperation.swift index 342561eb..291613da 100644 --- a/Spine/DeserializeOperation.swift +++ b/Spine/DeserializeOperation.swift @@ -176,8 +176,12 @@ class DeserializeOperation: Operation { resource.id = id resource.url = representation["links"]["self"].URL resource.meta = representation["meta"].dictionaryObject - extractAttributes(from: representation, intoResource: resource) - extractRelationships(from: representation, intoResource: resource) +// extractAttributes(from: representation, intoResource: resource) +// extractRelationships(from: representation, intoResource: resource) + + for field in resource.fields { + field.extract(from: representation, intoResource: resource, withKeyFormatter: keyFormatter, withValueFormatters: valueFormatters) + } resource.isLoaded = true @@ -191,32 +195,32 @@ class DeserializeOperation: Operation { /// /// - parameter serializedData: The data from which to extract the attributes. /// - parameter resource: The resource into which to extract the attributes. - fileprivate func extractAttributes(from serializedData: JSON, intoResource resource: Resource) { - for case let field as Attribute in resource.fields { - let key = keyFormatter.format(field) - if let extractedValue = extractAttribute(key, from: serializedData) { - let formattedValue = valueFormatters.unformatValue(extractedValue, forAttribute: field) - resource.setValue(formattedValue, forField: field.name) - } - } - } - +// fileprivate func extractAttributes(from serializedData: JSON, intoResource resource: Resource) { +// for case let field as Attribute in resource.fields { +// let key = keyFormatter.format(field) +// if let extractedValue = extractAttribute(key, from: serializedData) { +// let formattedValue = valueFormatters.unformatValue(extractedValue, forAttribute: field) +// resource.setValue(formattedValue, forField: field.name) +// } +// } +// } + /// Extracts the value for the given key from the passed serialized data. /// /// - parameter key: The data from which to extract the attribute. /// - parameter serializedData: The key for which to extract the value from the data. /// /// - returns: The extracted value or nil if no attribute with the given key was found in the data. - fileprivate func extractAttribute(_ key: String, from serializedData: JSON) -> Any? { - let value = serializedData["attributes"][key] - - if let _ = value.null { - return nil - } else { - return value.rawValue - } - } - +// fileprivate func extractAttribute(_ key: String, from serializedData: JSON) -> Any? { +// let value = serializedData["attributes"][key] +// +// if let _ = value.null { +// return nil +// } else { +// return value.rawValue +// } +// } + // MARK: Relationships @@ -224,28 +228,28 @@ class DeserializeOperation: Operation { /// /// - parameter serializedData: The data from which to extract the relationships. /// - parameter resource: The resource into which to extract the relationships. - fileprivate func extractRelationships(from serializedData: JSON, intoResource resource: Resource) { - for field in resource.fields { - let key = keyFormatter.format(field) - resource.relationships[field.name] = extractRelationshipData(serializedData["relationships"][key]) - - switch field { - case let toOne as ToOneRelationship: - if let linkedResource = extractToOneRelationship(key, from: serializedData, linkedType: toOne.linkedType.resourceType) { - if resource.value(forField: toOne.name) == nil || (resource.value(forField: toOne.name) as? Resource)?.isLoaded == false { - resource.setValue(linkedResource, forField: toOne.name) - } - } - case let toMany as ToManyRelationship: - if let linkedResourceCollection = extractToManyRelationship(key, from: serializedData) { - if linkedResourceCollection.linkage != nil || resource.value(forField: toMany.name) == nil { - resource.setValue(linkedResourceCollection, forField: toMany.name) - } - } - default: () - } - } - } +// fileprivate func extractRelationships(from serializedData: JSON, intoResource resource: Resource) { +// for field in resource.fields { +// let key = keyFormatter.format(field) +// resource.relationships[field.name] = extractRelationshipData(serializedData["relationships"][key]) +// +// switch field { +// case let toOne as ToOneRelationshipProtocol: +// if let linkedResource = toOne.extractToOneRelationship(key, from: serializedData, linkedType: toOne.linkedType) { //extractToOneRelationship(key, from: serializedData, linkedType: toOne.linkedType.resourceType) { // +// if resource.value(forField: toOne.name) == nil || (resource.value(forField: toOne.name) as? Resource)?.isLoaded == false { +// resource.setValue(linkedResource, forField: toOne.name) +// } +// } +// case let toMany as ToManyRelationshipProtocol: +// if let linkedResourceCollection = toMany.extractToManyRelationship(key, from: serializedData) { // extractToManyRelationship(key, from: serializedData, linkedType: toMany.linkedType) { +// if linkedResourceCollection.linkage != nil || resource.value(forField: toMany.name) == nil { +// resource.setValue(linkedResourceCollection, forField: toMany.name) +// } +// } +// default: () +// } +// } +// } /// Extracts the to-one relationship for the given key from the passed serialized data. /// This method supports both the single ID form and the resource object forms. @@ -255,33 +259,33 @@ class DeserializeOperation: Operation { /// - parameter linkedType: The type of the linked resource as it is defined on the parent resource. /// /// - returns: The extracted relationship or nil if no relationship with the given key was found in the data. - fileprivate func extractToOneRelationship(_ key: String, from serializedData: JSON, linkedType: ResourceType) -> Resource? { - var resource: Resource? = nil - - if let linkData = serializedData["relationships"][key].dictionary { - let type = linkData["data"]?["type"].string ?? linkedType - - if let id = linkData["data"]?["id"].string { - do { - resource = try resourceFactory.dispense(type, id: id, pool: &resourcePool) - } catch { - resource = try! resourceFactory.dispense(linkedType, id: id, pool: &resourcePool) - } - } else { - do { - resource = try resourceFactory.instantiate(type) - } catch { - resource = try! resourceFactory.instantiate(linkedType) - } - } - - if let resourceURL = linkData["links"]?["related"].URL { - resource!.url = resourceURL - } - } - - return resource - } +// fileprivate func extractToOneRelationship(_ key: String, from serializedData: JSON, linkedType: ResourceType) -> Resource? { +// var resource: Resource? = nil +// +// if let linkData = serializedData["relationships"][key].dictionary { +// let type = linkData["data"]?["type"].string ?? linkedType +// +// if let id = linkData["data"]?["id"].string { +// do { +// resource = try resourceFactory.dispense(type, id: id, pool: &resourcePool) +// } catch { +// resource = try! resourceFactory.dispense(linkedType, id: id, pool: &resourcePool) +// } +// } else { +// do { +// resource = try resourceFactory.instantiate(type) +// } catch { +// resource = try! resourceFactory.instantiate(linkedType) +// } +// } +// +// if let resourceURL = linkData["links"]?["related"].URL { +// resource!.url = resourceURL +// } +// } +// +// return resource +// } /// Extracts the to-many relationship for the given key from the passed serialized data. /// This method supports both the array of IDs form and the resource object forms. @@ -290,46 +294,46 @@ class DeserializeOperation: Operation { /// - parameter serializedData: The data from which to extract the relationship. /// /// - returns: The extracted relationship or nil if no relationship with the given key was found in the data. - fileprivate func extractToManyRelationship(_ key: String, from serializedData: JSON) -> LinkedResourceCollection? { - var resourceCollection: LinkedResourceCollection? = nil +// fileprivate func extractToManyRelationship(_ key: String, from serializedData: JSON, linkedType type: Resource.Type) -> LinkedResourceCollection? { +// var resourceCollection: LinkedResourceCollection? = nil +// +// if let linkData = serializedData["relationships"][key].dictionary { +// let resourcesURL: URL? = linkData["links"]?["related"].URL +// let linkURL: URL? = linkData["links"]?["self"].URL +// +// if let linkage = linkData["data"]?.array { +// let mappedLinkage = linkage.map { ResourceIdentifier(type: $0["type"].stringValue, id: $0["id"].stringValue) } +// resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: mappedLinkage) +// } else { +// resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: nil) +// } +// } +// +// return resourceCollection +// } - if let linkData = serializedData["relationships"][key].dictionary { - let resourcesURL: URL? = linkData["links"]?["related"].URL - let linkURL: URL? = linkData["links"]?["self"].URL - - if let linkage = linkData["data"]?.array { - let mappedLinkage = linkage.map { ResourceIdentifier(type: $0["type"].stringValue, id: $0["id"].stringValue) } - resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: mappedLinkage) - } else { - resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: nil) - } - } - - return resourceCollection - } - /// Extract the relationship data from the given JSON. /// /// - parameter linkData: The JSON from which to extract relationship data. /// /// - returns: A RelationshipData object. - fileprivate func extractRelationshipData(_ linkData: JSON) -> RelationshipData { - let selfURL = linkData["links"]["self"].URL - let relatedURL = linkData["links"]["related"].URL - let data: [ResourceIdentifier]? - - if let toOne = linkData["data"].dictionary { - data = [ResourceIdentifier(type: toOne["type"]!.stringValue, id: toOne["id"]!.stringValue)] - } else if let toMany = linkData["data"].array { - data = toMany.map { JSON -> ResourceIdentifier in - return ResourceIdentifier(type: JSON["type"].stringValue, id: JSON["id"].stringValue) - } - } else { - data = nil - } - - return RelationshipData(selfURL: selfURL, relatedURL: relatedURL, data: data) - } +// fileprivate func extractRelationshipData(_ linkData: JSON) -> RelationshipData { +// let selfURL = linkData["links"]["self"].URL +// let relatedURL = linkData["links"]["related"].URL +// let data: [ResourceIdentifier]? +// +// if let toOne = linkData["data"].dictionary { +// data = [ResourceIdentifier(type: toOne["type"]!.stringValue, id: toOne["id"]!.stringValue)] +// } else if let toMany = linkData["data"].array { +// data = toMany.map { JSON -> ResourceIdentifier in +// return ResourceIdentifier(type: JSON["type"].stringValue, id: JSON["id"].stringValue) +// } +// } else { +// data = nil +// } +// +// return RelationshipData(selfURL: selfURL, relatedURL: relatedURL, data: data) +// } /// Resolves the relations of the fetched resources. fileprivate func resolveRelationships() { diff --git a/Spine/Operation.swift b/Spine/Operation.swift index ab2414f2..80596076 100644 --- a/Spine/Operation.swift +++ b/Spine/Operation.swift @@ -165,14 +165,14 @@ class FetchOperation: ConcurrentOperation { } /// DeleteOperation deletes a resource from a Spine. -class DeleteOperation: ConcurrentOperation { +class DeleteOperation: ConcurrentOperation { /// The resource to delete. - let resource: Resource + let resource: T /// The result of the operation. You can safely force unwrap this in the completionBlock. var result: Failable? - init(resource: Resource, spine: Spine) { + init(resource: T, spine: Spine) { self.resource = resource super.init() self.spine = spine @@ -208,9 +208,9 @@ class DeleteOperation: ConcurrentOperation { } /// A SaveOperation updates or adds a resource in a Spine. -class SaveOperation: ConcurrentOperation { +class SaveOperation: ConcurrentOperation { /// The resource to save. - let resource: Resource + let resource: T /// The result of the operation. You can safely force unwrap this in the completionBlock. var result: Failable? @@ -220,7 +220,7 @@ class SaveOperation: ConcurrentOperation { fileprivate let relationshipOperationQueue = OperationQueue() - init(resource: Resource, spine: Spine) { + init(resource: T, spine: Spine) { self.resource = resource self.isNewResource = (resource.id == nil) super.init() @@ -394,11 +394,11 @@ private class RelationshipOperation: ConcurrentOperation { } /// A RelationshipReplaceOperation replaces the entire contents of a relationship. -private class RelationshipReplaceOperation: RelationshipOperation { - let resource: Resource - let relationship: Relationship +private class RelationshipReplaceOperation: RelationshipOperation { + let resource: T + let relationship: Relationship - init(resource: Resource, relationship: Relationship, spine: Spine) { + init(resource: T, relationship: Relationship, spine: Spine) { self.resource = resource self.relationship = relationship super.init() @@ -411,9 +411,9 @@ private class RelationshipReplaceOperation: RelationshipOperation { switch relationship { case is ToOneRelationship: - payload = try! serializer.serializeLinkData(resource.value(forField: relationship.name) as? Resource) + payload = try! serializer.serializeLinkData(resource.value(forField: relationship.name) as? T) case is ToManyRelationship: - let relatedResources = (resource.value(forField: relationship.name) as? ResourceCollection)?.resources ?? [] + let relatedResources = (resource.value(forField: relationship.name) as? ResourceCollection)?.resources ?? [] payload = try! serializer.serializeLinkData(relatedResources) default: assertionFailure("Cannot only replace relationship contents for ToOneRelationship and ToManyRelationship") @@ -425,17 +425,18 @@ private class RelationshipReplaceOperation: RelationshipOperation { } } +private enum Mutation { + case add, remove +} + /// A RelationshipMutateOperation mutates a to-many relationship by adding or removing linked resources. -private class RelationshipMutateOperation: RelationshipOperation { - enum Mutation { - case add, remove - } +private class RelationshipMutateOperation: RelationshipOperation { - let resource: Resource + let resource: T let relationship: ToManyRelationship let mutation: Mutation - init(resource: Resource, relationship: ToManyRelationship, mutation: Mutation, spine: Spine) { + init(resource: T, relationship: ToManyRelationship, mutation: Mutation, spine: Spine) { self.resource = resource self.relationship = relationship self.mutation = mutation @@ -444,9 +445,9 @@ private class RelationshipMutateOperation: RelationshipOperation { } override func execute() { - let resourceCollection = resource.value(forField: relationship.name) as! LinkedResourceCollection + let resourceCollection = resource.value(forField: relationship.name) as! LinkedResourceCollection let httpMethod: String - let relatedResources: [Resource] + let relatedResources: [T] switch mutation { case .add: diff --git a/Spine/Query.swift b/Spine/Query.swift index 8142a339..c9fa34d2 100644 --- a/Spine/Query.swift +++ b/Spine/Query.swift @@ -73,7 +73,7 @@ public struct Query { /// - parameter resourceCollection: The resource collection whose resources to fetch. /// /// - returns: Query - public init(resourceType: T.Type, resourceCollection: ResourceCollection) { + public init(resourceType: T.Type, resourceCollection: ResourceCollection) { self.resourceType = T.resourceType self.url = resourceCollection.resourcesURL } @@ -198,7 +198,7 @@ public struct Query { /// /// - parameter relationshipName: The name of the relationship to filter on. /// - parameter resource: The resource that should be related. - public mutating func whereRelationship(_ relationshipName: String, isOrContains resource: Resource) { + public mutating func whereRelationship(_ relationshipName: String, isOrContains resource: U) { assert(resource.id != nil, "Attempt to add a where filter on a relationship, but the target resource does not have an id.") addPredicateWithField(relationshipName, value: resource.id! as AnyObject, type: .equalTo) } @@ -225,7 +225,7 @@ public struct Query { /// /// - parameter type: The resource type for which to restrict the properties. /// - parameter fieldNames: Names of fields to fetch. - public mutating func restrictFieldsOfResourceType(_ type: Resource.Type, to fieldNames: String...) { + public mutating func restrictFieldsOfResourceType(_ type: T.Type, to fieldNames: String...) { for fieldName in fieldNames { guard let field = type.field(named: fieldName) else { assertionFailure("Cannot restrict to field \(fieldName) of resource \(type.resourceType). No such field has been configured.") diff --git a/Spine/Resource.swift b/Spine/Resource.swift index 9b37995c..4d9fbf0b 100644 --- a/Spine/Resource.swift +++ b/Spine/Resource.swift @@ -79,7 +79,7 @@ public struct RelationshipData { /// A base recource class that provides some defaults for resources. /// You can create custom resource classes by subclassing from Resource. -public protocol Resource: NSCoding, NSObjectProtocol, Equatable { +public protocol Resource: class, NSCoding, NSObjectProtocol { /// The resource type in plural form. static var resourceType: ResourceType { get } // open class var resourceType: ResourceType { @@ -119,6 +119,9 @@ public protocol Resource: NSCoding, NSObjectProtocol, Equatable { /// Returns the field named `name`, or nil if no such field exists. static func field(named name: String) -> Field? + + /// XXX: New stuff + static func includeKeys(_ keys: [String], with formatter: KeyFormatter) -> [String] } extension Resource where Self: NSObject { @@ -191,6 +194,25 @@ extension Resource where Self: NSObject { static func field(named name: String) -> Field? { return fields.filter { $0.name == name }.first } + + static func includeKeys(_ keys: [String], with formatter: KeyFormatter) -> [String] { + if keys.count == 0 { + return [] + } + + let k = keys[0] + + if let field = self.field(named: k), let relatedType = field.relatedType { + let remainingKeys = Array(keys[1..: NSObject, NSCoding { /// Whether the resources for this collection are loaded. public var isLoaded: Bool = false @@ -24,21 +24,21 @@ public class ResourceCollection: NSObject, NSCoding { public var previousURL: URL? /// The loaded resources - public internal(set) var resources: [Resource] = [] + public internal(set) var resources: [T] = [] // MARK: Initializers public override init() {} - public init(resources: [Resource], resourcesURL: URL? = nil) { + public init(resources: [T], resourcesURL: URL? = nil) { self.resources = resources self.resourcesURL = resourcesURL self.isLoaded = !resources.isEmpty } init(document: JSONAPIDocument) { - self.resources = document.data ?? [] + self.resources = document.data as? [T] ?? [] self.resourcesURL = document.links?["self"] as URL? self.nextURL = document.links?["next"] as URL? self.previousURL = document.links?["previous"] as URL? @@ -53,7 +53,7 @@ public class ResourceCollection: NSObject, NSCoding { resourcesURL = coder.decodeObject(forKey: "resourcesURL") as? URL nextURL = coder.decodeObject(forKey: "nextURL") as? URL previousURL = coder.decodeObject(forKey: "previousURL") as? URL - resources = coder.decodeObject(forKey: "resources") as! [Resource] + resources = coder.decodeObject(forKey: "resources") as! [T] } public func encode(with coder: NSCoder) { @@ -68,7 +68,7 @@ public class ResourceCollection: NSObject, NSCoding { // MARK: Subscript and count /// Returns the loaded resource at the given index. - public subscript (index: Int) -> Resource { + public subscript (index: Int) -> T { return resources[index] } @@ -79,31 +79,31 @@ public class ResourceCollection: NSObject, NSCoding { /// Returns a resource identified by the given type and id, /// or nil if no resource was found. - public func resourceWithType(_ type: ResourceType, id: String) -> Resource? { + public func resourceWithType(_ type: ResourceType, id: String) -> T? { return resources.filter { $0.id == id && $0.resourceType == type }.first } // MARK: Mutators /// Append `resource` to the collection. - public func appendResource(_ resource: Resource) { + public func appendResource(_ resource: T) { resources.append(resource) } /// Append `resources` to the collection. - public func appendResources(_ resources: [Resource]) { + public func appendResources(_ resources: [T]) { for resource in resources { appendResource(resource) } } /// Remove `resource` from the collection. - open func removeResource(_ resource: Resource) { + open func removeResource(_ resource: T) { resources = resources.filter { $0 !== resource } } /// Remove `resources` from the collection. - open func removeResources(_ resources: [Resource]) { + open func removeResources(_ resources: [T]) { for resource in resources { removeResource(resource) } @@ -111,7 +111,7 @@ public class ResourceCollection: NSObject, NSCoding { } extension ResourceCollection: Sequence { - public typealias Iterator = IndexingIterator<[Resource]> + public typealias Iterator = IndexingIterator<[T]> public func makeIterator() -> Iterator { return resources.makeIterator() @@ -123,7 +123,7 @@ extension ResourceCollection: Sequence { /// /// A `LinkedResourceCollection` keeps track of resources that are linked and unlinked from the collection. /// This allows Spine to make partial updates to the collection when it the parent resource is persisted. -public class LinkedResourceCollection: ResourceCollection { +public class LinkedResourceCollection: ResourceCollection { /// The type/id pairs of resources present in this link. public var linkage: [ResourceIdentifier]? @@ -131,10 +131,10 @@ public class LinkedResourceCollection: ResourceCollection { public var linkURL: URL? /// Resources added to this linked collection, but not yet persisted. - public internal(set) var addedResources: [Resource] = [] + public internal(set) var addedResources: [T] = [] /// Resources removed from this linked collection, but not yet persisted. - public internal(set) var removedResources: [Resource] = [] + public internal(set) var removedResources: [T] = [] public init(resourcesURL: URL?, linkURL: URL?, linkage: [ResourceIdentifier]?) { super.init(resources: [], resourcesURL: resourcesURL) @@ -145,8 +145,8 @@ public class LinkedResourceCollection: ResourceCollection { public required init?(coder: NSCoder) { super.init(coder: coder) linkURL = coder.decodeObject(forKey: "linkURL") as? URL - addedResources = coder.decodeObject(forKey: "addedResources") as! [Resource] - removedResources = coder.decodeObject(forKey: "removedResources") as! [Resource] + addedResources = coder.decodeObject(forKey: "addedResources") as! [T] + removedResources = coder.decodeObject(forKey: "removedResources") as! [T] if let encodedLinkage = coder.decodeObject(forKey: "linkage") as? [NSDictionary] { linkage = encodedLinkage.map { ResourceIdentifier(dictionary: $0) } @@ -166,31 +166,41 @@ public class LinkedResourceCollection: ResourceCollection { } // MARK: Mutators + + private func index(of resource: T, in resources: [T]) -> Int? { + for (index, element) in resources.enumerated() { + if element.isEqual(resource) { + return index + } + } + return nil + } /// Link `resource` to the parent resource by appending it to the collection. /// This marks the resource as newly linked. The relationship will be persisted when /// the parent resource is saved. - public func linkResource(_ resource: Resource) { + public func linkResource(_ resource: T) { assert(resource.id != nil, "Cannot link resource that hasn't been persisted yet.") resources.append(resource) - if let index = removedResources.index(of: resource) { + if let index = self.index(of: resource, in: removedResources) { //removedResources.index(of: resource) { removedResources.remove(at: index) } else { addedResources.append(resource) } + } /// Unlink `resource` from the parent resource by removing it from the collection. /// This marks the resource as unlinked. The relationship will be persisted when /// the parent resource is saved. - public func unlinkResource(_ resource: Resource) { + public func unlinkResource(_ resource: T) { assert(resource.id != nil, "Cannot unlink resource that hasn't been persisted yet.") resources = resources.filter { $0 !== resource } - if let index = addedResources.index(of: resource) { + if let index = self.index(of: resource, in: addedResources) { //addedResources.index(of: resource) { addedResources.remove(at: index) } else { removedResources.append(resource) @@ -200,7 +210,7 @@ public class LinkedResourceCollection: ResourceCollection { /// Link `resources` to the parent resource by appending them to the collection. /// This marks the resources as newly linked. The relationship will be persisted when /// the parent resource is saved. - public func linkResources(_ resources: [Resource]) { + public func linkResources(_ resources: [T]) { for resource in resources { linkResource(resource) } @@ -209,7 +219,7 @@ public class LinkedResourceCollection: ResourceCollection { /// Unlink `resources` from the parent resource by removing then from the collection. /// This marks the resources as unlinked. The relationship will be persisted when /// the parent resource is saved. - public func unlinkResources(_ resources: [Resource]) { + public func unlinkResources(_ resources: [T]) { for resource in resources { unlinkResource(resource) } @@ -217,7 +227,7 @@ public class LinkedResourceCollection: ResourceCollection { /// Append `resource` to the collection as if it is already linked. /// If it was previously linked or unlinked, this status will be removed. - public override func appendResource(_ resource: Resource) { + public override func appendResource(_ resource: T) { super.appendResource(resource) removedResources = removedResources.filter { $0 !== resource } addedResources = addedResources.filter { $0 !== resource } @@ -225,7 +235,7 @@ public class LinkedResourceCollection: ResourceCollection { /// Append `resources` to the collection as if they are already linked. /// If a resource was previously linked or unlinked, this status will be removed. - public override func appendResources(_ resources: [Resource]) { + public override func appendResources(_ resources: [T]) { for resource in resources { appendResource(resource) } diff --git a/Spine/ResourceField.swift b/Spine/ResourceField.swift index 5feabac9..d513c688 100644 --- a/Spine/ResourceField.swift +++ b/Spine/ResourceField.swift @@ -7,7 +7,10 @@ // import Foundation +import SwiftyJSON + +// XXX: remove this public func fieldsFromDictionary(_ dictionary: [String: Field]) -> [Field] { return dictionary.map { (name, field) in field.name = name @@ -17,88 +20,443 @@ public func fieldsFromDictionary(_ dictionary: [String: Field]) -> [Field] { /// Base field. /// Do not use this field type directly, instead use a specific subclass. -open class Field { - /// The name of the field as it appears in the model class. - /// This is declared as an implicit optional to support the `fieldsFromDictionary` function, - /// however it should *never* be nil. - public internal(set) var name: String! = nil - - /// The name of the field that will be used for formatting to the JSON key. - /// This can be nil, in which case the regular name will be used. - public internal(set) var serializedName: String { - get { - return _serializedName ?? name - } - set { - _serializedName = newValue - } - } - fileprivate var _serializedName: String? - - var isReadOnly: Bool = false - - fileprivate init() {} - - /// Sets the serialized name. - /// - /// - parameter name: The serialized name to use. - /// - /// - returns: The field. - public func serializeAs(_ name: String) -> Self { - serializedName = name - return self - } - - public func readOnly() -> Self { - isReadOnly = true - return self - } +//open class Field { +// /// The name of the field as it appears in the model class. +// /// This is declared as an implicit optional to support the `fieldsFromDictionary` function, +// /// however it should *never* be nil. +// public internal(set) var name: String! = nil +// +// /// The name of the field that will be used for formatting to the JSON key. +// /// This can be nil, in which case the regular name will be used. +// public internal(set) var serializedName: String { +// get { +// return _serializedName ?? name +// } +// set { +// _serializedName = newValue +// } +// } +// fileprivate var _serializedName: String? +// +// var isReadOnly: Bool = false +// +// fileprivate init() {} +// +// /// Sets the serialized name. +// /// +// /// - parameter name: The serialized name to use. +// /// +// /// - returns: The field. +// public func serializeAs(_ name: String) -> Self { +// serializedName = name +// return self +// } +// +// public func readOnly() -> Self { +// isReadOnly = true +// return self +// } +//} + +public protocol Field { + var name: String { get set } // XXX: remove set + var serializedName: String { get set } + var isReadOnly: Bool { get set } + + func readOnly() -> Self + func serializeAs(_ serializeName: String) -> Self + + var relatedType: Resource.Type? { get } + + func extract(from serializedData: JSON, + intoResource resource: Resource, + withKeyFormatter keyFormatter: KeyFormatter, + withValueFormatters valueFormatters: ValueFormatterRegistry) +} + +extension Field { + public func readOnly() -> Self { + var newField = self + newField.isReadOnly = true + return newField + } + + public func serializeAs(_ serializeName: String) -> Self { + var newField = self + newField.serializedName = serializeName + return newField + } } +protocol Attribute: Field { + +} + +extension Attribute { + public var relatedType: Resource.Type? { + return nil + } + + public func extract(from serializedData: JSON, + intoResource resource: Resource, + withKeyFormatter keyFormatter: KeyFormatter, + withValueFormatters valueFormatters: ValueFormatterRegistry) { + let key = keyFormatter.format(self) + let value = serializedData["attributes"][key] + + if let _ = value.null { + // XXX: pass + } else { + let formattedValue = valueFormatters.unformatValue(value.rawValue, forAttribute: self) + resource.setValue(formattedValue, forField: self.name) + } + } +} + + +public struct PlainAttribute : Attribute { + public var name: String + public var serializedName: String + public var isReadOnly: Bool = false + + init(withName name: String) { + self.name = name + self.serializedName = name + } +} + +public struct BooleanAttribute : Attribute { + public var name: String + public var serializedName: String + public var isReadOnly: Bool = false + + init(withName name: String) { + self.name = name + self.serializedName = name + } +} + +public struct URLAttribute : Attribute { + public var name: String + public var serializedName: String + public var isReadOnly: Bool = false + public let baseURL: URL? + + init(withName name: String, for url: URL? = nil) { + self.name = name + self.serializedName = name + self.baseURL = url + } +} + +public struct DateAttribute : Attribute { + public var name: String + public var serializedName: String + public var isReadOnly: Bool = false + public let format: String + + init(withName name: String, format: String = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ") { + self.name = name + self.serializedName = name + self.format = format + } +} + + + // MARK: - Built in fields /// A basic attribute field. -open class Attribute: Field { - override public init() {} -} +//open class Attribute: Field { +// override public init() {} +//} /// A URL attribute that maps to an URL property. /// You can optionally specify a base URL to which relative /// URLs will be made absolute. -public class URLAttribute: Attribute { - let baseURL: URL? - - public init(baseURL: URL? = nil) { - self.baseURL = baseURL - } -} +//public class URLAttribute: Attribute { +// let baseURL: URL? +// +// public init(baseURL: URL? = nil) { +// self.baseURL = baseURL +// } +//} /// A date attribute that maps to an NSDate property. /// By default, it uses ISO8601 format `yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ`. /// You can specify a custom format by passing it to the initializer. -public class DateAttribute: Attribute { - let format: String - - public init(format: String = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ") { - self.format = format - } -} +//public class DateAttribute: Attribute { +// let format: String +// +// public init(format: String = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ") { +// self.format = format +// } +//} /// A boolean attribute that maps to an NSNumber property. -public class BooleanAttribute: Attribute {} +//public class BooleanAttribute: Attribute {} /// A basic relationship field. /// Do not use this field type directly, instead use either `ToOneRelationship` or `ToManyRelationship`. -public class Relationship: Field { - let linkedType: Resource.Type - - public init(_ type: Resource.Type) { - linkedType = type - } +//public class Relationship: Field { +// let linkedType: Resource.Type +// +// public init(_ type: Resource.Type) { +// linkedType = type +// } +//} + +//public class Relationship: Field { +// let linkedType: T.Type +// +// public init(_ type: T.Type) { +// linkedType = type +// } +//} + +//protocol Relationship { +// associatedtype LinkedType: Resource +// +//// init(_ type: LinkedType.Type) +//} + +//extension Relationship { +// let linkedTo: LinkedType +// +// public init(_ type: LinkedType.Type) { +// linkedTo = type +// } +//} + +//public class ToOneRelationship: Field, Relationship { +// typealias LinkedType = T +// +// public init(_ type: T.Type) { } +//} +// +//public class ToManyRelationship: Field, Relationship { +// typealias LinkedType = T +// +// +// public init(_ type: T.Type) { } +//} + + + + + +public protocol Relationship : Field { + associatedtype Linked: Resource + // XXX: create protocol that combines Resource and LinkedResourceCollection +// associatedtype ReturnValue + +} + +extension Relationship { + public var relatedType: Resource.Type? { + return Linked.self + } + + + func extractRelationshipData(_ linkData: JSON) -> RelationshipData { + let selfURL = linkData["links"]["self"].URL + let relatedURL = linkData["links"]["related"].URL + let data: [ResourceIdentifier]? + + if let toOne = linkData["data"].dictionary { + data = [ResourceIdentifier(type: toOne["type"]!.stringValue, id: toOne["id"]!.stringValue)] + } else if let toMany = linkData["data"].array { + data = toMany.map { JSON -> ResourceIdentifier in + return ResourceIdentifier(type: JSON["type"].stringValue, id: JSON["id"].stringValue) + } + } else { + data = nil + } + + return RelationshipData(selfURL: selfURL, relatedURL: relatedURL, data: data) + } +} + +//public protocol ToOneRelationshipProtocol: Relationship { +// // XXX: move to RelationshipProtocol +// func extractToOneRelationship(_ key: String, from serializedData: JSON, linkedType: Linked.Type) -> Linked? +//} +// +//public protocol ToManyRelationshipProtocol: Relationship { +// // XXX: move to RelationshipProtocol +// func extractToManyRelationship(_ key: String, from serializedData: JSON) -> LinkedResourceCollection? +//} + +public struct ToOneRelationship : Relationship { + public typealias Linked = T +// public typealias ReturnValue = Linked + + public var name: String + public var serializedName: String + public var isReadOnly: Bool = false + + init(to linkedType: T.Type, withName name: String) { + self.name = name + self.serializedName = name + } + + public func extract(from serializedData: JSON, + intoResource resource: Resource, + withKeyFormatter keyFormatter: KeyFormatter, + withValueFormatters valueFormatters: ValueFormatterRegistry) { + let key = keyFormatter.format(self) + resource.relationships[self.name] = self.extractRelationshipData(serializedData["relationships"][key]) + + var linkedResource: T? = nil + + if let linkData = serializedData["relationships"][key].dictionary { + let type = linkData["data"]?["type"].string ?? Linked.resourceType + + // XXX: do not remove this + // if let id = linkData["data"]?["id"].string { + // do { + // linkedResource = try resourceFactory.dispense(type, id: id, pool: &resourcePool) + // } catch { + // linkedResource = try! resourceFactory.dispense(linkedType.resourceType, id: id, pool: &resourcePool) + // } + // } else { + // do { + // linkedResource = try resourceFactory.instantiate(type) + // } catch { + // linkedResource = try! resourceFactory.instantiate(linkedType.resourceType) + // } + // } + + if let resourceURL = linkData["links"]?["related"].URL { + linkedResource!.url = resourceURL + } + } + + if let linkedResource = linkedResource { + if linkedResource.value(forField: self.name) == nil || (linkedResource.value(forField: self.name) as? Resource)?.isLoaded == false { + linkedResource.setValue(linkedResource, forField: self.name) + } + } + } + +} + +public struct ToManyRelationship : Relationship { + public typealias Linked = T + + public var name: String + public var serializedName: String + public var isReadOnly: Bool = false + + init(to linkedType: T.Type, withName name: String) { + self.name = name + self.serializedName = name + } + + public func extract(from serializedData: JSON, + intoResource resource: Resource, + withKeyFormatter keyFormatter: KeyFormatter, + withValueFormatters valueFormatters: ValueFormatterRegistry) { + let key = keyFormatter.format(self) + resource.relationships[self.name] = self.extractRelationshipData(serializedData["relationships"][key]) + + var resourceCollection: LinkedResourceCollection? = nil + + if let linkData = serializedData["relationships"][key].dictionary { + let resourcesURL: URL? = linkData["links"]?["related"].URL + let linkURL: URL? = linkData["links"]?["self"].URL + + if let linkage = linkData["data"]?.array { + let mappedLinkage = linkage.map { ResourceIdentifier(type: $0["type"].stringValue, id: $0["id"].stringValue) } + resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: mappedLinkage) + } else { + resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: nil) + } + } + + if let linkedResourceCollection = resourceCollection { + if linkedResourceCollection.linkage != nil || resource.value(forField: self.name) == nil { + resource.setValue(linkedResourceCollection, forField: self.name) + } + } + } + +// public func extractToManyRelationship(_ key: String, from serializedData: JSON) -> LinkedResourceCollection? { +// var resourceCollection: LinkedResourceCollection? = nil +// +// if let linkData = serializedData["relationships"][key].dictionary { +// let resourcesURL: URL? = linkData["links"]?["related"].URL +// let linkURL: URL? = linkData["links"]?["self"].URL +// +// if let linkage = linkData["data"]?.array { +// let mappedLinkage = linkage.map { ResourceIdentifier(type: $0["type"].stringValue, id: $0["id"].stringValue) } +// resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: mappedLinkage) +// } else { +// resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: nil) +// } +// } +// +// return resourceCollection +// } } /// A to-one relationship field. -public class ToOneRelationship: Relationship { } +//public class ToOneRelationship: Relationship { } +//public class ToOneRelationship: Field, ToOneRelationshipProtcol { +// typealias Linked = T +// typealias ReturnValue = Linked +// +// func extractToOneRelationship(_ key: String, from serializedData: JSON, linkedType: T.Type) -> T? { +// var resource: T? = nil +// +// if let linkData = serializedData["relationships"][key].dictionary { +// let type = linkData["data"]?["type"].string ?? linkedType.resourceType +// +// // XXX: do not remove this +//// if let id = linkData["data"]?["id"].string { +//// do { +//// resource = try resourceFactory.dispense(type, id: id, pool: &resourcePool) +//// } catch { +//// resource = try! resourceFactory.dispense(linkedType.resourceType, id: id, pool: &resourcePool) +//// } +//// } else { +//// do { +//// resource = try resourceFactory.instantiate(type) +//// } catch { +//// resource = try! resourceFactory.instantiate(linkedType.resourceType) +//// } +//// } +// +// if let resourceURL = linkData["links"]?["related"].URL { +// resource!.url = resourceURL +// } +// } +// +// return resource +// } +//} /// A to-many relationship field. -public class ToManyRelationship: Relationship { } +//public class ToManyRelationship: Relationship { } +//public class ToManyRelationship: Field, ToManyRelationshipProtcol { +// typealias Linked = T +// typealias ReturnValue = LinkedResourceCollection +// +// func extractToManyRelationship(_ key: String, from serializedData: JSON) -> LinkedResourceCollection? { +// var resourceCollection: LinkedResourceCollection? = nil +// +// if let linkData = serializedData["relationships"][key].dictionary { +// let resourcesURL: URL? = linkData["links"]?["related"].URL +// let linkURL: URL? = linkData["links"]?["self"].URL +// +// if let linkage = linkData["data"]?.array { +// let mappedLinkage = linkage.map { ResourceIdentifier(type: $0["type"].stringValue, id: $0["id"].stringValue) } +// resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: mappedLinkage) +// } else { +// resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: nil) +// } +// } +// +// return resourceCollection +// } +//} diff --git a/Spine/Routing.swift b/Spine/Routing.swift index 94898939..317cf3d3 100644 --- a/Spine/Routing.swift +++ b/Spine/Routing.swift @@ -34,7 +34,7 @@ public protocol Router: class { - returns: The URL. */ - func urlForRelationship(_ relationship: Relationship, ofResource resource: T) -> URL + func urlForRelationship(_ relationship: U, ofResource resource: T) -> URL /** Returns an URL that represents the given query. @@ -69,7 +69,7 @@ open class JSONAPIRouter: Router { return baseURL.appendingPathComponent(type) } - open func urlForRelationship(_ relationship: Relationship, ofResource resource: T) -> URL { + open func urlForRelationship(_ relationship: U, ofResource resource: T) -> URL { if let selfURL = resource.relationships[relationship.name]?.selfURL { return selfURL } @@ -115,15 +115,19 @@ open class JSONAPIRouter: Router { var resolvedIncludes = [String]() for include in query.includes { - var keys = [String]() - - var relatedResourceType: Resource.Type = T.self - for part in include.components(separatedBy: ".") { - if let relationship = relatedResourceType.field(named: part) as? Relationship { - keys.append(keyFormatter.format(relationship)) - relatedResourceType = relationship.linkedType - } - } + let keys = T.includeKeys(include.components(separatedBy: "."), with: keyFormatter) + +// var keys = [String]() +// +// var relatedResourceType: Resource.Type = T.self +// for part in include.components(separatedBy: ".") { +// if let relationship = relatedResourceType.field(named: part) as? Relationship { +// keys.append(keyFormatter.format(relationship)) +// relatedResourceType = relationship.linkedType +// } +// } + + resolvedIncludes.append(keys.joined(separator: ".")) } diff --git a/Spine/Serializing.swift b/Spine/Serializing.swift index c1a30ef9..a883d341 100644 --- a/Spine/Serializing.swift +++ b/Spine/Serializing.swift @@ -76,7 +76,7 @@ public class Serializer { /// - throws: SerializerError that can occur in the serialization. /// /// - returns: Serialized data. - public func serializeResources(_ resources: [Resource], options: SerializationOptions = [.IncludeID]) throws -> Data { + public func serializeResources(_ resources: [T], options: SerializationOptions = [.IncludeID]) throws -> Data { let document = JSONAPIDocument(data: resources, included: nil, errors: nil, meta: nil, links: nil, jsonapi: nil) return try serializeDocument(document, options: options) } @@ -167,6 +167,8 @@ public struct JSONAPIDocument { /// Included resources extracted from the response. public var included: [Resource]? + + public var inc: [String: Resource]? /// Errors extracted from the response. public var errors: [APIError]? diff --git a/Spine/Spine.swift b/Spine/Spine.swift index cf58198f..13d74204 100644 --- a/Spine/Spine.swift +++ b/Spine/Spine.swift @@ -112,8 +112,8 @@ open class Spine { /// - parameter query: The query describing which resources to fetch. /// /// - returns: A future that resolves to a tuple containing the fetched ResourceCollection, the document meta, and the document jsonapi object. - open func find(_ query: Query) -> Future<(resources: ResourceCollection, meta: Metadata?, jsonapi: JSONAPIData?), SpineError> { - let promise = Promise<(resources: ResourceCollection, meta: Metadata?, jsonapi: JSONAPIData?), SpineError>() + open func find(_ query: Query) -> Future<(resources: ResourceCollection, meta: Metadata?, jsonapi: JSONAPIData?), SpineError> { + let promise = Promise<(resources: ResourceCollection, meta: Metadata?, jsonapi: JSONAPIData?), SpineError>() let operation = FetchOperation(query: query, spine: self) @@ -121,7 +121,7 @@ open class Spine { switch operation.result! { case .success(let document): - let response = (ResourceCollection(document: document), document.meta, document.jsonapi) + let response = (ResourceCollection(document: document), document.meta, document.jsonapi) promise.success(response) case .failure(let error): promise.failure(error) @@ -139,7 +139,7 @@ open class Spine { /// - parameter type: The type of resource to fetch. /// /// - returns: A future that resolves to a tuple containing the fetched ResourceCollection, the document meta, and the document jsonapi object. - open func find(_ ids: [String], ofType type: T.Type) -> Future<(resources: ResourceCollection, meta: Metadata?, jsonapi: JSONAPIData?), SpineError> { + open func find(_ ids: [String], ofType type: T.Type) -> Future<(resources: ResourceCollection, meta: Metadata?, jsonapi: JSONAPIData?), SpineError> { let query = Query(resourceType: type, resourceIDs: ids) return find(query) } @@ -193,7 +193,7 @@ open class Spine { /// - parameter type: The type of resource to fetch. /// /// - returns: A future that resolves to a tuple containing the fetched ResourceCollection, the document meta, and the document jsonapi object. - open func findAll(_ type: T.Type) -> Future<(resources: ResourceCollection, meta: Metadata?, jsonapi: JSONAPIData?), SpineError> { + open func findAll(_ type: T.Type) -> Future<(resources: ResourceCollection, meta: Metadata?, jsonapi: JSONAPIData?), SpineError> { let query = Query(resourceType: type) return find(query) } @@ -277,17 +277,17 @@ open class Spine { /// - parameter collection: The collection for which to load the next page. /// /// - returns: A future that resolves to the ResourceCollection including the newly loaded resources. - open func loadNextPageOfCollection(_ collection: ResourceCollection) -> Future { - let promise = Promise() + open func loadNextPageOfCollection(_ collection: ResourceCollection) -> Future, SpineError> { + let promise = Promise, SpineError>() if let nextURL = collection.nextURL { - let query = Query(url: nextURL) + let query = Query(url: nextURL) let operation = FetchOperation(query: query, spine: self) operation.completionBlock = { [unowned operation] in switch operation.result! { case .success(let document): - let nextCollection = ResourceCollection(document: document) + let nextCollection = ResourceCollection(document: document) collection.resources += nextCollection.resources collection.resourcesURL = nextCollection.resourcesURL collection.nextURL = nextCollection.nextURL @@ -314,17 +314,17 @@ open class Spine { /// - parameter collection: The collection for which to load the previous page. /// /// - returns: A future that resolves to the ResourceCollection including the newly loaded resources. - open func loadPreviousPageOfCollection(_ collection: ResourceCollection) -> Future { - let promise = Promise() + open func loadPreviousPageOfCollection(_ collection: ResourceCollection) -> Future, SpineError> { + let promise = Promise, SpineError>() if let previousURL = collection.previousURL { - let query = Query(url: previousURL) + let query = Query(url: previousURL) let operation = FetchOperation(query: query, spine: self) operation.completionBlock = { [unowned operation] in switch operation.result! { case .success(let document): - let previousCollection = ResourceCollection(document: document) + let previousCollection = ResourceCollection(document: document) collection.resources = previousCollection.resources + collection.resources collection.resourcesURL = previousCollection.resourcesURL collection.nextURL = previousCollection.nextURL @@ -398,7 +398,7 @@ public extension Spine { /// Registers a resource class. /// /// - parameter resourceClass: The resource class to register. - func registerResource(_ resourceClass: Resource.Type) { + func registerResource(_ resourceClass: T.Type) { serializer.registerResource(resourceClass) } diff --git a/Spine/ValueFormatter.swift b/Spine/ValueFormatter.swift index e53b9ca0..cc94575d 100644 --- a/Spine/ValueFormatter.swift +++ b/Spine/ValueFormatter.swift @@ -42,7 +42,7 @@ public protocol ValueFormatter { /// A value formatter Registry keeps a list of value formatters, and chooses between these value formatters /// to transform values between the serialized and deserialized form. -struct ValueFormatterRegistry { +public struct ValueFormatterRegistry { /// Registered serializer functions. fileprivate var formatters: [(Any, Attribute) -> Any?] = [] @@ -134,7 +134,7 @@ struct ValueFormatterRegistry { /// it will return an absolute URL, relative to the baseURL. private struct URLValueFormatter: ValueFormatter { func unformatValue(_ value: String, forAttribute attribute: URLAttribute) -> URL { - return URL(string: value, relativeTo: attribute.baseURL as URL?)! + return URL(string: value, relativeTo: attribute.baseURL)! } func formatValue(_ value: URL, forAttribute attribute: URLAttribute) -> String { diff --git a/SpineTests/Fixtures.swift b/SpineTests/Fixtures.swift index 6182e1c9..623e44aa 100644 --- a/SpineTests/Fixtures.swift +++ b/SpineTests/Fixtures.swift @@ -26,11 +26,11 @@ class Foo: Resource { override class var fields: [Field] { return fieldsFromDictionary([ - "stringAttribute": Attribute(), - "integerAttribute": Attribute(), - "floatAttribute": Attribute(), + "stringAttribute": PlainAttribute(), + "integerAttribute": PlainAttribute(), + "floatAttribute": PlainAttribute(), "booleanAttribute": BooleanAttribute(), - "nilAttribute": Attribute(), + "nilAttribute": PlainAttribute(), "dateAttribute": DateAttribute(), "toOneAttribute": ToOneRelationship(Bar.self), "toManyAttribute": ToManyRelationship(Bar.self) From 454e948ede5ed04dd94f6a1dc6392b814b05033b Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Wed, 18 Jan 2017 12:05:00 +0100 Subject: [PATCH 03/14] changes to fixtures and fields inits --- Spine/ResourceField.swift | 24 +++++++------- SpineTests/Fixtures.swift | 69 +++++++++++++++++++-------------------- 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/Spine/ResourceField.swift b/Spine/ResourceField.swift index d513c688..e9122a76 100644 --- a/Spine/ResourceField.swift +++ b/Spine/ResourceField.swift @@ -11,12 +11,12 @@ import SwiftyJSON // XXX: remove this -public func fieldsFromDictionary(_ dictionary: [String: Field]) -> [Field] { - return dictionary.map { (name, field) in - field.name = name - return field - } -} +//public func fieldsFromDictionary(_ dictionary: [String: Field]) -> [Field] { +// return dictionary.map { (name, field) in +// field.name = name +// return field +// } +//} /// Base field. /// Do not use this field type directly, instead use a specific subclass. @@ -119,7 +119,7 @@ public struct PlainAttribute : Attribute { public var serializedName: String public var isReadOnly: Bool = false - init(withName name: String) { + init(_ name: String) { self.name = name self.serializedName = name } @@ -130,7 +130,7 @@ public struct BooleanAttribute : Attribute { public var serializedName: String public var isReadOnly: Bool = false - init(withName name: String) { + init(_ name: String) { self.name = name self.serializedName = name } @@ -142,7 +142,7 @@ public struct URLAttribute : Attribute { public var isReadOnly: Bool = false public let baseURL: URL? - init(withName name: String, for url: URL? = nil) { + init(_ name: String, for url: URL? = nil) { self.name = name self.serializedName = name self.baseURL = url @@ -155,7 +155,7 @@ public struct DateAttribute : Attribute { public var isReadOnly: Bool = false public let format: String - init(withName name: String, format: String = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ") { + init(_ name: String, format: String = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ") { self.name = name self.serializedName = name self.format = format @@ -295,7 +295,7 @@ public struct ToOneRelationship : Relationship { public var serializedName: String public var isReadOnly: Bool = false - init(to linkedType: T.Type, withName name: String) { + init(_ name: String, to linkedType: T.Type) { self.name = name self.serializedName = name } @@ -348,7 +348,7 @@ public struct ToManyRelationship : Relationship { public var serializedName: String public var isReadOnly: Bool = false - init(to linkedType: T.Type, withName name: String) { + init(_ name: String, to linkedType: T.Type) { self.name = name self.serializedName = name } diff --git a/SpineTests/Fixtures.swift b/SpineTests/Fixtures.swift index 623e44aa..35f2b8ca 100644 --- a/SpineTests/Fixtures.swift +++ b/SpineTests/Fixtures.swift @@ -10,7 +10,11 @@ import Foundation import XCTest import SwiftyJSON -class Foo: Resource { +class Foo: NSObject, Resource { + var id: String? + var url: URL? +// var isLoaded: Bool + var stringAttribute: String? var integerAttribute: NSNumber? var floatAttribute: NSNumber? @@ -18,27 +22,23 @@ class Foo: Resource { var nilAttribute: AnyObject? var dateAttribute: Date? var toOneAttribute: Bar? - var toManyAttribute: LinkedResourceCollection? + var toManyAttribute: LinkedResourceCollection? - override class var resourceType: String { + static var resourceType: String { return "foos" } - override class var fields: [Field] { - return fieldsFromDictionary([ - "stringAttribute": PlainAttribute(), - "integerAttribute": PlainAttribute(), - "floatAttribute": PlainAttribute(), - "booleanAttribute": BooleanAttribute(), - "nilAttribute": PlainAttribute(), - "dateAttribute": DateAttribute(), - "toOneAttribute": ToOneRelationship(Bar.self), - "toManyAttribute": ToManyRelationship(Bar.self) - ]) - } - - required init() { - super.init() + static var fields: [Field] { + return [ + PlainAttribute("stringAttribute"), + PlainAttribute("integerAttribute"), + PlainAttribute("floatAttribute"), + BooleanAttribute("booleanAttribute"), + PlainAttribute("nilAttribute"), + DateAttribute("dateAttribute"), + ToOneRelationship("toOneAttribute", to: Bar.self), + ToManyRelationship("toManyAttribute", to: Bar.self) + ] } init(id: String) { @@ -46,28 +46,27 @@ class Foo: Resource { self.id = id } - required init(coder: NSCoder) { - super.init(coder: coder) - } +// required init(coder: NSCoder) { +// super.init(coder: coder) +// } } -class Bar: Resource { +class Bar: NSObject, Resource { + var id: String? + var url: URL? + var barStringAttribute: String? var barIntegerAttribute: NSNumber? - override class var resourceType: String { + static var resourceType: String { return "bars" } - override class var fields: [Field] { - return fieldsFromDictionary([ - "barStringAttribute": Attribute(), - "barIntegerAttribute": Attribute() - ]) - } - - required init() { - super.init() + static var fields: [Field] { + return [ + PlainAttribute("barStringAttribute"), + PlainAttribute("barIntegerAttribute"), + ] } init(id: String) { @@ -75,7 +74,7 @@ class Bar: Resource { self.id = id } - required init(coder: NSCoder) { - super.init(coder: coder) - } +// required init(coder: NSCoder) { +// super.init(coder: coder) +// } } From 561940fca3787d7deea0894c86e336a9f74ef115 Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Wed, 18 Jan 2017 13:53:19 +0100 Subject: [PATCH 04/14] work on dispense function --- Spine/DeserializeOperation.swift | 2 +- Spine/Resource.swift | 68 ++++++++++++++++---------------- Spine/ResourceFactory.swift | 61 +++++++++++++++++++--------- Spine/ResourceField.swift | 41 ++++++++++--------- 4 files changed, 98 insertions(+), 74 deletions(-) diff --git a/Spine/DeserializeOperation.swift b/Spine/DeserializeOperation.swift index 291613da..2aad9321 100644 --- a/Spine/DeserializeOperation.swift +++ b/Spine/DeserializeOperation.swift @@ -180,7 +180,7 @@ class DeserializeOperation: Operation { // extractRelationships(from: representation, intoResource: resource) for field in resource.fields { - field.extract(from: representation, intoResource: resource, withKeyFormatter: keyFormatter, withValueFormatters: valueFormatters) + field.extract(from: representation, intoResource: resource, withKeyFormatter: keyFormatter, withValueFormatters: valueFormatters, fromResourcePool: &resourcePool, withFactory: resourceFactory) } resource.isLoaded = true diff --git a/Spine/Resource.swift b/Spine/Resource.swift index 4d9fbf0b..7a4ef602 100644 --- a/Spine/Resource.swift +++ b/Spine/Resource.swift @@ -79,7 +79,7 @@ public struct RelationshipData { /// A base recource class that provides some defaults for resources. /// You can create custom resource classes by subclassing from Resource. -public protocol Resource: class, NSCoding, NSObjectProtocol { +public protocol Resource: class, NSObjectProtocol { // NSCoding, /// The resource type in plural form. static var resourceType: ResourceType { get } // open class var resourceType: ResourceType { @@ -122,6 +122,8 @@ public protocol Resource: class, NSCoding, NSObjectProtocol { /// XXX: New stuff static func includeKeys(_ keys: [String], with formatter: KeyFormatter) -> [String] + + init() } extension Resource where Self: NSObject { @@ -137,39 +139,39 @@ extension Resource where Self: NSObject { return [:] } - public init() { - // XXX: check this for recursion - self.init() - } - - public init(coder: NSCoder) { -// super.init() - self.init() - self.id = coder.decodeObject(forKey: "id") as? String - self.url = coder.decodeObject(forKey: "url") as? URL - self.isLoaded = coder.decodeBool(forKey: "isLoaded") - self.meta = coder.decodeObject(forKey: "meta") as? [String: AnyObject] - - if let relationshipsData = coder.decodeObject(forKey: "relationships") as? [String: NSDictionary] { - var relationships = [String: RelationshipData]() - for (key, value) in relationshipsData { - relationships[key] = RelationshipData.init(dictionary: value) - } - } - } +// public init() { +// // XXX: check this for recursion +// self.init() +// } - public func encode(with coder: NSCoder) { - coder.encode(id, forKey: "id") - coder.encode(url, forKey: "url") - coder.encode(isLoaded, forKey: "isLoaded") - coder.encode(meta, forKey: "meta") - - var relationshipsData = [String: NSDictionary]() - for (key, value) in relationships { - relationshipsData[key] = value.toDictionary() - } - coder.encode(relationshipsData, forKey: "relationships") - } +// public init(coder: NSCoder) { +//// super.init() +//// self.init() +// self.id = coder.decodeObject(forKey: "id") as? String +// self.url = coder.decodeObject(forKey: "url") as? URL +// self.isLoaded = coder.decodeBool(forKey: "isLoaded") +// self.meta = coder.decodeObject(forKey: "meta") as? [String: AnyObject] +// +// if let relationshipsData = coder.decodeObject(forKey: "relationships") as? [String: NSDictionary] { +// var relationships = [String: RelationshipData]() +// for (key, value) in relationshipsData { +// relationships[key] = RelationshipData.init(dictionary: value) +// } +// } +// } +// +// public func encode(with coder: NSCoder) { +// coder.encode(id, forKey: "id") +// coder.encode(url, forKey: "url") +// coder.encode(isLoaded, forKey: "isLoaded") +// coder.encode(meta, forKey: "meta") +// +// var relationshipsData = [String: NSDictionary]() +// for (key, value) in relationships { +// relationshipsData[key] = value.toDictionary() +// } +// coder.encode(relationshipsData, forKey: "relationships") +// } /// Returns the value for the field named `field`. func value(forField field: String) -> Any? { diff --git a/Spine/ResourceFactory.swift b/Spine/ResourceFactory.swift index 111fe1b8..e891e09b 100644 --- a/Spine/ResourceFactory.swift +++ b/Spine/ResourceFactory.swift @@ -10,7 +10,7 @@ import Foundation /// A ResourceFactory creates resources from given factory funtions. -struct ResourceFactory { +public struct ResourceFactory { fileprivate var resourceTypes: [ResourceType: Resource.Type] = [:] @@ -51,22 +51,45 @@ struct ResourceFactory { /// - throws: A SerializerError.resourceTypeUnregistered erro when the type is not registered. /// /// - returns: A resource with the given type and id. - func dispense(_ type: ResourceType, id: String, pool: inout [Resource], index: Int? = nil) throws -> Resource { - var resource: Resource! = pool.filter { $0.resourceType == type && $0.id == id }.first - - if resource == nil && index != nil && !pool.isEmpty { - let applicableResources = pool.filter { $0.resourceType == type } - if index! < applicableResources.count { - resource = applicableResources[index!] - } - } - - if resource == nil { - resource = try instantiate(type) - resource.id = id - pool.append(resource) - } - - return resource - } +// func dispense(_ type: ResourceType, id: String, pool: inout [Resource], index: Int? = nil) throws -> T { +// +// if let resource = (pool.filter { $0.resourceType == type && $0.id == id }.first) as? T { +// return resource +// } +// +// if !pool.isEmpty { +// if let applicableResources = (pool.filter { $0.resourceType == type }) as? [T], let index = index { +// if index < applicableResources.count { +// return applicableResources[index] +// } +// } +// +// } +// +// let resource = try instantiate(type) as! T +// resource.id = id +// pool.append(resource) +// return resource +// } + + func dispense(_ type: T.Type, id: String, pool: inout [Resource], index: Int? = nil) -> T { + + if let resource = (pool.filter { $0.resourceType == T.resourceType && $0.id == id }.first) as? T { + return resource + } + + if !pool.isEmpty { + if let applicableResources = (pool.filter { $0.resourceType == T.resourceType }) as? [T], let index = index { + if index < applicableResources.count { + return applicableResources[index] + } + } + + } + + let resource = T.init() + resource.id = id + pool.append(resource) + return resource + } } diff --git a/Spine/ResourceField.swift b/Spine/ResourceField.swift index e9122a76..e0f142f6 100644 --- a/Spine/ResourceField.swift +++ b/Spine/ResourceField.swift @@ -71,7 +71,9 @@ public protocol Field { func extract(from serializedData: JSON, intoResource resource: Resource, withKeyFormatter keyFormatter: KeyFormatter, - withValueFormatters valueFormatters: ValueFormatterRegistry) + withValueFormatters valueFormatters: ValueFormatterRegistry, + fromResourcePool pool: inout [Resource], + withFactory factory: ResourceFactory) } extension Field { @@ -100,7 +102,9 @@ extension Attribute { public func extract(from serializedData: JSON, intoResource resource: Resource, withKeyFormatter keyFormatter: KeyFormatter, - withValueFormatters valueFormatters: ValueFormatterRegistry) { + withValueFormatters valueFormatters: ValueFormatterRegistry, + fromResourcePool pool: inout [Resource], + withFactory factory: ResourceFactory) { let key = keyFormatter.format(self) let value = serializedData["attributes"][key] @@ -303,30 +307,23 @@ public struct ToOneRelationship : Relationship { public func extract(from serializedData: JSON, intoResource resource: Resource, withKeyFormatter keyFormatter: KeyFormatter, - withValueFormatters valueFormatters: ValueFormatterRegistry) { + withValueFormatters valueFormatters: ValueFormatterRegistry, + fromResourcePool pool: inout [Resource], + withFactory factory: ResourceFactory) { let key = keyFormatter.format(self) resource.relationships[self.name] = self.extractRelationshipData(serializedData["relationships"][key]) var linkedResource: T? = nil if let linkData = serializedData["relationships"][key].dictionary { - let type = linkData["data"]?["type"].string ?? Linked.resourceType - - // XXX: do not remove this - // if let id = linkData["data"]?["id"].string { - // do { - // linkedResource = try resourceFactory.dispense(type, id: id, pool: &resourcePool) - // } catch { - // linkedResource = try! resourceFactory.dispense(linkedType.resourceType, id: id, pool: &resourcePool) - // } - // } else { - // do { - // linkedResource = try resourceFactory.instantiate(type) - // } catch { - // linkedResource = try! resourceFactory.instantiate(linkedType.resourceType) - // } - // } - + assert(linkData["data"]?["type"].string == Linked.resourceType) + + if let id = linkData["data"]?["id"].string { + linkedResource = factory.dispense(Linked.self, id: id, pool: &pool) + } else { + linkedResource = Linked.init() + } + if let resourceURL = linkData["links"]?["related"].URL { linkedResource!.url = resourceURL } @@ -356,7 +353,9 @@ public struct ToManyRelationship : Relationship { public func extract(from serializedData: JSON, intoResource resource: Resource, withKeyFormatter keyFormatter: KeyFormatter, - withValueFormatters valueFormatters: ValueFormatterRegistry) { + withValueFormatters valueFormatters: ValueFormatterRegistry, + fromResourcePool: inout [Resource], + withFactory: ResourceFactory) { let key = keyFormatter.format(self) resource.relationships[self.name] = self.extractRelationshipData(serializedData["relationships"][key]) From 78b9f47880253c4da7d92d1e1ff4715c3be252e7 Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Wed, 18 Jan 2017 14:17:07 +0100 Subject: [PATCH 05/14] work on resolveRelationships --- Spine/DeserializeOperation.swift | 48 +++++++++++++++++--------------- Spine/ResourceField.swift | 24 ++++++++++++++++ 2 files changed, 50 insertions(+), 22 deletions(-) diff --git a/Spine/DeserializeOperation.swift b/Spine/DeserializeOperation.swift index 2aad9321..f73b231c 100644 --- a/Spine/DeserializeOperation.swift +++ b/Spine/DeserializeOperation.swift @@ -338,28 +338,32 @@ class DeserializeOperation: Operation { /// Resolves the relations of the fetched resources. fileprivate func resolveRelationships() { for resource in resourcePool { - for case let field as ToManyRelationship in resource.fields { - - guard let linkedResourceCollection = resource.value(forField: field.name) as? LinkedResourceCollection else { - Spine.logInfo(.serializing, "Cannot resolve relationship '\(field.name)' of \(resource.resourceType):\(resource.id!) because the JSON did not include the relationship.") - continue - } - - guard let linkage = linkedResourceCollection.linkage else { - Spine.logInfo(.serializing, "Cannot resolve relationship '\(field.name)' of \(resource.resourceType):\(resource.id!) because the JSON did not include linkage.") - continue - } - - let targetResources = linkage.flatMap { (link: ResourceIdentifier) in - return resourcePool.filter { $0.resourceType == link.type && $0.id == link.id } - } - - if !targetResources.isEmpty { - linkedResourceCollection.resources = targetResources - linkedResourceCollection.isLoaded = true - } - - } + for field in resource.fields { + field.resolve(for: resource, withResourcePool: resourcePool) + } + +// for case let field as ToManyRelationship in resource.fields { +// +// guard let linkedResourceCollection = resource.value(forField: field.name) as? LinkedResourceCollection else { +// Spine.logInfo(.serializing, "Cannot resolve relationship '\(field.name)' of \(resource.resourceType):\(resource.id!) because the JSON did not include the relationship.") +// continue +// } +// +// guard let linkage = linkedResourceCollection.linkage else { +// Spine.logInfo(.serializing, "Cannot resolve relationship '\(field.name)' of \(resource.resourceType):\(resource.id!) because the JSON did not include linkage.") +// continue +// } +// +// let targetResources = linkage.flatMap { (link: ResourceIdentifier) in +// return resourcePool.filter { $0.resourceType == link.type && $0.id == link.id } +// } +// +// if !targetResources.isEmpty { +// linkedResourceCollection.resources = targetResources +// linkedResourceCollection.isLoaded = true +// } +// +// } } } } diff --git a/Spine/ResourceField.swift b/Spine/ResourceField.swift index e0f142f6..a08be827 100644 --- a/Spine/ResourceField.swift +++ b/Spine/ResourceField.swift @@ -74,6 +74,7 @@ public protocol Field { withValueFormatters valueFormatters: ValueFormatterRegistry, fromResourcePool pool: inout [Resource], withFactory factory: ResourceFactory) + func resolve(for resource: Resource, withResourcePool pool: [Resource]) } extension Field { @@ -88,6 +89,8 @@ extension Field { newField.serializedName = serializeName return newField } + + public func resolve(for resource: Resource, withResourcePool pool: [Resource]) {} } protocol Attribute: Field { @@ -380,6 +383,27 @@ public struct ToManyRelationship : Relationship { } } + public func resolve(for resource: Resource, withResourcePool pool: [Resource]) { + guard let linkedResourceCollection = resource.value(forField: self.name) as? LinkedResourceCollection else { + Spine.logInfo(.serializing, "Cannot resolve relationship '\(self.name)' of \(resource.resourceType):\(resource.id!) because the JSON did not include the relationship.") + return + } + + guard let linkage = linkedResourceCollection.linkage else { + Spine.logInfo(.serializing, "Cannot resolve relationship '\(self.name)' of \(resource.resourceType):\(resource.id!) because the JSON did not include linkage.") + return + } + + let targetResources = linkage.flatMap { (link: ResourceIdentifier) in + return pool.filter { $0.resourceType == link.type && $0.id == link.id } as! [Linked] + } + + if !targetResources.isEmpty { + linkedResourceCollection.resources = targetResources + linkedResourceCollection.isLoaded = true + } + } + // public func extractToManyRelationship(_ key: String, from serializedData: JSON) -> LinkedResourceCollection? { // var resourceCollection: LinkedResourceCollection? = nil // From 8495a192996c53193ba5fa9d09aa20cf4f288696 Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Thu, 19 Jan 2017 15:32:48 +0100 Subject: [PATCH 06/14] serialize operation --- Spine/ResourceField.swift | 104 +++++++++++++++++++ Spine/SerializeOperation.swift | 179 +++++++++++++++++---------------- 2 files changed, 197 insertions(+), 86 deletions(-) diff --git a/Spine/ResourceField.swift b/Spine/ResourceField.swift index a08be827..da532b4b 100644 --- a/Spine/ResourceField.swift +++ b/Spine/ResourceField.swift @@ -68,6 +68,12 @@ public protocol Field { var relatedType: Resource.Type? { get } + func serialize(from resource: Resource, + into serializedData: inout [String: Any], + withKeyFormatter keyFormatter: KeyFormatter, + withValueFormatters valueFormatters: ValueFormatterRegistry, + withOptions options: SerializationOptions) + func extract(from serializedData: JSON, intoResource resource: Resource, withKeyFormatter keyFormatter: KeyFormatter, @@ -102,6 +108,33 @@ extension Attribute { return nil } + public func serialize(from resource: Resource, + into serializedData: inout [String: Any], + withKeyFormatter keyFormatter: KeyFormatter, + withValueFormatters valueFormatters: ValueFormatterRegistry, + withOptions options: SerializationOptions) { + let key = keyFormatter.format(self) + + Spine.logDebug(.serializing, "Serializing attribute \(self) as '\(key)'") + + var value: Any? = nil + if let unformattedValue = resource.value(forField: self.name) { + value = valueFormatters.formatValue(unformattedValue, forAttribute: self) + } else if(!options.contains(.OmitNullValues)){ + value = NSNull() + } + + if let value = value { + if serializedData["attributes"] == nil { + serializedData["attributes"] = [key: value] + } else { + var relationships = serializedData["attributes"] as! [String: Any] + relationships[key] = value + serializedData["attributes"] = relationships + } + } + } + public func extract(from serializedData: JSON, intoResource resource: Resource, withKeyFormatter keyFormatter: KeyFormatter, @@ -307,6 +340,43 @@ public struct ToOneRelationship : Relationship { self.serializedName = name } + public func serialize(from resource: Resource, + into serializedData: inout [String: Any], + withKeyFormatter keyFormatter: KeyFormatter, + withValueFormatters valueFormatters: ValueFormatterRegistry, + withOptions options: SerializationOptions) { + let key = keyFormatter.format(self) + + Spine.logDebug(.serializing, "Serializing toOne relationship \(self) as '\(key)'") + + if options.contains(.IncludeToOne) { + let serializedId: Any + let linkedResource = resource.value(forField: self.name) as? Linked + + if let resourceId = linkedResource?.id { + serializedId = resourceId + } else { + serializedId = NSNull() + } + + let serializedRelationship = [ + "data": [ + "type": Linked.resourceType, + "id": serializedId + ] + ] + + if serializedData["relationships"] == nil { + serializedData["relationships"] = [key: serializedRelationship] + } else { + var relationships = serializedData["relationships"] as! [String: Any] + relationships[key] = serializedRelationship + serializedData["relationships"] = relationships + } + } + + } + public func extract(from serializedData: JSON, intoResource resource: Resource, withKeyFormatter keyFormatter: KeyFormatter, @@ -353,6 +423,40 @@ public struct ToManyRelationship : Relationship { self.serializedName = name } + public func serialize(from resource: Resource, + into serializedData: inout [String: Any], + withKeyFormatter keyFormatter: KeyFormatter, + withValueFormatters valueFormatters: ValueFormatterRegistry, + withOptions options: SerializationOptions) { + let key = keyFormatter.format(self) + + Spine.logDebug(.serializing, "Serializing toMany relationship \(self) as '\(key)'") + + if options.contains(.IncludeToMany) { + let linkedResources = resource.value(forField: self.name) as? ResourceCollection + var resourceIdentifiers: [ResourceIdentifier] = [] + + if let resources = linkedResources?.resources { + resourceIdentifiers = resources.filter { $0.id != nil }.map { resource in + return ResourceIdentifier(type: resource.resourceType, id: resource.id!) + } + } + + let serializedRelationship = [ + "data": resourceIdentifiers.map { $0.toDictionary() } + ] + + if serializedData["relationships"] == nil { + serializedData["relationships"] = [key: serializedRelationship] + } else { + var relationships = serializedData["relationships"] as! [String: Any] + relationships[key] = serializedRelationship + serializedData["relationships"] = relationships + } + } + + } + public func extract(from serializedData: JSON, intoResource resource: Resource, withKeyFormatter keyFormatter: KeyFormatter, diff --git a/Spine/SerializeOperation.swift b/Spine/SerializeOperation.swift index 8d73235c..1cd760d2 100644 --- a/Spine/SerializeOperation.swift +++ b/Spine/SerializeOperation.swift @@ -56,15 +56,22 @@ class SerializeOperation: Operation { // Serialize ID if let id = resource.id , options.contains(.IncludeID) { - serializedData["id"] = id as AnyObject? + serializedData["id"] = id //as AnyObject? } // Serialize type - serializedData["type"] = resource.resourceType as AnyObject? + serializedData["type"] = resource.resourceType //as AnyObject? // Serialize fields - addAttributes(from: resource, to: &serializedData ) - addRelationships(from: resource, to: &serializedData) + for field in resource.fields where !field.isReadOnly { + field.serialize(from: resource, + into: &serializedData, + withKeyFormatter: keyFormatter, + withValueFormatters: valueFormatters, + withOptions: options) + } +// addAttributes(from: resource, to: &serializedData ) +// addRelationships(from: resource, to: &serializedData) return serializedData } @@ -76,23 +83,23 @@ class SerializeOperation: Operation { /// /// - parameter resource: The resource whose attributes to add. /// - parameter serializedData: The data to add the attributes to. - fileprivate func addAttributes(from resource: Resource, to serializedData: inout [String: Any]) { - var attributes = [String: Any](); - - for case let field as Attribute in resource.fields where field.isReadOnly == false { - let key = keyFormatter.format(field) - - Spine.logDebug(.serializing, "Serializing attribute \(field) as '\(key)'") - - if let unformattedValue = resource.value(forField: field.name) { - attributes[key] = valueFormatters.formatValue(unformattedValue, forAttribute: field) - } else if(!options.contains(.OmitNullValues)){ - attributes[key] = NSNull() - } - } - - serializedData["attributes"] = attributes - } +// fileprivate func addAttributes(from resource: Resource, to serializedData: inout [String: Any]) { +// var attributes = [String: Any](); +// +// for case let field as Attribute in resource.fields where field.isReadOnly == false { +// let key = keyFormatter.format(field) +// +// Spine.logDebug(.serializing, "Serializing attribute \(field) as '\(key)'") +// +// if let unformattedValue = resource.value(forField: field.name) { +// attributes[key] = valueFormatters.formatValue(unformattedValue, forAttribute: field) +// } else if(!options.contains(.OmitNullValues)){ +// attributes[key] = NSNull() +// } +// } +// +// serializedData["attributes"] = attributes +// } // MARK: Relationships @@ -101,81 +108,81 @@ class SerializeOperation: Operation { /// /// - parameter resource: The resource whose relationships to add. /// - parameter serializedData: The data to add the relationships to. - fileprivate func addRelationships(from resource: Resource, to serializedData: inout [String: Any]) { - for case let field as Relationship in resource.fields where field.isReadOnly == false { - let key = keyFormatter.format(field) - - Spine.logDebug(.serializing, "Serializing relationship \(field) as '\(key)'") - - switch field { - case let toOne as ToOneRelationship: - if options.contains(.IncludeToOne) { - addToOneRelationship(resource.value(forField: field.name) as? Resource, to: &serializedData, key: key, type: toOne.linkedType.resourceType) - } - case let toMany as ToManyRelationship: - if options.contains(.IncludeToMany) { - addToManyRelationship(resource.value(forField: field.name) as? ResourceCollection, to: &serializedData, key: key, type: toMany.linkedType.resourceType) - } - default: () - } - } - } - +// fileprivate func addRelationships(from resource: Resource, to serializedData: inout [String: Any]) { +// for case let field as Relationship in resource.fields where field.isReadOnly == false { +// let key = keyFormatter.format(field) +// +// Spine.logDebug(.serializing, "Serializing relationship \(field) as '\(key)'") +// +// switch field { +// case let toOne as ToOneRelationship: +// if options.contains(.IncludeToOne) { +// addToOneRelationship(resource.value(forField: field.name) as? Resource, to: &serializedData, key: key, type: toOne.linkedType.resourceType) +// } +// case let toMany as ToManyRelationship: +// if options.contains(.IncludeToMany) { +// addToManyRelationship(resource.value(forField: field.name) as? ResourceCollection, to: &serializedData, key: key, type: toMany.linkedType.resourceType) +// } +// default: () +// } +// } +// } + /// Adds the given resource as a to to-one relationship to the serialized data. /// /// - parameter linkedResource: The linked resource to add to the serialized data. /// - parameter serializedData: The data to add the related resource to. /// - parameter key: The key to add to the serialized data. /// - parameter type: The resource type of the linked resource as defined on the parent resource. - fileprivate func addToOneRelationship(_ linkedResource: Resource?, to serializedData: inout [String: Any], key: String, type: ResourceType) { - let serializedId: Any - if let resourceId = linkedResource?.id { - serializedId = resourceId - } else { - serializedId = NSNull() - } - - let serializedRelationship = [ - "data": [ - "type": type, - "id": serializedId - ] - ] - - if serializedData["relationships"] == nil { - serializedData["relationships"] = [key: serializedRelationship] - } else { - var relationships = serializedData["relationships"] as! [String: Any] - relationships[key] = serializedRelationship - serializedData["relationships"] = relationships - } - } - +// fileprivate func addToOneRelationship(_ linkedResource: Resource?, to serializedData: inout [String: Any], key: String, type: ResourceType) { +// let serializedId: Any +// if let resourceId = linkedResource?.id { +// serializedId = resourceId +// } else { +// serializedId = NSNull() +// } +// +// let serializedRelationship = [ +// "data": [ +// "type": type, +// "id": serializedId +// ] +// ] +// +// if serializedData["relationships"] == nil { +// serializedData["relationships"] = [key: serializedRelationship] +// } else { +// var relationships = serializedData["relationships"] as! [String: Any] +// relationships[key] = serializedRelationship +// serializedData["relationships"] = relationships +// } +// } + /// Adds the given resources as a to to-many relationship to the serialized data. /// /// - parameter linkedResources: The linked resources to add to the serialized data. /// - parameter serializedData: The data to add the related resources to. /// - parameter key: The key to add to the serialized data. /// - parameter type: The resource type of the linked resource as defined on the parent resource. - fileprivate func addToManyRelationship(_ linkedResources: ResourceCollection?, to serializedData: inout [String: Any], key: String, type: ResourceType) { - var resourceIdentifiers: [ResourceIdentifier] = [] - - if let resources = linkedResources?.resources { - resourceIdentifiers = resources.filter { $0.id != nil }.map { resource in - return ResourceIdentifier(type: resource.resourceType, id: resource.id!) - } - } - - let serializedRelationship = [ - "data": resourceIdentifiers.map { $0.toDictionary() } - ] - - if serializedData["relationships"] == nil { - serializedData["relationships"] = [key: serializedRelationship] - } else { - var relationships = serializedData["relationships"] as! [String: Any] - relationships[key] = serializedRelationship - serializedData["relationships"] = relationships - } - } +// fileprivate func addToManyRelationship(_ linkedResources: ResourceCollection?, to serializedData: inout [String: Any], key: String, type: ResourceType) { +// var resourceIdentifiers: [ResourceIdentifier] = [] +// +// if let resources = linkedResources?.resources { +// resourceIdentifiers = resources.filter { $0.id != nil }.map { resource in +// return ResourceIdentifier(type: resource.resourceType, id: resource.id!) +// } +// } +// +// let serializedRelationship = [ +// "data": resourceIdentifiers.map { $0.toDictionary() } +// ] +// +// if serializedData["relationships"] == nil { +// serializedData["relationships"] = [key: serializedRelationship] +// } else { +// var relationships = serializedData["relationships"] as! [String: Any] +// relationships[key] = serializedRelationship +// serializedData["relationships"] = relationships +// } +// } } From e632fce2cb809b85c28a5f532e54a063a72d3c68 Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Thu, 19 Jan 2017 15:45:01 +0100 Subject: [PATCH 07/14] jsonapidocument --- Spine/DeserializeOperation.swift | 7 ++++++- Spine/Serializing.swift | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Spine/DeserializeOperation.swift b/Spine/DeserializeOperation.swift index f73b231c..1cf5965a 100644 --- a/Spine/DeserializeOperation.swift +++ b/Spine/DeserializeOperation.swift @@ -137,8 +137,13 @@ class DeserializeOperation: Operation { resolveRelationships() // Create a result - var responseDocument = JSONAPIDocument(data: nil, included: nil, errors: extractedErrors, meta: extractedMeta, links: extractedLinks as [String : URL]?, jsonapi: extractedJSONAPI) +// var responseDocument = JSONAPIDocument(data: nil, included: nil, errors: extractedErrors, meta: extractedMeta, links: extractedLinks as [String : URL]?, jsonapi: extractedJSONAPI) + var responseDocument = JSONAPIDocument() responseDocument.data = extractedPrimaryResources + responseDocument.errors = extractedErrors + responseDocument.meta = extractedMeta + responseDocument.links = extractedLinks + responseDocument.jsonapi = extractedJSONAPI if !extractedIncludedResources.isEmpty { responseDocument.included = extractedIncludedResources } diff --git a/Spine/Serializing.swift b/Spine/Serializing.swift index a883d341..9457e2cd 100644 --- a/Spine/Serializing.swift +++ b/Spine/Serializing.swift @@ -77,7 +77,9 @@ public class Serializer { /// /// - returns: Serialized data. public func serializeResources(_ resources: [T], options: SerializationOptions = [.IncludeID]) throws -> Data { - let document = JSONAPIDocument(data: resources, included: nil, errors: nil, meta: nil, links: nil, jsonapi: nil) + var document = JSONAPIDocument() + document.data = resources +// let document = JSONAPIDocument(data: resources, included: nil, errors: nil, meta: nil, links: nil, jsonapi: nil) return try serializeDocument(document, options: options) } From 4dba5ccdc3780813e328e99c7e914e90083920c6 Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Thu, 19 Jan 2017 17:25:05 +0100 Subject: [PATCH 08/14] oh no more errors --- Spine/DeserializeOperation.swift | 2 +- Spine/Operation.swift | 105 ++++++++++++++++--------------- Spine/Resource.swift | 18 +++--- Spine/ResourceFactory.swift | 25 ++++++++ Spine/ResourceField.swift | 63 +++++++++++++++++-- Spine/Serializing.swift | 68 ++++++++++---------- 6 files changed, 183 insertions(+), 98 deletions(-) diff --git a/Spine/DeserializeOperation.swift b/Spine/DeserializeOperation.swift index 1cf5965a..5a2192bb 100644 --- a/Spine/DeserializeOperation.swift +++ b/Spine/DeserializeOperation.swift @@ -175,7 +175,7 @@ class DeserializeOperation: Operation { } // Dispense a resource - let resource = try resourceFactory.dispense(type, id: id, pool: &resourcePool, index: mappingTargetIndex) + let resource = try resourceFactory.dispenseRaw(type, id: id, pool: &resourcePool, index: mappingTargetIndex) // Extract data resource.id = id diff --git a/Spine/Operation.swift b/Spine/Operation.swift index 80596076..03c0f3dc 100644 --- a/Spine/Operation.swift +++ b/Spine/Operation.swift @@ -49,7 +49,7 @@ Operating against a Spine ========================= The `Spine` instance variable references the Spine against which to operate. */ -class ConcurrentOperation: Operation { +public class ConcurrentOperation: Operation { enum State: String { case ready = "isReady" case executing = "isExecuting" @@ -67,16 +67,16 @@ class ConcurrentOperation: Operation { didChangeValue(forKey: state.rawValue) } } - override var isReady: Bool { + override public var isReady: Bool { return super.isReady && state == .ready } - override var isExecuting: Bool { + override public var isExecuting: Bool { return state == .executing } - override var isFinished: Bool { + override public var isFinished: Bool { return state == .finished } - override var isAsynchronous: Bool { + override public var isAsynchronous: Bool { return true } @@ -96,7 +96,7 @@ class ConcurrentOperation: Operation { override init() {} - final override func start() { + final override public func start() { if isCancelled { state = .finished } else { @@ -105,7 +105,7 @@ class ConcurrentOperation: Operation { } } - final override func main() { + final override public func main() { execute() } @@ -307,7 +307,7 @@ class SaveOperation: ConcurrentOperation { } /// Serializes `resource` into NSData using `options`. Any error that occurs is rethrown as a SpineError. - fileprivate func serializePayload(_ resource: Resource, options: SerializationOptions) throws -> Data { + fileprivate func serializePayload(_ resource: T, options: SerializationOptions) throws -> Data { do { let payload = try serializer.serializeResources([resource], options: options) return payload @@ -317,11 +317,11 @@ class SaveOperation: ConcurrentOperation { } fileprivate func updateRelationships() { - let relationships = resource.fields.filter { field in - return field is Relationship && !field.isReadOnly - } - - guard !relationships.isEmpty else { +// let relationships = resource.fields.filter { field in +// return field is Relationship && !field.isReadOnly +// } + + guard !resource.fields.isEmpty else { updateResource() return } @@ -334,23 +334,27 @@ class SaveOperation: ConcurrentOperation { } } - for relationship in relationships { - switch relationship { - case let toOne as ToOneRelationship: - let operation = RelationshipReplaceOperation(resource: resource, relationship: toOne, spine: spine) - operation.completionBlock = { [unowned operation] in completionHandler(operation.result) } - relationshipOperationQueue.addOperation(operation) - - case let toMany as ToManyRelationship: - let addOperation = RelationshipMutateOperation(resource: resource, relationship: toMany, mutation: .add, spine: spine) - addOperation.completionBlock = { [unowned addOperation] in completionHandler(addOperation.result) } - relationshipOperationQueue.addOperation(addOperation) - - let removeOperation = RelationshipMutateOperation(resource: resource, relationship: toMany, mutation: .remove, spine: spine) - removeOperation.completionBlock = { [unowned removeOperation] in completionHandler(removeOperation.result) } - relationshipOperationQueue.addOperation(removeOperation) - default: () - } + for field in resource.fields { + for operation in field.updateOperations(for: resource, wihtSpine: spine) { + operation.completionBlock = { [unowned operation] in completionHandler(operation.result) } + relationshipOperationQueue.addOperation(operation) + } +// switch relationship { +// case let toOne as ToOneRelationship: +// let operation = RelationshipReplaceOperation(resource: resource, relationship: toOne, spine: spine) +// operation.completionBlock = { [unowned operation] in completionHandler(operation.result) } +// relationshipOperationQueue.addOperation(operation) +// +// case let toMany as ToManyRelationship: +// let addOperation = RelationshipMutateOperation(resource: resource, relationship: toMany, mutation: .add, spine: spine) +// addOperation.completionBlock = { [unowned addOperation] in completionHandler(addOperation.result) } +// relationshipOperationQueue.addOperation(addOperation) +// +// let removeOperation = RelationshipMutateOperation(resource: resource, relationship: toMany, mutation: .remove, spine: spine) +// removeOperation.completionBlock = { [unowned removeOperation] in completionHandler(removeOperation.result) } +// relationshipOperationQueue.addOperation(removeOperation) +// default: () +// } } } @@ -367,7 +371,7 @@ class SaveOperation: ConcurrentOperation { } } -private class RelationshipOperation: ConcurrentOperation { +public class RelationshipOperation: ConcurrentOperation { var result: Failable? func handleNetworkResponse(_ statusCode: Int?, responseData: Data?, networkError: NSError?) { @@ -394,11 +398,11 @@ private class RelationshipOperation: ConcurrentOperation { } /// A RelationshipReplaceOperation replaces the entire contents of a relationship. -private class RelationshipReplaceOperation: RelationshipOperation { +class RelationshipReplaceOperation: RelationshipOperation { let resource: T - let relationship: Relationship + let relationship: U - init(resource: T, relationship: Relationship, spine: Spine) { + init(resource: T, relationship: U, spine: Spine) { self.resource = resource self.relationship = relationship super.init() @@ -407,36 +411,36 @@ private class RelationshipReplaceOperation: Relationsh override func execute() { let url = router.urlForRelationship(relationship, ofResource: resource) - let payload: Data + let payload: Data = try! relationship.serializeLinkData(for: resource) - switch relationship { - case is ToOneRelationship: - payload = try! serializer.serializeLinkData(resource.value(forField: relationship.name) as? T) - case is ToManyRelationship: - let relatedResources = (resource.value(forField: relationship.name) as? ResourceCollection)?.resources ?? [] - payload = try! serializer.serializeLinkData(relatedResources) - default: - assertionFailure("Cannot only replace relationship contents for ToOneRelationship and ToManyRelationship") - return - } +// switch relationship { +// case is ToOneRelationship: +// payload = try! serializer.serializeLinkData(resource.value(forField: relationship.name) as? T) +// case is ToManyRelationship: +// let relatedResources = (resource.value(forField: relationship.name) as? ResourceCollection)?.resources ?? [] +// payload = try! serializer.serializeLinkData(relatedResources) +// default: +// assertionFailure("Cannot only replace relationship contents for ToOneRelationship and ToManyRelationship") +// return +// } Spine.logInfo(.spine, "Replacing relationship \(relationship) using URL: \(url)") networkClient.request(method: "PATCH", url: url, payload: payload, callback: handleNetworkResponse) } } -private enum Mutation { +enum Mutation { case add, remove } /// A RelationshipMutateOperation mutates a to-many relationship by adding or removing linked resources. -private class RelationshipMutateOperation: RelationshipOperation { +class RelationshipMutateOperation: RelationshipOperation { let resource: T - let relationship: ToManyRelationship + let relationship: U let mutation: Mutation - init(resource: T, relationship: ToManyRelationship, mutation: Mutation, spine: Spine) { + init(resource: T, relationship: U, mutation: Mutation, spine: Spine) { self.resource = resource self.relationship = relationship self.mutation = mutation @@ -465,7 +469,8 @@ private class RelationshipMutateOperation: RelationshipOperation { } let url = router.urlForRelationship(relationship, ofResource: resource) - let payload = try! serializer.serializeLinkData(relatedResources) +// let payload = try! serializer.serializeLinkData(relatedResources) + let payload = try! relationship.serializeLinkData(for: resource) Spine.logInfo(.spine, "Mutating relationship \(relationship) using URL: \(url)") networkClient.request(method: httpMethod, url: url, payload: payload, callback: handleNetworkResponse) } diff --git a/Spine/Resource.swift b/Spine/Resource.swift index 7a4ef602..b6e32b93 100644 --- a/Spine/Resource.swift +++ b/Spine/Resource.swift @@ -104,8 +104,8 @@ public protocol Resource: class, NSObjectProtocol { // NSCoding, /// Raw relationship data keyed by relationship name. var relationships: [String: RelationshipData] { get set } - var description: String { get } - var debugDescription: String { get } +// var description: String { get } +// var debugDescription: String { get } /// Returns the value for the field named `field`. @@ -218,13 +218,13 @@ extension Resource where Self: NSObject { } extension Resource { - var description: String { - return "\(Self.resourceType)(\(id), \(url))" - } - - var debugDescription: String { - return description - } +// var description: String { +// return "\(Self.resourceType)(\(id), \(url))" +// } +// +// var debugDescription: String { +// return description +// } } // Instance counterparts of class functions diff --git a/Spine/ResourceFactory.swift b/Spine/ResourceFactory.swift index e891e09b..9e92cb56 100644 --- a/Spine/ResourceFactory.swift +++ b/Spine/ResourceFactory.swift @@ -72,6 +72,31 @@ public struct ResourceFactory { // return resource // } + func dispenseRaw(_ type: ResourceType, id: String, pool: inout [Resource], index: Int? = nil) throws -> Resource { +// guard let resourceType = resourceTypes[type] else { +// throw SerializerError.resourceTypeUnregistered(type) +// } + + if let resource = (pool.filter { $0.resourceType == type && $0.id == id }.first) { + return resource + } + + if !pool.isEmpty { + let applicableResources = (pool.filter { $0.resourceType == type }) + if !applicableResources.isEmpty, let index = index { + if index < applicableResources.count { + return applicableResources[index] + } + } + + } + + let resource = try self.instantiate(type) + resource.id = id + pool.append(resource) + return resource + } + func dispense(_ type: T.Type, id: String, pool: inout [Resource], index: Int? = nil) -> T { if let resource = (pool.filter { $0.resourceType == T.resourceType && $0.id == id }.first) as? T { diff --git a/Spine/ResourceField.swift b/Spine/ResourceField.swift index da532b4b..cb0f75a1 100644 --- a/Spine/ResourceField.swift +++ b/Spine/ResourceField.swift @@ -81,6 +81,7 @@ public protocol Field { fromResourcePool pool: inout [Resource], withFactory factory: ResourceFactory) func resolve(for resource: Resource, withResourcePool pool: [Resource]) + func updateOperations(for resource: T, wihtSpine spine: Spine) -> [RelationshipOperation] } extension Field { @@ -151,6 +152,10 @@ extension Attribute { resource.setValue(formattedValue, forField: self.name) } } + + public func updateOperations(for resource: T, wihtSpine spine: Spine) -> [RelationshipOperation] { + return [] + } } @@ -281,15 +286,14 @@ public struct DateAttribute : Attribute { // public init(_ type: T.Type) { } //} - - - - public protocol Relationship : Field { + associatedtype Linked: Resource // XXX: create protocol that combines Resource and LinkedResourceCollection // associatedtype ReturnValue + func serializeLinkData(for resource: Resource) throws -> Data + } extension Relationship { @@ -315,6 +319,8 @@ extension Relationship { return RelationshipData(selfURL: selfURL, relatedURL: relatedURL, data: data) } + + } //public protocol ToOneRelationshipProtocol: Relationship { @@ -409,6 +415,28 @@ public struct ToOneRelationship : Relationship { } } + public func serializeLinkData(for resource: Resource) throws -> Data { + let relatedResource = resource.value(forField: self.name) as? Linked + let payloadData: Any + + if let related = relatedResource { + assert(related.id != nil, "Attempt to convert resource without id to linkage. Only resources with ids can be converted to linkage.") + payloadData = ["type": related.resourceType, "id": related.id!] + } else { + payloadData = NSNull() + } + + do { + return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) + } catch let error as NSError { + throw SerializerError.jsonSerializationError(error) + } + } + + public func updateOperations(for resource: T, wihtSpine spine: Spine) -> [RelationshipOperation] { + let operation = RelationshipReplaceOperation(resource: resource, relationship: self, spine: spine) + return [operation] + } } public struct ToManyRelationship : Relationship { @@ -508,6 +536,31 @@ public struct ToManyRelationship : Relationship { } } + public func serializeLinkData(for resource: Resource) throws -> Data { + let relatedResources = (resource.value(forField: self.name) as? ResourceCollection)?.resources ?? [] + let payloadData: Any + + if relatedResources.isEmpty { + payloadData = [] + } else { + payloadData = relatedResources.map { r in + return ["type": r.resourceType, "id": r.id!] + } + } + + do { + return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) + } catch let error as NSError { + throw SerializerError.jsonSerializationError(error) + } + } + + public func updateOperations(for resource: T, wihtSpine spine: Spine) -> [RelationshipOperation] { + let addOperation = RelationshipMutateOperation(resource: resource, relationship: self, mutation: .add, spine: spine) + let removeOperation = RelationshipMutateOperation(resource: resource, relationship: self, mutation: .remove, spine: spine) + return [addOperation, removeOperation] + } + // public func extractToManyRelationship(_ key: String, from serializedData: JSON) -> LinkedResourceCollection? { // var resourceCollection: LinkedResourceCollection? = nil // @@ -587,3 +640,5 @@ public struct ToManyRelationship : Relationship { // return resourceCollection // } //} + + diff --git a/Spine/Serializing.swift b/Spine/Serializing.swift index 9457e2cd..0c9e8921 100644 --- a/Spine/Serializing.swift +++ b/Spine/Serializing.swift @@ -29,7 +29,7 @@ public class Serializer { /// - throws: SerializerError that can occur in the deserialization. /// /// - returns: A JSONAPIDocument - public func deserializeData(_ data: Data, mappingTargets: [Resource]? = nil) throws -> JSONAPIDocument { + public func deserializeData(_ data: Data, mappingTargets: [Resource]? = nil) throws -> JSONAPIDocument { let deserializeOperation = DeserializeOperation(data: data, resourceFactory: resourceFactory, valueFormatters: valueFormatters, keyFormatter: keyFormatter) if let mappingTargets = mappingTargets { @@ -95,22 +95,22 @@ public class Serializer { /// - throws: SerializerError that can occur in the serialization. /// /// - returns: Serialized data. - public func serializeLinkData(_ resource: Resource?) throws -> Data { - let payloadData: Any - - if let resource = resource { - assert(resource.id != nil, "Attempt to convert resource without id to linkage. Only resources with ids can be converted to linkage.") - payloadData = ["type": resource.resourceType, "id": resource.id!] - } else { - payloadData = NSNull() - } - - do { - return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) - } catch let error as NSError { - throw SerializerError.jsonSerializationError(error) - } - } +// public func serializeLinkData(_ resource: Resource?) throws -> Data { +// let payloadData: Any +// +// if let resource = resource { +// assert(resource.id != nil, "Attempt to convert resource without id to linkage. Only resources with ids can be converted to linkage.") +// payloadData = ["type": resource.resourceType, "id": resource.id!] +// } else { +// payloadData = NSNull() +// } +// +// do { +// return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) +// } catch let error as NSError { +// throw SerializerError.jsonSerializationError(error) +// } +// } /// Converts the given resources to link data, and serializes it into NSData. /// ```json @@ -127,23 +127,23 @@ public class Serializer { /// - throws: SerializerError that can occur in the serialization. /// /// - returns: Serialized data. - public func serializeLinkData(_ resources: [Resource]) throws -> Data { - let payloadData: Any - - if resources.isEmpty { - payloadData = [] - } else { - payloadData = resources.map { resource in - return ["type": resource.resourceType, "id": resource.id!] - } - } - - do { - return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) - } catch let error as NSError { - throw SerializerError.jsonSerializationError(error) - } - } +// public func serializeLinkData(_ resources: [Resource]) throws -> Data { +// let payloadData: Any +// +// if resources.isEmpty { +// payloadData = [] +// } else { +// payloadData = resources.map { resource in +// return ["type": resource.resourceType, "id": resource.id!] +// } +// } +// +// do { +// return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) +// } catch let error as NSError { +// throw SerializerError.jsonSerializationError(error) +// } +// } /// Registers a resource class. /// From f5de3ec2d1fea8f61fd205616d5d2df2dcca17f1 Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Tue, 24 Jan 2017 18:22:53 +0100 Subject: [PATCH 09/14] first step to working tests --- Spine/Query.swift | 2 +- Spine/Resource.swift | 31 +++++++++++++++--------- SpineTests/Fixtures.swift | 23 +++++++++++++++++- SpineTests/ResourceCollectionTests.swift | 20 +++++++-------- 4 files changed, 53 insertions(+), 23 deletions(-) diff --git a/Spine/Query.swift b/Spine/Query.swift index c9fa34d2..db1e1b4d 100644 --- a/Spine/Query.swift +++ b/Spine/Query.swift @@ -225,7 +225,7 @@ public struct Query { /// /// - parameter type: The resource type for which to restrict the properties. /// - parameter fieldNames: Names of fields to fetch. - public mutating func restrictFieldsOfResourceType(_ type: T.Type, to fieldNames: String...) { + public mutating func restrictFieldsOfResourceType(_ type: U.Type, to fieldNames: String...) { for fieldName in fieldNames { guard let field = type.field(named: fieldName) else { assertionFailure("Cannot restrict to field \(fieldName) of resource \(type.resourceType). No such field has been configured.") diff --git a/Spine/Resource.swift b/Spine/Resource.swift index b6e32b93..ef76d308 100644 --- a/Spine/Resource.swift +++ b/Spine/Resource.swift @@ -126,19 +126,26 @@ public protocol Resource: class, NSObjectProtocol { // NSCoding, init() } -extension Resource where Self: NSObject { +extension Resource { // static var fields: [Field] { // return [] // } var isLoaded: Bool { + // XXX ahh return false } var relationships: [String: RelationshipData] { + // XXX ahh return [:] } + var meta: [String: Any]? { + // XXX ahh + return nil + } + // public init() { // // XXX: check this for recursion // self.init() @@ -173,16 +180,6 @@ extension Resource where Self: NSObject { // coder.encode(relationshipsData, forKey: "relationships") // } - /// Returns the value for the field named `field`. - func value(forField field: String) -> Any? { - return value(forKey: field) as AnyObject? - } - - /// Sets the value for the field named `field` to `value`. - func setValue(_ value: Any?, forField field: String) { - setValue(value, forKey: field) - } - /// Set the values for all fields to nil and sets `isLoaded` to false. public func unload() { for field in Self.fields { @@ -217,6 +214,18 @@ extension Resource where Self: NSObject { } } +extension Resource where Self: NSObject { + /// Returns the value for the field named `field`. + func value(forField field: String) -> Any? { + return value(forKey: field) as AnyObject? + } + + /// Sets the value for the field named `field` to `value`. + func setValue(_ value: Any?, forField field: String) { + setValue(value, forKey: field) + } +} + extension Resource { // var description: String { // return "\(Self.resourceType)(\(id), \(url))" diff --git a/SpineTests/Fixtures.swift b/SpineTests/Fixtures.swift index 35f2b8ca..84c5da76 100644 --- a/SpineTests/Fixtures.swift +++ b/SpineTests/Fixtures.swift @@ -11,9 +11,19 @@ import XCTest import SwiftyJSON class Foo: NSObject, Resource { + /// Raw relationship data keyed by relationship name. + public var relationships: [String : RelationshipData] + + /// The metadata for this resource. + public var meta: [String : Any]? + + public override required init() { + + } + var id: String? var url: URL? -// var isLoaded: Bool + var isLoaded: Bool var stringAttribute: String? var integerAttribute: NSNumber? @@ -52,8 +62,19 @@ class Foo: NSObject, Resource { } class Bar: NSObject, Resource { + /// Raw relationship data keyed by relationship name. + public var relationships: [String : RelationshipData] + + /// The metadata for this resource. + public var meta: [String : Any]? + + public override required init() { + + } + var id: String? var url: URL? + var isLoaded: Bool var barStringAttribute: String? var barIntegerAttribute: NSNumber? diff --git a/SpineTests/ResourceCollectionTests.swift b/SpineTests/ResourceCollectionTests.swift index cacb293a..e3e0c3f2 100644 --- a/SpineTests/ResourceCollectionTests.swift +++ b/SpineTests/ResourceCollectionTests.swift @@ -12,7 +12,7 @@ class ResourceCollectionTests: XCTestCase { func testInitWithResourcesURLAndResources() { let url = URL(string: "http://example.com/foos")! - let resources = [Foo(), Bar()] + let resources = [Foo(), Foo()] // 2nd was Bar let collection = ResourceCollection(resources: resources, resourcesURL: url) XCTAssertNotNil(collection.resourcesURL, "Expected URL to be not nil.") @@ -22,7 +22,7 @@ class ResourceCollectionTests: XCTestCase { } func testIndexSubscript() { - let resources = [Foo(), Bar()] + let resources = [Foo(), Foo()] // 2nd was Bar let collection = ResourceCollection(resources: resources) XCTAssert(collection[0] === resources[0], "Expected resource to be equal.") @@ -30,7 +30,7 @@ class ResourceCollectionTests: XCTestCase { } func testTypeAndIDSubscript() { - let resources = [Foo(id: "5"), Bar(id: "6")] + let resources = [Foo(id: "5"), Foo(id: "6")] // 2nd was Bar let collection = ResourceCollection(resources: resources) XCTAssert(collection.resourceWithType("foos", id: "5")! === resources[0], "Expected resource to be equal.") @@ -38,7 +38,7 @@ class ResourceCollectionTests: XCTestCase { } func testCount() { - let resources = [Foo(), Bar()] + let resources = [Foo(), Foo()] // 2nd was Bar let collection = ResourceCollection(resources: resources) XCTAssertEqual(collection.count, 2, "Expected count to be 2.") @@ -46,7 +46,7 @@ class ResourceCollectionTests: XCTestCase { func testAppendResource() { let foo = Foo(id: "1") - let collection = ResourceCollection(resources: []) + let collection = ResourceCollection(resources: []) collection.appendResource(foo) XCTAssertEqual(collection.resources, [foo], "Expected resources to be equal.") @@ -90,7 +90,7 @@ class LinkedResourceCollectionTests: XCTestCase { } func testAppendResource() { - let collection = LinkedResourceCollection(resourcesURL: nil, linkURL: nil, linkage: nil) + let collection = LinkedResourceCollection(resourcesURL: nil, linkURL: nil, linkage: nil) let foo = Foo(id: "1") collection.appendResource(foo) @@ -101,7 +101,7 @@ class LinkedResourceCollectionTests: XCTestCase { } func testLinkResource() { - let collection = LinkedResourceCollection(resourcesURL: nil, linkURL: nil, linkage: nil) + let collection = LinkedResourceCollection(resourcesURL: nil, linkURL: nil, linkage: nil) let foo = Foo(id: "1") collection.linkResource(foo) @@ -111,7 +111,7 @@ class LinkedResourceCollectionTests: XCTestCase { } func testLinkUnlinked() { - let collection = LinkedResourceCollection(resourcesURL: nil, linkURL: nil, linkage: nil) + let collection = LinkedResourceCollection(resourcesURL: nil, linkURL: nil, linkage: nil) let foo = Foo(id: "1") collection.appendResource(foo) @@ -124,7 +124,7 @@ class LinkedResourceCollectionTests: XCTestCase { } func testUnlink() { - let collection = LinkedResourceCollection(resourcesURL: nil, linkURL: nil, linkage: nil) + let collection = LinkedResourceCollection(resourcesURL: nil, linkURL: nil, linkage: nil) let foo = Foo(id: "1") collection.appendResource(foo) @@ -135,7 +135,7 @@ class LinkedResourceCollectionTests: XCTestCase { } func testUnlinkLinked() { - let collection = LinkedResourceCollection(resourcesURL: nil, linkURL: nil, linkage: nil) + let collection = LinkedResourceCollection(resourcesURL: nil, linkURL: nil, linkage: nil) let foo = Foo(id: "1") collection.linkResource(foo) From e58bca9a7cf6ab1f30fb87f862acefd39dd95b48 Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Wed, 25 Jan 2017 11:45:20 +0100 Subject: [PATCH 10/14] make ResourceIdentifier and RelationshipData generic. --- Spine/Resource.swift | 35 +++++++++++++++--------- Spine/ResourceCollection.swift | 4 +-- Spine/ResourceField.swift | 19 +++++++------ SpineTests/ResourceCollectionTests.swift | 9 +++--- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/Spine/Resource.swift b/Spine/Resource.swift index ef76d308..be8a4bfa 100644 --- a/Spine/Resource.swift +++ b/Spine/Resource.swift @@ -11,16 +11,16 @@ import Foundation public typealias ResourceType = String /// A ResourceIdentifier uniquely identifies a resource that exists on the server. -public struct ResourceIdentifier: Equatable { +public struct ResourceIdentifier : Equatable { /// The resource type. var type: ResourceType /// The resource ID. - var id: String + public var id: String /// Constructs a new ResourceIdentifier instance with given `type` and `id`. - init(type: ResourceType, id: String) { - self.type = type + init(type: T.Type, id: String) { + self.type = type.resourceType self.id = id } @@ -32,22 +32,27 @@ public struct ResourceIdentifier: Equatable { } /// Returns a dictionary with "type" and "id" keys containing the type and id. - func toDictionary() -> NSDictionary { + public func toDictionary() -> NSDictionary { return ["type": type, "id": id] } } -public func ==(lhs: ResourceIdentifier, rhs: ResourceIdentifier) -> Bool { - return lhs.type == rhs.type && lhs.id == rhs.id +public func ==(lhs: ResourceIdentifier, rhs: ResourceIdentifier) -> Bool { + return lhs.id == rhs.id +} + +public protocol RelationshipData { + var selfURL: URL? { get } } + /// A RelationshipData struct holds data about a relationship. -public struct RelationshipData { - var selfURL: URL? +public struct TypedRelationshipData : RelationshipData { + public var selfURL: URL? var relatedURL: URL? - var data: [ResourceIdentifier]? + var data: [ResourceIdentifier]? - init(selfURL: URL?, relatedURL: URL?, data: [ResourceIdentifier]?) { + init(selfURL: URL?, relatedURL: URL?, data: [ResourceIdentifier]?) { self.selfURL = selfURL self.relatedURL = relatedURL self.data = data @@ -58,8 +63,11 @@ public struct RelationshipData { init(dictionary: NSDictionary) { selfURL = dictionary["selfURL"] as? URL relatedURL = dictionary["relatedURL"] as? URL - data = (dictionary["data"] as? [NSDictionary])?.map(ResourceIdentifier.init) - } + data = (dictionary["data"] as? [[String: String]])?.map { d in + return ResourceIdentifier(type: T.self, id: d["id"]!) // XXX force unwrap + } + +} /// Returns a dictionary with "type" and "id" keys containing the type and id. func toDictionary() -> NSDictionary { @@ -104,6 +112,7 @@ public protocol Resource: class, NSObjectProtocol { // NSCoding, /// Raw relationship data keyed by relationship name. var relationships: [String: RelationshipData] { get set } + // XXX: don't remove // var description: String { get } // var debugDescription: String { get } diff --git a/Spine/ResourceCollection.swift b/Spine/ResourceCollection.swift index 80cd1162..ac700008 100644 --- a/Spine/ResourceCollection.swift +++ b/Spine/ResourceCollection.swift @@ -125,7 +125,7 @@ extension ResourceCollection: Sequence { /// This allows Spine to make partial updates to the collection when it the parent resource is persisted. public class LinkedResourceCollection: ResourceCollection { /// The type/id pairs of resources present in this link. - public var linkage: [ResourceIdentifier]? + public var linkage: [ResourceIdentifier]? /// The URL of the link object of this collection. public var linkURL: URL? @@ -136,7 +136,7 @@ public class LinkedResourceCollection: ResourceCollection { /// Resources removed from this linked collection, but not yet persisted. public internal(set) var removedResources: [T] = [] - public init(resourcesURL: URL?, linkURL: URL?, linkage: [ResourceIdentifier]?) { + public init(resourcesURL: URL?, linkURL: URL?, linkage: [ResourceIdentifier]?) { super.init(resources: [], resourcesURL: resourcesURL) self.linkURL = linkURL self.linkage = linkage diff --git a/Spine/ResourceField.swift b/Spine/ResourceField.swift index cb0f75a1..97c255fc 100644 --- a/Spine/ResourceField.swift +++ b/Spine/ResourceField.swift @@ -305,19 +305,21 @@ extension Relationship { func extractRelationshipData(_ linkData: JSON) -> RelationshipData { let selfURL = linkData["links"]["self"].URL let relatedURL = linkData["links"]["related"].URL - let data: [ResourceIdentifier]? + let data: [ResourceIdentifier]? if let toOne = linkData["data"].dictionary { - data = [ResourceIdentifier(type: toOne["type"]!.stringValue, id: toOne["id"]!.stringValue)] + // XXX: assert ["type"]!.stringValue == Linked.resourceType + data = [ResourceIdentifier(type: Linked.self, id: toOne["id"]!.stringValue)] } else if let toMany = linkData["data"].array { - data = toMany.map { JSON -> ResourceIdentifier in - return ResourceIdentifier(type: JSON["type"].stringValue, id: JSON["id"].stringValue) + data = toMany.map { JSON -> ResourceIdentifier in + // XXX: assert ["type"]!.stringValue == Linked.resourceType + return ResourceIdentifier(type: Linked.self, id: JSON["id"].stringValue) } } else { data = nil } - return RelationshipData(selfURL: selfURL, relatedURL: relatedURL, data: data) + return TypedRelationshipData(selfURL: selfURL, relatedURL: relatedURL, data: data) } @@ -462,11 +464,11 @@ public struct ToManyRelationship : Relationship { if options.contains(.IncludeToMany) { let linkedResources = resource.value(forField: self.name) as? ResourceCollection - var resourceIdentifiers: [ResourceIdentifier] = [] + var resourceIdentifiers: [ResourceIdentifier] = [] if let resources = linkedResources?.resources { resourceIdentifiers = resources.filter { $0.id != nil }.map { resource in - return ResourceIdentifier(type: resource.resourceType, id: resource.id!) + return ResourceIdentifier(type: T.self, id: resource.id!) } } @@ -501,7 +503,8 @@ public struct ToManyRelationship : Relationship { let linkURL: URL? = linkData["links"]?["self"].URL if let linkage = linkData["data"]?.array { - let mappedLinkage = linkage.map { ResourceIdentifier(type: $0["type"].stringValue, id: $0["id"].stringValue) } + // XXX: assert $0["type"].stringValue == T.resourceType + let mappedLinkage = linkage.map { ResourceIdentifier(type: T.self, id: $0["id"].stringValue) } resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: mappedLinkage) } else { resourceCollection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: nil) diff --git a/SpineTests/ResourceCollectionTests.swift b/SpineTests/ResourceCollectionTests.swift index e3e0c3f2..ceceaedb 100644 --- a/SpineTests/ResourceCollectionTests.swift +++ b/SpineTests/ResourceCollectionTests.swift @@ -59,7 +59,7 @@ class LinkedResourceCollectionTests: XCTestCase { func testInitWithResourcesURLAndURLAndLinkage() { let resourcesURL = URL(string: "http://example.com/foos")! let linkURL = URL(string: "http://example.com/bars/1/link/foos")! - let linkage = [ResourceIdentifier(type: "foos", id: "1"), ResourceIdentifier(type: "bars", id: "2")] + let linkage = [ResourceIdentifier(type: Foo.self, id: "1"), ResourceIdentifier(type: Foo.self, id: "2")] // 2nd was ResourceIdentifier(type: "bars", id: "2") let collection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: linkage) XCTAssertNotNil(collection.resourcesURL, "Expected resources URL to be not nil.") @@ -76,7 +76,8 @@ class LinkedResourceCollectionTests: XCTestCase { func testInitWithResourcesURLAndURLAndHomogenousTypeAndLinkage() { let resourcesURL = URL(string: "http://example.com/foos")! let linkURL = URL(string: "http://example.com/bars/1/link/foos")! - let collection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: ["1", "2"].map { ResourceIdentifier(type: "foos", id: $0) }) + let linkage = ["1", "2"].map { ResourceIdentifier(type: Foo.self, id: $0) } + let collection = LinkedResourceCollection(resourcesURL: resourcesURL, linkURL: linkURL, linkage: linkage) XCTAssertNotNil(collection.resourcesURL, "Expected resources URL to be not nil.") XCTAssertEqual(collection.resourcesURL!, resourcesURL, "Expected resources URL to be equal.") @@ -85,8 +86,8 @@ class LinkedResourceCollectionTests: XCTestCase { XCTAssertEqual(collection.linkURL!, linkURL, "Expected link URL to be equal.") XCTAssert(collection.linkage != nil, "Expected linkage to be not nil.") - XCTAssertEqual(collection.linkage![0], ResourceIdentifier(type: "foos", id: "1"), "Expected first linkage item to be equal.") - XCTAssertEqual(collection.linkage![1], ResourceIdentifier(type: "foos", id: "2"), "Expected second linkage item to be equal.") + XCTAssertEqual(collection.linkage![0], ResourceIdentifier(type: Foo.self, id: "1"), "Expected first linkage item to be equal.") + XCTAssertEqual(collection.linkage![1], ResourceIdentifier(type: Foo.self, id: "2"), "Expected second linkage item to be equal.") } func testAppendResource() { From d037c513c43960c8cb9572b46ab0860514963fc7 Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Thu, 26 Jan 2017 21:01:21 +0100 Subject: [PATCH 11/14] Create workspace. - use carthage update --no-build --- Cartfile.resolved | 2 +- Spine.xcodeproj/project.pbxproj | 1 + Spine.xcworkspace/contents.xcworkspacedata | 13 +++++++++++++ Spine/DeserializeOperation.swift | 2 +- Spine/ResourceField.swift | 10 +++++----- 5 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 Spine.xcworkspace/contents.xcworkspacedata diff --git a/Cartfile.resolved b/Cartfile.resolved index 62613afa..890d1dbd 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,3 +1,3 @@ github "antitypical/Result" "3.1.0" -github "SwiftyJSON/SwiftyJSON" "3.1.3" +github "SwiftyJSON/SwiftyJSON" "3.1.4" github "Thomvis/BrightFutures" "v5.1.0" diff --git a/Spine.xcodeproj/project.pbxproj b/Spine.xcodeproj/project.pbxproj index 1ac87975..4f1724f8 100644 --- a/Spine.xcodeproj/project.pbxproj +++ b/Spine.xcodeproj/project.pbxproj @@ -1549,6 +1549,7 @@ D398E14E1DA1554300FBC6FD /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Spine.xcworkspace/contents.xcworkspacedata b/Spine.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..1a8a6663 --- /dev/null +++ b/Spine.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/Spine/DeserializeOperation.swift b/Spine/DeserializeOperation.swift index 5a2192bb..f8f698e9 100644 --- a/Spine/DeserializeOperation.swift +++ b/Spine/DeserializeOperation.swift @@ -179,7 +179,7 @@ class DeserializeOperation: Operation { // Extract data resource.id = id - resource.url = representation["links"]["self"].URL + resource.url = representation["links"]["self"].url resource.meta = representation["meta"].dictionaryObject // extractAttributes(from: representation, intoResource: resource) // extractRelationships(from: representation, intoResource: resource) diff --git a/Spine/ResourceField.swift b/Spine/ResourceField.swift index 97c255fc..9698ca59 100644 --- a/Spine/ResourceField.swift +++ b/Spine/ResourceField.swift @@ -303,8 +303,8 @@ extension Relationship { func extractRelationshipData(_ linkData: JSON) -> RelationshipData { - let selfURL = linkData["links"]["self"].URL - let relatedURL = linkData["links"]["related"].URL + let selfURL = linkData["links"]["self"].url + let relatedURL = linkData["links"]["related"].url let data: [ResourceIdentifier]? if let toOne = linkData["data"].dictionary { @@ -405,7 +405,7 @@ public struct ToOneRelationship : Relationship { linkedResource = Linked.init() } - if let resourceURL = linkData["links"]?["related"].URL { + if let resourceURL = linkData["links"]?["related"].url { linkedResource!.url = resourceURL } } @@ -499,8 +499,8 @@ public struct ToManyRelationship : Relationship { var resourceCollection: LinkedResourceCollection? = nil if let linkData = serializedData["relationships"][key].dictionary { - let resourcesURL: URL? = linkData["links"]?["related"].URL - let linkURL: URL? = linkData["links"]?["self"].URL + let resourcesURL: URL? = linkData["links"]?["related"].url + let linkURL: URL? = linkData["links"]?["self"].url if let linkage = linkData["data"]?.array { // XXX: assert $0["type"].stringValue == T.resourceType From 31218bdada4aceb1fabc36e12d82866ac8a136fa Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Thu, 26 Jan 2017 21:11:56 +0100 Subject: [PATCH 12/14] add reflction --- Cartfile | 1 + Cartfile.resolved | 1 + .../Reflection.xcodeproj/project.pbxproj | 446 ++++++++++++++++++ Reflection/Reflection/Info.plist | 24 + Reflection/Reflection/Reflection.h | 19 + Spine.xcodeproj/project.pbxproj | 24 + Spine.xcworkspace/contents.xcworkspacedata | 3 + 7 files changed, 518 insertions(+) create mode 100644 Reflection/Reflection.xcodeproj/project.pbxproj create mode 100644 Reflection/Reflection/Info.plist create mode 100644 Reflection/Reflection/Reflection.h diff --git a/Cartfile b/Cartfile index 34b2c18e..9d31b941 100644 --- a/Cartfile +++ b/Cartfile @@ -1,2 +1,3 @@ github "SwiftyJSON/SwiftyJSON" ~> 3.1 github "Thomvis/BrightFutures" ~> 5.0 +github "ZeWo/reflection" ~> 0.14 diff --git a/Cartfile.resolved b/Cartfile.resolved index 890d1dbd..ee562c81 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,3 +1,4 @@ github "antitypical/Result" "3.1.0" github "SwiftyJSON/SwiftyJSON" "3.1.4" +github "ZeWo/reflection" "0.14.3" github "Thomvis/BrightFutures" "v5.1.0" diff --git a/Reflection/Reflection.xcodeproj/project.pbxproj b/Reflection/Reflection.xcodeproj/project.pbxproj new file mode 100644 index 00000000..3eb840ce --- /dev/null +++ b/Reflection/Reflection.xcodeproj/project.pbxproj @@ -0,0 +1,446 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 509BB4271E3A8EAC001FC417 /* Reflection.h in Headers */ = {isa = PBXBuildFile; fileRef = 509BB4251E3A8EAC001FC417 /* Reflection.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 509BB44D1E3A8EF4001FC417 /* Advance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB42F1E3A8EF4001FC417 /* Advance.swift */; }; + 509BB44E1E3A8EF4001FC417 /* Any+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4301E3A8EF4001FC417 /* Any+Extensions.swift */; }; + 509BB44F1E3A8EF4001FC417 /* Array+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4311E3A8EF4001FC417 /* Array+Extensions.swift */; }; + 509BB4501E3A8EF4001FC417 /* Construct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4321E3A8EF4001FC417 /* Construct.swift */; }; + 509BB4511E3A8EF4001FC417 /* Get.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4331E3A8EF4001FC417 /* Get.swift */; }; + 509BB4521E3A8EF4001FC417 /* Identity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4341E3A8EF4001FC417 /* Identity.swift */; }; + 509BB4531E3A8EF4001FC417 /* MemoryProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4351E3A8EF4001FC417 /* MemoryProperties.swift */; }; + 509BB4541E3A8EF4001FC417 /* Metadata+Class.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4361E3A8EF4001FC417 /* Metadata+Class.swift */; }; + 509BB4551E3A8EF4001FC417 /* Metadata+Kind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4371E3A8EF4001FC417 /* Metadata+Kind.swift */; }; + 509BB4561E3A8EF4001FC417 /* Metadata+Struct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4381E3A8EF4001FC417 /* Metadata+Struct.swift */; }; + 509BB4571E3A8EF4001FC417 /* Metadata+Tuple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4391E3A8EF4001FC417 /* Metadata+Tuple.swift */; }; + 509BB4581E3A8EF4001FC417 /* Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43A1E3A8EF4001FC417 /* Metadata.swift */; }; + 509BB4591E3A8EF4001FC417 /* MetadataType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43B1E3A8EF4001FC417 /* MetadataType.swift */; }; + 509BB45A1E3A8EF4001FC417 /* NominalType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43C1E3A8EF4001FC417 /* NominalType.swift */; }; + 509BB45B1E3A8EF4001FC417 /* NominalTypeDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43D1E3A8EF4001FC417 /* NominalTypeDescriptor.swift */; }; + 509BB45C1E3A8EF4001FC417 /* PointerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43E1E3A8EF4001FC417 /* PointerType.swift */; }; + 509BB45D1E3A8EF4001FC417 /* Properties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43F1E3A8EF4001FC417 /* Properties.swift */; }; + 509BB45E1E3A8EF4001FC417 /* ReflectionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4401E3A8EF4001FC417 /* ReflectionError.swift */; }; + 509BB45F1E3A8EF4001FC417 /* RelativePointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4411E3A8EF4001FC417 /* RelativePointer.swift */; }; + 509BB4601E3A8EF4001FC417 /* Set.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4421E3A8EF4001FC417 /* Set.swift */; }; + 509BB4611E3A8EF4001FC417 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4431E3A8EF4001FC417 /* Storage.swift */; }; + 509BB4621E3A8EF4001FC417 /* UnsafePointer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4441E3A8EF4001FC417 /* UnsafePointer+Extensions.swift */; }; + 509BB4631E3A8EF4001FC417 /* ValueWitnessTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4451E3A8EF4001FC417 /* ValueWitnessTable.swift */; }; + 509BB4641E3A8EF4001FC417 /* LinuxMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4471E3A8EF4001FC417 /* LinuxMain.swift */; }; + 509BB4651E3A8EF4001FC417 /* InternalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4491E3A8EF4001FC417 /* InternalTests.swift */; }; + 509BB4661E3A8EF4001FC417 /* MappableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB44A1E3A8EF4001FC417 /* MappableTests.swift */; }; + 509BB4671E3A8EF4001FC417 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB44B1E3A8EF4001FC417 /* PerformanceTests.swift */; }; + 509BB4681E3A8EF4001FC417 /* PublicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB44C1E3A8EF4001FC417 /* PublicTests.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 509BB4221E3A8EAC001FC417 /* Reflection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Reflection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 509BB4251E3A8EAC001FC417 /* Reflection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Reflection.h; sourceTree = ""; }; + 509BB4261E3A8EAC001FC417 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 509BB42F1E3A8EF4001FC417 /* Advance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Advance.swift; sourceTree = ""; }; + 509BB4301E3A8EF4001FC417 /* Any+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Any+Extensions.swift"; sourceTree = ""; }; + 509BB4311E3A8EF4001FC417 /* Array+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Extensions.swift"; sourceTree = ""; }; + 509BB4321E3A8EF4001FC417 /* Construct.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Construct.swift; sourceTree = ""; }; + 509BB4331E3A8EF4001FC417 /* Get.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Get.swift; sourceTree = ""; }; + 509BB4341E3A8EF4001FC417 /* Identity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Identity.swift; sourceTree = ""; }; + 509BB4351E3A8EF4001FC417 /* MemoryProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MemoryProperties.swift; sourceTree = ""; }; + 509BB4361E3A8EF4001FC417 /* Metadata+Class.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Metadata+Class.swift"; sourceTree = ""; }; + 509BB4371E3A8EF4001FC417 /* Metadata+Kind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Metadata+Kind.swift"; sourceTree = ""; }; + 509BB4381E3A8EF4001FC417 /* Metadata+Struct.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Metadata+Struct.swift"; sourceTree = ""; }; + 509BB4391E3A8EF4001FC417 /* Metadata+Tuple.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Metadata+Tuple.swift"; sourceTree = ""; }; + 509BB43A1E3A8EF4001FC417 /* Metadata.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Metadata.swift; sourceTree = ""; }; + 509BB43B1E3A8EF4001FC417 /* MetadataType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MetadataType.swift; sourceTree = ""; }; + 509BB43C1E3A8EF4001FC417 /* NominalType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NominalType.swift; sourceTree = ""; }; + 509BB43D1E3A8EF4001FC417 /* NominalTypeDescriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NominalTypeDescriptor.swift; sourceTree = ""; }; + 509BB43E1E3A8EF4001FC417 /* PointerType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PointerType.swift; sourceTree = ""; }; + 509BB43F1E3A8EF4001FC417 /* Properties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Properties.swift; sourceTree = ""; }; + 509BB4401E3A8EF4001FC417 /* ReflectionError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReflectionError.swift; sourceTree = ""; }; + 509BB4411E3A8EF4001FC417 /* RelativePointer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RelativePointer.swift; sourceTree = ""; }; + 509BB4421E3A8EF4001FC417 /* Set.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Set.swift; sourceTree = ""; }; + 509BB4431E3A8EF4001FC417 /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; + 509BB4441E3A8EF4001FC417 /* UnsafePointer+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UnsafePointer+Extensions.swift"; sourceTree = ""; }; + 509BB4451E3A8EF4001FC417 /* ValueWitnessTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValueWitnessTable.swift; sourceTree = ""; }; + 509BB4471E3A8EF4001FC417 /* LinuxMain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinuxMain.swift; sourceTree = ""; }; + 509BB4491E3A8EF4001FC417 /* InternalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InternalTests.swift; sourceTree = ""; }; + 509BB44A1E3A8EF4001FC417 /* MappableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MappableTests.swift; sourceTree = ""; }; + 509BB44B1E3A8EF4001FC417 /* PerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceTests.swift; sourceTree = ""; }; + 509BB44C1E3A8EF4001FC417 /* PublicTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublicTests.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 509BB41E1E3A8EAC001FC417 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 509BB4181E3A8EAC001FC417 = { + isa = PBXGroup; + children = ( + 509BB42D1E3A8EF4001FC417 /* Sources */, + 509BB4461E3A8EF4001FC417 /* Tests */, + 509BB4241E3A8EAC001FC417 /* Reflection */, + 509BB4231E3A8EAC001FC417 /* Products */, + ); + sourceTree = ""; + }; + 509BB4231E3A8EAC001FC417 /* Products */ = { + isa = PBXGroup; + children = ( + 509BB4221E3A8EAC001FC417 /* Reflection.framework */, + ); + name = Products; + sourceTree = ""; + }; + 509BB4241E3A8EAC001FC417 /* Reflection */ = { + isa = PBXGroup; + children = ( + 509BB4251E3A8EAC001FC417 /* Reflection.h */, + 509BB4261E3A8EAC001FC417 /* Info.plist */, + ); + path = Reflection; + sourceTree = ""; + }; + 509BB42D1E3A8EF4001FC417 /* Sources */ = { + isa = PBXGroup; + children = ( + 509BB42E1E3A8EF4001FC417 /* Reflection */, + ); + name = Sources; + path = ../Carthage/Checkouts/reflection/Sources; + sourceTree = ""; + }; + 509BB42E1E3A8EF4001FC417 /* Reflection */ = { + isa = PBXGroup; + children = ( + 509BB42F1E3A8EF4001FC417 /* Advance.swift */, + 509BB4301E3A8EF4001FC417 /* Any+Extensions.swift */, + 509BB4311E3A8EF4001FC417 /* Array+Extensions.swift */, + 509BB4321E3A8EF4001FC417 /* Construct.swift */, + 509BB4331E3A8EF4001FC417 /* Get.swift */, + 509BB4341E3A8EF4001FC417 /* Identity.swift */, + 509BB4351E3A8EF4001FC417 /* MemoryProperties.swift */, + 509BB4361E3A8EF4001FC417 /* Metadata+Class.swift */, + 509BB4371E3A8EF4001FC417 /* Metadata+Kind.swift */, + 509BB4381E3A8EF4001FC417 /* Metadata+Struct.swift */, + 509BB4391E3A8EF4001FC417 /* Metadata+Tuple.swift */, + 509BB43A1E3A8EF4001FC417 /* Metadata.swift */, + 509BB43B1E3A8EF4001FC417 /* MetadataType.swift */, + 509BB43C1E3A8EF4001FC417 /* NominalType.swift */, + 509BB43D1E3A8EF4001FC417 /* NominalTypeDescriptor.swift */, + 509BB43E1E3A8EF4001FC417 /* PointerType.swift */, + 509BB43F1E3A8EF4001FC417 /* Properties.swift */, + 509BB4401E3A8EF4001FC417 /* ReflectionError.swift */, + 509BB4411E3A8EF4001FC417 /* RelativePointer.swift */, + 509BB4421E3A8EF4001FC417 /* Set.swift */, + 509BB4431E3A8EF4001FC417 /* Storage.swift */, + 509BB4441E3A8EF4001FC417 /* UnsafePointer+Extensions.swift */, + 509BB4451E3A8EF4001FC417 /* ValueWitnessTable.swift */, + ); + path = Reflection; + sourceTree = ""; + }; + 509BB4461E3A8EF4001FC417 /* Tests */ = { + isa = PBXGroup; + children = ( + 509BB4471E3A8EF4001FC417 /* LinuxMain.swift */, + 509BB4481E3A8EF4001FC417 /* ReflectionTests */, + ); + name = Tests; + path = ../Carthage/Checkouts/reflection/Tests; + sourceTree = ""; + }; + 509BB4481E3A8EF4001FC417 /* ReflectionTests */ = { + isa = PBXGroup; + children = ( + 509BB4491E3A8EF4001FC417 /* InternalTests.swift */, + 509BB44A1E3A8EF4001FC417 /* MappableTests.swift */, + 509BB44B1E3A8EF4001FC417 /* PerformanceTests.swift */, + 509BB44C1E3A8EF4001FC417 /* PublicTests.swift */, + ); + path = ReflectionTests; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 509BB41F1E3A8EAC001FC417 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 509BB4271E3A8EAC001FC417 /* Reflection.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 509BB4211E3A8EAC001FC417 /* Reflection */ = { + isa = PBXNativeTarget; + buildConfigurationList = 509BB42A1E3A8EAC001FC417 /* Build configuration list for PBXNativeTarget "Reflection" */; + buildPhases = ( + 509BB41D1E3A8EAC001FC417 /* Sources */, + 509BB41E1E3A8EAC001FC417 /* Frameworks */, + 509BB41F1E3A8EAC001FC417 /* Headers */, + 509BB4201E3A8EAC001FC417 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Reflection; + productName = Reflection; + productReference = 509BB4221E3A8EAC001FC417 /* Reflection.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 509BB4191E3A8EAC001FC417 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0820; + TargetAttributes = { + 509BB4211E3A8EAC001FC417 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = 3YVY2RHHVQ; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 509BB41C1E3A8EAC001FC417 /* Build configuration list for PBXProject "Reflection" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = 509BB4181E3A8EAC001FC417; + productRefGroup = 509BB4231E3A8EAC001FC417 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 509BB4211E3A8EAC001FC417 /* Reflection */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 509BB4201E3A8EAC001FC417 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 509BB41D1E3A8EAC001FC417 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 509BB4631E3A8EF4001FC417 /* ValueWitnessTable.swift in Sources */, + 509BB4601E3A8EF4001FC417 /* Set.swift in Sources */, + 509BB4591E3A8EF4001FC417 /* MetadataType.swift in Sources */, + 509BB44E1E3A8EF4001FC417 /* Any+Extensions.swift in Sources */, + 509BB4541E3A8EF4001FC417 /* Metadata+Class.swift in Sources */, + 509BB45E1E3A8EF4001FC417 /* ReflectionError.swift in Sources */, + 509BB4551E3A8EF4001FC417 /* Metadata+Kind.swift in Sources */, + 509BB45B1E3A8EF4001FC417 /* NominalTypeDescriptor.swift in Sources */, + 509BB4571E3A8EF4001FC417 /* Metadata+Tuple.swift in Sources */, + 509BB4611E3A8EF4001FC417 /* Storage.swift in Sources */, + 509BB4621E3A8EF4001FC417 /* UnsafePointer+Extensions.swift in Sources */, + 509BB4521E3A8EF4001FC417 /* Identity.swift in Sources */, + 509BB44F1E3A8EF4001FC417 /* Array+Extensions.swift in Sources */, + 509BB44D1E3A8EF4001FC417 /* Advance.swift in Sources */, + 509BB4681E3A8EF4001FC417 /* PublicTests.swift in Sources */, + 509BB4501E3A8EF4001FC417 /* Construct.swift in Sources */, + 509BB4641E3A8EF4001FC417 /* LinuxMain.swift in Sources */, + 509BB4511E3A8EF4001FC417 /* Get.swift in Sources */, + 509BB4671E3A8EF4001FC417 /* PerformanceTests.swift in Sources */, + 509BB4661E3A8EF4001FC417 /* MappableTests.swift in Sources */, + 509BB45F1E3A8EF4001FC417 /* RelativePointer.swift in Sources */, + 509BB45D1E3A8EF4001FC417 /* Properties.swift in Sources */, + 509BB45A1E3A8EF4001FC417 /* NominalType.swift in Sources */, + 509BB4531E3A8EF4001FC417 /* MemoryProperties.swift in Sources */, + 509BB4581E3A8EF4001FC417 /* Metadata.swift in Sources */, + 509BB4651E3A8EF4001FC417 /* InternalTests.swift in Sources */, + 509BB4561E3A8EF4001FC417 /* Metadata+Struct.swift in Sources */, + 509BB45C1E3A8EF4001FC417 /* PointerType.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 509BB4281E3A8EAC001FC417 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 509BB4291E3A8EAC001FC417 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 509BB42B1E3A8EAC001FC417 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3YVY2RHHVQ; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Reflection/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.zewo.Reflection; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 509BB42C1E3A8EAC001FC417 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3YVY2RHHVQ; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Reflection/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.zewo.Reflection; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 509BB41C1E3A8EAC001FC417 /* Build configuration list for PBXProject "Reflection" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 509BB4281E3A8EAC001FC417 /* Debug */, + 509BB4291E3A8EAC001FC417 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 509BB42A1E3A8EAC001FC417 /* Build configuration list for PBXNativeTarget "Reflection" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 509BB42B1E3A8EAC001FC417 /* Debug */, + 509BB42C1E3A8EAC001FC417 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; +/* End XCConfigurationList section */ + }; + rootObject = 509BB4191E3A8EAC001FC417 /* Project object */; +} diff --git a/Reflection/Reflection/Info.plist b/Reflection/Reflection/Info.plist new file mode 100644 index 00000000..fbe1e6b3 --- /dev/null +++ b/Reflection/Reflection/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Reflection/Reflection/Reflection.h b/Reflection/Reflection/Reflection.h new file mode 100644 index 00000000..91bca2ab --- /dev/null +++ b/Reflection/Reflection/Reflection.h @@ -0,0 +1,19 @@ +// +// Reflection.h +// Reflection +// +// Created by Max Bothe on 26/01/17. +// +// + +#import + +//! Project version number for Reflection. +FOUNDATION_EXPORT double ReflectionVersionNumber; + +//! Project version string for Reflection. +FOUNDATION_EXPORT const unsigned char ReflectionVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Spine.xcodeproj/project.pbxproj b/Spine.xcodeproj/project.pbxproj index 4f1724f8..a9aec040 100644 --- a/Spine.xcodeproj/project.pbxproj +++ b/Spine.xcodeproj/project.pbxproj @@ -82,6 +82,10 @@ 24E6DF751D6831520072D4DC /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E6DF721D6831520072D4DC /* SwiftyJSON.framework */; }; 24EA5DB11D2D39A700F3E867 /* SingleFooWithUnregisteredType.json in Resources */ = {isa = PBXBuildFile; fileRef = 24EA5DB01D2D39A100F3E867 /* SingleFooWithUnregisteredType.json */; }; 24EA5DB21D2D39A800F3E867 /* SingleFooWithUnregisteredType.json in Resources */ = {isa = PBXBuildFile; fileRef = 24EA5DB01D2D39A100F3E867 /* SingleFooWithUnregisteredType.json */; }; + 509BB46A1E3A8F25001FC417 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 509BB4691E3A8F25001FC417 /* Reflection.framework */; }; + 509BB46C1E3A8F2C001FC417 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 509BB46B1E3A8F2C001FC417 /* Reflection.framework */; }; + 509BB46E1E3A8F31001FC417 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 509BB46D1E3A8F31001FC417 /* Reflection.framework */; }; + 509BB4701E3A8F36001FC417 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 509BB46F1E3A8F36001FC417 /* Reflection.framework */; }; D302A6531DA13BAF00420C48 /* Spine.swift in Sources */ = {isa = PBXBuildFile; fileRef = D373F7A319B224BB00275AFC /* Spine.swift */; }; D302A6541DA13BAF00420C48 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = D331836B19B2302500936FBB /* Query.swift */; }; D302A6551DA13BAF00420C48 /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3452C2E1AD18E6900CD413B /* Operation.swift */; }; @@ -228,6 +232,10 @@ 24E6DF711D6831520072D4DC /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/Mac/Result.framework; sourceTree = ""; }; 24E6DF721D6831520072D4DC /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/Mac/SwiftyJSON.framework; sourceTree = ""; }; 24EA5DB01D2D39A100F3E867 /* SingleFooWithUnregisteredType.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = SingleFooWithUnregisteredType.json; sourceTree = ""; }; + 509BB4691E3A8F25001FC417 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "Reflection/build/Debug-iphoneos/Reflection.framework"; sourceTree = ""; }; + 509BB46B1E3A8F2C001FC417 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "Reflection/build/Debug-iphoneos/Reflection.framework"; sourceTree = ""; }; + 509BB46D1E3A8F31001FC417 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "Reflection/build/Debug-iphoneos/Reflection.framework"; sourceTree = ""; }; + 509BB46F1E3A8F36001FC417 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "Reflection/build/Debug-iphoneos/Reflection.framework"; sourceTree = ""; }; D307FBED1A97756700EE0FAC /* SingleFooIncludingBars.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = SingleFooIncludingBars.json; sourceTree = ""; }; D312E2F719BB83A8004BB3E0 /* SerializingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SerializingTests.swift; sourceTree = ""; }; D32EA6DC1BCBD5930076CFA5 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; @@ -279,6 +287,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 509BB46C1E3A8F2C001FC417 /* Reflection.framework in Frameworks */, 240BCA761CD930BE00842222 /* Result.framework in Frameworks */, 240BCA781CD930C700842222 /* BrightFutures.framework in Frameworks */, 240BCA7A1CD930CD00842222 /* SwiftyJSON.framework in Frameworks */, @@ -299,6 +308,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 509BB46E1E3A8F31001FC417 /* Reflection.framework in Frameworks */, 24E6DF731D6831520072D4DC /* BrightFutures.framework in Frameworks */, 24E6DF741D6831520072D4DC /* Result.framework in Frameworks */, 24E6DF751D6831520072D4DC /* SwiftyJSON.framework in Frameworks */, @@ -320,6 +330,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 509BB46A1E3A8F25001FC417 /* Reflection.framework in Frameworks */, D32EA6DD1BCBD5930076CFA5 /* Result.framework in Frameworks */, D32EA6DA1BCBD5930076CFA5 /* BrightFutures.framework in Frameworks */, D32EA6DB1BCBD5930076CFA5 /* SwiftyJSON.framework in Frameworks */, @@ -340,6 +351,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 509BB4701E3A8F36001FC417 /* Reflection.framework in Frameworks */, D398E1631DA1562E00FBC6FD /* BrightFutures.framework in Frameworks */, D398E1641DA1562E00FBC6FD /* Result.framework in Frameworks */, D398E1651DA1562E00FBC6FD /* SwiftyJSON.framework in Frameworks */, @@ -362,6 +374,10 @@ 245B5DD41CD92E3200E44FBE /* Frameworks */ = { isa = PBXGroup; children = ( + 509BB46F1E3A8F36001FC417 /* Reflection.framework */, + 509BB46D1E3A8F31001FC417 /* Reflection.framework */, + 509BB46B1E3A8F2C001FC417 /* Reflection.framework */, + 509BB4691E3A8F25001FC417 /* Reflection.framework */, D398E15F1DA1561400FBC6FD /* watchOS */, 24E6DF6F1D6831280072D4DC /* macOS */, 245B5DD51CD92E3900E44FBE /* iOS */, @@ -1062,6 +1078,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/tvOS", + "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", ); INFOPLIST_FILE = Spine/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1085,6 +1102,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/tvOS", + "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", ); INFOPLIST_FILE = Spine/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1150,6 +1168,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/Mac", + "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", ); FRAMEWORK_VERSION = A; GCC_NO_COMMON_BLOCKS = YES; @@ -1179,6 +1198,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/Mac", + "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", ); FRAMEWORK_VERSION = A; GCC_NO_COMMON_BLOCKS = YES; @@ -1343,6 +1363,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", ); INFOPLIST_FILE = Spine/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1367,6 +1388,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/iOS", + "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", ); INFOPLIST_FILE = Spine/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1430,6 +1452,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/watchOS", + "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", ); INFOPLIST_FILE = "$(SRCROOT)/Spine/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1462,6 +1485,7 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/watchOS", + "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", ); INFOPLIST_FILE = "$(SRCROOT)/Spine/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/Spine.xcworkspace/contents.xcworkspacedata b/Spine.xcworkspace/contents.xcworkspacedata index 1a8a6663..b1eb3668 100644 --- a/Spine.xcworkspace/contents.xcworkspacedata +++ b/Spine.xcworkspace/contents.xcworkspacedata @@ -1,6 +1,9 @@ + + From 195383d3adb8866a116b2de4a25a21a768f4b03c Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Fri, 27 Jan 2017 10:39:53 +0100 Subject: [PATCH 13/14] running with reflection. - broke macOS, tvOS, watchOS --- .../Reflection.xcodeproj/project.pbxproj | 485 +++++++++++++----- Reflection/Reflection/Info.plist | 2 + Reflection/Reflection/Reflection.h | 19 - Spine.xcodeproj/project.pbxproj | 252 ++++----- Spine/Resource.swift | 1 + SpineTests/Fixtures.swift | 8 +- 6 files changed, 487 insertions(+), 280 deletions(-) delete mode 100644 Reflection/Reflection/Reflection.h diff --git a/Reflection/Reflection.xcodeproj/project.pbxproj b/Reflection/Reflection.xcodeproj/project.pbxproj index 3eb840ce..9a4d416c 100644 --- a/Reflection/Reflection.xcodeproj/project.pbxproj +++ b/Reflection/Reflection.xcodeproj/project.pbxproj @@ -7,41 +7,13 @@ objects = { /* Begin PBXBuildFile section */ - 509BB4271E3A8EAC001FC417 /* Reflection.h in Headers */ = {isa = PBXBuildFile; fileRef = 509BB4251E3A8EAC001FC417 /* Reflection.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 509BB44D1E3A8EF4001FC417 /* Advance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB42F1E3A8EF4001FC417 /* Advance.swift */; }; - 509BB44E1E3A8EF4001FC417 /* Any+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4301E3A8EF4001FC417 /* Any+Extensions.swift */; }; - 509BB44F1E3A8EF4001FC417 /* Array+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4311E3A8EF4001FC417 /* Array+Extensions.swift */; }; - 509BB4501E3A8EF4001FC417 /* Construct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4321E3A8EF4001FC417 /* Construct.swift */; }; - 509BB4511E3A8EF4001FC417 /* Get.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4331E3A8EF4001FC417 /* Get.swift */; }; - 509BB4521E3A8EF4001FC417 /* Identity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4341E3A8EF4001FC417 /* Identity.swift */; }; - 509BB4531E3A8EF4001FC417 /* MemoryProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4351E3A8EF4001FC417 /* MemoryProperties.swift */; }; - 509BB4541E3A8EF4001FC417 /* Metadata+Class.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4361E3A8EF4001FC417 /* Metadata+Class.swift */; }; - 509BB4551E3A8EF4001FC417 /* Metadata+Kind.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4371E3A8EF4001FC417 /* Metadata+Kind.swift */; }; - 509BB4561E3A8EF4001FC417 /* Metadata+Struct.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4381E3A8EF4001FC417 /* Metadata+Struct.swift */; }; - 509BB4571E3A8EF4001FC417 /* Metadata+Tuple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4391E3A8EF4001FC417 /* Metadata+Tuple.swift */; }; - 509BB4581E3A8EF4001FC417 /* Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43A1E3A8EF4001FC417 /* Metadata.swift */; }; - 509BB4591E3A8EF4001FC417 /* MetadataType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43B1E3A8EF4001FC417 /* MetadataType.swift */; }; - 509BB45A1E3A8EF4001FC417 /* NominalType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43C1E3A8EF4001FC417 /* NominalType.swift */; }; - 509BB45B1E3A8EF4001FC417 /* NominalTypeDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43D1E3A8EF4001FC417 /* NominalTypeDescriptor.swift */; }; - 509BB45C1E3A8EF4001FC417 /* PointerType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43E1E3A8EF4001FC417 /* PointerType.swift */; }; - 509BB45D1E3A8EF4001FC417 /* Properties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB43F1E3A8EF4001FC417 /* Properties.swift */; }; - 509BB45E1E3A8EF4001FC417 /* ReflectionError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4401E3A8EF4001FC417 /* ReflectionError.swift */; }; - 509BB45F1E3A8EF4001FC417 /* RelativePointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4411E3A8EF4001FC417 /* RelativePointer.swift */; }; - 509BB4601E3A8EF4001FC417 /* Set.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4421E3A8EF4001FC417 /* Set.swift */; }; - 509BB4611E3A8EF4001FC417 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4431E3A8EF4001FC417 /* Storage.swift */; }; - 509BB4621E3A8EF4001FC417 /* UnsafePointer+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4441E3A8EF4001FC417 /* UnsafePointer+Extensions.swift */; }; - 509BB4631E3A8EF4001FC417 /* ValueWitnessTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4451E3A8EF4001FC417 /* ValueWitnessTable.swift */; }; - 509BB4641E3A8EF4001FC417 /* LinuxMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4471E3A8EF4001FC417 /* LinuxMain.swift */; }; - 509BB4651E3A8EF4001FC417 /* InternalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB4491E3A8EF4001FC417 /* InternalTests.swift */; }; - 509BB4661E3A8EF4001FC417 /* MappableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB44A1E3A8EF4001FC417 /* MappableTests.swift */; }; - 509BB4671E3A8EF4001FC417 /* PerformanceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB44B1E3A8EF4001FC417 /* PerformanceTests.swift */; }; - 509BB4681E3A8EF4001FC417 /* PublicTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 509BB44C1E3A8EF4001FC417 /* PublicTests.swift */; }; + 50F64E2D1E3B4BC400419003 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 50F64E2C1E3B4BC400419003 /* Info.plist */; }; + 50F64E2E1E3B4BC400419003 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 50F64E2C1E3B4BC400419003 /* Info.plist */; }; + 50F64E2F1E3B4BC400419003 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 50F64E2C1E3B4BC400419003 /* Info.plist */; }; + 50F64E301E3B4BC400419003 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 50F64E2C1E3B4BC400419003 /* Info.plist */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 509BB4221E3A8EAC001FC417 /* Reflection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Reflection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 509BB4251E3A8EAC001FC417 /* Reflection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Reflection.h; sourceTree = ""; }; - 509BB4261E3A8EAC001FC417 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 509BB42F1E3A8EF4001FC417 /* Advance.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Advance.swift; sourceTree = ""; }; 509BB4301E3A8EF4001FC417 /* Any+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Any+Extensions.swift"; sourceTree = ""; }; 509BB4311E3A8EF4001FC417 /* Array+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Array+Extensions.swift"; sourceTree = ""; }; @@ -65,15 +37,36 @@ 509BB4431E3A8EF4001FC417 /* Storage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; 509BB4441E3A8EF4001FC417 /* UnsafePointer+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UnsafePointer+Extensions.swift"; sourceTree = ""; }; 509BB4451E3A8EF4001FC417 /* ValueWitnessTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ValueWitnessTable.swift; sourceTree = ""; }; - 509BB4471E3A8EF4001FC417 /* LinuxMain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinuxMain.swift; sourceTree = ""; }; - 509BB4491E3A8EF4001FC417 /* InternalTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InternalTests.swift; sourceTree = ""; }; - 509BB44A1E3A8EF4001FC417 /* MappableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MappableTests.swift; sourceTree = ""; }; - 509BB44B1E3A8EF4001FC417 /* PerformanceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformanceTests.swift; sourceTree = ""; }; - 509BB44C1E3A8EF4001FC417 /* PublicTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PublicTests.swift; sourceTree = ""; }; + 50F64DFB1E3B468C00419003 /* Reflection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Reflection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50F64E081E3B46C100419003 /* Reflection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Reflection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50F64E151E3B46EC00419003 /* Reflection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Reflection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50F64E221E3B471400419003 /* Reflection.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Reflection.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 50F64E2C1E3B4BC400419003 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Reflection/Info.plist; sourceTree = SOURCE_ROOT; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 509BB41E1E3A8EAC001FC417 /* Frameworks */ = { + 50F64DF71E3B468C00419003 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E041E3B46C100419003 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E111E3B46EC00419003 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E1E1E3B471400419003 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( @@ -87,8 +80,7 @@ isa = PBXGroup; children = ( 509BB42D1E3A8EF4001FC417 /* Sources */, - 509BB4461E3A8EF4001FC417 /* Tests */, - 509BB4241E3A8EAC001FC417 /* Reflection */, + 50F64E321E3B4CC100419003 /* Supporting Files */, 509BB4231E3A8EAC001FC417 /* Products */, ); sourceTree = ""; @@ -96,20 +88,14 @@ 509BB4231E3A8EAC001FC417 /* Products */ = { isa = PBXGroup; children = ( - 509BB4221E3A8EAC001FC417 /* Reflection.framework */, + 50F64DFB1E3B468C00419003 /* Reflection.framework */, + 50F64E081E3B46C100419003 /* Reflection.framework */, + 50F64E151E3B46EC00419003 /* Reflection.framework */, + 50F64E221E3B471400419003 /* Reflection.framework */, ); name = Products; sourceTree = ""; }; - 509BB4241E3A8EAC001FC417 /* Reflection */ = { - isa = PBXGroup; - children = ( - 509BB4251E3A8EAC001FC417 /* Reflection.h */, - 509BB4261E3A8EAC001FC417 /* Info.plist */, - ); - path = Reflection; - sourceTree = ""; - }; 509BB42D1E3A8EF4001FC417 /* Sources */ = { isa = PBXGroup; children = ( @@ -149,57 +135,118 @@ path = Reflection; sourceTree = ""; }; - 509BB4461E3A8EF4001FC417 /* Tests */ = { + 50F64E321E3B4CC100419003 /* Supporting Files */ = { isa = PBXGroup; children = ( - 509BB4471E3A8EF4001FC417 /* LinuxMain.swift */, - 509BB4481E3A8EF4001FC417 /* ReflectionTests */, + 50F64E2C1E3B4BC400419003 /* Info.plist */, ); - name = Tests; - path = ../Carthage/Checkouts/reflection/Tests; - sourceTree = ""; - }; - 509BB4481E3A8EF4001FC417 /* ReflectionTests */ = { - isa = PBXGroup; - children = ( - 509BB4491E3A8EF4001FC417 /* InternalTests.swift */, - 509BB44A1E3A8EF4001FC417 /* MappableTests.swift */, - 509BB44B1E3A8EF4001FC417 /* PerformanceTests.swift */, - 509BB44C1E3A8EF4001FC417 /* PublicTests.swift */, - ); - path = ReflectionTests; + name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 509BB41F1E3A8EAC001FC417 /* Headers */ = { + 50F64DF81E3B468C00419003 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E051E3B46C100419003 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E121E3B46EC00419003 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E1F1E3B471400419003 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 509BB4271E3A8EAC001FC417 /* Reflection.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 509BB4211E3A8EAC001FC417 /* Reflection */ = { + 50F64DFA1E3B468C00419003 /* Reflection-iOS */ = { isa = PBXNativeTarget; - buildConfigurationList = 509BB42A1E3A8EAC001FC417 /* Build configuration list for PBXNativeTarget "Reflection" */; + buildConfigurationList = 50F64E001E3B468D00419003 /* Build configuration list for PBXNativeTarget "Reflection-iOS" */; buildPhases = ( - 509BB41D1E3A8EAC001FC417 /* Sources */, - 509BB41E1E3A8EAC001FC417 /* Frameworks */, - 509BB41F1E3A8EAC001FC417 /* Headers */, - 509BB4201E3A8EAC001FC417 /* Resources */, + 50F64DF61E3B468C00419003 /* Sources */, + 50F64DF71E3B468C00419003 /* Frameworks */, + 50F64DF81E3B468C00419003 /* Headers */, + 50F64DF91E3B468C00419003 /* Resources */, ); buildRules = ( ); dependencies = ( ); - name = Reflection; + name = "Reflection-iOS"; productName = Reflection; - productReference = 509BB4221E3A8EAC001FC417 /* Reflection.framework */; + productReference = 50F64DFB1E3B468C00419003 /* Reflection.framework */; + productType = "com.apple.product-type.framework"; + }; + 50F64E071E3B46C100419003 /* Reflection-macOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50F64E0D1E3B46C100419003 /* Build configuration list for PBXNativeTarget "Reflection-macOS" */; + buildPhases = ( + 50F64E031E3B46C100419003 /* Sources */, + 50F64E041E3B46C100419003 /* Frameworks */, + 50F64E051E3B46C100419003 /* Headers */, + 50F64E061E3B46C100419003 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Reflection-macOS"; + productName = Reflection; + productReference = 50F64E081E3B46C100419003 /* Reflection.framework */; + productType = "com.apple.product-type.framework"; + }; + 50F64E141E3B46EC00419003 /* Reflection-tvOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50F64E1A1E3B46EC00419003 /* Build configuration list for PBXNativeTarget "Reflection-tvOS" */; + buildPhases = ( + 50F64E101E3B46EC00419003 /* Sources */, + 50F64E111E3B46EC00419003 /* Frameworks */, + 50F64E121E3B46EC00419003 /* Headers */, + 50F64E131E3B46EC00419003 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Reflection-tvOS"; + productName = Reflection; + productReference = 50F64E151E3B46EC00419003 /* Reflection.framework */; + productType = "com.apple.product-type.framework"; + }; + 50F64E211E3B471400419003 /* Reflection-watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 50F64E271E3B471400419003 /* Build configuration list for PBXNativeTarget "Reflection-watchOS" */; + buildPhases = ( + 50F64E1D1E3B471400419003 /* Sources */, + 50F64E1E1E3B471400419003 /* Frameworks */, + 50F64E1F1E3B471400419003 /* Headers */, + 50F64E201E3B471400419003 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "Reflection-watchOS"; + productName = Reflection; + productReference = 50F64E221E3B471400419003 /* Reflection.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ @@ -210,7 +257,22 @@ attributes = { LastUpgradeCheck = 0820; TargetAttributes = { - 509BB4211E3A8EAC001FC417 = { + 50F64DFA1E3B468C00419003 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = 3YVY2RHHVQ; + ProvisioningStyle = Automatic; + }; + 50F64E071E3B46C100419003 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = 3YVY2RHHVQ; + ProvisioningStyle = Automatic; + }; + 50F64E141E3B46EC00419003 = { + CreatedOnToolsVersion = 8.2.1; + DevelopmentTeam = 3YVY2RHHVQ; + ProvisioningStyle = Automatic; + }; + 50F64E211E3B471400419003 = { CreatedOnToolsVersion = 8.2.1; DevelopmentTeam = 3YVY2RHHVQ; ProvisioningStyle = Automatic; @@ -229,54 +291,75 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 509BB4211E3A8EAC001FC417 /* Reflection */, + 50F64DFA1E3B468C00419003 /* Reflection-iOS */, + 50F64E071E3B46C100419003 /* Reflection-macOS */, + 50F64E141E3B46EC00419003 /* Reflection-tvOS */, + 50F64E211E3B471400419003 /* Reflection-watchOS */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 509BB4201E3A8EAC001FC417 /* Resources */ = { + 50F64DF91E3B468C00419003 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 50F64E2D1E3B4BC400419003 /* Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E061E3B46C100419003 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 50F64E2E1E3B4BC400419003 /* Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E131E3B46EC00419003 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 50F64E2F1E3B4BC400419003 /* Info.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E201E3B471400419003 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 50F64E301E3B4BC400419003 /* Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 509BB41D1E3A8EAC001FC417 /* Sources */ = { + 50F64DF61E3B468C00419003 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E031E3B46C100419003 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E101E3B46EC00419003 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 50F64E1D1E3B471400419003 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 509BB4631E3A8EF4001FC417 /* ValueWitnessTable.swift in Sources */, - 509BB4601E3A8EF4001FC417 /* Set.swift in Sources */, - 509BB4591E3A8EF4001FC417 /* MetadataType.swift in Sources */, - 509BB44E1E3A8EF4001FC417 /* Any+Extensions.swift in Sources */, - 509BB4541E3A8EF4001FC417 /* Metadata+Class.swift in Sources */, - 509BB45E1E3A8EF4001FC417 /* ReflectionError.swift in Sources */, - 509BB4551E3A8EF4001FC417 /* Metadata+Kind.swift in Sources */, - 509BB45B1E3A8EF4001FC417 /* NominalTypeDescriptor.swift in Sources */, - 509BB4571E3A8EF4001FC417 /* Metadata+Tuple.swift in Sources */, - 509BB4611E3A8EF4001FC417 /* Storage.swift in Sources */, - 509BB4621E3A8EF4001FC417 /* UnsafePointer+Extensions.swift in Sources */, - 509BB4521E3A8EF4001FC417 /* Identity.swift in Sources */, - 509BB44F1E3A8EF4001FC417 /* Array+Extensions.swift in Sources */, - 509BB44D1E3A8EF4001FC417 /* Advance.swift in Sources */, - 509BB4681E3A8EF4001FC417 /* PublicTests.swift in Sources */, - 509BB4501E3A8EF4001FC417 /* Construct.swift in Sources */, - 509BB4641E3A8EF4001FC417 /* LinuxMain.swift in Sources */, - 509BB4511E3A8EF4001FC417 /* Get.swift in Sources */, - 509BB4671E3A8EF4001FC417 /* PerformanceTests.swift in Sources */, - 509BB4661E3A8EF4001FC417 /* MappableTests.swift in Sources */, - 509BB45F1E3A8EF4001FC417 /* RelativePointer.swift in Sources */, - 509BB45D1E3A8EF4001FC417 /* Properties.swift in Sources */, - 509BB45A1E3A8EF4001FC417 /* NominalType.swift in Sources */, - 509BB4531E3A8EF4001FC417 /* MemoryProperties.swift in Sources */, - 509BB4581E3A8EF4001FC417 /* Metadata.swift in Sources */, - 509BB4651E3A8EF4001FC417 /* InternalTests.swift in Sources */, - 509BB4561E3A8EF4001FC417 /* Metadata+Struct.swift in Sources */, - 509BB45C1E3A8EF4001FC417 /* PointerType.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -324,7 +407,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -371,7 +454,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.2; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; @@ -382,9 +465,10 @@ }; name = Release; }; - 509BB42B1E3A8EAC001FC417 /* Debug */ = { + 50F64E011E3B468D00419003 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 3YVY2RHHVQ; @@ -395,15 +479,19 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.zewo.Reflection; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = Reflection; + SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 3.1; }; name = Debug; }; - 509BB42C1E3A8EAC001FC417 /* Release */ = { + 50F64E021E3B468D00419003 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; CODE_SIGN_IDENTITY = ""; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 3YVY2RHHVQ; @@ -414,12 +502,151 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = com.zewo.Reflection; - PRODUCT_NAME = "$(TARGET_NAME)"; + PRODUCT_NAME = Reflection; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 3.1; + }; + name = Release; + }; + 50F64E0E1E3B46C100419003 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3YVY2RHHVQ; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = Reflection/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = com.zewo.Reflection; + PRODUCT_NAME = Reflection; + SDKROOT = macosx; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 50F64E0F1E3B46C100419003 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3YVY2RHHVQ; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = Reflection/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MACOSX_DEPLOYMENT_TARGET = 10.11; + PRODUCT_BUNDLE_IDENTIFIER = com.zewo.Reflection; + PRODUCT_NAME = Reflection; + SDKROOT = macosx; SKIP_INSTALL = YES; SWIFT_VERSION = 3.0; }; name = Release; }; + 50F64E1B1E3B46EC00419003 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3YVY2RHHVQ; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Reflection/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.zewo.Reflection; + PRODUCT_NAME = Reflection; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 10.1; + }; + name = Debug; + }; + 50F64E1C1E3B46EC00419003 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3YVY2RHHVQ; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Reflection/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.zewo.Reflection; + PRODUCT_NAME = Reflection; + SDKROOT = appletvos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = 3; + TVOS_DEPLOYMENT_TARGET = 10.1; + }; + name = Release; + }; + 50F64E281E3B471400419003 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3YVY2RHHVQ; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Reflection/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.zewo.Reflection; + PRODUCT_NAME = Reflection; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 3.1; + }; + name = Debug; + }; + 50F64E291E3B471400419003 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + APPLICATION_EXTENSION_API_ONLY = YES; + CODE_SIGN_IDENTITY = ""; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = 3YVY2RHHVQ; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Reflection/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.zewo.Reflection; + PRODUCT_NAME = Reflection; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 3.1; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -432,11 +659,35 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 509BB42A1E3A8EAC001FC417 /* Build configuration list for PBXNativeTarget "Reflection" */ = { + 50F64E001E3B468D00419003 /* Build configuration list for PBXNativeTarget "Reflection-iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50F64E011E3B468D00419003 /* Debug */, + 50F64E021E3B468D00419003 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + 50F64E0D1E3B46C100419003 /* Build configuration list for PBXNativeTarget "Reflection-macOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50F64E0E1E3B46C100419003 /* Debug */, + 50F64E0F1E3B46C100419003 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + 50F64E1A1E3B46EC00419003 /* Build configuration list for PBXNativeTarget "Reflection-tvOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 50F64E1B1E3B46EC00419003 /* Debug */, + 50F64E1C1E3B46EC00419003 /* Release */, + ); + defaultConfigurationIsVisible = 0; + }; + 50F64E271E3B471400419003 /* Build configuration list for PBXNativeTarget "Reflection-watchOS" */ = { isa = XCConfigurationList; buildConfigurations = ( - 509BB42B1E3A8EAC001FC417 /* Debug */, - 509BB42C1E3A8EAC001FC417 /* Release */, + 50F64E281E3B471400419003 /* Debug */, + 50F64E291E3B471400419003 /* Release */, ); defaultConfigurationIsVisible = 0; }; diff --git a/Reflection/Reflection/Info.plist b/Reflection/Reflection/Info.plist index fbe1e6b3..d3de8eef 100644 --- a/Reflection/Reflection/Info.plist +++ b/Reflection/Reflection/Info.plist @@ -16,6 +16,8 @@ FMWK CFBundleShortVersionString 1.0 + CFBundleSignature + ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass diff --git a/Reflection/Reflection/Reflection.h b/Reflection/Reflection/Reflection.h deleted file mode 100644 index 91bca2ab..00000000 --- a/Reflection/Reflection/Reflection.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Reflection.h -// Reflection -// -// Created by Max Bothe on 26/01/17. -// -// - -#import - -//! Project version number for Reflection. -FOUNDATION_EXPORT double ReflectionVersionNumber; - -//! Project version string for Reflection. -FOUNDATION_EXPORT const unsigned char ReflectionVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Spine.xcodeproj/project.pbxproj b/Spine.xcodeproj/project.pbxproj index a9aec040..712ce8da 100644 --- a/Spine.xcodeproj/project.pbxproj +++ b/Spine.xcodeproj/project.pbxproj @@ -55,12 +55,6 @@ 240BCA711CD9302E00842222 /* PagedFoos-1.json in Resources */ = {isa = PBXBuildFile; fileRef = D3BE2B1B1AD56C840061167C /* PagedFoos-1.json */; }; 240BCA721CD9303000842222 /* PagedFoos-2.json in Resources */ = {isa = PBXBuildFile; fileRef = D3BE2B1C1AD56C840061167C /* PagedFoos-2.json */; }; 240BCA731CD9303300842222 /* Errors.json in Resources */ = {isa = PBXBuildFile; fileRef = D3960DF01A9B5FBC009948B0 /* Errors.json */; }; - 240BCA761CD930BE00842222 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 240BCA751CD930BE00842222 /* Result.framework */; }; - 240BCA781CD930C700842222 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 240BCA771CD930C700842222 /* BrightFutures.framework */; }; - 240BCA7A1CD930CD00842222 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 240BCA791CD930CD00842222 /* SwiftyJSON.framework */; }; - 240BCA7B1CD9312C00842222 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 240BCA751CD930BE00842222 /* Result.framework */; }; - 240BCA7C1CD9312D00842222 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 240BCA771CD930C700842222 /* BrightFutures.framework */; }; - 240BCA7D1CD9313000842222 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 240BCA791CD930CD00842222 /* SwiftyJSON.framework */; }; 24E6DF5F1D6830FF0072D4DC /* Spine.swift in Sources */ = {isa = PBXBuildFile; fileRef = D373F7A319B224BB00275AFC /* Spine.swift */; }; 24E6DF601D6830FF0072D4DC /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = D331836B19B2302500936FBB /* Query.swift */; }; 24E6DF611D6830FF0072D4DC /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3452C2E1AD18E6900CD413B /* Operation.swift */; }; @@ -77,15 +71,29 @@ 24E6DF6C1D6830FF0072D4DC /* SerializeOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D35F9D421A53016000E5FF97 /* SerializeOperation.swift */; }; 24E6DF6D1D6830FF0072D4DC /* ValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D35F9D471A532EC600E5FF97 /* ValueFormatter.swift */; }; 24E6DF6E1D6830FF0072D4DC /* KeyFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3B96D611C32B7D300910F83 /* KeyFormatter.swift */; }; - 24E6DF731D6831520072D4DC /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E6DF701D6831520072D4DC /* BrightFutures.framework */; }; - 24E6DF741D6831520072D4DC /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E6DF711D6831520072D4DC /* Result.framework */; }; - 24E6DF751D6831520072D4DC /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E6DF721D6831520072D4DC /* SwiftyJSON.framework */; }; 24EA5DB11D2D39A700F3E867 /* SingleFooWithUnregisteredType.json in Resources */ = {isa = PBXBuildFile; fileRef = 24EA5DB01D2D39A100F3E867 /* SingleFooWithUnregisteredType.json */; }; 24EA5DB21D2D39A800F3E867 /* SingleFooWithUnregisteredType.json in Resources */ = {isa = PBXBuildFile; fileRef = 24EA5DB01D2D39A100F3E867 /* SingleFooWithUnregisteredType.json */; }; - 509BB46A1E3A8F25001FC417 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 509BB4691E3A8F25001FC417 /* Reflection.framework */; }; - 509BB46C1E3A8F2C001FC417 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 509BB46B1E3A8F2C001FC417 /* Reflection.framework */; }; - 509BB46E1E3A8F31001FC417 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 509BB46D1E3A8F31001FC417 /* Reflection.framework */; }; - 509BB4701E3A8F36001FC417 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 509BB46F1E3A8F36001FC417 /* Reflection.framework */; }; + 50F64DA61E3B3D9300419003 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DA41E3B3D9300419003 /* BrightFutures.framework */; }; + 50F64DA71E3B3D9300419003 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DA51E3B3D9300419003 /* SwiftyJSON.framework */; }; + 50F64DA91E3B3D9D00419003 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DA81E3B3D9D00419003 /* Reflection.framework */; }; + 50F64DAA1E3B3DB400419003 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DA41E3B3D9300419003 /* BrightFutures.framework */; }; + 50F64DAB1E3B3DB400419003 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DA51E3B3D9300419003 /* SwiftyJSON.framework */; }; + 50F64DAD1E3B3DB400419003 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DAC1E3B3DB400419003 /* Result.framework */; }; + 50F64DDB1E3B417D00419003 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DD81E3B417D00419003 /* BrightFutures.framework */; }; + 50F64DDC1E3B417D00419003 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DD91E3B417D00419003 /* Reflection.framework */; }; + 50F64DDD1E3B417D00419003 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DDA1E3B417D00419003 /* SwiftyJSON.framework */; }; + 50F64DE11E3B419500419003 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DDE1E3B419500419003 /* BrightFutures.framework */; }; + 50F64DE21E3B419500419003 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DDF1E3B419500419003 /* Result.framework */; }; + 50F64DE31E3B419500419003 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DE01E3B419500419003 /* SwiftyJSON.framework */; }; + 50F64DE71E3B41A100419003 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DE41E3B41A100419003 /* BrightFutures.framework */; }; + 50F64DE91E3B41A100419003 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DE61E3B41A100419003 /* SwiftyJSON.framework */; }; + 50F64DED1E3B41AF00419003 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DEA1E3B41AF00419003 /* BrightFutures.framework */; }; + 50F64DEE1E3B41AF00419003 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DEB1E3B41AF00419003 /* Result.framework */; }; + 50F64DEF1E3B41AF00419003 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DEC1E3B41AF00419003 /* SwiftyJSON.framework */; }; + 50F64DF31E3B41BE00419003 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DF01E3B41BE00419003 /* BrightFutures.framework */; }; + 50F64DF41E3B41BE00419003 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DF11E3B41BE00419003 /* Reflection.framework */; }; + 50F64DF51E3B41BE00419003 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64DF21E3B41BE00419003 /* SwiftyJSON.framework */; }; + 50F64E311E3B4C2300419003 /* Reflection.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50F64E2A1E3B477400419003 /* Reflection.framework */; }; D302A6531DA13BAF00420C48 /* Spine.swift in Sources */ = {isa = PBXBuildFile; fileRef = D373F7A319B224BB00275AFC /* Spine.swift */; }; D302A6541DA13BAF00420C48 /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = D331836B19B2302500936FBB /* Query.swift */; }; D302A6551DA13BAF00420C48 /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3452C2E1AD18E6900CD413B /* Operation.swift */; }; @@ -119,18 +127,9 @@ D302A6711DA13BC700420C48 /* PagedFoos-1.json in Resources */ = {isa = PBXBuildFile; fileRef = D3BE2B1B1AD56C840061167C /* PagedFoos-1.json */; }; D302A6721DA13BC700420C48 /* PagedFoos-2.json in Resources */ = {isa = PBXBuildFile; fileRef = D3BE2B1C1AD56C840061167C /* PagedFoos-2.json */; }; D302A6731DA13BC700420C48 /* Errors.json in Resources */ = {isa = PBXBuildFile; fileRef = D3960DF01A9B5FBC009948B0 /* Errors.json */; }; - D302A6741DA13C1400420C48 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E6DF711D6831520072D4DC /* Result.framework */; }; - D302A6751DA13C1400420C48 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E6DF701D6831520072D4DC /* BrightFutures.framework */; }; - D302A6761DA13C1400420C48 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E6DF721D6831520072D4DC /* SwiftyJSON.framework */; }; - D302A6781DA13CAB00420C48 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D32EA6DC1BCBD5930076CFA5 /* Result.framework */; }; - D302A6791DA13CAB00420C48 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3411E771A4B5C2C00D27F54 /* BrightFutures.framework */; }; - D302A67A1DA13CAB00420C48 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3411E7A1A4B5D2200D27F54 /* SwiftyJSON.framework */; }; D307FBEE1A97756700EE0FAC /* SingleFooIncludingBars.json in Resources */ = {isa = PBXBuildFile; fileRef = D307FBED1A97756700EE0FAC /* SingleFooIncludingBars.json */; }; D312E2F819BB83A8004BB3E0 /* SerializingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D312E2F719BB83A8004BB3E0 /* SerializingTests.swift */; }; D312E30219BB8822004BB3E0 /* Networking.swift in Sources */ = {isa = PBXBuildFile; fileRef = D37FB17E19B9D7F10073A888 /* Networking.swift */; }; - D32EA6DA1BCBD5930076CFA5 /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3411E771A4B5C2C00D27F54 /* BrightFutures.framework */; }; - D32EA6DB1BCBD5930076CFA5 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D3411E7A1A4B5D2200D27F54 /* SwiftyJSON.framework */; }; - D32EA6DD1BCBD5930076CFA5 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D32EA6DC1BCBD5930076CFA5 /* Result.framework */; }; D331836C19B2302500936FBB /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = D331836B19B2302500936FBB /* Query.swift */; }; D341907719D30BA4007B38D6 /* Routing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D341907619D30BA4007B38D6 /* Routing.swift */; }; D341907D19D31176007B38D6 /* Routing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D341907619D30BA4007B38D6 /* Routing.swift */; }; @@ -169,10 +168,6 @@ D39890F51C3D571F005CFB93 /* ResourceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39890F41C3D571F005CFB93 /* ResourceFactory.swift */; }; D39890F71C3D5978005CFB93 /* ResourceFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39890F41C3D571F005CFB93 /* ResourceFactory.swift */; }; D398E1291DA1538E00FBC6FD /* Spine.h in Headers */ = {isa = PBXBuildFile; fileRef = D373F78D19B2249900275AFC /* Spine.h */; settings = {ATTRIBUTES = (Public, ); }; }; - D398E12A1DA153D500FBC6FD /* Spine.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24E6DF481D6830030072D4DC /* Spine.framework */; }; - D398E1321DA1548C00FBC6FD /* Result.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 24E6DF711D6831520072D4DC /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - D398E1331DA1548C00FBC6FD /* BrightFutures.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 24E6DF701D6831520072D4DC /* BrightFutures.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - D398E1341DA1548C00FBC6FD /* SwiftyJSON.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 24E6DF721D6831520072D4DC /* SwiftyJSON.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; D398E14F1DA1554E00FBC6FD /* Spine.swift in Sources */ = {isa = PBXBuildFile; fileRef = D373F7A319B224BB00275AFC /* Spine.swift */; }; D398E1501DA1554E00FBC6FD /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = D331836B19B2302500936FBB /* Query.swift */; }; D398E1511DA1554E00FBC6FD /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3452C2E1AD18E6900CD413B /* Operation.swift */; }; @@ -189,9 +184,6 @@ D398E15C1DA1554E00FBC6FD /* SerializeOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D35F9D421A53016000E5FF97 /* SerializeOperation.swift */; }; D398E15D1DA1554E00FBC6FD /* ValueFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D35F9D471A532EC600E5FF97 /* ValueFormatter.swift */; }; D398E15E1DA1554E00FBC6FD /* KeyFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D3B96D611C32B7D300910F83 /* KeyFormatter.swift */; }; - D398E1631DA1562E00FBC6FD /* BrightFutures.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D398E1601DA1562800FBC6FD /* BrightFutures.framework */; }; - D398E1641DA1562E00FBC6FD /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D398E1611DA1562800FBC6FD /* Result.framework */; }; - D398E1651DA1562E00FBC6FD /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D398E1621DA1562800FBC6FD /* SwiftyJSON.framework */; }; D398E1671DA1567D00FBC6FD /* Spine.h in Headers */ = {isa = PBXBuildFile; fileRef = D373F78D19B2249900275AFC /* Spine.h */; settings = {ATTRIBUTES = (Public, ); }; }; D39929EB1A52F3A0008BF0A9 /* ResourceField.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39929EA1A52F3A0008BF0A9 /* ResourceField.swift */; }; D39CD5381AA0FA8F00049432 /* CallbackHTTPClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = D39CD5371AA0FA8F00049432 /* CallbackHTTPClient.swift */; }; @@ -205,43 +197,35 @@ FC3F73E31D74E26600BF2AAC /* EmptyFoos.json in Resources */ = {isa = PBXBuildFile; fileRef = FC3F73E01D74E10400BF2AAC /* EmptyFoos.json */; }; /* End PBXBuildFile section */ -/* Begin PBXCopyFilesBuildPhase section */ - D398E1301DA1547E00FBC6FD /* CopyFiles */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - D398E1321DA1548C00FBC6FD /* Result.framework in CopyFiles */, - D398E1331DA1548C00FBC6FD /* BrightFutures.framework in CopyFiles */, - D398E1341DA1548C00FBC6FD /* SwiftyJSON.framework in CopyFiles */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - /* Begin PBXFileReference section */ - 240BCA751CD930BE00842222 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/tvOS/Result.framework; sourceTree = ""; }; - 240BCA771CD930C700842222 /* BrightFutures.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BrightFutures.framework; path = Carthage/Build/tvOS/BrightFutures.framework; sourceTree = ""; }; - 240BCA791CD930CD00842222 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/tvOS/SwiftyJSON.framework; sourceTree = ""; }; 2413110C1CD8F40000527E10 /* Spine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Spine.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 241311151CD8F40000527E10 /* Spine-tvOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Spine-tvOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 24E6DF481D6830030072D4DC /* Spine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Spine.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 24E6DF511D6830030072D4DC /* Spine-macOSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Spine-macOSTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 24E6DF701D6831520072D4DC /* BrightFutures.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BrightFutures.framework; path = Carthage/Build/Mac/BrightFutures.framework; sourceTree = ""; }; - 24E6DF711D6831520072D4DC /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/Mac/Result.framework; sourceTree = ""; }; - 24E6DF721D6831520072D4DC /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/Mac/SwiftyJSON.framework; sourceTree = ""; }; 24EA5DB01D2D39A100F3E867 /* SingleFooWithUnregisteredType.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = SingleFooWithUnregisteredType.json; sourceTree = ""; }; - 509BB4691E3A8F25001FC417 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "Reflection/build/Debug-iphoneos/Reflection.framework"; sourceTree = ""; }; - 509BB46B1E3A8F2C001FC417 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "Reflection/build/Debug-iphoneos/Reflection.framework"; sourceTree = ""; }; - 509BB46D1E3A8F31001FC417 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "Reflection/build/Debug-iphoneos/Reflection.framework"; sourceTree = ""; }; - 509BB46F1E3A8F36001FC417 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "Reflection/build/Debug-iphoneos/Reflection.framework"; sourceTree = ""; }; + 50F64DA41E3B3D9300419003 /* BrightFutures.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BrightFutures.framework; path = "../../../Library/Developer/Xcode/DerivedData/Spine-czhllmroobocbnfxbcmkdkdkikyc/Build/Products/Debug-iphonesimulator/BrightFutures.framework"; sourceTree = ""; }; + 50F64DA51E3B3D9300419003 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = "../../../Library/Developer/Xcode/DerivedData/Spine-czhllmroobocbnfxbcmkdkdkikyc/Build/Products/Debug-iphonesimulator/SwiftyJSON.framework"; sourceTree = ""; }; + 50F64DA81E3B3D9D00419003 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "../../../Library/Developer/Xcode/DerivedData/Spine-czhllmroobocbnfxbcmkdkdkikyc/Build/Products/Debug-iphonesimulator/Reflection.framework"; sourceTree = ""; }; + 50F64DAC1E3B3DB400419003 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = "../../../Library/Developer/Xcode/DerivedData/Spine-czhllmroobocbnfxbcmkdkdkikyc/Build/Products/Debug-iphonesimulator/Result.framework"; sourceTree = ""; }; + 50F64DD81E3B417D00419003 /* BrightFutures.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BrightFutures.framework; path = "Carthage/Checkouts/BrightFutures/build/Debug-appletvos/BrightFutures.framework"; sourceTree = ""; }; + 50F64DD91E3B417D00419003 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "Reflection/build/Debug-appletvos/Reflection.framework"; sourceTree = ""; }; + 50F64DDA1E3B417D00419003 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = "Carthage/Checkouts/SwiftyJSON/build/Debug-appletvos/SwiftyJSON.framework"; sourceTree = ""; }; + 50F64DDE1E3B419500419003 /* BrightFutures.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BrightFutures.framework; path = "Carthage/Checkouts/BrightFutures/build/Debug-appletvos/BrightFutures.framework"; sourceTree = ""; }; + 50F64DDF1E3B419500419003 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = "Carthage/Checkouts/Result/build/Debug-appletvos/Result.framework"; sourceTree = ""; }; + 50F64DE01E3B419500419003 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = "Carthage/Checkouts/SwiftyJSON/build/Debug-appletvos/SwiftyJSON.framework"; sourceTree = ""; }; + 50F64DE41E3B41A100419003 /* BrightFutures.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BrightFutures.framework; path = Carthage/Checkouts/BrightFutures/build/Debug/BrightFutures.framework; sourceTree = ""; }; + 50F64DE51E3B41A100419003 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = Reflection/build/Debug/Reflection.framework; sourceTree = ""; }; + 50F64DE61E3B41A100419003 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Checkouts/SwiftyJSON/build/Debug/SwiftyJSON.framework; sourceTree = ""; }; + 50F64DEA1E3B41AF00419003 /* BrightFutures.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BrightFutures.framework; path = Carthage/Checkouts/BrightFutures/build/Debug/BrightFutures.framework; sourceTree = ""; }; + 50F64DEB1E3B41AF00419003 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Checkouts/Result/build/Debug/Result.framework; sourceTree = ""; }; + 50F64DEC1E3B41AF00419003 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Checkouts/SwiftyJSON/build/Debug/SwiftyJSON.framework; sourceTree = ""; }; + 50F64DF01E3B41BE00419003 /* BrightFutures.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BrightFutures.framework; path = "Carthage/Checkouts/BrightFutures/build/Debug-watchos/BrightFutures.framework"; sourceTree = ""; }; + 50F64DF11E3B41BE00419003 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "Reflection/build/Debug-watchos/Reflection.framework"; sourceTree = ""; }; + 50F64DF21E3B41BE00419003 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = "Carthage/Checkouts/SwiftyJSON/build/Debug-watchos/SwiftyJSON.framework"; sourceTree = ""; }; + 50F64E2A1E3B477400419003 /* Reflection.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reflection.framework; path = "../../../Library/Developer/Xcode/DerivedData/Spine-czhllmroobocbnfxbcmkdkdkikyc/Build/Products/Debug/Reflection.framework"; sourceTree = ""; }; D307FBED1A97756700EE0FAC /* SingleFooIncludingBars.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = SingleFooIncludingBars.json; sourceTree = ""; }; D312E2F719BB83A8004BB3E0 /* SerializingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SerializingTests.swift; sourceTree = ""; }; - D32EA6DC1BCBD5930076CFA5 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; D331836B19B2302500936FBB /* Query.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Query.swift; sourceTree = ""; }; - D3411E771A4B5C2C00D27F54 /* BrightFutures.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BrightFutures.framework; path = Carthage/Build/iOS/BrightFutures.framework; sourceTree = ""; }; - D3411E7A1A4B5D2200D27F54 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/iOS/SwiftyJSON.framework; sourceTree = ""; }; D341907619D30BA4007B38D6 /* Routing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Routing.swift; sourceTree = ""; }; D3452C2E1AD18E6900CD413B /* Operation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Operation.swift; sourceTree = ""; }; D3452C301AD19B0900CD413B /* Logging.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = ""; }; @@ -270,9 +254,6 @@ D3960DF01A9B5FBC009948B0 /* Errors.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Errors.json; sourceTree = ""; }; D39890F41C3D571F005CFB93 /* ResourceFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResourceFactory.swift; sourceTree = ""; }; D398E1471DA1554300FBC6FD /* Spine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Spine.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - D398E1601DA1562800FBC6FD /* BrightFutures.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BrightFutures.framework; path = Carthage/Build/watchOS/BrightFutures.framework; sourceTree = ""; }; - D398E1611DA1562800FBC6FD /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/watchOS/Result.framework; sourceTree = ""; }; - D398E1621DA1562800FBC6FD /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/watchOS/SwiftyJSON.framework; sourceTree = ""; }; D39929EA1A52F3A0008BF0A9 /* ResourceField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResourceField.swift; sourceTree = ""; }; D39CD5371AA0FA8F00049432 /* CallbackHTTPClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CallbackHTTPClient.swift; path = SpineTests/CallbackHTTPClient.swift; sourceTree = SOURCE_ROOT; }; D3B96D611C32B7D300910F83 /* KeyFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyFormatter.swift; sourceTree = ""; }; @@ -287,10 +268,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 509BB46C1E3A8F2C001FC417 /* Reflection.framework in Frameworks */, - 240BCA761CD930BE00842222 /* Result.framework in Frameworks */, - 240BCA781CD930C700842222 /* BrightFutures.framework in Frameworks */, - 240BCA7A1CD930CD00842222 /* SwiftyJSON.framework in Frameworks */, + 50F64DDB1E3B417D00419003 /* BrightFutures.framework in Frameworks */, + 50F64DDC1E3B417D00419003 /* Reflection.framework in Frameworks */, + 50F64DDD1E3B417D00419003 /* SwiftyJSON.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -298,9 +278,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 240BCA7B1CD9312C00842222 /* Result.framework in Frameworks */, - 240BCA7C1CD9312D00842222 /* BrightFutures.framework in Frameworks */, - 240BCA7D1CD9313000842222 /* SwiftyJSON.framework in Frameworks */, + 50F64DE11E3B419500419003 /* BrightFutures.framework in Frameworks */, + 50F64DE21E3B419500419003 /* Result.framework in Frameworks */, + 50F64DE31E3B419500419003 /* SwiftyJSON.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -308,10 +288,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 509BB46E1E3A8F31001FC417 /* Reflection.framework in Frameworks */, - 24E6DF731D6831520072D4DC /* BrightFutures.framework in Frameworks */, - 24E6DF741D6831520072D4DC /* Result.framework in Frameworks */, - 24E6DF751D6831520072D4DC /* SwiftyJSON.framework in Frameworks */, + 50F64E311E3B4C2300419003 /* Reflection.framework in Frameworks */, + 50F64DE71E3B41A100419003 /* BrightFutures.framework in Frameworks */, + 50F64DE91E3B41A100419003 /* SwiftyJSON.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -319,10 +298,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D302A6741DA13C1400420C48 /* Result.framework in Frameworks */, - D302A6751DA13C1400420C48 /* BrightFutures.framework in Frameworks */, - D398E12A1DA153D500FBC6FD /* Spine.framework in Frameworks */, - D302A6761DA13C1400420C48 /* SwiftyJSON.framework in Frameworks */, + 50F64DED1E3B41AF00419003 /* BrightFutures.framework in Frameworks */, + 50F64DEE1E3B41AF00419003 /* Result.framework in Frameworks */, + 50F64DEF1E3B41AF00419003 /* SwiftyJSON.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -330,10 +308,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 509BB46A1E3A8F25001FC417 /* Reflection.framework in Frameworks */, - D32EA6DD1BCBD5930076CFA5 /* Result.framework in Frameworks */, - D32EA6DA1BCBD5930076CFA5 /* BrightFutures.framework in Frameworks */, - D32EA6DB1BCBD5930076CFA5 /* SwiftyJSON.framework in Frameworks */, + 50F64DA91E3B3D9D00419003 /* Reflection.framework in Frameworks */, + 50F64DA61E3B3D9300419003 /* BrightFutures.framework in Frameworks */, + 50F64DA71E3B3D9300419003 /* SwiftyJSON.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -341,9 +318,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - D302A6781DA13CAB00420C48 /* Result.framework in Frameworks */, - D302A6791DA13CAB00420C48 /* BrightFutures.framework in Frameworks */, - D302A67A1DA13CAB00420C48 /* SwiftyJSON.framework in Frameworks */, + 50F64DAD1E3B3DB400419003 /* Result.framework in Frameworks */, + 50F64DAA1E3B3DB400419003 /* BrightFutures.framework in Frameworks */, + 50F64DAB1E3B3DB400419003 /* SwiftyJSON.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -351,10 +328,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 509BB4701E3A8F36001FC417 /* Reflection.framework in Frameworks */, - D398E1631DA1562E00FBC6FD /* BrightFutures.framework in Frameworks */, - D398E1641DA1562E00FBC6FD /* Result.framework in Frameworks */, - D398E1651DA1562E00FBC6FD /* SwiftyJSON.framework in Frameworks */, + 50F64DF31E3B41BE00419003 /* BrightFutures.framework in Frameworks */, + 50F64DF41E3B41BE00419003 /* Reflection.framework in Frameworks */, + 50F64DF51E3B41BE00419003 /* SwiftyJSON.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -364,9 +340,11 @@ 240BCA741CD930A000842222 /* tvOS */ = { isa = PBXGroup; children = ( - 240BCA751CD930BE00842222 /* Result.framework */, - 240BCA771CD930C700842222 /* BrightFutures.framework */, - 240BCA791CD930CD00842222 /* SwiftyJSON.framework */, + 50F64DDF1E3B419500419003 /* Result.framework */, + 50F64DE01E3B419500419003 /* SwiftyJSON.framework */, + 50F64DD81E3B417D00419003 /* BrightFutures.framework */, + 50F64DD91E3B417D00419003 /* Reflection.framework */, + 50F64DDA1E3B417D00419003 /* SwiftyJSON.framework */, ); name = tvOS; sourceTree = ""; @@ -374,10 +352,14 @@ 245B5DD41CD92E3200E44FBE /* Frameworks */ = { isa = PBXGroup; children = ( - 509BB46F1E3A8F36001FC417 /* Reflection.framework */, - 509BB46D1E3A8F31001FC417 /* Reflection.framework */, - 509BB46B1E3A8F2C001FC417 /* Reflection.framework */, - 509BB4691E3A8F25001FC417 /* Reflection.framework */, + 50F64E2A1E3B477400419003 /* Reflection.framework */, + 50F64DEA1E3B41AF00419003 /* BrightFutures.framework */, + 50F64DEB1E3B41AF00419003 /* Result.framework */, + 50F64DEC1E3B41AF00419003 /* SwiftyJSON.framework */, + 50F64DE41E3B41A100419003 /* BrightFutures.framework */, + 50F64DE51E3B41A100419003 /* Reflection.framework */, + 50F64DE61E3B41A100419003 /* SwiftyJSON.framework */, + 50F64DDE1E3B419500419003 /* BrightFutures.framework */, D398E15F1DA1561400FBC6FD /* watchOS */, 24E6DF6F1D6831280072D4DC /* macOS */, 245B5DD51CD92E3900E44FBE /* iOS */, @@ -389,9 +371,10 @@ 245B5DD51CD92E3900E44FBE /* iOS */ = { isa = PBXGroup; children = ( - D32EA6DC1BCBD5930076CFA5 /* Result.framework */, - D3411E771A4B5C2C00D27F54 /* BrightFutures.framework */, - D3411E7A1A4B5D2200D27F54 /* SwiftyJSON.framework */, + 50F64DAC1E3B3DB400419003 /* Result.framework */, + 50F64DA81E3B3D9D00419003 /* Reflection.framework */, + 50F64DA41E3B3D9300419003 /* BrightFutures.framework */, + 50F64DA51E3B3D9300419003 /* SwiftyJSON.framework */, ); name = iOS; sourceTree = ""; @@ -399,9 +382,6 @@ 24E6DF6F1D6831280072D4DC /* macOS */ = { isa = PBXGroup; children = ( - 24E6DF711D6831520072D4DC /* Result.framework */, - 24E6DF701D6831520072D4DC /* BrightFutures.framework */, - 24E6DF721D6831520072D4DC /* SwiftyJSON.framework */, ); name = macOS; sourceTree = ""; @@ -523,9 +503,9 @@ D398E15F1DA1561400FBC6FD /* watchOS */ = { isa = PBXGroup; children = ( - D398E1601DA1562800FBC6FD /* BrightFutures.framework */, - D398E1611DA1562800FBC6FD /* Result.framework */, - D398E1621DA1562800FBC6FD /* SwiftyJSON.framework */, + 50F64DF01E3B41BE00419003 /* BrightFutures.framework */, + 50F64DF11E3B41BE00419003 /* Reflection.framework */, + 50F64DF21E3B41BE00419003 /* SwiftyJSON.framework */, ); name = watchOS; sourceTree = ""; @@ -601,7 +581,6 @@ 241311111CD8F40000527E10 /* Sources */, 241311121CD8F40000527E10 /* Frameworks */, 241311131CD8F40000527E10 /* Resources */, - 240BCA7E1CD9314C00842222 /* ShellScript */, ); buildRules = ( ); @@ -637,7 +616,6 @@ 24E6DF4D1D6830030072D4DC /* Sources */, 24E6DF4E1D6830030072D4DC /* Frameworks */, 24E6DF4F1D6830030072D4DC /* Resources */, - D398E1301DA1547E00FBC6FD /* CopyFiles */, ); buildRules = ( ); @@ -673,7 +651,6 @@ D373F78F19B2249900275AFC /* Sources */, D373F79019B2249900275AFC /* Frameworks */, D373F79119B2249900275AFC /* Resources */, - D35047881A94F784002FDF57 /* ShellScript */, ); buildRules = ( ); @@ -840,41 +817,6 @@ }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 240BCA7E1CD9314C00842222 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/tvOS/BrightFutures.framework", - "$(SRCROOT)/Carthage/Build/tvOS/SwiftyJSON.framework", - "$(SRCROOT)/Carthage/Build/tvOS/Result.framework", - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks"; - }; - D35047881A94F784002FDF57 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/BrightFutures.framework", - "$(SRCROOT)/Carthage/Build/iOS/SwiftyJSON.framework", - "$(SRCROOT)/Carthage/Build/iOS/Result.framework", - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/usr/local/bin/carthage copy-frameworks"; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 241311071CD8F40000527E10 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -1079,6 +1021,9 @@ "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/tvOS", "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", + "$(PROJECT_DIR)/Carthage/Checkouts/BrightFutures/build/Debug-appletvos", + "$(PROJECT_DIR)/Reflection/build/Debug-appletvos", + "$(PROJECT_DIR)/Carthage/Checkouts/SwiftyJSON/build/Debug-appletvos", ); INFOPLIST_FILE = Spine/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1103,6 +1048,9 @@ "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/tvOS", "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", + "$(PROJECT_DIR)/Carthage/Checkouts/BrightFutures/build/Debug-appletvos", + "$(PROJECT_DIR)/Reflection/build/Debug-appletvos", + "$(PROJECT_DIR)/Carthage/Checkouts/SwiftyJSON/build/Debug-appletvos", ); INFOPLIST_FILE = Spine/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1123,6 +1071,9 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/tvOS", + "$(PROJECT_DIR)/Carthage/Checkouts/BrightFutures/build/Debug-appletvos", + "$(PROJECT_DIR)/Carthage/Checkouts/Result/build/Debug-appletvos", + "$(PROJECT_DIR)/Carthage/Checkouts/SwiftyJSON/build/Debug-appletvos", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SpineTests/Info.plist; @@ -1143,6 +1094,9 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/tvOS", + "$(PROJECT_DIR)/Carthage/Checkouts/BrightFutures/build/Debug-appletvos", + "$(PROJECT_DIR)/Carthage/Checkouts/Result/build/Debug-appletvos", + "$(PROJECT_DIR)/Carthage/Checkouts/SwiftyJSON/build/Debug-appletvos", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SpineTests/Info.plist; @@ -1169,6 +1123,9 @@ "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/Mac", "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", + "$(PROJECT_DIR)/Carthage/Checkouts/BrightFutures/build/Debug", + "$(PROJECT_DIR)/Reflection/build/Debug", + "$(PROJECT_DIR)/Carthage/Checkouts/SwiftyJSON/build/Debug", ); FRAMEWORK_VERSION = A; GCC_NO_COMMON_BLOCKS = YES; @@ -1199,6 +1156,9 @@ "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/Mac", "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", + "$(PROJECT_DIR)/Carthage/Checkouts/BrightFutures/build/Debug", + "$(PROJECT_DIR)/Reflection/build/Debug", + "$(PROJECT_DIR)/Carthage/Checkouts/SwiftyJSON/build/Debug", ); FRAMEWORK_VERSION = A; GCC_NO_COMMON_BLOCKS = YES; @@ -1223,6 +1183,9 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/Mac", + "$(PROJECT_DIR)/Carthage/Checkouts/BrightFutures/build/Debug", + "$(PROJECT_DIR)/Carthage/Checkouts/Result/build/Debug", + "$(PROJECT_DIR)/Carthage/Checkouts/SwiftyJSON/build/Debug", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SpineTests/Info.plist; @@ -1245,6 +1208,9 @@ FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/Mac", + "$(PROJECT_DIR)/Carthage/Checkouts/BrightFutures/build/Debug", + "$(PROJECT_DIR)/Carthage/Checkouts/Result/build/Debug", + "$(PROJECT_DIR)/Carthage/Checkouts/SwiftyJSON/build/Debug", ); GCC_NO_COMMON_BLOCKS = YES; INFOPLIST_FILE = SpineTests/Info.plist; @@ -1453,6 +1419,9 @@ "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/watchOS", "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", + "$(PROJECT_DIR)/Carthage/Checkouts/BrightFutures/build/Debug-watchos", + "$(PROJECT_DIR)/Reflection/build/Debug-watchos", + "$(PROJECT_DIR)/Carthage/Checkouts/SwiftyJSON/build/Debug-watchos", ); INFOPLIST_FILE = "$(SRCROOT)/Spine/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; @@ -1486,6 +1455,9 @@ "$(inherited)", "$(PROJECT_DIR)/Carthage/Build/watchOS", "$(PROJECT_DIR)/Reflection/build/Debug-iphoneos", + "$(PROJECT_DIR)/Carthage/Checkouts/BrightFutures/build/Debug-watchos", + "$(PROJECT_DIR)/Reflection/build/Debug-watchos", + "$(PROJECT_DIR)/Carthage/Checkouts/SwiftyJSON/build/Debug-watchos", ); INFOPLIST_FILE = "$(SRCROOT)/Spine/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; diff --git a/Spine/Resource.swift b/Spine/Resource.swift index be8a4bfa..f0eb6051 100644 --- a/Spine/Resource.swift +++ b/Spine/Resource.swift @@ -7,6 +7,7 @@ // import Foundation +import Reflection public typealias ResourceType = String diff --git a/SpineTests/Fixtures.swift b/SpineTests/Fixtures.swift index 84c5da76..480eb1f4 100644 --- a/SpineTests/Fixtures.swift +++ b/SpineTests/Fixtures.swift @@ -12,7 +12,7 @@ import SwiftyJSON class Foo: NSObject, Resource { /// Raw relationship data keyed by relationship name. - public var relationships: [String : RelationshipData] + public var relationships: [String : RelationshipData] = [:] /// The metadata for this resource. public var meta: [String : Any]? @@ -23,7 +23,7 @@ class Foo: NSObject, Resource { var id: String? var url: URL? - var isLoaded: Bool + var isLoaded: Bool = false var stringAttribute: String? var integerAttribute: NSNumber? @@ -63,7 +63,7 @@ class Foo: NSObject, Resource { class Bar: NSObject, Resource { /// Raw relationship data keyed by relationship name. - public var relationships: [String : RelationshipData] + public var relationships: [String : RelationshipData] = [:] /// The metadata for this resource. public var meta: [String : Any]? @@ -74,7 +74,7 @@ class Bar: NSObject, Resource { var id: String? var url: URL? - var isLoaded: Bool + var isLoaded: Bool = false var barStringAttribute: String? var barIntegerAttribute: NSNumber? From 705324951ac99546705af6cb4d9a1ad574416cb8 Mon Sep 17 00:00:00 2001 From: Max Bothe Date: Fri, 27 Jan 2017 13:09:14 +0100 Subject: [PATCH 14/14] Add ResoureData struct. Fix tests (iOS). --- Spine/Operation.swift | 9 +- Spine/Resource.swift | 105 +++++++++++++++++++---- Spine/ResourceCollection.swift | 9 +- Spine/ResourceField.swift | 55 +++--------- Spine/Serializing.swift | 68 +++++++-------- SpineTests/Fixtures.swift | 20 +---- SpineTests/ResourceCollectionTests.swift | 3 +- SpineTests/ResourceTests.swift | 39 +++++---- SpineTests/SerializingTests.swift | 10 +-- SpineTests/SpineTests.swift | 18 ++-- 10 files changed, 179 insertions(+), 157 deletions(-) diff --git a/Spine/Operation.swift b/Spine/Operation.swift index 03c0f3dc..389401aa 100644 --- a/Spine/Operation.swift +++ b/Spine/Operation.swift @@ -411,7 +411,7 @@ class RelationshipReplaceOperation: RelationshipOp override func execute() { let url = router.urlForRelationship(relationship, ofResource: resource) - let payload: Data = try! relationship.serializeLinkData(for: resource) + let payload: Data = try! relationship.serializeLinkData(for: resource, with: serializer) // switch relationship { // case is ToOneRelationship: @@ -449,9 +449,9 @@ class RelationshipMutateOperation: RelationshipOpe } override func execute() { - let resourceCollection = resource.value(forField: relationship.name) as! LinkedResourceCollection + let resourceCollection = resource.value(forField: relationship.name) as! LinkedResourceCollection let httpMethod: String - let relatedResources: [T] + let relatedResources: [U.Linked] switch mutation { case .add: @@ -469,8 +469,7 @@ class RelationshipMutateOperation: RelationshipOpe } let url = router.urlForRelationship(relationship, ofResource: resource) -// let payload = try! serializer.serializeLinkData(relatedResources) - let payload = try! relationship.serializeLinkData(for: resource) + let payload = try! serializer.serializeLinkData(relatedResources) Spine.logInfo(.spine, "Mutating relationship \(relationship) using URL: \(url)") networkClient.request(method: httpMethod, url: url, payload: payload, callback: handleNetworkResponse) } diff --git a/Spine/Resource.swift b/Spine/Resource.swift index f0eb6051..38e61aad 100644 --- a/Spine/Resource.swift +++ b/Spine/Resource.swift @@ -130,6 +130,9 @@ public protocol Resource: class, NSObjectProtocol { // NSCoding, /// Returns the field named `name`, or nil if no such field exists. static func field(named name: String) -> Field? + // XXX: Combines id url isLoaded ... + var resourceData: ResourceData { get set } + /// XXX: New stuff static func includeKeys(_ keys: [String], with formatter: KeyFormatter) -> [String] @@ -141,19 +144,74 @@ extension Resource { // return [] // } + public var id: String? { + get { + return self.resourceData.id + } + set { + self.resourceData.id = newValue + } + } + + var url: URL? { + get { + return self.resourceData.url + } + set { + self.resourceData.url = newValue + } + } + var isLoaded: Bool { - // XXX ahh - return false + get { + return self.resourceData.isLoaded + } + set { + self.resourceData.isLoaded = newValue + } } var relationships: [String: RelationshipData] { - // XXX ahh - return [:] + get { + return self.resourceData.relationships + } + set { + self.resourceData.relationships = newValue + } } var meta: [String: Any]? { - // XXX ahh - return nil + get { + return self.resourceData.meta + } + set { + self.resourceData.meta = newValue + } + } + + /// Returns the value for the field named `field`. + func value(forField field: String) -> Any? { + do { + return try get(field, from: self) + } catch { + // XXX: throw error + fatalError("Can't get value for field '\(field)'") + } + } + + /// Sets the value for the field named `field` to `value`. + func setValue(_ value: Any?, forField field: String) { + unowned var unownedSelf = self + do { + if let value = value { + try set(value, key: field, for: &unownedSelf) + } else { + try set(NSNull(), key: field, for: &unownedSelf) + } + } catch { + // XXX: throw error + fatalError("Can't set value '\(value)' for field '\(field)'") + } } // public init() { @@ -224,17 +282,17 @@ extension Resource { } } -extension Resource where Self: NSObject { - /// Returns the value for the field named `field`. - func value(forField field: String) -> Any? { - return value(forKey: field) as AnyObject? - } - - /// Sets the value for the field named `field` to `value`. - func setValue(_ value: Any?, forField field: String) { - setValue(value, forKey: field) - } -} +//extension Resource where Self: NSObject { +// /// Returns the value for the field named `field`. +// func value(forField field: String) -> Any? { +// return value(forKey: field) as AnyObject? +// } +// +// /// Sets the value for the field named `field` to `value`. +// func setValue(_ value: Any?, forField field: String) { +// setValue(value, forKey: field) +// } +//} extension Resource { // var description: String { @@ -255,3 +313,16 @@ extension Resource { public func == (left: T, right: T) -> Bool { return (left.id == right.id) && (left.resourceType == right.resourceType) } + +public struct ResourceData { + var id: String? + var url: URL? + var isLoaded: Bool + var meta: [String : Any]? + var relationships: [String : RelationshipData] + + public init() { + self.isLoaded = false + self.relationships = [:] + } +} diff --git a/Spine/ResourceCollection.swift b/Spine/ResourceCollection.swift index ac700008..f41d2b41 100644 --- a/Spine/ResourceCollection.swift +++ b/Spine/ResourceCollection.swift @@ -76,13 +76,8 @@ public class ResourceCollection: NSObject, NSCoding { public var count: Int { return resources.count } - - /// Returns a resource identified by the given type and id, - /// or nil if no resource was found. - public func resourceWithType(_ type: ResourceType, id: String) -> T? { - return resources.filter { $0.id == id && $0.resourceType == type }.first - } - + + // MARK: Mutators /// Append `resource` to the collection. diff --git a/Spine/ResourceField.swift b/Spine/ResourceField.swift index 9698ca59..9a8f8280 100644 --- a/Spine/ResourceField.swift +++ b/Spine/ResourceField.swift @@ -164,7 +164,7 @@ public struct PlainAttribute : Attribute { public var serializedName: String public var isReadOnly: Bool = false - init(_ name: String) { + public init(_ name: String) { self.name = name self.serializedName = name } @@ -175,7 +175,7 @@ public struct BooleanAttribute : Attribute { public var serializedName: String public var isReadOnly: Bool = false - init(_ name: String) { + public init(_ name: String) { self.name = name self.serializedName = name } @@ -187,7 +187,7 @@ public struct URLAttribute : Attribute { public var isReadOnly: Bool = false public let baseURL: URL? - init(_ name: String, for url: URL? = nil) { + public init(_ name: String, for url: URL? = nil) { self.name = name self.serializedName = name self.baseURL = url @@ -200,7 +200,7 @@ public struct DateAttribute : Attribute { public var isReadOnly: Bool = false public let format: String - init(_ name: String, format: String = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ") { + public init(_ name: String, format: String = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ") { self.name = name self.serializedName = name self.format = format @@ -292,7 +292,7 @@ public protocol Relationship : Field { // XXX: create protocol that combines Resource and LinkedResourceCollection // associatedtype ReturnValue - func serializeLinkData(for resource: Resource) throws -> Data + func serializeLinkData(for resource: Resource, with serializer: Serializer) throws -> Data } @@ -343,7 +343,7 @@ public struct ToOneRelationship : Relationship { public var serializedName: String public var isReadOnly: Bool = false - init(_ name: String, to linkedType: T.Type) { + public init(_ name: String, to linkedType: T.Type) { self.name = name self.serializedName = name } @@ -397,7 +397,7 @@ public struct ToOneRelationship : Relationship { var linkedResource: T? = nil if let linkData = serializedData["relationships"][key].dictionary { - assert(linkData["data"]?["type"].string == Linked.resourceType) + // XXX: assert(linkData["data"]?["type"].string == Linked.resourceType) if let id = linkData["data"]?["id"].string { linkedResource = factory.dispense(Linked.self, id: id, pool: &pool) @@ -411,28 +411,15 @@ public struct ToOneRelationship : Relationship { } if let linkedResource = linkedResource { - if linkedResource.value(forField: self.name) == nil || (linkedResource.value(forField: self.name) as? Resource)?.isLoaded == false { - linkedResource.setValue(linkedResource, forField: self.name) + if resource.value(forField: self.name) == nil || (resource.value(forField: self.name) as? Resource)?.isLoaded == false { + resource.setValue(linkedResource, forField: self.name) } } } - public func serializeLinkData(for resource: Resource) throws -> Data { + public func serializeLinkData(for resource: Resource, with serializer: Serializer) throws -> Data { let relatedResource = resource.value(forField: self.name) as? Linked - let payloadData: Any - - if let related = relatedResource { - assert(related.id != nil, "Attempt to convert resource without id to linkage. Only resources with ids can be converted to linkage.") - payloadData = ["type": related.resourceType, "id": related.id!] - } else { - payloadData = NSNull() - } - - do { - return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) - } catch let error as NSError { - throw SerializerError.jsonSerializationError(error) - } + return try serializer.serializeLinkData(relatedResource) } public func updateOperations(for resource: T, wihtSpine spine: Spine) -> [RelationshipOperation] { @@ -448,7 +435,7 @@ public struct ToManyRelationship : Relationship { public var serializedName: String public var isReadOnly: Bool = false - init(_ name: String, to linkedType: T.Type) { + public init(_ name: String, to linkedType: T.Type) { self.name = name self.serializedName = name } @@ -539,23 +526,9 @@ public struct ToManyRelationship : Relationship { } } - public func serializeLinkData(for resource: Resource) throws -> Data { + public func serializeLinkData(for resource: Resource, with serializer: Serializer) throws -> Data { let relatedResources = (resource.value(forField: self.name) as? ResourceCollection)?.resources ?? [] - let payloadData: Any - - if relatedResources.isEmpty { - payloadData = [] - } else { - payloadData = relatedResources.map { r in - return ["type": r.resourceType, "id": r.id!] - } - } - - do { - return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) - } catch let error as NSError { - throw SerializerError.jsonSerializationError(error) - } + return try serializer.serializeLinkData(relatedResources) } public func updateOperations(for resource: T, wihtSpine spine: Spine) -> [RelationshipOperation] { diff --git a/Spine/Serializing.swift b/Spine/Serializing.swift index 0c9e8921..d5a2a430 100644 --- a/Spine/Serializing.swift +++ b/Spine/Serializing.swift @@ -95,23 +95,23 @@ public class Serializer { /// - throws: SerializerError that can occur in the serialization. /// /// - returns: Serialized data. -// public func serializeLinkData(_ resource: Resource?) throws -> Data { -// let payloadData: Any -// -// if let resource = resource { -// assert(resource.id != nil, "Attempt to convert resource without id to linkage. Only resources with ids can be converted to linkage.") -// payloadData = ["type": resource.resourceType, "id": resource.id!] -// } else { -// payloadData = NSNull() -// } -// -// do { -// return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) -// } catch let error as NSError { -// throw SerializerError.jsonSerializationError(error) -// } -// } - + public func serializeLinkData(_ resource: T?) throws -> Data { + let payloadData: Any + + if let resource = resource { + assert(resource.id != nil, "Attempt to convert resource without id to linkage. Only resources with ids can be converted to linkage.") + payloadData = ["type": resource.resourceType, "id": resource.id!] + } else { + payloadData = NSNull() + } + + do { + return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) + } catch let error as NSError { + throw SerializerError.jsonSerializationError(error) + } + } + /// Converts the given resources to link data, and serializes it into NSData. /// ```json /// { @@ -127,23 +127,23 @@ public class Serializer { /// - throws: SerializerError that can occur in the serialization. /// /// - returns: Serialized data. -// public func serializeLinkData(_ resources: [Resource]) throws -> Data { -// let payloadData: Any -// -// if resources.isEmpty { -// payloadData = [] -// } else { -// payloadData = resources.map { resource in -// return ["type": resource.resourceType, "id": resource.id!] -// } -// } -// -// do { -// return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) -// } catch let error as NSError { -// throw SerializerError.jsonSerializationError(error) -// } -// } + public func serializeLinkData(_ resources: [T]) throws -> Data { + let payloadData: Any + + if resources.isEmpty { + payloadData = [] + } else { + payloadData = resources.map { resource in + return ["type": resource.resourceType, "id": resource.id!] + } + } + + do { + return try JSONSerialization.data(withJSONObject: ["data": payloadData], options: JSONSerialization.WritingOptions(rawValue: 0)) + } catch let error as NSError { + throw SerializerError.jsonSerializationError(error) + } + } /// Registers a resource class. /// diff --git a/SpineTests/Fixtures.swift b/SpineTests/Fixtures.swift index 480eb1f4..80e63977 100644 --- a/SpineTests/Fixtures.swift +++ b/SpineTests/Fixtures.swift @@ -11,20 +11,12 @@ import XCTest import SwiftyJSON class Foo: NSObject, Resource { - /// Raw relationship data keyed by relationship name. - public var relationships: [String : RelationshipData] = [:] - - /// The metadata for this resource. - public var meta: [String : Any]? + var resourceData = ResourceData() public override required init() { } - var id: String? - var url: URL? - var isLoaded: Bool = false - var stringAttribute: String? var integerAttribute: NSNumber? var floatAttribute: NSNumber? @@ -62,20 +54,12 @@ class Foo: NSObject, Resource { } class Bar: NSObject, Resource { - /// Raw relationship data keyed by relationship name. - public var relationships: [String : RelationshipData] = [:] - - /// The metadata for this resource. - public var meta: [String : Any]? + var resourceData = ResourceData() public override required init() { } - var id: String? - var url: URL? - var isLoaded: Bool = false - var barStringAttribute: String? var barIntegerAttribute: NSNumber? diff --git a/SpineTests/ResourceCollectionTests.swift b/SpineTests/ResourceCollectionTests.swift index ceceaedb..514ccafd 100644 --- a/SpineTests/ResourceCollectionTests.swift +++ b/SpineTests/ResourceCollectionTests.swift @@ -33,8 +33,7 @@ class ResourceCollectionTests: XCTestCase { let resources = [Foo(id: "5"), Foo(id: "6")] // 2nd was Bar let collection = ResourceCollection(resources: resources) - XCTAssert(collection.resourceWithType("foos", id: "5")! === resources[0], "Expected resource to be equal.") - XCTAssert(collection.resourceWithType("bars", id: "6")! === resources[1], "Expected resource to be equal.") + XCTAssert(collection[0] === resources[0], "Expected resource to be equal.") } func testCount() { diff --git a/SpineTests/ResourceTests.swift b/SpineTests/ResourceTests.swift index 383cc272..9ba0dded 100644 --- a/SpineTests/ResourceTests.swift +++ b/SpineTests/ResourceTests.swift @@ -53,23 +53,24 @@ class ResourceTests: XCTestCase { foo.setValue("newStringValue", forField: "stringAttribute") } - - func testEncoding() { - foo.url = URL(string: "http://example.com/api/foos/1") - foo.isLoaded = true - - let encodedData = NSKeyedArchiver.archivedData(withRootObject: foo) - let decodedFoo: AnyObject? = NSKeyedUnarchiver.unarchiveObject(with: encodedData) as AnyObject? - - XCTAssertNotNil(decodedFoo, "Expected decoded object to be not nil") - XCTAssert(decodedFoo is Foo, "Expected decoded object to be of type 'Foo'") - - if let decodedFoo = decodedFoo as? Foo { - XCTAssertEqual(decodedFoo.id!, foo.id!, "Expected id to be equal") - XCTAssertEqual(decodedFoo.url!, foo.url!, "Expected URL to be equal") - XCTAssertEqual(decodedFoo.isLoaded, foo.isLoaded, "Expected isLoaded to be equal") - } else { - XCTFail("Fail") - } - } + + // XXX remove: dont suppert NSCoding +// func testEncoding() { +// foo.url = URL(string: "http://example.com/api/foos/1") +// foo.isLoaded = true +// +// let encodedData = NSKeyedArchiver.archivedData(withRootObject: foo) +// let decodedFoo: AnyObject? = NSKeyedUnarchiver.unarchiveObject(with: encodedData) as AnyObject? +// +// XCTAssertNotNil(decodedFoo, "Expected decoded object to be not nil") +// XCTAssert(decodedFoo is Foo, "Expected decoded object to be of type 'Foo'") +// +// if let decodedFoo = decodedFoo as? Foo { +// XCTAssertEqual(decodedFoo.id!, foo.id!, "Expected id to be equal") +// XCTAssertEqual(decodedFoo.url!, foo.url!, "Expected URL to be equal") +// XCTAssertEqual(decodedFoo.isLoaded, foo.isLoaded, "Expected isLoaded to be equal") +// } else { +// XCTFail("Fail") +// } +// } } diff --git a/SpineTests/SerializingTests.swift b/SpineTests/SerializingTests.swift index a2b795c7..7cf0a538 100644 --- a/SpineTests/SerializingTests.swift +++ b/SpineTests/SerializingTests.swift @@ -172,11 +172,11 @@ class DeserializingTests: SerializerTests { // To many link XCTAssertNotNil(foo.toManyAttribute, "Deserialized linked resources should not be nil.") - if let barCollection = foo.toManyAttribute { - for bar in barCollection { - XCTAssert(bar is Bar, "Expected relationship resource to be of class 'Bar'.") - } - } +// if let barCollection = foo.toManyAttribute { +// for bar in barCollection { +// XCTAssert(bar is Bar, "Expected relationship resource to be of class 'Bar'.") +// } +// } } } catch let error as NSError { XCTFail("Deserialisation failed with error: \(error).") diff --git a/SpineTests/SpineTests.swift b/SpineTests/SpineTests.swift index 83ebabe9..e50e808b 100644 --- a/SpineTests/SpineTests.swift +++ b/SpineTests/SpineTests.swift @@ -43,9 +43,9 @@ class FindAllTests: SpineTests { expectation.fulfill() for (index, resource) in fooCollection.enumerated() { XCTAssertEqual(fooCollection.count, 2, "Deserialized resources count not equal.") - XCTAssert(resource is Foo, "Deserialized resource should be of class 'Foo'.") - let foo = resource as! Foo - assertFooResource(foo, isEqualToJSON: fixture.json["data"][index]) +// XCTAssert(resource is Foo, "Deserialized resource should be of class 'Foo'.") +// let foo = resource as! Foo + assertFooResource(resource, isEqualToJSON: fixture.json["data"][index]) } }.onFailure { error in expectation.fulfill() @@ -100,9 +100,9 @@ class FindByIDTests: SpineTests { expectation.fulfill() for (index, resource) in fooCollection.enumerated() { XCTAssertEqual(fooCollection.count, 2, "Expected resource count to be 2.") - XCTAssert(resource is Foo, "Expected resource to be of class 'Foo'.") - let foo = resource as! Foo - assertFooResource(foo, isEqualToJSON: fixture.json["data"][index]) +// XCTAssert(resource is Foo, "Expected resource to be of class 'Foo'.") +// let foo = resource as! Foo + assertFooResource(resource, isEqualToJSON: fixture.json["data"][index]) } }.onFailure { error in expectation.fulfill() @@ -206,9 +206,9 @@ class FindByQueryTests: SpineTests { expectation.fulfill() for (index, resource) in fooCollection.enumerated() { XCTAssertEqual(fooCollection.count, 2, "Deserialized resources count not equal.") - XCTAssert(resource is Foo, "Deserialized resource should be of class 'Foo'.") - let foo = resource as! Foo - assertFooResource(foo, isEqualToJSON: fixture.json["data"][index]) +// XCTAssert(resource is Foo, "Deserialized resource should be of class 'Foo'.") +// let foo = resource as! Foo + assertFooResource(resource, isEqualToJSON: fixture.json["data"][index]) } }.onFailure { error in expectation.fulfill()