summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMinh Nguyễn <mxn@1ec5.org>2018-03-29 04:21:59 -0700
committerMinh Nguyễn <mxn@1ec5.org>2018-03-29 04:21:59 -0700
commit9c70d383bf0d12eafeb17ed02341a33f45902a3b (patch)
treef35412f9339c09763b9b16c9795255a1ba6b8987
parent72499daf39b6baea8c5fa48b768bf46f35e2b6e3 (diff)
downloadqtlocation-mapboxgl-9c70d383bf0d12eafeb17ed02341a33f45902a3b.tar.gz
[ios, macos] Restored OEM conditionals where available
This is the preferred syntax for simple conditionals on iOS 9 and above, because you can inline the predicate instead of wrapping it in a constant value expression, which means you can write a conditional in a single format string.
-rw-r--r--platform/darwin/docs/guides/For Style Authors.md.ejs2
-rw-r--r--platform/darwin/docs/guides/Predicates and Expressions.md3
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.mm6
-rw-r--r--platform/darwin/test/MGLExpressionTests.mm58
4 files changed, 66 insertions, 3 deletions
diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs
index 8dd5d53ebf..45cfa105b8 100644
--- a/platform/darwin/docs/guides/For Style Authors.md.ejs
+++ b/platform/darwin/docs/guides/For Style Authors.md.ejs
@@ -354,7 +354,7 @@ In style specification | Method, function, or predicate type | Format string syn
`>=` | `NSGreaterThanOrEqualToPredicateOperatorType` | `key >= value`
`all` | `NSAndPredicateType` | `p0 AND … AND pn`
`any` | `NSOrPredicateType` | `p0 OR … OR pn`
-`case` | `MGL_IF` | `MGL_IF(1 = 2, YES, 2 = 2, YES, NO)`
+`case` | `+[NSExpression expressionForConditional:trueExpression:falseExpression:]` or `MGL_IF` | `TERNARY(1 = 2, YES, NO)` or `MGL_IF(1 = 2, YES, 2 = 2, YES, NO)`
`coalesce` | `mgl_coalesce:` | `mgl_coalesce({x, y, z})`
`match` | `MGL_MATCH` | `MGL_MATCH(x, 0, 'zero match', 1, 'one match', 'two match', 'default')`
`interpolate` | `mgl_interpolate:withCurveType:parameters:stops:` |
diff --git a/platform/darwin/docs/guides/Predicates and Expressions.md b/platform/darwin/docs/guides/Predicates and Expressions.md
index 53fe40e3aa..4abdcff492 100644
--- a/platform/darwin/docs/guides/Predicates and Expressions.md
+++ b/platform/darwin/docs/guides/Predicates and Expressions.md
@@ -199,8 +199,7 @@ Initializer parameter | Format string syntax | Description
`mgl_coalesce:` | `mgl_coalesce({x, y, z})` | Returns the first non-`nil` value from an array of expressions.
`MGL_LET` | `MGL_LET('age', uppercase('old'), 'name', uppercase('MacDonald'), mgl_join({$age, $name}))` | Any number of variable names interspersed with their assigned `NSExpression` values, followed by an `NSExpression` that may contain references to those variables. Compared to the `mgl_expressionWithContext:` custom function, this function takes the variable names and values inline before the expression that contains references to those variables.
`MGL_MATCH` | `MGL_MATCH(x, 0, 'zero match', 1, 'one match', 'two match', 'default')` | Evaluates the first expression and returns the value that matches the initial condition. After the first expression condition a pair of matching/return value should be added and a default value.
-`MGL_IF` | `MGL_IF(1 = 2, YES, 2 = 2, YES, NO)` | Returns the first value that meets the condition otherwise a default value. The expression conditions should be added in pairs of conditional/return value.
-`mgl_hasProperty:properties:` | `mgl_hasProperty:properties:('x', {'x': 'value'})` | Evaluates the expression and returns true if the properties contains the passed property.
+`MGL_IF` | `MGL_IF(1 = 2, YES, 2 = 2, YES, NO)` | Returns the first value that meets the condition otherwise a default value. The expression conditions should be added in pairs of conditional/return value. Unlike `+[NSExpression expressionForConditional:trueExpression:falseExpression:]` or the `TERNARY()` syntax, this function can accept multiple “if else” conditions and is supported on iOS 8._x_ and macOS 10.10._x_; however, each conditional passed into this function must be wrapped in a constant expression.
The following custom functions are also available with the
`+[NSExpression expressionForFunction:selectorName:arguments:]` method or the
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm
index 765d1e9385..7fe8ce3c91 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.mm
+++ b/platform/darwin/src/NSExpression+MGLAdditions.mm
@@ -665,6 +665,12 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
}
}
+ if (@available(iOS 9.0, *)) {
+ if (arguments.count == 3) {
+ NSPredicate *conditional = [NSPredicate mgl_predicateWithJSONObject:argumentObjects.firstObject];
+ return [NSExpression expressionForConditional:conditional trueExpression:arguments[1] falseExpression:arguments[2]];
+ }
+ }
return [NSExpression expressionForFunction:@"MGL_IF" arguments:arguments];
} else if ([op isEqualToString:@"match"]) {
NSMutableArray *optionsArray = [NSMutableArray array];
diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm
index 63c8e5d2f1..bcc708e51e 100644
--- a/platform/darwin/test/MGLExpressionTests.mm
+++ b/platform/darwin/test/MGLExpressionTests.mm
@@ -671,6 +671,31 @@ using namespace std::string_literals;
}
- (void)testConditionalExpressionObject {
+ // This test crashes on iOS 8, which doesn't have `+[NSExpression expressionForConditional:trueExpression:falseExpression:]`.
+ // https://github.com/mapbox/mapbox-gl-native/issues/11007
+ if (@available(iOS 9.0, *)) {
+ {
+ NSPredicate *conditional = [NSPredicate predicateWithFormat:@"1 = 2"];
+ NSExpression *trueExpression = [NSExpression expressionForConstantValue:@YES];
+ NSExpression *falseExpression = [NSExpression expressionForConstantValue:@NO];
+ NSExpression *expression = [NSExpression expressionForConditional:conditional trueExpression:trueExpression falseExpression:falseExpression];
+ NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"TERNARY(1 = 2, TRUE, FALSE)"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
+ XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"];
+ NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
+ expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, TRUE, %@, TRUE, FALSE)",
+ MGLConstantExpression([NSPredicate predicateWithFormat:@"0 = 1"]),
+ MGLConstantExpression([NSPredicate predicateWithFormat:@"1 = 2"])];
+ XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);
+ }
+ }
{
NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, %@, %@)",
[NSExpression expressionWithFormat:@"%@", [NSPredicate predicateWithFormat:@"1 = 2"]],
@@ -680,6 +705,9 @@ using namespace std::string_literals;
NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
+ if (@available(iOS 9.0, *)) {
+ expression = [NSExpression expressionWithFormat:@"TERNARY(1 = 2, YES, NO)"];
+ }
XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
}
@@ -745,6 +773,36 @@ using namespace std::string_literals;
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);
}
+ {
+ NSExpression *expression;
+ if (@available(iOS 9.0, *)) {
+ expression = [NSExpression expressionWithFormat:@"TERNARY(key != nil, 1, 0)"];
+ } else {
+ expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, 1, 0)",
+ MGLConstantExpression([NSPredicate predicateWithFormat:@"key != nil"])];
+ }
+ NSArray *jsonExpression = @[@"case", @[@"!=", @[@"get", @"key"], [NSNull null]], @1, @0];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression], expression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:@{} context:nil], @NO);
+ XCTAssertEqualObjects([expression expressionValueWithObject:@{@"key": @"🗝"} context:nil], @YES);
+ }
+ {
+ NSDictionary *dictionary = @{@"key": @"🔑"};
+ NSExpression *expression;
+ if (@available(iOS 9.0, *)) {
+ expression = [NSExpression expressionWithFormat:@"TERNARY(%@.key != nil, 1, 0)", dictionary];
+ } else {
+ NSPredicate *conditional = [NSPredicate predicateWithFormat:@"%@.key != nil", dictionary];
+ expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, 1, 0)",
+ MGLConstantExpression(conditional)];
+ }
+ NSArray *jsonExpression = @[@"case", @[@"!=", @[@"get", @"key", @[@"literal", dictionary]], [NSNull null]], @1, @0];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ // The dictionary isn’t equal enough.
+ XCTAssertEqualObjects([NSExpression mgl_expressionWithJSONObject:jsonExpression].description, expression.description);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @YES);
+ }
}
- (void)testGenericExpressionObject {