0001    //
0002    //  Option.swift
0003    //  Commandant
0004    //
0005    //  Created by Justin Spahr-Summers on 2014-11-21.
0006    //  Copyright (c) 2014 Carthage. All rights reserved.
0007    //
0008    
0009    import Foundation
0010    import Result
0011    
0012    /// Represents a record of options for a command, which can be parsed from
0013    /// a list of command-line arguments.
0014    ///
0015    /// This is most helpful when used in conjunction with the `Option` and `Switch`
0016    /// types, and `<*>` and `<|` combinators.
0017    ///
0018    /// Example:
0019    ///
0020    ///		struct LogOptions: OptionsType {
0021    ///			let verbosity: Int
0022    ///			let outputFilename: String
0023    ///			let logName: String
0024    ///
0025    ///			static func create(verbosity: Int)(outputFilename: String)(logName: String) -> LogOptions {
0026    ///				return LogOptions(verbosity: verbosity, outputFilename: outputFilename, logName: logName)
0027    ///			}
0028    ///
0029    ///			static func evaluate(m: CommandMode) -> Result<LogOptions, CommandantError<YourErrorType>> {
0030    ///				return create
0031    ///					<*> m <| Option(key: "verbose", defaultValue: 0, usage: "the verbosity level with which to read the logs")
0032    ///					<*> m <| Option(key: "outputFilename", defaultValue: "", usage: "a file to print output to, instead of stdout")
0033    ///					<*> m <| Switch(flag: "d", key: "delete", defaultValue: false, usage: "delete the logs when finished")
0034    ///					<*> m <| Option(usage: "the log to read")
0035    ///			}
0036    ///		}
0037    public protocol OptionsType
HelpCommand.swift:61
public struct HelpOptions<ClientError: ErrorType>: OptionsType {
Option.swift:47
public struct NoOptions<ClientError: ErrorType>: OptionsType {
{ 0038 typealias ClientError
Command.swift:42
	private init<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(_ command: C) {
Command.swift:93
	public func register<C: CommandType where C.ClientError == ClientError, C.Options.ClientError == ClientError>(command: C) {
: ErrorType 0039 0040 /// Evaluates this set of options in the given mode. 0041 /// 0042 /// Returns the parsed options or a `UsageError`. 0043 static func evaluate(m: CommandMode) -> Result<Self, CommandantError<ClientError>> 0044 } 0045 0046 /// An `OptionsType` that has no options. 0047 public struct NoOptions<ClientError: ErrorType>: OptionsType { 0048 public init() {} 0049 0050 public static func evaluate(m: CommandMode) -> Result<NoOptions, CommandantError<ClientError>> { 0051 return .Success(NoOptions()) 0052 } 0053 } 0054 0055 /// Describes an option that can be provided on the command line. 0056 public struct Option
Errors.swift:126
internal func informativeUsageError<T, ClientError>(keyValueExample: String, option: Option<T>) -> CommandantError<ClientError> {
Errors.swift:135
internal func informativeUsageError<T: ArgumentType, ClientError>(option: Option<T>) -> CommandantError<ClientError> {
Errors.swift:153
internal func informativeUsageError<ClientError>(option: Option<Bool>) -> CommandantError<ClientError> {
Option.swift:89
extension Option: CustomStringConvertible {
Option.swift:163
public func <| <T: ArgumentType, ClientError>(mode: CommandMode, option: Option<T>) -> Result<T, CommandantError<ClientError>> {
Option.swift:202
public func <| <ClientError>(mode: CommandMode, option: Option<Bool>) -> Result<Bool, CommandantError<ClientError>> {
<T
Option.swift:65
	public let defaultValue: T?
Option.swift:75
	public init(key: String, defaultValue: T? = nil, usage: String) {
> { 0057 /// The key that controls this option. For example, a key of `verbose` would 0058 /// be used for a `--verbose` option. 0059 public let key
Errors.swift:136
	var example = "--\(option.key) "
Errors.swift:154
	let key = option.key
Option.swift:76
		self.key = key
Option.swift:91
		return "--\(key)"
Option.swift:205
		if let value = arguments.consumeBooleanKey(option.key) {
: String 0060 0061 /// The default value for this option. This is the value that will be used 0062 /// if the option is never explicitly specified on the command line. 0063 /// 0064 /// If this is nil, this option is always required. 0065 public let defaultValue
Errors.swift:127
	if option.defaultValue != nil {
Errors.swift:139
	if let defaultValue = option.defaultValue {
Errors.swift:156
	if let defaultValue = option.defaultValue {
Option.swift:77
		self.defaultValue = defaultValue
Option.swift:207
		} else if let defaultValue = option.defaultValue {
: T? 0066 0067 /// A human-readable string describing the purpose of this option. This will 0068 /// be shown in help messages. 0069 /// 0070 /// For boolean operations, this should describe the effect of _not_ using 0071 /// the default value (i.e., what will happen if you disable/enable the flag 0072 /// differently from the default). 0073 public let usage
Errors.swift:128
		return informativeUsageError("[\(keyValueExample)]", usage: option.usage)
Errors.swift:130
		return informativeUsageError(keyValueExample, usage: option.usage)
Option.swift:78
		self.usage = usage
: String 0074 0075 public init(key: String, defaultValue: T? = nil, usage: String) { 0076 self.key = key 0077 self.defaultValue = defaultValue 0078 self.usage = usage 0079 } 0080 0081 /// Constructs an `InvalidArgument` error that describes how the option was 0082 /// used incorrectly. `value` should be the invalid value given by the user. 0083 private func invalidUsageError<ClientError>(value: String) -> CommandantError<ClientError> { 0084 let description = "Invalid value for '\(self)': \(value)" 0085 return .UsageError(description: description) 0086 } 0087 } 0088 0089 extension Option: CustomStringConvertible { 0090 public var description: String { 0091 return "--\(key)" 0092 } 0093 } 0094 0095 // Inspired by the Argo library: 0096 // https://github.com/thoughtbot/Argo 0097 /* 0098 Copyright (c) 2014 thoughtbot, inc. 0099 0100 MIT License 0101 0102 Permission is hereby granted, free of charge, to any person obtaining 0103 a copy of this software and associated documentation files (the 0104 "Software"), to deal in the Software without restriction, including 0105 without limitation the rights to use, copy, modify, merge, publish, 0106 distribute, sublicense, and/or sell copies of the Software, and to 0107 permit persons to whom the Software is furnished to do so, subject to 0108 the following conditions: 0109 0110 The above copyright notice and this permission notice shall be 0111 included in all copies or substantial portions of the Software. 0112 0113 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 0114 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 0115 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 0116 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 0117 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 0118 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 0119 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0120 */ 0121 infix operator <*> { 0122 associativity left 0123 } 0124 0125 infix operator <| { 0126 associativity left 0127 precedence 150 0128 } 0129 0130 /// Applies `f` to the value in the given result. 0131 /// 0132 /// In the context of command-line option parsing, this is used to chain 0133 /// together the parsing of multiple arguments. See OptionsType for an example. 0134 public func <*> <T, U, ClientError>(f: T -> U, value: Result<T, CommandantError<ClientError>>) -> Result<U, CommandantError<ClientError>> { 0135 return value.map(f) 0136 } 0137 0138 /// Applies the function in `f` to the value in the given result. 0139 /// 0140 /// In the context of command-line option parsing, this is used to chain 0141 /// together the parsing of multiple arguments. See OptionsType for an example. 0142 public func <*> <T, U, ClientError>(f: Result<(T -> U), CommandantError<ClientError>>, value: Result<T, CommandantError<ClientError>>) -> Result<U, CommandantError<ClientError>> { 0143 switch (f, value) { 0144 case let (.Failure(left), .Failure(right)): 0145 return .Failure(combineUsageErrors(left, right)) 0146 0147 case let (.Failure(left), .Success): 0148 return .Failure(left) 0149 0150 case let (.Success, .Failure(right)): 0151 return .Failure(right) 0152 0153 case let (.Success(f), .Success(value)): 0154 let newValue = f(value) 0155 return .Success(newValue) 0156 } 0157 } 0158 0159 /// Evaluates the given option in the given mode. 0160 /// 0161 /// If parsing command line arguments, and no value was specified on the command 0162 /// line, the option's `defaultValue` is used. 0163 public func <| <T: ArgumentType, ClientError>(mode: CommandMode, option: Option<T>) -> Result<T, CommandantError<ClientError>> { 0164 switch mode { 0165 case let .Arguments(arguments): 0166 var stringValue: String? 0167 switch arguments.consumeValueForKey(option.key) { 0168 case let .Success(value): 0169 stringValue = value 0170 0171 case let .Failure(error): 0172 switch error { 0173 case let .UsageError(description): 0174 return .Failure(.UsageError(description: description)) 0175 0176 case .CommandError: 0177 fatalError("CommandError should be impossible when parameterized over NoError") 0178 } 0179 } 0180 0181 if let stringValue = stringValue { 0182 if let value = T.fromString(stringValue) { 0183 return .Success(value) 0184 } 0185 0186 return .Failure(option.invalidUsageError(stringValue)) 0187 } else if let defaultValue = option.defaultValue { 0188 return .Success(defaultValue) 0189 } else { 0190 return .Failure(missingArgumentError(option.description)) 0191 } 0192 0193 case .Usage: 0194 return .Failure(informativeUsageError(option)) 0195 } 0196 } 0197 0198 /// Evaluates the given boolean option in the given mode. 0199 /// 0200 /// If parsing command line arguments, and no value was specified on the command 0201 /// line, the option's `defaultValue` is used. 0202 public func <| <ClientError>(mode: CommandMode, option: Option<Bool>) -> Result<Bool, CommandantError<ClientError>> { 0203 switch mode { 0204 case let .Arguments(arguments): 0205 if let value = arguments.consumeBooleanKey(option.key) { 0206 return .Success(value) 0207 } else if let defaultValue = option.defaultValue { 0208 return .Success(defaultValue) 0209 } else { 0210 return .Failure(missingArgumentError(option.description)) 0211 } 0212 0213 case .Usage: 0214 return .Failure(informativeUsageError(option)) 0215 } 0216 } 0217