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
Source
# File lib/taskjuggler/LogicalOperation.rb, line 36 def initialize(opnd1, operator = nil, opnd2 = nil) @operand1 = opnd1 @operand2 = opnd2 @operator = operator end
Create a new LogicalOperation
object. opnd1 is the mandatory operand. The @operand2 and the @operator can be set later.
Public Instance Methods
Source
# File lib/taskjuggler/LogicalOperation.rb, line 45 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
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.
Source
# File lib/taskjuggler/LogicalOperation.rb, line 96 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
Convert the operation into a textual representation.
Private Instance Methods
Source
# File lib/taskjuggler/LogicalOperation.rb, line 143 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 boolean value.
Source
# File lib/taskjuggler/LogicalOperation.rb, line 155 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 number. In case this fails, an exception is raised.
Source
# File lib/taskjuggler/LogicalOperation.rb, line 163 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.
Source
# File lib/taskjuggler/LogicalOperation.rb, line 172 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
Force the val into a String
. In case this fails, an exception is raised.
Source
# File lib/taskjuggler/LogicalOperation.rb, line 123 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
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.
Source
# File lib/taskjuggler/LogicalOperation.rb, line 109 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