1
1
mirror of https://github.com/nsomar/Swiftline.git synced 2024-08-15 16:40:24 +03:00

Adding documentation on the public methods

This commit is contained in:
Omar Abdelhafith 2015-11-10 22:44:34 +00:00
parent 0398426282
commit c642a4cf07
49 changed files with 1428 additions and 641 deletions

6
.gitmodules vendored Normal file
View File

@ -0,0 +1,6 @@
[submodule "Nimble"]
path = Nimble
url = https://github.com/Quick/Nimble.git
[submodule "Quick"]
path = Quick
url = https://github.com/Quick/Quick.git

12
.travis.yml Normal file
View File

@ -0,0 +1,12 @@
sudo: false
language: objective-c
osx_image: xcode7.1
install:
- gem install xcpretty --no-rdoc --no-ri --no-document --quiet
script:
- xctool -project Swiftline.xcodeproj -scheme Swiftline build test -sdk macosx GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES
after_success:
- bash <(curl -s https://codecov.io/bash)

1
Nimble Submodule

@ -0,0 +1 @@
Subproject commit 13d4a2bca41d41e53b1c9681bc2039e5f5bca5fe

13
Podfile
View File

@ -1,13 +0,0 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '8.0'
# Uncomment this line if you're using Swift
use_frameworks!
target 'swiftline' do
end
target 'tests' do
pod 'Quick', '~> 0.8.0'
pod 'Nimble', '~> 3.0.0'
end

View File

@ -1,13 +0,0 @@
PODS:
- Nimble (3.0.0)
- Quick (0.8.0)
DEPENDENCIES:
- Nimble (~> 3.0.0)
- Quick (~> 0.8.0)
SPEC CHECKSUMS:
Nimble: 4c353d43735b38b545cbb4cb91504588eb5de926
Quick: 563d0f6ec5f72e394645adb377708639b7dd38ab
COCOAPODS: 0.39.0

1
Quick Submodule

@ -0,0 +1 @@
Subproject commit a98f8e37867462c8f00fea1a7b255d12f5a4b611

231
Readme.md
View File

@ -1,10 +1,235 @@
# Swiftline
Easier to do command line with swift
## 🏃
[![Build Status](https://travis-ci.org/oarrabi/swiftline.svg?branch=master)](https://travis-ci.org/oarrabi/swiftline)
## Ask, Choose, Agree
Swiftline is a set of tools to help you create command line applications. Swiftline is inspired by [highline](https://github.com/JEG2/highline)
---
Swiftline can be divided to three main parts:
- Colorize; Helps adding colors to strings written to the terminal
- Ask, Choose and agree; Easily create prompt for asking the user more info
- Runner; A quick way to run an external command and read its standard output and standard error.
## Installation
## Usage
## Colorize
Colorize helps styling the strings before printing them to the terminal. You can change the text color, the text background and the text style.
Colorize works by extending `String` struct to add styling to it.
To change the text color, use either `string.f` or `string.foreground`:
```swift
print("Red String".f.Red)
print("Blue String".foreground.Blue)
```
To change the text background color, use either `string.b` or `string.background`:
```swift
print("I have a white background".b.White)
print("My background color is green".background.Green)
```
To change the text background color, use either `string.s` or `string.style`:
```swift
print("I am a bold string".s.Bold)
print("I have an underline".style.Underline)
```
You can compose foreground, background, and style:
```swift
print("I am an underlined red on white string".s.Underline.f.Red.b.White)
```
## Ask, Choose, Agree
Ask, Choose and Agree are used to prompt the user for more information.
### Ask
Ask presents the user with a prompt and waits for the user input.
```swift
let userName = ask("Enter user name?")
```
`userName` will contain the name entered by the user
Ask can be used to ask for value of Int, Double or Float types, to ask for an integer for example:
```swift
let age = ask("How old are you?", type: Int.self)
```
If the user prints something thats not convertible to integer, a new prompt is displayed to him, this prompt will keep displaying until the user enters an Int:
How old are you?
None
You must enter a valid Integer.
? Error
You must enter a valid Integer.
? 5
5
Validations are added by calling `addInvalidCase` on `AskSettings`.
```swift
let name = ask("Who are you?") { settings in
settings.addInvalidCase("Snuffles is not allowed") { value in
value.containsString("Snuffles")
}
}
```
If the user entered `Snuffles` ask will keep displaying the invalid message passed to `addInvalidCase`
Who are you?
Snuffles
Snuffles is not allowed
? Snuffles
Snuffles is not allowed
? Snowball
Your name is Snowball
`AskSettings.confirm` will ask the user to confirm his choice after entering it
```swift
let name = ask("Who are you?") { settings in
settings.confirm = true
}
```
The above will output:
Who are you?
Snuffles
Are you sure? YES
Your name is Snuffles
### Choose
Choose is used to prompt the user to select an item between several possible items.
To display a choice of programming lanaugage for example:
```swift
let choice = choose("Whats your favorite programming language? ",
choices: "Swift", "Objective C", "Ruby", "Python", "Java :S")
```
This will print:
1. Swift
2. Objective C
3. Ruby
4. Python
5. Java :S
Whats your favorite programming language?
The user can either choose the numbers (1..5) or the item itself. If the user enters a wrong input. A prompt will keep showing until the user makes a correct choice
Whats your favorite programming language? JavaScript
You must choose one of [1, 2, 3, 4, 5, Swift, Objective C, Ruby, Python, Java :S].
? BBB
You must choose one of [1, 2, 3, 4, 5, Swift, Objective C, Ruby, Python, Java :S].
? Swift
You selected Swift, good choice!
You can customize the return value for each choice element. For example if you want to get an Int from the choice, you would do this
```swift
let choice = choose("Whats your favorite programming language? ", type: Int.self) { settings in
settings.addChoice("Swift") { 42 }
settings.addChoice("Objective C") { 20 }
}
```
The number on the left can be changed to letters, here is how you could do that:
```siwft
let choice = choose("Whats your favorite programming language? ", type: String.self) { settings in
//choice value will be set to GOOD
settings.addChoice("Swift") { "GOOD" }
//choice value will be set to BAD
settings.addChoice("Java") { "BAD" }
settings.index = .Letters
settings.indexSuffix = " ----> "
}
```
That will print:
a ----> Swift
b ----> Java
Whats your favorite programming language?
### Agree
Agree is used to ask a user for a Yes/No question. It returns a boolean representing the user input.
```swift
let choice = agree("Are you sure you want to `rm -rf /` ?")
```
If the user enters any invalid input, agree will keep prompting him for a Yes/No question
Are you sure you want to `rm -rf /` ? What!
Please enter "yes" or "no".
Are you sure you want to `rm -rf /` ? Wait
Please enter "yes" or "no".
Are you sure you want to `rm -rf /` ? No
You entered false
## Runner
Runner provides a quick, concise way to run an external command and read its standard output and standard error.
To execute a simple command you would do:
```swift
let result = run("ls -all")
print(result.stdout)
```
`result` type is `RunResults`, it contains:
- `exitStatus`: The command exit status
- `stdout`: The standard output for the command executed
- `stderr`: The standard error for the command executed
While `run("command")` can split the arguments by spaces. Some times argument splitting is not trivial. If you have multiple argument to pass to the command to execute, you should use `run(command: String, args: String...)`. The above translates to:
```swift
let result = run("ls", args: "-all")
```
To costumize the run function, you can pass in a customization block:
```swift
let result = run("ls -all") { settings in
settings.dryRun = true
settings.echo = [.Stdout, .Stderr, .Command]
settings.interactive = false
}
```
`settings` is an instance of RunSettings, which contains the following variables:
- `settings.dryRun`: defaults to false. If false, the command is actually run. If true, the command is logged to the stdout paramter of result
- `settings.echo`: Customize the message printed to stdout, `echo` can contain any of the following:
- `EchoSettings.Stdout`: The stdout returned from running the command will be printed to the terminal
- `EchoSettings.Stderr`: The stderr returned from running the command will be printed to the terminal
- `EchoSettings.Command`: The command executed will be printed to the terminal
- `settings.interactive`: defaults to false. If set to true the command will be executed using `system` kernel function and only the exit status will be captured. If set to false, the command will be executed using `NSTask` and both stdout and stderr will be captured.
Set `interactive` to true if you expect the launched command to ask input from the user through the stdin.
`runWithoutCapture("command")` is a quick way to run a command in interactive mode. The return value is the exit code of that command.
### Improvement
- Better documentation
- Add gather (from [highline](https://github.com/JEG2/highline)) to ask function
- Figure out a way to eliminate the need of `interactive`
## Tests
Tests can be found [here](). They can be normally run from the Xcode
.

View File

@ -1,13 +0,0 @@
//
// main.swift
// swiftline
//
// Created by Omar Abdelhafith on 10/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//
import Foundation
let choice = choose("Choose the best programming language? ", choices: "Swift", "Objective", "Ruby", "Python", "Java :S")
print("\nYou choosed " + choice.f.Green)

View File

@ -1,55 +0,0 @@
//
// Chooser.swift
// Choose
//
// Created by Omar Abdelhafith on 03/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//
import Foundation
func choose(prompt: String, choices: String...) -> String {
return choose(prompt, type: String.self) {
for choice in choices {
$0.addChoice(choice) { return choice }
}
}
}
func choose<T>(callback: (ChooseSettings<T> -> Void)) -> T {
let settings = getChooseSettings(callback)
return choose(settings, type: T.self)
}
func choose<T>(prompt: String, type: T.Type, callback: (ChooseSettings<T> -> Void)) -> T {
let settings = getChooseSettings(callback)
settings.promptQuestion = prompt
return choose(settings, type: type)
}
func choose<T>(type: T.Type, callback: (ChooseSettings<T> -> Void)) -> T {
let settings = getChooseSettings(callback)
return choose(settings, type: type)
}
func choose<T>(settings: ChooseSettings<T>, type: T.Type) -> T {
let items = settings.preparePromptItems()
items.forEach { PromptSettings.print($0) }
PromptSettings.print("\(settings.promptQuestion)", terminator: "")
let stringRead = readStringOrEmpty()
return askForValidatedItem(originalValue: stringRead, validator: settings)
}
func getChooseSettings<T>(callback: ChooseSettings<T> -> Void) -> ChooseSettings<T> {
let settings = ChooseSettings<T>()
callback(settings)
return settings
}

28
SwiftLine/Info.plist Normal file
View File

@ -0,0 +1,28 @@
<?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>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2015 Omar Abdelhafith. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@ -1,48 +0,0 @@
//
// ArgConvertible.swift
// ArgConvertible
//
// Created by Omar Abdelhafith on 02/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//
import Foundation
protocol ArgConvertibleType {
static func fromString(string: String) -> Self?
static func typeName() -> String
}
extension Int: ArgConvertibleType {
static func fromString(string: String) -> Int? {
return Int(string)
}
static func typeName() -> String {
return "Integer"
}
}
extension Double: ArgConvertibleType {
static func fromString(string: String) -> Double? {
return Double(string)
}
static func typeName() -> String {
return "Double"
}
}
extension String: ArgConvertibleType {
static func fromString(string: String) -> String? {
return string
}
static func typeName() -> String {
return "String"
}
}

View File

@ -1,25 +0,0 @@
//
// RunSettings.swift
// RunSettings
//
// Created by Omar Abdelhafith on 05/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//
import Foundation
class RunSettings {
var dryRun = false
var echo = EchoSettings.None
var interactive = false
}
struct EchoSettings: OptionSetType {
let rawValue: Int
static var None = EchoSettings(rawValue: 0)
static let Stdout = EchoSettings(rawValue: 1 << 0)
static let Stderr = EchoSettings(rawValue: 1 << 1)
static let Command = EchoSettings(rawValue: 1 << 2)
}

View File

@ -1,34 +0,0 @@
//
// ShortHandRunner.swift
// ShortHandRunner
//
// Created by Omar Abdelhafith on 05/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//
import Foundation
func runWithoutCapture(command: String) -> Int {
return 🏃.runWithoutCapture(command)
}
func run(command: String, args: String...) -> RunResults {
return 🏃.run(command, args: args as [String])
}
func run(command: String, args: [String]) -> RunResults {
return 🏃.run(command, args: args as [String])
}
func run(command: String, settings: (RunSettings -> Void)) -> RunResults {
return 🏃.run(command, settings: settings)
}
func run(command: String, args: [String], settings: (RunSettings -> Void)) -> RunResults {
return 🏃.run(command, args: args, settings: settings)
}
func run(command: String, echo: EchoSettings) -> RunResults {
return 🏃.run(command, echo: echo)
}

19
SwiftLine/Swiftline.h Normal file
View File

@ -0,0 +1,19 @@
//
// Swiftline.h
// Swiftline
//
// Created by Omar Abdelhafith on 11/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//
#import <Cocoa/Cocoa.h>
//! Project version number for Swiftline.
FOUNDATION_EXPORT double SwiftlineVersionNumber;
//! Project version string for Swiftline.
FOUNDATION_EXPORT const unsigned char SwiftlineVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <Swiftline/PublicHeader.h>

View File

@ -8,7 +8,13 @@
import Foundation
func agree(prompt: String) -> Bool {
/**
Displays a yes/no prompt to the user
- parameter prompt: The prompt to display
- returns: the user decision
*/
public func agree(prompt: String) -> Bool {
PromptSettings.print(prompt, terminator: " ")
let value = readStringOrEmpty()

View File

@ -9,16 +9,34 @@
import Foundation
func ask(prompt: String, callback: (AskSettings<String> -> Void)? = nil) -> String {
return ask(prompt, type: String.self, callback: callback)
/**
Display a promt to the user
- parameter prompt: The message to display
- parameter customizationBlock: The block to costumize the prompt before displaying
- returns: The string enters from the user
*/
public func ask(prompt: String, customizationBlock: (AskSettings<String> -> Void)? = nil) -> String {
return ask(prompt, type: String.self, customizationBlock: customizationBlock)
}
func ask<T: ArgConvertibleType>(prompt: String, type: T.Type, callback: (AskSettings<T> -> Void)? = nil) -> T {
/**
Display a promt to the user
- parameter prompt:The message to display
- parameter type: The value type to be expected from the user
- parameter customizationBlock: The block to costumize the prompt before displaying
- returns: The string casted to the type requested
- discussion: If the user enters a wrong type, ask will keep prompting until a correct value has been entered
*/
public func ask<T: ArgConvertibleType>(prompt: String, type: T.Type, customizationBlock: (AskSettings<T> -> Void)? = nil) -> T {
PromptSettings.print(prompt)
let settings = getSettings(callback)
let settings = getSettings(customizationBlock)
if settings.confirm {
return getValidatedStringWithConfirmation(settings)
@ -27,11 +45,16 @@ func ask<T: ArgConvertibleType>(prompt: String, type: T.Type, callback: (AskSett
}
}
// MARK:- Internal functions
func getValidatedString<T: ArgConvertibleType, W: AskerValidator where W.Item == T>(validator: W) -> T {
let stringOrEmpty = readStringOrEmpty()
return askForValidatedItem(originalValue: stringOrEmpty, validator: validator)
}
func getValidatedStringWithConfirmation<T: ArgConvertibleType, W: AskerValidator where W.Item == T>(validator: W) -> T {
while true {
@ -46,12 +69,14 @@ func getValidatedStringWithConfirmation<T: ArgConvertibleType, W: AskerValidator
}
}
func getSettings<T>(callback: (AskSettings<T> -> Void)?) -> AskSettings<T> {
let settings = AskSettings<T>()
callback?(settings)
return settings
}
func readStringOrEmpty() -> String {
return PromptSettings.read() ?? ""
}

View File

@ -9,13 +9,27 @@
import Foundation
class AskSettings<T: ArgConvertibleType> {
var defaultValue: T?
/// Settings used to costumize the behaviour of ask()
public class AskSettings<T: ArgConvertibleType> {
/// Default value to set incase the user entered a blank
public var defaultValue: T?
/// If set to true, another message will follow successful user entry asking the user to confirm
/// his selection
public var confirm = false
var invalidClousures: [(T -> Bool, String)] = []
var confirm = false
func addInvalidCase(description: String, invalidIfTrue: (T -> Bool)) {
/**
Add an invalid entry case
- parameter description: The string to be printed to the stdout if the case is invalid
- parameter invalidIfTrue: If true is returned, then the user input was invalid, if false, the
user input was valid.
*/
public func addInvalidCase(description: String, invalidIfTrue: (T -> Bool)) {
invalidClousures.append(invalidIfTrue, description)
}
@ -28,7 +42,11 @@ class AskSettings<T: ArgConvertibleType> {
}
}
// MARK:- Internal extension
extension AskSettings: AskerValidator {
func invalidItemMessage(string: String?) -> String? {
guard let string = string else {
return "You provided an empty message, pelase enter anything!"

View File

@ -0,0 +1,95 @@
//
// Chooser.swift
// Choose
//
// Created by Omar Abdelhafith on 03/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//
import Foundation
/**
Presents a user with a menu of items to choose from
- parameter prompt: The menu prompt message
- parameter choices: List of choices
- returns: The user selected item
*/
public func choose(prompt: String, choices: String...) -> String {
return choose(prompt, type: String.self) {
for choice in choices {
$0.addChoice(choice) { return choice }
}
}
}
/**
Presents a user with a menu of items to choose from
- parameter costumizationBlock: Closure to be called with a ChooseSettings, changes to the settings are reflected to the prompt
- returns: The user selected item
*/
public func choose<T>(costumizationBlock: (ChooseSettings<T> -> Void)) -> T {
let settings = getChooseSettings(costumizationBlock)
return choose(settings, type: T.self)
}
/**
Presents a user with a menu of items to choose from
- parameter prompt: The menu prompt message
- parameter type: The value type to be expected from the user
- parameter costumizationBlock: Closure to be called with a ChooseSettings, changes to the settings are reflected to the prompt
- returns: The user selected item
*/
public func choose<T>(prompt: String, type: T.Type, costumizationBlock: (ChooseSettings<T> -> Void)) -> T {
let settings = getChooseSettings(costumizationBlock)
settings.promptQuestion = prompt
return choose(settings, type: type)
}
/**
Presents a user with a menu of items to choose from
- parameter type: The value type to be expected from the user
- parameter costumizationBlock: Closure to be called with a ChooseSettings, changes to the settings are reflected to the prompt
- returns: The user selected item
*/
public func choose<T>(type: T.Type, costumizationBlock: (ChooseSettings<T> -> Void)) -> T {
let settings = getChooseSettings(costumizationBlock)
return choose(settings, type: type)
}
// MARK :- Internal functions
func choose<T>(settings: ChooseSettings<T>, type: T.Type) -> T {
let items = settings.preparePromptItems()
items.forEach { PromptSettings.print($0) }
PromptSettings.print("\(settings.promptQuestion)", terminator: "")
let stringRead = readStringOrEmpty()
return askForValidatedItem(originalValue: stringRead, validator: settings)
}
func getChooseSettings<T>(costumizationBlock: ChooseSettings<T> -> Void) -> ChooseSettings<T> {
let settings = ChooseSettings<T>()
costumizationBlock(settings)
return settings
}

View File

@ -9,26 +9,48 @@
import Foundation
enum ChoiceIndexType {
/**
Choice index type
- Letters: Use letters as choice index (a. b. c.)
- Numbers: Use numbers as choice index (1. 2. 3.)
*/
public enum ChoiceIndexType {
case Letters
case Numbers
}
class ChooseSettings<T> {
/// Settings to costumize the behavior of choose
public class ChooseSettings<T> {
typealias Item = T
var choices: [(choice: String, callback: Void -> T)] = []
var promptQuestion = ""
var index = ChoiceIndexType.Numbers
var indexSuffix = ". "
/// Prompt message to use
public var promptQuestion = ""
func addChoice(choice: String..., callback: Void -> T) {
/// Choice index used for choose items
public var index = ChoiceIndexType.Numbers
/// Index suffix used between the index and the item
public var indexSuffix = ". "
/**
Add a new item to the list of choices
- parameter choice: Item name
- parameter callback: callback called when the item is selected, the value returned from this call back will be returned from choose
*/
public func addChoice(choice: String..., callback: Void -> T) {
choice.forEach {
choices.append(($0, callback))
}
}
// MARK:- Internal
func validChoices() -> [String] {
let validChoices = Array(1...choices.count).map { "\($0)" }
return validChoices + stringChoices()
@ -84,6 +106,8 @@ class ChooseSettings<T> {
}
// MARK:- Internal Class
extension ChooseSettings: AskerValidator {
func validatedItem(forString string: String) -> T {
return choiceForInput(string)!

View File

@ -9,6 +9,43 @@
import Foundation
extension String {
/// Access the methods to change the foreground color
public var f: StringForegroundColorizer {
get { return foreground }
}
/// Access the methods to change the foreground color
public var foreground: StringForegroundColorizer {
get { return StringForegroundColorizer(string: self) }
}
/// Access the methods to change the background color
public var b: StringBackgroundColorizer {
get { return background }
}
/// Access the methods to change the background color
public var background: StringBackgroundColorizer {
get { return StringBackgroundColorizer(string: self) }
}
/// Access the methods to change the text style
public var s: StringStyleColorizer {
get { return style }
}
/// Access the methods to change the text style
public var style: StringStyleColorizer {
get { return StringStyleColorizer(string: self) }
}
}
// MARK- Internal
class Colorizer: CustomStringConvertible {
let color: StringStyle
@ -26,33 +63,4 @@ class Colorizer: CustomStringConvertible {
}
}
}
extension String {
var f: StringForegroundColorizer {
get { return foreground }
}
var foreground: StringForegroundColorizer {
get { return StringForegroundColorizer(string: self) }
}
var b: StringBackgroundColorizer {
get { return background }
}
var background: StringBackgroundColorizer {
get { return StringBackgroundColorizer(string: self) }
}
var s: StringStyleColorizer {
get { return style }
}
var style: StringStyleColorizer {
get { return StringStyleColorizer(string: self) }
}
}
}

View File

@ -11,53 +11,53 @@ import Foundation
extension String {
struct StringBackgroundColorizer {
public struct StringBackgroundColorizer {
let string: String
var Black: String {
public var Black: String {
get {
return Colorizer(string: string, color: BackgroundColor.Black).description
}
}
var Red: String {
public var Red: String {
get {
return Colorizer(string: string, color: BackgroundColor.Red).description
}
}
var Green: String {
public var Green: String {
get {
return Colorizer(string: string, color: BackgroundColor.Green).description
}
}
var Yellow: String {
public var Yellow: String {
get {
return Colorizer(string: string, color: BackgroundColor.Yellow).description
}
}
var Blue: String {
public var Blue: String {
get {
return Colorizer(string: string, color: BackgroundColor.Blue).description
}
}
var Magenta: String {
public var Magenta: String {
get {
return Colorizer(string: string, color: BackgroundColor.Magenta).description
}
}
var Cyan: String {
public var Cyan: String {
get {
return Colorizer(string: string, color: BackgroundColor.Cyan).description
}
}
var White: String {
public var White: String {
get {
return Colorizer(string: string, color: BackgroundColor.White).description
}

View File

@ -11,53 +11,53 @@ import Foundation
extension String {
struct StringForegroundColorizer {
public struct StringForegroundColorizer {
let string: String
var Black: String {
public var Black: String {
get {
return Colorizer(string: string, color: ForegroundColor.Black).description
}
}
var Red: String {
public var Red: String {
get {
return Colorizer(string: string, color: ForegroundColor.Red).description
}
}
var Green: String {
public var Green: String {
get {
return Colorizer(string: string, color: ForegroundColor.Green).description
}
}
var Yellow: String {
public var Yellow: String {
get {
return Colorizer(string: string, color: ForegroundColor.Yellow).description
}
}
var Blue: String {
public var Blue: String {
get {
return Colorizer(string: string, color: ForegroundColor.Blue).description
}
}
var Magenta: String {
public var Magenta: String {
get {
return Colorizer(string: string, color: ForegroundColor.Magenta).description
}
}
var Cyan: String {
public var Cyan: String {
get {
return Colorizer(string: string, color: ForegroundColor.Cyan).description
}
}
var White: String {
public var White: String {
get {
return Colorizer(string: string, color: ForegroundColor.White).description
}

View File

@ -9,73 +9,74 @@
import Foundation
extension String {
public extension String {
struct StringStyleColorizer {
public struct StringStyleColorizer {
let string: String
var Reset: String {
public var Reset: String {
get {
return Colorizer(string: string, color: StringTextStyle.Reset).description
}
}
var Bold: String {
public var Bold: String {
get {
return Colorizer(string: string, color: StringTextStyle.Bold).description
}
}
var Italic: String {
public var Italic: String {
get {
return Colorizer(string: string, color: StringTextStyle.Italic).description
}
}
var Underline: String {
public var Underline: String {
get {
return Colorizer(string: string, color: StringTextStyle.Underline).description
}
}
var Inverse: String {
public var Inverse: String {
get {
return Colorizer(string: string, color: StringTextStyle.Inverse).description
}
}
var Strikethrough: String {
public var Strikethrough: String {
get {
return Colorizer(string: string, color: StringTextStyle.Strikethrough).description
}
}
var BoldOff: String {
public var BoldOff: String {
get {
return Colorizer(string: string, color: StringTextStyle.BoldOff).description
}
}
var ItalicOff: String {
public var ItalicOff: String {
get {
return Colorizer(string: string, color: StringTextStyle.ItalicOff).description
}
}
var UnderlineOff: String {
public var UnderlineOff: String {
get {
return Colorizer(string: string, color: StringTextStyle.UnderlineOff).description
}
}
var InverseOff: String {
public var InverseOff: String {
get {
return Colorizer(string: string, color: StringTextStyle.InverseOff).description
}
}
var StrikethroughOff: String {
public var StrikethroughOff: String {
get {
return Colorizer(string: string, color: StringTextStyle.StrikethroughOff).description
}

View File

@ -0,0 +1,65 @@
//
// ArgConvertible.swift
// ArgConvertible
//
// Created by Omar Abdelhafith on 02/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//
import Foundation
/**
* Any type that extends ArgConvertibleType can be used in ask and choose
*/
public protocol ArgConvertibleType {
/// Create an instance out of a string
static func fromString(string: String) -> Self?
/// Return the display name of a type
static func typeName() -> String
}
extension Int: ArgConvertibleType {
public static func fromString(string: String) -> Int? {
return Int(string)
}
public static func typeName() -> String {
return "Integer"
}
}
extension Double: ArgConvertibleType {
public static func fromString(string: String) -> Double? {
return Double(string)
}
public static func typeName() -> String {
return "Double"
}
}
extension Float: ArgConvertibleType {
public static func fromString(string: String) -> Float? {
return Float(string)
}
public static func typeName() -> String {
return "Float"
}
}
extension String: ArgConvertibleType {
public static func fromString(string: String) -> String? {
return string
}
public static func typeName() -> String {
return "String"
}
}

View File

@ -9,13 +9,15 @@
import Foundation
struct RunResults {
public struct RunResults {
let exitStatus: Int
let stdout: String
let stderr: String
}
// MARK:- Internal
func splitCommandToArgs(command: String) -> [String] {
if command.containsString(" ") {
return command.componentsSeparatedByString(" ")

View File

@ -0,0 +1,46 @@
//
// RunSettings.swift
// RunSettings
//
// Created by Omar Abdelhafith on 05/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//
import Foundation
/// Settings to costumize the run function
public class RunSettings {
/// If set to true, the command wont be run on the system, the stdout will contain the command executed
public var dryRun = false
/// Which parts of the command to be echoed during execution
public var echo = EchoSettings.None
/// Run the command in interactive mode; output wont be captured
public var interactive = false
}
/// Echo settings
public struct EchoSettings: OptionSetType {
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
/// Dont echo anything, this is the default settings
public static var None = EchoSettings(rawValue: 0)
/// Echo the stdout from the run command to the terminal
public static let Stdout = EchoSettings(rawValue: 1 << 0)
/// Echo the stderr from the run command to the terminal
public static let Stderr = EchoSettings(rawValue: 1 << 1)
/// Echo the command executed to the terminal
public static let Command = EchoSettings(rawValue: 1 << 2)
}

View File

@ -0,0 +1,87 @@
//
// ShortHandRunner.swift
// ShortHandRunner
//
// Created by Omar Abdelhafith on 05/11/2015.
// Copyright © 2015 Omar Abdelhafith. All rights reserved.
//
import Foundation
/**
Executes a command and captures its output
- parameter command: the command to execute
- parameter args: the parameters to pass to the command
- returns: RunResults describing the command results
*/
public func run(command: String, args: String...) -> RunResults {
return 🏃.run(command, args: args as [String])
}
/**
Executes a command and captures its output
- parameter command: the command to execute
- parameter args: the parameters to pass to the command
- returns: RunResults describing the command results
*/
public func run(command: String, args: [String]) -> RunResults {
return 🏃.run(command, args: args as [String])
}
/**
Executes a command and captures its output
- parameter command: the command to execute
- parameter settingsBlock: block that receives the settings to costumize the behavior of run
- returns: RunResults describing the command results
*/
public func run(command: String, settingsBlock: (RunSettings -> Void)) -> RunResults {
return 🏃.run(command, settings: settingsBlock)
}
/**
Executes a command and captures its output
- parameter command: the command to execute
- parameter args: the parameters to pass to the command
- parameter settingsBlock: block that receives the settings to costumize the behavior of run
- returns: RunResults describing the command results
*/
public func run(command: String, args: [String], settings: (RunSettings -> Void)) -> RunResults {
return 🏃.run(command, args: args, settings: settings)
}
/**
Executes a command and captures its output
- parameter command: the command to execute
- parameter echo: echo settings that describe what parts of the command to print
- returns: RunResults describing the command results
*/
func run(command: String, echo: EchoSettings) -> RunResults {
return 🏃.run(command, echo: echo)
}
/**
Execute a command in interactive mode, output won't be captured
- parameter command: the command to execute
- returns: executed command exit code
*/
public func runWithoutCapture(command: String) -> Int {
return 🏃.runWithoutCapture(command)
}

View File

@ -1,5 +1,6 @@
import Quick
import Nimble
@testable import Swiftline
class AgreeSettingsTest: QuickSpec {
override func spec() {

View File

@ -1,5 +1,6 @@
import Quick
import Nimble
@testable import Swiftline
class AgreeTest: QuickSpec {
override func spec() {

View File

@ -1,5 +1,6 @@
import Quick
import Nimble
@testable import Swiftline
class AskSettingsTests: QuickSpec {
override func spec() {

View File

@ -1,5 +1,6 @@
import Quick
import Nimble
@testable import Swiftline
class AskerTest: QuickSpec {
override func spec() {

View File

@ -1,5 +1,6 @@
import Quick
import Nimble
@testable import Swiftline
class ChooseSettingsTests: QuickSpec {
override func spec() {

View File

@ -1,5 +1,6 @@
import Quick
import Nimble
@testable import Swiftline
class ChooseTests: QuickSpec {
override func spec() {

View File

@ -1,6 +1,6 @@
import Quick
import Nimble
@testable import Swiftline
class ColorizerTest: QuickSpec {
override func spec() {

View File

@ -1,5 +1,6 @@
import Quick
import Nimble
@testable import Swiftline
class RunnerTests: QuickSpec {
override func spec() {

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
location = "self:swiftline.xcodeproj">
location = "self:Swiftline.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0710"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D72762D21BF2C9E900126D99"
BuildableName = "Swiftline.framework"
BlueprintName = "Swiftline"
ReferencedContainer = "container:Swiftline.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
codeCoverageEnabled = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D72762DC1BF2C9E900126D99"
BuildableName = "SwiftlineTests.xctest"
BlueprintName = "SwiftlineTests"
ReferencedContainer = "container:Swiftline.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D72762D21BF2C9E900126D99"
BuildableName = "Swiftline.framework"
BlueprintName = "Swiftline"
ReferencedContainer = "container:Swiftline.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D72762D21BF2C9E900126D99"
BuildableName = "Swiftline.framework"
BlueprintName = "Swiftline"
ReferencedContainer = "container:Swiftline.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D72762D21BF2C9E900126D99"
BuildableName = "Swiftline.framework"
BlueprintName = "Swiftline"
ReferencedContainer = "container:Swiftline.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:swiftline.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>