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 { 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 { static func predicateNotEvaluatable(_ predicate: String, description: String) -> Self {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -49,7 +49,7 @@ extension SADCommand {
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: /// - Parameters:
/// - outputFilePath: A file path to a file where to write the data /// - outputFilePath: A file path to a file where to write the data
/// - pathExplorer: The path explorer to use to get the data /// - pathExplorer: The path explorer to use to get the data
@ -84,6 +84,26 @@ extension SADCommand {
} }
return 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: case .noExport:
break break
} }

View File

@ -52,7 +52,7 @@ struct ReadCommand: PathExplorerInputCommand, ExportCommand {
var csvSeparator: String? var csvSeparator: String?
@Option(name: .export, help: .export) @Option(name: .export, help: .export)
var exportFormat: Scout.DataFormat? var exportFormat: ExportFormat?
// MARK: - Functions // MARK: - Functions
@ -60,7 +60,6 @@ struct ReadCommand: PathExplorerInputCommand, ExportCommand {
let readingPath = self.readingPath ?? Path() let readingPath = self.readingPath ?? Path()
var explorer = try pathExplorer.get(readingPath) var explorer = try pathExplorer.get(readingPath)
let value = try getValue(from: &explorer) let value = try getValue(from: &explorer)
let colorInjector = try self.colorInjector(for: exportFormat ?? P.format)
if value == "" { if value == "" {
throw RuntimeError.noValueAt(path: readingPath.description) throw RuntimeError.noValueAt(path: readingPath.description)
@ -71,8 +70,15 @@ struct ReadCommand: PathExplorerInputCommand, ExportCommand {
return return
} }
let output = colorise ? colorInjector.inject(in: value) : value switch try exportOption() {
print(output) 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 { func getValue<Explorer: SerializablePathExplorer>(from explorer: inout Explorer) throws -> String {
@ -85,6 +91,26 @@ struct ReadCommand: PathExplorerInputCommand, ExportCommand {
case .dataFormat(let format): case .dataFormat(let format):
return try explorer.exportString(to: format, rootName: fileName(of: inputFilePath)) 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: case .noExport:
break break
} }

View File

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

View File

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