diff options
author | Minh Nguyễn <mxn@1ec5.org> | 2018-03-29 04:21:59 -0700 |
---|---|---|
committer | Minh Nguyễn <mxn@1ec5.org> | 2018-03-29 04:21:59 -0700 |
commit | 9c70d383bf0d12eafeb17ed02341a33f45902a3b (patch) | |
tree | f35412f9339c09763b9b16c9795255a1ba6b8987 | |
parent | 72499daf39b6baea8c5fa48b768bf46f35e2b6e3 (diff) | |
download | qtlocation-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.
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 { |