Add PromiseKit dependency

- Added PromiseKit dependency
This commit is contained in:
2018-11-15 22:08:00 -04:00
parent 2689d86c18
commit be7b6b5881
541 changed files with 46282 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
ignore:
- "Tests"
codecov:
notify:
require_ci_to_pass: yes
coverage:
precision: 1
round: up
range: "70...100"
status:
project: yes
patch: yes
changes: no
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment: off

View File

@@ -0,0 +1,5 @@
*.xcodeproj/**/xcuserdata/
*.xcscmblueprint
/Carthage
/.build
.DS_Store

View File

@@ -0,0 +1,125 @@
branches:
only:
- master
stages:
- lint
- compile
- test
jobs:
include:
- &pod
stage: lint
osx_image: xcode8.3
env: SWIFT=3.1
name: pod lib lint --swift-version=3.1
os: osx
language: objective-c
before_install:
gem install cocoapods --prerelease --version 1.6.0.beta.1
install:
carthage bootstrap --no-build PromiseKit
script: |
cd Carthage/Checkouts/PromiseKit
mv .github/PromiseKit.podspec .
rm -rf Extensions/Foundation/Sources
cp -R ../../../Sources Extensions/Foundation
pod lib lint --subspec=PromiseKit/Foundation --fail-fast --swift-version=$SWIFT
- <<: *pod
osx_image: xcode9.2
env: SWIFT=3.2
name: pod lib lint --swift-version=3.2
- <<: *pod
osx_image: xcode9.4
env: SWIFT=3.3
name: pod lib lint --swift-version=3.3
- <<: *pod
osx_image: xcode10
env: SWIFT=3.4
name: pod lib lint --swift-version=3.4
- <<: *pod
osx_image: xcode9.2
env: SWIFT=4.0
name: pod lib lint --swift-version=4.0
- <<: *pod
osx_image: xcode9.4
env: SWIFT=4.1
name: pod lib lint --swift-version=4.1
- <<: *pod
osx_image: xcode10
env: SWIFT=4.2
name: pod lib lint --swift-version=4.2
- &linux
stage: compile
env: SWIFT_BUILD_VERSION=3 SWIFT_VERSION=4.0
# ^^ we have some source-conditionals for this version
name: Linux / Swift 3.2.0
os: linux
dist: trusty
sudo: required
language: generic
before_install:
eval "$(curl -sL https://swiftenv.fuller.li/install.sh)"
script:
swift build -Xswiftc -swift-version -Xswiftc $SWIFT_BUILD_VERSION
- <<: *linux
env: SWIFT_BUILD_VERSION=3 SWIFT_VERSION=4.0.3
name: Linux / Swift 3.2.3
- <<: *linux
env: SWIFT_BUILD_VERSION=3 SWIFT_VERSION=4.1.2
name: Linux / Swift 3.3
- <<: *linux
env: SWIFT_BUILD_VERSION=3 SWIFT_VERSION=4.2
name: Linux / Swift 3.4
- <<: *linux
env: SWIFT_BUILD_VERSION=4 SWIFT_VERSION=4.0
name: Linux / Swift 4.0.0
# ^^ we have some source-conditionals for this version
- <<: *linux
env: SWIFT_BUILD_VERSION=4 SWIFT_VERSION=4.0.3
name: Linux / Swift 4.0.3
- <<: *linux
env: SWIFT_BUILD_VERSION=4 SWIFT_VERSION=4.1.2
name: Linux / Swift 4.1
- <<: *linux
env: SWIFT_BUILD_VERSION=4 SWIFT_VERSION=4.2
name: Linux / Swift 4.2
- &swiftpm
stage: compile
name: Xcode 8.3 / SwiftPM
os: osx
osx_image: xcode8.3
language: objective-c
script: swift build
- <<: *swiftpm
name: Xcode 9.4 / SwiftPM
osx_image: xcode9.4
- <<: *swiftpm
name: Xcode 10.0 / SwiftPM
osx_image: xcode10
- &test
stage: test
osx_image: xcode10
name: macOS Tests
env: DST='arch=x86_64' PLAT=macOS
os: osx
language: objective-c
cache:
directories:
- Carthage
before_install:
carthage bootstrap --cache-builds --no-use-binaries --platform $PLAT
install:
xcodebuild -scheme PMKFoundation -target PMKFoundation -quiet -destination "$DST" SWIFT_TREAT_WARNINGS_AS_ERRORS=YES build
script:
xcodebuild -scheme PMKFoundation -quiet -destination "$DST" test
after_success:
bash <(curl -s https://codecov.io/bash);
- <<: *test
env: DST='OS=12.0,name=iPhone SE' PLAT=iOS
name: iOS Tests
- <<: *test
env: DST='OS=12.0,name=Apple TV' PLAT=tvOS
name: tvOS Tests

View File

@@ -0,0 +1 @@
github "mxcl/PromiseKit" ~> 6.3

View File

@@ -0,0 +1 @@
github "AliSoftware/OHHTTPStubs" ~> 6.0

View File

@@ -0,0 +1,2 @@
github "AliSoftware/OHHTTPStubs" "6.1.0"
github "mxcl/PromiseKit" "6.5.0"

View File

@@ -0,0 +1,7 @@
// Created by Kevin Ballard on 12/14/15.
// Copyright © 2015 Postmates. All rights reserved.
FRAMEWORK_SEARCH_PATHS[sdk=macosx*] = $(SRCROOT)/Carthage/Build/Mac/ $(inherited)
FRAMEWORK_SEARCH_PATHS[sdk=iphone*] = $(SRCROOT)/Carthage/Build/iOS/ $(inherited)
FRAMEWORK_SEARCH_PATHS[sdk=watch*] = $(SRCROOT)/Carthage/Build/watchOS/ $(inherited)
FRAMEWORK_SEARCH_PATHS[sdk=appletv*] = $(SRCROOT)/Carthage/Build/tvOS/ $(inherited)

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@@ -0,0 +1,20 @@
Copyright 2018-present, Max Howell; mxcl@me.com
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,506 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
6364F66F1D68B8DF008D7B94 /* NSNotificationCenter+AnyPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = 6364F66C1D68B8DF008D7B94 /* NSNotificationCenter+AnyPromise.h */; settings = {ATTRIBUTES = (Public, ); }; };
6364F6701D68B8DF008D7B94 /* NSTask+AnyPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = 6364F66D1D68B8DF008D7B94 /* NSTask+AnyPromise.h */; settings = {ATTRIBUTES = (Public, ); }; };
6364F6711D68B8DF008D7B94 /* NSURLSession+AnyPromise.h in Headers */ = {isa = PBXBuildFile; fileRef = 6364F66E1D68B8DF008D7B94 /* NSURLSession+AnyPromise.h */; settings = {ATTRIBUTES = (Public, ); }; };
63C700031D5C021F003BAE60 /* TestNSNotificationCenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C7FFFD1D5C021F003BAE60 /* TestNSNotificationCenter.swift */; };
63C700041D5C021F003BAE60 /* TestNSObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C7FFFE1D5C021F003BAE60 /* TestNSObject.swift */; };
63C700051D5C021F003BAE60 /* TestNSTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C7FFFF1D5C021F003BAE60 /* TestNSTask.swift */; };
63C700081D5C021F003BAE60 /* TestNSURLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C700021D5C021F003BAE60 /* TestNSURLSession.swift */; };
63C7FFDC1D5C00F2003BAE60 /* afterlife.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C7FFCE1D5C00F2003BAE60 /* afterlife.swift */; };
63C7FFDE1D5C00F2003BAE60 /* NSNotificationCenter+AnyPromise.m in Sources */ = {isa = PBXBuildFile; fileRef = 63C7FFD01D5C00F2003BAE60 /* NSNotificationCenter+AnyPromise.m */; };
63C7FFDF1D5C00F2003BAE60 /* NSNotificationCenter+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C7FFD11D5C00F2003BAE60 /* NSNotificationCenter+Promise.swift */; };
63C7FFE01D5C00F2003BAE60 /* NSObject+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C7FFD21D5C00F2003BAE60 /* NSObject+Promise.swift */; };
63C7FFE21D5C00F2003BAE60 /* NSTask+AnyPromise.m in Sources */ = {isa = PBXBuildFile; fileRef = 63C7FFD41D5C00F2003BAE60 /* NSTask+AnyPromise.m */; };
63C7FFE31D5C00F2003BAE60 /* Process+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C7FFD51D5C00F2003BAE60 /* Process+Promise.swift */; };
63C7FFE81D5C00F2003BAE60 /* NSURLSession+AnyPromise.m in Sources */ = {isa = PBXBuildFile; fileRef = 63C7FFDA1D5C00F2003BAE60 /* NSURLSession+AnyPromise.m */; };
63C7FFE91D5C00F2003BAE60 /* NSURLSession+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63C7FFDB1D5C00F2003BAE60 /* NSURLSession+Promise.swift */; };
63C7FFED1D5C00FD003BAE60 /* PMKFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 63C7FFEB1D5C00FD003BAE60 /* PMKFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
63C7FFF71D5C020D003BAE60 /* PMKFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63C7FFA71D5BEE09003BAE60 /* PMKFoundation.framework */; };
63CAF1061D682F9600D3835B /* TestNSURLSession.m in Sources */ = {isa = PBXBuildFile; fileRef = 63CAF1051D682F9600D3835B /* TestNSURLSession.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
63C7FFF81D5C020D003BAE60 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 63C7FF9E1D5BEE09003BAE60 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 63C7FFA61D5BEE09003BAE60;
remoteInfo = PMKFoundation;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
6364F66C1D68B8DF008D7B94 /* NSNotificationCenter+AnyPromise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSNotificationCenter+AnyPromise.h"; path = "Sources/NSNotificationCenter+AnyPromise.h"; sourceTree = SOURCE_ROOT; };
6364F66D1D68B8DF008D7B94 /* NSTask+AnyPromise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSTask+AnyPromise.h"; path = "Sources/NSTask+AnyPromise.h"; sourceTree = SOURCE_ROOT; };
6364F66E1D68B8DF008D7B94 /* NSURLSession+AnyPromise.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSURLSession+AnyPromise.h"; path = "Sources/NSURLSession+AnyPromise.h"; sourceTree = SOURCE_ROOT; };
63C700021D5C021F003BAE60 /* TestNSURLSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestNSURLSession.swift; path = Tests/TestNSURLSession.swift; sourceTree = SOURCE_ROOT; };
63C700091D5C0253003BAE60 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
63C7FFA71D5BEE09003BAE60 /* PMKFoundation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PMKFoundation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
63C7FFCE1D5C00F2003BAE60 /* afterlife.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = afterlife.swift; path = Sources/afterlife.swift; sourceTree = SOURCE_ROOT; };
63C7FFD01D5C00F2003BAE60 /* NSNotificationCenter+AnyPromise.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSNotificationCenter+AnyPromise.m"; path = "Sources/NSNotificationCenter+AnyPromise.m"; sourceTree = SOURCE_ROOT; };
63C7FFD11D5C00F2003BAE60 /* NSNotificationCenter+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSNotificationCenter+Promise.swift"; path = "Sources/NSNotificationCenter+Promise.swift"; sourceTree = SOURCE_ROOT; };
63C7FFD21D5C00F2003BAE60 /* NSObject+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSObject+Promise.swift"; path = "Sources/NSObject+Promise.swift"; sourceTree = SOURCE_ROOT; };
63C7FFD41D5C00F2003BAE60 /* NSTask+AnyPromise.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSTask+AnyPromise.m"; path = "Sources/NSTask+AnyPromise.m"; sourceTree = SOURCE_ROOT; };
63C7FFD51D5C00F2003BAE60 /* Process+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Process+Promise.swift"; path = "Sources/Process+Promise.swift"; sourceTree = SOURCE_ROOT; };
63C7FFDA1D5C00F2003BAE60 /* NSURLSession+AnyPromise.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSURLSession+AnyPromise.m"; path = "Sources/NSURLSession+AnyPromise.m"; sourceTree = SOURCE_ROOT; };
63C7FFDB1D5C00F2003BAE60 /* NSURLSession+Promise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSURLSession+Promise.swift"; path = "Sources/NSURLSession+Promise.swift"; sourceTree = SOURCE_ROOT; };
63C7FFEB1D5C00FD003BAE60 /* PMKFoundation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PMKFoundation.h; path = Sources/PMKFoundation.h; sourceTree = SOURCE_ROOT; };
63C7FFF21D5C020D003BAE60 /* PMKNSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PMKNSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
63C7FFFD1D5C021F003BAE60 /* TestNSNotificationCenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestNSNotificationCenter.swift; path = Tests/TestNSNotificationCenter.swift; sourceTree = SOURCE_ROOT; };
63C7FFFE1D5C021F003BAE60 /* TestNSObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestNSObject.swift; path = Tests/TestNSObject.swift; sourceTree = SOURCE_ROOT; };
63C7FFFF1D5C021F003BAE60 /* TestNSTask.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestNSTask.swift; path = Tests/TestNSTask.swift; sourceTree = SOURCE_ROOT; };
63CAF1051D682F9600D3835B /* TestNSURLSession.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TestNSURLSession.m; path = Tests/TestNSURLSession.m; sourceTree = SOURCE_ROOT; };
63CCF8121D5C0C4E00503216 /* Cartfile */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile; sourceTree = "<group>"; };
63CCF8131D5C0C4E00503216 /* Cartfile.private */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile.private; sourceTree = "<group>"; };
63CCF8171D5C11B500503216 /* Carthage.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Carthage.xcconfig; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
63C7FFA31D5BEE09003BAE60 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
63C7FFEF1D5C020D003BAE60 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
63C7FFF71D5C020D003BAE60 /* PMKFoundation.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
63C7FF9D1D5BEE09003BAE60 = {
isa = PBXGroup;
children = (
63C700091D5C0253003BAE60 /* Info.plist */,
63CCF8121D5C0C4E00503216 /* Cartfile */,
63CCF8131D5C0C4E00503216 /* Cartfile.private */,
63CCF8171D5C11B500503216 /* Carthage.xcconfig */,
63C7FFA91D5BEE09003BAE60 /* Sources */,
63C7FFF31D5C020D003BAE60 /* Tests */,
63C7FFA81D5BEE09003BAE60 /* Products */,
);
sourceTree = "<group>";
};
63C7FFA81D5BEE09003BAE60 /* Products */ = {
isa = PBXGroup;
children = (
63C7FFA71D5BEE09003BAE60 /* PMKFoundation.framework */,
63C7FFF21D5C020D003BAE60 /* PMKNSTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
63C7FFA91D5BEE09003BAE60 /* Sources */ = {
isa = PBXGroup;
children = (
63C7FFCE1D5C00F2003BAE60 /* afterlife.swift */,
63C7FFD51D5C00F2003BAE60 /* Process+Promise.swift */,
6364F66C1D68B8DF008D7B94 /* NSNotificationCenter+AnyPromise.h */,
63C7FFD01D5C00F2003BAE60 /* NSNotificationCenter+AnyPromise.m */,
63C7FFD11D5C00F2003BAE60 /* NSNotificationCenter+Promise.swift */,
63C7FFD21D5C00F2003BAE60 /* NSObject+Promise.swift */,
6364F66D1D68B8DF008D7B94 /* NSTask+AnyPromise.h */,
63C7FFD41D5C00F2003BAE60 /* NSTask+AnyPromise.m */,
6364F66E1D68B8DF008D7B94 /* NSURLSession+AnyPromise.h */,
63C7FFDA1D5C00F2003BAE60 /* NSURLSession+AnyPromise.m */,
63C7FFDB1D5C00F2003BAE60 /* NSURLSession+Promise.swift */,
63C7FFEB1D5C00FD003BAE60 /* PMKFoundation.h */,
);
path = Sources;
sourceTree = SOURCE_ROOT;
};
63C7FFF31D5C020D003BAE60 /* Tests */ = {
isa = PBXGroup;
children = (
63C7FFFD1D5C021F003BAE60 /* TestNSNotificationCenter.swift */,
63C7FFFE1D5C021F003BAE60 /* TestNSObject.swift */,
63C7FFFF1D5C021F003BAE60 /* TestNSTask.swift */,
63C700021D5C021F003BAE60 /* TestNSURLSession.swift */,
63CAF1051D682F9600D3835B /* TestNSURLSession.m */,
);
path = Tests;
sourceTree = SOURCE_ROOT;
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
63C7FFA41D5BEE09003BAE60 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
63C7FFED1D5C00FD003BAE60 /* PMKFoundation.h in Headers */,
6364F66F1D68B8DF008D7B94 /* NSNotificationCenter+AnyPromise.h in Headers */,
6364F6711D68B8DF008D7B94 /* NSURLSession+AnyPromise.h in Headers */,
6364F6701D68B8DF008D7B94 /* NSTask+AnyPromise.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
63C7FFA61D5BEE09003BAE60 /* PMKFoundation */ = {
isa = PBXNativeTarget;
buildConfigurationList = 63C7FFAF1D5BEE09003BAE60 /* Build configuration list for PBXNativeTarget "PMKFoundation" */;
buildPhases = (
63C7FFA21D5BEE09003BAE60 /* Sources */,
63C7FFA31D5BEE09003BAE60 /* Frameworks */,
63C7FFA41D5BEE09003BAE60 /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = PMKFoundation;
productName = "PMK+UIKit";
productReference = 63C7FFA71D5BEE09003BAE60 /* PMKFoundation.framework */;
productType = "com.apple.product-type.framework";
};
63C7FFF11D5C020D003BAE60 /* PMKNSTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 63C7FFFA1D5C020D003BAE60 /* Build configuration list for PBXNativeTarget "PMKNSTests" */;
buildPhases = (
63C7FFEE1D5C020D003BAE60 /* Sources */,
63C7FFEF1D5C020D003BAE60 /* Frameworks */,
639447051D5D011300DDAE3C /* Embed Carthage Frameworks */,
);
buildRules = (
);
dependencies = (
63C7FFF91D5C020D003BAE60 /* PBXTargetDependency */,
);
name = PMKNSTests;
productName = PMKTests/NS;
productReference = 63C7FFF21D5C020D003BAE60 /* PMKNSTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
63C7FF9E1D5BEE09003BAE60 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0800;
LastUpgradeCheck = 0930;
ORGANIZATIONNAME = "Max Howell";
TargetAttributes = {
63C7FFA61D5BEE09003BAE60 = {
CreatedOnToolsVersion = 8.0;
LastSwiftMigration = 0900;
ProvisioningStyle = Automatic;
};
63C7FFF11D5C020D003BAE60 = {
CreatedOnToolsVersion = 8.0;
LastSwiftMigration = 0900;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 63C7FFA11D5BEE09003BAE60 /* Build configuration list for PBXProject "PMKFoundation" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 63C7FF9D1D5BEE09003BAE60;
productRefGroup = 63C7FFA81D5BEE09003BAE60 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
63C7FFA61D5BEE09003BAE60 /* PMKFoundation */,
63C7FFF11D5C020D003BAE60 /* PMKNSTests */,
);
};
/* End PBXProject section */
/* Begin PBXShellScriptBuildPhase section */
639447051D5D011300DDAE3C /* Embed Carthage Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
PromiseKit,
OHHTTPStubs,
);
name = "Embed Carthage Frameworks";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "case \"$PLATFORM_NAME\" in\nmacosx) plat=Mac;;\niphone*) plat=iOS;;\nwatch*) plat=watchOS;;\nappletv*) plat=tvOS;;\n*) echo \"error: Unknown PLATFORM_NAME: $PLATFORM_NAME\"; exit 1;;\nesac\nfor (( n = 0; n < SCRIPT_INPUT_FILE_COUNT; n++ )); do\nVAR=SCRIPT_INPUT_FILE_$n\nframework=$(basename \"${!VAR}\")\nexport SCRIPT_INPUT_FILE_$n=\"$SRCROOT\"/Carthage/Build/$plat/\"$framework\".framework\ndone\n\n/usr/local/bin/carthage copy-frameworks || exit\n\nfor (( n = 0; n < SCRIPT_INPUT_FILE_COUNT; n++ )); do\nVAR=SCRIPT_INPUT_FILE_$n\nsource=${!VAR}.dSYM\ndest=${BUILT_PRODUCTS_DIR}/$(basename \"$source\")\nditto \"$source\" \"$dest\" || exit\ndone";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
63C7FFA21D5BEE09003BAE60 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
63C7FFDF1D5C00F2003BAE60 /* NSNotificationCenter+Promise.swift in Sources */,
63C7FFDC1D5C00F2003BAE60 /* afterlife.swift in Sources */,
63C7FFDE1D5C00F2003BAE60 /* NSNotificationCenter+AnyPromise.m in Sources */,
63C7FFE91D5C00F2003BAE60 /* NSURLSession+Promise.swift in Sources */,
63C7FFE31D5C00F2003BAE60 /* Process+Promise.swift in Sources */,
63C7FFE01D5C00F2003BAE60 /* NSObject+Promise.swift in Sources */,
63C7FFE81D5C00F2003BAE60 /* NSURLSession+AnyPromise.m in Sources */,
63C7FFE21D5C00F2003BAE60 /* NSTask+AnyPromise.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
63C7FFEE1D5C020D003BAE60 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
63C700051D5C021F003BAE60 /* TestNSTask.swift in Sources */,
63C700031D5C021F003BAE60 /* TestNSNotificationCenter.swift in Sources */,
63C700081D5C021F003BAE60 /* TestNSURLSession.swift in Sources */,
63CAF1061D682F9600D3835B /* TestNSURLSession.m in Sources */,
63C700041D5C021F003BAE60 /* TestNSObject.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
63C7FFF91D5C020D003BAE60 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 63C7FFA61D5BEE09003BAE60 /* PMKFoundation */;
targetProxy = 63C7FFF81D5C020D003BAE60 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
63C7FFAD1D5BEE09003BAE60 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 63CCF8171D5C11B500503216 /* Carthage.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1.0.4;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.Foundation;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos watchsimulator watchos macosx appletvsimulator appletvos";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
name = Debug;
};
63C7FFAE1D5BEE09003BAE60 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 63CCF8171D5C11B500503216 /* Carthage.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 1.0.4;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.10;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = org.promisekit.Foundation;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos watchsimulator watchos macosx appletvsimulator appletvos";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
TARGETED_DEVICE_FAMILY = "1,2,3,4";
TVOS_DEPLOYMENT_TARGET = 9.0;
VALIDATE_PRODUCT = YES;
WATCHOS_DEPLOYMENT_TARGET = 2.0;
};
name = Release;
};
63C7FFB01D5BEE09003BAE60 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_MODULE_NAME = "${TARGET_NAME}";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
63C7FFB11D5BEE09003BAE60 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = "";
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_MODULE_NAME = "${TARGET_NAME}";
PRODUCT_NAME = "$(TARGET_NAME)";
};
name = Release;
};
63C7FFFB1D5C020D003BAE60 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_SUPPRESS_WARNINGS = YES;
SWIFT_VERSION = 4.0;
};
name = Debug;
};
63C7FFFC1D5C020D003BAE60 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SUPPRESS_WARNINGS = YES;
SWIFT_VERSION = 4.0;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
63C7FFA11D5BEE09003BAE60 /* Build configuration list for PBXProject "PMKFoundation" */ = {
isa = XCConfigurationList;
buildConfigurations = (
63C7FFAD1D5BEE09003BAE60 /* Debug */,
63C7FFAE1D5BEE09003BAE60 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
63C7FFAF1D5BEE09003BAE60 /* Build configuration list for PBXNativeTarget "PMKFoundation" */ = {
isa = XCConfigurationList;
buildConfigurations = (
63C7FFB01D5BEE09003BAE60 /* Debug */,
63C7FFB11D5BEE09003BAE60 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
63C7FFFA1D5C020D003BAE60 /* Build configuration list for PBXNativeTarget "PMKNSTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
63C7FFFB1D5C020D003BAE60 /* Debug */,
63C7FFFC1D5C020D003BAE60 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 63C7FF9E1D5BEE09003BAE60 /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:/Users/mxcl/Desktop/PMK+UIKit/PMKFoundation.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
</dict>
</plist>

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "NO">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "NO"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63C7FFA61D5BEE09003BAE60"
BuildableName = "PMKFoundation.framework"
BlueprintName = "PMKFoundation"
ReferencedContainer = "container:PMKFoundation.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63C7FFF11D5C020D003BAE60"
BuildableName = "PMKNSTests.xctest"
BlueprintName = "PMKNSTests"
ReferencedContainer = "container:PMKFoundation.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63C7FFA61D5BEE09003BAE60"
BuildableName = "PMKFoundation.framework"
BlueprintName = "PMKFoundation"
ReferencedContainer = "container:PMKFoundation.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63C7FFA61D5BEE09003BAE60"
BuildableName = "PMKFoundation.framework"
BlueprintName = "PMKFoundation"
ReferencedContainer = "container:PMKFoundation.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "63C7FFA61D5BEE09003BAE60"
BuildableName = "PMKFoundation.framework"
BlueprintName = "PMKFoundation"
ReferencedContainer = "container:PMKFoundation.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,16 @@
{
"object": {
"pins": [
{
"package": "PromiseKit",
"repositoryURL": "https://github.com/mxcl/PromiseKit.git",
"state": {
"branch": null,
"revision": "9e5bc43281cae89ab0b6e47df3ea25a2c44af7f0",
"version": "6.5.0"
}
}
]
},
"version": 1
}

View File

@@ -0,0 +1,23 @@
import PackageDescription
let package = Package(
name: "PMKFoundation",
dependencies: [
.Package(url: "https://github.com/mxcl/PromiseKit.git", majorVersion: 6)
],
swiftLanguageVersions: [3, 4],
exclude: [
"Sources/NSNotificationCenter+AnyPromise.m",
"Sources/NSTask+AnyPromise.m",
"Sources/NSURLSession+AnyPromise.m",
"Sources/PMKFoundation.h",
"Tests" // currently SwiftPM is not savvy to having a single test
]
)
#if os(Linux)
package.exclude += [
"Sources/afterlife.swift",
"Sources/NSObject+Promise.swift"
]
#endif

View File

@@ -0,0 +1,32 @@
// swift-tools-version:4.2
import PackageDescription
let pkg = Package(name: "PMKFoundation")
pkg.products = [
.library(name: "PMKFoundation", targets: ["PMKFoundation"]),
]
pkg.dependencies = [
.package(url: "https://github.com/mxcl/PromiseKit.git", .upToNextMajor(from: "6.0.0"))
]
pkg.swiftLanguageVersions = [.v3, .v4, .v4_2]
let target: Target = .target(name: "PMKFoundation")
target.path = "Sources"
target.exclude = ["NSNotificationCenter", "NSTask", "NSURLSession"].flatMap {
["\($0)+AnyPromise.m", "\($0)+AnyPromise.h"]
}
target.exclude.append("PMKFoundation.h")
target.dependencies = [
"PromiseKit"
]
#if os(Linux)
target.exclude += [
"afterlife.swift",
"NSObject+Promise.swift"
]
#endif
pkg.targets = [target]

View File

@@ -0,0 +1,46 @@
# PromiseKit Foundation Extensions ![Build Status]
This project adds promises to the Swift Foundation framework.
We support iOS, tvOS, watchOS, macOS and Linux, Swift 3.0, 3.1, 3.2, 4.0 and 4.1.
## CococaPods
```ruby
pod "PromiseKit/Foundation", "~> 6.0"
```
The extensions are built into `PromiseKit.framework` thus nothing else is needed.
## Carthage
```ruby
github "PromiseKit/Foundation" ~> 3.0
```
The extensions are built into their own framework:
```swift
// swift
import PromiseKit
import PMKFoundation
```
```objc
// objc
@import PromiseKit;
@import PMKFoundation;
```
## SwiftPM
```swift
let package = Package(
dependencies: [
.Package(url: "https://github.com/PromiseKit/Foundation.git", majorVersion: 3)
]
)
```
[Build Status]: https://travis-ci.org/PromiseKit/Foundation.svg?branch=master

View File

@@ -0,0 +1,44 @@
#import <Foundation/NSNotification.h>
#import <PromiseKit/AnyPromise.h>
/**
To import the `NSNotificationCenter` category:
use_frameworks!
pod "PromiseKit/Foundation"
Or `NSNotificationCenter` is one of the categories imported by the umbrella pod:
use_frameworks!
pod "PromiseKit"
And then in your sources:
#import <PromiseKit/PromiseKit.h>
*/
@interface NSNotificationCenter (PromiseKit)
/**
Observe the named notification once.
[NSNotificationCenter once:UIKeyboardWillShowNotification].then(^(id note, id userInfo){
UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
CGFloat duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] floatValue];
return [UIView promiseWithDuration:duration delay:0.0 options:(curve << 16) animations:^{
}];
});
@warning *Important* Promises only resolve once. If you need your block to execute more than once then use `-addObserverForName:object:queue:usingBlock:`.
@param notificationName The name of the notification for which to register the observer.
@return A promise that fulfills with two parameters:
1. The NSNotification object.
2. The NSNotifications userInfo property.
*/
+ (AnyPromise *)once:(NSString *)notificationName NS_REFINED_FOR_SWIFT;
@end

View File

@@ -0,0 +1,18 @@
#import <Foundation/NSOperation.h>
#import <Foundation/NSThread.h>
#import "PMKFoundation.h"
@implementation NSNotificationCenter (PromiseKit)
+ (AnyPromise *)once:(NSString *)name {
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
__block id identifier;
identifier = [[NSNotificationCenter defaultCenter] addObserverForName:name object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[[NSNotificationCenter defaultCenter] removeObserver:identifier name:name object:nil];
identifier = nil;
resolve(PMKManifold(note, note.userInfo));
}];
}];
}
@end

View File

@@ -0,0 +1,33 @@
import Foundation
#if !PMKCocoaPods
import PromiseKit
#endif
/**
To import the `NSNotificationCenter` category:
use_frameworks!
pod "PromiseKit/Foundation"
Or `NSNotificationCenter` is one of the categories imported by the umbrella pod:
use_frameworks!
pod "PromiseKit"
And then in your sources:
import PromiseKit
*/
extension NotificationCenter {
/// Observe the named notification once
public func observe(once name: Notification.Name, object: Any? = nil) -> Guarantee<Notification> {
let (promise, fulfill) = Guarantee<Notification>.pending()
#if os(Linux) && ((swift(>=4.0) && !swift(>=4.0.1)) || (swift(>=3.0) && !swift(>=3.2.1)))
let id = addObserver(forName: name, object: object, queue: nil, usingBlock: fulfill)
#else
let id = addObserver(forName: name, object: object, queue: nil, using: fulfill)
#endif
promise.done { _ in self.removeObserver(id) }
return promise
}
}

View File

@@ -0,0 +1,57 @@
import Foundation
#if !PMKCocoaPods
import PromiseKit
#endif
/**
To import the `NSObject` category:
use_frameworks!
pod "PromiseKit/Foundation"
Or `NSObject` is one of the categories imported by the umbrella pod:
use_frameworks!
pod "PromiseKit"
And then in your sources:
import PromiseKit
*/
extension NSObject {
/**
- Returns: A promise that resolves when the provided keyPath changes.
- Warning: *Important* The promise must not outlive the object under observation.
- SeeAlso: Apples KVO documentation.
*/
public func observe(_: PMKNamespacer, keyPath: String) -> Guarantee<Any?> {
return Guarantee { KVOProxy(observee: self, keyPath: keyPath, resolve: $0) }
}
}
private class KVOProxy: NSObject {
var retainCycle: KVOProxy?
let fulfill: (Any?) -> Void
@discardableResult
init(observee: NSObject, keyPath: String, resolve: @escaping (Any?) -> Void) {
fulfill = resolve
super.init()
observee.addObserver(self, forKeyPath: keyPath, options: NSKeyValueObservingOptions.new, context: pointer)
retainCycle = self
}
fileprivate override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if let change = change, context == pointer {
defer { retainCycle = nil }
fulfill(change[NSKeyValueChangeKey.newKey])
if let object = object as? NSObject, let keyPath = keyPath {
object.removeObserver(self, forKeyPath: keyPath)
}
}
}
private lazy var pointer: UnsafeMutableRawPointer = {
return Unmanaged<KVOProxy>.passUnretained(self).toOpaque()
}()
}

View File

@@ -0,0 +1,53 @@
#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && !TARGET_OS_SIMULATOR
#import <Foundation/NSTask.h>
#import <PromiseKit/AnyPromise.h>
#define PMKTaskErrorLaunchPathKey @"PMKTaskErrorLaunchPathKey"
#define PMKTaskErrorArgumentsKey @"PMKTaskErrorArgumentsKey"
#define PMKTaskErrorStandardOutputKey @"PMKTaskErrorStandardOutputKey"
#define PMKTaskErrorStandardErrorKey @"PMKTaskErrorStandardErrorKey"
#define PMKTaskErrorExitStatusKey @"PMKTaskErrorExitStatusKey"
/**
To import the `NSTask` category:
use_frameworks!
pod "PromiseKit/Foundation"
Or `NSTask` is one of the categories imported by the umbrella pod:
use_frameworks!
pod "PromiseKit"
And then in your sources:
#import <PromiseKit/PromiseKit.h>
*/
@interface NSTask (PromiseKit)
/**
Launches the receiver and resolves when it exits.
If the task fails the promise is rejected with code `PMKTaskError`, and
`userInfo` keys: `PMKTaskErrorStandardOutputKey`,
`PMKTaskErrorStandardErrorKey` and `PMKTaskErrorExitStatusKey`.
NSTask *task = [NSTask new];
task.launchPath = @"/usr/bin/basename";
task.arguments = @[@"/usr/bin/sleep"];
[task promise].then(^(NSString *stdout){
//…
});
@return A promise that fulfills with three parameters:
1) The stdout interpreted as a UTF8 string.
2) The stderr interpreted as a UTF8 string.
3) The stdout as `NSData`.
*/
- (AnyPromise *)promise NS_REFINED_FOR_SWIFT;
@end
#endif

View File

@@ -0,0 +1,59 @@
#import <Foundation/NSDictionary.h>
#import <Foundation/NSFileHandle.h>
#import <PromiseKit/PromiseKit.h>
#import <Foundation/NSString.h>
#import <Foundation/NSError.h>
#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && !TARGET_OS_SIMULATOR
#import "NSTask+AnyPromise.h"
@implementation NSTask (PromiseKit)
- (AnyPromise *)promise {
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
self.standardOutput = [NSPipe pipe];
self.standardError = [NSPipe pipe];
self.terminationHandler = ^(NSTask *task){
id stdoutData = [[task.standardOutput fileHandleForReading] readDataToEndOfFile];
id stdoutString = [[NSString alloc] initWithData:stdoutData encoding:NSUTF8StringEncoding];
id stderrData = [[task.standardError fileHandleForReading] readDataToEndOfFile];
id stderrString = [[NSString alloc] initWithData:stderrData encoding:NSUTF8StringEncoding];
if (task.terminationReason == NSTaskTerminationReasonExit && self.terminationStatus == 0) {
resolve(PMKManifold(stdoutString, stderrString, stdoutData));
} else {
id cmd = [NSMutableArray arrayWithObject:task.launchPath];
[cmd addObjectsFromArray:task.arguments];
cmd = [cmd componentsJoinedByString:@" "];
id info = @{
NSLocalizedDescriptionKey:[NSString stringWithFormat:@"Failed executing: %@.", cmd],
PMKTaskErrorStandardOutputKey: stdoutString,
PMKTaskErrorStandardErrorKey: stderrString,
PMKTaskErrorExitStatusKey: @(task.terminationStatus),
};
resolve([NSError errorWithDomain:PMKErrorDomain code:PMKTaskError userInfo:info]);
}
};
#if __clang_major__ >= 9
if (@available(macOS 10.13, *)) {
NSError *error = nil;
if (![self launchAndReturnError:&error]) {
resolve(error);
}
} else {
[self launch];
}
#else
[self launch]; // might @throw
#endif
}];
}
@end
#endif

View File

@@ -0,0 +1,79 @@
#import <Foundation/NSDictionary.h>
#import <Foundation/NSURLSession.h>
#import <Foundation/NSURLRequest.h>
#import <PromiseKit/AnyPromise.h>
#define PMKURLErrorFailingURLResponseKey @"PMKURLErrorFailingURLResponseKey"
#define PMKURLErrorFailingDataKey @"PMKURLErrorFailingDataKey"
#define PMKURLErrorFailingStringKey @"PMKURLErrorFailingStringKey"
#define PMKJSONErrorJSONObjectKey @"PMKJSONErrorJSONObjectKey"
/**
Really we shouldnt assume JSON for (application|text)/(x-)javascript,
really we should return a String of Javascript. However in practice
for the apps we write it *will be* JSON. Thus if you actually want
a Javascript String, use the promise variant of our category functions.
*/
#define PMKHTTPURLResponseIsJSON(rsp) [@[@"application/json", @"text/json", @"text/javascript", @"application/x-javascript", @"application/javascript"] containsObject:[rsp MIMEType]]
#define PMKHTTPURLResponseIsImage(rsp) [@[@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap"] containsObject:[rsp MIMEType]]
#define PMKHTTPURLResponseIsText(rsp) [[rsp MIMEType] hasPrefix:@"text/"]
#define PMKJSONDeserializationOptions ((NSJSONReadingOptions)(NSJSONReadingAllowFragments | NSJSONReadingMutableContainers))
/**
To import the `NSURLSession` category:
use_frameworks!
pod "PromiseKit/Foundation"
Or `NSURLConnection` is one of the categories imported by the umbrella pod:
use_frameworks!
pod "PromiseKit"
And then in your sources:
#import <PromiseKit/PromiseKit.h>
*/
@interface NSURLSession (PromiseKit)
/**
Creates a task that retrieves the contents of a URL based on the
specified URL request object.
PromiseKit automatically deserializes the raw HTTP data response into the
appropriate rich data type based on the mime type the server provides.
Thus if the response is JSON you will get the deserialized JSON response.
PromiseKit supports decoding into strings, JSON and UIImages.
However if your server does not provide a rich content-type, you will
just get `NSData`. This is rare, but a good example we came across was
downloading files from Dropbox.
PromiseKit goes to quite some lengths to provide good `NSError` objects
for error conditions at all stages of the HTTP to rich-data type
pipeline. We provide the following additional `userInfo` keys as
appropriate:
- `PMKURLErrorFailingDataKey`
- `PMKURLErrorFailingStringKey`
- `PMKURLErrorFailingURLResponseKey`
[[NSURLConnection sharedSession] promiseDataTaskWithRequest:rq].then(^(id response){
// response is probably an NSDictionary deserialized from JSON
});
@param request The URL request.
@return A promise that fulfills with three parameters:
1) The deserialized data response.
2) The `NSHTTPURLResponse`.
3) The raw `NSData` response.
@see https://github.com/mxcl/OMGHTTPURLRQ
*/
- (AnyPromise *)promiseDataTaskWithRequest:(NSURLRequest *)request NS_REFINED_FOR_SWIFT;
@end

View File

@@ -0,0 +1,113 @@
#import <Foundation/NSJSONSerialization.h>
#import <Foundation/NSURLResponse.h>
#import <CoreFoundation/CFString.h>
#import "NSURLSession+AnyPromise.h"
#import <Foundation/NSOperation.h>
#import <Foundation/NSURLError.h>
#import <PromiseKit/PromiseKit.h>
#import <CoreFoundation/CFURL.h>
#import <Foundation/NSThread.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSError.h>
#import <Foundation/NSURL.h>
@implementation NSURLSession (PromiseKit)
- (AnyPromise *)promiseDataTaskWithRequest:(NSURLRequest *)rq {
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[[self dataTaskWithRequest:rq completionHandler:^(NSData *data, id rsp, NSError *urlError){
assert(![NSThread isMainThread]);
PMKResolver fulfiller = ^(id responseObject){
resolve(PMKManifold(responseObject, rsp, data));
};
PMKResolver rejecter = ^(NSError *error){
id userInfo = error.userInfo.mutableCopy ?: [NSMutableDictionary new];
if (data) userInfo[PMKURLErrorFailingDataKey] = data;
if (rsp) userInfo[PMKURLErrorFailingURLResponseKey] = rsp;
error = [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
resolve(error);
};
NSStringEncoding (^stringEncoding)(void) = ^NSStringEncoding{
id encodingName = [rsp textEncodingName];
if (encodingName) {
CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)encodingName);
if (encoding != kCFStringEncodingInvalidId)
return CFStringConvertEncodingToNSStringEncoding(encoding);
}
return NSUTF8StringEncoding;
};
if (urlError) {
rejecter(urlError);
} else if (![rsp isKindOfClass:[NSHTTPURLResponse class]]) {
fulfiller(data);
} else if ([rsp statusCode] < 200 || [rsp statusCode] >= 300) {
id info = @{
NSLocalizedDescriptionKey: @"The server returned a bad HTTP response code",
NSURLErrorFailingURLStringErrorKey: rq.URL.absoluteString,
NSURLErrorFailingURLErrorKey: rq.URL
};
id err = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadServerResponse userInfo:info];
rejecter(err);
} else if (PMKHTTPURLResponseIsJSON(rsp)) {
// work around ever-so-common Rails workaround: https://github.com/rails/rails/issues/1742
if ([rsp expectedContentLength] == 1 && [data isEqualToData:[NSData dataWithBytes:" " length:1]])
return fulfiller(nil);
NSError *err = nil;
id json = [NSJSONSerialization JSONObjectWithData:data options:PMKJSONDeserializationOptions error:&err];
if (!err) {
fulfiller(json);
} else {
id userInfo = err.userInfo.mutableCopy;
if (data) {
NSString *string = [[NSString alloc] initWithData:data encoding:stringEncoding()];
if (string)
userInfo[PMKURLErrorFailingStringKey] = string;
}
long long length = [rsp expectedContentLength];
id bytes = length <= 0 ? @"" : [NSString stringWithFormat:@"%lld bytes", length];
id fmt = @"The server claimed a %@ JSON response, but decoding failed with: %@";
userInfo[NSLocalizedDescriptionKey] = [NSString stringWithFormat:fmt, bytes, userInfo[NSLocalizedDescriptionKey]];
err = [NSError errorWithDomain:err.domain code:err.code userInfo:userInfo];
rejecter(err);
}
#ifdef UIKIT_EXTERN
} else if (PMKHTTPURLResponseIsImage(rsp)) {
UIImage *image = [[UIImage alloc] initWithData:data];
image = [[UIImage alloc] initWithCGImage:[image CGImage] scale:image.scale orientation:image.imageOrientation];
if (image)
fulfiller(image);
else {
id info = @{
NSLocalizedDescriptionKey: @"The server returned invalid image data",
NSURLErrorFailingURLStringErrorKey: rq.URL.absoluteString,
NSURLErrorFailingURLErrorKey: rq.URL
};
id err = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:info];
rejecter(err);
}
#endif
} else if (PMKHTTPURLResponseIsText(rsp)) {
id str = [[NSString alloc] initWithData:data encoding:stringEncoding()];
if (str)
fulfiller(str);
else {
id info = @{
NSLocalizedDescriptionKey: @"The server returned invalid string data",
NSURLErrorFailingURLStringErrorKey: rq.URL.absoluteString,
NSURLErrorFailingURLErrorKey: rq.URL
};
id err = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:info];
rejecter(err);
}
} else {
fulfiller(data);
}
}] resume];
}];
}
@end

View File

@@ -0,0 +1,241 @@
import Foundation
#if !PMKCocoaPods
import PromiseKit
#endif
/**
To import the `NSURLSession` category:
use_frameworks!
pod "PromiseKit/Foundation"
Or `NSURLSession` is one of the categories imported by the umbrella pod:
use_frameworks!
pod "PromiseKit"
And then in your sources:
import PromiseKit
*/
extension URLSession {
/**
Example usage:
firstly {
URLSession.shared.dataTask(.promise, with: rq)
}.compactMap { data, _ in
try JSONSerialization.jsonObject(with: data) as? [String: Any]
}.then { json in
//
}
We recommend the use of [OMGHTTPURLRQ] which allows you to construct correct REST requests:
firstly {
let rq = OMGHTTPURLRQ.POST(url, json: parameters)
URLSession.shared.dataTask(.promise, with: rq)
}.then { data, urlResponse in
//
}
We provide a convenience initializer for `String` specifically for this promise:
firstly {
URLSession.shared.dataTask(.promise, with: rq)
}.compactMap(String.init).then { string in
// decoded per the string encoding specified by the server
}.then { string in
print("response: string")
}
Other common types can be easily decoded using compactMap also:
firstly {
URLSession.shared.dataTask(.promise, with: rq)
}.compactMap {
UIImage(data: $0)
}.then {
self.imageView.image = $0
}
Though if you do decode the image this way, we recommend inflating it on a background thread
first as this will improve main thread performance when rendering the image:
firstly {
URLSession.shared.dataTask(.promise, with: rq)
}.compactMap(on: QoS.userInitiated) { data, _ in
guard let img = UIImage(data: data) else { return nil }
_ = cgImage?.dataProvider?.data
return img
}.then {
self.imageView.image = $0
}
- Parameter convertible: A URL or URLRequest.
- Returns: A promise that represents the URL request.
- SeeAlso: [OMGHTTPURLRQ]
- Remark: We deliberately dont provide a `URLRequestConvertible` for `String` because in our experience, you should be explicit with this error path to make good apps.
[OMGHTTPURLRQ]: https://github.com/mxcl/OMGHTTPURLRQ
*/
public func dataTask(_: PMKNamespacer, with convertible: URLRequestConvertible) -> Promise<(data: Data, response: URLResponse)> {
return Promise { dataTask(with: convertible.pmkRequest, completionHandler: adapter($0)).resume() }
}
public func uploadTask(_: PMKNamespacer, with convertible: URLRequestConvertible, from data: Data) -> Promise<(data: Data, response: URLResponse)> {
return Promise { uploadTask(with: convertible.pmkRequest, from: data, completionHandler: adapter($0)).resume() }
}
public func uploadTask(_: PMKNamespacer, with convertible: URLRequestConvertible, fromFile file: URL) -> Promise<(data: Data, response: URLResponse)> {
return Promise { uploadTask(with: convertible.pmkRequest, fromFile: file, completionHandler: adapter($0)).resume() }
}
/// - Remark: we force a `to` parameter because Apple deletes the downloaded file immediately after the underyling completion handler returns.
/// - Note: we do not create the destination directory for you, because we move the file with FileManager.moveItem which changes it behavior depending on the directory status of the URL you provide. So create your own directory first!
public func downloadTask(_: PMKNamespacer, with convertible: URLRequestConvertible, to saveLocation: URL) -> Promise<(saveLocation: URL, response: URLResponse)> {
return Promise { seal in
downloadTask(with: convertible.pmkRequest, completionHandler: { tmp, rsp, err in
if let error = err {
seal.reject(error)
} else if let rsp = rsp, let tmp = tmp {
do {
try FileManager.default.moveItem(at: tmp, to: saveLocation)
seal.fulfill((saveLocation, rsp))
} catch {
seal.reject(error)
}
} else {
seal.reject(PMKError.invalidCallingConvention)
}
}).resume()
}
}
}
public protocol URLRequestConvertible {
var pmkRequest: URLRequest { get }
}
extension URLRequest: URLRequestConvertible {
public var pmkRequest: URLRequest { return self }
}
extension URL: URLRequestConvertible {
public var pmkRequest: URLRequest { return URLRequest(url: self) }
}
#if !os(Linux)
public extension String {
/**
- Remark: useful when converting a `URLSession` response into a `String`
firstly {
URLSession.shared.dataTask(.promise, with: rq)
}.map(String.init).done {
print($0)
}
*/
init?(data: Data, urlResponse: URLResponse) {
guard let str = String(bytes: data, encoding: urlResponse.stringEncoding ?? .utf8) else {
return nil
}
self.init(str)
}
}
private extension URLResponse {
var stringEncoding: String.Encoding? {
guard let encodingName = textEncodingName else { return nil }
let encoding = CFStringConvertIANACharSetNameToEncoding(encodingName as CFString)
guard encoding != kCFStringEncodingInvalidId else { return nil }
return String.Encoding(rawValue: CFStringConvertEncodingToNSStringEncoding(encoding))
}
}
#endif
private func adapter<T, U>(_ seal: Resolver<(data: T, response: U)>) -> (T?, U?, Error?) -> Void {
return { t, u, e in
if let t = t, let u = u {
seal.fulfill((t, u))
} else if let e = e {
seal.reject(e)
} else {
seal.reject(PMKError.invalidCallingConvention)
}
}
}
#if swift(>=3.1)
public enum PMKHTTPError: Error, LocalizedError, CustomStringConvertible {
case badStatusCode(Int, Data, HTTPURLResponse)
public var errorDescription: String? {
func url(_ rsp: URLResponse) -> String {
return rsp.url?.absoluteString ?? "nil"
}
switch self {
case .badStatusCode(401, _, let response):
return "Unauthorized (\(url(response))"
case .badStatusCode(let code, _, let response):
return "Invalid HTTP response (\(code)) for \(url(response))."
}
}
#if swift(>=4.0)
public func decodeResponse<T: Decodable>(_ t: T.Type, decoder: JSONDecoder = JSONDecoder()) -> T? {
switch self {
case .badStatusCode(_, let data, _):
return try? decoder.decode(t, from: data)
}
}
#endif
//TODO rename responseJSON
public var jsonDictionary: Any? {
switch self {
case .badStatusCode(_, let data, _):
return try? JSONSerialization.jsonObject(with: data)
}
}
var responseBodyString: String? {
switch self {
case .badStatusCode(_, let data, _):
return String(data: data, encoding: .utf8)
}
}
public var failureReason: String? {
return responseBodyString
}
public var description: String {
switch self {
case .badStatusCode(let code, let data, let response):
var dict: [String: Any] = [
"Status Code": code,
"Body": String(data: data, encoding: .utf8) ?? "\(data.count) bytes"
]
dict["URL"] = response.url
dict["Headers"] = response.allHeaderFields
return "<NSHTTPResponse> \(NSDictionary(dictionary: dict))" // as NSDictionary makes the output look like NSHTTPURLResponse looks
}
}
}
public extension Promise where T == (data: Data, response: URLResponse) {
func validate() -> Promise<T> {
return map {
guard let response = $0.response as? HTTPURLResponse else { return $0 }
switch response.statusCode {
case 200..<300:
return $0
case let code:
throw PMKHTTPError.badStatusCode(code, $0.data, response)
}
}
}
}
#endif

View File

@@ -0,0 +1,3 @@
#import "NSNotificationCenter+AnyPromise.h"
#import "NSURLSession+AnyPromise.h"
#import "NSTask+AnyPromise.h"

View File

@@ -0,0 +1,190 @@
import Foundation
#if !PMKCocoaPods
import PromiseKit
#endif
#if os(macOS)
/**
To import the `Process` category:
use_frameworks!
pod "PromiseKit/Foundation"
Or `Process` is one of the categories imported by the umbrella pod:
use_frameworks!
pod "PromiseKit"
And then in your sources:
import PromiseKit
*/
extension Process {
/**
Launches the receiver and resolves when it exits.
let proc = Process()
proc.launchPath = "/bin/ls"
proc.arguments = ["/bin"]
proc.launch(.promise).compactMap { std in
String(data: std.out.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8)
}.then { stdout in
print(str)
}
*/
public func launch(_: PMKNamespacer) -> Promise<(out: Pipe, err: Pipe)> {
let (stdout, stderr) = (Pipe(), Pipe())
do {
standardOutput = stdout
standardError = stderr
#if swift(>=4.0)
if #available(OSX 10.13, *) {
try run()
} else if let path = launchPath, FileManager.default.isExecutableFile(atPath: path) {
launch()
} else {
throw PMKError.notExecutable(launchPath)
}
#else
guard let path = launchPath, FileManager.default.isExecutableFile(atPath: path) else {
throw PMKError.notExecutable(launchPath)
}
launch()
#endif
} catch {
return Promise(error: error)
}
var q: DispatchQueue {
if #available(macOS 10.10, iOS 8.0, tvOS 9.0, watchOS 2.0, *) {
return DispatchQueue.global(qos: .default)
} else {
return DispatchQueue.global(priority: .default)
}
}
return Promise { seal in
q.async {
self.waitUntilExit()
guard self.terminationReason == .exit, self.terminationStatus == 0 else {
let stdoutData = try? self.readDataFromPipe(stdout)
let stderrData = try? self.readDataFromPipe(stderr)
let stdoutString = stdoutData.flatMap { (data: Data) -> String? in String(data: data, encoding: .utf8) }
let stderrString = stderrData.flatMap { (data: Data) -> String? in String(data: data, encoding: .utf8) }
return seal.reject(PMKError.execution(process: self, standardOutput: stdoutString, standardError: stderrString))
}
seal.fulfill((stdout, stderr))
}
}
}
private func readDataFromPipe(_ pipe: Pipe) throws -> Data {
let handle = pipe.fileHandleForReading
defer { handle.closeFile() }
// Someday, NSFileHandle will probably be updated with throwing equivalents to its read and write methods,
// as NSTask has, to avoid raising exceptions and crashing the app.
// Unfortunately that day has not yet come, so use the underlying BSD calls for now.
let fd = handle.fileDescriptor
let bufsize = 1024 * 8
let buf = UnsafeMutablePointer<UInt8>.allocate(capacity: bufsize)
#if swift(>=4.1)
defer { buf.deallocate() }
#else
defer { buf.deallocate(capacity: bufsize) }
#endif
var data = Data()
while true {
let bytesRead = read(fd, buf, bufsize)
if bytesRead == 0 {
break
}
if bytesRead < 0 {
throw POSIXError.Code(rawValue: errno).map { POSIXError($0) } ?? CocoaError(.fileReadUnknown)
}
data.append(buf, count: bytesRead)
}
return data
}
/**
The error generated by PromiseKits `Process` extension
*/
public enum PMKError {
/// NOT AVAILABLE ON 10.13 and above because Apple provide this error handling themselves
case notExecutable(String?)
case execution(process: Process, standardOutput: String?, standardError: String?)
}
}
extension Process.PMKError: LocalizedError {
public var errorDescription: String? {
switch self {
case .notExecutable(let path?):
return "File not executable: \(path)"
case .notExecutable(nil):
return "No launch path specified"
case .execution(process: let task, standardOutput: _, standardError: _):
return "Failed executing: `\(task)` (\(task.terminationStatus))."
}
}
}
public extension Promise where T == (out: Pipe, err: Pipe) {
func print() -> Promise<T> {
return tap { result in
switch result {
case .fulfilled(let raw):
let stdout = String(data: raw.out.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8)
let stderr = String(data: raw.err.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8)
Swift.print("stdout: `\(stdout ?? "")`")
Swift.print("stderr: `\(stderr ?? "")`")
case .rejected(let err):
Swift.print(err)
}
}
}
}
extension Process {
/// Provided because Foundations is USELESS
open override var description: String {
let launchPath = self.launchPath ?? "$0"
var args = [launchPath]
arguments.flatMap{ args += $0 }
return args.map { arg in
let contains: Bool
#if swift(>=3.2)
contains = arg.contains(" ")
#else
contains = arg.characters.contains(" ")
#endif
if contains {
return "\"\(arg)\""
} else if arg == "" {
return "\"\""
} else {
return arg
}
}.joined(separator: " ")
}
}
#endif

View File

@@ -0,0 +1,26 @@
import Foundation
#if !PMKCocoaPods
import PromiseKit
#endif
/**
- Returns: A promise that resolves when the provided object deallocates
- Important: The promise is not guarenteed to resolve immediately when the provided object is deallocated. So you cannot write code that depends on exact timing.
*/
public func after(life object: NSObject) -> Guarantee<Void> {
var reaper = objc_getAssociatedObject(object, &handle) as? GrimReaper
if reaper == nil {
reaper = GrimReaper()
objc_setAssociatedObject(object, &handle, reaper, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
return reaper!.promise
}
private var handle: UInt8 = 0
private class GrimReaper: NSObject {
deinit {
fulfill(())
}
let (promise, fulfill) = Guarantee<Void>.pending()
}

View File

@@ -0,0 +1,22 @@
import PMKFoundation
import Foundation
import PromiseKit
import XCTest
class NSNotificationCenterTests: XCTestCase {
func test() {
let ex = expectation(description: "")
let userInfo = ["a": 1]
NotificationCenter.default.observe(once: PMKTestNotification).done { value in
XCTAssertEqual(value.userInfo?.count, 1)
ex.fulfill()
}
NotificationCenter.default.post(name: PMKTestNotification, object: nil, userInfo: userInfo)
waitForExpectations(timeout: 1)
}
}
private let PMKTestNotification = Notification.Name("PMKTestNotification")

View File

@@ -0,0 +1,76 @@
import PMKFoundation
import Foundation
import PromiseKit
import XCTest
class NSObjectTests: XCTestCase {
func testKVO() {
let ex = expectation(description: "")
let foo = Foo()
foo.observe(.promise, keyPath: "bar").done { newValue in
XCTAssertEqual(newValue as? String, "moo")
ex.fulfill()
}.catch { _ in
XCTFail()
}
foo.bar = "moo"
waitForExpectations(timeout: 1)
}
func testAfterlife() {
let ex = expectation(description: "")
var killme: NSObject!
autoreleasepool {
func innerScope() {
killme = NSObject()
after(life: killme).done { _ in
//
ex.fulfill()
}
}
innerScope()
after(.milliseconds(200)).done {
killme = nil
}
}
waitForExpectations(timeout: 1)
}
func testMultiObserveAfterlife() {
let ex1 = expectation(description: "")
let ex2 = expectation(description: "")
var killme: NSObject!
autoreleasepool {
func innerScope() {
killme = NSObject()
after(life: killme).done { _ in
ex1.fulfill()
}
after(life: killme).done { _ in
ex2.fulfill()
}
}
innerScope()
after(.milliseconds(200)).done {
killme = nil
}
}
waitForExpectations(timeout: 1)
}
}
private class Foo: NSObject {
@objc dynamic var bar: String = "bar"
}

View File

@@ -0,0 +1,50 @@
import PMKFoundation
import Foundation
import PromiseKit
import XCTest
#if os(macOS)
class NSTaskTests: XCTestCase {
func test1() {
let ex = expectation(description: "")
let task = Process()
task.launchPath = "/usr/bin/basename"
task.arguments = ["/foo/doe/bar"]
task.launch(.promise).done { stdout, _ in
let stdout = String(data: stdout.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8)
XCTAssertEqual(stdout, "bar\n")
ex.fulfill()
}
waitForExpectations(timeout: 10)
}
func test2() {
let ex = expectation(description: "")
let dir = "PMKAbsentDirectory"
let task = Process()
task.launchPath = "/bin/ls"
task.arguments = [dir]
task.launch(.promise).done { _ in
XCTFail()
}.catch { err in
do {
throw err
} catch Process.PMKError.execution(let proc, let stdout, let stderr) {
let expectedStderr = "ls: \(dir): No such file or directory\n"
XCTAssertEqual(stderr, expectedStderr)
XCTAssertEqual(proc.terminationStatus, 1)
XCTAssertEqual(stdout?.count ?? 0, 0)
} catch {
XCTFail()
}
ex.fulfill()
}
waitForExpectations(timeout: 10)
}
}
#endif

View File

@@ -0,0 +1,55 @@
@import PMKFoundation;
@import OHHTTPStubs;
@import Foundation;
@import PromiseKit;
@import XCTest;
@implementation NSURLSessionTests: XCTestCase
- (void)tearDown {
[OHHTTPStubs removeAllStubs];
}
- (void)test200 {
id stubData = [NSData dataWithBytes:"a" length:1];
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *rq){
return [rq.URL.host isEqualToString:@"example.com"];
} withStubResponse:^(NSURLRequest *request){
return [OHHTTPStubsResponse responseWithData:stubData statusCode:200 headers:@{@"Content-Type": @"text/html"}];
}];
id ex = [self expectationWithDescription:@""];
id rq = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]];
[[NSURLSession sharedSession] promiseDataTaskWithRequest:rq].then(^{
[ex fulfill];
});
[self waitForExpectationsWithTimeout:10 handler:nil];
}
- (void)testBadJSON {
id stubData = [NSData dataWithBytes:"[a: 3]" length:1];
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *rq){
return [rq.URL.host isEqualToString:@"example.com"];
} withStubResponse:^(NSURLRequest *request){
return [OHHTTPStubsResponse responseWithData:stubData statusCode:200 headers:@{@"Content-Type": @"application/json"}];
}];
id ex = [self expectationWithDescription:@""];
id rq = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]];
[[NSURLSession sharedSession] promiseDataTaskWithRequest:rq].catch(^(NSError *err){
XCTAssertEqualObjects(err.domain, NSCocoaErrorDomain); //TODO this is why we should replace this domain
XCTAssertEqual(err.code, 3840);
XCTAssertEqualObjects(err.userInfo[PMKURLErrorFailingDataKey], stubData);
XCTAssertNotNil(err.userInfo[PMKURLErrorFailingURLResponseKey]);
[ex fulfill];
});
[self waitForExpectationsWithTimeout:10 handler:nil];
}
@end

View File

@@ -0,0 +1,76 @@
import PMKFoundation
import OHHTTPStubs
import PromiseKit
import XCTest
class NSURLSessionTests: XCTestCase {
func test1() {
let json: NSDictionary = ["key1": "value1", "key2": ["value2A", "value2B"]]
OHHTTPStubs.stubRequests(passingTest: { $0.url!.host == "example.com" }) { _ in
return OHHTTPStubsResponse(jsonObject: json, statusCode: 200, headers: nil)
}
let ex = expectation(description: "")
let rq = URLRequest(url: URL(string: "http://example.com")!)
firstly {
URLSession.shared.dataTask(.promise, with: rq)
}.compactMap {
try JSONSerialization.jsonObject(with: $0.data) as? NSDictionary
}.done { rsp in
XCTAssertEqual(json, rsp)
ex.fulfill()
}
waitForExpectations(timeout: 1)
}
func test2() {
// test that URLDataPromise chains thens
// this test because I dont trust the Swift compiler
let dummy = ("fred" as NSString).data(using: String.Encoding.utf8.rawValue)!
OHHTTPStubs.stubRequests(passingTest: { $0.url!.host == "example.com" }) { _ in
return OHHTTPStubsResponse(data: dummy, statusCode: 200, headers: [:])
}
let ex = expectation(description: "")
let rq = URLRequest(url: URL(string: "http://example.com")!)
after(.milliseconds(100)).then {
URLSession.shared.dataTask(.promise, with: rq)
}.done { x in
XCTAssertEqual(x.data, dummy)
ex.fulfill()
}
waitForExpectations(timeout: 1)
}
/// test that our convenience String constructor applies
func test3() {
let dummy = "fred"
OHHTTPStubs.stubRequests(passingTest: { $0.url!.host == "example.com" }) { _ in
let data = dummy.data(using: .utf8)!
return OHHTTPStubsResponse(data: data, statusCode: 200, headers: [:])
}
let ex = expectation(description: "")
let rq = URLRequest(url: URL(string: "http://example.com")!)
after(.milliseconds(100)).then {
URLSession.shared.dataTask(.promise, with: rq)
}.map(String.init).done {
XCTAssertEqual($0, dummy)
ex.fulfill()
}
waitForExpectations(timeout: 1)
}
override func tearDown() {
OHHTTPStubs.removeAllStubs()
}
}