Export 1-dimension arrays and dicts to Zsh

Export arrays to Zsh arrays and dictionaries to Zsh associate arrays.
This commit is contained in:
Alexis Bridoux 2021-04-27 00:53:49 +02:00
parent 8132bcbe0b
commit 2912e48c86
12 changed files with 114 additions and 16 deletions

View File

@ -98,7 +98,7 @@ public extension ExplorerError {
}
static func mismatchingType<T>(_ type: T.Type, value: ExplorerValue) -> Self {
ExplorerError(description: "ExplorerValue \(value) cannot be represented as \(T.self)")
ExplorerError(description: "ExplorerValue '\(value)' cannot be represented as \(T.self)")
}
static func predicateNotEvaluatable(_ predicate: String, description: String) -> Self {

View File

@ -6,7 +6,6 @@
import ArgumentParser
import Scout
import ScoutCLTCore
import Foundation
struct AddCommand: SADCommand {
@ -44,7 +43,7 @@ struct AddCommand: SADCommand {
var csvSeparator: String?
@Option(name: .export, help: .export)
var exportFormat: Scout.DataFormat?
var exportFormat: ExportFormat?
// MARK: - Functions

View File

@ -5,7 +5,7 @@
import ArgumentParser
import Scout
import Foundation
import ScoutCLTCore
struct DeleteCommand: SADCommand {
@ -46,7 +46,7 @@ struct DeleteCommand: SADCommand {
var csvSeparator: String?
@Option(name: .export, help: .export)
var exportFormat: Scout.DataFormat?
var exportFormat: ExportFormat?
// MARK: - Functions

View File

@ -3,7 +3,7 @@
// Copyright (c) 2020-present Alexis Bridoux
// MIT license, see LICENSE file for details
import Foundation
import ScoutCLTCore
import Scout
import ArgumentParser
@ -51,7 +51,7 @@ struct DeleteKeyCommand: SADCommand {
var csvSeparator: String?
@Option(name: [.short, .customLong("export")], help: "Convert the data to the specified format")
var exportFormat: Scout.DataFormat?
var exportFormat: ExportFormat?
// MARK: - Functions

View File

@ -7,6 +7,7 @@ import Foundation
import ArgumentParser
import Scout
import Lux
import ScoutCLTCore
extension ParsableCommand {

View File

@ -16,6 +16,7 @@ protocol PathExplorerInputCommand: ParsableCommand {
/// A file path from which to read and write the data
var modifyFilePath: String? { get }
/// The data format to use to read the data
var dataFormat: Scout.DataFormat { get }
/// Called with the correct `PathExplorer` when `inferPathExplorer(from:in:)` completes

View File

@ -49,7 +49,7 @@ extension SADCommand {
extension SADCommand {
/// Print the data from the path explorer and colorize it if specified
/// Print the data from the path explorer and highlight it if specified
/// - Parameters:
/// - outputFilePath: A file path to a file where to write the data
/// - pathExplorer: The path explorer to use to get the data
@ -84,6 +84,26 @@ extension SADCommand {
}
return
case .array:
do {
let array = try pathExplorer.array(of: GroupExportValue.self).map(\.value).joined(separator: " ")
print("\(array)")
} catch {
throw RuntimeError.custom("Unable to represent the value as an array of single elements")
}
case .dictionary:
do {
let dict = try pathExplorer.dictionary(of: GroupExportValue.self)
.map { "\($0.key) \($0.value.value)" }
.joined(separator: " ")
print("\(dict)")
} catch {
throw RuntimeError.custom("Unable to represent the value as a dictionary of single elements")
}
case .noExport:
break
}

View File

@ -52,7 +52,7 @@ struct ReadCommand: PathExplorerInputCommand, ExportCommand {
var csvSeparator: String?
@Option(name: .export, help: .export)
var exportFormat: Scout.DataFormat?
var exportFormat: ExportFormat?
// MARK: - Functions
@ -60,7 +60,6 @@ struct ReadCommand: PathExplorerInputCommand, ExportCommand {
let readingPath = self.readingPath ?? Path()
var explorer = try pathExplorer.get(readingPath)
let value = try getValue(from: &explorer)
let colorInjector = try self.colorInjector(for: exportFormat ?? P.format)
if value == "" {
throw RuntimeError.noValueAt(path: readingPath.description)
@ -71,8 +70,15 @@ struct ReadCommand: PathExplorerInputCommand, ExportCommand {
return
}
let output = colorise ? colorInjector.inject(in: value) : value
print(output)
switch try exportOption() {
case .array, .dictionary, .noExport, .csv: // cases already handled in getValue()
print(value)
case .dataFormat(let format):
let colorInjector = try self.colorInjector(for: format)
let output = colorInjector.inject(in: value)
print(output)
}
}
func getValue<Explorer: SerializablePathExplorer>(from explorer: inout Explorer) throws -> String {
@ -85,6 +91,26 @@ struct ReadCommand: PathExplorerInputCommand, ExportCommand {
case .dataFormat(let format):
return try explorer.exportString(to: format, rootName: fileName(of: inputFilePath))
case .array:
do {
let array = try explorer.array(of: GroupExportValue.self).map(\.value).joined(separator: " ")
return "\(array)"
} catch {
throw RuntimeError.custom("Unable to represent the value as an array of single elements")
}
case .dictionary:
do {
let dict = try explorer.dictionary(of: GroupExportValue.self)
.map { "\($0.key) \($0.value.value)" }
.joined(separator: " ")
return "\(dict)"
} catch {
throw RuntimeError.custom("Unable to represent the value as an array of single elements")
}
case .noExport:
break
}

View File

@ -43,7 +43,7 @@ struct SetCommand: SADCommand {
var csvSeparator: String?
@Option(name: .export, help: .export)
var exportFormat: Scout.DataFormat?
var exportFormat: ExportFormat?
// MARK: - Functions

View File

@ -9,12 +9,14 @@ import Scout
public enum Export: Equatable {
case noExport
case csv(separator: String)
case dataFormat(format: Scout.DataFormat)
case dataFormat(format: DataFormat)
case array
case dictionary
}
public protocol ExportCommand {
var csvSeparator: String? { get }
var exportFormat: DataFormat? { get }
var exportFormat: ExportFormat? { get }
}
public extension ExportCommand {
@ -22,7 +24,15 @@ public extension ExportCommand {
func exportOption() throws -> Export {
switch (csvSeparator, exportFormat) {
case (let separator?, nil): return .csv(separator: separator)
case (nil, let format?): return .dataFormat(format: format)
case (nil, let format?):
switch format {
case .array: return .array
case .dict: return .dictionary
case .json: return .dataFormat(format: .json)
case .plist: return .dataFormat(format: .plist)
case .yaml: return .dataFormat(format: .yaml)
case .xml: return .dataFormat(format: .xml)
}
case (nil, nil): return .noExport
case (.some, .some): throw CLTCoreError.exportConflict
}

View File

@ -0,0 +1,12 @@
//
// Scout
// Copyright (c) 2020-present Alexis Bridoux
// MIT license, see LICENSE file for details
import ArgumentParser
import Scout
/// Models the value the export process can take
public enum ExportFormat: String, CaseIterable, ExpressibleByArgument, Equatable {
case json, plist, yaml, xml, array, dict
}

View File

@ -0,0 +1,29 @@
//
// Scout
// Copyright (c) 2020-present Alexis Bridoux
// MIT license, see LICENSE file for details
import Foundation
import Scout
/// Type serving only the purpose to map dictionaries or arrays
/// returned by a `PathExplorer` to a `String` value.
///
/// Init throws if the value is not single.
public struct GroupExportValue: ExplorerValueCreatable {
public let value: String
public init(from explorerValue: ExplorerValue) throws {
switch explorerValue {
case .string(let string): value = string
case .int(let int): value = int.description
case .double(let double): value = double.description
case .bool(let bool): value = bool.description
case .data(let data): value = data.base64EncodedString()
case .date(let date): value = date.description
case .dictionary: throw CLTCoreError.wrongUsage("Trying to export a dictionary of values that are not single")
case .array: throw CLTCoreError.wrongUsage("Trying to export an array of values that are not single")
}
}
}