Skip to content

Commit

Permalink
feat: add project documentation (#11)
Browse files Browse the repository at this point in the history
There is no behavior or functionality added in this change, it only adds
method documentation to support developers to use the library.
  • Loading branch information
rapatao authored Nov 4, 2023
1 parent e2b2fc1 commit d8d6a95
Show file tree
Hide file tree
Showing 10 changed files with 295 additions and 5 deletions.
13 changes: 13 additions & 0 deletions src/main/kotlin/com/rapatao/projects/ruleset/engine/Evaluator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,23 @@ import org.mozilla.javascript.Context
import org.mozilla.javascript.Script
import org.mozilla.javascript.ScriptableObject

/**
* The Evaluator class is used to evaluate a given rule expression against input data.
*
* @property contextFactory The factory used to create a context for evaluating the expressions.
* Defaults to ContextFactory().
*/
class Evaluator(
val contextFactory: ContextFactory = ContextFactory(),
) {

/**
* Evaluates the given rule expression against the provided input data.
*
* @param rule The expression to be evaluated.
* @param inputData The input data to be used in the evaluation.
* @return `true` if the rule expression evaluates to `true`, `false` otherwise.
*/
fun evaluate(rule: Expression, inputData: Any): Boolean {
return contextFactory.call(inputData) { context, scope ->
val processIsTrue = rule.takeIf { v -> v.parseable() }?.processExpression(context, scope) ?: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,27 @@ import org.mozilla.javascript.Context
import org.mozilla.javascript.ContextFactory
import org.mozilla.javascript.ScriptableObject

/**
* A factory for creating JavaScript contexts with customizable options.
*
* @property optimizationLevel The optimization level for the context. Defaults to -1.
* @property wrapJavaPrimitives Determines if Java primitive values should be wrapped in their corresponding JavaScript
* wrapper objects. Defaults to false.
* @property languageVersion The language version of the JavaScript code to be executed in the context.
* Defaults to Context.VERSION_DEFAULT.
*/
open class ContextFactory(
val optimizationLevel: Int = -1,
val wrapJavaPrimitives: Boolean = false,
val languageVersion: Int = Context.VERSION_DEFAULT
) : ContextFactory() {
/**
* Check if the given feature is enabled in the context.
*
* @param cx the context in which to check the feature
* @param featureIndex the index of the feature to check
* @return true if the feature is enabled, false otherwise
*/
override fun hasFeature(cx: Context, featureIndex: Int): Boolean {
if (Context.FEATURE_ENABLE_JAVA_MAP_ACCESS == featureIndex) {
return true
Expand All @@ -19,6 +35,11 @@ open class ContextFactory(
return super.hasFeature(cx, featureIndex)
}

/**
* Creates and configures a new context for executing JavaScript code.
*
* @return The newly created context.
*/
override fun makeContext(): Context {
val context = super.makeContext()

Expand All @@ -29,10 +50,20 @@ open class ContextFactory(
return context
}

fun call(
/**
* Executes the provided block of code with the given input data and returns a boolean value indicating
* the success or failure of the execution.
*
* @param inputData The input data to be used in the execution.
* @param block A lambda function that takes in a context and a scope as parameters and returns a boolean value.
* The context represents the context in which the execution takes place, and the scope represents
* the scope of the execution.
* @return The result of the execution.
*/
open fun <T> call(
inputData: Any,
block: (context: Context, scope: ScriptableObject) -> Boolean
): Boolean {
block: (context: Context, scope: ScriptableObject) -> T
): T {
return this.call { context ->
val scope = context.initSafeStandardObjects()

Expand All @@ -42,7 +73,14 @@ open class ContextFactory(
}
}

private fun parseParameters(
/**
* Parses parameters and injects them into the given scope based on the input data.
*
* @param scope the scriptable object scope where the parameters will be injected
* @param context the context in which the parameters will be injected
* @param inputData the input data containing the parameters
*/
open fun parseParameters(
scope: ScriptableObject,
context: Context,
inputData: Any,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
package com.rapatao.projects.ruleset.engine.types

/**
* Represents an expression used in a logical query.
*
* An expression can consist of one or more sub-expressions and an operator.
* It can also specify the action to take if the expression fails.
*
* @property allMatch A list of sub-expressions that all must match.
* @property anyMatch A list of sub-expressions where at least one must match.
* @property noneMatch A list of sub-expressions where none must match.
* @property left The left operand of the expression.
* @property operator The operator to apply to the expression.
* @property right The right operand of the expression.
* @property onFailure The action to take if the expression fails.
*/
data class Expression(
val allMatch: List<Expression>? = null,
val anyMatch: List<Expression>? = null,
Expand All @@ -11,9 +25,13 @@ data class Expression(
) {
fun operator() = operator
fun onFailure() = onFailure

fun parseable(): Boolean = operator != null

/**
* Checks if the current object is valid.
*
* @return Boolean value indicating whether the object is valid.
*/
fun isValid(): Boolean {
val any = anyMatch?.map { it.isValid() }?.firstOrNull { !it } ?: true
val none = noneMatch?.map { it.isValid() }?.firstOrNull { !it } ?: true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
package com.rapatao.projects.ruleset.engine.types

/**
* Enum class representing the possible actions on failure.
*
* This enum class defines three choices that can be made when handling failures:
* - [FALSE]: Indicates that the failure should be considered as a false result.
* - [TRUE]: Indicates that the failure should be considered as a true result.
* - [THROW]: Indicates that an exception should be thrown when a failure occurs.
**/
enum class OnFailure {
FALSE,
TRUE,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
package com.rapatao.projects.ruleset.engine.types

/**
* Enum class for different operators.
*
* This enum class represents various operators that can be used for comparison or evaluation operations.
* The available operators are:
* - EQUALS: Represents the equals operator (==).
* - NOT_EQUALS: Represents the not equals operator (!=).
* - GREATER_THAN: Represents the greater than operator (>).
* - GREATER_OR_EQUAL_THAN: Represents the greater than or equal to operator (>=).
* - LESS_THAN: Represents the less than operator (<).
* - LESS_OR_EQUAL_THAN: Represents the less than or equal to operator (<=).
*/
enum class Operator {
EQUALS,
NOT_EQUALS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,51 @@ package com.rapatao.projects.ruleset.engine.types.builder
import com.rapatao.projects.ruleset.engine.types.Expression
import com.rapatao.projects.ruleset.engine.types.Operator

/**
* Creates a [BetweenBuilder] object to build a between condition.
*
* @param from The lower boundary value.
* @return A [BetweenBuilder] object to build the between condition.
*/
infix fun Any.from(from: Any): BetweenBuilder = BetweenBuilder(
left = this, from = from, operator = Operator.GREATER_THAN,
)

/**
* Creates a [BetweenBuilder] with the given left operand, starting value, and comparison operator
*
* @param from The starting value of the range, inclusive
* @return The [BetweenBuilder] instance for further chaining
*/
infix fun Any.fromInclusive(from: Any): BetweenBuilder = BetweenBuilder(
left = this, from = from, operator = Operator.GREATER_OR_EQUAL_THAN,
)

/**
* A builder class for constructing expressions representing a between condition.
*
* @property left The left operand of the condition.
* @property from The starting value of the range.
* @property operator The comparison operator for the condition.
*/
data class BetweenBuilder(val left: Any, val from: Any, val operator: Operator) {
/**
* Creates a non-inclusive range expression using the given `to` value.
*
* @param to The upper bound value to compare against.
* @return A range expression.
*/
infix fun to(to: Any): Expression = MatcherBuilder.allMatch(
ExpressionBuilder.expression(left = left, operator = operator, right = from),
ExpressionBuilder.expression(left = left, operator = Operator.LESS_THAN, right = to),
)

/**
* Creates an inclusive range expression using the given `to` value.
*
* @param to The upper bound of the range.
* @return A range expression
*/
infix fun toInclusive(to: Any): Expression = MatcherBuilder.allMatch(
ExpressionBuilder.expression(left = left, operator = operator, right = from),
ExpressionBuilder.expression(left = left, operator = Operator.LESS_OR_EQUAL_THAN, right = to),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,119 @@ import com.rapatao.projects.ruleset.engine.types.Operator.LESS_OR_EQUAL_THAN
import com.rapatao.projects.ruleset.engine.types.Operator.LESS_THAN
import com.rapatao.projects.ruleset.engine.types.Operator.NOT_EQUALS

/**
* A utility class for building expressions using different operators.
*/
object ExpressionBuilder {

/**
* Creates a new instance of [Builder] with the given [left] parameter.
*
* @param left the value to set as the left property of the [Builder] instance.
*/
fun left(left: Any) = Builder(left)

/**
* Checks if the given expression evaluates to true.
*
* @param expression The expression to be evaluated.
* @return true if the expression evaluates to true, false otherwise.
*/
fun isTrue(expression: Any) = left(expression).isTrue()

/**
* Checks if the given expression evaluates to false.
*
* @param expression the expression to be evaluated
* @return true if the expression evaluates to false, false otherwise
*/
fun isFalse(expression: Any) = left(expression).isFalse()

/**
* Creates an expression using the given left operand, operator, and right operand.
*
* @param left The left operand of the expression.
* @param operator The operator of the expression.
* @param right The right operand of the expression.
* @return The created expression.
*/
fun expression(left: Any, operator: Operator, right: Any) = Expression(
left = left, operator = operator, right = right
)

/**
* Represents a builder for creating expressions.
*
* @param left The left-hand side of the expression.
*/
class Builder(private val left: Any) {
/**
* Creates an expression that represents the "equals to" comparison between the left operand and the right
* operand.
*
* @param right The right operand to compare.
* @return The expression representing the "equals to" comparison.
*/
infix fun equalsTo(right: Any) = Expression(left = left, operator = EQUALS, right = right)

/**
* Creates an expression representing the inequality comparison between the left-hand side and the right-hand
* side.
*
* @param right The right-hand side of the comparison.
* @return A new expression representing the inequality comparison.
*/
infix fun notEqualsTo(right: Any) = Expression(left = left, operator = NOT_EQUALS, right = right)

/**
* Creates an Expression object representing the greater-than comparison between the left operand and the right
* operand.
*
* @param right the right operand to compare with the left operand
*
* @return the Expression object representing the greater-than comparison
*/
infix fun greaterThan(right: Any) =
Expression(left = left, operator = GREATER_THAN, right = right)

/**
* Creates an expression that represents the "greater than or equal to" operation
*
* @param right the value to compare with
* @return an expression representing the "greater than or equal to" operation
*/
infix fun greaterOrEqualThan(right: Any) =
Expression(left = left, operator = GREATER_OR_EQUAL_THAN, right = right)

/**
* Creates an 'less than' expression with the specified 'right' value.
*
* @param right The right value of the expression.
* @return The created expression.
*/
infix fun lessThan(right: Any) = Expression(left = left, operator = LESS_THAN, right = right)

/**
* Creates an expression that represents the less than or equal to operation.
*
* @param right The value to compare against the left operand.
* @return An Expression object representing the less than or equal to operation.
*/
infix fun lessOrEqualThan(right: Any) =
Expression(left = left, operator = LESS_OR_EQUAL_THAN, right = right)

/**
* Checks if the left operand represents a boolean with value true.
*
* @return The boolean expression representing if the condition is true.
*/
fun isTrue() = Expression(left = left, operator = EQUALS, right = true)

/**
* Checks if the left operand represents a boolean with value false.
*
* @return The boolean expression representing if the condition is false.
*/
fun isFalse() = Expression(left = left, operator = EQUALS, right = false)
}
}
Loading

0 comments on commit d8d6a95

Please sign in to comment.