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

Add type safe render method #33

Merged
merged 7 commits into from May 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 2 additions & 9 deletions .travis.yml
Expand Up @@ -10,28 +10,21 @@ branches:

matrix:
include:
- os: linux
dist: trusty
sudo: required
env: SWIFT_SNAPSHOT=3.1.1
- os: linux
dist: trusty
sudo: required
env: SWIFT_SNAPSHOT=4.0.3
- os: linux
dist: trusty
sudo: required
- os: osx
osx_image: xcode8.3
sudo: required
env: SWIFT_SNAPSHOT=3.1.1
- os: osx
osx_image: xcode9.2
sudo: required
env: SWIFT_SNAPSHOT=4.0.3
- os: osx
osx_image: xcode9.3beta
osx_image: xcode9.3
sudo: required
env: SWIFT_SNAPSHOT:4.1

before_install:
- git clone https://github.com/IBM-Swift/Package-Builder.git
Expand Down
23 changes: 21 additions & 2 deletions Package.swift
@@ -1,3 +1,6 @@
// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

/**
* Copyright IBM Corporation 2016, 2018
*
Expand All @@ -18,8 +21,24 @@ import PackageDescription

let package = Package(
name: "KituraStencil",
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "KituraStencil",
targets: ["KituraStencil"]
)
],
dependencies: [
.Package(url: "https://github.com/IBM-Swift/Kitura-TemplateEngine.git", majorVersion: 1, minor: 7),
.Package(url: "https://github.com/kylef/Stencil.git", majorVersion: 0, minor: 10)
.package(url: "https://github.com/IBM-Swift/Kitura-TemplateEngine.git", from: "2.0.0"),
.package(url: "https://github.com/kylef/Stencil.git", .upToNextMinor(from: "0.11.0"))
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "KituraStencil",
dependencies: ["KituraTemplateEngine", "Stencil"]
)
]
)

44 changes: 0 additions & 44 deletions Package@swift-4.swift

This file was deleted.

63 changes: 60 additions & 3 deletions Sources/KituraStencil/KituraStencilTemplateEngine.swift
Expand Up @@ -17,10 +17,27 @@
import KituraTemplateEngine
import Stencil
import PathKit
import Foundation

// StencilTemplateEngineError for Error handling.
public enum StencilTemplateEngineError: Swift.Error {
// Thrown when StencilTemplateEngine.rootPaths property is empty.
case rootPathsEmpty
case deprecatedRenderMethodCalled // call render(filePath, context, options, templateName)

// Call render(filePath, context, options, templateName).
case deprecatedRenderMethodCalled

// Thrown when unable to cast 'json' value to a [String: Any].
case unableToCastJSONToDict

// Thrown when unable to encode the Encodable value provided to data.
case unableToEncodeValue(value: Encodable)

// Thrown when Stencil fails to render the context with the given template.
case unableToRenderContext(context: [String: Any])

//Thrown when an array or set of Encodables is passed without a Key.
case noKeyProvidedForType(value: Encodable)
}

public class StencilTemplateEngine: TemplateEngine {
Expand All @@ -39,7 +56,7 @@ public class StencilTemplateEngine: TemplateEngine {
public func render(filePath: String, context: [String: Any]) throws -> String {
throw StencilTemplateEngineError.deprecatedRenderMethodCalled
}

public func render(filePath: String, context: [String: Any], options: RenderingOptions,
templateName: String) throws -> String {
if rootPaths.isEmpty {
Expand All @@ -50,6 +67,46 @@ public class StencilTemplateEngine: TemplateEngine {
let environment = Environment(loader: loader, extensions: [`extension`])
var context = context
context["loader"] = loader
return try environment.renderTemplate(name: templateName, context: context)
do {
return try environment.renderTemplate(name: templateName, context: context)
} catch {
throw StencilTemplateEngineError.unableToRenderContext(context: context)
}
}

public func render<T: Encodable>(filePath: String, with value: T, forKey key: String?,
options: RenderingOptions, templateName: String) throws -> String {
if rootPaths.isEmpty {
throw StencilTemplateEngineError.rootPathsEmpty
}

//Throw an error if an array is passed without providing a key.
if key == nil {
let mirror = Mirror(reflecting: value)
if mirror.displayStyle == .collection || mirror.displayStyle == .set {
throw StencilTemplateEngineError.noKeyProvidedForType(value: value)
}
}

let json: [String: Any]

if let contextKey = key {
json = [contextKey: value]
} else {
var data = Data()
do {
data = try JSONEncoder().encode(value)
} catch {
throw StencilTemplateEngineError.unableToEncodeValue(value: value)
}

guard let dict = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] else {
throw StencilTemplateEngineError.unableToCastJSONToDict
}

json = dict
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not guard let json = try... above, then you wouldn't need this line?

}

return try render(filePath: filePath, context: json, options: options, templateName: templateName)
}
}