<commit_before>//
//  ContentfulClient.swift
//  Contentful
//
//  Created by <NAME> on 18/08/15.
//  Copyright © 2015 Contentful GmbH. All rights reserved.
//

import Decodable
import Foundation
import Interstellar

public class ContentfulClient {
    private let configuration: Configuration
    private let network = Network()
    private let spaceIdentifier: String

    private var scheme: String { return configuration.secure ? "https" : "http" }

    public init(spaceIdentifier: String, accessToken: String, configuration: Configuration = Configuration()) {
        network.sessionConfigurator = { (sessionConfiguration) in
            sessionConfiguration.HTTPAdditionalHeaders = [ "Authorization": "Bearer \(accessToken)" ]
        }

        self.configuration = configuration
        self.spaceIdentifier = spaceIdentifier
    }

    private func fetch<T: Decodable>(url: NSURL?, _ completion: Result<T> -> Void) -> NSURLSessionDataTask? {
        if let url = url {
            let (task, signal) = network.fetch(url)

            signal.next { (data) in
                do {
                    let json = try NSJSONSerialization.JSONObjectWithData(data, options: [])
                    completion(.Success(try T.decode(json)))
                } catch let error as DecodingError {
                    completion(.Error(ContentfulError.UnparseableJSON(data: data, errorMessage: error.debugDescription)))
                } catch _ {
                    completion(.Error(ContentfulError.UnparseableJSON(data: data, errorMessage: "")))
                }
            }.error { completion(.Error($0)) }

            return task
        }

        completion(.Error(ContentfulError.InvalidURL(string: "")))
        return nil
    }

    private func URLForFragment(fragment: String = "", parameters: [String: AnyObject]? = nil) -> NSURL? {
        if let components = NSURLComponents(string: "\(scheme)://\(configuration.server)/spaces/\(spaceIdentifier)/\(fragment)") {
            if let parameters = parameters {
                components.queryItems = parameters.map() { (key, value) in NSURLQueryItem(name: key, value: value.description) }
            }

            if let url = components.URL {
                return url
            }
        }
        
        return nil
    }
}

extension ContentfulClient {
    public func fetchAsset(identifier: String, completion: Result<Asset> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("assets/\(identifier)"), completion)
    }

    public func fetchAsset(identifier: String) -> (NSURLSessionDataTask?, Signal<Asset>) {
        return signalify(identifier, fetchAsset)
    }

    public func fetchAssets(matching: [String:AnyObject] = [String:AnyObject](), completion: Result<ContentfulArray<Asset>> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("assets", parameters: matching), completion)
    }

    public func fetchAssets(matching: [String:AnyObject] = [String:AnyObject]()) -> (NSURLSessionDataTask?, Signal<ContentfulArray<Asset>>) {
        return signalify(matching, fetchAssets)
    }
}

extension ContentfulClient {
    public func fetchContentType(identifier: String, completion: Result<ContentType> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("content_types/\(identifier)"), completion)
    }

    public func fetchContentType(identifier: String) -> (NSURLSessionDataTask?, Signal<ContentType>) {
        return signalify(identifier, fetchContentType)
    }

    public func fetchContentTypes(matching: [String:AnyObject] = [String:AnyObject](), completion: Result<ContentfulArray<ContentType>> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("content_types", parameters: matching), completion)
    }

    public func fetchContentTypes(matching: [String:AnyObject] = [String:AnyObject]()) -> (NSURLSessionDataTask?, Signal<ContentfulArray<ContentType>>) {
        return signalify(matching, fetchContentTypes)
    }
}

extension ContentfulClient {
    public func fetchEntries(matching: [String:AnyObject] = [String:AnyObject](), completion: Result<ContentfulArray<Entry>> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("entries", parameters: matching), completion)
    }

    public func fetchEntries(matching: [String:AnyObject] = [String:AnyObject]()) -> (NSURLSessionDataTask?, Signal<ContentfulArray<Entry>>) {
        return signalify(matching, fetchEntries)
    }

    public func fetchEntry(identifier: String, completion: Result<Entry> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("entries/\(identifier)"), completion)
    }

    public func fetchEntry(identifier: String) -> (NSURLSessionDataTask?, Signal<Entry>) {
        return signalify(identifier, fetchEntry)
    }
}

extension ContentfulClient {
    public func fetchSpace(completion: Result<Space> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment(), completion)
    }

    public func fetchSpace() -> (NSURLSessionDataTask?, Signal<Space>) {
        return signalify(fetchSpace)
    }
}
<commit_msg>Serialize arrays as comma-separated strings<commit_after>//
//  ContentfulClient.swift
//  Contentful
//
//  Created by <NAME> on 18/08/15.
//  Copyright © 2015 Contentful GmbH. All rights reserved.
//

import Decodable
import Foundation
import Interstellar

public class ContentfulClient {
    private let configuration: Configuration
    private let network = Network()
    private let spaceIdentifier: String

    private var scheme: String { return configuration.secure ? "https" : "http" }

    public init(spaceIdentifier: String, accessToken: String, configuration: Configuration = Configuration()) {
        network.sessionConfigurator = { (sessionConfiguration) in
            sessionConfiguration.HTTPAdditionalHeaders = [ "Authorization": "Bearer \(accessToken)" ]
        }

        self.configuration = configuration
        self.spaceIdentifier = spaceIdentifier
    }

    private func fetch<T: Decodable>(url: NSURL?, _ completion: Result<T> -> Void) -> NSURLSessionDataTask? {
        if let url = url {
            let (task, signal) = network.fetch(url)

            signal.next { (data) in
                do {
                    let json = try NSJSONSerialization.JSONObjectWithData(data, options: [])
                    completion(.Success(try T.decode(json)))
                } catch let error as DecodingError {
                    completion(.Error(ContentfulError.UnparseableJSON(data: data, errorMessage: error.debugDescription)))
                } catch _ {
                    completion(.Error(ContentfulError.UnparseableJSON(data: data, errorMessage: "")))
                }
            }.error { completion(.Error($0)) }

            return task
        }

        completion(.Error(ContentfulError.InvalidURL(string: "")))
        return nil
    }

    private func URLForFragment(fragment: String = "", parameters: [String: AnyObject]? = nil) -> NSURL? {
        if let components = NSURLComponents(string: "\(scheme)://\(configuration.server)/spaces/\(spaceIdentifier)/\(fragment)") {
            if let parameters = parameters {
                components.queryItems = parameters.map() { (key, var value) in
                    if let array = value as? NSArray {
                        value = array.componentsJoinedByString(",")
                    }

                    return NSURLQueryItem(name: key, value: value.description)
                }
            }

            if let url = components.URL {
                return url
            }
        }
        
        return nil
    }
}

extension ContentfulClient {
    public func fetchAsset(identifier: String, completion: Result<Asset> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("assets/\(identifier)"), completion)
    }

    public func fetchAsset(identifier: String) -> (NSURLSessionDataTask?, Signal<Asset>) {
        return signalify(identifier, fetchAsset)
    }

    public func fetchAssets(matching: [String:AnyObject] = [String:AnyObject](), completion: Result<ContentfulArray<Asset>> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("assets", parameters: matching), completion)
    }

    public func fetchAssets(matching: [String:AnyObject] = [String:AnyObject]()) -> (NSURLSessionDataTask?, Signal<ContentfulArray<Asset>>) {
        return signalify(matching, fetchAssets)
    }
}

extension ContentfulClient {
    public func fetchContentType(identifier: String, completion: Result<ContentType> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("content_types/\(identifier)"), completion)
    }

    public func fetchContentType(identifier: String) -> (NSURLSessionDataTask?, Signal<ContentType>) {
        return signalify(identifier, fetchContentType)
    }

    public func fetchContentTypes(matching: [String:AnyObject] = [String:AnyObject](), completion: Result<ContentfulArray<ContentType>> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("content_types", parameters: matching), completion)
    }

    public func fetchContentTypes(matching: [String:AnyObject] = [String:AnyObject]()) -> (NSURLSessionDataTask?, Signal<ContentfulArray<ContentType>>) {
        return signalify(matching, fetchContentTypes)
    }
}

extension ContentfulClient {
    public func fetchEntries(matching: [String:AnyObject] = [String:AnyObject](), completion: Result<ContentfulArray<Entry>> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("entries", parameters: matching), completion)
    }

    public func fetchEntries(matching: [String:AnyObject] = [String:AnyObject]()) -> (NSURLSessionDataTask?, Signal<ContentfulArray<Entry>>) {
        return signalify(matching, fetchEntries)
    }

    public func fetchEntry(identifier: String, completion: Result<Entry> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment("entries/\(identifier)"), completion)
    }

    public func fetchEntry(identifier: String) -> (NSURLSessionDataTask?, Signal<Entry>) {
        return signalify(identifier, fetchEntry)
    }
}

extension ContentfulClient {
    public func fetchSpace(completion: Result<Space> -> Void) -> NSURLSessionDataTask? {
        return fetch(URLForFragment(), completion)
    }

    public func fetchSpace() -> (NSURLSessionDataTask?, Signal<Space>) {
        return signalify(fetchSpace)
    }
}

{'fraction_non_alphanumeric': 0.11392526044155596, 'fraction_numerical': 0.0021026474242569052, 'mean_word_length': 3.1856, 'pattern_counts': {'":': 2, '<': 49, '<?xml version=': 0, '>': 97, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3841942', 'n_tokens_mistral': 2803, 'n_tokens_neox': 2672, 'n_words': 620}