Created
December 26, 2016 13:21
-
-
Save seivan/9edbb32ef39f3340b24e500a617ed914 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // EitherProtocol+Error.swift | |
| // CaoCaoKit | |
| // | |
| // Created by Seivan Heidari on 16/08/29. | |
| // | |
| // | |
| import Foundation | |
| extension EitherProtocol where Self.Left == Error { | |
| public var isError:Bool { return self.isLeft } | |
| public var isValid:Bool { return self.isRight } | |
| public var error:Error? { return self.value.left } | |
| } | |
| extension EitherProtocol where Self.Left == Error { | |
| public var description: String { return self.either(transformRight: { ".OK(\($0))" }, orLeft: { ".ERROR(\($0))" } ) } | |
| public var debugDescription: String { return self.description } | |
| public func unwrapError() throws -> Right { | |
| switch self.toConcreteType { | |
| case let .right(r): return r | |
| case let .left(l): throw l | |
| } | |
| } | |
| public func flatMap<NextRight>(_ transform: (Right) throws -> Either<NextRight, Error>) -> Either<NextRight, Error> { | |
| return self.either(transformRight: { | |
| do { return try transform($0) } | |
| catch { return Either.left(error) } | |
| }, orLeft:Either.left) | |
| } | |
| public func filter(_ left:((Right) -> Error), transform: (Right) throws -> Bool) -> Either<Right, Error> { | |
| switch self.toConcreteType { | |
| case let .right(value): do { return try transform(value) ? Either.right(value) : Either.left(left(value)) } catch { return Either.left(left(value)) } | |
| case let .left(value): return Either.left(value) | |
| } | |
| } | |
| public func filter<NextLeft:Error>(_ left:NextLeft, transform: (Right) throws -> Bool) -> Either<Right, NextLeft> { | |
| switch self.toConcreteType { | |
| case let .right(value): do { return try transform(value) ? Either.right(value) : Either.left(left) } catch { return Either.left(left) } | |
| case .left(_): return Either.left(left) | |
| } | |
| } | |
| public func map<NextRight>(_ transform: (Right) throws -> NextRight) -> Either<NextRight, Left> { | |
| return self.flatMap { | |
| do {return try .right(transform($0)) } | |
| catch { return .left(error) } | |
| } | |
| } | |
| // public func apply<NextRight>(_ transform: ((Right) throws -> NextRight)) -> Either<NextRight, Left> { | |
| // return Either.right(transform).flatMap(self.map) | |
| // } | |
| // public func apply<NextRight>(_ transform: Either<((Right) throws -> NextRight), Left>) -> Either<NextRight, Left> { | |
| // return transform.flatMap(self.map) | |
| // } | |
| public func flatMapLeft(_ transform: (Left) throws -> Either<Right, Error>) -> Either<Right, Error> { | |
| switch self.toConcreteType { | |
| case let .right(value): return .right(value) | |
| case let .left(value): | |
| do { return try transform(value) } | |
| catch { return .left(error) } | |
| } | |
| } | |
| public func mapLeft(_ transform: (Left) throws -> Error) -> Either<Right, Error> { | |
| return self.flatMapLeft { | |
| do { return try .left(transform($0)) } | |
| catch { return .left(error) } | |
| } | |
| } | |
| } | |
| extension LazyEitherProtocol where Self.Element : EitherProtocol, Self.Right == Self.Element.Right, Self.Left == Self.Element.Left, Self.Element.Left == Error { | |
| public func flatMap<NextRight>(_ transform: @escaping (Right) throws -> Either<NextRight, Left>) -> LazyEither<Either<NextRight, Left>> { | |
| return LazyEither(self.next().flatMap(transform)) | |
| } | |
| public func filter(_ left: @escaping (Right) -> Left, transform: @escaping (Right) throws -> Bool) -> LazyEither<Either<Right, Left>> { | |
| return LazyEither(self.next().filter(left, transform: transform)) | |
| } | |
| public func filter<NextLeft:Error>(_ left:NextLeft, transform: @escaping (Right) throws -> Bool) -> LazyEither<Either<Right, NextLeft>> { | |
| return LazyEither(self.next().filter(left, transform: transform)) | |
| } | |
| public func map<NextRight>(_ transform: @escaping (Right) throws -> NextRight) -> LazyEither<Either<NextRight, Left>> { | |
| return LazyEither(self.next().map(transform)) | |
| } | |
| // public func apply<NextRight>(_ transform: @escaping ((Right) throws -> NextRight)) -> LazyEither<Either<NextRight, Left>> { | |
| // return LazyEither(self.next().apply(transform)) | |
| // } | |
| // public func apply<NextRight>(_ transform: Either<((Right) throws -> NextRight), Left>) -> LazyEither<Either<NextRight, Left>> { | |
| // return LazyEither(self.next().apply(transform)) | |
| // } | |
| // public func apply<NextRight>(_ transform: LazyEither<Either<((Right) throws -> NextRight), Left>>) -> LazyEither<Either<NextRight, Left>> { | |
| // return LazyEither(self.next().apply(transform.next())) | |
| // } | |
| } | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // | |
| // Parser.swift | |
| // ConfuciusKit | |
| // | |
| // Created by Seivan Heidari on 13/06/16. | |
| // | |
| // | |
| import Foundation | |
| #if os(iOS) || os(watchOS) || os(tvOS) | |
| import UIKit | |
| #else | |
| import Cocoa | |
| #endif | |
| final public class Parser : ConfuciusKitDelegating { | |
| public typealias ValidTopLevelContent = Array<Dictionary<String,AnyObject>> | |
| public typealias FilteredContent = FileSystemLoaderFileContent<(raw:String, processed:ValidTopLevelContent)> | |
| fileprivate typealias UnfilteredContent = FileSystemLoaderFileContent<(raw:String, processed:AnyObject)> | |
| weak var delegate:ConfuciusKit! | |
| internal init() { | |
| } | |
| public func parse(fromFile file:FileSystemLoader.File) throws -> Parser.FilteredContent { | |
| return try Either<FileSystemLoader.File, Error> | |
| .right(file) | |
| .map(Parser.readContentOfFile) | |
| .map(FileSystemLoaderFileContent.init) | |
| .map(Parser.parsers) | |
| .map(Parser.validateTopLevelArrayWithNestedDictionaries) | |
| // .map(Parser.insertFilenameAsRootNamespaceIfNoRootPresent) | |
| .unwrapError() | |
| } | |
| public func parse(fromFiles files:[FileSystemLoader.File]) -> [Either<Parser.FilteredContent, Error>] { | |
| return files | |
| .flatMap(Either<FileSystemLoader.File, Error>.right) | |
| .flatMap { $0.map(self.parse) } | |
| } | |
| } | |
| public extension Parser { | |
| public enum ParseError : Error { | |
| case missingParserForExtension(FileSystemLoader.File) | |
| case failedParsingFromFileContent(FileSystemLoaderFileContent<String>, Error) | |
| case failedEncodingFileContentToData(FileSystemLoaderFileContent<String>) | |
| case invalidProcessedObjectShouldBeDictionary(FileSystemLoaderFileContent<(raw:String, processed:AnyObject)>) | |
| } | |
| } | |
| fileprivate extension Parser { | |
| static fileprivate func readContentOfFile(fromFile file:FileSystemLoader.File) throws -> (String, FileSystemLoader.File) { | |
| return try (String(contentsOf: file.path), file) | |
| } | |
| static fileprivate func parsers(forFileContent fileContent:FileSystemLoaderFileContent<String>) throws -> Parser.UnfilteredContent { | |
| switch fileContent.file.fileExtension { | |
| case "yml", "yaml": return try parseYAML(fromFileContent: fileContent) | |
| case "json": return try parseJSON(fromFileContent: fileContent) | |
| default: throw Parser.ParseError.missingParserForExtension(fileContent.file) | |
| } | |
| } | |
| static fileprivate func parseJSON(fromFileContent fileContent:FileSystemLoaderFileContent<String>) throws -> Parser.UnfilteredContent { | |
| return try Either<FileSystemLoaderFileContent<String>, Error> | |
| .right(fileContent) | |
| .map { $0.content } | |
| .map { $0.data(using: String.Encoding.utf8) } | |
| .map { try $0.throwingIfNil(Parser.ParseError.failedEncodingFileContentToData(fileContent)) } | |
| .map { try JSONSerialization.jsonObject(with: $0, options: []) } | |
| .mapLeft { throw Parser.ParseError.failedParsingFromFileContent(fileContent, $0) } | |
| .map { FileSystemLoaderFileContent(pathContent: (raw:fileContent.content, processed:$0 as AnyObject), from: fileContent.file) } | |
| .unwrapError() | |
| } | |
| static fileprivate func parseYAML(fromFileContent fileContent:FileSystemLoaderFileContent<String>) throws -> Parser.UnfilteredContent { | |
| return try Either<FileSystemLoaderFileContent<String>, Error> | |
| .right(fileContent) | |
| .map { $0.content } | |
| .map(Yaml.yamlObject) | |
| .map { FileSystemLoaderFileContent(pathContent: (raw:fileContent.content, processed:$0), from: fileContent.file) } | |
| .unwrapError() | |
| } | |
| static fileprivate func validateTopLevelArrayWithNestedDictionaries(forFileContent fileContent:Parser.UnfilteredContent) throws -> Parser.FilteredContent { | |
| switch fileContent.content.processed { | |
| case let content as ValidTopLevelContent: | |
| return FileSystemLoaderFileContent( pathContent: (raw:fileContent.content.raw, processed:content), from: fileContent.file) | |
| default: | |
| throw Parser.ParseError.invalidProcessedObjectShouldBeDictionary(fileContent) | |
| } | |
| } | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment