Mastering paths (end)
This commit is contained in:
parent
4ae5cdb922
commit
723bb2d229
|
@ -5,60 +5,6 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
// MARK: - Storage
|
||||
|
||||
private struct IndexedSlice {
|
||||
var index: Int
|
||||
var lowerBound: Int
|
||||
var upperBound: Int
|
||||
}
|
||||
|
||||
private struct Indexed<Value> {
|
||||
var index: Int
|
||||
var value: Value
|
||||
}
|
||||
|
||||
private struct IndexedCollection<Value>: Collection {
|
||||
typealias Element = Indexed<Value>
|
||||
|
||||
var elements: [Element]
|
||||
|
||||
var startIndex: Int { elements.startIndex }
|
||||
var endIndex: Int { elements.endIndex }
|
||||
|
||||
init() {
|
||||
elements = []
|
||||
}
|
||||
|
||||
subscript(position: Int) -> Element { elements[position] }
|
||||
func index(after i: Int) -> Int { elements.index(after: i) }
|
||||
|
||||
func makeIterator() -> IndexingIterator<[Element]> {
|
||||
elements.makeIterator()
|
||||
}
|
||||
|
||||
mutating func append(index: Int, value: Value) {
|
||||
elements.append(.init(index: index, value: value))
|
||||
}
|
||||
|
||||
mutating func popLast() -> Element? { elements.popLast() }
|
||||
mutating func removeAll() { elements.removeAll() }
|
||||
}
|
||||
|
||||
private struct IndexedElements {
|
||||
var indexes = IndexedCollection<Int>()
|
||||
var slices = [IndexedSlice]()
|
||||
var keys = IndexedCollection<String>()
|
||||
var filters = IndexedCollection<String>()
|
||||
}
|
||||
|
||||
private extension Array where Element == IndexedSlice {
|
||||
|
||||
mutating func append(index: Int, lower: Int, upper: Int) {
|
||||
append(.init(index: index, lowerBound: lower, upperBound: upper))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Functions
|
||||
|
||||
extension Path {
|
||||
|
@ -66,7 +12,7 @@ extension Path {
|
|||
/// Compute the path by changing the special path elements like slices or filters
|
||||
///
|
||||
/// Filters are changed to the key they correspond to. Slices are changed to indexes.
|
||||
/// #### Complexity
|
||||
/// ### Complexity
|
||||
/// O(n) with `n` the count of elements in the path
|
||||
public func flattened() -> Path {
|
||||
var indexedElements = getIndexedElements()
|
||||
|
@ -89,6 +35,11 @@ extension Path {
|
|||
|
||||
return Path(newPath)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Helpers
|
||||
|
||||
extension Path {
|
||||
|
||||
/// Parse the path and store the relevant elements with their indexes
|
||||
private func getIndexedElements() -> IndexedElements {
|
||||
|
@ -184,3 +135,53 @@ extension Path {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Storage models
|
||||
|
||||
private struct IndexedSlice {
|
||||
var index: Int
|
||||
var lowerBound: Int
|
||||
var upperBound: Int
|
||||
}
|
||||
|
||||
private struct Indexed<Value> {
|
||||
var index: Int
|
||||
var value: Value
|
||||
}
|
||||
|
||||
private struct IndexedCollection<Value>: Collection {
|
||||
typealias Element = Indexed<Value>
|
||||
|
||||
var elements: [Element] = []
|
||||
|
||||
var startIndex: Int { elements.startIndex }
|
||||
var endIndex: Int { elements.endIndex }
|
||||
|
||||
subscript(position: Int) -> Element { elements[position] }
|
||||
func index(after i: Int) -> Int { elements.index(after: i) }
|
||||
|
||||
func makeIterator() -> IndexingIterator<[Element]> {
|
||||
elements.makeIterator()
|
||||
}
|
||||
|
||||
mutating func append(index: Int, value: Value) {
|
||||
elements.append(.init(index: index, value: value))
|
||||
}
|
||||
|
||||
mutating func popLast() -> Element? { elements.popLast() }
|
||||
mutating func removeAll() { elements.removeAll() }
|
||||
}
|
||||
|
||||
private struct IndexedElements {
|
||||
var indexes = IndexedCollection<Int>()
|
||||
var slices = [IndexedSlice]()
|
||||
var keys = IndexedCollection<String>()
|
||||
var filters = IndexedCollection<String>()
|
||||
}
|
||||
|
||||
private extension Array where Element == IndexedSlice {
|
||||
|
||||
mutating func append(index: Int, lower: Int, upper: Int) {
|
||||
append(.init(index: index, lowerBound: lower, upperBound: upper))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,12 +36,15 @@ public extension Collection where Element == PathElement {
|
|||
|
||||
public extension Collection where SubSequence == Slice<Path> {
|
||||
|
||||
/// The greatest prefix that both paths have in common
|
||||
func commonPrefix(with otherPath: Self) -> Slice<Path> {
|
||||
var iterator = makeIterator()
|
||||
var otherIterator = otherPath.makeIterator()
|
||||
var lastIndex = 0
|
||||
|
||||
while let element = iterator.next(), let otherElement = otherIterator.next(), element == otherElement {
|
||||
while
|
||||
let element = iterator.next(), let otherElement = otherIterator.next(),
|
||||
element == otherElement {
|
||||
lastIndex += 1
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,8 @@ import Foundation
|
|||
public extension Collection where Element == PathElement {
|
||||
|
||||
/// Prints all the elements in the path, with the default separator
|
||||
/// #### Complexity
|
||||
///
|
||||
/// ### Complexity
|
||||
/// O(n) where `n`: element's count
|
||||
var description: String {
|
||||
var description = reduce(into: "", newDescription)
|
||||
|
|
|
@ -17,28 +17,27 @@ public struct Path: Hashable {
|
|||
|
||||
private var elements: [PathElement] = []
|
||||
|
||||
/// An empty `Path`
|
||||
public static var empty: Path { .init() }
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
/// Instantiate a `Path` for a string representing path components separated with the separator.
|
||||
///
|
||||
/// ### Example with default separator '.'
|
||||
/// ## Example with default separator '.'
|
||||
///
|
||||
/// `computers[2].name` will make the path `["computers", 2, "name"]`
|
||||
///
|
||||
/// `computer.general.serial_number` will make the path `["computer", "general", "serial_number"]`
|
||||
///
|
||||
/// `company.computers[#]` will make the path `["company", "computers", PathElement.count]`
|
||||
/// - `computers[2].name` will make the path `["computers", 2, "name"]`
|
||||
/// - `computer.general.serial_number` will make the path `["computer", "general", "serial_number"]`
|
||||
/// - `company.computers[#]` will make the path `["company", "computers", PathElement.count]`
|
||||
///
|
||||
/// - parameter string: The string representing the path
|
||||
/// - parameter separator: The separator used to split the string. Default is ".".
|
||||
///
|
||||
/// ### Brackets
|
||||
/// ## Brackets
|
||||
/// When enclosed with brackets, a path element will not be parsed. For example `computer.(general.information).serial_number`
|
||||
/// will make the path ["computer", "general.information", "serial_number"]
|
||||
///
|
||||
/// ### Excluded separators
|
||||
/// ## Excluded separators
|
||||
/// The following separators will not work: '[', ']', '(', ')'.
|
||||
public init(string: String, separator: String = Self.defaultSeparator) throws {
|
||||
if Self.forbiddenSeparators.contains(separator) { throw PathError.invalidSeparator(separator) }
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
/// Store the possible elements that can be used to subscript a `PathExplorer`
|
||||
/// Tthe possible elements that can be used to subscript a ``PathExplorer``
|
||||
public enum PathElement: Hashable {
|
||||
|
||||
// MARK: - Constants
|
||||
|
|
|
@ -7,7 +7,7 @@ import Foundation
|
|||
|
||||
/// A collection of paths arranged following their common prefixes.
|
||||
///
|
||||
/// Useful when building a PathExplorer from a list of paths to reuse the last created explorer
|
||||
/// Useful when building a `PathExplorer` from a list of paths to reuse the last created explorer
|
||||
/// to add children to it (rather than starting again from the root each time).
|
||||
final class PathTree<Value: Equatable> {
|
||||
|
||||
|
@ -30,7 +30,7 @@ final class PathTree<Value: Equatable> {
|
|||
return nil
|
||||
}
|
||||
|
||||
// MARK: - Initialisation
|
||||
// MARK: - Initialization
|
||||
|
||||
init(value: ValueType, element: PathElement) {
|
||||
self.value = value
|
||||
|
|
|
@ -9,7 +9,8 @@ import Foundation
|
|||
protocol EquatablePathExplorer: PathExplorer {
|
||||
|
||||
/// `true` when self is equal to the provided other element.
|
||||
/// #### Complexity
|
||||
///
|
||||
/// ### Complexity
|
||||
/// Most often `O(n)` where `n` is the children count.
|
||||
func isEqual(to other: Self) -> Bool
|
||||
}
|
||||
|
|
|
@ -18,18 +18,10 @@ public extension PathExplorer {
|
|||
public extension PathExplorer {
|
||||
|
||||
/// Get the key at the given path
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key)
|
||||
func get(_ path: [PathElement]) throws -> Self { try get(Path(path)) }
|
||||
|
||||
/// Get the key at the given path
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key)
|
||||
func get(_ path: PathElement...) throws -> Self { try get(path) }
|
||||
}
|
||||
|
@ -41,33 +33,18 @@ public extension PathExplorer {
|
|||
// MARK: Mutating
|
||||
|
||||
/// Set the value of the key at the given path
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key)
|
||||
mutating func set(_ path: PathElement..., to newValue: ExplorerValue) throws { try set(Path(path), to: newValue) }
|
||||
|
||||
// MARK: Mutating ExplorerValueRepresentable
|
||||
|
||||
/// Set the provided `ExplorerValueRepresentable`value of the key at the given path
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key), or if the `newValue.explorerValue()` function fails
|
||||
mutating func set(_ path: Path, to newValue: ExplorerValueRepresentable) throws {
|
||||
try set(path, to: newValue.explorerValue())
|
||||
}
|
||||
|
||||
/// Set the value of the key at the given path
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// Set the provided `ExplorerValueRepresentable`value of the key at the given path
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key), or if the `newValue.explorerValue()` function fails
|
||||
mutating func set(_ path: PathElement..., to newValue: ExplorerValueRepresentable) throws {
|
||||
try set(Path(path), to: newValue.explorerValue())
|
||||
|
@ -76,29 +53,14 @@ public extension PathExplorer {
|
|||
// MARK: Non mutating
|
||||
|
||||
/// Set the value of the key at the given path and return a new modified `PathExplorer`
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key)
|
||||
func setting(_ path: PathElement..., to newValue: ExplorerValue) throws -> Self { try setting(Path(path), to: newValue) }
|
||||
|
||||
/// Set the value of the key at the given path and return a new modified `PathExplorer`
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key), or if the `newValue.explorerValue()` function fails
|
||||
func setting(_ path: Path, to newValue: ExplorerValueRepresentable) throws -> Self { try setting(path, to: newValue.explorerValue()) }
|
||||
|
||||
/// Set the value of the key at the given path and return a new modified `PathExplorer`
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key), or if the `newValue.explorerValue()` function fails
|
||||
func setting(_ path: PathElement..., to newValue: ExplorerValueRepresentable) throws -> Self { try setting(Path(path), to: newValue.explorerValue()) }
|
||||
}
|
||||
|
@ -108,38 +70,18 @@ public extension PathExplorer {
|
|||
public extension PathExplorer {
|
||||
|
||||
/// Set the name of the key at the given path
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary)
|
||||
mutating func set(_ path: [PathElement], keyNameTo newKeyName: String) throws { try set(Path(path), keyNameTo: newKeyName) }
|
||||
|
||||
/// Set the name of the key at the given path
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary)
|
||||
mutating func set(_ path: PathElement..., keyNameTo newKeyName: String) throws { try set(path, keyNameTo: newKeyName) }
|
||||
|
||||
/// Set the name of the key at the given path, and return a new modified `PathExplorer`
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary)
|
||||
func setting(_ path: [PathElement], keyNameTo newKeyName: String) throws -> Self { try setting(Path(path), keyNameTo: newKeyName) }
|
||||
|
||||
/// Set the name of the key at the given path, and return a new modified `PathExplorer`
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary)
|
||||
func setting(_ path: PathElement..., keyNameTo newKeyName: String) throws -> Self { try setting(path, keyNameTo: newKeyName) }
|
||||
}
|
||||
|
@ -149,51 +91,26 @@ public extension PathExplorer {
|
|||
public extension PathExplorer {
|
||||
|
||||
/// Delete the key at the given path.
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - parameter deleteIfEmpty: When `true`, the dictionary or array holding the value will be deleted too if empty after the key deletion. Default: `false`
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key)
|
||||
mutating func delete(_ path: Path) throws { try delete(Path(path), deleteIfEmpty: false) }
|
||||
|
||||
/// Delete the key at the given path.
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - parameter deleteIfEmpty: When `true`, the dictionary or array holding the value will be deleted too if empty after the key deletion. Default: `false`
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key)
|
||||
mutating func delete(_ path: [PathElement], deleteIfEmpty: Bool = false) throws { try delete(Path(path), deleteIfEmpty: deleteIfEmpty) }
|
||||
|
||||
/// Delete the key at the given path.
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - parameter deleteIfEmpty: When `true`, the dictionary or array holding the value will be deleted too if empty after the key deletion. Default: `false`
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key)
|
||||
mutating func delete(_ path: PathElement..., deleteIfEmpty: Bool = false) throws { try delete(path, deleteIfEmpty: deleteIfEmpty) }
|
||||
|
||||
/// Delete the key at the given path and return a new modified `PathExplorer`
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - parameter deleteIfEmpty: When `true`, the dictionary or array holding the value will be deleted too if empty after the key deletion. Default: `false`
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key)
|
||||
func deleting(_ path: [PathElement], deleteIfEmpty: Bool = false) throws -> Self { try deleting(Path(path), deleteIfEmpty: deleteIfEmpty) }
|
||||
|
||||
/// Delete the key at the given path and return a new modified `PathExplorer`
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element of an array.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// - parameter deleteIfEmpty: When `true`, the dictionary or array holding the value will be deleted too if empty after the key deletion. Default: `false`
|
||||
/// - Throws: If the path is invalid (e.g. a key does not exist in a dictionary, or indicating an index on a non-array key)
|
||||
func deleting(_ path: PathElement..., deleteIfEmpty: Bool = false) throws -> Self { try deleting(path, deleteIfEmpty: deleteIfEmpty) }
|
||||
|
@ -207,35 +124,20 @@ public extension PathExplorer {
|
|||
|
||||
/// Add a value at the given path.
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// #### Appending
|
||||
/// ### Appending
|
||||
/// To add a key at the end of an array, specify the `PathElement.count`
|
||||
///
|
||||
/// ### Non-existing key
|
||||
/// Any non existing key encountered in the path will be created.
|
||||
mutating func add(_ value: ExplorerValue, at path: PathElement...) throws { try add(value, at: Path(path)) }
|
||||
|
||||
/// Add a value at the given path.
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// #### Appending
|
||||
/// ### Appending
|
||||
/// To add a key at the end of an array, specify the `PathElement.count`
|
||||
/// - Throws: If the `newValue.explorerValue` function fails
|
||||
mutating func add(_ value: ExplorerValueRepresentable, at path: Path) throws { try add(value.explorerValue(), at: path) }
|
||||
|
||||
/// Add a value at the given path.
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// #### Appending
|
||||
/// ### Appending
|
||||
/// To add a key at the end of an array, specify the `PathElement.count`
|
||||
/// - Throws: If the `newValue.explorerValue()` function fails
|
||||
mutating func add(_ value: ExplorerValueRepresentable, at path: PathElement...) throws { try add(value.explorerValue(), at: Path(path)) }
|
||||
|
@ -244,11 +146,7 @@ public extension PathExplorer {
|
|||
|
||||
/// Add a value at the given path, and return a new modified `PathExplorer`
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// #### Appending
|
||||
/// ### Appending
|
||||
/// To add a key at the end of an array, specify the `PathElement.count`
|
||||
///
|
||||
/// ### Non-existing key
|
||||
|
@ -257,22 +155,14 @@ public extension PathExplorer {
|
|||
|
||||
/// Add a value at the given path, and return a new modified `PathExplorer`
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// #### Appending
|
||||
/// ### Appending
|
||||
/// To add a key at the end of an array, specify the `PathElement.count`
|
||||
/// - Throws: If the `newValue.explorerValue()` function fails
|
||||
func adding(_ value: ExplorerValueRepresentable, at path: Path) throws -> Self { try adding(value.explorerValue(), at: path) }
|
||||
|
||||
/// Add a value at the given path, and return a new modified `PathExplorer`
|
||||
///
|
||||
/// #### Negative index
|
||||
/// It's possible to specify a negative index to target the last nth element.
|
||||
/// For example, -1 targets the last element and -3 the last 3rd element.
|
||||
///
|
||||
/// #### Appending
|
||||
/// ### Appending
|
||||
/// To add a key at the end of an array, specify the `PathElement.count`
|
||||
/// - Throws: If the `newValue.explorerValue()` function fails
|
||||
func adding(_ value: ExplorerValueRepresentable, at path: PathElement...) throws -> Self { try adding(value.explorerValue(), at: Path(path)) }
|
||||
|
|
|
@ -8,9 +8,10 @@ import Foundation
|
|||
/// A `PathExplorer` which can be instantiated from data and export itself to another format
|
||||
public protocol SerializablePathExplorer: PathExplorer {
|
||||
|
||||
/// The `DataFormat` of the serializable `PathExplorer`: JSON, Plist, XML, or YAML
|
||||
static var format: DataFormat { get }
|
||||
|
||||
/// Initialise a new ``PathExplorer`` from the `Data`
|
||||
/// Initialize a new ``PathExplorer`` from the `Data`
|
||||
///
|
||||
/// - Throws: If the data cannot be serialized into the format
|
||||
init(data: Data) throws
|
||||
|
@ -49,7 +50,7 @@ public protocol SerializablePathExplorer: PathExplorer {
|
|||
|
||||
/// New explorer replacing the group values (array or dictionaries) sub values by a unique one
|
||||
/// holding a fold mark to be replaced when exporting the string value.
|
||||
/// - note: Use `exportFoldedString(upTo:)` to directly get the string value
|
||||
/// - note: Use ``exportFoldedString(upTo:)`` to directly get the string value
|
||||
func folded(upTo level: Int) -> Self
|
||||
|
||||
/// Folded explored description, replacing the group values (array or dictionaries) sub values by a single string "..."
|
||||
|
|
|
@ -177,13 +177,15 @@ For instance, to get all keys in Tom's dictionary that start with "h".
|
|||
let path = Path(elements: "Tom", .filter("h.*"))
|
||||
let filteredTom = try json.get(path: path)
|
||||
print(filteredTom)
|
||||
// {
|
||||
// "hobbies" : [
|
||||
// "cooking",
|
||||
// "guitar"
|
||||
// ],
|
||||
// "height" : 175
|
||||
// }
|
||||
```
|
||||
```json
|
||||
{
|
||||
"hobbies" : [
|
||||
"cooking",
|
||||
"guitar"
|
||||
],
|
||||
"height" : 175
|
||||
}
|
||||
```
|
||||
|
||||
Or to get Tom and Robert first hobby.
|
||||
|
@ -200,33 +202,49 @@ print(firstHobbies)
|
|||
It's possible to mix both array slicing and dictionary filtering in a same path. For instance to get Tom and Robert first two hobbies.
|
||||
|
||||
```swift
|
||||
try json.get(.filter("Tom|Robert"), "hobbies", .slide(.first, 1))
|
||||
let path = Path(elements: .filter("Tom|Robert"), "hobbies", .slide(.first, 1))
|
||||
let hobbies = try json.get(path: path)
|
||||
print(hobbies)
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"Tom" : [
|
||||
"cooking",
|
||||
"guitar"
|
||||
],
|
||||
"Robert" : [
|
||||
"video games",
|
||||
"party"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Literals and PathElementRepresentable
|
||||
Using plain strings and numbers is made possible because ``PathElement`` implements `ExpressibleByStringLiteral` and `ExpressibleByIntLiteral`. When it comes to use variables as `PathElement`, it is required to specify the element.
|
||||
Using plain strings and numbers is made possible because ``PathElement`` implements `ExpressibleByStringLiteral` and `ExpressibleByIntLiteral`. But when it comes to use variables as `PathElement`, it is required to specify the element.
|
||||
|
||||
For instance with the first example path to target Robert's second hobby.
|
||||
|
||||
```swift
|
||||
let firstKey = "Robert"
|
||||
let secondKey = "hobbies"
|
||||
let firstIndex = 1
|
||||
let path = Path(elements: .key(firstKey), .key(secondKey), .index(firstIndex))
|
||||
let robertKey = "Robert"
|
||||
let hobbiesKey = "hobbies"
|
||||
let hobbyIndex = 1
|
||||
let path = Path(elements: .key(robertKey), .key(hobbiesKey), .index(hobbyIndex))
|
||||
```
|
||||
|
||||
As this syntax might be a bit heavy, it's possible to use ``PathElementRepresentable`` to create the `Path` with ``Path/init(_:)-1b2iy``. With it, the code above can be rewritten like so.
|
||||
|
||||
```swift
|
||||
let firstKey = "Robert"
|
||||
let secondKey = "hobbies"
|
||||
let firstIndex = 1
|
||||
let path = Path(firstKey, secondKey, firstIndex)
|
||||
let robertKey = "Robert"
|
||||
let hobbiesKey = "hobbies"
|
||||
let hobbyIndex = 1
|
||||
let path = Path(robertKey, hobbiesKey, hobbyIndex)
|
||||
```
|
||||
|
||||
The drawback is that this is possible only for `PathElement.index` and `PathElement.key`. When dealing with other elements like ``PathElement/count``, it is required to specify the `PathElement` type:
|
||||
The drawback is that this is possible only for `PathElement.index` and `PathElement.key`. When dealing with other elements like ``PathElement/count``, it is required to specify the `PathElement` type.
|
||||
|
||||
```swift
|
||||
Path(firstKey, secondKey, PathElement.count)
|
||||
Path(robertKey, hobbiesKey, PathElement.count)
|
||||
```
|
||||
|
||||
The convenience overloads for the `PathExplorer` functions similarly works with `PathElement` and `PathElementRepresentable`.
|
||||
|
|
|
@ -51,3 +51,14 @@ A `Path` is easily represented as a `String`, which is especially useful when wo
|
|||
When a `Path` contains special group scoping elements like ``PathElement/slice(_:)`` or ``PathElement/filter(_:)``, specifying a `PathElement.index` or `PathElement.key` will not refer to an immediate dictionary or array. The "flatten" operation will replace the slices and the filters in the `Path` with the proper values when the path is complete. Mainly used in paths listing ``PathExplorer/listPaths(startingAt:)``.
|
||||
|
||||
- ``flattened()``
|
||||
|
||||
### Map elements (Collection)
|
||||
|
||||
- ``Path/compactMapIndexes``
|
||||
- ``Path/compactMapKeys``
|
||||
- ``Path/compactMapSlices``
|
||||
- ``Path/compactMapFilter``
|
||||
|
||||
### Compare path (Collection)
|
||||
|
||||
- ``Path/commonPrefix(with:)``
|
||||
|
|
Loading…
Reference in New Issue