Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clean up coding logic, reducing hard to maintain code duplication; improve box naming #27

Merged
merged 7 commits into from Dec 21, 2018
26 changes: 13 additions & 13 deletions Sources/XMLCoder/Auxiliaries/XMLElement.swift
Expand Up @@ -23,24 +23,24 @@ internal class _XMLElement {
self.children = children
}

static func createRootElement(rootKey: String, object: ArrayBox) -> _XMLElement? {
static func createRootElement(rootKey: String, object: UnkeyedBox) -> _XMLElement? {
let element = _XMLElement(key: rootKey)

_XMLElement.createElement(parentElement: element, key: rootKey, object: object)

return element
}

static func createRootElement(rootKey: String, object: DictionaryBox) -> _XMLElement? {
static func createRootElement(rootKey: String, object: KeyedBox) -> _XMLElement? {
let element = _XMLElement(key: rootKey)

_XMLElement.modifyElement(element: element, parentElement: nil, key: nil, object: object)

return element
}

fileprivate static func modifyElement(element: _XMLElement, parentElement: _XMLElement?, key: String?, object: DictionaryBox) {
let attributesBox = object[_XMLElement.attributesKey] as? DictionaryBox
fileprivate static func modifyElement(element: _XMLElement, parentElement: _XMLElement?, key: String?, object: KeyedBox) {
let attributesBox = object[_XMLElement.attributesKey] as? KeyedBox
let uniqueAttributes: [(String, String)]? = attributesBox?.unbox().compactMap { key, box in
return box.xmlString().map { (key, $0) }
}
Expand All @@ -59,11 +59,11 @@ internal class _XMLElement {

fileprivate static func createElement(parentElement: _XMLElement, key: String, object: Box) {
switch object {
case let box as ArrayBox:
case let box as UnkeyedBox:
for box in box.unbox() {
_XMLElement.createElement(parentElement: parentElement, key: key, object: box)
}
case let box as DictionaryBox:
case let box as KeyedBox:
modifyElement(element: _XMLElement(key: key), parentElement: parentElement, key: key, object: box)
case _:
let element = _XMLElement(key: key, value: object.xmlString())
Expand All @@ -84,28 +84,28 @@ internal class _XMLElement {
for childElement in children {
for child in childElement.value {
if let content = child.value {
if let oldContent = node[childElement.key] as? ArrayBox {
if let oldContent = node[childElement.key] as? UnkeyedBox {
oldContent.append(StringBox(content))
// FIXME: Box is a reference type, so this shouldn't be necessary:
node[childElement.key] = oldContent
} else if let oldContent = node[childElement.key] {
node[childElement.key] = ArrayBox([oldContent, StringBox(content)])
node[childElement.key] = UnkeyedBox([oldContent, StringBox(content)])
} else {
node[childElement.key] = StringBox(content)
}
} else if !child.children.isEmpty || !child.attributes.isEmpty {
let newValue = child.flatten()

if let existingValue = node[childElement.key] {
if let array = existingValue as? ArrayBox {
array.append(DictionaryBox(newValue))
if let unkeyed = existingValue as? UnkeyedBox {
unkeyed.append(KeyedBox(newValue))
// FIXME: Box is a reference type, so this shouldn't be necessary:
node[childElement.key] = array
node[childElement.key] = unkeyed
} else {
node[childElement.key] = ArrayBox([existingValue, DictionaryBox(newValue)])
node[childElement.key] = UnkeyedBox([existingValue, KeyedBox(newValue)])
}
} else {
node[childElement.key] = DictionaryBox(newValue)
node[childElement.key] = KeyedBox(newValue)
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions Sources/XMLCoder/Box/BoolBox.swift
Expand Up @@ -34,10 +34,6 @@ extension BoolBox: Box {
return false
}

var isFragment: Bool {
return true
}

/// # Lexical representation
/// Boolean has a lexical representation consisting of the following
/// legal literals {`true`, `false`, `1`, `0`}.
Expand All @@ -53,6 +49,10 @@ extension BoolBox: Box {
}
}

extension BoolBox: SimpleBox {

}

extension BoolBox: CustomStringConvertible {
var description: String {
return self.unboxed.description
Expand Down
7 changes: 5 additions & 2 deletions Sources/XMLCoder/Box/Box.swift
Expand Up @@ -9,7 +9,10 @@ import Foundation

protocol Box {
var isNull: Bool { get }
var isFragment: Bool { get }

func xmlString() -> String?
}

/// A box that only describes a single atomic value.
protocol SimpleBox: Box {

}
8 changes: 4 additions & 4 deletions Sources/XMLCoder/Box/DataBox.swift
Expand Up @@ -46,15 +46,15 @@ extension DataBox: Box {
return false
}

var isFragment: Bool {
return true
}

func xmlString() -> String? {
return self.xmlString(format: self.format)
}
}

extension DataBox: SimpleBox {

}

extension DataBox: CustomStringConvertible {
var description: String {
return self.unboxed.description
Expand Down
8 changes: 4 additions & 4 deletions Sources/XMLCoder/Box/DateBox.swift
Expand Up @@ -88,15 +88,15 @@ extension DateBox: Box {
return false
}

var isFragment: Bool {
return true
}

func xmlString() -> String? {
return self.xmlString(format: self.format)
}
}

extension DateBox: SimpleBox {

}

extension DateBox: CustomStringConvertible {
var description: String {
return self.unboxed.description
Expand Down
8 changes: 4 additions & 4 deletions Sources/XMLCoder/Box/DecimalBox.swift
Expand Up @@ -33,10 +33,6 @@ extension DecimalBox: Box {
return false
}

var isFragment: Bool {
return true
}

/// # Lexical representation
/// Decimal has a lexical representation consisting of a finite-length sequence of
/// decimal digits separated by a period as a decimal indicator.
Expand All @@ -60,6 +56,10 @@ extension DecimalBox: Box {
}
}

extension DecimalBox: SimpleBox {

}

extension DecimalBox: CustomStringConvertible {
var description: String {
return self.unboxed.description
Expand Down
8 changes: 4 additions & 4 deletions Sources/XMLCoder/Box/FloatBox.swift
Expand Up @@ -33,10 +33,6 @@ extension FloatBox: Box {
return false
}

var isFragment: Bool {
return true
}

/// # Lexical representation
/// float values have a lexical representation consisting of a mantissa followed, optionally,
/// by the character `"E"` or `"e"`, followed by an exponent. The exponent **must** be an integer.
Expand Down Expand Up @@ -78,6 +74,10 @@ extension FloatBox: Box {
}
}

extension FloatBox: SimpleBox {

}

extension FloatBox: CustomStringConvertible {
var description: String {
return self.unboxed.description
Expand Down
8 changes: 4 additions & 4 deletions Sources/XMLCoder/Box/IntBox.swift
Expand Up @@ -33,10 +33,6 @@ extension IntBox: Box {
return false
}

var isFragment: Bool {
return true
}

/// # Lexical representation
/// Integer has a lexical representation consisting of a finite-length sequence of
/// decimal digits with an optional leading sign. If the sign is omitted, `"+"` is assumed.
Expand All @@ -55,6 +51,10 @@ extension IntBox: Box {
}
}

extension IntBox: SimpleBox {

}

extension IntBox: CustomStringConvertible {
var description: String {
return self.unboxed.description
Expand Down
@@ -1,5 +1,5 @@
//
// DictionaryBox.swift
// KeyedBox.swift
// XMLCoderPackageDescription
//
// Created by Vincent Esche on 11/19/18.
Expand All @@ -8,7 +8,7 @@
import Foundation

// Minimalist implementation of an order-preserving keyed box:
class DictionaryBox {
class KeyedBox {
typealias Key = String
typealias Value = Box

Expand Down Expand Up @@ -58,27 +58,30 @@ class DictionaryBox {
return try self.unboxed.compactMap(transform)
}

func mapValues(_ transform: (Value) throws -> Value) rethrows -> DictionaryBox {
return DictionaryBox(try self.unboxed.mapValues(transform))
func mapValues(_ transform: (Value) throws -> Value) rethrows -> KeyedBox {
return KeyedBox(try self.unboxed.mapValues(transform))
}
}

extension DictionaryBox: Box {
extension KeyedBox: Box {
var isNull: Bool {
return false
}

var isFragment: Bool {
return false
}

func xmlString() -> String? {
return nil
}
}

extension KeyedBox: Sequence {
typealias Iterator = Unboxed.Iterator

func makeIterator() -> Iterator {
return self.unboxed.makeIterator()
}
}

extension DictionaryBox: CustomStringConvertible {
extension KeyedBox: CustomStringConvertible {
var description: String {
return self.unboxed.description
}
Expand Down
8 changes: 4 additions & 4 deletions Sources/XMLCoder/Box/NullBox.swift
Expand Up @@ -16,15 +16,15 @@ extension NullBox: Box {
return true
}

var isFragment: Bool {
return true
}

func xmlString() -> String? {
return nil
}
}

extension NullBox: SimpleBox {

}

extension NullBox: Equatable {
static func == (lhs: NullBox, rhs: NullBox) -> Bool {
return true
Expand Down
8 changes: 4 additions & 4 deletions Sources/XMLCoder/Box/StringBox.swift
Expand Up @@ -30,15 +30,15 @@ extension StringBox: Box {
return false
}

var isFragment: Bool {
return true
}

func xmlString() -> String? {
return self.unboxed.description
}
}

extension StringBox: SimpleBox {

}

extension StringBox: CustomStringConvertible {
var description: String {
return self.unboxed.description
Expand Down
8 changes: 4 additions & 4 deletions Sources/XMLCoder/Box/UIntBox.swift
Expand Up @@ -33,10 +33,6 @@ extension UIntBox: Box {
return false
}

var isFragment: Bool {
return true
}

/// # Lexical representation
/// Unsigned integer has a lexical representation consisting of an optional
/// sign followed by a finite-length sequence of decimal digits.
Expand All @@ -58,6 +54,10 @@ extension UIntBox: Box {
}
}

extension UIntBox: SimpleBox {

}

extension UIntBox: CustomStringConvertible {
var description: String {
return self.unboxed.description
Expand Down
@@ -1,5 +1,5 @@
//
// ArrayBox.swift
// UnkeyedBox.swift
// XMLCoderPackageDescription
//
// Created by Vincent Esche on 11/20/18.
Expand All @@ -8,7 +8,7 @@
import Foundation

// Minimalist implementation of an order-preserving unkeyed box:
class ArrayBox {
class UnkeyedBox {
typealias Element = Box
typealias Unboxed = [Element]

Expand Down Expand Up @@ -56,21 +56,25 @@ class ArrayBox {
}
}

extension ArrayBox: Box {
extension UnkeyedBox: Box {
var isNull: Bool {
return false
}

var isFragment: Bool {
return false
}

func xmlString() -> String? {
return nil
}
}

extension ArrayBox: CustomStringConvertible {
extension UnkeyedBox: Sequence {
typealias Iterator = Unboxed.Iterator

func makeIterator() -> Iterator {
return self.unboxed.makeIterator()
}
}

extension UnkeyedBox: CustomStringConvertible {
var description: String {
return self.unboxed.description
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/XMLCoder/Decoder/DecodingErrorExtension.swift
Expand Up @@ -43,9 +43,9 @@ internal extension DecodingError {
return "an unsigned integer value"
case is FloatBox:
return "a floating-point value"
case is ArrayBox:
case is UnkeyedBox:
return "a array value"
case is DictionaryBox:
case is KeyedBox:
return "a dictionary value"
case _:
return "\(type(of: box))"
Expand Down