method -> transform
This commit is contained in:
@@ -20,7 +20,7 @@ struct HBMustacheSequenceContext: HBMustacheTransformable {
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Transforms available are `first`, `last`, `index`, `even` and `odd`
|
/// Transforms available are `first`, `last`, `index`, `even` and `odd`
|
||||||
/// - Parameter name: Method name
|
/// - Parameter name: transform name
|
||||||
/// - Returns: Result
|
/// - Returns: Result
|
||||||
func transform(_ name: String) -> Any? {
|
func transform(_ name: String) -> Any? {
|
||||||
switch name {
|
switch name {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ extension HBMustacheTemplate {
|
|||||||
|
|
||||||
struct ParserState {
|
struct ParserState {
|
||||||
var sectionName: String?
|
var sectionName: String?
|
||||||
var sectionMethod: String?
|
var sectionTransform: String?
|
||||||
var newLine: Bool
|
var newLine: Bool
|
||||||
var startDelimiter: String
|
var startDelimiter: String
|
||||||
var endDelimiter: String
|
var endDelimiter: String
|
||||||
@@ -38,10 +38,10 @@ extension HBMustacheTemplate {
|
|||||||
self.endDelimiter = "}}"
|
self.endDelimiter = "}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
func withSectionName(_ name: String, method: String? = nil) -> ParserState {
|
func withSectionName(_ name: String, transform: String? = nil) -> ParserState {
|
||||||
var newValue = self
|
var newValue = self
|
||||||
newValue.sectionName = name
|
newValue.sectionName = name
|
||||||
newValue.sectionMethod = method
|
newValue.sectionTransform = transform
|
||||||
return newValue
|
return newValue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,50 +104,50 @@ extension HBMustacheTemplate {
|
|||||||
case "#":
|
case "#":
|
||||||
// section
|
// section
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, method) = try parseName(&parser, state: state)
|
let (name, transform) = try parseName(&parser, state: state)
|
||||||
if self.isStandalone(&parser, state: state) {
|
if self.isStandalone(&parser, state: state) {
|
||||||
setNewLine = true
|
setNewLine = true
|
||||||
} else if whiteSpaceBefore.count > 0 {
|
} else if whiteSpaceBefore.count > 0 {
|
||||||
tokens.append(.text(String(whiteSpaceBefore)))
|
tokens.append(.text(String(whiteSpaceBefore)))
|
||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let sectionTokens = try parse(&parser, state: state.withSectionName(name, method: method))
|
let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform))
|
||||||
tokens.append(.section(name: name, method: method, template: HBMustacheTemplate(sectionTokens)))
|
tokens.append(.section(name: name, transform: transform, template: HBMustacheTemplate(sectionTokens)))
|
||||||
|
|
||||||
case "^":
|
case "^":
|
||||||
// inverted section
|
// inverted section
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, method) = try parseName(&parser, state: state)
|
let (name, transform) = try parseName(&parser, state: state)
|
||||||
if self.isStandalone(&parser, state: state) {
|
if self.isStandalone(&parser, state: state) {
|
||||||
setNewLine = true
|
setNewLine = true
|
||||||
} else if whiteSpaceBefore.count > 0 {
|
} else if whiteSpaceBefore.count > 0 {
|
||||||
tokens.append(.text(String(whiteSpaceBefore)))
|
tokens.append(.text(String(whiteSpaceBefore)))
|
||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let sectionTokens = try parse(&parser, state: state.withSectionName(name, method: method))
|
let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform))
|
||||||
tokens.append(.invertedSection(name: name, method: method, template: HBMustacheTemplate(sectionTokens)))
|
tokens.append(.invertedSection(name: name, transform: transform, template: HBMustacheTemplate(sectionTokens)))
|
||||||
|
|
||||||
case "$":
|
case "$":
|
||||||
// inherited section
|
// inherited section
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, method) = try parseName(&parser, state: state)
|
let (name, transform) = try parseName(&parser, state: state)
|
||||||
// ERROR: can't have methods applied to inherited sections
|
// ERROR: can't have transform applied to inherited sections
|
||||||
guard method == nil else { throw Error.transformAppliedToInheritanceSection }
|
guard transform == nil else { throw Error.transformAppliedToInheritanceSection }
|
||||||
if self.isStandalone(&parser, state: state) {
|
if self.isStandalone(&parser, state: state) {
|
||||||
setNewLine = true
|
setNewLine = true
|
||||||
} else if whiteSpaceBefore.count > 0 {
|
} else if whiteSpaceBefore.count > 0 {
|
||||||
tokens.append(.text(String(whiteSpaceBefore)))
|
tokens.append(.text(String(whiteSpaceBefore)))
|
||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let sectionTokens = try parse(&parser, state: state.withSectionName(name, method: method))
|
let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform))
|
||||||
tokens.append(.inheritedSection(name: name, template: HBMustacheTemplate(sectionTokens)))
|
tokens.append(.inheritedSection(name: name, template: HBMustacheTemplate(sectionTokens)))
|
||||||
|
|
||||||
case "/":
|
case "/":
|
||||||
// end of section
|
// end of section
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let position = parser.position
|
let position = parser.position
|
||||||
let (name, method) = try parseName(&parser, state: state)
|
let (name, transform) = try parseName(&parser, state: state)
|
||||||
guard name == state.sectionName, method == state.sectionMethod else {
|
guard name == state.sectionName, transform == state.sectionTransform else {
|
||||||
parser.unsafeSetPosition(position)
|
parser.unsafeSetPosition(position)
|
||||||
throw Error.sectionCloseNameIncorrect
|
throw Error.sectionCloseNameIncorrect
|
||||||
}
|
}
|
||||||
@@ -172,9 +172,9 @@ extension HBMustacheTemplate {
|
|||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, method) = try parseName(&parser, state: state)
|
let (name, transform) = try parseName(&parser, state: state)
|
||||||
guard try parser.read("}") else { throw Error.unfinishedName }
|
guard try parser.read("}") else { throw Error.unfinishedName }
|
||||||
tokens.append(.unescapedVariable(name: name, method: method))
|
tokens.append(.unescapedVariable(name: name, transform: transform))
|
||||||
|
|
||||||
case "&":
|
case "&":
|
||||||
// unescaped variable
|
// unescaped variable
|
||||||
@@ -183,8 +183,8 @@ extension HBMustacheTemplate {
|
|||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, method) = try parseName(&parser, state: state)
|
let (name, transform) = try parseName(&parser, state: state)
|
||||||
tokens.append(.unescapedVariable(name: name, method: method))
|
tokens.append(.unescapedVariable(name: name, transform: transform))
|
||||||
|
|
||||||
case ">":
|
case ">":
|
||||||
// partial
|
// partial
|
||||||
@@ -204,9 +204,9 @@ extension HBMustacheTemplate {
|
|||||||
case "<":
|
case "<":
|
||||||
// partial with inheritance
|
// partial with inheritance
|
||||||
parser.unsafeAdvance()
|
parser.unsafeAdvance()
|
||||||
let (name, method) = try parseName(&parser, state: state)
|
let (name, transform) = try parseName(&parser, state: state)
|
||||||
// ERROR: can't have methods applied to inherited sections
|
// ERROR: can't have transform applied to inherited sections
|
||||||
guard method == nil else { throw Error.transformAppliedToInheritanceSection }
|
guard transform == nil else { throw Error.transformAppliedToInheritanceSection }
|
||||||
var indent: String?
|
var indent: String?
|
||||||
if self.isStandalone(&parser, state: state) {
|
if self.isStandalone(&parser, state: state) {
|
||||||
setNewLine = true
|
setNewLine = true
|
||||||
@@ -215,8 +215,9 @@ extension HBMustacheTemplate {
|
|||||||
tokens.append(.text(indent!))
|
tokens.append(.text(indent!))
|
||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let sectionTokens = try parse(&parser, state: state.withSectionName(name, method: method))
|
let sectionTokens = try parse(&parser, state: state.withSectionName(name, transform: transform))
|
||||||
var inherit: [String: HBMustacheTemplate] = [:]
|
var inherit: [String: HBMustacheTemplate] = [:]
|
||||||
|
// parse tokens in section to extract inherited sections
|
||||||
for token in sectionTokens {
|
for token in sectionTokens {
|
||||||
switch token {
|
switch token {
|
||||||
case .inheritedSection(let name, let template):
|
case .inheritedSection(let name, let template):
|
||||||
@@ -241,8 +242,8 @@ extension HBMustacheTemplate {
|
|||||||
tokens.append(.text(String(whiteSpaceBefore)))
|
tokens.append(.text(String(whiteSpaceBefore)))
|
||||||
whiteSpaceBefore = ""
|
whiteSpaceBefore = ""
|
||||||
}
|
}
|
||||||
let (name, method) = try parseName(&parser, state: state)
|
let (name, transform) = try parseName(&parser, state: state)
|
||||||
tokens.append(.variable(name: name, method: method))
|
tokens.append(.variable(name: name, transform: transform))
|
||||||
}
|
}
|
||||||
state.newLine = setNewLine
|
state.newLine = setNewLine
|
||||||
}
|
}
|
||||||
@@ -285,7 +286,7 @@ extension HBMustacheTemplate {
|
|||||||
parser.read(while: \.isWhitespace)
|
parser.read(while: \.isWhitespace)
|
||||||
guard try parser.read(string: state.endDelimiter) else { throw Error.unfinishedName }
|
guard try parser.read(string: state.endDelimiter) else { throw Error.unfinishedName }
|
||||||
|
|
||||||
// does the name include brackets. If so this is a method call
|
// does the name include brackets. If so this is a transform call
|
||||||
var nameParser = HBParser(String(text))
|
var nameParser = HBParser(String(text))
|
||||||
let string = nameParser.read(while: self.sectionNameCharsWithoutBrackets)
|
let string = nameParser.read(while: self.sectionNameCharsWithoutBrackets)
|
||||||
if nameParser.reachedEnd() {
|
if nameParser.reachedEnd() {
|
||||||
|
|||||||
@@ -27,24 +27,24 @@ extension HBMustacheTemplate {
|
|||||||
switch token {
|
switch token {
|
||||||
case .text(let text):
|
case .text(let text):
|
||||||
return text
|
return text
|
||||||
case .variable(let variable, let method):
|
case .variable(let variable, let transform):
|
||||||
if let child = getChild(named: variable, method: method, 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 {
|
} else {
|
||||||
return String(describing: child).htmlEscape()
|
return String(describing: child).htmlEscape()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .unescapedVariable(let variable, let method):
|
case .unescapedVariable(let variable, let transform):
|
||||||
if let child = getChild(named: variable, method: method, context: context) {
|
if let child = getChild(named: variable, transform: transform, context: context) {
|
||||||
return String(describing: child)
|
return String(describing: child)
|
||||||
}
|
}
|
||||||
case .section(let variable, let method, let template):
|
case .section(let variable, let transform, let template):
|
||||||
let child = self.getChild(named: variable, method: method, 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)
|
||||||
|
|
||||||
case .invertedSection(let variable, let method, let template):
|
case .invertedSection(let variable, let transform, let template):
|
||||||
let child = self.getChild(named: variable, method: method, context: context)
|
let child = self.getChild(named: variable, transform: transform, context: context)
|
||||||
return self.renderInvertedSection(child, with: template, context: context)
|
return self.renderInvertedSection(child, with: template, context: context)
|
||||||
|
|
||||||
case .inheritedSection(let name, let template):
|
case .inheritedSection(let name, let template):
|
||||||
@@ -103,7 +103,7 @@ extension HBMustacheTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get child object from variable name
|
/// Get child object from variable name
|
||||||
func getChild(named name: String, method: String?, context: HBMustacheContext) -> Any? {
|
func getChild(named name: String, transform: String?, context: HBMustacheContext) -> Any? {
|
||||||
func _getImmediateChild(named name: String, from object: Any) -> Any? {
|
func _getImmediateChild(named name: String, from object: Any) -> Any? {
|
||||||
if let customBox = object as? HBMustacheParent {
|
if let customBox = object as? HBMustacheParent {
|
||||||
return customBox.child(named: name)
|
return customBox.child(named: name)
|
||||||
@@ -132,23 +132,23 @@ extension HBMustacheTemplate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// work out which object to access. "." means the current object, if the variable name is ""
|
// work out which object to access. "." means the current object, if the variable name is ""
|
||||||
// and we have a method to run on the variable then we need the context object, otherwise
|
// and we have a transform to run on the variable then we need the context object, otherwise
|
||||||
// the name is split by "." and we use mirror to get the correct child object
|
// the name is split by "." and we use mirror to get the correct child object
|
||||||
let child: Any?
|
let child: Any?
|
||||||
if name == "." {
|
if name == "." {
|
||||||
child = context.stack.last!
|
child = context.stack.last!
|
||||||
} else if name == "", method != nil {
|
} else if name == "", transform != nil {
|
||||||
child = context.sequenceContext
|
child = context.sequenceContext
|
||||||
} else {
|
} else {
|
||||||
let nameSplit = name.split(separator: ".").map { String($0) }
|
let nameSplit = name.split(separator: ".").map { String($0) }
|
||||||
child = _getChildInStack(named: nameSplit[...], from: context.stack)
|
child = _getChildInStack(named: nameSplit[...], from: context.stack)
|
||||||
}
|
}
|
||||||
// if we want to run a method and the current child can have methods applied to it then
|
// if we want to run a transform and the current child can have transforms applied to it then
|
||||||
// run method on the current child
|
// run transform on the current child
|
||||||
if let method = method,
|
if let transform = transform,
|
||||||
let runnable = child as? HBMustacheTransformable
|
let runnable = child as? HBMustacheTransformable
|
||||||
{
|
{
|
||||||
if let result = runnable.transform(method) {
|
if let result = runnable.transform(transform) {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ public final class HBMustacheTemplate {
|
|||||||
|
|
||||||
enum Token {
|
enum Token {
|
||||||
case text(String)
|
case text(String)
|
||||||
case variable(name: String, method: String? = nil)
|
case variable(name: String, transform: String? = nil)
|
||||||
case unescapedVariable(name: String, method: String? = nil)
|
case unescapedVariable(name: String, transform: String? = nil)
|
||||||
case section(name: String, method: String? = nil, template: HBMustacheTemplate)
|
case section(name: String, transform: String? = nil, template: HBMustacheTemplate)
|
||||||
case invertedSection(name: String, method: String? = nil, template: HBMustacheTemplate)
|
case invertedSection(name: String, transform: String? = nil, template: HBMustacheTemplate)
|
||||||
case inheritedSection(name: String, template: HBMustacheTemplate)
|
case inheritedSection(name: String, template: HBMustacheTemplate)
|
||||||
case partial(String, indentation: String?, inherits: [String: HBMustacheTemplate]?)
|
case partial(String, indentation: String?, inherits: [String: HBMustacheTemplate]?)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/// Objects that can have a transforms run on them. Mustache transforms are specific to this implementation
|
/// Objects that can have a transforms run on them. Mustache transforms are specific to this implementation
|
||||||
/// of Mustache. They allow you to process objects before they are rendered.
|
/// of Mustache. They allow you to process objects before they are rendered.
|
||||||
///
|
///
|
||||||
/// The syntax for applying transforms is `{{method(variable)}}`. Transforms can be applied to both
|
/// The syntax for applying transforms is `{{transform(variable)}}`. Transforms can be applied to both
|
||||||
/// variables, sections and inverted sections.
|
/// variables, sections and inverted sections.
|
||||||
///
|
///
|
||||||
/// A simple example would be ensuring a string is lowercase.
|
/// A simple example would be ensuring a string is lowercase.
|
||||||
@@ -21,7 +21,7 @@ public extension StringProtocol {
|
|||||||
/// Transform String/Substring
|
/// Transform String/Substring
|
||||||
///
|
///
|
||||||
/// Transforms available are `capitalized`, `lowercased`, `uppercased` and `reversed`
|
/// Transforms available are `capitalized`, `lowercased`, `uppercased` and `reversed`
|
||||||
/// - Parameter name: Method name
|
/// - Parameter name: transform name
|
||||||
/// - Returns: Result
|
/// - Returns: Result
|
||||||
func transform(_ name: String) -> Any? {
|
func transform(_ name: String) -> Any? {
|
||||||
switch name {
|
switch name {
|
||||||
@@ -52,7 +52,7 @@ extension Array: HBMustacheTransformable {
|
|||||||
///
|
///
|
||||||
/// Transforms available are `first`, `last`, `reversed`, `count` and for arrays
|
/// Transforms available are `first`, `last`, `reversed`, `count` and for arrays
|
||||||
/// with comparable elements `sorted`.
|
/// with comparable elements `sorted`.
|
||||||
/// - Parameter name: method name
|
/// - Parameter name: transform name
|
||||||
/// - Returns: Result
|
/// - Returns: Result
|
||||||
public func transform(_ name: String) -> Any? {
|
public func transform(_ name: String) -> Any? {
|
||||||
switch name {
|
switch name {
|
||||||
@@ -89,7 +89,7 @@ extension Dictionary: HBMustacheTransformable {
|
|||||||
///
|
///
|
||||||
/// Transforms available are `count`, `enumerated` and for dictionaries
|
/// Transforms available are `count`, `enumerated` and for dictionaries
|
||||||
/// with comparable keys `sorted`.
|
/// with comparable keys `sorted`.
|
||||||
/// - Parameter name: method name
|
/// - Parameter name: transform name
|
||||||
/// - Returns: Result
|
/// - Returns: Result
|
||||||
public func transform(_ name: String) -> Any? {
|
public func transform(_ name: String) -> Any? {
|
||||||
switch name {
|
switch name {
|
||||||
@@ -121,7 +121,7 @@ public extension FixedWidthInteger {
|
|||||||
/// Transform FixedWidthInteger
|
/// Transform FixedWidthInteger
|
||||||
///
|
///
|
||||||
/// Transforms available are `plusone`, `minusone`, `odd`, `even`
|
/// Transforms available are `plusone`, `minusone`, `odd`, `even`
|
||||||
/// - Parameter name: method name
|
/// - Parameter name: transform name
|
||||||
/// - Returns: Result
|
/// - Returns: Result
|
||||||
func transform(_ name: String) -> Any? {
|
func transform(_ name: String) -> Any? {
|
||||||
switch name {
|
switch name {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import HummingbirdMustache
|
import HummingbirdMustache
|
||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
final class MethodTests: XCTestCase {
|
final class TransformTests: XCTestCase {
|
||||||
func testLowercased() throws {
|
func testLowercased() throws {
|
||||||
let template = try HBMustacheTemplate(string: """
|
let template = try HBMustacheTemplate(string: """
|
||||||
{{ lowercased(name) }}
|
{{ lowercased(name) }}
|
||||||
Reference in New Issue
Block a user