From 42d077db4569b5b9d32248ad004a37a46d197579 Mon Sep 17 00:00:00 2001 From: steve benedick Date: Wed, 6 Jan 2021 16:05:03 -0700 Subject: [PATCH] -some cleanup in the rules engine --- LICENSE | 2 +- README.md | 44 ++++++++++++++++--- .../AEPRulesEngine/ConditionEvaluator.swift | 18 +++++--- Sources/AEPRulesEngine/Context.swift | 20 +++++++++ Sources/AEPRulesEngine/Evaluating.swift | 2 +- .../Expression/ComparisonExpression.swift | 10 +++-- .../{ => Expression}/Evaluable.swift | 2 +- .../Expression/LogicalExpression.swift | 4 +- .../AEPRulesEngine/Expression/Operand.swift | 6 +-- .../Expression/UnaryExpression.swift | 4 +- .../{RulesEngineLog.swift => Log/Log.swift} | 9 ++-- .../LogLevel.swift} | 28 +++++------- Sources/AEPRulesEngine/Log/Logging.swift | 22 ++++++++++ Sources/AEPRulesEngine/Operand+Literal.swift | 2 +- .../AEPRulesEngine/Result+RulesFailure.swift | 2 +- Sources/AEPRulesEngine/Rule.swift | 2 +- Sources/AEPRulesEngine/RulesEngine.swift | 23 ++-------- Sources/AEPRulesEngine/RulesFailure.swift | 22 ++++++++++ .../Template/MustacheError.swift | 22 ++++++++++ .../Template/MustacheToken.swift | 3 +- .../Template/ParserTagDelimiters.swift | 37 ++++++++++++++++ Sources/AEPRulesEngine/Template/Segment.swift | 11 +---- .../AEPRulesEngine/Template/Template.swift | 2 +- .../Template/TemplateParser.swift | 35 +++++---------- Sources/AEPRulesEngine/Transformer.swift | 32 ++++++++++++++ Sources/AEPRulesEngine/Transforming.swift | 19 +------- Sources/AEPRulesEngine/Traversable.swift | 2 +- .../UnitTests/ExpressionTests.swift | 28 ++++++------ .../UnitTests/OperandTests.swift | 6 +-- .../UnitTests/ParserTests.swift | 14 +++--- .../UnitTests/RulesEngineLogLevelTests.swift | 16 +++---- .../UnitTests/RulesEngineLoggingTests.swift | 24 +++++----- .../UnitTests/RulesEngineTests.swift | 2 +- .../UnitTests/TraverseTests.swift | 2 +- 34 files changed, 308 insertions(+), 169 deletions(-) create mode 100644 Sources/AEPRulesEngine/Context.swift rename Sources/AEPRulesEngine/{ => Expression}/Evaluable.swift (94%) rename Sources/AEPRulesEngine/{RulesEngineLog.swift => Log/Log.swift} (85%) rename Sources/AEPRulesEngine/{RulesEngineLogging.swift => Log/LogLevel.swift} (56%) create mode 100644 Sources/AEPRulesEngine/Log/Logging.swift create mode 100644 Sources/AEPRulesEngine/RulesFailure.swift create mode 100644 Sources/AEPRulesEngine/Template/MustacheError.swift create mode 100644 Sources/AEPRulesEngine/Template/ParserTagDelimiters.swift create mode 100644 Sources/AEPRulesEngine/Transformer.swift diff --git a/LICENSE b/LICENSE index 758d439..f897003 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2020 Adobe + Copyright 2021 Adobe Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 7754586..c9b1297 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,43 @@ AEPRulesEngine is currently in beta. Use of this code is by invitation only and A simple, generic, extensible Rules Engine in Swift. +## Requirements +- Xcode 11.0 (or newer) +- Swift 5.0 (or newer) + ## Installation +### [CocoaPods](https://guides.cocoapods.org/using/using-cocoapods.html) +```ruby +# Podfile +use_frameworks! + +# for app development, include all the following pods +target 'YOUR_TARGET_NAME' do + pod 'AEPRulesEngine', :git => 'https://github.com/adobe/aepsdk-rulesengine-ios.git', :branch => 'main' + pod 'AEPCore', :git => 'https://github.com/adobe/aepsdk-core-ios.git', :branch => 'main' + pod 'AEPServices', :git => 'https://github.com/adobe/aepsdk-core-ios.git', :branch => 'main' + pod 'AEPLifecycle', :git => 'https://github.com/adobe/aepsdk-core-ios.git', :branch => 'main' + pod 'AEPIdentity', :git => 'https://github.com/adobe/aepsdk-core-ios.git', :branch => 'main' +end + +# for extension development, include AEPCore and its dependencies +target 'YOUR_TARGET_NAME' do + pod 'AEPRulesEngine', :git => 'https://github.com/adobe/aepsdk-rulesengine-ios.git', :branch => 'main' + pod 'AEPCore', :git => 'https://github.com/adobe/aepsdk-core-ios.git', :branch => 'main' + pod 'AEPServices', :git => 'https://github.com/adobe/aepsdk-core-ios.git', :branch => 'main' +end +``` + +Replace `YOUR_TARGET_NAME` and then, in the `Podfile` directory, type: + +```bash +$ pod install +``` + ### Swift Package Manager -To add the AEPRulesEngine Package to your application, from the Xcode menu select: +To add the AEPRulesEngine package to your application, from the Xcode menu select: `File > Swift Packages > Add Package Dependency...` @@ -37,9 +69,9 @@ dependencies: [ ## Usage -### Initialize Rules Engine +### Initialize the Rules Engine -To create a `RuleEngine` instance, first define an `Evaluator` and then use it as the parameter for `RuleEngine`. +To create a `RulesEngine` instance, define an `Evaluator` and pass it to the `RulesEngine`'s initializer: ``` let evaluator = ConditionEvaluator(options: .caseInsensitive) let rulesEngine = RulesEngine(evaluator: evaluator) @@ -47,7 +79,7 @@ let rulesEngine = RulesEngine(evaluator: evaluator) ### Define Rules -Any thing that conforms to the `Rule` protocol can be used as rule. +Anything that conforms to the `Rule` protocol can be used as rule: ``` Swift public class MobileRule: Rule { init(condition: Evaluable) { self.condition = condition } @@ -57,7 +89,7 @@ let condition = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: " let rule = MobileRule(condition: condition) rulesEngine.addRules(rules: [rule]) ``` -However, a rule like this doesn't make much sense, without the ability to dynamically fetch a value it will always be true or false. +A rule without the flexibility to dynamically fetch a value will always evaluate to true or false. To fetch the value for a rule at runtime, use a Mustache Token: ``` Swift let mustache = Operand(mustache: "{{company}}") @@ -68,7 +100,7 @@ rulesEngine.addRules(rules: [rule]) ### Evaluate data -Use the method `evaluate` to run rule engine on the input data that is `Traversable`. +Use the `evaluate` method to process `Traversable` data through the `RulesEngine`: ``` let matchedRules = rulesEngine.evaluate(data: ["company":"adobe"]) diff --git a/Sources/AEPRulesEngine/ConditionEvaluator.swift b/Sources/AEPRulesEngine/ConditionEvaluator.swift index d565f0f..cde5a90 100644 --- a/Sources/AEPRulesEngine/ConditionEvaluator.swift +++ b/Sources/AEPRulesEngine/ConditionEvaluator.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -13,11 +13,14 @@ public class ConditionEvaluator: Evaluating { fileprivate let LOG_TAG = "ConditionEvaluator" var operators: [String: Any] = [:] + + // MARK: - Evaluating public func evaluate(operation: String, lhs: A) -> Result { let op = operators[getHash(operation: operation, typeA: A.self)] as? ((A) -> Bool) + guard let op_ = op else { - let message = "Operator not defined for \(getHash(operation: operation, typeA: A.self))" - RulesEngineLog.trace(label: LOG_TAG, message) + let message = "No operator defined for \(getHash(operation: operation, typeA: A.self))" + Log.trace(label: LOG_TAG, message) return Result.failure(RulesFailure.missingOperator(message: message)) } return op_(lhs) ? Result.success(true) : Result.failure(.conditionNotMatched(message: "(\(String(describing: A.self))(\(lhs)) \(operation))")) @@ -27,8 +30,8 @@ public class ConditionEvaluator: Evaluating { let op = operators[getHash(operation: operation, typeA: A.self, typeB: B.self)] as? ((A, B) -> Bool) guard let op_ = op else { - let message = "Operator not defined for \(getHash(operation: operation, typeA: A.self, typeB: B.self))" - RulesEngineLog.trace(label: LOG_TAG, message) + let message = "No operator defined for \(getHash(operation: operation, typeA: A.self, typeB: B.self))" + Log.trace(label: LOG_TAG, message) return Result.failure(RulesFailure.missingOperator(message: message)) } return op_(lhs, rhs) ? Result.success(true) : Result.failure(.conditionNotMatched(message: "\(String(describing: A.self))(\(lhs)) \(operation) \(String(describing: B.self))(\(rhs))")) @@ -78,6 +81,7 @@ public extension ConditionEvaluator { } private func addDefaultOperators() { + addComparisonOperator(operation: "and", type: Bool.self, closure: { $0 && $1 }) addComparisonOperator(operation: "or", type: Bool.self, closure: { $0 || $1 }) @@ -117,9 +121,11 @@ public extension ConditionEvaluator { } private func addCaseInSensitiveOperators() { - addComparisonOperator(operation: "startsWith", type: String.self, closure: { $0.lowercased().starts(with: $1.lowercased()) }) addComparisonOperator(operation: "equals", type: String.self, closure: { $0.lowercased() == $1.lowercased() }) + addComparisonOperator(operation: "notEquals", type: String.self, closure: { $0.lowercased() != $1.lowercased() }) + addComparisonOperator(operation: "startsWith", type: String.self, closure: { $0.lowercased().starts(with: $1.lowercased()) }) addComparisonOperator(operation: "endsWith", type: String.self, closure: { $0.lowercased().hasSuffix($1.lowercased()) }) addComparisonOperator(operation: "contains", type: String.self, closure: { $0.lowercased().contains($1.lowercased()) }) + addComparisonOperator(operation: "notContains", type: String.self, closure: { !$0.lowercased().contains($1.lowercased()) }) } } diff --git a/Sources/AEPRulesEngine/Context.swift b/Sources/AEPRulesEngine/Context.swift new file mode 100644 index 0000000..965b743 --- /dev/null +++ b/Sources/AEPRulesEngine/Context.swift @@ -0,0 +1,20 @@ +/* + Copyright 2021 Adobe. All rights reserved. + This file is licensed to you under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + OF ANY KIND, either express or implied. See the License for the specific language + governing permissions and limitations under the License. + */ + +import Foundation + +/// A type that contains all pieces necessary for boolean evaluation +public struct Context { + public let data: Traversable + public let evaluator: Evaluating + public let transformer: Transforming +} diff --git a/Sources/AEPRulesEngine/Evaluating.swift b/Sources/AEPRulesEngine/Evaluating.swift index 18f1bd1..5457451 100644 --- a/Sources/AEPRulesEngine/Evaluating.swift +++ b/Sources/AEPRulesEngine/Evaluating.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/Sources/AEPRulesEngine/Expression/ComparisonExpression.swift b/Sources/AEPRulesEngine/Expression/ComparisonExpression.swift index 2a74b55..b9e604f 100644 --- a/Sources/AEPRulesEngine/Expression/ComparisonExpression.swift +++ b/Sources/AEPRulesEngine/Expression/ComparisonExpression.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -24,8 +24,10 @@ public struct ComparisonExpression: Evaluable { self.operationName = operationName } + // MARK: - Evaluable + public func evaluate(in context: Context) -> Result { - RulesEngineLog.trace(label: LOG_TAG, "Evaluating \(lhs) - \(operationName) - \(rhs)") + Log.trace(label: LOG_TAG, "Evaluating \(lhs) - \(operationName) - \(rhs)") let resolvedLhs = lhs(context) let resolvedRhs = rhs(context) var result: Result @@ -38,8 +40,8 @@ public struct ComparisonExpression: Evaluable { case .success: return result case let .failure(error): - RulesEngineLog.debug(label: LOG_TAG, "Failed to evaluate \(String(describing: resolvedLhs)) - \(operationName) - \(String(describing: resolvedRhs))") - return Result.failure(.innerFailure(message: "Comparison (\(lhs) \(operationName) \(rhs)) returns false", error: error)) + Log.debug(label: LOG_TAG, "Failed to evaluate \(String(describing: resolvedLhs)) - \(operationName) - \(String(describing: resolvedRhs))") + return Result.failure(.innerFailure(message: "Comparison (\(lhs) \(operationName) \(rhs)) returned false", error: error)) } } } diff --git a/Sources/AEPRulesEngine/Evaluable.swift b/Sources/AEPRulesEngine/Expression/Evaluable.swift similarity index 94% rename from Sources/AEPRulesEngine/Evaluable.swift rename to Sources/AEPRulesEngine/Expression/Evaluable.swift index 649326e..71ec5db 100644 --- a/Sources/AEPRulesEngine/Evaluable.swift +++ b/Sources/AEPRulesEngine/Expression/Evaluable.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/Sources/AEPRulesEngine/Expression/LogicalExpression.swift b/Sources/AEPRulesEngine/Expression/LogicalExpression.swift index f11aa2d..06e6f76 100644 --- a/Sources/AEPRulesEngine/Expression/LogicalExpression.swift +++ b/Sources/AEPRulesEngine/Expression/LogicalExpression.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -43,7 +43,7 @@ public struct LogicalExpression: Evaluable { } return Result.failure(.innerFailures(message: "`Or` returns false", errors: operandsResolve.filter { !$0.value }.map { $0.error ?? RulesFailure.unknown })) default: - return .failure(.missingOperator(message: "Unkonwn conjunction operator")) + return .failure(.missingOperator(message: "Unknown conjunction operator '\(operationName)'")) } } } diff --git a/Sources/AEPRulesEngine/Expression/Operand.swift b/Sources/AEPRulesEngine/Expression/Operand.swift index 51a66e1..9d3df7b 100644 --- a/Sources/AEPRulesEngine/Expression/Operand.swift +++ b/Sources/AEPRulesEngine/Expression/Operand.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -51,9 +51,9 @@ extension Operand: CustomStringConvertible { case .none: return "" case let .some(value): - return "" + return "" case let .token(mustache): - return "" + return "" } } } diff --git a/Sources/AEPRulesEngine/Expression/UnaryExpression.swift b/Sources/AEPRulesEngine/Expression/UnaryExpression.swift index dff8ec2..335c142 100644 --- a/Sources/AEPRulesEngine/Expression/UnaryExpression.swift +++ b/Sources/AEPRulesEngine/Expression/UnaryExpression.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -23,7 +23,7 @@ public struct UnaryExpression: Evaluable { } public func evaluate(in context: Context) -> Result { - RulesEngineLog.trace(label: LOG_TAG, "Evaluating \(operationName) - \(lhs)") + Log.trace(label: LOG_TAG, "Evaluating \(operationName) - \(lhs)") let resolvedLhs = lhs(context) if let resolvedLhs_ = resolvedLhs { return context.evaluator.evaluate(operation: operationName, lhs: resolvedLhs_) diff --git a/Sources/AEPRulesEngine/RulesEngineLog.swift b/Sources/AEPRulesEngine/Log/Log.swift similarity index 85% rename from Sources/AEPRulesEngine/RulesEngineLog.swift rename to Sources/AEPRulesEngine/Log/Log.swift index 9c6b718..c24280f 100644 --- a/Sources/AEPRulesEngine/RulesEngineLog.swift +++ b/Sources/AEPRulesEngine/Log/Log.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -12,8 +12,11 @@ import Foundation -public class RulesEngineLog { - public static var logging: RulesEngineLogging? +/// The `Log` class will be dormant unless its static `logging` variable is initialized. +/// To enable logging from the RulesEngine, implement a class that conforms to the +/// `Logging` protocol and use an instance of it to set the `Log.logging` variable. +public class Log { + public static var logging: Logging? /// Used to print more verbose information. /// - Parameters: /// - label: the name of the label to localize message diff --git a/Sources/AEPRulesEngine/RulesEngineLogging.swift b/Sources/AEPRulesEngine/Log/LogLevel.swift similarity index 56% rename from Sources/AEPRulesEngine/RulesEngineLogging.swift rename to Sources/AEPRulesEngine/Log/LogLevel.swift index c34a226..221e7a5 100644 --- a/Sources/AEPRulesEngine/RulesEngineLogging.swift +++ b/Sources/AEPRulesEngine/Log/LogLevel.swift @@ -1,9 +1,9 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, either express or implied. See the License for the specific language @@ -11,30 +11,22 @@ */ import Foundation -public protocol RulesEngineLogging { - /// Logs a message - /// - Parameters: - /// - level: One of the message level identifiers, e.g., DEBUG - /// - label: Name of a label to localize message - /// - message: The string message - func log(level: RulesEngineLogLevel, label: String, message: String) -} -public enum RulesEngineLogLevel: Int, Comparable { +public enum LogLevel: Int, Comparable { case error = 0 case warning = 1 case debug = 2 case trace = 3 - - /// Compares two `RulesEngineLogLevel`s for order + + /// Compares two `LogLevel`s for order /// - Parameters: - /// - lhs: the first `RulesEngineLogLevel` to be compared - /// - rhs: the second `RulesEngineLogLevel` to be compared - /// - Returns: true, only if the second `LogLevel` is more critical - public static func < (lhs: RulesEngineLogLevel, rhs: RulesEngineLogLevel) -> Bool { + /// - lhs: the first `LogLevel` to be compared + /// - rhs: the second `LogLevel` to be compared + /// - Returns: true if the second `LogLevel` is more critical + public static func < (lhs: LogLevel, rhs: LogLevel) -> Bool { lhs.rawValue < rhs.rawValue } - + public func toString() -> String { switch self { case .trace: diff --git a/Sources/AEPRulesEngine/Log/Logging.swift b/Sources/AEPRulesEngine/Log/Logging.swift new file mode 100644 index 0000000..c3e4b57 --- /dev/null +++ b/Sources/AEPRulesEngine/Log/Logging.swift @@ -0,0 +1,22 @@ +/* + Copyright 2021 Adobe. All rights reserved. + This file is licensed to you under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + OF ANY KIND, either express or implied. See the License for the specific language + governing permissions and limitations under the License. + */ + +import Foundation + +public protocol Logging { + /// Logs a message + /// - Parameters: + /// - level: A `LogLevel` identifying the severity of the log. e.g. - `.debug` + /// - label: Label for the log + /// - message: The `String` message + func log(level: LogLevel, label: String, message: String) +} diff --git a/Sources/AEPRulesEngine/Operand+Literal.swift b/Sources/AEPRulesEngine/Operand+Literal.swift index 7e92b66..f741f65 100644 --- a/Sources/AEPRulesEngine/Operand+Literal.swift +++ b/Sources/AEPRulesEngine/Operand+Literal.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/Sources/AEPRulesEngine/Result+RulesFailure.swift b/Sources/AEPRulesEngine/Result+RulesFailure.swift index cdefc23..ec3e25b 100644 --- a/Sources/AEPRulesEngine/Result+RulesFailure.swift +++ b/Sources/AEPRulesEngine/Result+RulesFailure.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/Sources/AEPRulesEngine/Rule.swift b/Sources/AEPRulesEngine/Rule.swift index fe59f7a..867c2c4 100644 --- a/Sources/AEPRulesEngine/Rule.swift +++ b/Sources/AEPRulesEngine/Rule.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/Sources/AEPRulesEngine/RulesEngine.swift b/Sources/AEPRulesEngine/RulesEngine.swift index e074337..67e152b 100644 --- a/Sources/AEPRulesEngine/RulesEngine.swift +++ b/Sources/AEPRulesEngine/RulesEngine.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -20,7 +20,7 @@ public class RulesEngine { var tracer: RulesTracer? var rules = [T]() - public init(evaluator: Evaluating, transformer: Transforming = Transform()) { + public init(evaluator: Evaluating, transformer: Transforming = Transformer()) { self.evaluator = evaluator self.transformer = transformer } @@ -51,24 +51,9 @@ public class RulesEngine { rules = [T]() } - /// trace the result of each rule eveluation - /// - Parameter tracer: the rules tracer will be called after each rule eveluation + /// trace the result of each rule evaluation + /// - Parameter tracer: the `RulesTracer` which will be called after each rule evaluation public func trace(with tracer: @escaping RulesTracer) { self.tracer = tracer } } - -public struct Context { - public let data: Traversable - public let evaluator: Evaluating - public let transformer: Transforming -} - -public enum RulesFailure: Error { - case unknown - case conditionNotMatched(message: String) - case typeMismatched(message: String) - case missingOperator(message: String) - indirect case innerFailure(message: String, error: RulesFailure) - indirect case innerFailures(message: String, errors: [RulesFailure]) -} diff --git a/Sources/AEPRulesEngine/RulesFailure.swift b/Sources/AEPRulesEngine/RulesFailure.swift new file mode 100644 index 0000000..fc47864 --- /dev/null +++ b/Sources/AEPRulesEngine/RulesFailure.swift @@ -0,0 +1,22 @@ +/* + Copyright 2021 Adobe. All rights reserved. + This file is licensed to you under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + OF ANY KIND, either express or implied. See the License for the specific language + governing permissions and limitations under the License. + */ + +import Foundation + +public enum RulesFailure: Error { + case unknown + case conditionNotMatched(message: String) + case typeMismatched(message: String) + case missingOperator(message: String) + indirect case innerFailure(message: String, error: RulesFailure) + indirect case innerFailures(message: String, errors: [RulesFailure]) +} diff --git a/Sources/AEPRulesEngine/Template/MustacheError.swift b/Sources/AEPRulesEngine/Template/MustacheError.swift new file mode 100644 index 0000000..d0d9ddc --- /dev/null +++ b/Sources/AEPRulesEngine/Template/MustacheError.swift @@ -0,0 +1,22 @@ +/* + Copyright 2021 Adobe. All rights reserved. + This file is licensed to you under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + OF ANY KIND, either express or implied. See the License for the specific language + governing permissions and limitations under the License. + */ + +import Foundation + +public struct MustacheError: Error { + /// Eventual error message + public let message: String? + + public init(message: String? = nil) { + self.message = message + } +} diff --git a/Sources/AEPRulesEngine/Template/MustacheToken.swift b/Sources/AEPRulesEngine/Template/MustacheToken.swift index eb693e0..f813a2f 100644 --- a/Sources/AEPRulesEngine/Template/MustacheToken.swift +++ b/Sources/AEPRulesEngine/Template/MustacheToken.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -11,6 +11,7 @@ */ import Foundation + public indirect enum MustacheToken { /// text case variable(text: String) diff --git a/Sources/AEPRulesEngine/Template/ParserTagDelimiters.swift b/Sources/AEPRulesEngine/Template/ParserTagDelimiters.swift new file mode 100644 index 0000000..00de45f --- /dev/null +++ b/Sources/AEPRulesEngine/Template/ParserTagDelimiters.swift @@ -0,0 +1,37 @@ +/* + Copyright 2021 Adobe. All rights reserved. + This file is licensed to you under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + OF ANY KIND, either express or implied. See the License for the specific language + governing permissions and limitations under the License. + */ + +import Foundation + +struct ParserTagDelimiters { + let tagDelimiterPair: DelimiterPair + + init(_ tagDelimiterPair: DelimiterPair) { + self.tagDelimiterPair = tagDelimiterPair + } + + var startTag: String { + return tagDelimiterPair.0 + } + + var startTagLength: Int { + return startTag.count + } + + var endTag: String { + return tagDelimiterPair.1 + } + + var endTagLength: Int { + return endTag.count + } +} diff --git a/Sources/AEPRulesEngine/Template/Segment.swift b/Sources/AEPRulesEngine/Template/Segment.swift index e120a31..4f16bbd 100644 --- a/Sources/AEPRulesEngine/Template/Segment.swift +++ b/Sources/AEPRulesEngine/Template/Segment.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -10,15 +10,6 @@ governing permissions and limitations under the License. */ -public struct MustacheError: Error { - /// Eventual error message - public let message: String? - - public init(message: String? = nil) { - self.message = message - } -} - public struct Segment { enum `Type` { /// text diff --git a/Sources/AEPRulesEngine/Template/Template.swift b/Sources/AEPRulesEngine/Template/Template.swift index b2ff21c..c3f10ce 100644 --- a/Sources/AEPRulesEngine/Template/Template.swift +++ b/Sources/AEPRulesEngine/Template/Template.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/Sources/AEPRulesEngine/Template/TemplateParser.swift b/Sources/AEPRulesEngine/Template/TemplateParser.swift index cc5187c..3cbc3cb 100644 --- a/Sources/AEPRulesEngine/Template/TemplateParser.swift +++ b/Sources/AEPRulesEngine/Template/TemplateParser.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -13,6 +13,8 @@ import Foundation /// A pair of tag delimiters, such as `("{{", "}}")`. +public typealias DelimiterPair = (String, String) + public struct TemplateParser { static let DefaultTagDelimiterPair: DelimiterPair = ("{{", "}}") @@ -27,15 +29,15 @@ public struct TemplateParser { while i < end { switch state { case .start: - if index(i, isAt: currentDelimiters.tagDelimiterPair.0, in: templateString) { + if index(i, isAt: currentDelimiters.startTag, in: templateString) { state = .tag(startIndex: i) - i = templateString.index(i, offsetBy: currentDelimiters.tagStartLength) + i = templateString.index(i, offsetBy: currentDelimiters.startTagLength) i = templateString.index(before: i) } else { state = .text(startIndex: i) } case let .text(startIndex): - if index(i, isAt: currentDelimiters.tagDelimiterPair.0, in: templateString) { + if index(i, isAt: currentDelimiters.startTag, in: templateString) { if startIndex != i { let range = startIndex ..< i let token = Segment( @@ -47,13 +49,13 @@ public struct TemplateParser { tokens.append(token) } state = .tag(startIndex: i) - i = templateString.index(i, offsetBy: currentDelimiters.tagStartLength) + i = templateString.index(i, offsetBy: currentDelimiters.startTagLength) i = templateString.index(before: i) } case let .tag(startIndex): - if index(i, isAt: currentDelimiters.tagDelimiterPair.1, in: templateString) { - let tagInitialIndex = templateString.index(startIndex, offsetBy: currentDelimiters.tagStartLength) - let tokenRange = startIndex ..< templateString.index(i, offsetBy: currentDelimiters.tagEndLength) + if index(i, isAt: currentDelimiters.endTag, in: templateString) { + let tagInitialIndex = templateString.index(startIndex, offsetBy: currentDelimiters.startTagLength) + let tokenRange = startIndex ..< templateString.index(i, offsetBy: currentDelimiters.endTagLength) let content = String(templateString[tagInitialIndex ..< i]) let mustacheToken = MustacheToken(content) @@ -65,7 +67,7 @@ public struct TemplateParser { tokens.append(token) state = .start - i = templateString.index(i, offsetBy: currentDelimiters.tagEndLength) + i = templateString.index(i, offsetBy: currentDelimiters.endTagLength) i = templateString.index(before: i) } } @@ -107,18 +109,3 @@ public struct TemplateParser { case tag(startIndex: String.Index) } } - -/// A pair of tag delimiters, such as `("{{", "}}")`. -public typealias DelimiterPair = (String, String) - -public struct ParserTagDelimiters { - let tagDelimiterPair: DelimiterPair - let tagStartLength: Int - let tagEndLength: Int - init(_ tagDelimiterPair: DelimiterPair) { - self.tagDelimiterPair = tagDelimiterPair - - tagStartLength = tagDelimiterPair.0.distance(from: tagDelimiterPair.0.startIndex, to: tagDelimiterPair.0.endIndex) - tagEndLength = tagDelimiterPair.1.distance(from: tagDelimiterPair.1.startIndex, to: tagDelimiterPair.1.endIndex) - } -} diff --git a/Sources/AEPRulesEngine/Transformer.swift b/Sources/AEPRulesEngine/Transformer.swift new file mode 100644 index 0000000..dc5e53c --- /dev/null +++ b/Sources/AEPRulesEngine/Transformer.swift @@ -0,0 +1,32 @@ +/* + Copyright 2021 Adobe. All rights reserved. + This file is licensed to you under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. You may obtain a copy + of the License at http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + OF ANY KIND, either express or implied. See the License for the specific language + governing permissions and limitations under the License. + */ + +import Foundation + +public class Transformer: Transforming { + var transformations: [String: Transformation] = [:] + + public init() {} + + public func register(name: String, transformation: @escaping Transformation) { + transformations[name] = transformation + } + + // MARK: - Transforming + + public func transform(name: String, parameter: Any) -> Any { + guard let transformation = transformations[name] else { + return parameter + } + return transformation(parameter) + } +} diff --git a/Sources/AEPRulesEngine/Transforming.swift b/Sources/AEPRulesEngine/Transforming.swift index 3f15da5..47e6969 100644 --- a/Sources/AEPRulesEngine/Transforming.swift +++ b/Sources/AEPRulesEngine/Transforming.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -11,25 +11,10 @@ */ import Foundation + public typealias Transformation = (Any) -> Any public protocol Transforming { func transform(name: String, parameter: Any) -> Any } -public class Transform: Transforming { - var transformations: [String: Transformation] = [:] - - public init() {} - - public func transform(name: String, parameter: Any) -> Any { - guard let transformation = transformations[name] else { - return parameter - } - return transformation(parameter) - } - - public func register(name: String, transformation: @escaping Transformation) { - transformations[name] = transformation - } -} diff --git a/Sources/AEPRulesEngine/Traversable.swift b/Sources/AEPRulesEngine/Traversable.swift index 5db00e5..e4ecf70 100644 --- a/Sources/AEPRulesEngine/Traversable.swift +++ b/Sources/AEPRulesEngine/Traversable.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/Tests/AEPRulesEngineTests/UnitTests/ExpressionTests.swift b/Tests/AEPRulesEngineTests/UnitTests/ExpressionTests.swift index ac3ef3c..50499da 100644 --- a/Tests/AEPRulesEngineTests/UnitTests/ExpressionTests.swift +++ b/Tests/AEPRulesEngineTests/UnitTests/ExpressionTests.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -33,7 +33,7 @@ class ExpressionTests: XCTestCase { let evaluator = ConditionEvaluator(options: .defaultOptions) let a = ComparisonExpression(lhs: 3, operationName: "equals", rhs: 3) - let result = a.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transform())) + let result = a.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transformer())) XCTAssertTrue(result.value) } @@ -43,7 +43,7 @@ class ExpressionTests: XCTestCase { let a = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc") let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc") let c = LogicalExpression(operationName: "and", operands: a, b) - let result = c.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transform())) + let result = c.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transformer())) XCTAssertTrue(result.value) } @@ -53,7 +53,7 @@ class ExpressionTests: XCTestCase { let a = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc1") let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc") let c = LogicalExpression(operationName: "or", operands: a, b) - let result = c.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transform())) + let result = c.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transformer())) XCTAssertTrue(result.value) } @@ -63,7 +63,7 @@ class ExpressionTests: XCTestCase { let a = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc1") let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc1") let c = LogicalExpression(operationName: "or", operands: a, b) - let result = c.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transform())) + let result = c.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transformer())) XCTAssertTrue(!result.value) } @@ -73,7 +73,7 @@ class ExpressionTests: XCTestCase { let a = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc1") let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc1") let c = LogicalExpression(operationName: "unkonwn", operands: a, b) - let result = c.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transform())) + let result = c.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transformer())) XCTAssertTrue(!result.value) } @@ -87,7 +87,7 @@ class ExpressionTests: XCTestCase { let a = UnaryExpression(lhs: mustache, operationName: "isTrue") let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc") let c = LogicalExpression(operationName: "and", operands: a, b) - let result = c.evaluate(in: Context(data: ["custom1": CustomOperand()], evaluator: evaluator, transformer: Transform())) + let result = c.evaluate(in: Context(data: ["custom1": CustomOperand()], evaluator: evaluator, transformer: Transformer())) XCTAssertTrue(!result.value) } @@ -97,7 +97,7 @@ class ExpressionTests: XCTestCase { let a = ComparisonExpression(lhs: mustache, operationName: "equals", rhs: "abc") let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc") let c = LogicalExpression(operationName: "and", operands: a, b) - let result = c.evaluate(in: Context(data: ["key": "abc"], evaluator: evaluator, transformer: Transform())) + let result = c.evaluate(in: Context(data: ["key": "abc"], evaluator: evaluator, transformer: Transformer())) XCTAssertTrue(result.value) } @@ -107,7 +107,7 @@ class ExpressionTests: XCTestCase { let a = ComparisonExpression(lhs: mustache, operationName: "equals", rhs: "abc") let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc") let c = LogicalExpression(operationName: "and", operands: a, b) - let result = c.evaluate(in: Context(data: ["key1": "abc"], evaluator: evaluator, transformer: Transform())) + let result = c.evaluate(in: Context(data: ["key1": "abc"], evaluator: evaluator, transformer: Transformer())) XCTAssertTrue(!result.value) } @@ -117,7 +117,7 @@ class ExpressionTests: XCTestCase { let a = ComparisonExpression(lhs: mustache, operationName: "equals", rhs: "abc") let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc") let c = LogicalExpression(operationName: "and", operands: [a, b]) - let result = c.evaluate(in: Context(data: ["someelse": "abc"], evaluator: evaluator, transformer: Transform())) + let result = c.evaluate(in: Context(data: ["someelse": "abc"], evaluator: evaluator, transformer: Transformer())) XCTAssertFalse(result.value) } @@ -127,7 +127,7 @@ class ExpressionTests: XCTestCase { let a = ComparisonExpression(lhs: mustache, operationName: "nx", rhs: Operand.none) let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc") let c = LogicalExpression(operationName: "and", operands: a, b) - let result = c.evaluate(in: Context(data: ["key": "abc"], evaluator: evaluator, transformer: Transform())) + let result = c.evaluate(in: Context(data: ["key": "abc"], evaluator: evaluator, transformer: Transformer())) XCTAssertFalse(result.value) } @@ -138,7 +138,7 @@ class ExpressionTests: XCTestCase { let a = ComparisonExpression(lhs: mustache, operationName: "notExist", rhs: Operand.none) let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc") let c = LogicalExpression(operationName: "and", operands: a, b) - let result = c.evaluate(in: Context(data: ["key": "abc"], evaluator: evaluator, transformer: Transform())) + let result = c.evaluate(in: Context(data: ["key": "abc"], evaluator: evaluator, transformer: Transformer())) XCTAssertTrue(result.value) } @@ -153,7 +153,7 @@ class ExpressionTests: XCTestCase { let a = UnaryExpression(lhs: mustache, operationName: "isAmazing") let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc") let c = LogicalExpression(operationName: "and", operands: a, b) - let result = c.evaluate(in: Context(data: ["custom": CustomOperand()], evaluator: evaluator, transformer: Transform())) + let result = c.evaluate(in: Context(data: ["custom": CustomOperand()], evaluator: evaluator, transformer: Transformer())) XCTAssertTrue(result.value) } @@ -163,7 +163,7 @@ class ExpressionTests: XCTestCase { true } let a = ComparisonExpression(lhs: "3", operationName: "equals", rhs: 3) - let result = a.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transform())) + let result = a.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transformer())) XCTAssertTrue(result.value) } } diff --git a/Tests/AEPRulesEngineTests/UnitTests/OperandTests.swift b/Tests/AEPRulesEngineTests/UnitTests/OperandTests.swift index 7227354..d542cf4 100644 --- a/Tests/AEPRulesEngineTests/UnitTests/OperandTests.swift +++ b/Tests/AEPRulesEngineTests/UnitTests/OperandTests.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -24,12 +24,12 @@ class OperandTests: XCTestCase { func testDoubleValue(){ let operand = Operand(floatLiteral: 1.2) - XCTAssertEqual("", String(describing: operand)) + XCTAssertEqual("", String(describing: operand)) } func testBoolValue(){ let operand = Operand(booleanLiteral: true) - XCTAssertEqual("", String(describing: operand)) + XCTAssertEqual("", String(describing: operand)) } func testNilValue(){ diff --git a/Tests/AEPRulesEngineTests/UnitTests/ParserTests.swift b/Tests/AEPRulesEngineTests/UnitTests/ParserTests.swift index dbf40a7..b201e70 100644 --- a/Tests/AEPRulesEngineTests/UnitTests/ParserTests.swift +++ b/Tests/AEPRulesEngineTests/UnitTests/ParserTests.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -31,19 +31,19 @@ class ParserTests: XCTestCase { func testPerformanceExample() { let template = Template(templateString: "sdfdfd{{test}}aaa") - let result = template.render(data: ["test": "value"], transformers: Transform()) + let result = template.render(data: ["test": "value"], transformers: Transformer()) XCTAssertEqual("sdfdfdvalueaaa", result) } func testCustomizedTokenFormat() { let template = Template(templateString: "sdfdfd[[test]]aaa", tagDelimiterPair: ("[[","]]")) - let result = template.render(data: ["test": "value"], transformers: Transform()) + let result = template.render(data: ["test": "value"], transformers: Transformer()) XCTAssertEqual("sdfdfdvalueaaa", result) } func testTransform() { let template = Template(templateString: "sdfdfd{{dash(test)}}aaa") - let tran = Transform() + let tran = Transformer() tran.register(name: "dash", transformation: { value in if value is String { return "-\(value as! String)-" @@ -58,21 +58,21 @@ class ParserTests: XCTestCase { func testTransform1() { let template = Template(templateString: "sdfdfd{{dash(test)}}aaa{{dash(int)}}") - let tran = Transform() + let tran = Transformer() let result = template.render(data: ["test": "value", "int": 5], transformers: tran) XCTAssertEqual("sdfdfdvalueaaa5", result) } func testTransform12() { let template = Template(templateString: "sdfdfd{{dash(test)}}aaa{{dash(int)}") - let tran = Transform() + let tran = Transformer() let result = template.render(data: ["test": "value", "int": 5], transformers: tran) XCTAssertEqual("", result) } func testTransform123() { let template = Template(templateString: "sdfdfd{{}}") - let tran = Transform() + let tran = Transformer() let result = template.render(data: ["test": "value", "int": 5], transformers: tran) XCTAssertEqual("sdfdfd", result) } diff --git a/Tests/AEPRulesEngineTests/UnitTests/RulesEngineLogLevelTests.swift b/Tests/AEPRulesEngineTests/UnitTests/RulesEngineLogLevelTests.swift index 5f686ef..5e71e9e 100644 --- a/Tests/AEPRulesEngineTests/UnitTests/RulesEngineLogLevelTests.swift +++ b/Tests/AEPRulesEngineTests/UnitTests/RulesEngineLogLevelTests.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -16,15 +16,15 @@ import XCTest class RulesEngineLogLevelTests: XCTestCase { func testLogLevelComparison() { - XCTAssertTrue(RulesEngineLogLevel.error < RulesEngineLogLevel.warning) - XCTAssertTrue(RulesEngineLogLevel.warning < RulesEngineLogLevel.debug) - XCTAssertTrue(RulesEngineLogLevel.debug < RulesEngineLogLevel.trace) + XCTAssertTrue(LogLevel.error < LogLevel.warning) + XCTAssertTrue(LogLevel.warning < LogLevel.debug) + XCTAssertTrue(LogLevel.debug < LogLevel.trace) } func testLogLevelToString() { - XCTAssertEqual(RulesEngineLogLevel.error.toString(), "ERROR") - XCTAssertEqual(RulesEngineLogLevel.warning.toString(), "WARNING") - XCTAssertEqual(RulesEngineLogLevel.debug.toString(), "DEBUG") - XCTAssertEqual(RulesEngineLogLevel.trace.toString(), "TRACE") + XCTAssertEqual(LogLevel.error.toString(), "ERROR") + XCTAssertEqual(LogLevel.warning.toString(), "WARNING") + XCTAssertEqual(LogLevel.debug.toString(), "DEBUG") + XCTAssertEqual(LogLevel.trace.toString(), "TRACE") } } diff --git a/Tests/AEPRulesEngineTests/UnitTests/RulesEngineLoggingTests.swift b/Tests/AEPRulesEngineTests/UnitTests/RulesEngineLoggingTests.swift index a7c8bd3..5270ae2 100644 --- a/Tests/AEPRulesEngineTests/UnitTests/RulesEngineLoggingTests.swift +++ b/Tests/AEPRulesEngineTests/UnitTests/RulesEngineLoggingTests.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 @@ -15,11 +15,11 @@ import XCTest @testable import AEPRulesEngine -private class Log: RulesEngineLogging { +private class TestLogger: Logging { public var message = "" public var label = "" - public var level = RulesEngineLogLevel.debug - public func log(level: RulesEngineLogLevel, label: String, message: String) { + public var level = LogLevel.debug + public func log(level: LogLevel, label: String, message: String) { self.message = message self.level = level self.label = label @@ -28,15 +28,15 @@ private class Log: RulesEngineLogging { class RulesEngineLoggingTests: XCTestCase { func testLogging() { - let log = Log() - RulesEngineLog.logging = log - RulesEngineLog.debug(label: "labelA", "debug message") + let log = TestLogger() + Log.logging = log + Log.debug(label: "labelA", "debug message") XCTAssertEqual("labelA", log.label) XCTAssertEqual("debug message", log.message) - XCTAssertEqual(RulesEngineLogLevel.debug, log.level) - RulesEngineLog.warning(label: "labelA", "warning message") - XCTAssertEqual(RulesEngineLogLevel.warning, log.level) - RulesEngineLog.error(label: "labelA", "error message") - XCTAssertEqual(RulesEngineLogLevel.error, log.level) + XCTAssertEqual(LogLevel.debug, log.level) + Log.warning(label: "labelA", "warning message") + XCTAssertEqual(LogLevel.warning, log.level) + Log.error(label: "labelA", "error message") + XCTAssertEqual(LogLevel.error, log.level) } } diff --git a/Tests/AEPRulesEngineTests/UnitTests/RulesEngineTests.swift b/Tests/AEPRulesEngineTests/UnitTests/RulesEngineTests.swift index ba02fda..265e00f 100644 --- a/Tests/AEPRulesEngineTests/UnitTests/RulesEngineTests.swift +++ b/Tests/AEPRulesEngineTests/UnitTests/RulesEngineTests.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 diff --git a/Tests/AEPRulesEngineTests/UnitTests/TraverseTests.swift b/Tests/AEPRulesEngineTests/UnitTests/TraverseTests.swift index 4fc8217..f08279c 100644 --- a/Tests/AEPRulesEngineTests/UnitTests/TraverseTests.swift +++ b/Tests/AEPRulesEngineTests/UnitTests/TraverseTests.swift @@ -1,5 +1,5 @@ /* - Copyright 2020 Adobe. All rights reserved. + Copyright 2021 Adobe. All rights reserved. This file is licensed to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0