Skip to content

Commit

Permalink
Merge pull request #55 from mdiep/create-file
Browse files Browse the repository at this point in the history
Create file
  • Loading branch information
mdiep authored Jan 26, 2017
2 parents a3fc862 + 890f1d8 commit c780caa
Show file tree
Hide file tree
Showing 15 changed files with 788 additions and 48 deletions.
158 changes: 116 additions & 42 deletions Tentacle.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

84 changes: 84 additions & 0 deletions Tentacle.xcodeproj/xcshareddata/xcschemes/Tentacle-OSX.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,90 @@
ReferencedContainer = "container:Tentacle.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F89335531A4CE83000B88685"
BuildableName = "Argo.framework"
BlueprintName = "Argo-Mac"
ReferencedContainer = "container:Carthage/Checkouts/Argo/Argo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F886307C1B4EF9F800F53969"
BuildableName = "Curry.framework"
BlueprintName = "Curry-Mac"
ReferencedContainer = "container:Carthage/Checkouts/Curry/Curry.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BFF261D11B66435100C5552D"
BuildableName = "Ogra.framework"
BlueprintName = "Ogra-Mac"
ReferencedContainer = "container:Carthage/Checkouts/Ogra/Ogra.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D04725E919E49ED7006002AA"
BuildableName = "ReactiveSwift.framework"
BlueprintName = "ReactiveSwift-macOS"
ReferencedContainer = "container:Carthage/Checkouts/ReactiveSwift/ReactiveSwift.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D45480561A9572F5009D7229"
BuildableName = "Result.framework"
BlueprintName = "Result-Mac"
ReferencedContainer = "container:Carthage/Checkouts/Result/Result.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "F86B2E0A1A5F2B8D00C3B8BD"
BuildableName = "Runes.framework"
BlueprintName = "Runes-Mac"
ReferencedContainer = "container:Carthage/Checkouts/Runes/Runes.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
Expand Down
14 changes: 14 additions & 0 deletions Tentacle.xcodeproj/xcshareddata/xcschemes/Tentacle-iOS.xcscheme
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,20 @@
ReferencedContainer = "container:Tentacle.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "BFF261B21B66432500C5552D"
BuildableName = "Ogra.framework"
BlueprintName = "Ogra-iOS"
ReferencedContainer = "container:Carthage/Checkouts/Ogra/Ogra.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
Expand Down
31 changes: 31 additions & 0 deletions Tentacle/ArgoExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,33 @@ import Argo
import Foundation
import Result

public protocol Encodable {
func encode() -> JSON
}

extension JSON {
func JSONObject() -> Any {
switch self {
case .null:
return NSNull()
case .string(let value):
return value
case .number(let value):
return value
case .array(let array):
return array.map { $0.JSONObject() }
case .bool(let value):
return value
case .object(let object):
var dict: [String : Any] = [:]
for (key, value) in object {
dict[key] = value.JSONObject()
}
return dict as Any
}
}
}

internal func decode<T: Decodable>(_ object: Any) -> Result<T, DecodeError> where T == T.DecodedType {
let decoded: Decoded<T> = decode(object)
switch decoded {
Expand Down Expand Up @@ -92,3 +119,7 @@ internal func toUserType(_ string: String) -> Decoded<User.UserType> {
return .failure(.custom("String \(string) does not represent a valid user type"))
}
}

internal func toSHA(_ string: String) -> Decoded<SHA> {
return .success(SHA(hash: string))
}
42 changes: 42 additions & 0 deletions Tentacle/Author.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// Author.swift
// Tentacle
//
// Created by Romain Pouclet on 2016-12-22.
// Copyright © 2016 Matt Diephouse. All rights reserved.
//

import Foundation
import Argo

public struct Author {
/// Name of the Author
let name: String
/// Email of the Author
let email: String

public init(name: String, email: String) {
self.name = name
self.email = email
}
}

extension Author: Encodable {
public func encode() -> JSON {
return JSON.object([
"name": .string(name),
"email": .string(email)
])
}
}

extension Author: Hashable, Equatable {
public var hashValue: Int {
return name.hashValue ^ email.hashValue
}

static public func ==(lhs: Author, rhs: Author) -> Bool {
return lhs.name == rhs.name
&& lhs.email == rhs.email
}
}
53 changes: 47 additions & 6 deletions Tentacle/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import Foundation
import ReactiveSwift
import Result


extension JSONSerialization {
internal static func deserializeJSON(_ data: Data) -> Result<Any, AnyError> {
return Result(try JSONSerialization.jsonObject(with: data))
Expand Down Expand Up @@ -55,6 +54,18 @@ extension URLRequest {

return request
}

internal static func create<Request: RequestType>(_ url: URL, _ request: Request, _ method: HTTPMethod, _ credentials: Client.Credentials?, contentType: String? = Client.APIContentType) -> URLRequest {
var URLRequest = create(url, credentials, contentType: contentType)
URLRequest.httpMethod = method.rawValue

let object = request.encode().JSONObject()
if let payload = try? JSONSerialization.data(withJSONObject: object, options: []) {
URLRequest.httpBody = payload
}

return URLRequest
}
}

extension URLSession {
Expand Down Expand Up @@ -88,6 +99,14 @@ extension URLSession {
}
}

enum HTTPMethod: String {
case get = "GET"
case post = "POST"
case put = "PUT"
case head = "HEAD"
case options = "OPTIONS"
}

/// A GitHub API Client
public final class Client {
/// The type of content to request from the GitHub API.
Expand Down Expand Up @@ -322,13 +341,22 @@ public final class Client {
return fetchOne(.content(owner: repository.owner, repository: repository.name, path: path))
}

public func create(file: File, atPath path: String, in repository: Repository) -> SignalProducer<(Response, FileResponse), Error> {
return send(file, to: .content(owner: repository.owner, repository: repository.name, path: path), using: .put)
}

/// Fetch an endpoint from the API.
private func fetch(_ endpoint: Endpoint, page: UInt?, pageSize: UInt?) -> SignalProducer<(Response, Any), Error> {
let url = URL(server, endpoint, page: page, pageSize: pageSize)
let request = URLRequest.create(url, credentials)

return fetch(URLRequest.create(url, credentials))
}

/// Sends an URLRequest and map response to JSON
private func fetch(_ urlRequest: URLRequest) -> SignalProducer<(Response, Any), Error> {
return urlSession
.reactive
.data(with: request)
.data(with: urlRequest)
.mapError { Error.networkError($0.error) }
.flatMap(.concat) { data, response -> SignalProducer<(Response, Any), Error> in
let response = response as! HTTPURLResponse
Expand All @@ -346,14 +374,14 @@ public final class Client {
.mapError(Error.jsonDecodingError)
.flatMap { error in
.failure(Error.apiError(response.statusCode, Response(headerFields: headers), error))
}
}
}
return .success(JSON)
}
.map { JSON in
return (Response(headerFields: headers), JSON)
}
}
}
}
}

/// Fetch an object from the API.
Expand Down Expand Up @@ -390,6 +418,19 @@ public final class Client {
.concat(response.links["next"] == nil ? SignalProducer.empty : self.fetchMany(endpoint, page: nextPage, pageSize: pageSize))
}
}

internal func send<Request: RequestType>(_ request: Request, to endpoint: Endpoint, using method: HTTPMethod) -> SignalProducer<(Response, Request.Response), Error> where Request.Response == Request.Response.DecodedType {
let urlRequest = URLRequest.create(URL(server, endpoint), request, method, credentials)

return fetch(urlRequest)
.attemptMap { response, JSON in
return decode(JSON)
.map { resource in
(response, resource)
}
.mapError(Error.jsonDecodingError)
}
}
}

extension Client.Error: Hashable {
Expand Down
Loading

0 comments on commit c780caa

Please sign in to comment.