Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify adding requirements #51

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,26 +44,16 @@ - (void)checkAppVersion
NSURL *princeOfVersionsURL = [NSURL URLWithString:Constant.princeOfVersionsURL];

PoVRequestOptions *options = [PoVRequestOptions new];
[options addRequirementWithKey:@"region" requirementCheck:^BOOL (id value) {

// Check OS localisation

if (![value isKindOfClass:[NSString class]]) {
return NO;
}

return [(NSString *)value isEqualToString:@"hr"];
[options addRequirementWithKey:@"region"
ofType:[NSString class]
requirementCheck:^BOOL(NSString *value) {
return [value isEqualToString:@"hr"];
}];

[options addRequirementWithKey:@"bluetooth" requirementCheck:^BOOL (id value) {

// Check device bluetooth version

if (![value isKindOfClass:[NSString class]]) {
return NO;
}

return [(NSString *)value hasPrefix:@"5"];
[options addRequirementWithKey:@"bluetooth"
ofType:[NSString class]
requirementCheck:^BOOL(NSString *value) {
return [value hasPrefix:@"5"];
}];

__weak __typeof(self) weakSelf = self;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,10 @@ private extension ConfigurationController {

let options = PoVRequestOptions()

options.addRequirement(key: "region") { (value) -> Bool in
guard let value = value as? String else { return false }
// Check OS localisation
return value == "hr"
}
options.addRequirement(key: "region", ofType: String.self) { $0.starts(with: "hr") }

options.addRequirement(key: "bluetooth", ofType: String.self) { $0.starts(with: "5") }

options.addRequirement(key: "bluetooth") { (value) -> Bool in
guard let value = value as? String else { return false }
// Check device bluetooth version
return value.starts(with: "5")
}

let princeOfVersionsURL = URL(string: Constants.princeOfVersionsURL)!

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,26 +45,18 @@ - (void)checkAppVersion
NSURL *princeOfVersionsURL = [NSURL URLWithString:Constant.princeOfVersionsURL];

PoVRequestOptions *options = [PoVRequestOptions new];
[options addRequirementWithKey:@"region" requirementCheck:^BOOL (id value) {

[options addRequirementWithKey:@"region"
ofType:[NSString class]
requirementCheck:^BOOL(NSString *value) {
// Check OS localisation

if (![value isKindOfClass:[NSString class]]) {
return NO;
}

return [(NSString *)value isEqualToString:@"hr"];
return [value isEqualToString:@"hr"];
}];

[options addRequirementWithKey:@"bluetooth" requirementCheck:^BOOL (id value) {

[options addRequirementWithKey:@"bluetooth"
ofType:[NSString class]
requirementCheck:^BOOL(NSString *value) {
// Check device bluetooth version

if (![value isKindOfClass:[NSString class]]) {
return NO;
}

return [(NSString *)value hasPrefix:@"5"];
return [value hasPrefix:@"5"];
}];

__weak __typeof(self) weakSelf = self;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,8 @@ private extension ConfigurationViewController {

let options = PoVRequestOptions()

options.addRequirement(key: "region") { (value) -> Bool in
guard let value = value as? String else { return false }
// Check OS localisation
return value == "hr"
}

options.addRequirement(key: "bluetooth") { (value) -> Bool in
guard let value = value as? String else { return false }
// Check device bluetooth version
return value.starts(with: "5")
}
options.addRequirement(key: "region", ofType: String.self) { $0.starts(with: "hr") }
options.addRequirement(key: "bluetooth", ofType: String.self) { $0.starts(with: "5") }

let princeOfVersionsURL = URL(string: Constants.princeOfVersionsURL)!

Expand Down
14 changes: 3 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,17 +118,9 @@ Here is the example of how to add requirement check closures.
```swift
let options = PoVRequestOptions()

options.addRequirement(key: "region") { (value) -> Bool in
guard let value = value as? String else { return false }
// Check OS localisation
return value == "hr"
}

options.addRequirement(key: "bluetooth") { (value) -> Bool in
guard let value = value as? String else { return false }
// Check device bluetooth version
return value.starts(with: "5")
}
options.addRequirement(key: "region", ofType: String.self) { $0.starts(with: "hr") }

options.addRequirement(key: "bluetooth", ofType: String.self) { $0.starts(with: "5") }

let princeOfVersionsURL = URL(string: "https://pastebin.com/raw/0MfYmWGu")!

Expand Down
32 changes: 28 additions & 4 deletions Sources/PrinceOfVersions/PoVDataTypes/PoVRequestOptions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,40 @@ public class PoVRequestOptions: NSObject {
// MARK: - Public methods

/**
Adds requirement check for configuration.
Adds requirement check for configuration.

Use this method to add custom requirement by which configuration must comply with.

- parameter key: String that matches key in requirements array in JSON with `requirementsCheck` parameter,
- parameter requirementCheck: A block used to check if a configuration meets requirement. This block returns `true` if configuration meets the requirement, and takes the any value as input parameter by which .
- parameter type: The expected type of the value.
- parameter requirementCheck: A block used to check if a configuration meets the requirement. This block returns `true` if the configuration meets the requirement, and takes the typed value as input.

*/
public func addRequirement(key: String, requirementCheck: @escaping ((Any) -> Bool)) {
userRequirements.updateValue(requirementCheck, forKey: key)
public func addRequirement<T>(key: String, ofType type: T.Type, requirementCheck: @escaping (T) -> Bool) {
userRequirements.updateValue({ value in
guard let typedValue = value as? T else { return false }
return requirementCheck(typedValue)
}, forKey: key)
}

/**
Adds requirement check for configuration (Objective-C compatible).

Use this method to add a custom requirement by which configuration must comply with.

- parameter key: String that matches the key in the requirements array in JSON with the `requirementCheck` parameter.
- parameter type: The expected class of the value (e.g., `NSString.class`).
- parameter requirementCheck: A block used to check if a configuration meets the requirement. This block returns `true` if the configuration meets the requirement, and takes the value as input.

This method is designed for Objective-C compatibility and uses runtime type checking (`isKindOfClass:`) to validate the value.
*/
@available(swift, obsoleted: 1.0, message: "Use the generic addRequirement(key:ofType:requirementCheck:) method in Swift.")
@objc(addRequirementWithKey:ofType:requirementCheck:)
public func addRequirementWithKey(key: String, ofType type: AnyClass, requirementCheck: @escaping (Any) -> Bool) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we also add unavailable for swift flag, the last time I did it, i think it was adding __ to the function name, but there might be be a better option now.

userRequirements.updateValue({ value in
guard let value = value as? NSObject, value.isKind(of: type) else { return false }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of returning false if the type does not match, maybe we could throw an error? That way, the user would know something went wrong instead of just getting a false negative response. What do you think about that approach?

return requirementCheck(value)
}, forKey: key)
}

}