mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
Merge pull request #2402 from cacaodev/CPExpression-constructors
NEW : CPExpression +expressionForBlock:arguments:
+expressionForConditional:trueExpression:falseExpression:
This commit is contained in:
@@ -28,3 +28,5 @@
|
||||
@import "_CPAggregateExpression.j"
|
||||
@import "_CPSetExpression.j"
|
||||
@import "_CPSubqueryExpression.j"
|
||||
@import "_CPBlockExpression.j"
|
||||
@import "_CPConditionalExpression.j"
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
@implementation _CPAggregateExpression : CPExpression
|
||||
{
|
||||
CPArray _aggregate;
|
||||
CPArray _aggregate @accessors(getter=collection);
|
||||
}
|
||||
|
||||
- (id)initWithAggregate:(CPArray)collection
|
||||
@@ -48,11 +48,6 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)collection
|
||||
{
|
||||
return _aggregate;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
{
|
||||
var eval_array = [CPArray array],
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* _CPBlockExpression.j
|
||||
*
|
||||
* Created by cacaodev.
|
||||
* Copyright 2015.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
@import "_CPExpression.j"
|
||||
|
||||
@implementation _CPBlockExpression : CPExpression
|
||||
{
|
||||
Function _block @accessors(getter=expressionBlock);
|
||||
CPArray _arguments @accessors(getter=arguments);
|
||||
}
|
||||
|
||||
- (id)initWithBlock:(Function)aBlock arguments:(CPArray)arguments
|
||||
{
|
||||
self = [super initWithExpressionType:CPBlockExpressionType];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_block = aBlock;
|
||||
_arguments = arguments;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (self === object)
|
||||
return YES;
|
||||
|
||||
if (object === nil || object.isa !== self.isa || [object expressionBlock] !== _block || ![[object arguments] isEqual:_arguments])
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
{
|
||||
var args = [];
|
||||
|
||||
[_arguments enumerateObjectsUsingBlock:function(exp, idx)
|
||||
{
|
||||
[args addObject:[exp expressionValueWithObject:object context:context]];
|
||||
}];
|
||||
|
||||
return _block(object, args, context);
|
||||
}
|
||||
|
||||
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)bindings
|
||||
{
|
||||
var args = [];
|
||||
|
||||
[_arguments enumerateObjectsUsingBlock:function(exp, idx)
|
||||
{
|
||||
[args addObject:[exp _expressionWithSubstitutionVariables:bindings]];
|
||||
}];
|
||||
|
||||
return [[_CPBlockExpression alloc] initWithBlock:_block arguments:args];
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [CPString stringWithFormat:@"Block(function, %@)", [_arguments description]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* _CPConditionalExpression.j
|
||||
*
|
||||
* Created by cacaodev.
|
||||
* Copyright 2015.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
@import "_CPPredicate.j"
|
||||
@import "_CPExpression.j"
|
||||
|
||||
@implementation _CPConditionalExpression : CPExpression
|
||||
{
|
||||
CPPredicate _predicate @accessors(getter=predicate);
|
||||
CPExpression _trueExpression @accessors(getter=trueExpression);
|
||||
CPExpression _falseExpression @accessors(getter=falseExpression);
|
||||
}
|
||||
|
||||
- (id)initWithPredicate:(CPPredicate)aPredicate trueExpression:(CPExpression)trueExpression falseExpression:(CPExpression)falseExpression
|
||||
{
|
||||
self = [super initWithExpressionType:CPConditionalExpressionType];
|
||||
|
||||
if (self)
|
||||
{
|
||||
_predicate = aPredicate;
|
||||
_trueExpression = trueExpression;
|
||||
_falseExpression = falseExpression;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (BOOL)isEqual:(id)object
|
||||
{
|
||||
if (self === object)
|
||||
return YES;
|
||||
|
||||
if (object === nil || object.isa !== self.isa || ![[object predicate] isEqual:_predicate] || ![[object trueExpression] isEqual:_trueExpression] || ![[object falseExpression] isEqual:_falseExpression])
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
{
|
||||
var eval = [_predicate evaluateWithObject:object substitutionVariables:context],
|
||||
exp = eval ? _trueExpression : _falseExpression;
|
||||
|
||||
return [exp expressionValueWithObject:object context:context];
|
||||
}
|
||||
|
||||
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)bindings
|
||||
{
|
||||
var predicate = [_predicate predicateWithSubstitutionVariables:bindings],
|
||||
trueExp = [_trueExpression _expressionWithSubstitutionVariables:bindings],
|
||||
falseExp = [_falseExpression _expressionWithSubstitutionVariables:bindings];
|
||||
|
||||
return [[_CPConditionalExpression alloc] initWithPredicate:predicate trueExpression:trueExp falseExpression:falseExp];
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [CPString stringWithFormat:@"TERNARY(%@,%@,%@)", [_predicate predicateFormat], [_trueExpression description], [_falseExpression description]];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
@implementation _CPConstantValueExpression : CPExpression
|
||||
{
|
||||
id _value;
|
||||
id _value @accessors(getter=constantValue);
|
||||
}
|
||||
|
||||
- (id)initWithValue:(id)value
|
||||
@@ -51,11 +51,6 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (id)constantValue
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
{
|
||||
return _value;
|
||||
|
||||
@@ -65,6 +65,14 @@ CPIntersectSetExpressionType = 8;
|
||||
An expression that combines two nested expression results by set subtraction.
|
||||
*/
|
||||
CPMinusSetExpressionType = 9;
|
||||
/*!
|
||||
An expression that returns the result of evaluating a block.
|
||||
*/
|
||||
CPBlockExpressionType = 10;
|
||||
/*!
|
||||
An expression that returns an expression that depends on the evaluation of a predicate.
|
||||
*/
|
||||
CPConditionalExpressionType = 11;
|
||||
|
||||
/*!
|
||||
@ingroup foundation
|
||||
@@ -259,6 +267,32 @@ CPMinusSetExpressionType = 9;
|
||||
return [[_CPSubqueryExpression alloc] initWithExpression:expression usingIteratorVariable:variable predicate:predicate];
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns Creates an NSExpression object that will use the Block for evaluating objects.
|
||||
@param aBlock The Block is applied to the object to be evaluated.
|
||||
|
||||
The Block takes three arguments and returns a value:
|
||||
|
||||
evaluatedObject
|
||||
The object to be evaluated.
|
||||
expressions
|
||||
An array of predicate expressions that evaluates to a collection.
|
||||
context
|
||||
A dictionary that the expression can use to store temporary state for one predicate evaluation.
|
||||
|
||||
@discussion Note that context is mutable, and that it can only be accessed during the evaluation of the expression.
|
||||
@param arguments An array containing NSExpression objects that will be used as parameters during the invocation of the block.
|
||||
*/
|
||||
+ (CPExpression)expressionForBlock:(Function)aBlock arguments:(CPArray)args
|
||||
{
|
||||
return [[_CPBlockExpression alloc] initWithBlock:aBlock arguments:args];
|
||||
}
|
||||
|
||||
+ (CPExpression)expressionForConditional:(CPPredicate)aPredicate trueExpression:(CPExpression)trueExpression falseExpression:(CPExpression)falseExpression
|
||||
{
|
||||
return [[_CPConditionalExpression alloc] initWithPredicate:aPredicate trueExpression:trueExpression falseExpression:falseExpression];
|
||||
}
|
||||
|
||||
// Getting Information About an Expression
|
||||
/*!
|
||||
Returns the expression type for the receiver.
|
||||
@@ -316,7 +350,7 @@ CPMinusSetExpressionType = 9;
|
||||
|
||||
/*!
|
||||
Returns the arguments for the receiver.
|
||||
@return The arguments for the receiver—that is, the array of expressions that will be passed as parameters during invocation of the selector on the operand of a function expression.
|
||||
@return The arguments for the receiver—that is, the array of expressions that will be passed as parameters during invocation of the selector on the operand of a function expression or as a parameter of the block of a block expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPArray)arguments
|
||||
@@ -337,8 +371,8 @@ CPMinusSetExpressionType = 9;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the predicate in a subquery expression.
|
||||
@return The predicate in a subquery expression..
|
||||
Returns the predicate in a subquery expression or a conditional expression.
|
||||
@return The predicate in a subquery expression or a conditional expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPPredicate)predicate
|
||||
@@ -380,6 +414,39 @@ CPMinusSetExpressionType = 9;
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the block of a block expression.
|
||||
@return The block of a block expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (Function)expressionBlock
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the true expression of a conditional expression.
|
||||
@return The true expression of a conditional expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPExpression)trueExpression
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the false expression of a conditional expression.
|
||||
@return The false expression of a conditional expression.
|
||||
This method raises an exception if it is not applicable to the receiver.
|
||||
*/
|
||||
- (CPExpression)falseExpression
|
||||
{
|
||||
_CPRaiseInvalidAbstractInvocation(self, _cmd);
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables
|
||||
{
|
||||
return self;
|
||||
|
||||
@@ -28,9 +28,9 @@
|
||||
|
||||
@implementation _CPFunctionExpression : CPExpression
|
||||
{
|
||||
CPExpression _operand;
|
||||
CPExpression _operand @accessors(getter=operand);
|
||||
SEL _selector;
|
||||
CPArray _arguments;
|
||||
CPArray _arguments @accessors(getter=arguments);
|
||||
int _argc;
|
||||
int _maxargs;
|
||||
}
|
||||
@@ -88,16 +88,6 @@
|
||||
return [self _function];
|
||||
}
|
||||
|
||||
- (CPArray)arguments
|
||||
{
|
||||
return _arguments;
|
||||
}
|
||||
|
||||
- (CPExpression)operand
|
||||
{
|
||||
return _operand;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:(id)object context:(CPDictionary)context
|
||||
{
|
||||
var target = [_operand expressionValueWithObject:object context:context],
|
||||
|
||||
@@ -744,16 +744,43 @@
|
||||
|
||||
if (![self scanString:@"," intoString:NULL])
|
||||
CPRaiseParseError(self, @"expression");
|
||||
|
||||
variableExpression = [self parseExpression];
|
||||
|
||||
if (![self scanString:@"," intoString:NULL])
|
||||
CPRaiseParseError(self, @"expression");
|
||||
|
||||
subpredicate = [self parsePredicate];
|
||||
|
||||
if (![self scanString:@")" intoString:NULL])
|
||||
CPRaiseParseError(self, @"predicate");
|
||||
|
||||
return [[_CPSubqueryExpression alloc] initWithExpression:collection usingIteratorExpression:variableExpression predicate:subpredicate];
|
||||
}
|
||||
|
||||
if ([self scanString:@"TERNARY" intoString:NULL])
|
||||
{
|
||||
if (![self scanString:@"(" intoString:NULL])
|
||||
CPRaiseParseError(self, @"expression");
|
||||
|
||||
var predicate = [self parsePredicate],
|
||||
trueExpression,
|
||||
falseExpression;
|
||||
|
||||
if (![self scanString:@"," intoString:NULL])
|
||||
CPRaiseParseError(self, @"predicate");
|
||||
|
||||
trueExpression = [self parseExpression];
|
||||
|
||||
if (![self scanString:@"," intoString:NULL])
|
||||
CPRaiseParseError(self, @"expression");
|
||||
|
||||
falseExpression = [self parseExpression];
|
||||
|
||||
if (![self scanString:@")" intoString:NULL])
|
||||
CPRaiseParseError(self, @"expression");
|
||||
|
||||
return [[_CPSubqueryExpression alloc] initWithExpression:collection usingIteratorExpression:variableExpression predicate:subpredicate];
|
||||
return [CPExpression expressionForConditional:predicate trueExpression:trueExpression falseExpression:falseExpression];
|
||||
}
|
||||
|
||||
if ([self scanString:@"FUNCTION" intoString:NULL])
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
@implementation _CPSetExpression : CPExpression
|
||||
{
|
||||
CPExpression _left;
|
||||
CPExpression _right;
|
||||
CPExpression _left @accessors(getter=leftExpression);
|
||||
CPExpression _right @accessors(getter=rightExpression);
|
||||
}
|
||||
|
||||
- (id)initWithType:(int)type left:(CPExpression)left right:(CPExpression)right
|
||||
@@ -88,16 +88,6 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CPExpression)leftExpression
|
||||
{
|
||||
return _left;
|
||||
}
|
||||
|
||||
- (CPExpression)rightExpression
|
||||
{
|
||||
return _right;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
var desc;
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
@implementation _CPSubqueryExpression : CPExpression
|
||||
{
|
||||
CPExpression _collection;
|
||||
CPExpression _collection @accessors(getter=collection);
|
||||
CPExpression _variableExpression;
|
||||
CPPredicate _subpredicate;
|
||||
CPPredicate _subpredicate @accessors(getter=predicate);
|
||||
}
|
||||
|
||||
- (id)initWithExpression:(CPExpression)collection usingIteratorVariable:(CPString)variable predicate:(CPPredicate)subpredicate
|
||||
@@ -81,21 +81,11 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPExpression)collection
|
||||
{
|
||||
return _collection;
|
||||
}
|
||||
|
||||
- (id)copy
|
||||
{
|
||||
return [[_CPSubqueryExpression alloc] initWithExpression:[_collection copy] usingIteratorExpression:[_variableExpression copy] predicate:[_subpredicate copy]];
|
||||
}
|
||||
|
||||
- (CPPredicate)predicate
|
||||
{
|
||||
return _subpredicate;
|
||||
}
|
||||
|
||||
- (CPString)description
|
||||
{
|
||||
return [self predicateFormat];
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
@implementation _CPVariableExpression : CPExpression
|
||||
{
|
||||
CPString _variable;
|
||||
CPString _variable @accessors(getter=variable);
|
||||
}
|
||||
|
||||
- (id)initWithVariable:(CPString)variable
|
||||
@@ -54,11 +54,6 @@
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (CPString)variable
|
||||
{
|
||||
return _variable;
|
||||
}
|
||||
|
||||
- (id)expressionValueWithObject:object context:(CPDictionary)context
|
||||
{
|
||||
var expression = [self _expressionWithSubstitutionVariables:context];
|
||||
|
||||
@@ -79,6 +79,17 @@
|
||||
|
||||
var expression_minusset = [CPExpression expressionForMinusSet:set with:array];
|
||||
[self assertNotNull:expression_minusset message:"MinusSet Expression should not be nil"];
|
||||
|
||||
var expression_block = [CPExpression expressionForBlock:function(obj, args, bindings)
|
||||
{
|
||||
return obj;
|
||||
} arguments:nil];
|
||||
|
||||
[self assertNotNull:expression_block message:"Block Expression should not be nil"];
|
||||
|
||||
var expression_conditional = [CPExpression expressionForConditional:[CPPredicate predicateWithValue:YES] trueExpression:expression_minusset falseExpression:expression_block];
|
||||
|
||||
[self assertNotNull:expression_conditional message:"Conditional Expression should not be nil"];
|
||||
}
|
||||
|
||||
- (void)testSetExpressionEvaluation
|
||||
@@ -147,6 +158,27 @@
|
||||
[self assertTrue:([eval isEqual:expected]) message:"'" + [expression predicateFormat] + "' result is "+ eval + "but should be " + expected];
|
||||
}
|
||||
|
||||
- (void)testBlockExpressionEvaluation
|
||||
{
|
||||
var block = function(obj, args, bindings)
|
||||
{
|
||||
return [obj stringByAppendingString:[args componentsJoinedByString:"-"]];
|
||||
};
|
||||
|
||||
var expression = [CPExpression expressionForBlock:block arguments:[[CPExpression expressionForConstantValue:"A"], [CPExpression expressionForConstantValue:"B"]]];
|
||||
|
||||
var eval = [expression expressionValueWithObject:"OBJ" context:@{}];
|
||||
[self assertTrue:([eval isEqual:"OBJA-B"]) message:"'" + [expression description] + "' result is "+ eval + "but should be " + "OBJA-B"];
|
||||
}
|
||||
|
||||
- (void)testConditionalExpressionEvaluation
|
||||
{
|
||||
var expression = [CPExpression expressionForConditional:[CPPredicate predicateWithFormat:"SELF = $variable"] trueExpression:[CPExpression expressionForConstantValue:"TRUE_EXP"] falseExpression:[CPExpression expressionForConstantValue:"FALSE_EXP"]];
|
||||
|
||||
var eval = [expression expressionValueWithObject:"OBJ" context:@{"variable":"OBJ"}];
|
||||
[self assertTrue:([eval isEqual:"TRUE_EXP"]) message:"'" + [expression description] + "' result is "+ eval + "but should be " + "TRUE_EXP"];
|
||||
}
|
||||
|
||||
- (void)testOptions
|
||||
{
|
||||
var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForConstantValue:@"àa"] rightExpression:[CPExpression expressionForConstantValue:@"aà"] modifier:CPDirectPredicateModifier type:CPLikePredicateOperatorType options:3];
|
||||
@@ -381,6 +413,9 @@
|
||||
predicate = [CPPredicate predicateWithFormat:@"a UNION {'b'} = {'a','b'}"];
|
||||
var left = [[predicate leftExpression] expressionValueWithObject:object context:nil];
|
||||
[self assertTrue:[left isEqualToSet:result] message:"Expression eval " + left + " should be " + result];
|
||||
|
||||
predicate = [CPPredicate predicateWithFormat:@"TERNARY(Record1.Children[SIZE] = 1, 'Single', Record1.Name) = 'John'"];
|
||||
[self assertTrue:[predicate evaluateWithObject:dict] message:"Predicate " + predicate + " should evaluate to TRUE"];
|
||||
}
|
||||
|
||||
- (void)testExpressionAndPredicateIsEqual
|
||||
@@ -439,6 +474,10 @@
|
||||
pred1 = [CPPredicate predicateWithFormat:@"a = 'a' AND b = 'b'"];
|
||||
pred2 = [CPPredicate predicateWithFormat:@"a = 'a' AND b = 'b'"];
|
||||
[self assert:pred1 equals:pred2];
|
||||
|
||||
pred1 = [CPPredicate predicateWithFormat:@"TERNARY(Record1.Children[FIRST] BEGINSWITH Record1.Name, 'SAME', 'DIFFERENT') = 'DIFFERENT'"];
|
||||
pred2 = [CPPredicate predicateWithFormat:@"TERNARY(Record1.Children[FIRST] BEGINSWITH Record1.Name, 'SAME', 'DIFFERENT') = 'DIFFERENT'"];
|
||||
[self assert:pred1 equals:pred2];
|
||||
}
|
||||
|
||||
- (void)testExpressionAndPredicateIsNotEqualToNil
|
||||
@@ -490,6 +529,10 @@
|
||||
|
||||
[self assert:pred1 notEqual:nil];
|
||||
|
||||
pred1 = [CPPredicate predicateWithFormat:@"TERNARY(Record1.Children[FIRST] BEGINSWITH Record1.Name, 'SAME', 'DIFFERENT') = 'DIFFERENT'"];
|
||||
|
||||
[self assert:pred1 notEqual:nil];
|
||||
|
||||
pred1 = [CPPredicate predicateWithFormat:@"$x CONTAINS 'a'"];
|
||||
|
||||
[self assert:pred1 notEqual:nil];
|
||||
|
||||
Reference in New Issue
Block a user