Skip to content

Commit

Permalink
Allow a representor to have multiple transitons with the same relation
Browse files Browse the repository at this point in the history
Closes #22
  • Loading branch information
kylef committed Sep 17, 2015
1 parent 0b06eb3 commit 061d996
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 25 deletions.
10 changes: 6 additions & 4 deletions Representor/Builder/RepresentorBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Foundation
/// A class used to build a representor using a builder pattern
public class RepresentorBuilder<Transition : TransitionType> {
/// The added transitions
private(set) public var transitions = [String:Transition]()
private(set) public var transitions = [String:[Transition]]()

/// The added representors
private(set) public var representors = [String:[Representor<Transition>]]()
Expand Down Expand Up @@ -60,7 +60,9 @@ public class RepresentorBuilder<Transition : TransitionType> {
/// - parameter name: The name (or relation) for the transition
/// - parameter transition: The transition
public func addTransition(name:String, _ transition:Transition) {
transitions[name] = transition
var transitions = self.transitions[name] ?? []
transitions.append(transition)
self.transitions[name] = transitions
}

/// Adds a transition with a URI
Expand All @@ -69,7 +71,7 @@ public class RepresentorBuilder<Transition : TransitionType> {
/// - parameter uri: The URI of the transition
public func addTransition(name:String, uri:String) {
let transition = Transition(uri: uri, attributes:[:], parameters:[:])
transitions[name] = transition
addTransition(name, transition)
}

/// Adds a transition with a URI using a builder
Expand All @@ -79,7 +81,7 @@ public class RepresentorBuilder<Transition : TransitionType> {
/// - parameter builder: The builder used to create the transition
public func addTransition(name:String, uri:String, builder:((Transition.Builder) -> ())) {
let transition = Transition(uri: uri, builder)
transitions[name] = transition
addTransition(name, transition)
}

// MARK: Metadata
Expand Down
15 changes: 9 additions & 6 deletions Representor/HTTP/Adapters/HTTPHALAdapter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@

import Foundation

func parseHALLinks(halLinks:[String:[String:AnyObject]]) -> [String:HTTPTransition] {
var links = [String:HTTPTransition]()
func parseHALLinks(halLinks:[String:[String:AnyObject]]) -> [String:[HTTPTransition]] {
var links = [String:[HTTPTransition]]()

for (link, options) in halLinks {
if let href = options["href"] as? String {
links[link] = HTTPTransition(uri: href)
let transition = HTTPTransition(uri: href)
links[link] = [transition]
}
}

Expand Down Expand Up @@ -43,7 +44,7 @@ func parseEmbeddedHALs(embeddedHALs:[String:AnyObject]) -> [String:[Representor<
public func deserializeHAL(hal:[String:AnyObject]) -> Representor<HTTPTransition> {
var hal = hal

var links = [String:HTTPTransition]()
var links = [String:[HTTPTransition]]()
if let halLinks = hal.removeValueForKey("_links") as? [String:[String:AnyObject]] {
links = parseHALLinks(halLinks)
}
Expand All @@ -63,8 +64,10 @@ public func serializeHAL(representor:Representor<HTTPTransition>) -> [String:Any
if !representor.transitions.isEmpty {
var links = [String:[String:String]]()

for (relation, transition) in representor.transitions {
links[relation] = ["href": transition.uri]
for (relation, transitions) in representor.transitions {
if let transition = transitions.first {
links[relation] = ["href": transition.uri]
}
}

representation["_links"] = links
Expand Down
26 changes: 17 additions & 9 deletions Representor/HTTP/Adapters/HTTPSirenAdapter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,15 @@ private func transitionToSirenAction(relation:String, transition:HTTPTransition)
/// A function to deserialize a Siren structure into a HTTP Transition.
public func deserializeSiren(siren:[String:AnyObject]) -> Representor<HTTPTransition> {
var representors = [String:[Representor<HTTPTransition>]]()
var transitions = [String:HTTPTransition]()
var transitions = [String:[HTTPTransition]]()
var attributes = [String:AnyObject]()

if let sirenLinks = siren["links"] as? [[String:AnyObject]] {
for link in sirenLinks {
if let href = link["href"] as? String {
if let relations = link["rel"] as? [String] {
for relation in relations {
transitions[relation] = HTTPTransition(uri: href)
transitions[relation] = [HTTPTransition(uri: href)]
}
}
}
Expand All @@ -113,7 +113,7 @@ public func deserializeSiren(siren:[String:AnyObject]) -> Representor<HTTPTransi
if let actions = siren["actions"] as? [[String:AnyObject]] {
for action in actions {
if let (name, transition) = sirenActionToTransition(action) {
transitions[name] = transition
transitions[name] = [transition]
}
}
}
Expand Down Expand Up @@ -147,17 +147,25 @@ public func serializeSiren(representor:Representor<HTTPTransition>) -> [String:A
representation["properties"] = representor.attributes
}

let links = representor.transitions.filter { $1.method == "GET" }
let actions = representor.transitions.filter { $1.method != "GET" }
var links = [[String:AnyObject]]()
var actions = [[String:AnyObject]]()

if !links.isEmpty {
representation["links"] = links.map { relation, transition in
return ["rel": [relation], "href": transition.uri]
for (relation, transitions) in representor.transitions {
for transition in transitions {
if transition.method == "GET" {
links.append(["rel": [relation], "href": transition.uri])
} else {
actions.append(transitionToSirenAction(relation, transition: transition))
}
}
}

if !links.isEmpty {
representation["links"] = links
}

if !actions.isEmpty {
representation["actions"] = actions.map(transitionToSirenAction)
representation["actions"] = actions
}

return representation
Expand Down
6 changes: 3 additions & 3 deletions Representor/Representor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public struct Representor<Transition : TransitionType> : Equatable, Hashable {
public typealias Builder = RepresentorBuilder<Transition>

/// The transitions available for the representor
public var transitions:[String:Transition]
public var transitions:[String:[Transition]]

/// The separate representors embedded in the current representor.
public var representors:[String:[Representor]]
Expand All @@ -24,7 +24,7 @@ public struct Representor<Transition : TransitionType> : Equatable, Hashable {
/// The attributes of the representor
public var attributes:[String:AnyObject]

public init(transitions:[String:Transition]? = nil, representors:[String:[Representor]]? = nil, attributes:[String:AnyObject]? = nil, metadata:[String:String]? = nil) {
public init(transitions:[String:[Transition]]? = nil, representors:[String:[Representor]]? = nil, attributes:[String:AnyObject]? = nil, metadata:[String:String]? = nil) {
self.transitions = transitions ?? [:]
self.representors = representors ?? [:]
self.attributes = attributes ?? [:]
Expand Down Expand Up @@ -53,7 +53,7 @@ public struct Representor<Transition : TransitionType> : Equatable, Hashable {
}
}

public func ==<Transition : TransitionType>(lhs:[String:[Representor<Transition>]], rhs:[String:[Representor<Transition>]]) -> Bool {
public func ==<Value : Equatable>(lhs:[String:[Value]], rhs:[String:[Value]]) -> Bool {
// There is a strange Swift bug where you cannot compare a
// dictionary which has an array of objects which conform to Equatable.
// So to be clear, that's comparing the following:
Expand Down
2 changes: 1 addition & 1 deletion RepresentorTests/Adapters/SirenAdapterTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class SirenAdapterTests: XCTestCase {

func testConversionFromSirenWithAction() {
let representor = deserializeSiren(representation)
XCTAssertEqual(representor.transitions["register"]!, transition)
XCTAssertEqual(representor.transitions["register"]!, [transition])
}

func testConversionToSirenWithAction() {
Expand Down
4 changes: 2 additions & 2 deletions RepresentorTests/RepresentorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class RepresentorTests: XCTestCase {
super.setUp()
transition = HTTPTransition(uri:"/self/")
embeddedRepresentor = Representor()
representor = Representor(transitions:["self": transition], representors:["embedded": [embeddedRepresentor]], attributes:["name":"Kyle"], metadata:["key": "value"])
representor = Representor(transitions:["self": [transition]], representors:["embedded": [embeddedRepresentor]], attributes:["name":"Kyle"], metadata:["key": "value"])
}

func testHasTransitions() {
Expand All @@ -39,7 +39,7 @@ class RepresentorTests: XCTestCase {
}

func testEquality() {
XCTAssertEqual(representor, Representor(transitions:["self": transition], representors:["embedded": [embeddedRepresentor]], attributes:["name":"Kyle"], metadata:["key": "value"]))
XCTAssertEqual(representor, Representor(transitions:["self": [transition]], representors:["embedded": [embeddedRepresentor]], attributes:["name":"Kyle"], metadata:["key": "value"]))
XCTAssertNotEqual(representor, Representor())
}

Expand Down

0 comments on commit 061d996

Please sign in to comment.