Add HBMustacheCustomRenderable

Support custom rendering of swift types
Fixes tests that rely on NSNull
This commit is contained in:
Adam Fowler
2021-05-03 15:33:28 +01:00
parent f852bc1d00
commit 4a78d44712
4 changed files with 45 additions and 7 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
.build
.git

View File

@@ -0,0 +1,29 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Hummingbird server framework project
//
// Copyright (c) 2021-2021 the Hummingbird authors
// Licensed under Apache License v2.0
//
// See LICENSE.txt for license information
// See hummingbird/CONTRIBUTORS.txt for the list of Hummingbird authors
//
// SPDX-License-Identifier: Apache-2.0
//
//===----------------------------------------------------------------------===//
import Foundation
protocol HBMustacheCustomRenderable {
var renderText: String { get }
var isNull: Bool { get }
}
extension HBMustacheCustomRenderable {
var renderText: String { String(describing: self) }
var isNull: Bool { false }
}
extension NSNull: HBMustacheCustomRenderable {
public var renderText: String { "" }
public var isNull: Bool { true }
}

View File

@@ -11,6 +11,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
import Foundation
extension HBMustacheTemplate { extension HBMustacheTemplate {
/// Render template using object /// Render template using object
@@ -46,14 +47,20 @@ extension HBMustacheTemplate {
if let child = getChild(named: variable, transform: transform, context: context) { if let child = getChild(named: variable, transform: transform, context: context) {
if let template = child as? HBMustacheTemplate { if let template = child as? HBMustacheTemplate {
return template.render(context: context) return template.render(context: context)
} else if let renderable = child as? HBMustacheCustomRenderable {
return context.contentType.escapeText(renderable.renderText)
} else { } else {
return context.contentType.escapeText(String(describing: child)) return context.contentType.escapeText(String(describing: child))
} }
} }
case .unescapedVariable(let variable, let transform): case .unescapedVariable(let variable, let transform):
if let child = getChild(named: variable, transform: transform, context: context) { if let child = getChild(named: variable, transform: transform, context: context) {
if let renderable = child as? HBMustacheCustomRenderable {
return renderable.renderText
} else {
return String(describing: child) return String(describing: child)
} }
}
case .section(let variable, let transform, let template): case .section(let variable, let transform, let template):
let child = self.getChild(named: variable, transform: transform, context: context) let child = self.getChild(named: variable, transform: transform, context: context)
return self.renderSection(child, with: template, context: context) return self.renderSection(child, with: template, context: context)
@@ -94,6 +101,8 @@ extension HBMustacheTemplate {
return bool ? template.render(context: context) : "" return bool ? template.render(context: context) : ""
case let lambda as HBMustacheLambda: case let lambda as HBMustacheLambda:
return lambda.run(context.stack.last!, template) return lambda.run(context.stack.last!, template)
case let null as HBMustacheCustomRenderable where null.isNull == true:
return ""
case .some(let value): case .some(let value):
return template.render(context: context.withObject(value)) return template.render(context: context.withObject(value))
case .none: case .none:
@@ -113,6 +122,8 @@ extension HBMustacheTemplate {
return array.renderInvertedSection(with: template, context: context) return array.renderInvertedSection(with: template, context: context)
case let bool as Bool: case let bool as Bool:
return bool ? "" : template.render(context: context) return bool ? "" : template.render(context: context)
case let null as HBMustacheCustomRenderable where null.isNull == true:
return template.render(context: context)
case .some: case .some:
return "" return ""
case .none: case .none:

View File

@@ -22,8 +22,8 @@ import XCTest
public struct AnyDecodable: Decodable { public struct AnyDecodable: Decodable {
public let value: Any public let value: Any
public init<T>(_ value: T?) { public init<T>(_ value: T) {
self.value = value ?? () self.value = value
} }
} }
@@ -32,11 +32,7 @@ public extension AnyDecodable {
let container = try decoder.singleValueContainer() let container = try decoder.singleValueContainer()
if container.decodeNil() { if container.decodeNil() {
#if canImport(Foundation)
self.init(NSNull()) self.init(NSNull())
#else
self.init(Self?.none)
#endif
} else if let bool = try? container.decode(Bool.self) { } else if let bool = try? container.decode(Bool.self) {
self.init(bool) self.init(bool)
} else if let int = try? container.decode(Int.self) { } else if let int = try? container.decode(Int.self) {