Compare commits
57 Commits
fixes-945
...
fix-NSErro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46451dde7d | ||
|
|
ef9b9ee63d | ||
|
|
59997dd6d9 | ||
|
|
6c954ab704 | ||
|
|
aea48ea185 | ||
|
|
f6b15b7626 | ||
|
|
817ea8c3f4 | ||
|
|
953665d28b | ||
|
|
f9cc0d67dc | ||
|
|
f95e7b2614 | ||
|
|
f14f16cc26 | ||
|
|
80053b1db5 | ||
|
|
34f74c1b8f | ||
|
|
87a0b0e30b | ||
|
|
98e3f1cd28 | ||
|
|
8fd461350f | ||
|
|
6652ad3d07 | ||
|
|
9ea7d3daed | ||
|
|
bf293b7395 | ||
|
|
15a73f95cd | ||
|
|
35379bb8a0 | ||
|
|
5fb0714f47 | ||
|
|
10c9e75f81 | ||
|
|
f8a593a320 | ||
|
|
8b97eb2599 | ||
|
|
586da3519a | ||
|
|
5e2e7e3a75 | ||
|
|
8fbf6985b4 | ||
|
|
e135aab767 | ||
|
|
c864814c1d | ||
|
|
e36de47eac | ||
|
|
f7e53175f2 | ||
|
|
10a10ed8bd | ||
|
|
08fb076071 | ||
|
|
4d8d1287d2 | ||
|
|
2136f01c21 | ||
|
|
2305c38634 | ||
|
|
b8c2dff1a7 | ||
|
|
346dd2c98d | ||
|
|
bee0497eb9 | ||
|
|
93a098f33b | ||
|
|
8818af27ba | ||
|
|
951993371a | ||
|
|
8e5f5d0945 | ||
|
|
c394b5231e | ||
|
|
2fdb8c64a8 | ||
|
|
6303e93089 | ||
|
|
9cd56c237d | ||
|
|
ee961e1f59 | ||
|
|
0452552590 | ||
|
|
fbe6decc6e | ||
|
|
a2cc02d3ac | ||
|
|
cfea84ff08 | ||
|
|
7d3028e0ee | ||
|
|
9f9f1f9e89 | ||
|
|
bed5229ba7 | ||
|
|
1c296a8637 |
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
tidelift: "cocoapods/PromiseKit"
|
||||
patreon: "mxcl"
|
||||
2
.github/PromiseKit.podspec
vendored
2
.github/PromiseKit.podspec
vendored
@ -19,7 +19,7 @@ Pod::Spec.new do |s|
|
||||
s.default_subspecs = 'CorePromise', 'UIKit', 'Foundation'
|
||||
s.requires_arc = true
|
||||
|
||||
s.swift_versions = ['3.1', '3.2', '3.3', '3.4', '4.0', '4.1', '4.2', '4.3', '4.4', '5.0']
|
||||
s.swift_versions = ['3.1', '3.2', '3.3', '3.4', '4.0', '4.1', '4.2', '4.3', '4.4', '5.0', '5.1']
|
||||
|
||||
# CocoaPods requires us to specify the root deployment targets
|
||||
# even though for us it is nonsense. Our root spec has no
|
||||
|
||||
1
.tidelift.yml
Normal file
1
.tidelift.yml
Normal file
@ -0,0 +1 @@
|
||||
extra_ignore_directories: [ Tests ]
|
||||
32
.travis.yml
32
.travis.yml
@ -1,5 +1,5 @@
|
||||
os: osx
|
||||
osx_image: xcode10.2
|
||||
osx_image: xcode10.3
|
||||
language: swift
|
||||
|
||||
branches:
|
||||
@ -32,7 +32,9 @@ jobs:
|
||||
- &carthage
|
||||
stage: carthage
|
||||
osx_image: xcode9
|
||||
before_script: sed -i '' "s/SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;/SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;/" *.xcodeproj/project.pbxproj
|
||||
before_script: |
|
||||
sed -i '' "s/SWIFT_TREAT_WARNINGS_AS_ERRORS = NO;/SWIFT_TREAT_WARNINGS_AS_ERRORS = YES;/" *.xcodeproj/project.pbxproj
|
||||
sed -i '' "s/GCC_TREAT_WARNINGS_AS_ERRORS = NO;/GCC_TREAT_WARNINGS_AS_ERRORS = YES;/" *.xcodeproj/project.pbxproj
|
||||
script: carthage build --no-skip-current --configuration Release
|
||||
name: Swift 4.0.0 / Xcode 9.0
|
||||
- <<: *carthage
|
||||
@ -51,8 +53,11 @@ jobs:
|
||||
osx_image: xcode10.1
|
||||
name: Swift 4.1.50 / Xcode 10.1
|
||||
- <<: *carthage
|
||||
osx_image: xcode10.2
|
||||
name: Swift 4.1.51 / Xcode 10.2
|
||||
osx_image: xcode10.3
|
||||
name: Swift 4.1.51 / Xcode 10.3
|
||||
- <<: *carthage
|
||||
osx_image: xcode11
|
||||
name: Swift 4.1.52 / Xcode 11
|
||||
|
||||
- &pod
|
||||
stage: lint
|
||||
@ -60,7 +65,7 @@ jobs:
|
||||
env: SWIFT=3.1
|
||||
cache: cocoapods
|
||||
before_install: mv .github/PromiseKit.podspec .
|
||||
install: gem install cocoapods --pre -v 1.7.0.beta.3
|
||||
install: gem install cocoapods -v '~> 1.7.0'
|
||||
script: pod lib lint --subspec=PromiseKit/CorePromise --fail-fast --swift-version=$SWIFT
|
||||
- <<: *pod
|
||||
osx_image: xcode9.2
|
||||
@ -81,11 +86,14 @@ jobs:
|
||||
osx_image: xcode10.1
|
||||
env: SWIFT=4.2
|
||||
- <<: *pod
|
||||
osx_image: xcode10.2
|
||||
osx_image: xcode10.3
|
||||
env: SWIFT=4.3
|
||||
- <<: *pod
|
||||
osx_image: xcode10.2
|
||||
osx_image: xcode10.3
|
||||
env: SWIFT=5.0
|
||||
- <<: *pod
|
||||
osx_image: xcode11
|
||||
env: SWIFT=5.1
|
||||
|
||||
- &linux
|
||||
stage: swiftpm
|
||||
@ -124,6 +132,9 @@ jobs:
|
||||
env: SWIFT_BUILD_VERSION=5 SWIFT_VERSION=5.0
|
||||
name: 'Linux / Swift 5.0 / +Tests'
|
||||
script: swift test -Xswiftc -swift-version -Xswiftc $SWIFT_BUILD_VERSION
|
||||
- <<: *linux
|
||||
env: SWIFT_BUILD_VERSION=5 SWIFT_VERSION=5.1
|
||||
name: Linux / Swift 5.1
|
||||
|
||||
- &test
|
||||
stage: test
|
||||
@ -161,12 +172,15 @@ jobs:
|
||||
osx_image: xcode10.1
|
||||
name: 'macOS / swift-tools-version: 4.2 / Swift 4.2.1'
|
||||
- <<: *swiftpm
|
||||
osx_image: xcode10.2
|
||||
osx_image: xcode10.3
|
||||
name: 'macOS / swift-tools-version: 5.0 / Swift 5.0.0'
|
||||
- <<: *swiftpm
|
||||
osx_image: xcode11
|
||||
name: 'macOS / swift-tools-version: 5.0 / Swift 5.1.0'
|
||||
|
||||
- name: '`pod trunk push`'
|
||||
stage: deploy
|
||||
install: gem install cocoapods --pre -v 1.7.0.beta.3
|
||||
install: gem install cocoapods -v '~> 1.7.0'
|
||||
before_script: |
|
||||
mv .github/PromiseKit.podspec .
|
||||
sed -i '' "s/s.version = '0.0.1'/s.version = '$TRAVIS_TAG'/g" PromiseKit.podspec
|
||||
|
||||
@ -173,7 +173,7 @@ When you have a series of tasks to perform on an array of data:
|
||||
```swift
|
||||
// fade all visible table cells one by one in a “cascading” effect
|
||||
|
||||
let fade = Guarantee()
|
||||
var fade = Guarantee()
|
||||
for cell in tableView.visibleCells {
|
||||
fade = fade.then {
|
||||
UIView.animate(.promise, duration: 0.1) {
|
||||
@ -186,12 +186,14 @@ fade.done {
|
||||
}
|
||||
```
|
||||
|
||||
Or if you have an array of promises:
|
||||
Or if you have an array of closures that return promises:
|
||||
|
||||
```swift
|
||||
var foo = Promise()
|
||||
for nextPromise in arrayOfPromises {
|
||||
foo = foo.then { nextPromise }
|
||||
for nextPromise in arrayOfClosuresThatReturnPromises {
|
||||
foo = foo.then(nextPromise)
|
||||
// ^^ you rarely would want an array of promises instead, since then
|
||||
// they have all already started, you may as well use `when()`
|
||||
}
|
||||
foo.done {
|
||||
// finish
|
||||
|
||||
@ -256,25 +256,35 @@ You want `recover`.
|
||||
## When do promises “start”?
|
||||
|
||||
Often people are confused about when Promises “start”. Is it immediately? Is it
|
||||
later? Is it when you call then?
|
||||
|
||||
The answer is: promises do not choose when the underlying task they represent
|
||||
starts. That is up to that task. For example here is the code for a simple
|
||||
promise that wraps Alamofire:
|
||||
later? Is it when you call `then`?
|
||||
|
||||
The answer is: The promise **body** executes during initialization of the promise, on the current thread.
|
||||
As an example, `"Executing the promise body"` will be printed to the console right after the promise is created,
|
||||
without having to call `then` on the promise.
|
||||
|
||||
```swift
|
||||
func foo() -> Promise<Any>
|
||||
return Promise { seal in
|
||||
Alamofire.request(rq).responseJSON { rsp in
|
||||
seal.resolve(rsp.value, rsp.error)
|
||||
}
|
||||
let testPromise = Promise<Bool> {
|
||||
print("Executing the promise body.")
|
||||
return $0.fulfill(true)
|
||||
}
|
||||
```
|
||||
|
||||
But what about asynchronous tasks that you create in your promise's body? They behave the same way as they would
|
||||
without using PromiseKit. Here's a simple example:
|
||||
|
||||
```swift
|
||||
let testPromise = Promise<Bool> { seal in
|
||||
print("Executing the promise body.")
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
|
||||
print("Executing asyncAfter.")
|
||||
return seal.fulfill(true)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Who chooses when this promise starts? The answer is: Alamofire does, and in this
|
||||
case, it “starts” immediately when `foo()` is called.
|
||||
The message `"Executing the promise body."` is being logged right away, but the message `"Executing asyncAfter."`
|
||||
is only logged three seconds later. In this case `DispatchQueue` is responsible for deciding when to execute
|
||||
the task you pass to it, PromiseKit has nothing to do with it.
|
||||
|
||||
## What is a good way to use Firebase with PromiseKit
|
||||
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 6e6d184768c0d383e5ca8d7a1ff9710351e17dfd
|
||||
Subproject commit 911b257783efc0aa705481d556c8ecdfcdc055a9
|
||||
@ -1 +1 @@
|
||||
Subproject commit 83ac281446b90a76357085e79616466cfc71a375
|
||||
Subproject commit 6c01f5719ff08bbbf81d42b7e20c5188cab4a81d
|
||||
@ -1 +1 @@
|
||||
Subproject commit 675857283337f0c83dae6e0abeeebfbcbd84f6c5
|
||||
Subproject commit c694fa0628a96951c6e2db113dc4eb6dd4e47ebc
|
||||
@ -1 +1 @@
|
||||
Subproject commit 7c6c6692fec51834128a7a8eb0f6a15bd93bfcf3
|
||||
Subproject commit a41a97d3d3aa6efb575d0f42f3b8aeec5a756ead
|
||||
@ -1 +1 @@
|
||||
Subproject commit 8492e28b521930227523b8a1b00e6f9134a9e6f5
|
||||
Subproject commit e4317d5279db7ecfc5bc565e1dd88fcabc02c352
|
||||
@ -1 +1 @@
|
||||
Subproject commit a14d7a64cccbf777c0e4bd1de212a56c7ccddba6
|
||||
Subproject commit fbc9941219c9bbdfe6d664ca6b8d10b5e2f8fb70
|
||||
@ -1 +1 @@
|
||||
Subproject commit 06514c39bf57e2a96a501948940ddb43f6bdd708
|
||||
Subproject commit 9586f3c06c4934e776c2b96c128f332a168c2c91
|
||||
@ -1 +1 @@
|
||||
Subproject commit f3f3d8525e9ea9fbc19ac269c80413a5454e9a8e
|
||||
Subproject commit c4ea4dba6e0516986b3cb1d93c86f6991ce46861
|
||||
@ -1 +1 @@
|
||||
Subproject commit cf9095526ba0efc0903626ffab3e26c71cc11dec
|
||||
Subproject commit 1f90d67538047087428d82550976c2e43aba0961
|
||||
@ -1 +1 @@
|
||||
Subproject commit e5c5d8471da5b28ad436b3a80fac2aea1f9785eb
|
||||
Subproject commit 1a276e598dac59489ed904887e0740fa75e571e0
|
||||
@ -1 +1 @@
|
||||
Subproject commit b7ad74638b2831b8488f2ccfae2aebe1f7b71f21
|
||||
Subproject commit b185822cb1fcf5297347498b783b4e21b2e55282
|
||||
@ -1 +1 @@
|
||||
Subproject commit 4372659d7704b1d3c395511451e014ee44a12271
|
||||
Subproject commit 668abe78a52a23bd276c8924dba91592ac0ca45a
|
||||
@ -1 +1 @@
|
||||
Subproject commit 4199cb79e9af1f8741250ea53e1fbb5c35432fad
|
||||
Subproject commit d1d4ebdd6ceac78d734e2ae27e8ab429906d6929
|
||||
@ -1 +1 @@
|
||||
Subproject commit ae1a282c3b29bc1115a7089437e2e75f2f74d222
|
||||
Subproject commit 2a93ce737502e13a3eaedc444b9ecb5abb28ec79
|
||||
@ -1 +1 @@
|
||||
Subproject commit a20dddd6a8a36534e123edc251adef5b3de16989
|
||||
Subproject commit 48f801454b01c69a1553873cb1d95e90ae2ec4cc
|
||||
@ -1 +1 @@
|
||||
Subproject commit c034f528da3309fa5f8b3f4a746ab100d6468389
|
||||
Subproject commit b22f187b6b3f82f102aa309b256bf24570a73d1f
|
||||
@ -1 +1 @@
|
||||
Subproject commit 95b086ce353be7258ff5bcf8628cbe06186346fc
|
||||
Subproject commit 378912a47a206183b931d2008e0f396e9fc390e8
|
||||
@ -1 +1 @@
|
||||
Subproject commit 6af1143636fd1f50afe533ead4f7a863d91c11ba
|
||||
Subproject commit e26f6a55921ea671855093754686991b08ef97cc
|
||||
@ -1 +1 @@
|
||||
Subproject commit f39adf82d349e175bddd99b748146d361b856328
|
||||
Subproject commit 6b009f906fc489346a73759b5668b263a320c51c
|
||||
@ -1 +1 @@
|
||||
Subproject commit a7a236cf81e8397aab37780af8d6624ab31fea06
|
||||
Subproject commit baf104ba29ff94d9d41e90e8ec557a56b87fecd4
|
||||
@ -1 +1 @@
|
||||
Subproject commit bdc99552c392c04849f06b77b2afdf0df5cb5a50
|
||||
Subproject commit b5b3fca958a7296f71313b6c172584bc91d6da8b
|
||||
@ -620,36 +620,35 @@
|
||||
6399A3721D595D9100D65233 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
LastUpgradeCheck = 0930;
|
||||
LastUpgradeCheck = 1200;
|
||||
TargetAttributes = {
|
||||
630019011D596292003B4E30 = {
|
||||
LastSwiftMigration = 0920;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
631411321D59795700E24B9E = {
|
||||
LastSwiftMigration = 0920;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
6317518B1D59766500A9DDDC = {
|
||||
LastSwiftMigration = 0920;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
633027E0203CC0060037E136 = {
|
||||
LastSwiftMigration = 0920;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
63B0AC561D595E1B00FA21D9 = {
|
||||
CreatedOnToolsVersion = 8.0;
|
||||
LastSwiftMigration = 0920;
|
||||
LastSwiftMigration = 1100;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
C0244E4E2047A6CB00ACB4AC = {
|
||||
LastSwiftMigration = 0920;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 6399A3751D595D9100D65233 /* Build configuration list for PBXProject "PromiseKit" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
English,
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
@ -816,12 +815,12 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
SWIFT_INSTALL_OBJC_HEADER = NO;
|
||||
TVOS_DEPLOYMENT_TARGET = 10.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 12.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@ -829,12 +828,12 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||
SWIFT_INSTALL_OBJC_HEADER = NO;
|
||||
TVOS_DEPLOYMENT_TARGET = 10.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 12.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
@ -908,6 +907,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@ -925,6 +925,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@ -940,7 +941,6 @@
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
@ -948,7 +948,7 @@
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_DYLIB_INSTALL_NAME = "@rpath";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
@ -959,7 +959,7 @@
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 4.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 12.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
};
|
||||
@ -969,6 +969,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
@ -986,6 +987,7 @@
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
@ -999,7 +1001,6 @@
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
@ -1007,7 +1008,7 @@
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
|
||||
LD_DYLIB_INSTALL_NAME = "@rpath";
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.10;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.promisekit;
|
||||
@ -1016,7 +1017,7 @@
|
||||
SUPPORTED_PLATFORMS = "macosx appletvsimulator appletvos watchsimulator iphonesimulator watchos iphoneos";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
|
||||
SWIFT_VERSION = 4.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 9.0;
|
||||
TVOS_DEPLOYMENT_TARGET = 12.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
WATCHOS_DEPLOYMENT_TARGET = 2.0;
|
||||
};
|
||||
@ -1050,6 +1051,7 @@
|
||||
ENABLE_TESTABILITY = YES;
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
@ -1104,6 +1106,7 @@
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
|
||||
GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0930"
|
||||
LastUpgradeVersion = "1200"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
@ -26,9 +26,9 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
codeCoverageEnabled = "YES"
|
||||
onlyGenerateCoverageForSpecifiedTargets = "YES"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
onlyGenerateCoverageForSpecifiedTargets = "YES">
|
||||
<CodeCoverageTargets>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
@ -90,17 +90,6 @@
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "63B0AC561D595E1B00FA21D9"
|
||||
BuildableName = "PromiseKit.framework"
|
||||
BlueprintName = "PromiseKit"
|
||||
ReferencedContainer = "container:PromiseKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
@ -121,8 +110,6 @@
|
||||
ReferencedContainer = "container:PromiseKit.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
|
||||
@ -188,6 +188,10 @@ became true, but nowadays it isn’t really necessary.
|
||||
Please check our [Troubleshooting Guide](Documentation/Troubleshooting.md), and
|
||||
if after that you still have a question, ask at our [Gitter chat channel] or on [our bug tracker].
|
||||
|
||||
## Security & Vulnerability Reporting or Disclosure
|
||||
|
||||
https://tidelift.com/security
|
||||
|
||||
|
||||
[badge-pod]: https://img.shields.io/cocoapods/v/PromiseKit.svg?label=version
|
||||
[badge-pms]: https://img.shields.io/badge/supports-CocoaPods%20%7C%20Carthage%20%7C%20Accio%20%7C%20SwiftPM-green.svg
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <dispatch/dispatch.h>
|
||||
#import "fwd.h"
|
||||
#import <PromiseKit/fwd.h>
|
||||
|
||||
/// INTERNAL DO NOT USE
|
||||
@class __AnyPromise;
|
||||
@ -71,7 +71,7 @@ typedef void (^PMKResolver)(id __nullable) NS_REFINED_FOR_SWIFT;
|
||||
|
||||
|
||||
/**
|
||||
The provided block is executed when its receiver is resolved.
|
||||
The provided block is executed when its receiver is fulfilled.
|
||||
|
||||
If you provide a block that takes a parameter, the value of the receiver will be passed as that parameter.
|
||||
|
||||
@ -182,6 +182,13 @@ typedef void (^PMKResolver)(id __nullable) NS_REFINED_FOR_SWIFT;
|
||||
*/
|
||||
- (AnyPromise * __nonnull(^ __nonnull)(dispatch_queue_t __nonnull, dispatch_block_t __nonnull))ensureOn NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
Wait until the promise is resolved.
|
||||
|
||||
@return Value if fulfilled or error if rejected.
|
||||
*/
|
||||
- (id __nullable)wait NS_REFINED_FOR_SWIFT;
|
||||
|
||||
/**
|
||||
Create a new promise with an associated resolver.
|
||||
|
||||
|
||||
@ -112,6 +112,10 @@ NSString *const PMKErrorDomain = @"PMKErrorDomain";
|
||||
};
|
||||
}
|
||||
|
||||
- (id)wait {
|
||||
return [d __wait];
|
||||
}
|
||||
|
||||
- (BOOL)pending {
|
||||
return [[d valueForKey:@"__pending"] boolValue];
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import Foundation
|
||||
/**
|
||||
__AnyPromise is an implementation detail.
|
||||
|
||||
Because of how ObjC/Swift compatability work we have to compose our AnyPromise
|
||||
Because of how ObjC/Swift compatibility work we have to compose our AnyPromise
|
||||
with this internal object, however this is still part of the public interface.
|
||||
Sadly. Please don’t use it.
|
||||
*/
|
||||
@ -61,6 +61,26 @@ import Foundation
|
||||
}))
|
||||
}
|
||||
|
||||
@objc public func __wait() -> Any? {
|
||||
if Thread.isMainThread {
|
||||
conf.logHandler(.waitOnMainThread)
|
||||
}
|
||||
|
||||
var result = __value
|
||||
|
||||
if result == nil {
|
||||
let group = DispatchGroup()
|
||||
group.enter()
|
||||
self.__pipe { obj in
|
||||
result = obj
|
||||
group.leave()
|
||||
}
|
||||
group.wait()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/// Internal, do not use! Some behaviors undefined.
|
||||
@objc public func __pipe(_ to: @escaping (Any?) -> Void) {
|
||||
let to = { (obj: Any?) -> Void in
|
||||
|
||||
@ -17,7 +17,7 @@ public struct PMKConfiguration {
|
||||
/// The closure used to log PromiseKit events.
|
||||
/// Not thread safe; change before processing any promises.
|
||||
/// - Note: The default handler calls `print()`
|
||||
public var logHandler: (LogEvent) -> () = { event in
|
||||
public var logHandler: (LogEvent) -> Void = { event in
|
||||
switch event {
|
||||
case .waitOnMainThread:
|
||||
print("PromiseKit: warning: `wait()` called on main thread!")
|
||||
|
||||
@ -83,9 +83,10 @@ extension Error {
|
||||
} catch CocoaError.userCancelled {
|
||||
return true
|
||||
} catch {
|
||||
#if os(macOS) || os(iOS) || os(tvOS)
|
||||
let pair = { ($0.domain, $0.code) }(error as NSError)
|
||||
return ("SKErrorDomain", 2) == pair
|
||||
#if canImport(StoreKit)
|
||||
let domain = (error as AnyObject).value(forKey: "domain") as? String
|
||||
let code = (error as AnyObject).value(forKey: "code") as? Int
|
||||
return ("SKErrorDomain", 2) == (domain, code)
|
||||
#else
|
||||
return false
|
||||
#endif
|
||||
|
||||
@ -105,7 +105,19 @@ public extension Guarantee {
|
||||
return rg
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
func map<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T, U>) -> Guarantee<U> {
|
||||
let rg = Guarantee<U>(.pending)
|
||||
pipe { value in
|
||||
on.async(flags: flags) {
|
||||
rg.box.seal(value[keyPath: keyPath])
|
||||
}
|
||||
}
|
||||
return rg
|
||||
}
|
||||
#endif
|
||||
|
||||
@discardableResult
|
||||
func then<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ body: @escaping(T) -> Guarantee<U>) -> Guarantee<U> {
|
||||
let rg = Guarantee<U>(.pending)
|
||||
pipe { value in
|
||||
@ -144,17 +156,97 @@ public extension Guarantee {
|
||||
}
|
||||
|
||||
public extension Guarantee where T: Sequence {
|
||||
/**
|
||||
`Guarantee<[T]>` => `T` -> `U` => `Guarantee<[U]>`
|
||||
|
||||
Guarantee.value([1,2,3])
|
||||
.mapValues { integer in integer * 2 }
|
||||
.done {
|
||||
// $0 => [2,4,6]
|
||||
}
|
||||
*/
|
||||
func mapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) -> U) -> Guarantee<[U]> {
|
||||
return map(on: on, flags: flags) { $0.map(transform) }
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
/**
|
||||
`Guarantee<[T]>` => `KeyPath<T, U>` => `Guarantee<[U]>`
|
||||
|
||||
Guarantee.value([Person(name: "Max"), Person(name: "Roman"), Person(name: "John")])
|
||||
.mapValues(\.name)
|
||||
.done {
|
||||
// $0 => ["Max", "Roman", "John"]
|
||||
}
|
||||
*/
|
||||
func mapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, U>) -> Guarantee<[U]> {
|
||||
return map(on: on, flags: flags) { $0.map { $0[keyPath: keyPath] } }
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
`Guarantee<[T]>` => `T` -> `[U]` => `Guarantee<[U]>`
|
||||
|
||||
Guarantee.value([1,2,3])
|
||||
.flatMapValues { integer in [integer, integer] }
|
||||
.done {
|
||||
// $0 => [1,1,2,2,3,3]
|
||||
}
|
||||
*/
|
||||
func flatMapValues<U: Sequence>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) -> U) -> Guarantee<[U.Iterator.Element]> {
|
||||
return map(on: on, flags: flags) { (foo: T) in
|
||||
foo.flatMap { transform($0) }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
`Guarantee<[T]>` => `T` -> `U?` => `Guarantee<[U]>`
|
||||
|
||||
Guarantee.value(["1","2","a","3"])
|
||||
.compactMapValues { Int($0) }
|
||||
.done {
|
||||
// $0 => [1,2,3]
|
||||
}
|
||||
*/
|
||||
func compactMapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) -> U?) -> Guarantee<[U]> {
|
||||
return map(on: on, flags: flags) { foo -> [U] in
|
||||
#if !swift(>=3.3) || (swift(>=4) && !swift(>=4.1))
|
||||
return foo.flatMap(transform)
|
||||
#else
|
||||
return foo.compactMap(transform)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
/**
|
||||
`Guarantee<[T]>` => `KeyPath<T, U?>` => `Guarantee<[U]>`
|
||||
|
||||
Guarantee.value([Person(name: "Max"), Person(name: "Roman", age: 26), Person(name: "John", age: 23)])
|
||||
.compactMapValues(\.age)
|
||||
.done {
|
||||
// $0 => [26, 23]
|
||||
}
|
||||
*/
|
||||
func compactMapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, U?>) -> Guarantee<[U]> {
|
||||
return map(on: on, flags: flags) { foo -> [U] in
|
||||
#if !swift(>=4.1)
|
||||
return foo.flatMap { $0[keyPath: keyPath] }
|
||||
#else
|
||||
return foo.compactMap { $0[keyPath: keyPath] }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
`Guarantee<[T]>` => `T` -> `Guarantee<U>` => `Guaranetee<[U]>`
|
||||
|
||||
firstly {
|
||||
.value([1,2,3])
|
||||
}.thenMap {
|
||||
.value($0 * 2)
|
||||
}.done {
|
||||
// $0 => [2,4,6]
|
||||
}
|
||||
Guarantee.value([1,2,3])
|
||||
.thenMap { .value($0 * 2) }
|
||||
.done {
|
||||
// $0 => [2,4,6]
|
||||
}
|
||||
*/
|
||||
func thenMap<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) -> Guarantee<U>) -> Guarantee<[U]> {
|
||||
return then(on: on, flags: flags) {
|
||||
@ -164,6 +256,88 @@ public extension Guarantee where T: Sequence {
|
||||
fatalError(String(describing: $0))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
`Guarantee<[T]>` => `T` -> `Guarantee<[U]>` => `Guarantee<[U]>`
|
||||
|
||||
Guarantee.value([1,2,3])
|
||||
.thenFlatMap { integer in .value([integer, integer]) }
|
||||
.done {
|
||||
// $0 => [1,1,2,2,3,3]
|
||||
}
|
||||
*/
|
||||
func thenFlatMap<U: Thenable>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T.Iterator.Element) -> U) -> Guarantee<[U.T.Iterator.Element]> where U.T: Sequence {
|
||||
return then(on: on, flags: flags) {
|
||||
when(fulfilled: $0.map(transform))
|
||||
}.map(on: nil) {
|
||||
$0.flatMap { $0 }
|
||||
}.recover {
|
||||
// if happens then is bug inside PromiseKit
|
||||
fatalError(String(describing: $0))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
`Guarantee<[T]>` => `T` -> Bool => `Guarantee<[T]>`
|
||||
|
||||
Guarantee.value([1,2,3])
|
||||
.filterValues { $0 > 1 }
|
||||
.done {
|
||||
// $0 => [2,3]
|
||||
}
|
||||
*/
|
||||
func filterValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ isIncluded: @escaping(T.Iterator.Element) -> Bool) -> Guarantee<[T.Iterator.Element]> {
|
||||
return map(on: on, flags: flags) {
|
||||
$0.filter(isIncluded)
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
/**
|
||||
`Guarantee<[T]>` => `KeyPath<T, Bool>` => `Guarantee<[T]>`
|
||||
|
||||
Guarantee.value([Person(name: "Max"), Person(name: "Roman", age: 26, isStudent: false), Person(name: "John", age: 23, isStudent: true)])
|
||||
.filterValues(\.isStudent)
|
||||
.done {
|
||||
// $0 => [Person(name: "John", age: 23, isStudent: true)]
|
||||
}
|
||||
*/
|
||||
func filterValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, Bool>) -> Guarantee<[T.Iterator.Element]> {
|
||||
return map(on: on, flags: flags) {
|
||||
$0.filter { $0[keyPath: keyPath] }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
`Guarantee<[T]>` => (`T`, `T`) -> Bool => `Guarantee<[T]>`
|
||||
|
||||
Guarantee.value([5,2,3,4,1])
|
||||
.sortedValues { $0 > $1 }
|
||||
.done {
|
||||
// $0 => [5,4,3,2,1]
|
||||
}
|
||||
*/
|
||||
func sortedValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ areInIncreasingOrder: @escaping(T.Iterator.Element, T.Iterator.Element) -> Bool) -> Guarantee<[T.Iterator.Element]> {
|
||||
return map(on: on, flags: flags) {
|
||||
$0.sorted(by: areInIncreasingOrder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension Guarantee where T: Sequence, T.Iterator.Element: Comparable {
|
||||
/**
|
||||
`Guarantee<[T]>` => `Guarantee<[T]>`
|
||||
|
||||
Guarantee.value([5,2,3,4,1])
|
||||
.sortedValues()
|
||||
.done {
|
||||
// $0 => [1,2,3,4,5]
|
||||
}
|
||||
*/
|
||||
func sortedValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil) -> Guarantee<[T.Iterator.Element]> {
|
||||
return map(on: on, flags: flags) { $0.sorted() }
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=3.1)
|
||||
@ -171,6 +345,10 @@ public extension Guarantee where T == Void {
|
||||
convenience init() {
|
||||
self.init(box: SealedBox(value: Void()))
|
||||
}
|
||||
|
||||
static var value: Guarantee<Void> {
|
||||
return .value(Void())
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ public final class Promise<T>: Thenable, CatchMixin {
|
||||
return .value(bar)
|
||||
}
|
||||
*/
|
||||
public class func value(_ value: T) -> Promise<T> {
|
||||
public static func value(_ value: T) -> Promise<T> {
|
||||
return Promise(box: SealedBox(value: .fulfilled(value)))
|
||||
}
|
||||
|
||||
@ -136,6 +136,11 @@ extension Promise where T == Void {
|
||||
public convenience init() {
|
||||
self.init(box: SealedBox(value: .fulfilled(Void())))
|
||||
}
|
||||
|
||||
/// Returns a new promise fulfilled with `Void`
|
||||
public static var value: Promise<Void> {
|
||||
return .value(Void())
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#import "fwd.h"
|
||||
#import "AnyPromise.h"
|
||||
#import <PromiseKit/fwd.h>
|
||||
#import <PromiseKit/AnyPromise.h>
|
||||
|
||||
#import <Foundation/NSObjCRuntime.h> // `FOUNDATION_EXPORT`
|
||||
|
||||
|
||||
@ -14,12 +14,12 @@ public protocol Thenable: class {
|
||||
|
||||
public extension Thenable {
|
||||
/**
|
||||
The provided closure executes when this promise resolves.
|
||||
The provided closure executes when this promise is fulfilled.
|
||||
|
||||
This allows chaining promises. The promise returned by the provided closure is resolved before the promise returned by this closure resolves.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The closure that executes when this promise fulfills. It must return a promise.
|
||||
- Parameter body: The closure that executes when this promise is fulfilled. It must return a promise.
|
||||
- Returns: A new promise that resolves when the promise returned from the provided closure resolves. For example:
|
||||
|
||||
firstly {
|
||||
@ -52,13 +52,13 @@ public extension Thenable {
|
||||
}
|
||||
|
||||
/**
|
||||
The provided closure is executed when this promise is resolved.
|
||||
The provided closure is executed when this promise is fulfilled.
|
||||
|
||||
This is like `then` but it requires the closure to return a non-promise.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter transform: The closure that is executed when this Promise is fulfilled. It must return a non-promise.
|
||||
- Returns: A new promise that is resolved with the value returned from the provided closure. For example:
|
||||
- Returns: A new promise that is fulfilled with the value returned from the provided closure or rejected if the provided closure throws. For example:
|
||||
|
||||
firstly {
|
||||
URLSession.shared.dataTask(.promise, with: url1)
|
||||
@ -87,8 +87,32 @@ public extension Thenable {
|
||||
return rp
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
/**
|
||||
The provided closure is executed when this promise is resolved.
|
||||
Similar to func `map<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U) -> Promise<U>`, but accepts a key path instead of a closure.
|
||||
|
||||
- Parameter on: The queue to which the provided key path for value dispatches.
|
||||
- Parameter keyPath: The key path to the value that is using when this Promise is fulfilled.
|
||||
- Returns: A new promise that is fulfilled with the value for the provided key path.
|
||||
*/
|
||||
func map<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T, U>) -> Promise<U> {
|
||||
let rp = Promise<U>(.pending)
|
||||
pipe {
|
||||
switch $0 {
|
||||
case .fulfilled(let value):
|
||||
on.async(flags: flags) {
|
||||
rp.box.seal(.fulfilled(value[keyPath: keyPath]))
|
||||
}
|
||||
case .rejected(let error):
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
return rp
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
The provided closure is executed when this promise is fulfilled.
|
||||
|
||||
In your closure return an `Optional`, if you return `nil` the resulting promise is rejected with `PMKError.compactMap`, otherwise the promise is fulfilled with the unwrapped value.
|
||||
|
||||
@ -125,15 +149,47 @@ public extension Thenable {
|
||||
return rp
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
/**
|
||||
The provided closure is executed when this promise is resolved.
|
||||
Similar to func `compactMap<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ transform: @escaping(T) throws -> U?) -> Promise<U>`, but accepts a key path instead of a closure.
|
||||
|
||||
- Parameter on: The queue to which the provided key path for value dispatches.
|
||||
- Parameter keyPath: The key path to the value that is using when this Promise is fulfilled. If the value for `keyPath` is `nil` the resulting promise is rejected with `PMKError.compactMap`.
|
||||
- Returns: A new promise that is fulfilled with the value for the provided key path.
|
||||
*/
|
||||
func compactMap<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T, U?>) -> Promise<U> {
|
||||
let rp = Promise<U>(.pending)
|
||||
pipe {
|
||||
switch $0 {
|
||||
case .fulfilled(let value):
|
||||
on.async(flags: flags) {
|
||||
do {
|
||||
if let rv = value[keyPath: keyPath] {
|
||||
rp.box.seal(.fulfilled(rv))
|
||||
} else {
|
||||
throw PMKError.compactMap(value, U.self)
|
||||
}
|
||||
} catch {
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
case .rejected(let error):
|
||||
rp.box.seal(.rejected(error))
|
||||
}
|
||||
}
|
||||
return rp
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
The provided closure is executed when this promise is fulfilled.
|
||||
|
||||
Equivalent to `map { x -> Void in`, but since we force the `Void` return Swift
|
||||
is happier and gives you less hassle about your closure’s qualification.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The closure that is executed when this Promise is fulfilled.
|
||||
- Returns: A new promise fulfilled as `Void`.
|
||||
- Returns: A new promise fulfilled as `Void` or rejected if the provided closure throws.
|
||||
|
||||
firstly {
|
||||
URLSession.shared.dataTask(.promise, with: url)
|
||||
@ -162,14 +218,14 @@ public extension Thenable {
|
||||
}
|
||||
|
||||
/**
|
||||
The provided closure is executed when this promise is resolved.
|
||||
The provided closure is executed when this promise is fulfilled.
|
||||
|
||||
This is like `done` but it returns the same value that the handler is fed.
|
||||
`get` immutably accesses the fulfilled value; the returned Promise maintains that value.
|
||||
|
||||
- Parameter on: The queue to which the provided closure dispatches.
|
||||
- Parameter body: The closure that is executed when this Promise is fulfilled.
|
||||
- Returns: A new promise that is resolved with the value that the handler is fed. For example:
|
||||
- Returns: A new promise that is fulfilled with the value that the handler is fed or rejected if the provided closure throws. For example:
|
||||
|
||||
firstly {
|
||||
.value(1)
|
||||
@ -290,6 +346,21 @@ public extension Thenable where T: Sequence {
|
||||
return map(on: on, flags: flags){ try $0.map(transform) }
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
/**
|
||||
`Promise<[T]>` => `KeyPath<T, U>` => `Promise<[U]>`
|
||||
|
||||
firstly {
|
||||
.value([Person(name: "Max"), Person(name: "Roman"), Person(name: "John")])
|
||||
}.mapValues(\.name).done {
|
||||
// $0 => ["Max", "Roman", "John"]
|
||||
}
|
||||
*/
|
||||
func mapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, U>) -> Promise<[U]> {
|
||||
return map(on: on, flags: flags){ $0.map { $0[keyPath: keyPath] } }
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
`Promise<[T]>` => `T` -> `[U]` => `Promise<[U]>`
|
||||
|
||||
@ -328,6 +399,27 @@ public extension Thenable where T: Sequence {
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
/**
|
||||
`Promise<[T]>` => `KeyPath<T, U?>` => `Promise<[U]>`
|
||||
|
||||
firstly {
|
||||
.value([Person(name: "Max"), Person(name: "Roman", age: 26), Person(name: "John", age: 23)])
|
||||
}.compactMapValues(\.age).done {
|
||||
// $0 => [26, 23]
|
||||
}
|
||||
*/
|
||||
func compactMapValues<U>(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, U?>) -> Promise<[U]> {
|
||||
return map(on: on, flags: flags) { foo -> [U] in
|
||||
#if !swift(>=4.1)
|
||||
return foo.flatMap { $0[keyPath: keyPath] }
|
||||
#else
|
||||
return foo.compactMap { $0[keyPath: keyPath] }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
`Promise<[T]>` => `T` -> `Promise<U>` => `Promise<[U]>`
|
||||
|
||||
@ -365,7 +457,7 @@ public extension Thenable where T: Sequence {
|
||||
}
|
||||
|
||||
/**
|
||||
`Promise<[T]>` => `T` -> Bool => `Promise<[U]>`
|
||||
`Promise<[T]>` => `T` -> Bool => `Promise<[T]>`
|
||||
|
||||
firstly {
|
||||
.value([1,2,3])
|
||||
@ -380,6 +472,23 @@ public extension Thenable where T: Sequence {
|
||||
$0.filter(isIncluded)
|
||||
}
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
/**
|
||||
`Promise<[T]>` => `KeyPath<T, Bool>` => `Promise<[T]>`
|
||||
|
||||
firstly {
|
||||
.value([Person(name: "Max"), Person(name: "Roman", age: 26, isStudent: false), Person(name: "John", age: 23, isStudent: true)])
|
||||
}.filterValues(\.isStudent).done {
|
||||
// $0 => [Person(name: "John", age: 23, isStudent: true)]
|
||||
}
|
||||
*/
|
||||
func filterValues(on: DispatchQueue? = conf.Q.map, flags: DispatchWorkItemFlags? = nil, _ keyPath: KeyPath<T.Iterator.Element, Bool>) -> Promise<[T.Iterator.Element]> {
|
||||
return map(on: on, flags: flags) {
|
||||
$0.filter { $0[keyPath: keyPath] }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public extension Thenable where T: Collection {
|
||||
|
||||
@ -21,7 +21,7 @@ import Dispatch
|
||||
URLSession.shared.dataTask(url: url3)
|
||||
}
|
||||
|
||||
- Note: the block you pass excecutes immediately on the current thread/queue.
|
||||
- Note: the block you pass executes immediately on the current thread/queue.
|
||||
*/
|
||||
public func firstly<U: Thenable>(execute body: () throws -> U) -> Promise<U.T> {
|
||||
do {
|
||||
|
||||
@ -139,7 +139,7 @@ public func when<It: IteratorProtocol>(fulfilled promiseIterator: It, concurrent
|
||||
}
|
||||
|
||||
var generator = promiseIterator
|
||||
var root = Promise<[It.Element.T]>.pending()
|
||||
let root = Promise<[It.Element.T]>.pending()
|
||||
var pendingPromises = 0
|
||||
var promises: [It.Element] = []
|
||||
|
||||
@ -154,15 +154,11 @@ public func when<It: IteratorProtocol>(fulfilled promiseIterator: It, concurrent
|
||||
}
|
||||
guard shouldDequeue else { return }
|
||||
|
||||
var index: Int!
|
||||
var promise: It.Element!
|
||||
|
||||
barrier.sync(flags: .barrier) {
|
||||
guard let next = generator.next() else { return }
|
||||
|
||||
promise = next
|
||||
index = promises.count
|
||||
|
||||
pendingPromises += 1
|
||||
promises.append(next)
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ class Test226: XCTestCase {
|
||||
describe("2.2.6: `then` may be called multiple times on the same promise.") {
|
||||
describe("2.2.6.1: If/when `promise` is fulfilled, all respective `onFulfilled` callbacks must execute in the order of their originating calls to `then`.") {
|
||||
describe("multiple boring fulfillment handlers") {
|
||||
testFulfilled(withExpectationCount: 4) { promise, exes, sentinel -> () in
|
||||
testFulfilled(withExpectationCount: 4) { promise, exes, sentinel -> Void in
|
||||
var orderValidator = 0
|
||||
promise.done {
|
||||
XCTAssertEqual($0, sentinel)
|
||||
|
||||
@ -757,6 +757,22 @@ static inline AnyPromise *fulfillLater() {
|
||||
[self waitForExpectationsWithTimeout:1 handler:nil];
|
||||
}
|
||||
|
||||
- (void)test_61_wait_for_value {
|
||||
id o = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
|
||||
resolve(@1);
|
||||
}].wait;
|
||||
|
||||
XCTAssertEqualObjects(o, @1);
|
||||
}
|
||||
|
||||
- (void)test_62_wait_for_error {
|
||||
NSError* err = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
|
||||
resolve([NSError errorWithDomain:@"a" code:123 userInfo:nil]);
|
||||
}].wait;
|
||||
|
||||
XCTAssertEqual(err.code, 123);
|
||||
}
|
||||
|
||||
- (void)test_properties {
|
||||
XCTAssertEqualObjects([AnyPromise promiseWithValue:@1].value, @1);
|
||||
XCTAssertEqualObjects([[AnyPromise promiseWithValue:dummyWithCode(2)].value localizedDescription], @"2");
|
||||
|
||||
@ -2,6 +2,10 @@ import Foundation
|
||||
import PromiseKit
|
||||
import XCTest
|
||||
|
||||
#if canImport(StoreKit)
|
||||
import StoreKit
|
||||
#endif
|
||||
|
||||
class CancellationTests: XCTestCase {
|
||||
func testCancellation() {
|
||||
let ex1 = expectation(description: "")
|
||||
@ -95,6 +99,25 @@ class CancellationTests: XCTestCase {
|
||||
waitForExpectations(timeout: 1)
|
||||
}
|
||||
|
||||
func testDoesntCrashSwift() {
|
||||
// Previously exposed a bridging crash in Swift
|
||||
// NOTE nobody was brave enough or diligent enough to report this to Apple :{
|
||||
XCTAssertFalse(NSError().isCancelled)
|
||||
|
||||
#if canImport(StoreKit)
|
||||
do {
|
||||
let err = SKError(.paymentCancelled)
|
||||
XCTAssertTrue(err.isCancelled)
|
||||
throw err
|
||||
} catch {
|
||||
XCTAssertTrue(error.isCancelled)
|
||||
}
|
||||
|
||||
XCTAssertFalse(SKError(.clientInvalid).isCancelled)
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if swift(>=3.2)
|
||||
func testIsCancelled() {
|
||||
XCTAssertTrue(PMKError.cancelled.isCancelled)
|
||||
|
||||
@ -13,10 +13,105 @@ class GuaranteeTests: XCTestCase {
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
func testMap() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value(1).map {
|
||||
$0 * 2
|
||||
}.done {
|
||||
XCTAssertEqual(2, $0)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
func testMapByKeyPath() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value(Person(name: "Max")).map(\.name).done {
|
||||
XCTAssertEqual("Max", $0)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
#endif
|
||||
|
||||
func testWait() {
|
||||
XCTAssertEqual(after(.milliseconds(100)).map(on: nil){ 1 }.wait(), 1)
|
||||
}
|
||||
|
||||
func testMapValues() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value([1, 2, 3])
|
||||
.mapValues { $0 * 2 }
|
||||
.done { values in
|
||||
XCTAssertEqual([2, 4, 6], values)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
func testMapValuesByKeyPath() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value([Person(name: "Max"), Person(name: "Roman"), Person(name: "John")])
|
||||
.mapValues(\.name)
|
||||
.done { values in
|
||||
XCTAssertEqual(["Max", "Roman", "John"], values)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
#endif
|
||||
|
||||
func testFlatMapValues() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value([1, 2, 3])
|
||||
.flatMapValues { [$0, $0] }
|
||||
.done { values in
|
||||
XCTAssertEqual([1, 1, 2, 2, 3, 3], values)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
func testCompactMapValues() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value(["1","2","a","3"])
|
||||
.compactMapValues { Int($0) }
|
||||
.done { values in
|
||||
XCTAssertEqual([1, 2, 3], values)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
func testCompactMapValuesByKeyPath() {
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value([Person(name: "Max"), Person(name: "Roman", age: 26), Person(name: "John", age: 23)])
|
||||
.compactMapValues(\.age)
|
||||
.done { values in
|
||||
XCTAssertEqual([26, 23], values)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
#endif
|
||||
|
||||
func testThenMap() {
|
||||
|
||||
let ex = expectation(description: "")
|
||||
@ -26,8 +121,93 @@ class GuaranteeTests: XCTestCase {
|
||||
.done { values in
|
||||
XCTAssertEqual([2, 4, 6], values)
|
||||
ex.fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
func testThenFlatMap() {
|
||||
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value([1, 2, 3])
|
||||
.thenFlatMap { Guarantee.value([$0, $0]) }
|
||||
.done { values in
|
||||
XCTAssertEqual([1, 1, 2, 2, 3, 3], values)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
func testFilterValues() {
|
||||
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value([1, 2, 3])
|
||||
.filterValues { $0 > 1 }
|
||||
.done { values in
|
||||
XCTAssertEqual([2, 3], values)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
func testFilterValuesByKeyPath() {
|
||||
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value([Person(name: "Max"), Person(name: "Roman", age: 26, isStudent: false), Person(name: "John", age: 23, isStudent: true)])
|
||||
.filterValues(\.isStudent)
|
||||
.done { values in
|
||||
XCTAssertEqual([Person(name: "John", age: 23, isStudent: true)], values)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
#endif
|
||||
|
||||
func testSorted() {
|
||||
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value([5, 2, 3, 4, 1])
|
||||
.sortedValues()
|
||||
.done { values in
|
||||
XCTAssertEqual([1, 2, 3, 4, 5], values)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
func testSortedBy() {
|
||||
|
||||
let ex = expectation(description: "")
|
||||
|
||||
Guarantee.value([5, 2, 3, 4, 1])
|
||||
.sortedValues { $0 > $1 }
|
||||
.done { values in
|
||||
XCTAssertEqual([5, 4, 3, 2, 1], values)
|
||||
ex.fulfill()
|
||||
}
|
||||
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
#if swift(>=3.1)
|
||||
func testNoAmbiguityForValue() {
|
||||
let ex = expectation(description: "")
|
||||
let a = Guarantee<Void>.value
|
||||
let b = Guarantee<Void>.value(Void())
|
||||
let c = Guarantee<Void>.value(())
|
||||
when(fulfilled: a, b, c).done {
|
||||
ex.fulfill()
|
||||
}.cauterize()
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -178,7 +178,7 @@ class LoggingTests: XCTestCase {
|
||||
func testPendingGuaranteeDeallocatedIsLogged() {
|
||||
|
||||
var logOutput: String? = nil
|
||||
let loggingClosure: (PromiseKit.LogEvent) -> () = { event in
|
||||
let loggingClosure: (PromiseKit.LogEvent) -> Void = { event in
|
||||
switch event {
|
||||
case .waitOnMainThread, .pendingPromiseDeallocated, .pendingGuaranteeDeallocated:
|
||||
logOutput = "\(event)"
|
||||
|
||||
@ -136,4 +136,17 @@ class PromiseTests: XCTestCase {
|
||||
}.silenceWarning()
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
#if swift(>=3.1)
|
||||
func testNoAmbiguityForValue() {
|
||||
let ex = expectation(description: "")
|
||||
let a = Promise<Void>.value
|
||||
let b = Promise<Void>.value(Void())
|
||||
let c = Promise<Void>.value(())
|
||||
when(fulfilled: a, b, c).done {
|
||||
ex.fulfill()
|
||||
}.cauterize()
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -2,6 +2,22 @@ import PromiseKit
|
||||
import Dispatch
|
||||
import XCTest
|
||||
|
||||
struct Person: Equatable {
|
||||
let name: String
|
||||
let age: Int?
|
||||
let isStudent: Bool
|
||||
|
||||
init(
|
||||
name: String = "",
|
||||
age: Int? = nil,
|
||||
isStudent: Bool = false
|
||||
) {
|
||||
self.name = name
|
||||
self.age = age
|
||||
self.isStudent = isStudent
|
||||
}
|
||||
}
|
||||
|
||||
class ThenableTests: XCTestCase {
|
||||
func testGet() {
|
||||
let ex1 = expectation(description: "")
|
||||
@ -16,6 +32,28 @@ class ThenableTests: XCTestCase {
|
||||
wait(for: [ex1, ex2], timeout: 10)
|
||||
}
|
||||
|
||||
func testMap() {
|
||||
let ex = expectation(description: "")
|
||||
Promise.value(1).map {
|
||||
$0 * 2
|
||||
}.done {
|
||||
XCTAssertEqual($0, 2)
|
||||
ex.fulfill()
|
||||
}.silenceWarning()
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
func testMapByKeyPath() {
|
||||
let ex = expectation(description: "")
|
||||
Promise.value(Person(name: "Max")).map(\.name).done {
|
||||
XCTAssertEqual($0, "Max")
|
||||
ex.fulfill()
|
||||
}.silenceWarning()
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
#endif
|
||||
|
||||
func testCompactMap() {
|
||||
let ex = expectation(description: "")
|
||||
Promise.value(1.0).compactMap {
|
||||
@ -72,6 +110,39 @@ class ThenableTests: XCTestCase {
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
func testCompactMapByKeyPath() {
|
||||
let ex = expectation(description: "")
|
||||
Promise.value(Person(name: "Roman", age: 26)).compactMap(\.age).done {
|
||||
XCTAssertEqual($0, 26)
|
||||
ex.fulfill()
|
||||
}.silenceWarning()
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
#endif
|
||||
|
||||
func testMapValues() {
|
||||
let ex = expectation(description: "")
|
||||
Promise.value([14, 20, 45]).mapValues {
|
||||
$0 * 2
|
||||
}.done {
|
||||
XCTAssertEqual([28, 40, 90], $0)
|
||||
ex.fulfill()
|
||||
}.silenceWarning()
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
func testMapValuesByKeyPath() {
|
||||
let ex = expectation(description: "")
|
||||
Promise.value([Person(name: "Max"), Person(name: "Roman"), Person(name: "John")]).mapValues(\.name).done {
|
||||
XCTAssertEqual(["Max", "Roman", "John"], $0)
|
||||
ex.fulfill()
|
||||
}.silenceWarning()
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
#endif
|
||||
|
||||
func testCompactMapValues() {
|
||||
let ex = expectation(description: "")
|
||||
Promise.value(["1","2","a","4"]).compactMapValues {
|
||||
@ -83,6 +154,17 @@ class ThenableTests: XCTestCase {
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
func testCompactMapValuesByKeyPath() {
|
||||
let ex = expectation(description: "")
|
||||
Promise.value([Person(name: "Max"), Person(name: "Roman", age: 26), Person(name: "John", age: 23)]).compactMapValues(\.age).done {
|
||||
XCTAssertEqual([26, 23], $0)
|
||||
ex.fulfill()
|
||||
}.silenceWarning()
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
#endif
|
||||
|
||||
func testThenMap() {
|
||||
let ex = expectation(description: "")
|
||||
Promise.value([1,2,3,4]).thenMap {
|
||||
@ -105,6 +187,28 @@ class ThenableTests: XCTestCase {
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
func testFilterValues() {
|
||||
let ex = expectation(description: "")
|
||||
Promise.value([Person(name: "Max"), Person(name: "Roman", age: 26, isStudent: false), Person(name: "John", age: 23, isStudent: true)]).filterValues {
|
||||
$0.isStudent
|
||||
}.done {
|
||||
XCTAssertEqual([Person(name: "John", age: 23, isStudent: true)], $0)
|
||||
ex.fulfill()
|
||||
}.silenceWarning()
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
|
||||
#if swift(>=4) && !swift(>=5.2)
|
||||
func testFilterValuesByKeyPath() {
|
||||
let ex = expectation(description: "")
|
||||
Promise.value([Person(name: "Max"), Person(name: "Roman", age: 26, isStudent: false), Person(name: "John", age: 23, isStudent: true)]).filterValues(\.isStudent).done {
|
||||
XCTAssertEqual([Person(name: "John", age: 23, isStudent: true)], $0)
|
||||
ex.fulfill()
|
||||
}.silenceWarning()
|
||||
wait(for: [ex], timeout: 10)
|
||||
}
|
||||
#endif
|
||||
|
||||
func testLastValueForEmpty() {
|
||||
XCTAssertTrue(Promise.value([]).lastValue.isRejected)
|
||||
}
|
||||
|
||||
@ -18,6 +18,7 @@ extension CancellationTests {
|
||||
// to regenerate.
|
||||
static let __allTests__CancellationTests = [
|
||||
("testCancellation", testCancellation),
|
||||
("testDoesntCrashSwift", testDoesntCrashSwift),
|
||||
("testFoundationBridging1", testFoundationBridging1),
|
||||
("testFoundationBridging2", testFoundationBridging2),
|
||||
("testIsCancelled", testIsCancelled),
|
||||
@ -55,7 +56,20 @@ extension GuaranteeTests {
|
||||
// `swift test --generate-linuxmain`
|
||||
// to regenerate.
|
||||
static let __allTests__GuaranteeTests = [
|
||||
("testCompactMapValues", testCompactMapValues),
|
||||
("testCompactMapValuesByKeyPath", testCompactMapValuesByKeyPath),
|
||||
("testFilterValues", testFilterValues),
|
||||
("testFilterValuesByKeyPath", testFilterValuesByKeyPath),
|
||||
("testFlatMapValues", testFlatMapValues),
|
||||
("testInit", testInit),
|
||||
("testMap", testMap),
|
||||
("testMapByKeyPath", testMapByKeyPath),
|
||||
("testMapValues", testMapValues),
|
||||
("testMapValuesByKeyPath", testMapValuesByKeyPath),
|
||||
("testNoAmbiguityForValue", testNoAmbiguityForValue),
|
||||
("testSorted", testSorted),
|
||||
("testSortedBy", testSortedBy),
|
||||
("testThenFlatMap", testThenFlatMap),
|
||||
("testThenMap", testThenMap),
|
||||
("testWait", testWait),
|
||||
]
|
||||
@ -130,6 +144,7 @@ extension PromiseTests {
|
||||
("testIsPending", testIsPending),
|
||||
("testIsRejected", testIsRejected),
|
||||
("testIsResolved", testIsResolved),
|
||||
("testNoAmbiguityForValue", testNoAmbiguityForValue),
|
||||
("testPipeForResolved", testPipeForResolved),
|
||||
("testThrowInFirstly", testThrowInFirstly),
|
||||
("testThrowInInitializer", testThrowInInitializer),
|
||||
@ -177,12 +192,20 @@ extension ThenableTests {
|
||||
static let __allTests__ThenableTests = [
|
||||
("testBarrier", testBarrier),
|
||||
("testCompactMap", testCompactMap),
|
||||
("testCompactMapByKeyPath", testCompactMapByKeyPath),
|
||||
("testCompactMapThrows", testCompactMapThrows),
|
||||
("testCompactMapValues", testCompactMapValues),
|
||||
("testCompactMapValuesByKeyPath", testCompactMapValuesByKeyPath),
|
||||
("testDispatchFlagsSyntax", testDispatchFlagsSyntax),
|
||||
("testFilterValues", testFilterValues),
|
||||
("testFilterValuesByKeyPath", testFilterValuesByKeyPath),
|
||||
("testFirstValueForEmpty", testFirstValueForEmpty),
|
||||
("testGet", testGet),
|
||||
("testLastValueForEmpty", testLastValueForEmpty),
|
||||
("testMap", testMap),
|
||||
("testMapByKeyPath", testMapByKeyPath),
|
||||
("testMapValues", testMapValues),
|
||||
("testMapValuesByKeyPath", testMapValuesByKeyPath),
|
||||
("testPMKErrorCompactMap", testPMKErrorCompactMap),
|
||||
("testRejectedPromiseCompactMap", testRejectedPromiseCompactMap),
|
||||
("testThenFlatMap", testThenFlatMap),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user