class TaskJuggler::LogicalOperation
A LogicalOperation
is the basic building block for a LogicalExpression
. A logical operation has one or two operands and an operator. The operands can be LogicalOperation
objects, fixed values or references to project data. The LogicalOperation
can be evaluated in a certain context. This contexts determines the actual values of the project data references. The evaluation is done by calling LogicalOperation#eval
. The result must be of a type that responds to all the operators that are used in the eval method.
Attributes
Public Class Methods
Create a new LogicalOperation
object. opnd1 is the mandatory operand. The @operand2 and the @operator can be set later.
# File lib/taskjuggler/LogicalOperation.rb, line 35 def initialize(opnd1, operator = nil, opnd2 = nil) @operand1 = opnd1 @operand2 = opnd2 @operator = operator end
Public Instance Methods
Evaluate the expression in a given context represented by expr of type LogicalExpression
. The result must be of a type that responds to all the operators of this function.
# File lib/taskjuggler/LogicalOperation.rb, line 44 def eval(expr) case @operator when nil if @operand1.respond_to?(:eval) # An operand can be a fixed value or another term. This could be a # LogicalOperation, LogicalFunction or anything else that provides # an appropriate eval() method. return @operand1.eval(expr) else return @operand1 end when '~' return !coerceBoolean(@operand1.eval(expr), expr) when '>', '>=', '=', '<', '<=', '!=' # Evaluate the operation for all 2 operand operations that can be # either interpreted as date, numbers or Strings. opnd1 = @operand1.eval(expr) opnd2 = @operand2.eval(expr) if opnd1.is_a?(TjTime) res= evalBinaryOperation(opnd1, operator, opnd2) do |o| coerceTime(o, expr) end return res elsif opnd1.is_a?(Integer) || opnd1.is_a?(Float) return evalBinaryOperation(opnd1, operator, opnd2) do |o| coerceNumber(o, expr) end elsif opnd1.is_a?(RichTextIntermediate) return evalBinaryOperation(opnd1.to_s, operator, opnd2) do |o| coerceString(o, expr) end elsif opnd1.is_a?(String) return evalBinaryOperation(opnd1, operator, opnd2) do |o| coerceString(o, expr) end else expr.error("First operand of a binary operation must be a date, " + "a number or a string: #{opnd1.class}") end when '&' return coerceBoolean(@operand1.eval(expr), expr) && coerceBoolean(@operand2.eval(expr), expr) when '|' return coerceBoolean(@operand1.eval(expr), expr) || coerceBoolean(@operand2.eval(expr), expr) else expr.error("Unknown operator #{@operator} in logical expression") end end
Convert the operation into a textual representation.
# File lib/taskjuggler/LogicalOperation.rb, line 95 def to_s(query) if @operator.nil? operand_to_s(@operand1, query) elsif @operand2.nil? @operator + operand_to_s(@operand1, query) else "(#{operand_to_s(@operand1, query)} #{@operator} " + "#{operand_to_s(@operand2, query)})" end end
Private Instance Methods
Force the val into a boolean value.
# File lib/taskjuggler/LogicalOperation.rb, line 142 def coerceBoolean(val, expr) # First the obvious ones. return val if val.class == TrueClass || val.class == FalseClass # An empty String means false, else true. return !val.empty? if val.is_a?(String) # In TJP logic 'non 0' means false. return val != 0 if val.is_a?(Integer) expr.error("Operand #{val} can't be evaluated to true or false.") end
Force the val into a number. In case this fails, an exception is raised.
# File lib/taskjuggler/LogicalOperation.rb, line 154 def coerceNumber(val, expr) unless val.is_a?(Integer) || val.is_a?(Float) expr.error("Operand #{val} of type #{val.class} must be a number.") end val end
Force the val into a String
. In case this fails, an exception is raised.
# File lib/taskjuggler/LogicalOperation.rb, line 162 def coerceString(val, expr) unless val.respond_to?('to_s') expr.error("Operand #{val} of type #{val.class} can't be converted " + "into a string") end val end
Force the val into a String
. In case this fails, an exception is raised.
# File lib/taskjuggler/LogicalOperation.rb, line 171 def coerceTime(val, expr) unless val.is_a?(TjTime) expr.error("Operand #{val} of type #{val.class} can't be converted " + "into a date") end val end
We need to do binary operator evaluation with various coerce functions. This function does the evaluation of opnd1 and opnd2 with the operation specified by operator. The operands are first coerced into the proper format by calling the block.
# File lib/taskjuggler/LogicalOperation.rb, line 122 def evalBinaryOperation(opnd1, operator, opnd2) case operator when '>' return yield(opnd1) > yield(opnd2) when '>=' return yield(opnd1) >= yield(opnd2) when '=' return yield(opnd1) == yield(opnd2) when '<' return yield(opnd1) < yield(opnd2) when '<=' return yield(opnd1) <= yield(opnd2) when '!=' return yield(opnd1) != yield(opnd2) else raise "Operator error" end end
# File lib/taskjuggler/LogicalOperation.rb, line 108 def operand_to_s(operand, query) if operand.is_a?(LogicalOperation) operand.to_s(query) elsif operand.is_a?(String) "'#{operand}'" else operand.to_s end end