Skip to content

Commit

Permalink
Nice README update
Browse files Browse the repository at this point in the history
  • Loading branch information
dreymonde committed Mar 28, 2016
1 parent 27965cb commit 1468e66
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 1 deletion.
140 changes: 139 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,145 @@
[![Zewo 0.4][zewo-badge]](http://zewo.io)
[![Swift 3][swift-badge]](https://swift.org)

InterchangeData mapper library, deeply inspired by lyft/mapper
**Topo** is a tiny and simple library which allows you to convert Zewo's `InterchangeData` to strongly typed objects. Deeply inspired by Lyft's [Mapper][mapper-url].

## Usage
#### Simplest example:

``` swift
import Topo

struct User: Mappable {
let id: Int
let username: String
let city: String?

// Mappable requirement
init(map: Mapper) throws {
try id = map.from("id")
try username = map.from("username")
city = map.optionalFrom("city")
}
}

let content: InterchangeData = [
"id": 1654,
"username": "fireringer",
"city": "Houston"
]
let user = User.from(content) // User?
```

#### Mapping arrays
**Be careful!** If you use `from` instead of `fromArray`, mapping will fail.

```swift
struct Album: Mappable {
let songs: [String]
init(map: Mapper) throws {
try songs = map.fromArray("songs")
}
}
```

#### Mapping enums
You can use **Topo** for mapping enums with raw values. Right now you can use only `String` and `Double` as raw value.

```swift
enum GuitarType: String {
case acoustic
case electric
}

struct Guitar: Mappable {
let vendor: String
let type: GuitarType

init(map: Mapper) throws {
try vendor = map.from("vendor")
try type = map.from("type")
}
}
```

#### Nested `Mappable` objects

```swift
struct League: Mappable {
let name: String
init(map: Mapper) throws {
try name = map.from("name")
}
}

struct Club: Mappable {
let name: String
let league: League
init(map: Mapper) throws {
try name = map.from("name")
try league = map.from("league")
}
}
```

#### Using `Convertible`
`Mappable` is great for complex entities, but for the simplest one you can use `Convertible` protocol. `Convertible` objects can be initializaed from `InterchangeData` itself, not from its `Mapper`. For example, **Topo** uses `Convertible` to allow seamless `Int` conversion:

```swift
extension Int: Convertible {
public static func from(customInterchangeData value: InterchangeData) -> Int? {
switch value {
case .numberValue(let number):
return Int(number)
default:
return nil
}
}
}
```

## Installation
- Add `Topo` to your `Package.swift`

```swift
import PackageDescription

let package = Package(
dependencies: [
.Package(url: "https://github.com/dreymonde/Topo.git", majorVersion: 0, minor: 2),
]
)
```

## Destination
Behind **Topo** stands the idea to use the same data structures both on Swift server-side and client-side. **Topo** depends only on Zewo's [InterchangeData][interchange-data-url], so once it will be ported on Apple systems, **Topo** will become available for iOS, OS X, watchOS and tvOS.

### Why not `ContentMappable`?
`ContentMappable: ContentInitializable` is a protocol provided by Zewo's [ContentNegotiationMiddleware][cont-neg-mid-url] and it has similar functionality to **Topo**. But it's a lot harder to use `ContentMappable` for types which are not described in `InterchangeData`. For example, you cannot simply call `content.get()` on `Int`. Nesting is another powerful feature of **Topo**.

Also, use of `ContentMappable` would make **Topo** depends on `ContentNegotiationMiddleware`, which is senseless for client-side.

Although, it is possible to have another version of **Topo** which is fully compatible with `ContentNegotiationMiddleware`. It may appear in future.


### See also
[Resource][resource-url] by @paulofaria, which provides RESTful resources for Zewo's Router.

## Contributing
**Topo** is in very early stage. If you want to contribute or to propose a change - you are very welcome. Almost anything can be questioned. Open an issue or submit a pull request if you have an idea.

## Community

[![Slack](http://s13.postimg.org/ybwy92ktf/Slack.png)](http://slack.zewo.io)

Join us on [Slack](http://slack.zewo.io).

## License
**Topo** is released under the MIT license. See LICENSE for details.

[zewo-badge]: https://img.shields.io/badge/Zewo-0.4-FF7565.svg?style=flat
[swift-badge]: https://img.shields.io/badge/Swift-3.0-orange.svg?style=flat
[mapper-url]: https://github.com/lyft/mapper
[interchange-data-url]: https://github.com/Zewo/InterchangeData
[resource-url]: https://github.com/paulofaria/Resource
[cont-neg-mid-url]: https://github.com/Zewo/ContentNegotiationMiddleware
64 changes: 64 additions & 0 deletions Resources/Examples.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
//
// Examples.swift
// Topo
//
// Created by Oleg Dreyman on 28.03.16.
// Copyright © 2016 Oleg Dreyman. All rights reserved.
//

struct User: Mappable {
let id: Int
let username: String
let city: String?

init(map: Mapper) throws {
try id = map.from("id")
try username = map.from("username")
city = map.optionalFrom("city")
}
}

let content: InterchangeData = [
"id": 1654,
"username": "fireringer",
"city": "Houston"
]
let user = User.from(content)

enum GuitarType: String {
case acoustic
case electric
}

struct Guitar: Mappable {
let vendor: String
let type: GuitarType

init(map: Mapper) throws {
try vendor = map.from("vendor")
try type = map.from("type")
}
}

struct League: Mappable {
let name: String
init(map: Mapper) throws {
try name = map.from("name")
}
}

struct Club: Mappable {
let name: String
let league: League
init(map: Mapper) throws {
try name = map.from("name")
try league = map.from("league")
}
}

struct Album: Mappable {
let songs: [String]
init(map: Mapper) throws {
try songs = map.fromArray("songs")
}
}
4 changes: 4 additions & 0 deletions Topo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
BEA128091CA92A46000F56F2 /* Examples.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEA128081CA92A46000F56F2 /* Examples.swift */; };
BEDB11861CA9195700C6C955 /* Convertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEDB11851CA9195700C6C955 /* Convertible.swift */; };
BEDB11971CA91A8F00C6C955 /* AsyncStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEDB11891CA91A8F00C6C955 /* AsyncStream.swift */; };
BEDB11981CA91A8F00C6C955 /* AsyncStreamClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEDB118A1CA91A8F00C6C955 /* AsyncStreamClient.swift */; };
Expand Down Expand Up @@ -45,6 +46,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
BEA128081CA92A46000F56F2 /* Examples.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Examples.swift; sourceTree = "<group>"; };
BEDB11851CA9195700C6C955 /* Convertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Convertible.swift; sourceTree = "<group>"; };
BEDB11891CA91A8F00C6C955 /* AsyncStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncStream.swift; sourceTree = "<group>"; };
BEDB118A1CA91A8F00C6C955 /* AsyncStreamClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncStreamClient.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -164,6 +166,7 @@
BEF2D84B1CA80ADC00172582 /* InterchangeData.swift */,
BEF2D8311CA80A7800172582 /* Topo.h */,
BEF2D8331CA80A7800172582 /* Info.plist */,
BEA128081CA92A46000F56F2 /* Examples.swift */,
);
path = Resources;
sourceTree = "<group>";
Expand Down Expand Up @@ -284,6 +287,7 @@
BEF2D84C1CA80ADC00172582 /* InterchangeData.swift in Sources */,
BEDB11A41CA91A8F00C6C955 /* URI.swift in Sources */,
BEDB11971CA91A8F00C6C955 /* AsyncStream.swift in Sources */,
BEA128091CA92A46000F56F2 /* Examples.swift in Sources */,
BEDB11991CA91A8F00C6C955 /* AsyncStreamServer.swift in Sources */,
BEDB11A31CA91A8F00C6C955 /* StreamServer.swift in Sources */,
BEDB11A11CA91A8F00C6C955 /* StreamClient.swift in Sources */,
Expand Down

0 comments on commit 1468e66

Please sign in to comment.