From 7be6352531a94c7ac4f9a70ce94b597a27bfc19a Mon Sep 17 00:00:00 2001 From: Brian Donovan Date: Thu, 21 Oct 2010 09:54:28 -0700 Subject: [PATCH 1/9] Add format parameter index support to sprintf. This is primarily useful in cases when the format string can vary, but the argument order will not, as is often the case with format strings in Localized.strings files. From http://perldoc.perl.org/functions/sprintf.html: An explicit format parameter index, such as 2$. By default sprintf will format the next unused argument in the list, but this allows you to take the arguments out of order. See also this Cocoa example: http://stackoverflow.com/questions/1063843/is-there-a-way-to-specify-argument-position-index-in-nsstring-stringwithformat --- Objective-J/sprintf.js | 27 ++++++++++++--------- Tests/Objective-J/sprintfTest.j | 43 +++++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/Objective-J/sprintf.js b/Objective-J/sprintf.js index d5df1b2a5..e728ed64e 100644 --- a/Objective-J/sprintf.js +++ b/Objective-J/sprintf.js @@ -22,8 +22,8 @@ // sprintf: -var formatRegex = new RegExp("([^%]+|%[\\+\\-\\ \\#0]*[0-9\\*]*(.[0-9\\*]+)?[hlL]?[cbBdieEfgGosuxXpn%@])", "g"); -var tagRegex = new RegExp("(%)([\\+\\-\\ \\#0]*)([0-9\\*]*)((.[0-9\\*]+)?)([hlL]?)([cbBdieEfgGosuxXpn%@])"); +var formatRegex = new RegExp("([^%]+|%(?:\\d+\\$)?[\\+\\-\\ \\#0]*[0-9\\*]*(.[0-9\\*]+)?[hlL]?[cbBdieEfgGosuxXpn%@])", "g"); +var tagRegex = new RegExp("(%)(?:(\\d+)\\$)?([\\+\\-\\ \\#0]*)([0-9\\*]*)((?:.[0-9\\*]+)?)([hlL]?)([cbBdieEfgGosuxXpn%@])"); exports.sprintf = function(format) { @@ -55,21 +55,27 @@ exports.sprintf = function(format) } var percentSign = subtokens[1], - flags = subtokens[2], - widthString = subtokens[3], - precisionString = subtokens[4], + argIndex = subtokens[2] + flags = subtokens[3], + widthString = subtokens[4], + precisionString = subtokens[5], length = subtokens[6], specifier = subtokens[7]; + if (argIndex === undefined) + argIndex = arg++; + else + argIndex = Number(argIndex); + var width = null; if (widthString == "*") - width = arguments[arg++]; + width = arguments[argIndex]; else if (widthString != "") width = Number(widthString); var precision = null; if (precisionString == ".*") - precision = arguments[arg++]; + precision = arguments[argIndex]; else if (precisionString != "") precision = Number(precisionString.substring(1)); @@ -80,7 +86,7 @@ exports.sprintf = function(format) if (RegExp("[bBdiufeExXo]").test(specifier)) { - var num = Number(arguments[arg++]); + var num = Number(arguments[argIndex]); var sign = ""; if (num < 0) @@ -154,12 +160,11 @@ exports.sprintf = function(format) if (specifier == "%") subresult = "%"; else if (specifier == "c") - subresult = String(arguments[arg++]).charAt(0); + subresult = String(arguments[argIndex]).charAt(0); else if (specifier == "s" || specifier == "@") - subresult = String(arguments[arg++]); + subresult = String(arguments[argIndex]); else if (specifier == "p" || specifier == "n") { - arg++; subresult = ""; } diff --git a/Tests/Objective-J/sprintfTest.j b/Tests/Objective-J/sprintfTest.j index b51bb7cd0..785c7707c 100644 --- a/Tests/Objective-J/sprintfTest.j +++ b/Tests/Objective-J/sprintfTest.j @@ -1,20 +1,37 @@ - -// TODO: add many many more of these... -var sprintfTestCases = [ - [["[%@]", "hello world"], "[hello world]"], - [["[%d]", 123], "[123]"], - [["[%f]", 123.1234], "[123.1234]"], - [["[%d]", 123.1234], "[123]"] -]; +var sprintf = ObjectiveJ.sprintf; @implementation sprintfTest : OJTestCase -- (void)test_sprintf +// TODO: add many many more of these... + +- (void)testObjectWithPrefixAndSuffix { - for (var i = 0; i < sprintfTestCases.length; i++) - { - [self assert:ObjectiveJ.sprintf.apply(null, sprintfTestCases[i][0]) equals:sprintfTestCases[i][1]]; - } + [self assert:@"[hello world]" equals:sprintf(@"[%@]", @"hello world")]; +} + +- (void)testDecimalWithPrefixAndSuffix +{ + [self assert:@"[123]" equals:sprintf(@"[%d]", 123)]; +} + +- (void)testFloatWithPrefixAndSuffix +{ + [self assert:@"[123.1234]" equals:sprintf(@"[%f]", 123.1234)]; +} + +- (void)testZeroPaddingWithWidthAndPercentEscaping +{ + [self assert:@"099%" equals:sprintf(@"%03d%%", 99)]; +} + +- (void)testOutOfOrderExplicitFormatParameterIndexes +{ + [self assert:@"2 > 1" equals:sprintf(@"%2$d > %1$d", 1, 2)]; +} + +- (void)testMixingImplicitAndExplicitFormatParameterIndexes +{ + [self assert:@"a < b && b > a" equals:sprintf(@"%@ < %2$@ && %@ > %1$@", @"a", @"b")]; } @end From 275f89a340baa7837bd1ca339ce2ff3238a41d1a Mon Sep 17 00:00:00 2001 From: cacaodev Date: Fri, 22 Oct 2010 21:58:52 +0200 Subject: [PATCH 2/9] CPPredicate: parsing 'BETWEEN' or 'CONTAINS' keywords now generates predicates with their corresponding operators. Some code style. CPComparisonPredicate: fixed typo in 'between' operator evaluation, simplified 'contains' and 'in' evaluation. Added tests in CPPredicateTest for theses fixes. --- .../CPPredicate/CPComparisonPredicate.j | 45 +++----------- Foundation/CPPredicate/CPPredicate.j | 62 +++++-------------- Tests/Foundation/CPPredicateTest.j | 10 +++ 3 files changed, 33 insertions(+), 84 deletions(-) diff --git a/Foundation/CPPredicate/CPComparisonPredicate.j b/Foundation/CPPredicate/CPComparisonPredicate.j index 8f5a9726b..dea89bb3d 100644 --- a/Foundation/CPPredicate/CPComparisonPredicate.j +++ b/Foundation/CPPredicate/CPComparisonPredicate.j @@ -441,43 +441,19 @@ var CPPredicateOperatorType; if (_options & CPDiacriticInsensitivePredicateOption) string_compare_options |= CPDiacriticInsensitiveSearch; return ([lhs compare:rhs options:string_compare_options range:range] == CPOrderedSame); - case CPInPredicateOperatorType: - // Handle special case where rhs is a collection and lhs an element of it. - if (![rhs isKindOfClass: [CPString class]]) - { - if (![rhs respondsToSelector: @selector(objectEnumerator)]) - [CPException raise:CPInvalidArgumentException reason:@"The right hand side for an IN operator must be a collection"]; - - var e = [rhs objectEnumerator], - value; - while (value = [e nextObject]) - if ([value isEqual:lhs]) - return YES; - - return NO; - } - - if (_options & CPCaseInsensitivePredicateOption) - string_compare_options |= CPCaseInsensitiveSearch; - if (_options & CPDiacriticInsensitivePredicateOption) - string_compare_options |= CPDiacriticInsensitiveSearch; - - return ([rhs rangeOfString:lhs options:string_compare_options].location != CPNotFound); case CPCustomSelectorPredicateOperatorType: return [lhs performSelector:_customSelector withObject:rhs]; + case CPInPredicateOperatorType: + var a = lhs; // swap + lhs = rhs; + rhs = a; case CPContainsPredicateOperatorType: - if (![lhs isKindOfClass: [CPString class]]) + if (![lhs isKindOfClass:[CPString class]]) { if (![lhs respondsToSelector: @selector(objectEnumerator)]) - [CPException raise:CPInvalidArgumentException reason:@"The left hand side for a CONTAINS operator must be a collection or a string"]; + [CPException raise:CPInvalidArgumentException reason:@"The left/right hand side for a CONTAINS/IN operator must be a collection or a string"]; - var e = [lhs objectEnumerator], - value; - while (value = [e nextObject]) - if ([value isEqual:rhs]) - return YES; - - return NO; + return [lhs containsObject:rhs]; } if (_options & CPCaseInsensitivePredicateOption) @@ -487,13 +463,10 @@ var CPPredicateOperatorType; return ([lhs rangeOfString:rhs options:string_compare_options].location != CPNotFound); case CPBetweenPredicateOperatorType: - if ([lhs count] < 2) + if ([rhs count] < 2) [CPException raise:CPInvalidArgumentException reason:@"The right hand side for a BETWEEN operator must contain 2 objects"]; - var lower = [rhs objectAtIndex:0], - upper = [rhs objectAtIndex:1]; - - return ([lhs compare:lower] == CPOrderedDescending && [lhs compare:upper] == CPOrderedAscending); + return ([lhs compare:rhs[0]] == CPOrderedDescending && [lhs compare:rhs[1]] == CPOrderedAscending); default: return NO; } diff --git a/Foundation/CPPredicate/CPPredicate.j b/Foundation/CPPredicate/CPPredicate.j index ff5f5f092..d7e9ba032 100644 --- a/Foundation/CPPredicate/CPPredicate.j +++ b/Foundation/CPPredicate/CPPredicate.j @@ -37,7 +37,7 @@ @param … A comma-separated list of arguments to substitute into format. @return A new predicate formed by creating a new string with format and parsing the result. */ -+ (CPPredicate)predicateWithFormat:(CPString) format, ... ++ (CPPredicate)predicateWithFormat:(CPString)format, ... { if (!format) [CPException raise:CPInvalidArgumentException reason:_cmd + " the format can't be 'nil'"]; @@ -238,7 +238,7 @@ function(newValue)\ unsigned _retrieved; } -- (id) initWithString:(CPString)format args:(CPArray)args +- (id)initWithString:(CPString)format args:(CPArray)args { self = [super initWithString:format]; if (self != nil) @@ -248,7 +248,7 @@ function(newValue)\ return self; } -- (id) nextArg +- (id)nextArg { return [_args nextObject]; } @@ -274,7 +274,7 @@ function(newValue)\ return NO; } -- (CPPredicate) parse +- (CPPredicate)parse { var r = nil; @@ -296,12 +296,12 @@ function(newValue)\ return r; } -- (CPPredicate) parsePredicate +- (CPPredicate)parsePredicate { return [self parseAnd]; } -- (CPPredicate) parseAnd +- (CPPredicate)parseAnd { var l = [self parseOr]; @@ -333,7 +333,7 @@ function(newValue)\ return l; } -- (CPPredicate) parseNot +- (CPPredicate)parseNot { if ([self scanString:@"(" intoString:NULL]) { @@ -361,7 +361,7 @@ function(newValue)\ return [self parseComparison]; } -- (CPPredicate) parseOr +- (CPPredicate)parseOr { var l = [self parseNot]; while ([self scanPredicateKeyword:@"OR"] || [self scanPredicateKeyword:@"||"]) @@ -392,7 +392,7 @@ function(newValue)\ return l; } -- (CPPredicate) parseComparison +- (CPPredicate)parseComparison { var modifier = CPDirectPredicateModifier, type = 0, @@ -400,8 +400,7 @@ function(newValue)\ left, right, p, - negate = NO, - swap = NO; + negate = NO; if ([self scanPredicateKeyword:@"ANY"]) { @@ -469,36 +468,11 @@ function(newValue)\ } else if ([self scanPredicateKeyword:@"CONTAINS"]) { - type = CPInPredicateOperatorType; - swap = YES; + type = CPContainsPredicateOperatorType; } else if ([self scanPredicateKeyword:@"BETWEEN"]) { - var exp = [self parseSimpleExpression], - a = [exp constantValue], - lower, upper, - lexp, uexp, - lp, up; - - if (![a isKindOfClass:[CPArray class]]) - [CPException raise:CPInvalidArgumentException reason:@"BETWEEN operator requires array argument"]; - - lower = [a objectAtIndex:0]; - upper = [a objectAtIndex:1]; - lexp = [CPExpression expressionForConstantValue:lower]; - uexp = [CPExpression expressionForConstantValue:upper]; - lp = [CPComparisonPredicate predicateWithLeftExpression:left - rightExpression:lexp - modifier:modifier - type:CPGreaterThanPredicateOperatorType - options:opts]; - up = [CPComparisonPredicate predicateWithLeftExpression:left - rightExpression:uexp - modifier:modifier - type:CPLessThanPredicateOperatorType - options:opts]; - return [CPCompoundPredicate andPredicateWithSubpredicates: - [CPArray arrayWithObjects:lp, up]]; + type = CPBetweenPredicateOperatorType; } else [CPException raise:CPInvalidArgumentException reason:@"Invalid comparison predicate: "+ [[self string] substringFromIndex: [self scanLocation]]]; @@ -518,14 +492,6 @@ function(newValue)\ right = [self parseExpression]; - if (swap == YES) - { - var tmp = left; - - left = right; - right = tmp; - } - p = [CPComparisonPredicate predicateWithLeftExpression:left rightExpression:right modifier:modifier @@ -535,12 +501,12 @@ function(newValue)\ return negate ? [CPCompoundPredicate notPredicateWithSubpredicate:p]:p; } -- (CPExpression) parseExpression +- (CPExpression)parseExpression { return [self parseBinaryExpression]; } -- (CPExpression) parseSimpleExpression +- (CPExpression)parseSimpleExpression { var identifier, location, diff --git a/Tests/Foundation/CPPredicateTest.j b/Tests/Foundation/CPPredicateTest.j index 242ac8efc..95cf498ea 100644 --- a/Tests/Foundation/CPPredicateTest.j +++ b/Tests/Foundation/CPPredicateTest.j @@ -209,8 +209,18 @@ predicate = [CPPredicate predicateWithFormat: @"%@ IN %K", @"Kid1", @"Record1.Children"]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + predicate = [CPPredicate predicateWithFormat: @"%K CONTAINS %@", @"Record1.Children", @"Kid1"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + predicate = [CPPredicate predicateWithFormat: @"ANY %K == %@", @"Record2.Children", @"Girl1"]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + +// TEST Operator type + predicate = [CPPredicate predicateWithFormat: @"a CONTAINS[c] \"b\""]; + [self assertTrue:([predicate predicateOperatorType] == CPContainsPredicateOperatorType) message:[predicate description] + " operator should be a CPContainsPredicateOperatorType"]; + + predicate = [CPPredicate predicateWithFormat: @"a BETWEEN {%f,%f}", 20, 40]; + [self assertTrue:([predicate predicateOperatorType] == CPBetweenPredicateOperatorType) message:[predicate description] + " operator should be a CPBetweenPredicateOperatorType"]; } @end From 8427697a4b7a2118dc68d330cdc654ffabf8f178 Mon Sep 17 00:00:00 2001 From: Brian Donovan Date: Fri, 22 Oct 2010 14:15:22 -0700 Subject: [PATCH 3/9] Fix accidental globals. --- Objective-J/sprintf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objective-J/sprintf.js b/Objective-J/sprintf.js index e728ed64e..82bf3c34c 100644 --- a/Objective-J/sprintf.js +++ b/Objective-J/sprintf.js @@ -55,7 +55,7 @@ exports.sprintf = function(format) } var percentSign = subtokens[1], - argIndex = subtokens[2] + argIndex = subtokens[2], flags = subtokens[3], widthString = subtokens[4], precisionString = subtokens[5], From 8ca2a1bf5b31adb924c778f289c5fcb0e006cf6a Mon Sep 17 00:00:00 2001 From: Brian Donovan Date: Fri, 22 Oct 2010 14:41:31 -0700 Subject: [PATCH 4/9] IE uses an empty string as the value of an empty capture group. --- Objective-J/sprintf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objective-J/sprintf.js b/Objective-J/sprintf.js index 82bf3c34c..9ad4723a5 100644 --- a/Objective-J/sprintf.js +++ b/Objective-J/sprintf.js @@ -62,7 +62,7 @@ exports.sprintf = function(format) length = subtokens[6], specifier = subtokens[7]; - if (argIndex === undefined) + if (argIndex === undefined || argIndex === null || argIndex === "") argIndex = arg++; else argIndex = Number(argIndex); From c735399ca58bfd7e0f22401afcc1a5ee109f3d55 Mon Sep 17 00:00:00 2001 From: cacaodev Date: Sat, 23 Oct 2010 09:20:24 +0200 Subject: [PATCH 5/9] CPPredicate: Fix for fail when parsing empty quotes. With Tests. --- Foundation/CPPredicate/CPPredicate.j | 19 +++++++++++-------- Tests/Foundation/CPPredicateTest.j | 3 +++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Foundation/CPPredicate/CPPredicate.j b/Foundation/CPPredicate/CPPredicate.j index d7e9ba032..6a77470da 100644 --- a/Foundation/CPPredicate/CPPredicate.j +++ b/Foundation/CPPredicate/CPPredicate.j @@ -638,37 +638,40 @@ function(newValue)\ [self setScanLocation:location]; } - + if ([self scanString:@"\"" intoString:NULL]) { var skip = [self charactersToBeSkipped], - str; + str = @""; [self setCharactersToBeSkipped:nil]; - if ([self scanUpToString:@"\"" intoString:REFERENCE(str)] == NO) + [self scanUpToString:@"\"" intoString:REFERENCE(str)]; + + if ([self scanString:@"\"" intoString:NULL] == NO) { [self setCharactersToBeSkipped:skip]; [CPException raise:CPInvalidArgumentException reason:@"Invalid double quoted literal at "+location]; } - [self scanString:@"\"" intoString:NULL]; [self setCharactersToBeSkipped:skip]; return [CPExpression expressionForConstantValue:str]; } + if ([self scanString:@"'" intoString:NULL]) { var skip = [self charactersToBeSkipped], - str; + str = @""; [self setCharactersToBeSkipped:nil]; - if ([self scanUpToString:@"'" intoString:REFERENCE(str)] == NO) + [self scanUpToString:@"'" intoString:REFERENCE(str)]; + + if ([self scanString:@"'" intoString:NULL] == NO) { [self setCharactersToBeSkipped:skip]; - [CPException raise:CPInvalidArgumentException reason:@"Invalid single quoted literal at "+location]; + [CPException raise:CPInvalidArgumentException reason:@"Invalid double quoted literal at "+location]; } - [self scanString:@"'" intoString:NULL]; [self setCharactersToBeSkipped:skip]; return [CPExpression expressionForConstantValue:str]; diff --git a/Tests/Foundation/CPPredicateTest.j b/Tests/Foundation/CPPredicateTest.j index 95cf498ea..19798c59f 100644 --- a/Tests/Foundation/CPPredicateTest.j +++ b/Tests/Foundation/CPPredicateTest.j @@ -221,6 +221,9 @@ predicate = [CPPredicate predicateWithFormat: @"a BETWEEN {%f,%f}", 20, 40]; [self assertTrue:([predicate predicateOperatorType] == CPBetweenPredicateOperatorType) message:[predicate description] + " operator should be a CPBetweenPredicateOperatorType"]; + + predicate = [CPPredicate predicateWithFormat: @"a CONTAINS \"\""]; + [self assertNotNull:predicate message:[predicate description] + " should not be nil"]; } @end From 2a955235777ffa9d41141836c6600b602ee4f126 Mon Sep 17 00:00:00 2001 From: cacaodev Date: Wed, 27 Oct 2010 00:57:31 +0200 Subject: [PATCH 6/9] CPPredicate & CPExpression changes: Parsing: fixed typos in built-in function names, fixed support for [FIRST], [LAST], [INDEX] Fixed aggregates {exp1,exp2} Fixed -expressionForFunction:selectorName:arguments: built-in functions are now class methods Cleaned a lot of code in built-in functions EvaluatedObjectExpression is now a singleton Merged inserset/minus/union Set into one file Deleted unused expression subclasses : expression_operator and expression_assignement Added CPCoding methods and changed key names to match Cocoa Made KeyPathExpresion a subclass of FunctionExpression like in Cocoa Tests --- .../CPPredicate/CPComparisonPredicate.j | 1 - Foundation/CPPredicate/CPExpression.j | 10 +- .../CPPredicate/CPExpression_aggregate.j | 51 +-- .../CPPredicate/CPExpression_assignment.j | 92 ----- .../CPPredicate/CPExpression_constant.j | 28 +- .../CPPredicate/CPExpression_function.j | 338 ++++++------------ .../CPPredicate/CPExpression_intersectset.j | 86 ----- Foundation/CPPredicate/CPExpression_keypath.j | 50 +-- .../CPPredicate/CPExpression_minusset.j | 81 ----- .../CPPredicate/CPExpression_operator.j | 117 ------ Foundation/CPPredicate/CPExpression_self.j | 17 +- Foundation/CPPredicate/CPExpression_set.j | 115 ++++++ .../CPPredicate/CPExpression_unionset.j | 84 ----- .../CPPredicate/CPExpression_variable.j | 27 +- Foundation/CPPredicate/CPPredicate.j | 69 ++-- Tests/Foundation/CPPredicateTest.j | 83 ++++- 16 files changed, 414 insertions(+), 835 deletions(-) delete mode 100644 Foundation/CPPredicate/CPExpression_assignment.j delete mode 100644 Foundation/CPPredicate/CPExpression_intersectset.j delete mode 100644 Foundation/CPPredicate/CPExpression_minusset.j delete mode 100644 Foundation/CPPredicate/CPExpression_operator.j create mode 100644 Foundation/CPPredicate/CPExpression_set.j delete mode 100644 Foundation/CPPredicate/CPExpression_unionset.j diff --git a/Foundation/CPPredicate/CPComparisonPredicate.j b/Foundation/CPPredicate/CPComparisonPredicate.j index dea89bb3d..7a8f855e3 100644 --- a/Foundation/CPPredicate/CPComparisonPredicate.j +++ b/Foundation/CPPredicate/CPComparisonPredicate.j @@ -4,7 +4,6 @@ @import "CPEnumerator.j" @import "CPPredicate.j" @import "CPExpression.j" -@import "CPExpression_operator.j" /*! A predicate to compare directly the left and right hand sides. diff --git a/Foundation/CPPredicate/CPExpression.j b/Foundation/CPPredicate/CPExpression.j index 64b43375b..78c0dabb5 100644 --- a/Foundation/CPPredicate/CPExpression.j +++ b/Foundation/CPPredicate/CPExpression.j @@ -132,7 +132,7 @@ CPMinusSetExpressionType = 9; */ + (CPExpression)expressionForUnionSet:(CPExpression)left with:(CPExpression)right { - return [[CPExpression_unionset alloc] initWithLeft:left right:right]; + return [[CPExpression_set alloc] initWithType:CPUnionSetExpressionType left:left right:right]; } /*! @@ -143,7 +143,7 @@ CPMinusSetExpressionType = 9; */ + (CPExpression)expressionForIntersectSet:(CPExpression)left with:(CPExpression)right { - return [[CPExpression_intersectset alloc] initWithLeft:left right:right]; + return [[CPExpression_set alloc] initWithType:CPIntersectSetExpressionType left:left right:right]; } /*! @@ -154,7 +154,7 @@ CPMinusSetExpressionType = 9; */ + (CPExpression)expressionForMinusSet:(CPExpression)left with:(CPExpression)right { - return [[CPExpression_minusset alloc] initWithLeft:left right:right]; + return [[CPExpression_set alloc] initWithType:CPMinusSetExpressionType left:left right:right]; } // Creating an Expression for a Function @@ -319,6 +319,4 @@ CPMinusSetExpressionType = 9; @import "CPExpression_keypath.j" @import "CPExpression_function.j" @import "CPExpression_aggregate.j" -@import "CPExpression_unionset.j" -@import "CPExpression_intersectset.j" -@import "CPExpression_minusset.j" +@import "CPExpression_set.j" diff --git a/Foundation/CPPredicate/CPExpression_aggregate.j b/Foundation/CPPredicate/CPExpression_aggregate.j index 90b25c8ec..fdf114bec 100644 --- a/Foundation/CPPredicate/CPExpression_aggregate.j +++ b/Foundation/CPPredicate/CPExpression_aggregate.j @@ -15,22 +15,6 @@ return self; } -+ (CPExpression)expressionForAggregate:(CPArray)collection -{ - return [[self alloc] initWithAggregate:collection]; -} - -- (id)initWithCoder:(CPCoder)coder -{ - var aggregate = [coder decodeObjectForKey:@"CPExpressionAggregate"]; - return [self initWithAggregate:aggregate]; -} - -- (void)encodeWithCoder:(CPCoder)coder -{ - [coder encodeObject:_aggregate forKey:@"CPExpressionAggregate"]; // subexpressions must be CPCoding compliant. -} - - (BOOL)isEqual:(id)object { if (self == object) @@ -47,22 +31,6 @@ return _aggregate; } -- (CPExpression)rightExpression -{ - if ([_aggregate count] > 0) - return [_aggregate lastObject]; - - return nil; -} - -- (CPExpression)leftExpression -{ - if ([_aggregate count] > 0) - return [_aggregate objectAtIndex:0]; - - return nil; -} - - (id)expressionValueWithObject:(id)object context:(CPDictionary)context { var eval_array = [CPArray array], @@ -72,7 +40,7 @@ while (exp = [collection nextObject]) { var eval = [exp expressionValueWithObject:object context:context]; - if (eval != nil)[eval_array addObject:eval]; + [eval_array addObject:eval]; } return eval_array; @@ -105,3 +73,20 @@ } @end + +var CPCollectionKey = @"CPCollection"; + +@implementation CPExpression_aggregate (CPCoding) + +- (id)initWithCoder:(CPCoder)coder +{ + var collection = [coder decodeObjectForKey:CPCollectionKey]; + return [self initWithAggregate:collection]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_aggregate forKey:CPCollectionKey]; +} + +@end \ No newline at end of file diff --git a/Foundation/CPPredicate/CPExpression_assignment.j b/Foundation/CPPredicate/CPExpression_assignment.j deleted file mode 100644 index 771119fd4..000000000 --- a/Foundation/CPPredicate/CPExpression_assignment.j +++ /dev/null @@ -1,92 +0,0 @@ - -@import "CPExpression.j" -@import "CPExpression_variable.j" -@import - - -@implementation CPExpression_assignment: CPExpression -{ - CPExpression_variable _assignmentVariable; - CPExpression _subexpression; -} - -- (id)initWithAssignmentVariable:(CPString)variable expression:(CPExpression)expression -{ - _assignmentVariable = [CPExpression expressionForVariable:variable]; - _subexpression = expression; - - return self; -} - -- (id)initWithAssignmentExpression:(CPExpression)variableExpression expression:(CPExpression)expression -{ - _assignmentVariable = variableExpression; - _subexpression = expression; - - return self; -} - -- (id)initWithCoder:(CPCoder)coder -{ - var variable = [coder decodeObjectForKey:@"CPExpressionAssignmentVariable"]; - var expression = [coder decodeObjectForKey:@"CPExpressionAssignmentExpression"]; - - return [self initWithAssignmentVariable:variable expression:expression]; -} - -- (void)encodeWithCoder:(CPCoder)coder -{ - [coder encodeObject:_assignmentVariable forKey:@"CPExpressionAssignmentVariable"]; - [coder encodeObject:_subexpression forKey:@"CPExpressionAssignmentExpression"]; -} - -- (BOOL)isEqual:(id)object -{ - if (self == object) - return YES; - - if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object subexpression] isEqual:[self subexpression]] || ![[object variable] isEqualToString:[self variable]]) - return NO; - - return YES; -} - -- (CPExpression)assignmentVariable -{ - return _assignmentVariable; -} - -- (CPExpression)subexpression -{ - return _subexpression; -} - -- (CPString)variable -{ - return [_assignmentVariable variable]; -} - -- (CPString)description -{ - var pretty = [_expression description]; - - if ([_subexpression isKindOfClass:[CPExpression_operator class]]) - pretty = [CPString stringWithFormat:@"(%@)", pretty]; - - return [CPString stringWithFormat:@"%@ := %@", [self variable], pretty]; -} - -- (id)expressionValueWithObject:(id)object context:(id)context -{ - // UNIMPLEMENTED - return nil; -} - -- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables -{ - // UNIMPLEMENTED - return nil; -} - -@end - diff --git a/Foundation/CPPredicate/CPExpression_constant.j b/Foundation/CPPredicate/CPExpression_constant.j index af6ed19d4..858cdcd0d 100644 --- a/Foundation/CPPredicate/CPExpression_constant.j +++ b/Foundation/CPPredicate/CPExpression_constant.j @@ -15,18 +15,6 @@ return self; } -- (id)initWithCoder:(CPCoder)coder -{ - var value = [coder decodeObjectForKey:@"CPExpressionConstantValue"]; - - return [self initWithValue:value]; -} - -- (void)encodeWithCoder:(CPCoder)coder -{ - [coder encodeObject:_value forKey:@"CPExpressionConstantValue"]; -} - - (BOOL)isEqual:(id)object { if (self == object) @@ -63,3 +51,19 @@ @end +var CPConstantValueKey = @"CPConstantValue"; + +@implementation CPExpression_constant (CPCoding) + +- (id)initWithCoder:(CPCoder)coder +{ + var value = [coder decodeObjectForKey:CPConstantValueKey]; + return [self initWithValue:value]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_value forKey:CPConstantValueKey]; +} + +@end diff --git a/Foundation/CPPredicate/CPExpression_function.j b/Foundation/CPPredicate/CPExpression_function.j index 539f947f0..2ff9c5c7f 100644 --- a/Foundation/CPPredicate/CPExpression_function.j +++ b/Foundation/CPPredicate/CPExpression_function.j @@ -12,30 +12,23 @@ int _argc; } -- (id)initWithSelector:(SEL)aselector arguments:(CPArray)parameters +- (id)initWithSelector:(SEL)aSelector arguments:(CPArray)parameters { - [super initWithExpressionType:CPFunctionExpressionType]; - - if (![self respondsToSelector:aselector]) - [CPException raise: CPInvalidArgumentException reason:@"Unknown function implementation: " + aselector]; - - _selector = aselector; - _operand = nil; - _arguments = parameters; - _argc = [parameters count]; - - return self; + var target = [CPPredicateUtilities class]; + if (![target respondsToSelector:aSelector]) + [CPException raise:CPInvalidArgumentException reason:@"Unknown function implementation: " + aSelector]; + + var operand = [CPExpression expressionForConstantValue:target]; + return [self initWithTarget:operand selector:aSelector arguments:parameters]; } -- (id)initWithTarget:(CPExpression)targetExpression selector:(SEL)aselector arguments:(CPArray)parameters +- (id)initWithTarget:(CPExpression)targetExpression selector:aSelector arguments:parameters { [super initWithExpressionType:CPFunctionExpressionType]; - var target = [targetExpression expressionValueWithObject:object context:context]; - if (![target respondsToSelector:aselector]) - [CPException raise: CPInvalidArgumentException reason:@"Unknown function implementation: " + aselector]; - - _selector = aselector; +// Cocoa doc: "This method throws an exception immediately if the selector is unknown" +// but targetExpression's value (selector's target) may be resolved only at runtime. + _selector = aSelector; _operand = targetExpression; _arguments = parameters; _argc = [parameters count]; @@ -43,20 +36,6 @@ return self; } -- (id)initWithCoder:(CPCoder)coder -{ - var selector = CPSelectorFromString([coder decodeObjectForKey:@"CPExpressionFunctionName"]); - var arguments = [coder decodeObjectForKey:@"CPExpressionFunctionArguments"]; - - return [self initWithSelector:selector arguments:arguments]; -} - -- (void)encodeWithCoder:(CPCoder)coder -{ - [coder encodeObject:[self _function] forKey:@"CPExpressionFunctionName"]; - [coder encodeObject:_arguments forKey:@"CPExpressionArguments"]; -} - - (BOOL)isEqual:(id)object { if (self == object) @@ -90,34 +69,31 @@ - (id)expressionValueWithObject:(id)object context:(CPDictionary)context { - var eval_args = [CPArray array], + var target = [_operand expressionValueWithObject:object context:context], + objj_args = [target, _selector], i; for (i = 0; i < _argc; i++) { - var arg = [[_arguments objectAtIndex:i] expressionValueWithObject:object context:context]; - if (arg != nil) - [eval_args addObject:arg]; - } - - var target = (_operand == nil) ? self : [_operand expressionValueWithObject:object context:context]; - return [target performSelector:_selector withObject:eval_args]; + var arg = [_arguments[i] expressionValueWithObject:object context:context]; + objj_args.push(arg); + } + + return objj_msgSend.apply(this, objj_args); } - (CPString)description { - var result = [CPString stringWithFormat:@"%@ %s(", [_operand description], [self _function]], - i; + var result = _operand + [self _function] + "("; - for (i = 0; i < _argc; i++) - result = result + [_arguments objectAtIndex:i] + (i+1<_argc) ? ", " : ""; + for (var i = 0; i < _argc; i++) + result = result + [_arguments[i] description] + ((i + 1 < _argc) ? ", " : ""); result = result + ")"; return result ; } - - (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables { var array = [CPArray array], @@ -129,245 +105,157 @@ return [CPExpression expressionForFunction:[self operand] selectorName:[self _function] arguments:array]; } -- (CPNumber)sum:(CPArray)parameters +@end + +var CPSelectorNameKey = @"CPSelectorName", + CPArgumentsKey = @"CPArguments", + CPOperandKey = @"CPOperand"; + +@implementation CPExpression_function (CPCoding) + +- (id)initWithCoder:(CPCoder)coder { - if (_argc < 1) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + var target = [coder decodeObjectForKey:CPOperandKey], + selector = CPSelectorFromString([coder decodeObjectForKey:CPSelectorNameKey]), + arguments = [coder decodeObjectForKey:CPArgumentsKey]; - var i, - sum = 0.0; - - for (i = 0; i < _argc; i++) - sum += [[parameters objectAtIndex:i] doubleValue]; - - return [CPNumber numberWithDouble: sum]; + return [self initWithTarget:target selector:selector arguments:arguments]; } -- (CPNumber)count:(CPArray)parameters +- (void)encodeWithCoder:(CPCoder)coder { - if (_argc < 1) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - return [CPNumber numberWithUnsignedInt: [[parameters objectAtIndex:0] count]]; + [coder encodeObject:[self _function] forKey:CPSelectorNameKey]; + [coder encodeObject:_arguments forKey:CPArgumentsKey]; + [coder encodeObject:_operand forKey:CPOperandKey]; } -- (CPNumber)min:(CPArray)parameters +@end + +// Built-in functions +@implementation CPPredicateUtilities : CPObject { - if (_argc < 1) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - return MIN([parameters objectAtIndex:0],[parameters objectAtIndex:1]); } -- (CPNumber)max:(CPArray)parameters ++ (float)sum:(CPArray)parameters { - if (_argc < 1) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; + var sum = 0, + count = parameters.length; - return MAX([parameters objectAtIndex:0],[parameters objectAtIndex:1]); + while (count--) + sum += parameters[count]; + + return sum; } -- (CPNumber)average:(CPArray)parameters ++ (float)count:(CPArray)parameters { - if (_argc < 1) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var i, - sum = 0.0; - - for (i = 0; i < _argc; i++) - sum += [[parameters objectAtIndex:i] doubleValue]; - - return [CPNumber numberWithDouble: sum / _argc]; + return [parameters count]; } -- (CPNumber)add:to:(CPArray)parameters ++ (float)min:(CPArray)parameters { - if (_argc != 2) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var left = [parameters objectAtIndex:0], - right = [parameters objectAtIndex:1]; - - return [CPNumber numberWithDouble: [left doubleValue] + [right doubleValue]]; + return parameters.sort()[0]; } -- (CPNumber)from:subtract:(CPArray)parameters ++ (float)max:(CPArray)parameters { - if (_argc != 2) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var left = [parameters objectAtIndex:0], - right = [parameters objectAtIndex:1]; - - return [CPNumber numberWithDouble: [left doubleValue] - [right doubleValue]]; + return parameters.sort()[parameters.length - 1]; } -- (CPNumber)multiply:by:(CPArray)parameters ++ (float)average:(CPArray)parameters { - if (_argc != 2) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var left = [parameters objectAtIndex:0], - right = [parameters objectAtIndex:1]; - - return [CPNumber numberWithDouble: [left doubleValue] * [right doubleValue]]; + return [self sum:parameters] / parameters.length; } -- (CPNumber)divide:by:(CPArray)parameters ++ (id)first:(CPArray)parameters { - if (_argc != 2) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var left = [parameters objectAtIndex:0], - right = [parameters objectAtIndex:1]; - - return [CPNumber numberWithDouble: [left doubleValue] / [right doubleValue]]; + return parameters[0]; } -- (CPNumber)sqrt:(CPArray)parameters ++ (id)last:(CPArray)parameters { - if (_argc != 1) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var num = [[parameters objectAtIndex:0] doubleValue]; - - return [CPNumber numberWithDouble: SQRT(num)]; + return parameters[parameters.length - 1]; } -- (CPNumber)raise:to:(CPArray)parameters ++ (id)fromObject:(id)object index:(id)anIndex { - if (_argc < 2) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var num = [[parameters objectAtIndex:0] doubleValue], - power = [[parameters objectAtIndex:1] doubleValue]; - - return [CPNumber numberWithDouble: POW(num,power)]; + if ([object isKindOfClass:[CPDictionary class]]) + return [object objectForKey:anIndex]; + else ([object isKindOfClass:[CPArray class]]) + return [object objectAtIndex:anIndex]; + + [CPException raise:CPInvalidArgumentException reason:@"object[#] requires a CPDictionary or CPArray"]; } -- (CPNumber)abs:(CPArray)parameters ++ (float)add:(int)n to:(int)m { - if (_argc != 1) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var num = [[parameters objectAtIndex:0] doubleValue]; - - return [CPNumber numberWithDouble:ABS(num)]; + return n + m; } -- (CPDate)now ++ (float)from:(int)n substract:(int)m +{ + return n - m; +} + ++ (float)multiply:(float)n by:(int)m +{ + return n * m; +} + ++ (float)divide:(float)n by:(float)m +{ + return n / m; +} + ++ (float)sqrt:(float)n +{ + return SQRT(n); +} + ++ (float)raise:(float)num to:(int)power +{ + return POW(num, power); +} + ++ (float)abs:(float)num +{ + return ABS(num); +} + ++ (CPDate)now { return [CPDate date]; } -- (CPNumber)ln:(CPArray)parameters ++ (float)ln:(float)num { - if (_argc != 1) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var num = [[parameters objectAtIndex:0] doubleValue]; - - return [CPNumber numberWithDouble:Math.log(num)]; + return LN10(num); } -- (CPNumber)exp:(CPArray)parameters ++ (float)exp:(float)num { - if (_argc != 1) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var num = [[parameters objectAtIndex:0] doubleValue]; - - return [CPNumber numberWithDouble:EXP(num)]; + return EXP(num); } -- (CPNumber)ceiling:(CPArray)parameters ++ (float)ceiling:(float)num { - if (_argc != 1) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var num = [[parameters objectAtIndex:0] doubleValue]; - - return [CPNumber numberWithDouble:CEIL(num)]; + return CEIL(num); } -- (CPNumber)random ++ (int)random:(int)num { - return [CPNumber numberWithDouble:RAND()]; + return ROUND(RAND() * num); } -- (CPNumber)modulus:by:(CPArray)parameters ++ (int)modulus:(int)n by:(int)n { - if (_argc != 2) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var left = [parameters objectAtIndex:0], - right = [parameters objectAtIndex:1]; - - return [CPNumber numberWithInt:([left intValue] % [right intValue])]; + return n % m; } - -- (id)first:(CPArray)parameters ++ (float)chs:(int)num { - if (_argc == 0) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - return [[parameters objectAtIndex:0] objectAtIndex:0]; + return -num; } -- (id)last:(CPArray)parameters -{ - if (_argc == 0) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - return [[parameters objectAtIndex:0] lastObject]; -} - -- (CPNumber)chs:(CPArray)parameters -{ - if (_argc == 0) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - return [CPNumber numberWithInt: - [[parameters objectAtIndex:0] intValue]]; -} - -- (id)index:(CPArray)parameters -{ - if (_argc < 2) - [CPException raise:CPInvalidArgumentException reason:"Invalid number of parameters"]; - - var left = [parameters objectAtIndex:0], - right = [parameters objectAtIndex:1]; - - if ([left isKindOfClass: [CPDictionary class]]) - return [left objectForKey:right]; - else - return [left objectAtIndex: [right intValue]]; -} - -/* -- (CPNumber)median:(CPArray)parameters -{ -} -- (CPNumber)mode:(CPArray)parameters -{ -} -- (CPNumber)stddev:(CPArray)parameters -{ -} -- (CPNumber)log:(CPArray)parameters -{ -} -- (CPNumber)raise:to:(CPArray)parameters -{ -} -- (CPNumber)trunc:(CPArray)parameters -{ -} - -// These functions are used when parsing -*/ - @end diff --git a/Foundation/CPPredicate/CPExpression_intersectset.j b/Foundation/CPPredicate/CPExpression_intersectset.j deleted file mode 100644 index f2f6f3a23..000000000 --- a/Foundation/CPPredicate/CPExpression_intersectset.j +++ /dev/null @@ -1,86 +0,0 @@ - -@import "CPExpression.j" - -@implementation CPExpression_intersectset : CPExpression -{ - CPExpression _left; - CPExpression _right; -} - -- (id)initWithLeft:(CPExpression)left right:(CPExpression)right -{ - [super initWithExpressionType:CPIntersectSetExpressionType]; - _left = left ; - _right = right; - - return self; -} - -- (id)initWithCoder:(CPCoder)coder -{ - var left = [coder decodeObjectForKey:@"CPExpressionUnionSetLeftExpression"]; - var right = [coder decodeObjectForKey:@"CPExpressionUnionSetRightExpression"]; - - return [self initWithLeft:left right:right]; -} - -- (void)encodeWithCoder:(CPCoder)coder -{ - [coder encodeObject:_left forKey:@"CPExpressionUnionSetLeftExpression"]; - [coder encodeObject:_right forKey:@"CPExpressionUnionSetRightExpression"]; -} - -- (BOOL)isEqual:(id)object -{ - if (self == object) - return YES; - - if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object leftExpression] isEqual:[self leftExpression]] || ![[object rightExpression] isEqual:[self rightExpression]]) - return NO; - - return YES; -} - -- (id)expressionValueWithObject:object context:(CPDictionary)context -{ - var right = [_right expressionValueWithObject:object context:context]; - if (![right respondsToSelector: @selector(objectEnumerator)]) - [CPException raise:CPInvalidArgumentException reason:@"The right expression for a CPIntersectSetExpressionType expression must be either a CPArray, CPDictionary or CPSet"]; - - var left = [_left expressionValueWithObject:object context:context]; - if (![left isKindOfClass:[CPSet set]]) - [CPException raise:CPInvalidArgumentException reason:@"The left expression for a CPIntersectSetExpressionType expression must a CPSet"]; - - var set = [CPSet setWithSet:left], - e = [right objectEnumerator], - item; - - while (item = [e nextObject]) - if ([left containsObject:item]) - [set addObject:item]; - - return [CPExpression expressionForConstantValue:set]; -} - -- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables -{ - return self; -} - -- (CPExpression)leftExpression -{ - return _left; -} - -- (CPExpression)rightExpression -{ - return _right; -} - -- (CPString )description -{ - return [_left description] +" INTERSECT "+ [_right description]; -} - -@end - diff --git a/Foundation/CPPredicate/CPExpression_keypath.j b/Foundation/CPPredicate/CPExpression_keypath.j index e74c77b71..b97cd9a52 100644 --- a/Foundation/CPPredicate/CPExpression_keypath.j +++ b/Foundation/CPPredicate/CPExpression_keypath.j @@ -2,61 +2,39 @@ @import "CPExpression.j" @import @import +@import "CPExpression_function.j" -@implementation CPExpression_keypath : CPExpression +@implementation CPExpression_keypath : CPExpression_function { - CPString _keyPath; } - (id)initWithKeyPath:(CPString)keyPath { - [super initWithExpressionType:CPKeyPathExpressionType]; - _keyPath = keyPath ; + return [self initWithOperand:[CPExpression expressionForEvaluatedObject] andKeyPath:keyPath]; +} + +- (id)initWithOperand:(CPExpression)operand andKeyPath:(CPString)keyPath +{ + var arg = [CPExpression expressionForConstantValue:keyPath]; + // Cocoa: if it's a direct path selector is valueForKey: + self = [super initWithTarget:operand selector:@selector(valueForKeyPath:) arguments:[arg]]; return self; } -- (id)initWithCoder:(CPCoder)coder +- (CPExpression)pathExpression { - var keyPath = [coder decodeObjectForKey:@"CPExpressionKeyPath"]; - - return [self initWithKeyPath:keyPath]; -} - -- (void)encodeWithCoder:(CPCoder)coder -{ - [coder encodeObject:_keyPath forKey:@"CPExpressionKeyPath"]; -} - -- (BOOL)isEqual:(id)object -{ - if (self == object) - return YES; - - if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object keyPath] isEqualToString:[self keyPath]]) - return NO; - - return YES; + return [[self arguments] objectAtIndex:0]; } - (CPString)keyPath { - return _keyPath; -} - -- (id)expressionValueWithObject:object context:(CPDictionary)context -{ - return [object valueForKeyPath:_keyPath]; -} - -- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables -{ - return self; + return [[self pathExpression] constantValue]; } - (CPString)description { - return _keyPath; + return [self keyPath]; } @end diff --git a/Foundation/CPPredicate/CPExpression_minusset.j b/Foundation/CPPredicate/CPExpression_minusset.j deleted file mode 100644 index 528580a9b..000000000 --- a/Foundation/CPPredicate/CPExpression_minusset.j +++ /dev/null @@ -1,81 +0,0 @@ - -@import "CPExpression.j" - -@implementation CPExpression_minusset : CPExpression - -- (id)initWithLeft:(CPExpression)left right:(CPExpression)right -{ - [super initWithExpressionType:CPMinusSetExpressionType]; - _left = left ; - _right = right; - - return self; -} - -- (id)initWithCoder:(CPCoder)coder -{ - var left = [coder decodeObjectForKey:@"CPExpressionMinusSetLeftExpression"]; - var right = [coder decodeObjectForKey:@"CPExpressionMinusSetRightExpression"]; - - return [self initWithLeft:left right:right]; -} - -- (void)encodeWithCoder:(CPCoder)coder -{ - [coder encodeObject:_left forKey:@"CPExpressionMinusSetLeftExpression"]; - [coder encodeObject:_right forKey:@"CPExpressionMinusSetRightExpression"]; -} - -- (BOOL)isEqual:(id)object -{ - if (self == object) - return YES; - - if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object leftExpression] isEqual:[self leftExpression]] || ![[object rightExpression] isEqual:[self rightExpression]]) - return NO; - - return YES; -} - -- (id)expressionValueWithObject:object context:(CPDictionary)context -{ - var right = [_right expressionValueWithObject:object context:context]; - if (![right respondsToSelector: @selector(objectEnumerator)]) - [CPException raise:CPInvalidArgumentException reason:@"The right expression for a CPIntersectSetExpressionType expression must be either a CPArray, CPDictionary or CPSet"]; - - var left = [_left expressionValueWithObject:object context:context]; - if (![left isKindOfClass:[CPSet set]]) - [CPException raise:CPInvalidArgumentException reason:@"The left expression for a CPIntersectSetExpressionType expression must a CPSet"]; - - var set = [CPSet setWithSet:left], - e = [right objectEnumerator], - item; - - while (item = [e nextObject]) - [set removeObject:item]; - - return [CPExpression expressionForConstantValue:set]; -} - -- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables -{ - return self; -} - -- (CPExpression)leftExpression -{ - return _left; -} - -- (CPExpression)rightExpression -{ - return _right; -} - -- (CPString )description -{ - return [_left description] +" MINUS "+ [_right description]; -} - -@end - diff --git a/Foundation/CPPredicate/CPExpression_operator.j b/Foundation/CPPredicate/CPExpression_operator.j deleted file mode 100644 index 3ac7d6450..000000000 --- a/Foundation/CPPredicate/CPExpression_operator.j +++ /dev/null @@ -1,117 +0,0 @@ - -@import "CPExpression.j" -@import -@import -@import - -var CPExpressionOperatorNegate = "CPExpressionOperatorNegate"; -var CPExpressionOperatorAdd = "CPExpressionOperatorAdd"; -var CPExpressionOperatorSubtract = "CPExpressionOperatorSubtract"; -var CPExpressionOperatorMultiply = "CPExpressionOperatorMultiply"; -var CPExpressionOperatorDivide = "CPExpressionOperatorDivide"; -var CPExpressionOperatorExp = "CPExpressionOperatorExp"; -var CPExpressionOperatorAssign = "CPExpressionOperatorAssign"; -var CPExpressionOperatorKeypath = "CPExpressionOperatorKeypath"; -var CPExpressionOperatorIndex = "CPExpressionOperatorIndex"; -var CPExpressionOperatorIndexFirst = "CPExpressionOperatorIndexFirst"; -var CPExpressionOperatorIndexLast = "CPExpressionOperatorIndexLast"; -var CPExpressionOperatorIndexSize = "CPExpressionOperatorIndexSize"; - -@implementation CPExpression_operator : CPExpression -{ - int _operator; - CPArray _arguments; -} - -- (id)initWithOperator:(int)operator arguments:(CPArray)arguments -{ - _operator = operator; - _arguments = arguments; - return self; -} - -+ (CPExpression)expressionForOperator:(CPExpressionOperator)operator arguments:(CPArray)arguments -{ - return [self initWithOperator:operator arguments:arguments]; -} - -- (CPArray)arguments -{ - return _arguments; -} - -- (CPString)description -{ - var result = [CPString string], - args = [CPArray array], - count = [_arguments count], - i; - - for (i = 0; i < count; i++) - { - var check = [_arguments objectAtIndex:i], - precedence = [check description]; - - if ([check isKindOfClass:[CPExpression_operator class]]) - precedence = [CPString stringWithFormat:@"(%@)", precedence]; - - [args addObject:precedence]; - } - - switch (_operator) - { - case CPExpressionOperatorNegate : - result = result + [CPString stringWithFormat:@"-%@", [args objectAtIndex:0]]; - break; - case CPExpressionOperatorAdd : - result = result + [CPString stringWithFormat:@"%@ + %@", [args objectAtIndex:0], [args objectAtIndex:1]]; - break; - case CPExpressionOperatorSubtract : - result = result + [CPString stringWithFormat:@"%@ - %@", [args objectAtIndex:0], [args objectAtIndex:1]]; - break; - case CPExpressionOperatorMultiply : - result = result + [CPString stringWithFormat:@"%@ * %@", [args objectAtIndex:0], [args objectAtIndex:1]]; - break; - case CPExpressionOperatorDivide : - result = result + [CPString stringWithFormat:@"%@ / %@", [args objectAtIndex:0], [args objectAtIndex:1]]; - break; - case CPExpressionOperatorExp : - result = result + [CPString stringWithFormat:@"%@ ** %@", [args objectAtIndex:0], [args objectAtIndex:1]]; - break; - case CPExpressionOperatorAssign : - result = result + [CPString stringWithFormat:@"%@ := %@", [args objectAtIndex:0], [args objectAtIndex:1]]; - break; - case CPExpressionOperatorKeypath : - result = result + [CPString stringWithFormat:@"%@.%@", [args objectAtIndex:0], [args objectAtIndex:1]]; - break; - case CPExpressionOperatorIndex : - result = result + [CPString stringWithFormat:@"%@[%@]", [args objectAtIndex:0], [args objectAtIndex:1]]; - break; - case CPExpressionOperatorIndexFirst : - result = result + [CPString stringWithFormat:@"%@[FIRST]", [args objectAtIndex:0]]; - break; - case CPExpressionOperatorIndexLast : - result = result + [CPString stringWithFormat:@"%@[LAST]", [args objectAtIndex:0]]; - break; - case CPExpressionOperatorIndexSize : - result = result + [CPString stringWithFormat:@"%@[SIZE]", [args objectAtIndex:0]]; - break; - } - - return result; -} - -- (CPExpression)_expressionWithSubstitutionVariables:(CPDictionary)variables -{ - var array = [CPArray array], - count = [_arguments count], - i; - - for (i = 0; i < count; i++) - [array addObject:[[_arguments objectAtIndex:i] _expressionWithSubstitutionVariables:variables]]; - - return [CPExpression_operator expressionForOperator:_operator arguments:array]; -} - -@end - diff --git a/Foundation/CPPredicate/CPExpression_self.j b/Foundation/CPPredicate/CPExpression_self.j index bfad66fe5..1173fe48c 100644 --- a/Foundation/CPPredicate/CPExpression_self.j +++ b/Foundation/CPPredicate/CPExpression_self.j @@ -4,13 +4,20 @@ @import @import -@implementation CPExpression_self : CPExpression{} +var defaultInstance = nil; +@implementation CPExpression_self : CPExpression +{ +} - (id)init { - [super initWithExpressionType:CPEvaluatedObjectExpressionType]; + if (defaultInstance == nil) + { + [super initWithExpressionType:CPEvaluatedObjectExpressionType]; + defaultInstance = self; + } - return self; + return defaultInstance; } - (id)initWithCoder:(CPCoder)coder @@ -24,10 +31,10 @@ - (BOOL)isEqual:(id)object { - return (object == self); + return (object === self); } -- (id)expressionValueWithObject:object context:(CPDictionary)context +- (id)expressionValueWithObject:(id)object context:(CPDictionary)context { return object; } diff --git a/Foundation/CPPredicate/CPExpression_set.j b/Foundation/CPPredicate/CPExpression_set.j new file mode 100644 index 000000000..990996233 --- /dev/null +++ b/Foundation/CPPredicate/CPExpression_set.j @@ -0,0 +1,115 @@ + +@import "CPExpression.j" + +@implementation CPExpression_set : CPExpression +{ + CPExpression _left; + CPExpression _right; +} + +- (id)initWithType:(int)type left:(CPExpression)left right:(CPExpression)right +{ + [super initWithExpressionType:type]; + _left = left; + _right = right; + + return self; +} + +- (BOOL)isEqual:(id)object +{ + if (self == object) + return YES; + + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object leftExpression] isEqual:[self leftExpression]] || ![[object rightExpression] isEqual:[self rightExpression]]) + return NO; + + return YES; +} + +- (id)expressionValueWithObject:object context:(CPDictionary)context +{ + var right = [_right expressionValueWithObject:object context:context]; + if ([right isKindOfClass:[CPArray class]]) // Or we could do [[right objectEnumerator] allObjects] + right = [CPSet setWithArray:right]; + else if ([right isKindOfClass:[CPDictionary class]]) + right = [CPSet setWithArray:[right allValues]]; + else if (![right isKindOfClass:[CPSet class]]) + [CPException raise:CPInvalidArgumentException reason:@"The right expression for a CP*SetExpressionType expression must evaluate to a CPArray, CPDictionary or CPSet"]; + + var left = [_left expressionValueWithObject:object context:context]; + if (![left isKindOfClass:[CPSet class]]) + [CPException raise:CPInvalidArgumentException reason:@"The left expression for a CP*SetExpressionType expression must evaluate to a CPSet"]; + + var result = [left copy]; + switch (_type) + { + case CPIntersectSetExpressionType : [result intersectSet:right]; + break; + case CPUnionSetExpressionType : [result unionSet:right]; + break; + case CPMinusSetExpressionType : [result minusSet:right]; + break; + default: + } + + return [CPExpression expressionForConstantValue:result]; +} + +- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables +{ + return self; +} + +- (CPExpression)leftExpression +{ + return _left; +} + +- (CPExpression)rightExpression +{ + return _right; +} + +- (CPString)description +{ + var desc; + switch (_type) + { + case CPIntersectSetExpressionType : desc = @" INTERSECT "; + break; + case CPUnionSetExpressionType : desc = @" UNION "; + break; + case CPMinusSetExpressionType : desc = @" MINUS "; + break; + default: + } + + return [_left description] + desc + [_right description]; +} + +@end + +var CPLeftExpressionKey = @"CPLeftExpression", + CPRightExpressionKey = @"CPRightExpression", + CPExpressionType = @"CPExpressionType"; + +@implementation CPExpression_set (CPCoding) + +- (id)initWithCoder:(CPCoder)coder +{ + var left = [coder decodeObjectForKey:CPLeftExpressionKey], + right = [coder decodeObjectForKey:CPRightExpressionKey], + type = [coder decodeIntForKey:CPExpressionType]; + + return [self initWithType:type left:left right:right]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_left forKey:CPLeftExpressionKey]; + [coder encodeObject:_right forKey:CPRightExpressionKey]; + [coder encodeInt:_type forKey:CPExpressionType]; +} + +@end diff --git a/Foundation/CPPredicate/CPExpression_unionset.j b/Foundation/CPPredicate/CPExpression_unionset.j deleted file mode 100644 index 45c9d137e..000000000 --- a/Foundation/CPPredicate/CPExpression_unionset.j +++ /dev/null @@ -1,84 +0,0 @@ - -@import "CPExpression.j" - -@implementation CPExpression_unionset : CPExpression - -- (id)initWithLeft:(CPExpression)left right:(CPExpression)right -{ - [super initWithExpressionType:CPUnionSetExpressionType]; - _left = left; - _right = right; - - return self; -} - -- (id)initWithCoder:(CPCoder)coder -{ - var left = [coder decodeObjectForKey:@"CPExpressionUnionSetLeftExpression"], - right = [coder decodeObjectForKey:@"CPExpressionUnionSetRightExpression"]; - - return [self initWithLeft:left right:right]; -} - -- (void)encodeWithCoder:(CPCoder)coder -{ - [coder encodeObject:_left forKey:@"CPExpressionUnionSetLeftExpression"]; - [coder encodeObject:_right forKey:@"CPExpressionUnionSetRightExpression"]; -} - -- (BOOL)isEqual:(id)object -{ - if (self == object) - return YES; - - if (object.isa != self.isa - || [object expressionType] != [self expressionType] - || ![[object leftExpression] isEqual:[self leftExpression]] - || ![[object rightExpression] isEqual:[self rightExpression]]) - return NO; - - return YES; -} - -- (id)expressionValueWithObject:object context:(CPDictionary )context -{ - var right = [_right expressionValueWithObject:object context:context]; - if (![right respondsToSelector: @selector(objectEnumerator)]) - [CPException raise:CPInvalidArgumentException reason:@"The right expression for a CPIntersectSetExpressionType expression must be either a CPArray, CPDictionary or CPSet"]; - - var left = [_left expressionValueWithObject:object context:context]; - if (![left isKindOfClass:[CPSet set]]) - [CPException raise:CPInvalidArgumentException reason:@"The left expression for a CPIntersectSetExpressionType expression must a CPSet"]; - - var unionset = [CPSet setWithSet:left], - e = [right objectEnumerator], - item; - - while (item = [e nextObject]) - [unionset addObject:item]; - - return [CPExpression expressionForConstantValue:unionset]; -} - -- (CPExpression )_expressionWithSubstitutionVariables:(CPDictionary )variables -{ - return self; -} - -- (CPExpression)leftExpression -{ - return _left; -} - -- (CPExpression)rightExpression -{ - return _right; -} - -- (CPString )description -{ - return [_left description] +" UNION "+ [_right description]; -} - -@end - diff --git a/Foundation/CPPredicate/CPExpression_variable.j b/Foundation/CPPredicate/CPExpression_variable.j index 1b7db6b28..f87c4fd4f 100644 --- a/Foundation/CPPredicate/CPExpression_variable.j +++ b/Foundation/CPPredicate/CPExpression_variable.j @@ -16,17 +16,6 @@ return self; } -- (id)initWithCoder:(CPCoder)coder -{ - var variable = [coder decodeObjectForKey:@"CPExpressionVariable"]; - return [self initWithVariable:variable]; -} - -- (void)encodeWithCoder:(CPCoder)coder -{ - [coder encodeObject:_variable forKey:@"CPExpressionVariable"]; -} - - (BOOL)isEqual:(id)object { if (self == object) @@ -63,6 +52,22 @@ return self; } +@end + +var CPVariableKey = @"CPVariable"; + +@implementation CPExpression_variable (CPCoding) + +- (id)initWithCoder:(CPCoder)coder +{ + var variable = [coder decodeObjectForKey:CPVariableKey]; + return [self initWithVariable:variable]; +} + +- (void)encodeWithCoder:(CPCoder)coder +{ + [coder encodeObject:_variable forKey:CPVariableKey]; +} @end diff --git a/Foundation/CPPredicate/CPPredicate.j b/Foundation/CPPredicate/CPPredicate.j index 6a77470da..12b139252 100644 --- a/Foundation/CPPredicate/CPPredicate.j +++ b/Foundation/CPPredicate/CPPredicate.j @@ -514,11 +514,11 @@ function(newValue)\ dbl; if ([self scanDouble:REFERENCE(dbl)]) - return [CPExpression expressionForConstantValue:[CPNumber numberWithDouble:dbl]]; + return [CPExpression expressionForConstantValue:dbl]; // FIXME: handle integer, hex constants, 0x 0o 0b if ([self scanString:@"-" intoString:NULL]) - return [CPExpression expressionForFunction:@"chs" arguments:[CPArray arrayWithObject:[self parseExpression]]]; + return [CPExpression expressionForFunction:@"chs:" arguments:[CPArray arrayWithObject:[self parseExpression]]]; if ([self scanString:@"(" intoString:NULL]) { @@ -544,7 +544,7 @@ function(newValue)\ if (![self scanString:@"}" intoString:NULL]) [CPException raise:CPInvalidArgumentException reason:@"Missing } in aggregate"]; - return [CPExpression expressionForConstantValue:a]; + return [CPExpression expressionForAggregate:a]; } if ([self scanPredicateKeyword:@"NULL"] || [self scanPredicateKeyword:@"NIL"]) @@ -728,28 +728,6 @@ function(newValue)\ } left = [CPExpression expressionForFunction:[left keyPath] arguments:args]; } - else if ([self scanString:@"[" intoString:NULL]) - { - // index expression - if ([self scanPredicateKeyword:@"FIRST"]) - { - left = [CPExpression expressionForFunction:@"first" arguments:[CPArray arrayWithObject:[self parseExpression]]]; - } - else if ([self scanPredicateKeyword:@"LAST"]) - { - left = [CPExpression expressionForFunction:@"last" arguments:[CPArray arrayWithObject:[self parseExpression]]]; - } - else if ([self scanPredicateKeyword:@"SIZE"]) - { - left = [CPExpression expressionForFunction:@"count" arguments:[CPArray arrayWithObject:[self parseExpression]]]; - } - else - { - left = [CPExpression expressionForFunction:@"index" arguments:[CPArray arrayWithObjects:left, [self parseExpression]]]; - } - if (![self scanString:@"]" intoString:NULL]) - [CPException raise:CPInvalidArgumentException reason:@"Missing ] in index argument"]; - } else if ([self scanString:@"." intoString:NULL]) { // keypath - this parser allows for (a).(b.c) @@ -760,12 +738,38 @@ function(newValue)\ if (![left keyPath]) [CPException raise:CPInvalidArgumentException reason:@"Invalid left keypath:" + left]; - var right = [self parseExpression]; + var right = [self parseSimpleExpression]; if (![right keyPath]) [CPException raise:CPInvalidArgumentException reason:@"Invalid right keypath:" + right]; // concatenate left = [CPExpression expressionForKeyPath:[left keyPath]+ "." + [right keyPath]]; + + } + else if ([self scanString:@"[" intoString:NULL]) + { + // index expression + if ([self scanPredicateKeyword:@"FIRST"]) + { + left = [CPExpression expressionForFunction:@"first:" arguments:[CPArray arrayWithObject:left]]; + } + else if ([self scanPredicateKeyword:@"LAST"]) + { + left = [CPExpression expressionForFunction:@"last:" arguments:[CPArray arrayWithObject:left]]; + } + else if ([self scanPredicateKeyword:@"SIZE"]) + { + left = [CPExpression expressionForFunction:@"count:" arguments:[CPArray arrayWithObject:left]]; + } + else + { + var integer; + if ([self scanInt:REFERENCE(integer)]) + left = [CPExpression expressionForFunction:@"fromObject:index:" arguments:[CPArray arrayWithObjects:left, [CPExpression expressionForConstantValue:integer]]]; + } + + if (![self scanString:@"]" intoString:NULL]) + [CPException raise:CPInvalidArgumentException reason:@"Missing ] in index argument"]; } else { @@ -786,7 +790,7 @@ function(newValue)\ if ([self scanString:@"**" intoString:NULL]) { right = [self parseFunctionalExpression]; - left = [CPExpression expressionForFunction:@"pow" arguments:[CPArray arrayWithObjects:left, right]]; + left = [CPExpression expressionForFunction:@"raise:to:" arguments:[CPArray arrayWithObjects:left, right]]; } else { @@ -806,12 +810,12 @@ function(newValue)\ if ([self scanString:@"*" intoString:NULL]) { right = [self parsePowerExpression]; - left = [CPExpression expressionForFunction:@"_mul" arguments:[CPArray arrayWithObjects:left, right]]; + left = [CPExpression expressionForFunction:@"multiply:by:" arguments:[CPArray arrayWithObjects:left, right]]; } else if ([self scanString:@"/" intoString:NULL]) { right = [self parsePowerExpression]; - left = [CPExpression expressionForFunction:@"_div" arguments:[CPArray arrayWithObjects:left, right]]; + left = [CPExpression expressionForFunction:@"divide:by:" arguments:[CPArray arrayWithObjects:left, right]]; } else { @@ -831,12 +835,12 @@ function(newValue)\ if ([self scanString:@"+" intoString:NULL]) { right = [self parseMultiplicationExpression]; - left = [CPExpression expressionForFunction:@"_add" arguments:[CPArray arrayWithObjects:left, right]]; + left = [CPExpression expressionForFunction:@"add:to:" arguments:[CPArray arrayWithObjects:left, right]]; } else if ([self scanString:@"-" intoString:NULL]) { right = [self parseMultiplicationExpression]; - left = [CPExpression expressionForFunction:@"_sub" arguments:[CPArray arrayWithObjects:left, right]]; + left = [CPExpression expressionForFunction:@"from:substract:" arguments:[CPArray arrayWithObjects:left, right]]; } else { @@ -872,6 +876,3 @@ function(newValue)\ @import "CPComparisonPredicate.j" @import "CPExpression.j" -@import "CPExpression_operator.j" -@import "CPExpression_aggregate.j" -@import "CPExpression_assignment.j" diff --git a/Tests/Foundation/CPPredicateTest.j b/Tests/Foundation/CPPredicateTest.j index 19798c59f..921667ba5 100644 --- a/Tests/Foundation/CPPredicateTest.j +++ b/Tests/Foundation/CPPredicateTest.j @@ -14,7 +14,7 @@ objects; dict = [[CPDictionary alloc] init]; - [dict setObject: @"A Title" forKey:@"title"]; + [dict setObject: @"Title" forKey:@"title"]; var keys = [CPArray arrayWithObjects:@"Name",@"Age",@"Children"]; objects = [CPArray arrayWithObjects:@"John",[CPNumber numberWithInt:34],[CPArray arrayWithObjects:@"Kid1", @"Kid2"]]; @@ -35,7 +35,8 @@ { var expression_keypath = [CPExpression expressionForKeyPath:@"name"]; [self assertNotNull:expression_keypath message:"KeyPath Expression should not be nil"]; - + [self assertTrue:[expression_keypath keyPath] == @"name" message:"-keyPath should not be \"name\""]; + var expression_str = [CPExpression expressionForConstantValue:@"j[a-z]an"]; [self assertNotNull:expression_str message:"ConstantValue Expression should not be nil"]; @@ -51,17 +52,20 @@ var expression_function = [CPExpression expressionForFunction:@"sum:" arguments:[CPArray arrayWithObjects:expression_num,expression_num]]; [self assertNotNull:expression_function message:"Function Expression should not be nil"]; - var expression_self = [CPExpression expressionForEvaluatedObject]; - [self assertNotNull:expression_self message:"Function Expression should not be nil"]; + expression_function = [CPExpression expressionForFunction:expression_num selectorName:@"isEqual:" arguments:[CPArray arrayWithObjects:expression_num]]; + [self assertNotNull:expression_function message:"Function Expression with target and selector should not be nil"]; - var expression_aggregate = [CPExpression expressionForAggregate:[CPArray arrayWithObjects:expression_str,expression_num,expression_function]]; + var expression_self = [CPExpression expressionForEvaluatedObject]; + [self assertNotNull:expression_self message:"Self Expression should not be nil"]; + + var expression_aggregate = [CPExpression expressionForAggregate:[CPArray arrayWithObjects:expression_str,expression_num]]; [self assertNotNull:expression_aggregate message:"Aggregate Expression should not be nil"]; var expression_subquery = [CPExpression expressionForSubquery:expression_collection usingIteratorVariable:@"self" predicate:[CPPredicate predicateWithValue:YES]]; // [self assertNotNull:expression_subquery message:"Subquery Expression should not be nil"]; - var set = [CPSet setWithObjects:@"a",@"b",@"d"]; - var array = [CPArray arrayWithObjects:@"a",@"b",@"d"]; + var set = [CPExpression expressionForConstantValue:[CPSet setWithObjects:@"a",@"b",@"c"]]; + var array = [CPExpression expressionForConstantValue:[CPArray arrayWithObjects:@"a",@"b",@"d"]]; var expression_intersect = [CPExpression expressionForIntersectSet:set with:array]; [self assertNotNull:expression_intersect message:"IntersectSet Expression should not be nil"]; @@ -73,16 +77,40 @@ [self assertNotNull:expression_minusset message:"MinusSet Expression should not be nil"]; } -- (void)testFunctionExpression +- (void)testSetExpressionEvaluation { - var function_exp = [CPExpression expressionForFunction:"sum:" arguments:[CPArray arrayWithObjects:[CPExpression expressionForConstantValue:1],[CPExpression expressionForConstantValue:2],[CPExpression expressionForConstantValue:3]]]; + var left = [CPExpression expressionForConstantValue:[CPSet setWithObjects:@"a",@"b",@"c"]]; + var right = [CPExpression expressionForConstantValue:[CPArray arrayWithObjects:@"a",@"b",@"d"]]; - var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:function_exp rightExpression:[CPExpression expressionForConstantValue:3] modifier:CPDirectPredicateModifier type:CPGreaterThanPredicateOperatorType options:0]; + var expression = [CPExpression expressionForIntersectSet:left with:right]; + var eval = [[expression expressionValueWithObject:nil context:nil] constantValue]; + [self assertTrue:[eval isEqualToSet:[CPSet setWithObjects:@"a",@"b"]] message:"Result should be {(a, b)}, is " + eval]; + expression = [CPExpression expressionForUnionSet:left with:right]; + eval = [[expression expressionValueWithObject:nil context:nil] constantValue]; + [self assertTrue:[eval isEqualToSet:[CPSet setWithObjects:@"a",@"b",@"c",@"d"]] message:"Result should be {(a, b, c, d)}, is " + eval]; + + expression = [CPExpression expressionForMinusSet:left with:right]; + eval = [[expression expressionValueWithObject:nil context:nil] constantValue]; + [self assertTrue:[eval isEqualToSet:[CPSet setWithObjects:@"c"]] message:"Result should be {(c)}, is " + eval]; +} + +- (void)testFunctionExpressionEvaluation +{ + var expression = [CPExpression expressionForConstantValue:[1,2,3]]; + var function_exp = [CPExpression expressionForFunction:"sum:" arguments:[expression]]; + + var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:function_exp rightExpression:[CPExpression expressionForConstantValue:6] modifier:CPDirectPredicateModifier type:CPEqualToPredicateOperatorType options:0]; + [self assertTrue:[pred evaluateWithObject:nil] message:[pred description] + " should be true"]; + + var operand = [CPExpression expressionForConstantValue:@"text"]; + var arg = [CPExpression expressionForConstantValue:2]; + function_exp = [CPExpression expressionForFunction:operand selectorName:@"substringFromIndex:" arguments:[arg]]; + pred = [[CPComparisonPredicate alloc] initWithLeftExpression:function_exp rightExpression:[CPExpression expressionForConstantValue:@"xt"] modifier:CPDirectPredicateModifier type:CPEqualToPredicateOperatorType options:0]; [self assertTrue:[pred evaluateWithObject:nil] message:[pred description] + " should be true"]; } -- (void)testVariableExpression +- (void)testVariableExpressionEvaluation { var variable_exp = [CPExpression expressionForVariable:@"variable"]; var pred = [[CPComparisonPredicate alloc] initWithLeftExpression:[CPExpression expressionForKeyPath:@"Record1.Age"] rightExpression:variable_exp modifier:CPDirectPredicateModifier type:CPGreaterThanPredicateOperatorType options:0]; @@ -205,7 +233,7 @@ predicate = [CPPredicate predicateWithFormat: @"%f > %K", 40.5, @"Record1.Age"]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; -// TEST Aggregate +// TEST KeyPath predicate = [CPPredicate predicateWithFormat: @"%@ IN %K", @"Kid1", @"Record1.Children"]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; @@ -215,6 +243,37 @@ predicate = [CPPredicate predicateWithFormat: @"ANY %K == %@", @"Record2.Children", @"Girl1"]; [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; +// Test Aggregate + predicate = [CPPredicate predicateWithFormat:@"{Record1 .Name, Record1.Age} = {'John',34}"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + +// Test Symbolic token + predicate = [CPPredicate predicateWithFormat:@"Record1.Children[FIRST] = 'Kid1'"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat:@"Record1.Children[1] = 'Kid2'"]; + [self assertTrue:[predicate evaluateWithObject:dict] message:[predicate description] + " should be true"]; + +// Test arithm + var n = 2; + predicate = [CPPredicate predicateWithFormat:@"SELF +1 = 3"]; + [self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat:@"SELF- 1 = 1"]; + [self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat:@"SELF / 2 = 1"]; + [self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat:@"SELF / 2 = 1"]; + [self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat:@"SELF* 2 = 4"]; + [self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"]; + + predicate = [CPPredicate predicateWithFormat:@"SELF** 3 = 8"]; + [self assertTrue:[predicate evaluateWithObject:n] message:[predicate description] + " should be true"]; + // TEST Operator type predicate = [CPPredicate predicateWithFormat: @"a CONTAINS[c] \"b\""]; [self assertTrue:([predicate predicateOperatorType] == CPContainsPredicateOperatorType) message:[predicate description] + " operator should be a CPContainsPredicateOperatorType"]; From 7626af00e73986ccc8508b212a3f9b694507f759 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 27 Oct 2010 20:16:14 -0300 Subject: [PATCH 7/9] Apply Cappuccino code style. --- .../CPPredicate/CPComparisonPredicate.j | 12 +++--- Foundation/CPPredicate/CPCompoundPredicate.j | 2 +- .../CPPredicate/CPExpression_aggregate.j | 16 ++++---- .../CPPredicate/CPExpression_constant.j | 6 +-- .../CPPredicate/CPExpression_function.j | 40 +++++++++---------- Foundation/CPPredicate/CPExpression_keypath.j | 2 +- Foundation/CPPredicate/CPExpression_set.j | 38 +++++++++--------- Foundation/CPPredicate/CPPredicate.j | 16 ++++---- 8 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Foundation/CPPredicate/CPComparisonPredicate.j b/Foundation/CPPredicate/CPComparisonPredicate.j index 7a8f855e3..5ccd47b97 100644 --- a/Foundation/CPPredicate/CPComparisonPredicate.j +++ b/Foundation/CPPredicate/CPComparisonPredicate.j @@ -135,8 +135,8 @@ CPContainsPredicateOperatorType = 99; */ CPBetweenPredicateOperatorType = 100; -var CPComparisonPredicateModifier; -var CPPredicateOperatorType; +var CPComparisonPredicateModifier, + CPPredicateOperatorType; /*! @ingroup foundation @@ -425,8 +425,8 @@ var CPPredicateOperatorType; lhs = lhs.stripDiacritics(); rhs = rhs.stripDiacritics(); } - var commut = (_options & CPCaseInsensitivePredicateOption) ? "gi":"g"; - var reg = new RegExp(rhs.escapeForRegExp(),commut); + var commut = (_options & CPCaseInsensitivePredicateOption) ? "gi":"g", + reg = new RegExp(rhs.escapeForRegExp(),commut); return reg.test(lhs); case CPBeginsWithPredicateOperatorType: var range = CPMakeRange(0,[rhs length]); @@ -544,8 +544,8 @@ var CPPredicateOperatorType; @end -var source = ['*','?','(',')','{','}','.','+','|','/','$','^']; -var dest = ['.*','.?','\\(','\\)','\\{','\\}','\\.','\\+','\\|','\\/','\\$','\\^']; +var source = ['*','?','(',')','{','}','.','+','|','/','$','^'], + dest = ['.*','.?','\\(','\\)','\\{','\\}','\\.','\\+','\\|','\\/','\\$','\\^']; String.prototype.escapeForRegExp = function() { diff --git a/Foundation/CPPredicate/CPCompoundPredicate.j b/Foundation/CPPredicate/CPCompoundPredicate.j index 55cd1ed0b..0ea197261 100644 --- a/Foundation/CPPredicate/CPCompoundPredicate.j +++ b/Foundation/CPPredicate/CPCompoundPredicate.j @@ -126,7 +126,7 @@ var CPCompoundPredicateType; i; if (count == 0) - return @"TRUPREDICATE"; + return @"TRUPREDICATE"; for (i = 0; i < count; i++) { diff --git a/Foundation/CPPredicate/CPExpression_aggregate.j b/Foundation/CPPredicate/CPExpression_aggregate.j index fdf114bec..4414afffe 100644 --- a/Foundation/CPPredicate/CPExpression_aggregate.j +++ b/Foundation/CPPredicate/CPExpression_aggregate.j @@ -19,10 +19,10 @@ { if (self == object) return YES; - + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object collection] isEqual:[self collection]]) return NO; - + return YES; } @@ -36,7 +36,7 @@ var eval_array = [CPArray array], collection = [_aggregate objectEnumerator], exp; - + while (exp = [collection nextObject]) { var eval = [exp expressionValueWithObject:object context:context]; @@ -49,14 +49,14 @@ - (CPString)description { var i, - count = [_aggregate count], + count = [_aggregate count], result = "{"; - + for (i = 0; i < count; i++) result = result + [CPString stringWithFormat:@"%s%s", [[_aggregate objectAtIndex:i] description], (i + 1 < count) ? @", " : @""]; - + result = result + "}"; - + return result; } @@ -65,7 +65,7 @@ var subst_array = [CPArray array], count = [_aggregate count], i; - + for (i = 0; i < count; i++) [subst_array addObject:[[_aggregate objectAtIndex:i] _expressionWithSubstitutionVariables:variables]]; diff --git a/Foundation/CPPredicate/CPExpression_constant.j b/Foundation/CPPredicate/CPExpression_constant.j index 858cdcd0d..4cd38fd99 100644 --- a/Foundation/CPPredicate/CPExpression_constant.j +++ b/Foundation/CPPredicate/CPExpression_constant.j @@ -11,7 +11,7 @@ { [super initWithExpressionType:CPConstantValueExpressionType]; _value = value; - + return self; } @@ -19,10 +19,10 @@ { if (self == object) return YES; - + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object constantValue] isEqual:[self constantValue]]) return NO; - + return YES; } diff --git a/Foundation/CPPredicate/CPExpression_function.j b/Foundation/CPPredicate/CPExpression_function.j index 2ff9c5c7f..02209a495 100644 --- a/Foundation/CPPredicate/CPExpression_function.j +++ b/Foundation/CPPredicate/CPExpression_function.j @@ -17,22 +17,22 @@ var target = [CPPredicateUtilities class]; if (![target respondsToSelector:aSelector]) [CPException raise:CPInvalidArgumentException reason:@"Unknown function implementation: " + aSelector]; - + var operand = [CPExpression expressionForConstantValue:target]; return [self initWithTarget:operand selector:aSelector arguments:parameters]; } - (id)initWithTarget:(CPExpression)targetExpression selector:aSelector arguments:parameters { - [super initWithExpressionType:CPFunctionExpressionType]; - + [super initWithExpressionType:CPFunctionExpressionType]; + // Cocoa doc: "This method throws an exception immediately if the selector is unknown" -// but targetExpression's value (selector's target) may be resolved only at runtime. +// but targetExpression's value (selector's target) may be resolved only at runtime. _selector = aSelector; _operand = targetExpression; _arguments = parameters; _argc = [parameters count]; - + return self; } @@ -40,10 +40,10 @@ { if (self == object) return YES; - + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object _function] isEqualToString:[self _function]] || ![[object operand] isEqual:[self operand]] || ![[object arguments] isEqualToArray:[self arguments]]) return NO; - + return YES; } @@ -77,20 +77,20 @@ { var arg = [_arguments[i] expressionValueWithObject:object context:context]; objj_args.push(arg); - } - + } + return objj_msgSend.apply(this, objj_args); } - (CPString)description -{ +{ var result = _operand + [self _function] + "("; - + for (var i = 0; i < _argc; i++) result = result + [_arguments[i] description] + ((i + 1 < _argc) ? ", " : ""); - + result = result + ")"; - + return result ; } @@ -98,7 +98,7 @@ { var array = [CPArray array], i; - + for (i = 0; i < _argc; i++) [array addObject:[[_arguments objectAtIndex:i] _expressionWithSubstitutionVariables:variables]]; @@ -118,7 +118,7 @@ var CPSelectorNameKey = @"CPSelectorName", var target = [coder decodeObjectForKey:CPOperandKey], selector = CPSelectorFromString([coder decodeObjectForKey:CPSelectorNameKey]), arguments = [coder decodeObjectForKey:CPArgumentsKey]; - + return [self initWithTarget:target selector:selector arguments:arguments]; } @@ -140,10 +140,10 @@ var CPSelectorNameKey = @"CPSelectorName", { var sum = 0, count = parameters.length; - + while (count--) sum += parameters[count]; - + return sum; } @@ -162,7 +162,7 @@ var CPSelectorNameKey = @"CPSelectorName", return parameters.sort()[parameters.length - 1]; } -+ (float)average:(CPArray)parameters ++ (float)average:(CPArray)parameters { return [self sum:parameters] / parameters.length; } @@ -183,7 +183,7 @@ var CPSelectorNameKey = @"CPSelectorName", return [object objectForKey:anIndex]; else ([object isKindOfClass:[CPArray class]]) return [object objectAtIndex:anIndex]; - + [CPException raise:CPInvalidArgumentException reason:@"object[#] requires a CPDictionary or CPArray"]; } @@ -214,7 +214,7 @@ var CPSelectorNameKey = @"CPSelectorName", + (float)raise:(float)num to:(int)power { - return POW(num, power); + return POW(num, power); } + (float)abs:(float)num diff --git a/Foundation/CPPredicate/CPExpression_keypath.j b/Foundation/CPPredicate/CPExpression_keypath.j index b97cd9a52..f5302a20c 100644 --- a/Foundation/CPPredicate/CPExpression_keypath.j +++ b/Foundation/CPPredicate/CPExpression_keypath.j @@ -18,7 +18,7 @@ var arg = [CPExpression expressionForConstantValue:keyPath]; // Cocoa: if it's a direct path selector is valueForKey: self = [super initWithTarget:operand selector:@selector(valueForKeyPath:) arguments:[arg]]; - + return self; } diff --git a/Foundation/CPPredicate/CPExpression_set.j b/Foundation/CPPredicate/CPExpression_set.j index 990996233..38f5a542f 100644 --- a/Foundation/CPPredicate/CPExpression_set.j +++ b/Foundation/CPPredicate/CPExpression_set.j @@ -12,7 +12,7 @@ [super initWithExpressionType:type]; _left = left; _right = right; - + return self; } @@ -20,15 +20,15 @@ { if (self == object) return YES; - + if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object leftExpression] isEqual:[self leftExpression]] || ![[object rightExpression] isEqual:[self rightExpression]]) return NO; - + return YES; } - (id)expressionValueWithObject:object context:(CPDictionary)context -{ +{ var right = [_right expressionValueWithObject:object context:context]; if ([right isKindOfClass:[CPArray class]]) // Or we could do [[right objectEnumerator] allObjects] right = [CPSet setWithArray:right]; @@ -37,22 +37,22 @@ else if (![right isKindOfClass:[CPSet class]]) [CPException raise:CPInvalidArgumentException reason:@"The right expression for a CP*SetExpressionType expression must evaluate to a CPArray, CPDictionary or CPSet"]; - var left = [_left expressionValueWithObject:object context:context]; + var left = [_left expressionValueWithObject:object context:context]; if (![left isKindOfClass:[CPSet class]]) [CPException raise:CPInvalidArgumentException reason:@"The left expression for a CP*SetExpressionType expression must evaluate to a CPSet"]; - - var result = [left copy]; + + var result = [left copy]; switch (_type) { case CPIntersectSetExpressionType : [result intersectSet:right]; - break; + break; case CPUnionSetExpressionType : [result unionSet:right]; - break; + break; case CPMinusSetExpressionType : [result minusSet:right]; - break; - default: + break; + default: } - + return [CPExpression expressionForConstantValue:result]; } @@ -72,17 +72,17 @@ } - (CPString)description -{ +{ var desc; switch (_type) { case CPIntersectSetExpressionType : desc = @" INTERSECT "; - break; + break; case CPUnionSetExpressionType : desc = @" UNION "; - break; + break; case CPMinusSetExpressionType : desc = @" MINUS "; - break; - default: + break; + default: } return [_left description] + desc + [_right description]; @@ -93,7 +93,7 @@ var CPLeftExpressionKey = @"CPLeftExpression", CPRightExpressionKey = @"CPRightExpression", CPExpressionType = @"CPExpressionType"; - + @implementation CPExpression_set (CPCoding) - (id)initWithCoder:(CPCoder)coder @@ -101,7 +101,7 @@ var CPLeftExpressionKey = @"CPLeftExpression", var left = [coder decodeObjectForKey:CPLeftExpressionKey], right = [coder decodeObjectForKey:CPRightExpressionKey], type = [coder decodeIntForKey:CPExpressionType]; - + return [self initWithType:type left:left right:right]; } diff --git a/Foundation/CPPredicate/CPPredicate.j b/Foundation/CPPredicate/CPPredicate.j index 12b139252..2041e7e71 100644 --- a/Foundation/CPPredicate/CPPredicate.j +++ b/Foundation/CPPredicate/CPPredicate.j @@ -255,8 +255,8 @@ function(newValue)\ - (BOOL)scanPredicateKeyword:(CPString)key { - var loc = [self scanLocation]; - var c; + var loc = [self scanLocation], + c; [self setCaseSensitive:NO]; if (![self scanString:key intoString:NULL]) @@ -638,7 +638,7 @@ function(newValue)\ [self setScanLocation:location]; } - + if ([self scanString:@"\"" intoString:NULL]) { var skip = [self charactersToBeSkipped], @@ -669,7 +669,7 @@ function(newValue)\ if ([self scanString:@"'" intoString:NULL] == NO) { [self setCharactersToBeSkipped:skip]; - [CPException raise:CPInvalidArgumentException reason:@"Invalid double quoted literal at "+location]; + [CPException raise:CPInvalidArgumentException reason:@"Invalid double quoted literal at " + location]; } [self setCharactersToBeSkipped:skip]; @@ -682,9 +682,9 @@ function(newValue)\ var e = [self parseExpression]; if (![e keyPath]) - [CPException raise:CPInvalidArgumentException reason:@"Invalid keypath identifier: "+e]; + [CPException raise:CPInvalidArgumentException reason:@"Invalid keypath identifier: " + e]; - return [CPExpression expressionForKeyPath:[e keyPath]+"@"]; + return [CPExpression expressionForKeyPath:[e keyPath] + "@"]; } [self scanString:@"#" intoString:NULL]; @@ -744,7 +744,7 @@ function(newValue)\ // concatenate left = [CPExpression expressionForKeyPath:[left keyPath]+ "." + [right keyPath]]; - + } else if ([self scanString:@"[" intoString:NULL]) { @@ -767,7 +767,7 @@ function(newValue)\ if ([self scanInt:REFERENCE(integer)]) left = [CPExpression expressionForFunction:@"fromObject:index:" arguments:[CPArray arrayWithObjects:left, [CPExpression expressionForConstantValue:integer]]]; } - + if (![self scanString:@"]" intoString:NULL]) [CPException raise:CPInvalidArgumentException reason:@"Missing ] in index argument"]; } From 923d7c63b5103c5f6355858c7e7e4df8886ffa5b Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 27 Oct 2010 20:24:05 -0300 Subject: [PATCH 8/9] Fixed an accidental global. --- Foundation/CPArray+KVO.j | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Foundation/CPArray+KVO.j b/Foundation/CPArray+KVO.j index 2d51447a6..fbc7b7407 100644 --- a/Foundation/CPArray+KVO.j +++ b/Foundation/CPArray+KVO.j @@ -28,7 +28,7 @@ - (id)mutableArrayValueForKey:(id)aKey { - return [[_CPKVCArray alloc] initWithKey:aKey forProxyObject:self]; + return [[_CPKVCArray alloc] initWithKey:aKey forProxyObject:self]; } - (id)mutableArrayValueForKeyPath:(id)aKeyPath @@ -423,7 +423,7 @@ kvoOperators["avg"] = function avgOperator(self, _cmd, param) { var objects = [self valueForKeyPath:param], length = [objects count], - index = length; + index = length, average = 0.0; if (!length) @@ -518,7 +518,7 @@ kvoOperators["sum"] = function sumOperator(self, _cmd, param) [super addObserver:observer forKeyPath:aKeyPath options:options context:context]; } --(void)removeObserver:(id)observer forKeyPath:(CPString)aKeyPath +- (void)removeObserver:(id)observer forKeyPath:(CPString)aKeyPath { if ([isa instanceMethodForSelector:_cmd] === [CPArray instanceMethodForSelector:_cmd]) [CPException raise:CPInvalidArgumentException reason:"Unsupported method on CPArray"]; From a80732f13abf8e24e5687904cca6412d8d150729 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Wed, 27 Oct 2010 20:44:55 -0300 Subject: [PATCH 9/9] Whitespace and style cleanup. --- Foundation/CPArray.j | 44 +++++++++++----------- Foundation/CPAttributedString.j | 22 +++++------ Foundation/CPCharacterSet.j | 64 ++++++++++++++++---------------- Foundation/CPDictionary.j | 2 +- Foundation/CPFormatter.j | 66 ++++++++++++++++----------------- Foundation/CPJSONPConnection.j | 2 +- 6 files changed, 100 insertions(+), 100 deletions(-) diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j index ed97d6ea1..866fd8dad 100755 --- a/Foundation/CPArray.j +++ b/Foundation/CPArray.j @@ -405,7 +405,7 @@ CPEnumerationReverse = 1 << 1; @param predicate The function to apply to elements of the array. The function receives two arguments: object The element in the array. index The index of the element in the array. - The predicate function should either return a Boolean value that indicates whether the object passed the test, + The predicate function should either return a Boolean value that indicates whether the object passed the test, or nil to stop the search, which will return CPNotFound to the sender. @return The index of the first matching object, or \c CPNotFound if there is no matching object. */ @@ -420,7 +420,7 @@ CPEnumerationReverse = 1 << 1; object The element in the array. index The index of the element in the array. context The object passed to the receiver in the aContext parameter. - The predicate function should either return a Boolean value that indicates whether the object passed the test, + The predicate function should either return a Boolean value that indicates whether the object passed the test, or nil to stop the search, which will return CPNotFound to the sender. @param context An object that contains context information you want passed to the predicate function. @return The index of the first matching object, or \c CPNotFound if there is no matching object. @@ -432,29 +432,29 @@ CPEnumerationReverse = 1 << 1; /*! Returns the index of the first object in the receiver that passes a test in a given Javascript function. - @param opts Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards + @param opts Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards or CPEnumerationReverse to search in reverse. @param predicate The function to apply to elements of the array. The function receives two arguments: object The element in the array. index The index of the element in the array. - The predicate function should either return a Boolean value that indicates whether the object passed the test, + The predicate function should either return a Boolean value that indicates whether the object passed the test, or nil to stop the search, which will return CPNotFound to the sender. @return The index of the first matching object, or \c CPNotFound if there is no matching object. */ - (unsigned)indexOfObjectWithOptions:(CPEnumerationOptions)opts passingTest:(Function)predicate { return [self indexOfObjectWithOptions:opts passingTest:predicate context:undefined]; -} +} /*! Returns the index of the first object in the receiver that passes a test in a given Javascript function. - @param opts Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards + @param opts Specifies the direction in which the array is searched. Pass CPEnumerationNormal to search forwards or CPEnumerationReverse to search in reverse. @param predicate The function to apply to elements of the array. The function receives two arguments: object The element in the array. index The index of the element in the array. context The object passed to the receiver in the aContext parameter. - The predicate function should either return a Boolean value that indicates whether the object passed the test, + The predicate function should either return a Boolean value that indicates whether the object passed the test, or nil to stop the search, which will return CPNotFound to the sender. @param context An object that contains context information you want passed to the predicate function. @return The index of the first matching object, or \c CPNotFound if there is no matching object. @@ -463,9 +463,9 @@ CPEnumerationReverse = 1 << 1; { // We don't use an enumerator because they return nil to indicate end of enumeration, // but nil may actually be the value we are looking for, so we have to loop over the array. - + var start, stop, increment; - + if (opts & CPEnumerationReverse) { start = [self count] - 1; @@ -478,17 +478,17 @@ CPEnumerationReverse = 1 << 1; stop = [self count]; increment = 1; } - + for (var i = start; i != stop; i += increment) { var result = predicate([self objectAtIndex:i], i, aContext); - + if (typeof result === 'boolean' && result) return i; else if (typeof result === 'object' && result == nil) return CPNotFound; } - + return CPNotFound; } @@ -615,7 +615,7 @@ CPEnumerationReverse = 1 << 1; result = CPOrderedSame; while (i < count) - if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame) + if ((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame) return result; return result; @@ -1103,7 +1103,7 @@ CPEnumerationReverse = 1 << 1; result = CPOrderedSame; while (i < count) - if((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame) + if ((result = [descriptors[i++] compareObject:lhs withObject:rhs]) != CPOrderedSame) return result; return result; @@ -1328,7 +1328,7 @@ CPEnumerationReverse = 1 << 1; { var h, i, j, k, l, m, n = [self count], o; var A, B = []; - + for (h = 1; h < n; h += h) { for (m = n - 1 - h; m >= 0; m -= h + h) @@ -1336,10 +1336,10 @@ CPEnumerationReverse = 1 << 1; l = m - h + 1; if (l < 0) l = 0; - + for (i = 0, j = l; j <= m; i++, j++) B[i] = self[j]; - + for (i = 0, k = l; k < j && j <= m + h; k++) { A = self[j]; @@ -1352,7 +1352,7 @@ CPEnumerationReverse = 1 << 1; j++; } } - + while (k < j) self[k++] = B[i++]; } @@ -1377,14 +1377,14 @@ var selectorCompare = function selectorCompare(object1, object2, selector) // sort using sort descriptors var compareObjectsUsingDescriptors= function compareObjectsUsingDescriptors(lhs, rhs, descriptors) -{ +{ var result = CPOrderedSame, - i = 0, + i = 0, n = [descriptors count]; - + while (i < n && result === CPOrderedSame) result = [descriptors[i++] compareObject:lhs withObject:rhs]; - + return result; } diff --git a/Foundation/CPAttributedString.j b/Foundation/CPAttributedString.j index 85bb3588f..4b61af4a7 100644 --- a/Foundation/CPAttributedString.j +++ b/Foundation/CPAttributedString.j @@ -390,11 +390,11 @@ */ - (BOOL)isEqualToAttributedString:(CPAttributedString)aString { - if (!aString) - return NO; + if (!aString) + return NO; - if (_string != [aString string]) - return NO; + if (_string != [aString string]) + return NO; var myRange = CPMakeRange(), comparisonRange = CPMakeRange(), @@ -424,13 +424,13 @@ */ - (BOOL)isEqual:(id)anObject { - if (anObject == self) - return YES; + if (anObject == self) + return YES; - if ([anObject isKindOfClass:[self class]]) - return [self isEqualToAttributedString:anObject]; + if ([anObject isKindOfClass:[self class]]) + return [self isEqualToAttributedString:anObject]; - return NO; + return NO; } //Extracting a Substring @@ -530,8 +530,8 @@ endingIndex = startingIndex + 1; - while(endingIndex < _rangeEntries.length) - _rangeEntries[endingIndex++].range.location+=additionalLength; + while (endingIndex < _rangeEntries.length) + _rangeEntries[endingIndex++].range.location += additionalLength; } /*! diff --git a/Foundation/CPCharacterSet.j b/Foundation/CPCharacterSet.j index fcc5c04d9..f75bff0f0 100644 --- a/Foundation/CPCharacterSet.j +++ b/Foundation/CPCharacterSet.j @@ -128,17 +128,17 @@ var _builtInCharacterSets = {}; + (id)_sharedCharacterSetWithName:(id)csname { var cs = _builtInCharacterSets[csname]; - if(cs == nil) + if (cs == nil) { var i, ranges = [CPArray array], rangeArray = eval(csname); - for(i = 0; i < rangeArray.length; i+= 2) + for (i = 0; i < rangeArray.length; i+= 2) { - var loc = rangeArray[i]; - var length = rangeArray[i+1]; - var range = CPMakeRange(loc,length); + var loc = rangeArray[i], + length = rangeArray[i + 1], + range = CPMakeRange(loc,length); [ranges addObject:range]; } cs = [[_CPRangeCharacterSet alloc] initWithRanges:ranges]; @@ -196,13 +196,13 @@ var _builtInCharacterSets = {}; - (BOOL)characterIsMember:(CPString)aCharacter { c = aCharacter.charCodeAt(0); - var enu = [_ranges objectEnumerator]; - var range; + var enu = [_ranges objectEnumerator], + range; while (range = [enu nextObject]) { if (CPLocationInRange(c, range)) - return !_inverted; + return !_inverted; } return _inverted; @@ -226,10 +226,10 @@ var _builtInCharacterSets = {}; { var i; - for(i = 0; i < aString.length; i++) + for (i = 0; i < aString.length; i++) { - var code = aString.charCodeAt(i); - var range = CPMakeRange(code,1); + var code = aString.charCodeAt(i), + range = CPMakeRange(code,1); [_ranges addObject:range]; } @@ -262,7 +262,7 @@ var _builtInCharacterSets = {}; return set; } --(id)invertedSet +- (id)invertedSet { var set = [[_CPStringContentCharacterSet alloc] initWithString:_string]; [set invert]; @@ -294,7 +294,7 @@ var _builtInCharacterSets = {}; - (void)addCharactersInRange:(CPRange)aRange // Needs _inverted support { var i; - for(i = aRange.location; i < aRange.location + aRange.length; i++) + for (i = aRange.location; i < aRange.location + aRange.length; i++) { var s = String.fromCharCode(i); @@ -307,7 +307,7 @@ var _builtInCharacterSets = {}; { var i; - for(i = 0; i < aString.length; i++) + for (i = 0; i < aString.length; i++) { var s = aString.charAt(i); @@ -330,34 +330,34 @@ _CPCharacterSetTrimAtEnd = 1 << 2; and the set is [CPCharacterSet whitespaceCharacterSet] the returned array would contain:
 ["Baku", "baku", "to", "jest", "", "skład."] 
- Adjacent occurences of the separator characters produce empty strings in the result. - @author Arkadiusz Młynarczyk + Adjacent occurences of the separator characters produce empty strings in the result. + @author Arkadiusz Młynarczyk @param A character set containing the characters to use to split the receiver. Must not be nil. @return An CPArray object containing substrings from the receiver that have been divided by characters in separator. */ - (CPArray)componentsSeparatedByCharactersInSet:(CPCharacterSet)separator { - if (!separator) - [CPException raise:CPInvalidArgumentException + if (!separator) + [CPException raise:CPInvalidArgumentException reason:"componentsSeparatedByCharactersInSet: the separator can't be 'nil'"]; - var components = [CPMutableArray array], - componentRange = CPMakeRange(0, 0); + var components = [CPMutableArray array], + componentRange = CPMakeRange(0, 0); - for (var i=0; i < self.length; i++) - { - if ([separator characterIsMember:self.charAt(i)]) - { - componentRange.length = i - componentRange.location; - [components addObject:[self substringWithRange:componentRange]]; - componentRange.location += componentRange.length + 1; - } - } + for (var i = 0; i < self.length; i++) + { + if ([separator characterIsMember:self.charAt(i)]) + { + componentRange.length = i - componentRange.location; + [components addObject:[self substringWithRange:componentRange]]; + componentRange.location += componentRange.length + 1; + } + } - componentRange.length = self.length - componentRange.location; - [components addObject:[self substringWithRange:componentRange]]; + componentRange.length = self.length - componentRange.location; + [components addObject:[self substringWithRange:componentRange]]; - return components; + return components; } // As per the Cocoa method. diff --git a/Foundation/CPDictionary.j b/Foundation/CPDictionary.j index 3d6995161..61634cd67 100755 --- a/Foundation/CPDictionary.j +++ b/Foundation/CPDictionary.j @@ -364,7 +364,7 @@ } return matchingKeys; -} +} /*! Returns an enumerator that enumerates over all the dictionary's keys. diff --git a/Foundation/CPFormatter.j b/Foundation/CPFormatter.j index 0ff278b1e..4098493d7 100644 --- a/Foundation/CPFormatter.j +++ b/Foundation/CPFormatter.j @@ -23,13 +23,13 @@ /*! @class CPFormatter @ingroup foundation - @brief CPFormatter is an abstract class that declares an interface for objects that create, interpret, - and validate the textual representation of cell contents. The Foundation framework provides two + @brief CPFormatter is an abstract class that declares an interface for objects that create, interpret, + and validate the textual representation of cell contents. The Foundation framework provides two concrete subclasses of CPFormatter to generate these objects: CPNumberFormatter and CPDateFormatter. - CPFormatter is intended for subclassing. A custom formatter can restrict the input and enhance the - display of data in novel ways. For example, you could have a custom formatter that ensures that serial - numbers entered by a user conform to predefined formats. Before you decide to create a custom formatter, + CPFormatter is intended for subclassing. A custom formatter can restrict the input and enhance the + display of data in novel ways. For example, you could have a custom formatter that ensures that serial + numbers entered by a user conform to predefined formats. Before you decide to create a custom formatter, make sure that you cannot configure the public subclasses CPDateFormatter and CPNumberFormatter to satisfy your requirements. */ @@ -40,10 +40,10 @@ /*! The default implementation of this method raises an exception. - When implementing a subclass, return the CPString object that textually represents - the view's object for display and if editingStringForObjectValue: is unimplemented for editing. - First test the passed-in object to see if it's of the correct class. If it isn't, return nil; - but if it is of the right class, return a properly formatted and, if necessary, localized string. + When implementing a subclass, return the CPString object that textually represents + the view's object for display and if editingStringForObjectValue: is unimplemented for editing. + First test the passed-in object to see if it's of the correct class. If it isn't, return nil; + but if it is of the right class, return a properly formatted and, if necessary, localized string. (See the specification of the CPString class for formatting and localizing details.) @param anObject The object for which a textual representation is returned @@ -65,9 +65,9 @@ /*! The default implementation of this method invokes stringForObjectValue:. - When implementing a subclass, override this method only when the string that users see and the string - that they edit are different. In your implementation, return an CPString object that is used for editing, - following the logic recommended for implementing stringForObjectValue:. As an example, you would implement + When implementing a subclass, override this method only when the string that users see and the string + that they edit are different. In your implementation, return an CPString object that is used for editing, + following the logic recommended for implementing stringForObjectValue:. As an example, you would implement this method if you want the dollar signs in displayed strings removed for editing. @param anObject the object for which to return an editing string @@ -82,11 +82,11 @@ /*! The default implementation of this method raises an exception. - When implementing a subclass, return by reference the object anObject after creating it from string. - Return YES if the conversion is successful. If you return NO, also return by indirection (in error) - a localized user-presentable CPString object that explains the reason why the conversion failed; the delegate - (if any) of the CPControl object managing the cell can then respond to the failure in - control:didFailToFormatString:errorDescription:. However, if error is nil, the sender is not interested in + When implementing a subclass, return by reference the object anObject after creating it from string. + Return YES if the conversion is successful. If you return NO, also return by indirection (in error) + a localized user-presentable CPString object that explains the reason why the conversion failed; the delegate + (if any) of the CPControl object managing the cell can then respond to the failure in + control:didFailToFormatString:errorDescription:. However, if error is nil, the sender is not interested in the error description, and you should not attempt to assign one. @param anObject if conversion is successful, upon return contains the object created from the string @@ -104,18 +104,18 @@ /*! Returns a Boolean value that indicates whether a partial string is valid. - This method is invoked each time the user presses a key while the cell has the keyboard focus it lets you verify and + This method is invoked each time the user presses a key while the cell has the keyboard focus it lets you verify and edit the cell text as the user types it. - In a subclass implementation, evaluate partialString according to the context, edit the text if necessary, and return - by reference any edited string in newString. Return YES if partialString is acceptable and NO if partialString is unacceptable. - If you return NO and newString is nil, the cell displays partialString minus the last character typed. If you return NO, you can - also return by indirection an CPString object (in error) that explains the reason why the validation failed; the delegate (if any) - of the CPControl object managing the cell can then respond to the failure in control:didFailToValidatePartialString:errorDescription:. + In a subclass implementation, evaluate partialString according to the context, edit the text if necessary, and return + by reference any edited string in newString. Return YES if partialString is acceptable and NO if partialString is unacceptable. + If you return NO and newString is nil, the cell displays partialString minus the last character typed. If you return NO, you can + also return by indirection an CPString object (in error) that explains the reason why the validation failed; the delegate (if any) + of the CPControl object managing the cell can then respond to the failure in control:didFailToValidatePartialString:errorDescription:. The selection range will always be set to the end of the text if replacement occurs. - This method is a compatibility method. If a subclass overrides this method and does not override - isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:, this method will be called as before + This method is a compatibility method. If a subclass overrides this method and does not override + isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription:, this method will be called as before (isPartialStringValid:proposedSelectedRange:originalString:originalSelectedRange:errorDescription: just calls this one by default). @param aPartialString the text currently in the view. @@ -130,20 +130,20 @@ } /*! - This method should be implemented in subclasses that want to validate user changes to a string in a field, where the user changes are - not necessarily at the end of the string, and preserve the selection (or set a different one, such as selecting the erroneous part of + This method should be implemented in subclasses that want to validate user changes to a string in a field, where the user changes are + not necessarily at the end of the string, and preserve the selection (or set a different one, such as selecting the erroneous part of the string the user has typed). - In a subclass implementation, evaluate partialString according to the context. Return YES if partialStringPtr is acceptable and NO if partialStringPtr - is unacceptable. Assign a new string to partialStringPtr and a new range to proposedSelRangePtr and return NO if you want to replace the string and - change the selection range. If you return NO, you can also return by indirection an CPString object (in error) that explains the reason why the - validation failed; the delegate (if any) of the CPControl object managing the cell can then respond to the failure in + In a subclass implementation, evaluate partialString according to the context. Return YES if partialStringPtr is acceptable and NO if partialStringPtr + is unacceptable. Assign a new string to partialStringPtr and a new range to proposedSelRangePtr and return NO if you want to replace the string and + change the selection range. If you return NO, you can also return by indirection an CPString object (in error) that explains the reason why the + validation failed; the delegate (if any) of the CPControl object managing the cell can then respond to the failure in control:didFailToValidatePartialString:errorDescription:. @param aPartialString The new string to validate. @param aProposedSelectedRange The selection range that will be used if the string is accepted or replaced. @param originalString The original string, before the proposed change. - @param originalSelectedRange The selection range over which the change is to take place. + @param originalSelectedRange The selection range over which the change is to take place. @param error If non-nil, if validation fails contains an CPString object that descibes the problem. @return YES if aPartialString is acceptable, otherwise NO. @@ -161,7 +161,7 @@ - (void)encodeWithCoder:(CPCoder)aCoder { - + } @end diff --git a/Foundation/CPJSONPConnection.j b/Foundation/CPJSONPConnection.j index c95a362c5..f69a5c954 100644 --- a/Foundation/CPJSONPConnection.j +++ b/Foundation/CPJSONPConnection.j @@ -134,7 +134,7 @@ CPJSONPCallbackReplacementString = @"${JSONP_CALLBACK}"; { var head = document.getElementsByTagName("head").item(0); - if(_scriptTag && _scriptTag.parentNode == head) + if (_scriptTag && _scriptTag.parentNode == head) head.removeChild(_scriptTag); CPJSONPConnectionCallbacks["callback" + [self UID]] = nil;