diff --git a/Foundation/CPArray+KVO.j b/Foundation/CPArray+KVO.j
index 39ae6291d..ecd3d2a26 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
@@ -430,7 +430,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)
@@ -525,7 +525,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"];
diff --git a/Foundation/CPArray.j b/Foundation/CPArray.j
index e912d1d27..0a7250c6d 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;
@@ -1071,7 +1071,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;
@@ -1296,7 +1296,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)
@@ -1304,10 +1304,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];
@@ -1320,7 +1320,7 @@ CPEnumerationReverse = 1 << 1;
j++;
}
}
-
+
while (k < j)
self[k++] = B[i++];
}
@@ -1345,14 +1345,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;
diff --git a/Foundation/CPPredicate/CPComparisonPredicate.j b/Foundation/CPPredicate/CPComparisonPredicate.j
index 8f5a9726b..5ccd47b97 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.
@@ -136,8 +135,8 @@ CPContainsPredicateOperatorType = 99;
*/
CPBetweenPredicateOperatorType = 100;
-var CPComparisonPredicateModifier;
-var CPPredicateOperatorType;
+var CPComparisonPredicateModifier,
+ CPPredicateOperatorType;
/*!
@ingroup foundation
@@ -426,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]);
@@ -441,43 +440,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 +462,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;
}
@@ -572,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.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..4414afffe 100644
--- a/Foundation/CPPredicate/CPExpression_aggregate.j
+++ b/Foundation/CPPredicate/CPExpression_aggregate.j
@@ -15,30 +15,14 @@
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)
return YES;
-
+
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object collection] isEqual:[self collection]])
return NO;
-
+
return YES;
}
@@ -47,32 +31,16 @@
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],
collection = [_aggregate objectEnumerator],
exp;
-
+
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;
@@ -81,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;
}
@@ -97,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]];
@@ -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..4cd38fd99 100644
--- a/Foundation/CPPredicate/CPExpression_constant.j
+++ b/Foundation/CPPredicate/CPExpression_constant.j
@@ -11,30 +11,18 @@
{
[super initWithExpressionType:CPConstantValueExpressionType];
_value = value;
-
+
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)
return YES;
-
+
if (object.isa != self.isa || [object expressionType] != [self expressionType] || ![[object constantValue] isEqual:[self constantValue]])
return NO;
-
+
return YES;
}
@@ -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..02209a495 100644
--- a/Foundation/CPPredicate/CPExpression_function.j
+++ b/Foundation/CPPredicate/CPExpression_function.j
@@ -12,59 +12,38 @@
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;
+ [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.
+ _selector = aSelector;
_operand = targetExpression;
_arguments = parameters;
_argc = [parameters count];
-
+
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)
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;
}
@@ -90,284 +69,193 @@
- (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 arg = [_arguments[i] expressionValueWithObject:object context:context];
+ objj_args.push(arg);
}
- var target = (_operand == nil) ? self : [_operand expressionValueWithObject:object context:context];
- return [target performSelector:_selector withObject:eval_args];
+ return objj_msgSend.apply(this, objj_args);
}
- (CPString)description
-{
- var result = [CPString stringWithFormat:@"%@ %s(", [_operand description], [self _function]],
- i;
-
- for (i = 0; i < _argc; i++)
- result = result + [_arguments objectAtIndex:i] + (i+1<_argc) ? ", " : "";
-
+{
+ var result = _operand + [self _function] + "(";
+
+ 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],
i;
-
+
for (i = 0; i < _argc; i++)
[array addObject:[[_arguments objectAtIndex:i] _expressionWithSubstitutionVariables:variables]];
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 i,
- sum = 0.0;
-
- for (i = 0; i < _argc; i++)
- sum += [[parameters objectAtIndex:i] doubleValue];
-
- return [CPNumber numberWithDouble: sum];
+ var target = [coder decodeObjectForKey:CPOperandKey],
+ selector = CPSelectorFromString([coder decodeObjectForKey:CPSelectorNameKey]),
+ arguments = [coder decodeObjectForKey:CPArgumentsKey];
+
+ 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"];
-
- return MAX([parameters objectAtIndex:0],[parameters objectAtIndex:1]);
+ var sum = 0,
+ count = parameters.length;
+
+ 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..f5302a20c 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..38f5a542f
--- /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 ff5f5f092..2041e7e71 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,15 +248,15 @@ function(newValue)\
return self;
}
-- (id) nextArg
+- (id)nextArg
{
return [_args nextObject];
}
- (BOOL)scanPredicateKeyword:(CPString)key
{
- var loc = [self scanLocation];
- var c;
+ var loc = [self scanLocation],
+ c;
[self setCaseSensitive:NO];
if (![self scanString:key intoString:NULL])
@@ -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,
@@ -548,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])
{
@@ -578,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"])
@@ -676,33 +642,36 @@ function(newValue)\
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];
@@ -713,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];
@@ -759,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)
@@ -791,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
{
@@ -817,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
{
@@ -837,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
{
@@ -862,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
{
@@ -903,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/Objective-J/sprintf.js b/Objective-J/sprintf.js
index d5df1b2a5..9ad4723a5 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 === null || argIndex === "")
+ 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/Foundation/CPPredicateTest.j b/Tests/Foundation/CPPredicateTest.j
index 242ac8efc..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,12 +233,56 @@
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"];
+ 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 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"];
+
+ 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
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