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 #eval. The result must be of a type that responds to all the operators that are used in the eval method.
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 34 def initialize(opnd1, operator = nil, opnd2 = nil) @operand1 = opnd1 @operand2 = opnd2 @operator = operator 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.
# File lib/taskjuggler/LogicalOperation.rb, line 43 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?(Fixnum) || opnd1.is_a?(Float) || opnd1.is_a?(Bignum) 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 94 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
Force the val into a boolean value.
# File lib/taskjuggler/LogicalOperation.rb, line 141 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?(Fixnum) || val.is_a?(Bignum) 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 153 def coerceNumber(val, expr) unless val.is_a?(Fixnum) || val.is_a?(Float) || val.is_a?(Bignum) 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 161 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 170 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 121 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 107 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