🔥 Deintegrate CocoaSeeds

This commit is contained in:
Ben Chatelain 2018-07-04 14:52:00 -06:00
parent 97f56a39fa
commit 89c9ee68c9
17 changed files with 0 additions and 1827 deletions

View file

@ -1,7 +0,0 @@
github "carthage/Commandant", "0.13.0", files: "Sources/Commandant/*.swift"
github "antitypical/Result", "3.2.4", files: "Result/*.swift"
target :"mas-tests" do
github "Quick/Nimble", "v7.0.3", files: "Nimble/**.{swift,h}"
github "Quick/Quick", "v1.2.0", files: "Quick/**.{swift,h}"
end

View file

@ -1,99 +0,0 @@
//
// Argument.swift
// Commandant
//
// Created by Syo Ikeda on 12/14/15.
// Copyright (c) 2015 Carthage. All rights reserved.
//
/// Describes an argument that can be provided on the command line.
public struct Argument<T> {
/// The default value for this argument. This is the value that will be used
/// if the argument is never explicitly specified on the command line.
///
/// If this is nil, this argument is always required.
public let defaultValue: T?
/// A human-readable string describing the purpose of this argument. This will
/// be shown in help messages.
public let usage: String
public init(defaultValue: T? = nil, usage: String) {
self.defaultValue = defaultValue
self.usage = usage
}
fileprivate func invalidUsageError<ClientError>(_ value: String) -> CommandantError<ClientError> {
let description = "Invalid value for '\(self)': \(value)"
return .usageError(description: description)
}
}
// MARK: - Operators
extension CommandMode {
/// Evaluates the given argument in the given mode.
///
/// If parsing command line arguments, and no value was specified on the command
/// line, the argument's `defaultValue` is used.
public static func <| <T: ArgumentProtocol, ClientError>(mode: CommandMode, argument: Argument<T>) -> Result<T, CommandantError<ClientError>> {
switch mode {
case let .arguments(arguments):
guard let stringValue = arguments.consumePositionalArgument() else {
if let defaultValue = argument.defaultValue {
return .success(defaultValue)
} else {
return .failure(missingArgumentError(argument.usage))
}
}
if let value = T.from(string: stringValue) {
return .success(value)
} else {
return .failure(argument.invalidUsageError(stringValue))
}
case .usage:
return .failure(informativeUsageError(argument))
}
}
/// Evaluates the given argument list in the given mode.
///
/// If parsing command line arguments, and no value was specified on the command
/// line, the argument's `defaultValue` is used.
public static func <| <T: ArgumentProtocol, ClientError>(mode: CommandMode, argument: Argument<[T]>) -> Result<[T], CommandantError<ClientError>> {
switch mode {
case let .arguments(arguments):
guard let firstValue = arguments.consumePositionalArgument() else {
if let defaultValue = argument.defaultValue {
return .success(defaultValue)
} else {
return .failure(missingArgumentError(argument.usage))
}
}
var values = [T]()
guard let value = T.from(string: firstValue) else {
return .failure(argument.invalidUsageError(firstValue))
}
values.append(value)
while let nextValue = arguments.consumePositionalArgument() {
guard let value = T.from(string: nextValue) else {
return .failure(argument.invalidUsageError(nextValue))
}
values.append(value)
}
return .success(values)
case .usage:
return .failure(informativeUsageError(argument))
}
}
}

View file

@ -1,191 +0,0 @@
//
// ArgumentParser.swift
// Commandant
//
// Created by Justin Spahr-Summers on 2014-11-21.
// Copyright (c) 2014 Carthage. All rights reserved.
//
import Foundation
/// Represents an argument passed on the command line.
private enum RawArgument: Equatable {
/// A key corresponding to an option (e.g., `verbose` for `--verbose`).
case key(String)
/// A value, either associated with an option or passed as a positional
/// argument.
case value(String)
/// One or more flag arguments (e.g 'r' and 'f' for `-rf`)
case flag(OrderedSet<Character>)
}
private func ==(lhs: RawArgument, rhs: RawArgument) -> Bool {
switch (lhs, rhs) {
case let (.key(left), .key(right)):
return left == right
case let (.value(left), .value(right)):
return left == right
case let (.flag(left), .flag(right)):
return left == right
default:
return false
}
}
extension RawArgument: CustomStringConvertible {
fileprivate var description: String {
switch self {
case let .key(key):
return "--\(key)"
case let .value(value):
return "\"\(value)\""
case let .flag(flags):
return "-\(String(flags))"
}
}
}
/// Destructively parses a list of command-line arguments.
public final class ArgumentParser {
/// The remaining arguments to be extracted, in their raw form.
private var rawArguments: [RawArgument] = []
/// Initializes the generator from a simple list of command-line arguments.
public init(_ arguments: [String]) {
// The first instance of `--` terminates the option list.
let params = arguments.split(maxSplits: 1, omittingEmptySubsequences: false) { $0 == "--" }
// Parse out the keyed and flag options.
let options = params.first!
rawArguments.append(contentsOf: options.map { arg in
if arg.hasPrefix("-") {
// Do we have `--{key}` or `-{flags}`.
let opt = arg.dropFirst()
if opt.first == "-" {
return .key(String(opt.dropFirst()))
} else {
return .flag(OrderedSet(opt))
}
} else {
return .value(arg)
}
})
// Remaining arguments are all positional parameters.
if params.count == 2 {
let positional = params.last!
rawArguments.append(contentsOf: positional.map(RawArgument.value))
}
}
/// Returns the remaining arguments.
internal var remainingArguments: [String]? {
return rawArguments.isEmpty ? nil : rawArguments.map { $0.description }
}
/// Returns whether the given key was enabled or disabled, or nil if it
/// was not given at all.
///
/// If the key is found, it is then removed from the list of arguments
/// remaining to be parsed.
internal func consumeBoolean(forKey key: String) -> Bool? {
let oldArguments = rawArguments
rawArguments.removeAll()
var result: Bool?
for arg in oldArguments {
if arg == .key(key) {
result = true
} else if arg == .key("no-\(key)") {
result = false
} else {
rawArguments.append(arg)
}
}
return result
}
/// Returns the value associated with the given flag, or nil if the flag was
/// not specified. If the key is presented, but no value was given, an error
/// is returned.
///
/// If a value is found, the key and the value are both removed from the
/// list of arguments remaining to be parsed.
internal func consumeValue(forKey key: String) -> Result<String?, CommandantError<NoError>> {
let oldArguments = rawArguments
rawArguments.removeAll()
var foundValue: String?
var index = 0
while index < oldArguments.count {
defer { index += 1 }
let arg = oldArguments[index]
guard arg == .key(key) else {
rawArguments.append(arg)
continue
}
index += 1
guard index < oldArguments.count, case let .value(value) = oldArguments[index] else {
return .failure(missingArgumentError("--\(key)"))
}
foundValue = value
}
return .success(foundValue)
}
/// Returns the next positional argument that hasn't yet been returned, or
/// nil if there are no more positional arguments.
internal func consumePositionalArgument() -> String? {
for (index, arg) in rawArguments.enumerated() {
if case let .value(value) = arg {
rawArguments.remove(at: index)
return value
}
}
return nil
}
/// Returns whether the given key was specified and removes it from the
/// list of arguments remaining.
internal func consume(key: String) -> Bool {
let oldArguments = rawArguments
rawArguments = oldArguments.filter { $0 != .key(key) }
return rawArguments.count < oldArguments.count
}
/// Returns whether the given flag was specified and removes it from the
/// list of arguments remaining.
internal func consumeBoolean(flag: Character) -> Bool {
for (index, arg) in rawArguments.enumerated() {
if case let .flag(flags) = arg, flags.contains(flag) {
var flags = flags
flags.remove(flag)
if flags.isEmpty {
rawArguments.remove(at: index)
} else {
rawArguments[index] = .flag(flags)
}
return true
}
}
return false
}
}

View file

@ -1,44 +0,0 @@
//
// ArgumentProtocol.swift
// Commandant
//
// Created by Syo Ikeda on 12/14/15.
// Copyright (c) 2015 Carthage. All rights reserved.
//
/// Represents a value that can be converted from a command-line argument.
public protocol ArgumentProtocol {
/// A human-readable name for this type.
static var name: String { get }
/// Attempts to parse a value from the given command-line argument.
static func from(string: String) -> Self?
}
extension Int: ArgumentProtocol {
public static let name = "integer"
public static func from(string: String) -> Int? {
return Int(string)
}
}
extension String: ArgumentProtocol {
public static let name = "string"
public static func from(string: String) -> String? {
return string
}
}
extension RawRepresentable where RawValue: StringProtocol, Self: ArgumentProtocol {
public static func from(string: String) -> Self? {
return RawValue(string).flatMap(Self.init(rawValue:))
}
}
extension RawRepresentable where RawValue: FixedWidthInteger, Self: ArgumentProtocol {
public static func from(string: String) -> Self? {
return RawValue(string).flatMap(Self.init(rawValue:))
}
}

View file

@ -1,222 +0,0 @@
//
// Command.swift
// Commandant
//
// Created by Justin Spahr-Summers on 2014-10-10.
// Copyright (c) 2014 Carthage. All rights reserved.
//
import Foundation
/// Represents a subcommand that can be executed with its own set of arguments.
public protocol CommandProtocol {
/// The command's options type.
associatedtype Options: OptionsProtocol
associatedtype ClientError: Error = Options.ClientError
/// The action that users should specify to use this subcommand (e.g.,
/// `help`).
var verb: String { get }
/// A human-readable, high-level description of what this command is used
/// for.
var function: String { get }
/// Runs this subcommand with the given options.
func run(_ options: Options) -> Result<(), ClientError>
}
/// A type-erased command.
public struct CommandWrapper<ClientError: Error> {
public let verb: String
public let function: String
public let run: (ArgumentParser) -> Result<(), CommandantError<ClientError>>
public let usage: () -> CommandantError<ClientError>?
/// Creates a command that wraps another.
fileprivate init<C: CommandProtocol>(_ command: C) where C.ClientError == ClientError, C.Options.ClientError == ClientError {
verb = command.verb
function = command.function
run = { (arguments: ArgumentParser) -> Result<(), CommandantError<ClientError>> in
let options = C.Options.evaluate(.arguments(arguments))
if let remainingArguments = arguments.remainingArguments {
return .failure(unrecognizedArgumentsError(remainingArguments))
}
switch options {
case let .success(options):
return command
.run(options)
.mapError(CommandantError.commandError)
case let .failure(error):
return .failure(error)
}
}
usage = { () -> CommandantError<ClientError>? in
return C.Options.evaluate(.usage).error
}
}
}
/// Describes the "mode" in which a command should run.
public enum CommandMode {
/// Options should be parsed from the given command-line arguments.
case arguments(ArgumentParser)
/// Each option should record its usage information in an error, for
/// presentation to the user.
case usage
}
/// Maintains the list of commands available to run.
public final class CommandRegistry<ClientError: Error> {
private var commandsByVerb: [String: CommandWrapper<ClientError>] = [:]
/// All available commands.
public var commands: [CommandWrapper<ClientError>] {
return commandsByVerb.values.sorted { return $0.verb < $1.verb }
}
public init() {}
/// Registers the given commands, making those available to run.
///
/// If another commands were already registered with the same `verb`s, those
/// will be overwritten.
@discardableResult
public func register<C: CommandProtocol>(_ commands: C...)
-> CommandRegistry
where C.ClientError == ClientError, C.Options.ClientError == ClientError
{
for command in commands {
commandsByVerb[command.verb] = CommandWrapper(command)
}
return self
}
/// Runs the command corresponding to the given verb, passing it the given
/// arguments.
///
/// Returns the results of the execution, or nil if no such command exists.
public func run(command verb: String, arguments: [String]) -> Result<(), CommandantError<ClientError>>? {
return self[verb]?.run(ArgumentParser(arguments))
}
/// Returns the command matching the given verb, or nil if no such command
/// is registered.
public subscript(verb: String) -> CommandWrapper<ClientError>? {
return commandsByVerb[verb]
}
}
extension CommandRegistry {
/// Hands off execution to the CommandRegistry, by parsing CommandLine.arguments
/// and then running whichever command has been identified in the argument
/// list.
///
/// If the chosen command executes successfully, the process will exit with
/// a successful exit code.
///
/// If the chosen command fails, the provided error handler will be invoked,
/// then the process will exit with a failure exit code.
///
/// If a matching command could not be found but there is any `executable-verb`
/// style subcommand executable in the caller's `$PATH`, the subcommand will
/// be executed.
///
/// If a matching command could not be found or a usage error occurred,
/// a helpful error message will be written to `stderr`, then the process
/// will exit with a failure error code.
public func main(defaultVerb: String, errorHandler: (ClientError) -> ()) -> Never {
main(arguments: CommandLine.arguments, defaultVerb: defaultVerb, errorHandler: errorHandler)
}
/// Hands off execution to the CommandRegistry, by parsing `arguments`
/// and then running whichever command has been identified in the argument
/// list.
///
/// If the chosen command executes successfully, the process will exit with
/// a successful exit code.
///
/// If the chosen command fails, the provided error handler will be invoked,
/// then the process will exit with a failure exit code.
///
/// If a matching command could not be found but there is any `executable-verb`
/// style subcommand executable in the caller's `$PATH`, the subcommand will
/// be executed.
///
/// If a matching command could not be found or a usage error occurred,
/// a helpful error message will be written to `stderr`, then the process
/// will exit with a failure error code.
public func main(arguments: [String], defaultVerb: String, errorHandler: (ClientError) -> ()) -> Never {
assert(arguments.count >= 1)
var arguments = arguments
// Extract the executable name.
let executableName = arguments.remove(at: 0)
// use the default verb even if we have other arguments
var verb = defaultVerb
if let argument = arguments.first, !argument.hasPrefix("-") {
verb = argument
// Remove the command name.
arguments.remove(at: 0)
}
switch run(command: verb, arguments: arguments) {
case .success?:
exit(EXIT_SUCCESS)
case let .failure(error)?:
switch error {
case let .usageError(description):
fputs(description + "\n", stderr)
case let .commandError(error):
errorHandler(error)
}
exit(EXIT_FAILURE)
case nil:
if let subcommandExecuted = executeSubcommandIfExists(executableName, verb: verb, arguments: arguments) {
exit(subcommandExecuted)
}
fputs("Unrecognized command: '\(verb)'. See `\(executableName) help`.\n", stderr)
exit(EXIT_FAILURE)
}
}
/// Finds and executes a subcommand which exists in your $PATH. The executable
/// name must be in the form of `executable-verb`.
///
/// - Returns: The exit status of found subcommand or nil.
private func executeSubcommandIfExists(_ executableName: String, verb: String, arguments: [String]) -> Int32? {
let subcommand = "\(NSString(string: executableName).lastPathComponent)-\(verb)"
func launchTask(_ path: String, arguments: [String]) -> Int32 {
let task = Process()
task.launchPath = path
task.arguments = arguments
task.launch()
task.waitUntilExit()
return task.terminationStatus
}
guard launchTask("/usr/bin/which", arguments: [ "-s", subcommand ]) == 0 else {
return nil
}
return launchTask("/usr/bin/env", arguments: [ subcommand ] + arguments)
}
}

View file

@ -1,17 +0,0 @@
//
// Commandant.h
// Commandant
//
// Created by Justin Spahr-Summers on 2014-11-21.
// Copyright (c) 2014 Carthage. All rights reserved.
//
#import <Foundation/Foundation.h>
//! Project version number for Commandant.
FOUNDATION_EXPORT double CommandantVersionNumber;
//! Project version string for Commandant.
FOUNDATION_EXPORT const unsigned char CommandantVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <Commandant/PublicHeader.h>

View file

@ -1,153 +0,0 @@
//
// Errors.swift
// Commandant
//
// Created by Justin Spahr-Summers on 2014-10-24.
// Copyright (c) 2014 Carthage. All rights reserved.
//
import Foundation
/// Possible errors that can originate from Commandant.
///
/// `ClientError` should be the type of error (if any) that can occur when
/// running commands.
public enum CommandantError<ClientError>: Error {
/// An option was used incorrectly.
case usageError(description: String)
/// An error occurred while running a command.
case commandError(ClientError)
}
extension CommandantError: CustomStringConvertible {
public var description: String {
switch self {
case let .usageError(description):
return description
case let .commandError(error):
return String(describing: error)
}
}
}
/// Constructs an `InvalidArgument` error that indicates a missing value for
/// the argument by the given name.
internal func missingArgumentError<ClientError>(_ argumentName: String) -> CommandantError<ClientError> {
let description = "Missing argument for \(argumentName)"
return .usageError(description: description)
}
/// Constructs an error by combining the example of key (and value, if applicable)
/// with the usage description.
internal func informativeUsageError<ClientError>(_ keyValueExample: String, usage: String) -> CommandantError<ClientError> {
let lines = usage.components(separatedBy: .newlines)
return .usageError(description: lines.reduce(keyValueExample) { previous, value in
return previous + "\n\t" + value
})
}
/// Combines the text of the two errors, if they're both `UsageError`s.
/// Otherwise, uses whichever one is not (biased toward the left).
internal func combineUsageErrors<ClientError>(_ lhs: CommandantError<ClientError>, _ rhs: CommandantError<ClientError>) -> CommandantError<ClientError> {
switch (lhs, rhs) {
case let (.usageError(left), .usageError(right)):
let combinedDescription = "\(left)\n\n\(right)"
return .usageError(description: combinedDescription)
case (.usageError, _):
return rhs
case (_, .usageError), (_, _):
return lhs
}
}
/// Constructs an error that indicates unrecognized arguments remains.
internal func unrecognizedArgumentsError<ClientError>(_ options: [String]) -> CommandantError<ClientError> {
return .usageError(description: "Unrecognized arguments: " + options.joined(separator: ", "))
}
// MARK: Argument
/// Constructs an error that describes how to use the argument, with the given
/// example of value usage if applicable.
internal func informativeUsageError<T, ClientError>(_ valueExample: String, argument: Argument<T>) -> CommandantError<ClientError> {
if argument.defaultValue != nil {
return informativeUsageError("[\(valueExample)]", usage: argument.usage)
} else {
return informativeUsageError(valueExample, usage: argument.usage)
}
}
/// Constructs an error that describes how to use the argument.
internal func informativeUsageError<T: ArgumentProtocol, ClientError>(_ argument: Argument<T>) -> CommandantError<ClientError> {
var example = ""
var valueExample = ""
if let defaultValue = argument.defaultValue {
valueExample = "\(defaultValue)"
}
if valueExample.isEmpty {
example += "(\(T.name))"
} else {
example += valueExample
}
return informativeUsageError(example, argument: argument)
}
/// Constructs an error that describes how to use the argument list.
internal func informativeUsageError<T: ArgumentProtocol, ClientError>(_ argument: Argument<[T]>) -> CommandantError<ClientError> {
var example = ""
var valueExample = ""
if let defaultValue = argument.defaultValue {
valueExample = "\(defaultValue)"
}
if valueExample.isEmpty {
example += "(\(T.name))"
} else {
example += valueExample
}
return informativeUsageError(example, argument: argument)
}
// MARK: Option
/// Constructs an error that describes how to use the option, with the given
/// example of key (and value, if applicable) usage.
internal func informativeUsageError<T, ClientError>(_ keyValueExample: String, option: Option<T>) -> CommandantError<ClientError> {
return informativeUsageError("[\(keyValueExample)]", usage: option.usage)
}
/// Constructs an error that describes how to use the option.
internal func informativeUsageError<T: ArgumentProtocol, ClientError>(_ option: Option<T>) -> CommandantError<ClientError> {
return informativeUsageError("--\(option.key) \(option.defaultValue)", option: option)
}
/// Constructs an error that describes how to use the option.
internal func informativeUsageError<T: ArgumentProtocol, ClientError>(_ option: Option<T?>) -> CommandantError<ClientError> {
return informativeUsageError("--\(option.key) (\(T.name))", option: option)
}
/// Constructs an error that describes how to use the option.
internal func informativeUsageError<T: ArgumentProtocol, ClientError>(_ option: Option<[T]>) -> CommandantError<ClientError> {
return informativeUsageError("--\(option.key) (\(option.defaultValue))", option: option)
}
/// Constructs an error that describes how to use the option.
internal func informativeUsageError<T: ArgumentProtocol, ClientError>(_ option: Option<[T]?>) -> CommandantError<ClientError> {
return informativeUsageError("--\(option.key) (\(T.name))", option: option)
}
/// Constructs an error that describes how to use the given boolean option.
internal func informativeUsageError<ClientError>(_ option: Option<Bool>) -> CommandantError<ClientError> {
let key = option.key
return informativeUsageError((option.defaultValue ? "--no-\(key)" : "--\(key)"), option: option)
}

View file

@ -1,75 +0,0 @@
//
// HelpCommand.swift
// Commandant
//
// Created by Justin Spahr-Summers on 2014-10-10.
// Copyright (c) 2014 Carthage. All rights reserved.
//
import Foundation
/// A basic implementation of a `help` command, using information available in a
/// `CommandRegistry`.
///
/// If you want to use this command, initialize it with the registry, then add
/// it to that same registry:
///
/// let commands: CommandRegistry<MyErrorType> =
/// let helpCommand = HelpCommand(registry: commands)
/// commands.register(helpCommand)
public struct HelpCommand<ClientError: Error>: CommandProtocol {
public typealias Options = HelpOptions<ClientError>
public let verb = "help"
public let function = "Display general or command-specific help"
private let registry: CommandRegistry<ClientError>
/// Initializes the command to provide help from the given registry of
/// commands.
public init(registry: CommandRegistry<ClientError>) {
self.registry = registry
}
public func run(_ options: Options) -> Result<(), ClientError> {
if let verb = options.verb {
if let command = self.registry[verb] {
print(command.function)
if let usageError = command.usage() {
print("\n\(usageError)")
}
return .success(())
} else {
fputs("Unrecognized command: '\(verb)'\n", stderr)
}
}
print("Available commands:\n")
let maxVerbLength = self.registry.commands.map { $0.verb.count }.max() ?? 0
for command in self.registry.commands {
let padding = repeatElement(Character(" "), count: maxVerbLength - command.verb.count)
print(" \(command.verb)\(String(padding)) \(command.function)")
}
return .success(())
}
}
public struct HelpOptions<ClientError: Error>: OptionsProtocol {
fileprivate let verb: String?
private init(verb: String?) {
self.verb = verb
}
private static func create(_ verb: String) -> HelpOptions {
return self.init(verb: (verb == "" ? nil : verb))
}
public static func evaluate(_ m: CommandMode) -> Result<HelpOptions, CommandantError<ClientError>> {
return create
<*> m <| Argument(defaultValue: "", usage: "the command to display help for")
}
}

View file

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.13.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2014 Carthage. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View file

@ -1,273 +0,0 @@
//
// Option.swift
// Commandant
//
// Created by Justin Spahr-Summers on 2014-11-21.
// Copyright (c) 2014 Carthage. All rights reserved.
//
import Foundation
/// Represents a record of options for a command, which can be parsed from
/// a list of command-line arguments.
///
/// This is most helpful when used in conjunction with the `Option` and `Switch`
/// types, and `<*>` and `<|` combinators.
///
/// Example:
///
/// struct LogOptions: OptionsProtocol {
/// let verbosity: Int
/// let outputFilename: String
/// let shouldDelete: Bool
/// let logName: String
///
/// static func create(_ verbosity: Int) -> (String) -> (Bool) -> (String) -> LogOptions {
/// return { outputFilename in { shouldDelete in { logName in LogOptions(verbosity: verbosity, outputFilename: outputFilename, shouldDelete: shouldDelete, logName: logName) } } }
/// }
///
/// static func evaluate(_ m: CommandMode) -> Result<LogOptions, CommandantError<YourErrorType>> {
/// return create
/// <*> m <| Option(key: "verbose", defaultValue: 0, usage: "the verbosity level with which to read the logs")
/// <*> m <| Option(key: "outputFilename", defaultValue: "", usage: "a file to print output to, instead of stdout")
/// <*> m <| Switch(flag: "d", key: "delete", usage: "delete the logs when finished")
/// <*> m <| Argument(usage: "the log to read")
/// }
/// }
public protocol OptionsProtocol {
associatedtype ClientError: Error
/// Evaluates this set of options in the given mode.
///
/// Returns the parsed options or a `UsageError`.
static func evaluate(_ m: CommandMode) -> Result<Self, CommandantError<ClientError>>
}
/// An `OptionsProtocol` that has no options.
public struct NoOptions<ClientError: Error>: OptionsProtocol {
public init() {}
public static func evaluate(_ m: CommandMode) -> Result<NoOptions, CommandantError<ClientError>> {
return .success(NoOptions())
}
}
/// Describes an option that can be provided on the command line.
public struct Option<T> {
/// The key that controls this option. For example, a key of `verbose` would
/// be used for a `--verbose` option.
public let key: String
/// The default value for this option. This is the value that will be used
/// if the option is never explicitly specified on the command line.
public let defaultValue: T
/// A human-readable string describing the purpose of this option. This will
/// be shown in help messages.
///
/// For boolean operations, this should describe the effect of _not_ using
/// the default value (i.e., what will happen if you disable/enable the flag
/// differently from the default).
public let usage: String
public init(key: String, defaultValue: T, usage: String) {
self.key = key
self.defaultValue = defaultValue
self.usage = usage
}
}
extension Option: CustomStringConvertible {
public var description: String {
return "--\(key)"
}
}
// MARK: - Operators
// Inspired by the Argo library:
// https://github.com/thoughtbot/Argo
/*
Copyright (c) 2014 thoughtbot, inc.
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
infix operator <*> : LogicalDisjunctionPrecedence
infix operator <| : MultiplicationPrecedence
/// Applies `f` to the value in the given result.
///
/// In the context of command-line option parsing, this is used to chain
/// together the parsing of multiple arguments. See OptionsProtocol for an example.
public func <*> <T, U, ClientError>(f: (T) -> U, value: Result<T, CommandantError<ClientError>>) -> Result<U, CommandantError<ClientError>> {
return value.map(f)
}
/// Applies the function in `f` to the value in the given result.
///
/// In the context of command-line option parsing, this is used to chain
/// together the parsing of multiple arguments. See OptionsProtocol for an example.
public func <*> <T, U, ClientError>(f: Result<((T) -> U), CommandantError<ClientError>>, value: Result<T, CommandantError<ClientError>>) -> Result<U, CommandantError<ClientError>> {
switch (f, value) {
case let (.failure(left), .failure(right)):
return .failure(combineUsageErrors(left, right))
case let (.failure(left), .success):
return .failure(left)
case let (.success, .failure(right)):
return .failure(right)
case let (.success(f), .success(value)):
let newValue = f(value)
return .success(newValue)
}
}
extension CommandMode {
/// Evaluates the given option in the given mode.
///
/// If parsing command line arguments, and no value was specified on the command
/// line, the option's `defaultValue` is used.
public static func <| <T: ArgumentProtocol, ClientError>(mode: CommandMode, option: Option<T>) -> Result<T, CommandantError<ClientError>> {
let wrapped = Option<T?>(key: option.key, defaultValue: option.defaultValue, usage: option.usage)
// Since we are passing a non-nil default value, we can safely unwrap the
// result.
return (mode <| wrapped).map { $0! }
}
/// Evaluates the given option in the given mode.
///
/// If parsing command line arguments, and no value was specified on the command
/// line, `nil` is used.
public static func <| <T: ArgumentProtocol, ClientError>(mode: CommandMode, option: Option<T?>) -> Result<T?, CommandantError<ClientError>> {
let key = option.key
switch mode {
case let .arguments(arguments):
var stringValue: String?
switch arguments.consumeValue(forKey: key) {
case let .success(value):
stringValue = value
case let .failure(error):
switch error {
case let .usageError(description):
return .failure(.usageError(description: description))
case .commandError:
fatalError("CommandError should be impossible when parameterized over NoError")
}
}
if let stringValue = stringValue {
if let value = T.from(string: stringValue) {
return .success(value)
}
let description = "Invalid value for '--\(key)': \(stringValue)"
return .failure(.usageError(description: description))
} else {
return .success(option.defaultValue)
}
case .usage:
return .failure(informativeUsageError(option))
}
}
/// Evaluates the given option in the given mode.
///
/// If parsing command line arguments, and no value was specified on the command
/// line, the option's `defaultValue` is used.
public static func <| <T: ArgumentProtocol, ClientError>(mode: CommandMode, option: Option<[T]>) -> Result<[T], CommandantError<ClientError>> {
let wrapped = Option<[T]?>(key: option.key, defaultValue: option.defaultValue, usage: option.usage)
// Since we are passing a non-nil default value, we can safely unwrap the
// result.
return (mode <| wrapped).map { $0! }
}
/// Evaluates the given option in the given mode.
///
/// If parsing command line arguments, and no value was specified on the command
/// line, `nil` is used.
public static func <| <T: ArgumentProtocol, ClientError>(mode: CommandMode, option: Option<[T]?>) -> Result<[T]?, CommandantError<ClientError>> {
let key = option.key
switch mode {
case let .arguments(arguments):
let stringValue: String?
switch arguments.consumeValue(forKey: key) {
case let .success(value):
stringValue = value
case let .failure(error):
switch error {
case let .usageError(description):
return .failure(.usageError(description: description))
case .commandError:
fatalError("CommandError should be impossible when parameterized over NoError")
}
}
guard let unwrappedStringValue = stringValue else {
return .success(option.defaultValue)
}
let components = unwrappedStringValue.split(
omittingEmptySubsequences: true,
whereSeparator: [",", " "].contains
)
var resultValues: [T] = []
for component in components {
guard let value = T.from(string: String(component)) else {
let description = "Invalid value for '--\(key)': \(unwrappedStringValue)"
return .failure(.usageError(description: description))
}
resultValues.append(value)
}
return .success(resultValues)
case .usage:
return .failure(informativeUsageError(option))
}
}
/// Evaluates the given boolean option in the given mode.
///
/// If parsing command line arguments, and no value was specified on the command
/// line, the option's `defaultValue` is used.
public static func <| <ClientError>(mode: CommandMode, option: Option<Bool>) -> Result<Bool, CommandantError<ClientError>> {
switch mode {
case let .arguments(arguments):
if let value = arguments.consumeBoolean(forKey: option.key) {
return .success(value)
} else {
return .success(option.defaultValue)
}
case .usage:
return .failure(informativeUsageError(option))
}
}
}

View file

@ -1,51 +0,0 @@
/// A poor man's ordered set.
internal struct OrderedSet<T: Hashable> {
fileprivate var values: [T] = []
init<S: Sequence>(_ sequence: S) where S.Element == T {
for e in sequence where !values.contains(e) {
values.append(e)
}
}
@discardableResult
mutating func remove(_ member: T) -> T? {
if let index = values.index(of: member) {
return values.remove(at: index)
} else {
return nil
}
}
}
extension OrderedSet: Equatable {
static func == (_ lhs: OrderedSet, rhs: OrderedSet) -> Bool {
return lhs.values == rhs.values
}
}
extension OrderedSet: Collection {
subscript(position: Int) -> T {
return values[position]
}
var count: Int {
return values.count
}
var isEmpty: Bool {
return values.isEmpty
}
var startIndex: Int {
return values.startIndex
}
var endIndex: Int {
return values.endIndex
}
func index(after i: Int) -> Int {
return values.index(after: i)
}
}

View file

@ -1,68 +0,0 @@
//
// Switch.swift
// Commandant
//
// Created by Neil Pankey on 3/31/15.
// Copyright (c) 2015 Carthage. All rights reserved.
//
/// Describes a parameterless command line flag that defaults to false and can only
/// be switched on. Canonical examples include `--force` and `--recurse`.
///
/// For a boolean toggle that can be enabled and disabled use `Option<Bool>`.
public struct Switch {
/// The key that enables this switch. For example, a key of `verbose` would be
/// used for a `--verbose` option.
public let key: String
/// Optional single letter flag that enables this switch. For example, `-v` would
/// be used as a shorthand for `--verbose`.
///
/// Multiple flags can be grouped together as a single argument and will split
/// when parsing (e.g. `rm -rf` treats 'r' and 'f' as inidividual flags).
public let flag: Character?
/// A human-readable string describing the purpose of this option. This will
/// be shown in help messages.
public let usage: String
public init(flag: Character? = nil, key: String, usage: String) {
self.flag = flag
self.key = key
self.usage = usage
}
}
extension Switch: CustomStringConvertible {
public var description: String {
var options = "--\(key)"
if let flag = self.flag {
options += "|-\(flag)"
}
return options
}
}
// MARK: - Operators
extension CommandMode {
/// Evaluates the given boolean switch in the given mode.
///
/// If parsing command line arguments, and no value was specified on the command
/// line, the option's `defaultValue` is used.
public static func <| <ClientError> (mode: CommandMode, option: Switch) -> Result<Bool, CommandantError<ClientError>> {
switch mode {
case let .arguments(arguments):
var enabled = arguments.consume(key: option.key)
if let flag = option.flag, !enabled {
enabled = arguments.consumeBoolean(flag: flag)
}
return .success(enabled)
case .usage:
return .failure(informativeUsageError(option.description, usage: option.usage))
}
}
}

View file

@ -1,8 +0,0 @@
// Copyright (c) 2015 Rob Rix. All rights reserved.
/// Project version number for Result.
extern double ResultVersionNumber;
/// Project version string for Result.
extern const unsigned char ResultVersionString[];

View file

@ -1,276 +0,0 @@
// Copyright (c) 2015 Rob Rix. All rights reserved.
/// An enum representing either a failure with an explanatory error, or a success with a result value.
public enum Result<T, Error: Swift.Error>: ResultProtocol, CustomStringConvertible, CustomDebugStringConvertible {
case success(T)
case failure(Error)
// MARK: Constructors
/// Constructs a success wrapping a `value`.
public init(value: T) {
self = .success(value)
}
/// Constructs a failure wrapping an `error`.
public init(error: Error) {
self = .failure(error)
}
/// Constructs a result from an `Optional`, failing with `Error` if `nil`.
public init(_ value: T?, failWith: @autoclosure () -> Error) {
self = value.map(Result.success) ?? .failure(failWith())
}
/// Constructs a result from a function that uses `throw`, failing with `Error` if throws.
public init(_ f: @autoclosure () throws -> T) {
self.init(attempt: f)
}
/// Constructs a result from a function that uses `throw`, failing with `Error` if throws.
public init(attempt f: () throws -> T) {
do {
self = .success(try f())
} catch var error {
if Error.self == AnyError.self {
error = AnyError(error)
}
self = .failure(error as! Error)
}
}
// MARK: Deconstruction
/// Returns the value from `success` Results or `throw`s the error.
public func dematerialize() throws -> T {
switch self {
case let .success(value):
return value
case let .failure(error):
throw error
}
}
/// Case analysis for Result.
///
/// Returns the value produced by applying `ifFailure` to `failure` Results, or `ifSuccess` to `success` Results.
public func analysis<Result>(ifSuccess: (T) -> Result, ifFailure: (Error) -> Result) -> Result {
switch self {
case let .success(value):
return ifSuccess(value)
case let .failure(value):
return ifFailure(value)
}
}
// MARK: Errors
/// The domain for errors constructed by Result.
public static var errorDomain: String { return "com.antitypical.Result" }
/// The userInfo key for source functions in errors constructed by Result.
public static var functionKey: String { return "\(errorDomain).function" }
/// The userInfo key for source file paths in errors constructed by Result.
public static var fileKey: String { return "\(errorDomain).file" }
/// The userInfo key for source file line numbers in errors constructed by Result.
public static var lineKey: String { return "\(errorDomain).line" }
/// Constructs an error.
public static func error(_ message: String? = nil, function: String = #function, file: String = #file, line: Int = #line) -> NSError {
var userInfo: [String: Any] = [
functionKey: function,
fileKey: file,
lineKey: line,
]
if let message = message {
userInfo[NSLocalizedDescriptionKey] = message
}
return NSError(domain: errorDomain, code: 0, userInfo: userInfo)
}
// MARK: CustomStringConvertible
public var description: String {
return analysis(
ifSuccess: { ".success(\($0))" },
ifFailure: { ".failure(\($0))" })
}
// MARK: CustomDebugStringConvertible
public var debugDescription: String {
return description
}
}
// MARK: - Derive result from failable closure
public func materialize<T>(_ f: () throws -> T) -> Result<T, AnyError> {
return materialize(try f())
}
public func materialize<T>(_ f: @autoclosure () throws -> T) -> Result<T, AnyError> {
do {
return .success(try f())
} catch {
return .failure(AnyError(error))
}
}
@available(*, deprecated, message: "Use the overload which returns `Result<T, AnyError>` instead")
public func materialize<T>(_ f: () throws -> T) -> Result<T, NSError> {
return materialize(try f())
}
@available(*, deprecated, message: "Use the overload which returns `Result<T, AnyError>` instead")
public func materialize<T>(_ f: @autoclosure () throws -> T) -> Result<T, NSError> {
do {
return .success(try f())
} catch {
// This isn't great, but it lets us maintain compatibility until this deprecated
// method can be removed.
#if _runtime(_ObjC)
return .failure(error as NSError)
#else
// https://github.com/apple/swift-corelibs-foundation/blob/swift-3.0.2-RELEASE/Foundation/NSError.swift#L314
let userInfo = _swift_Foundation_getErrorDefaultUserInfo(error) as? [String: Any]
let nsError = NSError(domain: error._domain, code: error._code, userInfo: userInfo)
return .failure(nsError)
#endif
}
}
// MARK: - Cocoa API conveniences
#if !os(Linux)
/// Constructs a `Result` with the result of calling `try` with an error pointer.
///
/// This is convenient for wrapping Cocoa API which returns an object or `nil` + an error, by reference. e.g.:
///
/// Result.try { NSData(contentsOfURL: URL, options: .dataReadingMapped, error: $0) }
@available(*, deprecated, message: "This will be removed in Result 4.0. Use `Result.init(attempt:)` instead. See https://github.com/antitypical/Result/issues/85 for the details.")
public func `try`<T>(_ function: String = #function, file: String = #file, line: Int = #line, `try`: (NSErrorPointer) -> T?) -> Result<T, NSError> {
var error: NSError?
return `try`(&error).map(Result.success) ?? .failure(error ?? Result<T, NSError>.error(function: function, file: file, line: line))
}
/// Constructs a `Result` with the result of calling `try` with an error pointer.
///
/// This is convenient for wrapping Cocoa API which returns a `Bool` + an error, by reference. e.g.:
///
/// Result.try { NSFileManager.defaultManager().removeItemAtURL(URL, error: $0) }
@available(*, deprecated, message: "This will be removed in Result 4.0. Use `Result.init(attempt:)` instead. See https://github.com/antitypical/Result/issues/85 for the details.")
public func `try`(_ function: String = #function, file: String = #file, line: Int = #line, `try`: (NSErrorPointer) -> Bool) -> Result<(), NSError> {
var error: NSError?
return `try`(&error) ?
.success(())
: .failure(error ?? Result<(), NSError>.error(function: function, file: file, line: line))
}
#endif
// MARK: - ErrorConvertible conformance
extension NSError: ErrorConvertible {
public static func error(from error: Swift.Error) -> Self {
func cast<T: NSError>(_ error: Swift.Error) -> T {
return error as! T
}
return cast(error)
}
}
// MARK: - Errors
/// An error that is impossible to construct.
///
/// This can be used to describe `Result`s where failures will never
/// be generated. For example, `Result<Int, NoError>` describes a result that
/// contains an `Int`eger and is guaranteed never to be a `failure`.
public enum NoError: Swift.Error, Equatable {
public static func ==(lhs: NoError, rhs: NoError) -> Bool {
return true
}
}
/// A type-erased error which wraps an arbitrary error instance. This should be
/// useful for generic contexts.
public struct AnyError: Swift.Error {
/// The underlying error.
public let error: Swift.Error
public init(_ error: Swift.Error) {
if let anyError = error as? AnyError {
self = anyError
} else {
self.error = error
}
}
}
extension AnyError: ErrorConvertible {
public static func error(from error: Error) -> AnyError {
return AnyError(error)
}
}
extension AnyError: CustomStringConvertible {
public var description: String {
return String(describing: error)
}
}
// There appears to be a bug in Foundation on Linux which prevents this from working:
// https://bugs.swift.org/browse/SR-3565
// Don't forget to comment the tests back in when removing this check when it's fixed!
#if !os(Linux)
extension AnyError: LocalizedError {
public var errorDescription: String? {
return error.localizedDescription
}
public var failureReason: String? {
return (error as? LocalizedError)?.failureReason
}
public var helpAnchor: String? {
return (error as? LocalizedError)?.helpAnchor
}
public var recoverySuggestion: String? {
return (error as? LocalizedError)?.recoverySuggestion
}
}
#endif
// MARK: - migration support
extension Result {
@available(*, unavailable, renamed: "success")
public static func Success(_: T) -> Result<T, Error> {
fatalError()
}
@available(*, unavailable, renamed: "failure")
public static func Failure(_: Error) -> Result<T, Error> {
fatalError()
}
}
extension NSError {
@available(*, unavailable, renamed: "error(from:)")
public static func errorFromErrorType(_ error: Swift.Error) -> Self {
fatalError()
}
}
import Foundation

View file

@ -1,203 +0,0 @@
// Copyright (c) 2015 Rob Rix. All rights reserved.
/// A type that can represent either failure with an error or success with a result value.
public protocol ResultProtocol {
associatedtype Value
associatedtype Error: Swift.Error
/// Constructs a successful result wrapping a `value`.
init(value: Value)
/// Constructs a failed result wrapping an `error`.
init(error: Error)
/// Case analysis for ResultProtocol.
///
/// Returns the value produced by appliying `ifFailure` to the error if self represents a failure, or `ifSuccess` to the result value if self represents a success.
func analysis<U>(ifSuccess: (Value) -> U, ifFailure: (Error) -> U) -> U
/// Returns the value if self represents a success, `nil` otherwise.
///
/// A default implementation is provided by a protocol extension. Conforming types may specialize it.
var value: Value? { get }
/// Returns the error if self represents a failure, `nil` otherwise.
///
/// A default implementation is provided by a protocol extension. Conforming types may specialize it.
var error: Error? { get }
}
public extension ResultProtocol {
/// Returns the value if self represents a success, `nil` otherwise.
public var value: Value? {
return analysis(ifSuccess: { $0 }, ifFailure: { _ in nil })
}
/// Returns the error if self represents a failure, `nil` otherwise.
public var error: Error? {
return analysis(ifSuccess: { _ in nil }, ifFailure: { $0 })
}
/// Returns a new Result by mapping `Success`es values using `transform`, or re-wrapping `Failure`s errors.
public func map<U>(_ transform: (Value) -> U) -> Result<U, Error> {
return flatMap { .success(transform($0)) }
}
/// Returns the result of applying `transform` to `Success`es values, or re-wrapping `Failure`s errors.
public func flatMap<U>(_ transform: (Value) -> Result<U, Error>) -> Result<U, Error> {
return analysis(
ifSuccess: transform,
ifFailure: Result<U, Error>.failure)
}
/// Returns a Result with a tuple of the receiver and `other` values if both
/// are `Success`es, or re-wrapping the error of the earlier `Failure`.
public func fanout<R: ResultProtocol>(_ other: @autoclosure () -> R) -> Result<(Value, R.Value), Error>
where Error == R.Error
{
return self.flatMap { left in other().map { right in (left, right) } }
}
/// Returns a new Result by mapping `Failure`'s values using `transform`, or re-wrapping `Success`es values.
public func mapError<Error2>(_ transform: (Error) -> Error2) -> Result<Value, Error2> {
return flatMapError { .failure(transform($0)) }
}
/// Returns the result of applying `transform` to `Failure`s errors, or re-wrapping `Success`es values.
public func flatMapError<Error2>(_ transform: (Error) -> Result<Value, Error2>) -> Result<Value, Error2> {
return analysis(
ifSuccess: Result<Value, Error2>.success,
ifFailure: transform)
}
/// Returns a new Result by mapping `Success`es values using `success`, and by mapping `Failure`'s values using `failure`.
public func bimap<U, Error2>(success: (Value) -> U, failure: (Error) -> Error2) -> Result<U, Error2> {
return analysis(
ifSuccess: { .success(success($0)) },
ifFailure: { .failure(failure($0)) }
)
}
}
public extension ResultProtocol {
// MARK: Higher-order functions
/// Returns `self.value` if this result is a .Success, or the given value otherwise. Equivalent with `??`
public func recover(_ value: @autoclosure () -> Value) -> Value {
return self.value ?? value()
}
/// Returns this result if it is a .Success, or the given result otherwise. Equivalent with `??`
public func recover(with result: @autoclosure () -> Self) -> Self {
return analysis(
ifSuccess: { _ in self },
ifFailure: { _ in result() })
}
}
/// Protocol used to constrain `tryMap` to `Result`s with compatible `Error`s.
public protocol ErrorConvertible: Swift.Error {
static func error(from error: Swift.Error) -> Self
}
public extension ResultProtocol where Error: ErrorConvertible {
/// Returns the result of applying `transform` to `Success`es values, or wrapping thrown errors.
public func tryMap<U>(_ transform: (Value) throws -> U) -> Result<U, Error> {
return flatMap { value in
do {
return .success(try transform(value))
}
catch {
let convertedError = Error.error(from: error)
// Revisit this in a future version of Swift. https://twitter.com/jckarter/status/672931114944696321
return .failure(convertedError)
}
}
}
}
// MARK: - Operators
infix operator &&& : LogicalConjunctionPrecedence
/// Returns a Result with a tuple of `left` and `right` values if both are `Success`es, or re-wrapping the error of the earlier `Failure`.
@available(*, deprecated, renamed: "ResultProtocol.fanout(self:_:)")
public func &&& <L: ResultProtocol, R: ResultProtocol> (left: L, right: @autoclosure () -> R) -> Result<(L.Value, R.Value), L.Error>
where L.Error == R.Error
{
return left.fanout(right)
}
precedencegroup ChainingPrecedence {
associativity: left
higherThan: TernaryPrecedence
}
infix operator >>- : ChainingPrecedence
/// Returns the result of applying `transform` to `Success`es values, or re-wrapping `Failure`s errors.
///
/// This is a synonym for `flatMap`.
@available(*, deprecated, renamed: "ResultProtocol.flatMap(self:_:)")
public func >>- <T: ResultProtocol, U> (result: T, transform: (T.Value) -> Result<U, T.Error>) -> Result<U, T.Error> {
return result.flatMap(transform)
}
/// Returns `true` if `left` and `right` are both `Success`es and their values are equal, or if `left` and `right` are both `Failure`s and their errors are equal.
public func == <T: ResultProtocol> (left: T, right: T) -> Bool
where T.Value: Equatable, T.Error: Equatable
{
if let left = left.value, let right = right.value {
return left == right
} else if let left = left.error, let right = right.error {
return left == right
}
return false
}
/// Returns `true` if `left` and `right` represent different cases, or if they represent the same case but different values.
public func != <T: ResultProtocol> (left: T, right: T) -> Bool
where T.Value: Equatable, T.Error: Equatable
{
return !(left == right)
}
/// Returns the value of `left` if it is a `Success`, or `right` otherwise. Short-circuits.
public func ?? <T: ResultProtocol> (left: T, right: @autoclosure () -> T.Value) -> T.Value {
return left.recover(right())
}
/// Returns `left` if it is a `Success`es, or `right` otherwise. Short-circuits.
public func ?? <T: ResultProtocol> (left: T, right: @autoclosure () -> T) -> T {
return left.recover(with: right())
}
// MARK: - migration support
@available(*, unavailable, renamed: "ResultProtocol")
public typealias ResultType = ResultProtocol
@available(*, unavailable, renamed: "Error")
public typealias ResultErrorType = Swift.Error
@available(*, unavailable, renamed: "ErrorConvertible")
public typealias ErrorTypeConvertible = ErrorConvertible
@available(*, deprecated, renamed: "ErrorConvertible")
public protocol ErrorProtocolConvertible: ErrorConvertible {}
extension ResultProtocol {
@available(*, unavailable, renamed: "recover(with:)")
public func recoverWith(_ result: @autoclosure () -> Self) -> Self {
fatalError()
}
}
extension ErrorConvertible {
@available(*, unavailable, renamed: "error(from:)")
public static func errorFromErrorType(_ error: Swift.Error) -> Self {
fatalError()
}
}

View file

@ -1,6 +0,0 @@
---
SEEDS:
- Commandant (0.13.0)
- Result (3.2.4)
- Nimble (v7.0.3)
- Quick (v1.2.0)

View file

@ -7,30 +7,11 @@
objects = {
/* Begin PBXBuildFile section */
073998C12AE3BEEC41CE0DAD /* OrderedSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9871C2273F4D762A1F19B07 /* OrderedSet.swift */; };
09756A23E9102359296C821B /* ResultProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5150F7FB7CF2A77F675D8E92 /* ResultProtocol.swift */; };
09A04CB22DC02B86AE4ACC8A /* ArgumentParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9D96DDBBCCCC5944160ABE /* ArgumentParser.swift */; };
0C47E694564FCB59996690DD /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E4D331CCD66ADFE19CE39 /* Command.swift */; };
0EBF5CDD379D7462C3389536 /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9257C5FABA335E5F060CB7F7 /* Result.swift */; };
15E27926A580EABEB1B218EF /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1B6BEDF32AF3F8A575FB1F /* Switch.swift */; };
27340A5BB9F2A5B166E3A72A /* ArgumentProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4237E5AA1A289D03D2A2FB8 /* ArgumentProtocol.swift */; };
3053D11E74A22A4C5A6BE833 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = F547B3DC473CFB1BE0AEB70A /* Errors.swift */; };
30EA893640B02CCF679F9C57 /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD7FE171F643805F7BC38A7 /* Option.swift */; };
3F177C62A7053BA3ED415E5E /* Argument.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36A4ABD8025E13060312925 /* Argument.swift */; };
4913269B1F48921D0010EB86 /* CKSoftwareMap+AppLookup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4913269A1F48921D0010EB86 /* CKSoftwareMap+AppLookup.swift */; };
49C2F3FDD805256BE934A70E /* Switch.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1B6BEDF32AF3F8A575FB1F /* Switch.swift */; };
4C8321353B9AE40539A1AC8A /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = F547B3DC473CFB1BE0AEB70A /* Errors.swift */; };
693A98991CBFFA760004D3B4 /* Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693A98981CBFFA760004D3B4 /* Search.swift */; };
693A989B1CBFFAAA0004D3B4 /* NSURLSession+Synchronous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 693A989A1CBFFAAA0004D3B4 /* NSURLSession+Synchronous.swift */; };
8078FAA81EC4F2FB004B5B3F /* Lucky.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8078FAA71EC4F2FB004B5B3F /* Lucky.swift */; };
900A1E811DBAC8CB0069B1A8 /* Info.swift in Sources */ = {isa = PBXBuildFile; fileRef = 900A1E801DBAC8CB0069B1A8 /* Info.swift */; };
92AE0FD7BE06D64692E6C1E6 /* OrderedSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9871C2273F4D762A1F19B07 /* OrderedSet.swift */; };
AD0785BC0EC6BBF4ED560DCC /* ArgumentParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA9D96DDBBCCCC5944160ABE /* ArgumentParser.swift */; };
ADE553C828AF4EAFF39ED3E1 /* ArgumentProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = B4237E5AA1A289D03D2A2FB8 /* ArgumentProtocol.swift */; };
C50DD25454FC5CAA1F37763F /* Result.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9257C5FABA335E5F060CB7F7 /* Result.swift */; };
DE6E193A6671F3D6807F746D /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = 326E4D331CCD66ADFE19CE39 /* Command.swift */; };
EBD6B44FDF65E0253153629F /* HelpCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FDC2B8063EC231E28353D23 /* HelpCommand.swift */; };
EC113CE6C98E8D8358228D33 /* ResultProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5150F7FB7CF2A77F675D8E92 /* ResultProtocol.swift */; };
ED031A7C1B5127C00097692E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED031A7B1B5127C00097692E /* main.swift */; };
ED0F237F1B87522400AE40CD /* Install.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F237E1B87522400AE40CD /* Install.swift */; };
ED0F23831B87533A00AE40CD /* List.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F23821B87533A00AE40CD /* List.swift */; };
@ -49,9 +30,6 @@
EDE296531C700F4300554778 /* SignOut.swift in Sources */ = {isa = PBXBuildFile; fileRef = EDE296521C700F4300554778 /* SignOut.swift */; };
EDEAA0C01B51CE6200F2FC3F /* StoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDEAA0BF1B51CE6200F2FC3F /* StoreFoundation.framework */; };
EDEAA17D1B5C579100F2FC3F /* CommerceKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDEAA17C1B5C579100F2FC3F /* CommerceKit.framework */; };
F184B6B7CD9C013CACDED0FB /* Argument.swift in Sources */ = {isa = PBXBuildFile; fileRef = F36A4ABD8025E13060312925 /* Argument.swift */; };
F48562FA81B0C0258AC063B4 /* HelpCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FDC2B8063EC231E28353D23 /* HelpCommand.swift */; };
F6D2058A70757D3477185A50 /* Option.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2AD7FE171F643805F7BC38A7 /* Option.swift */; };
F865880B2030F6DE0093DE57 /* MASErrorTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F865880A2030F6DE0093DE57 /* MASErrorTestCase.swift */; };
F86588272030FAE70093DE57 /* MASError.swift in Sources */ = {isa = PBXBuildFile; fileRef = ED0F238C1B8756E600AE40CD /* MASError.swift */; };
/* End PBXBuildFile section */
@ -79,20 +57,11 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
2AD7FE171F643805F7BC38A7 /* Option.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Option.swift; path = Seeds/Commandant/Sources/Commandant/Option.swift; sourceTree = "<group>"; };
326E4D331CCD66ADFE19CE39 /* Command.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Command.swift; path = Seeds/Commandant/Sources/Commandant/Command.swift; sourceTree = "<group>"; };
4913269A1F48921D0010EB86 /* CKSoftwareMap+AppLookup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CKSoftwareMap+AppLookup.swift"; sourceTree = "<group>"; };
5150F7FB7CF2A77F675D8E92 /* ResultProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ResultProtocol.swift; path = Seeds/Result/Result/ResultProtocol.swift; sourceTree = "<group>"; };
693A98981CBFFA760004D3B4 /* Search.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Search.swift; sourceTree = "<group>"; };
693A989A1CBFFAAA0004D3B4 /* NSURLSession+Synchronous.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSURLSession+Synchronous.swift"; sourceTree = "<group>"; };
8078FAA71EC4F2FB004B5B3F /* Lucky.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Lucky.swift; sourceTree = "<group>"; };
8FDC2B8063EC231E28353D23 /* HelpCommand.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HelpCommand.swift; path = Seeds/Commandant/Sources/Commandant/HelpCommand.swift; sourceTree = "<group>"; };
900A1E801DBAC8CB0069B1A8 /* Info.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Info.swift; sourceTree = "<group>"; };
9257C5FABA335E5F060CB7F7 /* Result.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Result.swift; path = Seeds/Result/Result/Result.swift; sourceTree = "<group>"; };
AF1B6BEDF32AF3F8A575FB1F /* Switch.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Switch.swift; path = Seeds/Commandant/Sources/Commandant/Switch.swift; sourceTree = "<group>"; };
B4237E5AA1A289D03D2A2FB8 /* ArgumentProtocol.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ArgumentProtocol.swift; path = Seeds/Commandant/Sources/Commandant/ArgumentProtocol.swift; sourceTree = "<group>"; };
D9871C2273F4D762A1F19B07 /* OrderedSet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = OrderedSet.swift; path = Seeds/Commandant/Sources/Commandant/OrderedSet.swift; sourceTree = "<group>"; };
EA9D96DDBBCCCC5944160ABE /* ArgumentParser.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ArgumentParser.swift; path = Seeds/Commandant/Sources/Commandant/ArgumentParser.swift; sourceTree = "<group>"; };
ED031A781B5127C00097692E /* mas */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mas; sourceTree = BUILT_PRODUCTS_DIR; };
ED031A7B1B5127C00097692E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
ED0F237E1B87522400AE40CD /* Install.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Install.swift; sourceTree = "<group>"; };
@ -137,8 +106,6 @@
EDEAA1551B5C576D00F2FC3F /* CKUpdateController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKUpdateController.h; sourceTree = "<group>"; };
EDEAA1661B5C576D00F2FC3F /* ISStoreURLOperationDelegate-Protocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ISStoreURLOperationDelegate-Protocol.h"; sourceTree = "<group>"; };
EDEAA17C1B5C579100F2FC3F /* CommerceKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CommerceKit.framework; path = /System/Library/PrivateFrameworks/CommerceKit.framework; sourceTree = "<absolute>"; };
F36A4ABD8025E13060312925 /* Argument.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Argument.swift; path = Seeds/Commandant/Sources/Commandant/Argument.swift; sourceTree = "<group>"; };
F547B3DC473CFB1BE0AEB70A /* Errors.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Errors.swift; path = Seeds/Commandant/Sources/Commandant/Errors.swift; sourceTree = "<group>"; };
F8233C87201EBDF000268278 /* mas-tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "mas-tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
F8233C8B201EBDF100268278 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F865880A2030F6DE0093DE57 /* MASErrorTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MASErrorTestCase.swift; sourceTree = "<group>"; };
@ -164,56 +131,6 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
0739FA024AB80925B32D64D1 /* Seeds */ = {
isa = PBXGroup;
children = (
A49C8EB621015CD588C621FD /* Commandant */,
A96B40B5852A4F029AFDA669 /* Nimble */,
6EB4B681BB79E32622860164 /* Quick */,
6569B225928F21A4A639BB22 /* Result */,
);
name = Seeds;
sourceTree = "<group>";
};
6569B225928F21A4A639BB22 /* Result */ = {
isa = PBXGroup;
children = (
9257C5FABA335E5F060CB7F7 /* Result.swift */,
5150F7FB7CF2A77F675D8E92 /* ResultProtocol.swift */,
);
name = Result;
sourceTree = "<group>";
};
6EB4B681BB79E32622860164 /* Quick */ = {
isa = PBXGroup;
children = (
);
name = Quick;
sourceTree = "<group>";
};
A49C8EB621015CD588C621FD /* Commandant */ = {
isa = PBXGroup;
children = (
F36A4ABD8025E13060312925 /* Argument.swift */,
EA9D96DDBBCCCC5944160ABE /* ArgumentParser.swift */,
B4237E5AA1A289D03D2A2FB8 /* ArgumentProtocol.swift */,
326E4D331CCD66ADFE19CE39 /* Command.swift */,
F547B3DC473CFB1BE0AEB70A /* Errors.swift */,
8FDC2B8063EC231E28353D23 /* HelpCommand.swift */,
2AD7FE171F643805F7BC38A7 /* Option.swift */,
D9871C2273F4D762A1F19B07 /* OrderedSet.swift */,
AF1B6BEDF32AF3F8A575FB1F /* Switch.swift */,
);
name = Commandant;
sourceTree = "<group>";
};
A96B40B5852A4F029AFDA669 /* Nimble */ = {
isa = PBXGroup;
children = (
);
name = Nimble;
sourceTree = "<group>";
};
ED031A6F1B5127C00097692E = {
isa = PBXGroup;
children = (
@ -222,7 +139,6 @@
EDFC76381B642A2E00D0DBD7 /* Frameworks */,
EDEAA0C11B51CEBD00F2FC3F /* PrivateHeaders */,
ED031A791B5127C00097692E /* Products */,
0739FA024AB80925B32D64D1 /* Seeds */,
);
sourceTree = "<group>";
};
@ -448,14 +364,8 @@
buildActionMask = 2147483647;
files = (
ED0F23871B87537200AE40CD /* Account.swift in Sources */,
F184B6B7CD9C013CACDED0FB /* Argument.swift in Sources */,
AD0785BC0EC6BBF4ED560DCC /* ArgumentParser.swift in Sources */,
ADE553C828AF4EAFF39ED3E1 /* ArgumentProtocol.swift in Sources */,
4913269B1F48921D0010EB86 /* CKSoftwareMap+AppLookup.swift in Sources */,
0C47E694564FCB59996690DD /* Command.swift in Sources */,
ED0F238B1B87569C00AE40CD /* Downloader.swift in Sources */,
3053D11E74A22A4C5A6BE833 /* Errors.swift in Sources */,
EBD6B44FDF65E0253153629F /* HelpCommand.swift in Sources */,
900A1E811DBAC8CB0069B1A8 /* Info.swift in Sources */,
ED0F237F1B87522400AE40CD /* Install.swift in Sources */,
ED0F23901B87A56F00AE40CD /* ISStoreAccount.swift in Sources */,
@ -464,18 +374,13 @@
ED031A7C1B5127C00097692E /* main.swift in Sources */,
ED0F238D1B8756E600AE40CD /* MASError.swift in Sources */,
693A989B1CBFFAAA0004D3B4 /* NSURLSession+Synchronous.swift in Sources */,
30EA893640B02CCF679F9C57 /* Option.swift in Sources */,
92AE0FD7BE06D64692E6C1E6 /* OrderedSet.swift in Sources */,
ED0F23851B87536A00AE40CD /* Outdated.swift in Sources */,
ED0F23891B87543D00AE40CD /* PurchaseDownloadObserver.swift in Sources */,
EDCBF9531D89AC6F000039C6 /* Reset.swift in Sources */,
0EBF5CDD379D7462C3389536 /* Result.swift in Sources */,
09756A23E9102359296C821B /* ResultProtocol.swift in Sources */,
693A98991CBFFA760004D3B4 /* Search.swift in Sources */,
EDC90B651C70045E0019E396 /* SignIn.swift in Sources */,
EDE296531C700F4300554778 /* SignOut.swift in Sources */,
EDA3BE521B8B84AF00C18D70 /* SSPurchase.swift in Sources */,
15E27926A580EABEB1B218EF /* Switch.swift in Sources */,
EDD3B3631C34709400B56B88 /* Upgrade.swift in Sources */,
EDCBF9551D89CFC7000039C6 /* Utilities.swift in Sources */,
EDB6CE8C1BAEC3D400648B4D /* Version.swift in Sources */,
@ -486,19 +391,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3F177C62A7053BA3ED415E5E /* Argument.swift in Sources */,
09A04CB22DC02B86AE4ACC8A /* ArgumentParser.swift in Sources */,
27340A5BB9F2A5B166E3A72A /* ArgumentProtocol.swift in Sources */,
DE6E193A6671F3D6807F746D /* Command.swift in Sources */,
4C8321353B9AE40539A1AC8A /* Errors.swift in Sources */,
F48562FA81B0C0258AC063B4 /* HelpCommand.swift in Sources */,
F86588272030FAE70093DE57 /* MASError.swift in Sources */,
F865880B2030F6DE0093DE57 /* MASErrorTestCase.swift in Sources */,
F6D2058A70757D3477185A50 /* Option.swift in Sources */,
073998C12AE3BEEC41CE0DAD /* OrderedSet.swift in Sources */,
C50DD25454FC5CAA1F37763F /* Result.swift in Sources */,
EC113CE6C98E8D8358228D33 /* ResultProtocol.swift in Sources */,
49C2F3FDD805256BE934A70E /* Switch.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};